Improve support for VLAN priorities in our vlan(4) driver: - Add new ioctls, SIOCGVLANPCP and SIOCSVLANPCP to get and set VLAN priority properties on a vlan(4) interface. - Add a new ifconfig command, "vlanprio X", which allows setting a VLAN priority to place in the 802.1Q headers of packets transmitted on a vlan(4) interface. - Add a new system privilege, PRIV_NET_SETVLANPCP, to control access to changing a VLAN interface's filter. Also employ the same VIMAGE-related controls present on SIOCSETVLAN, for consistency, even though we might refine those in the future. - In numerous places in the vlan(4) implementation, better differentiate "tags" and "VLAN IDs" -- tags contain three fields, the VID (VLAN identifer), PCP (priority), and CFI (canonical format flag), not just the identifier. To this end, rename lots of arguments, variables, functions, etc. VIDs, rather than tags, should be used to match VLANs, as arguments to hash functions, etc. - Rename VLAN_TAG to VLAN_VID, and vlan_tag_p to vlan_vid_p. Most of this change is MFCable without modification, but we might want to omit or modify this aspect of the change for KPI and KBI reasons. Discussed with: rrs, yongari Sponsored by: ADARA Networks, Inc. MFC after: 1 month Index: sys/ofed/include/rdma/ib_addr.h =================================================================== --- sys/ofed/include/rdma/ib_addr.h (revision 229389) +++ sys/ofed/include/rdma/ib_addr.h (working copy) @@ -154,11 +154,11 @@ return dev->priv_flags & IFF_802_1Q_VLAN ? vlan_dev_vlan_id(dev) : 0xffff; #else - uint16_t tag; + uint16_t vid; - if (VLAN_TAG(__DECONST(struct ifnet *, dev), &tag) != 0) + if (VLAN_VID(__DECONST(struct ifnet *, dev), &vid) != 0) return 0xffff; - return tag; + return vid; #endif } Index: sys/net/if.c =================================================================== --- sys/net/if.c (revision 229389) +++ sys/net/if.c (working copy) @@ -1870,7 +1870,7 @@ void (*vlan_trunk_cap_p)(struct ifnet *); /* XXX: private from if_vlan */ struct ifnet *(*vlan_trunkdev_p)(struct ifnet *); struct ifnet *(*vlan_devat_p)(struct ifnet *, uint16_t); -int (*vlan_tag_p)(struct ifnet *, uint16_t *); +int (*vlan_vid_p)(struct ifnet *, uint16_t *); int (*vlan_setcookie_p)(struct ifnet *, void *); void *(*vlan_cookie_p)(struct ifnet *); Index: sys/net/if.h =================================================================== --- sys/net/if.h (revision 229389) +++ sys/net/if.h (working copy) @@ -330,6 +330,7 @@ caddr_t ifru_data; int ifru_cap[2]; u_int ifru_fib; + u_char ifru_vlan_pcp; } ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ @@ -347,6 +348,7 @@ #define ifr_curcap ifr_ifru.ifru_cap[1] /* current capabilities */ #define ifr_index ifr_ifru.ifru_index /* interface index */ #define ifr_fib ifr_ifru.ifru_fib /* interface fib */ +#define ifr_vlan_pcp ifr_ifru.ifru_vlan_pcp /* VLAN priority */ }; #define _SIZEOF_ADDR_IFREQ(ifr) \ Index: sys/net/if_vlan_var.h =================================================================== --- sys/net/if_vlan_var.h (revision 229389) +++ sys/net/if_vlan_var.h (working copy) @@ -81,6 +81,9 @@ /* * Configuration structure for SIOCSETVLAN and SIOCGETVLAN ioctls. + * + * XXXRW: Note that despite being named vlr_tag, the field below should really + * be named vlr_vid. */ struct vlanreq { char vlr_parent[IFNAMSIZ]; @@ -89,6 +92,9 @@ #define SIOCSETVLAN SIOCSIFGENERIC #define SIOCGETVLAN SIOCGIFGENERIC +#define SIOCGVLANPCP _IOWR('i', 152, struct ifreq) /* Get VLAN PCP */ +#define SIOCSVLANPCP _IOW('i', 153, struct ifreq) /* Set VLAN PCP */ + #ifdef _KERNEL /* * Drivers that are capable of adding and removing the VLAN header @@ -133,20 +139,20 @@ #define VLAN_TRUNKDEV(_ifp) \ (_ifp)->if_type == IFT_L2VLAN ? (*vlan_trunkdev_p)((_ifp)) : NULL -#define VLAN_TAG(_ifp, _tag) \ - (_ifp)->if_type == IFT_L2VLAN ? (*vlan_tag_p)((_ifp), (_tag)) : EINVAL +#define VLAN_VID(_ifp, _vid) \ + (_ifp)->if_type == IFT_L2VLAN ? (*vlan_vid_p)((_ifp), (_vid)) : EINVAL #define VLAN_COOKIE(_ifp) \ (_ifp)->if_type == IFT_L2VLAN ? (*vlan_cookie_p)((_ifp)) : NULL #define VLAN_SETCOOKIE(_ifp, _cookie) \ (_ifp)->if_type == IFT_L2VLAN ? \ (*vlan_setcookie_p)((_ifp), (_cookie)) : EINVAL -#define VLAN_DEVAT(_ifp, _tag) \ - (_ifp)->if_vlantrunk != NULL ? (*vlan_devat_p)((_ifp), (_tag)) : NULL +#define VLAN_DEVAT(_ifp, _vid) \ + (_ifp)->if_vlantrunk != NULL ? (*vlan_devat_p)((_ifp), (_vid)) : NULL extern void (*vlan_trunk_cap_p)(struct ifnet *); extern struct ifnet *(*vlan_trunkdev_p)(struct ifnet *); extern struct ifnet *(*vlan_devat_p)(struct ifnet *, uint16_t); -extern int (*vlan_tag_p)(struct ifnet *, uint16_t *); +extern int (*vlan_vid_p)(struct ifnet *, uint16_t *); extern int (*vlan_setcookie_p)(struct ifnet *, void *); extern void *(*vlan_cookie_p)(struct ifnet *); Index: sys/net/if_vlan.c =================================================================== --- sys/net/if_vlan.c (revision 229389) +++ sys/net/if_vlan.c (working copy) @@ -1,6 +1,10 @@ /*- * Copyright 1998 Massachusetts Institute of Technology + * Copyright 2012 ADARA Networks, Inc. * + * Portions of this software were developed by Robert N. M. Watson under + * contract to ADARA Networks, Inc. + * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby * granted, provided that both the above copyright notice and this @@ -50,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +113,15 @@ uint16_t ifvm_proto; /* encapsulation ethertype */ uint16_t ifvm_tag; /* tag to apply on packets leaving if */ } ifv_mib; + + /* + * These fields are authoritative configuration state; ifvm_tag caches + * a precomputed tag to use during packet generation. Currently, the + * CFI bit is always set to 0; we may want to change this at some + * point. + */ + uint16_t ifv_vid; /* VLAN Identifier (VID). */ + uint8_t ifv_pcp; /* Priority Code Point (PCP). */ SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead; #ifndef VLAN_ARRAY LIST_ENTRY(ifvlan) ifv_list; @@ -178,7 +192,7 @@ static int vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv); static void vlan_growhash(struct ifvlantrunk *trunk, int howmuch); static __inline struct ifvlan * vlan_gethash(struct ifvlantrunk *trunk, - uint16_t tag); + uint16_t vid); #endif static void trunk_destroy(struct ifvlantrunk *trunk); @@ -198,7 +212,7 @@ static void vlan_capabilities(struct ifvlan *ifv); static void vlan_trunk_capabilities(struct ifnet *ifp); -static struct ifnet *vlan_clone_match_ethertag(struct if_clone *, +static struct ifnet *vlan_clone_match_ethervid(struct if_clone *, const char *, int *); static int vlan_clone_match(struct if_clone *, const char *); static int vlan_clone_create(struct if_clone *, char *, size_t, caddr_t); @@ -266,9 +280,9 @@ KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); b = 1 << trunk->hwidth; - i = HASH(ifv->ifv_tag, trunk->hmask); + i = HASH(ifv->ifv_vid, trunk->hmask); LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) - if (ifv->ifv_tag == ifv2->ifv_tag) + if (ifv->ifv_vid == ifv2->ifv_vid) return (EEXIST); /* @@ -278,7 +292,7 @@ */ if (trunk->refcnt > (b * b) / 2) { vlan_growhash(trunk, 1); - i = HASH(ifv->ifv_tag, trunk->hmask); + i = HASH(ifv->ifv_vid, trunk->hmask); } LIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list); trunk->refcnt++; @@ -296,7 +310,7 @@ KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); b = 1 << trunk->hwidth; - i = HASH(ifv->ifv_tag, trunk->hmask); + i = HASH(ifv->ifv_vid, trunk->hmask); LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) if (ifv2 == ifv) { trunk->refcnt--; @@ -348,7 +362,7 @@ for (i = 0; i < n; i++) while ((ifv = LIST_FIRST(&trunk->hash[i])) != NULL) { LIST_REMOVE(ifv, ifv_list); - j = HASH(ifv->ifv_tag, n2 - 1); + j = HASH(ifv->ifv_vid, n2 - 1); LIST_INSERT_HEAD(&hash2[j], ifv, ifv_list); } free(trunk->hash, M_VLAN); @@ -362,14 +376,14 @@ } static __inline struct ifvlan * -vlan_gethash(struct ifvlantrunk *trunk, uint16_t tag) +vlan_gethash(struct ifvlantrunk *trunk, uint16_t vid) { struct ifvlan *ifv; TRUNK_LOCK_RASSERT(trunk); - LIST_FOREACH(ifv, &trunk->hash[HASH(tag, trunk->hmask)], ifv_list) - if (ifv->ifv_tag == tag) + LIST_FOREACH(ifv, &trunk->hash[HASH(vid, trunk->hmask)], ifv_list) + if (ifv->ifv_vid == vid) return (ifv); return (NULL); } @@ -393,19 +407,19 @@ #else static __inline struct ifvlan * -vlan_gethash(struct ifvlantrunk *trunk, uint16_t tag) +vlan_gethash(struct ifvlantrunk *trunk, uint16_t vid) { - return trunk->vlans[tag]; + return trunk->vlans[vid]; } static __inline int vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv) { - if (trunk->vlans[ifv->ifv_tag] != NULL) + if (trunk->vlans[ifv->ifv_vid] != NULL) return EEXIST; - trunk->vlans[ifv->ifv_tag] = ifv; + trunk->vlans[ifv->ifv_vid] = ifv; trunk->refcnt++; return (0); @@ -415,7 +429,7 @@ vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv) { - trunk->vlans[ifv->ifv_tag] = NULL; + trunk->vlans[ifv->ifv_vid] = NULL; trunk->refcnt--; return (0); @@ -598,6 +612,16 @@ } /* + * Recalculate the cached VLAN tag to apply to outgoing packets. + */ +static void +vlan_tag_recalculate(struct ifvlan *ifv) +{ + + ifv->ifv_tag = EVL_MAKETAG(ifv->ifv_vid, ifv->ifv_pcp, 0); +} + +/* * Return the trunk device for a virtual interface. */ static struct ifnet * @@ -617,17 +641,18 @@ } /* - * Return the 16bit vlan tag for this interface. + * Return the 12-bit VLAN VID for this interface, for use in external + * components such as Infiniband. */ static int -vlan_tag(struct ifnet *ifp, uint16_t *tagp) +vlan_vid(struct ifnet *ifp, uint16_t *vidp) { struct ifvlan *ifv; if (ifp->if_type != IFT_L2VLAN) return (EINVAL); ifv = ifp->if_softc; - *tagp = ifv->ifv_tag; + *vidp = ifv->ifv_vid; return (0); } @@ -663,10 +688,10 @@ } /* - * Return the vlan device present at the specific tag. + * Return the vlan device present at the specific VID. */ static struct ifnet * -vlan_devat(struct ifnet *ifp, uint16_t tag) +vlan_devat(struct ifnet *ifp, uint16_t vid) { struct ifvlantrunk *trunk; struct ifvlan *ifv; @@ -676,7 +701,7 @@ return (NULL); ifp = NULL; TRUNK_RLOCK(trunk); - ifv = vlan_gethash(trunk, tag); + ifv = vlan_gethash(trunk, vid); if (ifv) ifp = ifv->ifv_ifp; TRUNK_RUNLOCK(trunk); @@ -716,7 +741,7 @@ vlan_trunkdev_p = vlan_trunkdev; vlan_cookie_p = vlan_cookie; vlan_setcookie_p = vlan_setcookie; - vlan_tag_p = vlan_tag; + vlan_vid_p = vlan_vid; vlan_devat_p = vlan_devat; #ifndef VIMAGE if_clone_attach(&vlan_cloner); @@ -741,7 +766,7 @@ vlan_link_state_p = NULL; vlan_trunk_cap_p = NULL; vlan_trunkdev_p = NULL; - vlan_tag_p = NULL; + vlan_vid_p = NULL; vlan_cookie_p = vlan_cookie; vlan_setcookie_p = vlan_setcookie; vlan_devat_p = NULL; @@ -786,7 +811,7 @@ #endif static struct ifnet * -vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag) +vlan_clone_match_ethervid(struct if_clone *ifc, const char *name, int *vid) { const char *cp; struct ifnet *ifp; @@ -814,8 +839,8 @@ t = (t * 10) + (*cp - '0'); if (*cp != '\0') continue; - if (tag != NULL) - *tag = t; + if (vid != NULL) + *vid = t; break; } IFNET_RUNLOCK_NOSLEEP(); @@ -828,7 +853,7 @@ { const char *cp; - if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL) + if (vlan_clone_match_ethervid(ifc, name, NULL) != NULL) return (1); if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0) @@ -848,7 +873,7 @@ int wildcard; int unit; int error; - int tag; + int vid; int ethertag; struct ifvlan *ifv; struct ifnet *ifp; @@ -866,6 +891,9 @@ * must be configured separately. * The first technique is preferred; the latter two are * supported for backwards compatibilty. + * + * XXXRW: Note historic use of the word "tag" here. New ioctls may + * be called for. */ if (params) { error = copyin(params, &vlr, sizeof(vlr)); @@ -875,7 +903,7 @@ if (p == NULL) return ENXIO; /* - * Don't let the caller set up a VLAN tag with + * Don't let the caller set up a VLAN ID with * anything except VLID bits. */ if (vlr.vlr_tag & ~EVL_VLID_MASK) @@ -885,18 +913,18 @@ return (error); ethertag = 1; - tag = vlr.vlr_tag; + vid = vlr.vlr_tag; wildcard = (unit < 0); - } else if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) { + } else if ((p = vlan_clone_match_ethervid(ifc, name, &vid)) != NULL) { ethertag = 1; unit = -1; wildcard = 0; /* - * Don't let the caller set up a VLAN tag with + * Don't let the caller set up a VLAN ID with * anything except VLID bits. */ - if (tag & ~EVL_VLID_MASK) + if (vid & ~EVL_VLID_MASK) return (EINVAL); } else { ethertag = 0; @@ -958,7 +986,7 @@ sdl->sdl_type = IFT_L2VLAN; if (ethertag) { - error = vlan_config(ifv, p, tag); + error = vlan_config(ifv, p, vid); if (error != 0) { /* * Since we've partialy failed, we need to back @@ -1105,7 +1133,7 @@ { struct ifvlantrunk *trunk = ifp->if_vlantrunk; struct ifvlan *ifv; - uint16_t tag; + uint16_t vid; KASSERT(trunk != NULL, ("%s: no trunk", __func__)); @@ -1114,7 +1142,7 @@ * Packet is tagged, but m contains a normal * Ethernet frame; the tag is stored out-of-band. */ - tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); + vid = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); m->m_flags &= ~M_VLANTAG; } else { struct ether_vlan_header *evl; @@ -1130,7 +1158,7 @@ return; } evl = mtod(m, struct ether_vlan_header *); - tag = EVL_VLANOFTAG(ntohs(evl->evl_tag)); + vid = EVL_VLANOFTAG(ntohs(evl->evl_tag)); /* * Remove the 802.1q header by copying the Ethernet @@ -1155,7 +1183,7 @@ } TRUNK_RLOCK(trunk); - ifv = vlan_gethash(trunk, tag); + ifv = vlan_gethash(trunk, vid); if (ifv == NULL || !UP_AND_RUNNING(ifv->ifv_ifp)) { TRUNK_RUNLOCK(trunk); m_freem(m); @@ -1172,14 +1200,14 @@ } static int -vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag) +vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid) { struct ifvlantrunk *trunk; struct ifnet *ifp; int error = 0; /* VID numbers 0x0 and 0xFFF are reserved */ - if (tag == 0 || tag == 0xFFF) + if (vid == 0 || vid == 0xFFF) return (EINVAL); if (p->if_type != IFT_ETHER && (p->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) @@ -1211,7 +1239,10 @@ TRUNK_LOCK(trunk); } - ifv->ifv_tag = tag; /* must set this before vlan_inshash() */ + ifv->ifv_vid = vid; /* must set this before vlan_inshash() */ + ifv->ifv_pcp = 0; /* Default: best effort delivery. */ + vlan_tag_recalculate(ifv); + error = vlan_inshash(trunk, ifv); if (error) goto done; @@ -1289,7 +1320,7 @@ done: TRUNK_UNLOCK(trunk); if (error == 0) - EVENTHANDLER_INVOKE(vlan_config, p, ifv->ifv_tag); + EVENTHANDLER_INVOKE(vlan_config, p, ifv->ifv_vid); VLAN_UNLOCK(); return (error); @@ -1377,7 +1408,7 @@ * to cleanup anyway. */ if (parent != NULL) - EVENTHANDLER_INVOKE(vlan_unconfig, parent, ifv->ifv_tag); + EVENTHANDLER_INVOKE(vlan_unconfig, parent, ifv->ifv_vid); } /* Handle a reference counted flag that should be set on the parent as well */ @@ -1615,7 +1646,7 @@ break; } /* - * Don't let the caller set up a VLAN tag with + * Don't let the caller set up a VLAN ID with * anything except VLID bits. */ if (vlr.vlr_tag & ~EVL_VLID_MASK) { @@ -1642,7 +1673,7 @@ if (TRUNK(ifv) != NULL) { strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname, sizeof(vlr.vlr_parent)); - vlr.vlr_tag = ifv->ifv_tag; + vlr.vlr_tag = ifv->ifv_vid; } VLAN_UNLOCK(); error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); @@ -1667,6 +1698,34 @@ error = vlan_setmulti(ifp); break; + case SIOCGVLANPCP: +#ifdef VIMAGE + if (ifp->if_vnet != ifp->if_home_vnet) { + error = EPERM; + break; + } +#endif + ifr->ifr_vlan_pcp = ifv->ifv_pcp; + break; + + case SIOCSVLANPCP: +#ifdef VIMAGE + if (ifp->if_vnet != ifp->if_home_vnet) { + error = EPERM; + break; + } +#endif + error = priv_check(curthread, PRIV_NET_SETVLANPCP); + if (error) + break; + if (ifr->ifr_vlan_pcp > 7) { + error = EINVAL; + break; + } + ifv->ifv_pcp = ifr->ifr_vlan_pcp; + vlan_tag_recalculate(ifv); + break; + default: error = EINVAL; break; Index: sys/sys/priv.h =================================================================== --- sys/sys/priv.h (revision 229389) +++ sys/sys/priv.h (working copy) @@ -338,6 +338,7 @@ #define PRIV_NET_SETIFVNET 417 /* Move interface to vnet. */ #define PRIV_NET_SETIFDESCR 418 /* Set interface description. */ #define PRIV_NET_SETIFFIB 419 /* Set interface fib. */ +#define PRIV_NET_SETVLANPCP 420 /* Set VLAN priority. */ /* * 802.11-related privileges. Index: sbin/ifconfig/ifconfig.8 =================================================================== --- sbin/ifconfig/ifconfig.8 (revision 229518) +++ sbin/ifconfig/ifconfig.8 (working copy) @@ -2375,9 +2375,9 @@ .Xr vlan 4 interfaces: .Bl -tag -width indent -.It Cm vlan Ar vlan_tag -Set the VLAN tag value to -.Ar vlan_tag . +.It Cm vlan Ar vid +Set the VLAN VID value to +.Ar vid . This value is a 12-bit VLAN Identifier (VID) which is used to create an 802.1Q VLAN header for packets sent from the .Xr vlan 4 @@ -2444,6 +2444,17 @@ The .Ar iface argument is useless and hence deprecated. +.It Cm vlanprio Ar prio +Set the VLAN priority to +.Ar prio . +This value is a 3-bit number used to set the PCP field in an 802.1Q VLAN +header for packets sent from the +.Xr vlan 4 +interface. +Interfaces default to a priority of 0 when created, selecting best-effort +delivery. +Values between 1 and 7 may also be used, with 1 selecting lowest +priority, and 7 highest. .El .Pp The following parameters are used to configure Index: sbin/ifconfig/ifvlan.c =================================================================== --- sbin/ifconfig/ifvlan.c (revision 229389) +++ sbin/ifconfig/ifvlan.c (working copy) @@ -79,10 +79,14 @@ { struct vlanreq vreq; - if (getvlan(s, &ifr, &vreq) != -1) - printf("\tvlan: %d parent interface: %s\n", - vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ? - "" : vreq.vlr_parent); + if (getvlan(s, &ifr, &vreq) == -1) + return; + printf("\tvlan: %d", vreq.vlr_tag); + if (ioctl(s, SIOCGVLANPCP, (caddr_t)&ifr) != -1) + printf(" vlanprio: %u", ifr.ifr_vlan_pcp); + printf(" parent interface: %s", vreq.vlr_parent[0] == '\0' ? + "" : vreq.vlr_parent); + printf("\n"); } static void @@ -93,7 +97,7 @@ * One or both parameters were specified, make sure both. */ if (params.vlr_tag == NOTAG) - errx(1, "must specify a tag for vlan create"); + errx(1, "must specify a VID for vlan create"); if (params.vlr_parent[0] == '\0') errx(1, "must specify a parent device for vlan create"); ifr->ifr_data = (caddr_t) ¶ms; @@ -120,7 +124,7 @@ } static -DECL_CMD_FUNC(setvlantag, val, d) +DECL_CMD_FUNC(setvlanvid, val, d) { struct vlanreq vreq; u_long ul; @@ -150,6 +154,22 @@ } static +DECL_CMD_FUNC(setvlanprio, val, d) +{ + u_long ul; + char *endp; + + ul = strtoul(val, &endp, 0); + if (*endp != '\0') + errx(1, "invalid value for vlanprio"); + if (ul > 7) + errx(1, "value for vlanprio out of range"); + ifr.ifr_vlan_pcp = ul; + if (ioctl(s, SIOCSVLANPCP, (caddr_t)&ifr) == -1) + err(1, "SIOCSVLANPCP"); +} + +static DECL_CMD_FUNC(unsetvlandev, val, d) { struct vlanreq vreq; @@ -168,11 +188,12 @@ } static struct cmd vlan_cmds[] = { - DEF_CLONE_CMD_ARG("vlan", setvlantag), + DEF_CLONE_CMD_ARG("vlan", setvlanvid), DEF_CLONE_CMD_ARG("vlandev", setvlandev), /* NB: non-clone cmds */ - DEF_CMD_ARG("vlan", setvlantag), + DEF_CMD_ARG("vlan", setvlanvid), DEF_CMD_ARG("vlandev", setvlandev), + DEF_CMD_ARG("vlanprio", setvlanprio), /* XXX For compatibility. Should become DEF_CMD() some day. */ DEF_CMD_OPTARG("-vlandev", unsetvlandev), DEF_CMD("vlanmtu", IFCAP_VLAN_MTU, setifcap),