15c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy/* 25c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy * iplink_vlan.c VLAN device support 35c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy * 45c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy * This program is free software; you can redistribute it and/or 55c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy * modify it under the terms of the GNU General Public License 65c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy * as published by the Free Software Foundation; either version 75c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy * 2 of the License, or (at your option) any later version. 85c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy * 95c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy * Authors: Patrick McHardy <kaber@trash.net> 105c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy */ 115c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 125c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#include <stdio.h> 135c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#include <stdlib.h> 145c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#include <string.h> 155c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#include <linux/if_vlan.h> 165c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 175c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#include "rt_names.h" 185c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#include "utils.h" 195c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#include "ip_common.h" 205c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 215c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardystatic void explain(void) 225c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy{ 235c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(stderr, 245c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy "Usage: ... vlan id VLANID [ FLAG-LIST ]\n" 255c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy " [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n" 265c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy "\n" 275c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy "VLANID := 0-4095\n" 285c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy "FLAG-LIST := [ FLAG-LIST ] FLAG\n" 2947420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ]\n" 302180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy " [ loose_binding { on | off } ]\n" 315c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy "QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n" 325c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy "QOS-MAPPING := FROM:TO\n" 335c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy ); 345c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy} 355c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 365c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardystatic int on_off(char *msg) 375c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy{ 385c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg); 395c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return -1; 405c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy} 415c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 425c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardystatic int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n, 435c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy int attrtype) 445c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy{ 455c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy int argc = *argcp; 465c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy char **argv = *argvp; 475c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy struct ifla_vlan_qos_mapping m; 485c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy struct rtattr *tail; 495c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 505c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy tail = NLMSG_TAIL(n); 515c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy addattr_l(n, 1024, attrtype, NULL, 0); 525c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 535c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy while (argc > 0) { 545c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy char *colon = strchr(*argv, ':'); 555c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 565c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (!colon) 575c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy break; 585c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy *colon = '\0'; 595c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 605c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (get_u32(&m.from, *argv, 0)) 615c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return 1; 625c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (get_u32(&m.to, colon + 1, 0)) 635c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return 1; 645c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy argc--, argv++; 655c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 665c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m)); 675c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } 685c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 695c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail; 705c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 715c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy *argcp = argc; 725c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy *argvp = argv; 735c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return 0; 745c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy} 755c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 765c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardystatic int vlan_parse_opt(struct link_util *lu, int argc, char **argv, 775c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy struct nlmsghdr *n) 785c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy{ 795c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy struct ifla_vlan_flags flags = { 0 }; 805c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy __u16 id; 815c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 825c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy while (argc > 0) { 835c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (matches(*argv, "id") == 0) { 845c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy NEXT_ARG(); 855c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (get_u16(&id, *argv, 0)) 865c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy invarg("id is invalid", *argv); 875c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy addattr_l(n, 1024, IFLA_VLAN_ID, &id, 2); 885c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } else if (matches(*argv, "reorder_hdr") == 0) { 895c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy NEXT_ARG(); 905c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy flags.mask |= VLAN_FLAG_REORDER_HDR; 915c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (strcmp(*argv, "on") == 0) 925c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy flags.flags |= VLAN_FLAG_REORDER_HDR; 935c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy else if (strcmp(*argv, "off") == 0) 945c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy flags.flags &= ~VLAN_FLAG_REORDER_HDR; 955c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy else 965c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return on_off("reorder_hdr"); 9747420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy } else if (matches(*argv, "gvrp") == 0) { 9847420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy NEXT_ARG(); 9947420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy flags.mask |= VLAN_FLAG_GVRP; 10047420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy if (strcmp(*argv, "on") == 0) 10147420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy flags.flags |= VLAN_FLAG_GVRP; 10247420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy else if (strcmp(*argv, "off") == 0) 10347420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy flags.flags &= ~VLAN_FLAG_GVRP; 10447420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy else 10547420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy return on_off("gvrp"); 1062180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy } else if (matches(*argv, "loose_binding") == 0) { 1072180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy NEXT_ARG(); 1082180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy flags.mask |= VLAN_FLAG_LOOSE_BINDING; 1092180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy if (strcmp(*argv, "on") == 0) 1102180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy flags.flags |= VLAN_FLAG_LOOSE_BINDING; 1112180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy else if (strcmp(*argv, "off") == 0) 1122180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy flags.flags &= ~VLAN_FLAG_LOOSE_BINDING; 1132180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy else 1142180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy return on_off("loose_binding"); 1155c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } else if (matches(*argv, "ingress-qos-map") == 0) { 1165c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy NEXT_ARG(); 1175c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (vlan_parse_qos_map(&argc, &argv, n, 1185c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy IFLA_VLAN_INGRESS_QOS)) 1195c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy invarg("invalid ingress-qos-map", *argv); 1205c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy continue; 1215c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } else if (matches(*argv, "egress-qos-map") == 0) { 1225c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy NEXT_ARG(); 1235c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (vlan_parse_qos_map(&argc, &argv, n, 1245c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy IFLA_VLAN_EGRESS_QOS)) 1255c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy invarg("invalid egress-qos-map", *argv); 1265c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy continue; 1275c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } else if (matches(*argv, "help") == 0) { 1285c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy explain(); 1295c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return -1; 1305c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } else { 1315c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(stderr, "vlan: what is \"%s\"?\n", *argv); 1325c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy explain(); 1335c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return -1; 1345c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } 1355c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy argc--, argv++; 1365c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } 1375c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1385c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (flags.mask) 1395c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy addattr_l(n, 1024, IFLA_VLAN_FLAGS, &flags, sizeof(flags)); 1405c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1415c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return 0; 1425c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy} 1435c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1445c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardystatic void vlan_print_map(FILE *f, char *name, struct rtattr *attr) 1455c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy{ 1465c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy struct ifla_vlan_qos_mapping *m; 1475c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy struct rtattr *i; 1485c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy int rem; 1495c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1505c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(f, "\n %s { ", name); 1515c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1525c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy rem = RTA_PAYLOAD(attr); 1535c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { 1545c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy m = RTA_DATA(i); 1555c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(f, "%u:%u ", m->from, m->to); 1565c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } 1575c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(f, "} "); 1585c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy} 1595c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1605c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardystatic void vlan_print_flags(FILE *fp, __u32 flags) 1615c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy{ 1625c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(fp, "<"); 1635c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#define _PF(f) if (flags & VLAN_FLAG_##f) { \ 1645c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy flags &= ~ VLAN_FLAG_##f; \ 1655c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(fp, #f "%s", flags ? "," : ""); \ 1665c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } 1675c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy _PF(REORDER_HDR); 16847420640687cbd389ddd99d39cf7fb0e0bcb265aPatrick McHardy _PF(GVRP); 1692180b6b50bdc50e1a7740e5283930088da0bbae7Patrick McHardy _PF(LOOSE_BINDING); 1705c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy#undef _PF 1715c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (flags) 1725c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(fp, "%x", flags); 1735c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy fprintf(fp, "> "); 1745c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy} 1755c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1765c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardystatic void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 1775c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy{ 1785c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy struct ifla_vlan_flags *flags; 1795c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (!tb) 1805c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return; 1815c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1825c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (!tb[IFLA_VLAN_ID] || 1835c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16)) 1845c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return; 1855c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 186ff24746cca1ef0c92d46614158e6672acd6b63d3Stephen Hemminger fprintf(f, "id %u ", rta_getattr_u16(tb[IFLA_VLAN_ID])); 1875c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 1885c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (tb[IFLA_VLAN_FLAGS]) { 1895c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags)) 1905c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy return; 1915c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]); 1925c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy vlan_print_flags(f, flags->flags); 1935c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy } 1945c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (tb[IFLA_VLAN_INGRESS_QOS]) 1955c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]); 1965c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy if (tb[IFLA_VLAN_EGRESS_QOS]) 1975c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]); 1985c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy} 1995c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy 2005c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardystruct link_util vlan_link_util = { 2015c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy .id = "vlan", 2025c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy .maxattr = IFLA_VLAN_MAX, 2035c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy .parse_opt = vlan_parse_opt, 2045c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy .print_opt = vlan_print_opt, 2055c302d518f10e67ddab9e44207a0c878214ed389Patrick McHardy}; 206