Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108374264
D26436.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
26 KB
Referenced Files
None
Subscribers
None
D26436.diff
View Options
Index: head/sbin/ifconfig/ifclone.c
===================================================================
--- head/sbin/ifconfig/ifclone.c
+++ head/sbin/ifconfig/ifclone.c
@@ -49,6 +49,11 @@
#include "ifconfig.h"
+typedef enum {
+ MT_PREFIX,
+ MT_FILTER,
+} clone_match_type;
+
static void
list_cloners(void)
{
@@ -76,7 +81,11 @@
}
struct clone_defcb {
- char ifprefix[IFNAMSIZ];
+ union {
+ char ifprefix[IFNAMSIZ];
+ clone_match_func *ifmatch;
+ };
+ clone_match_type clone_mt;
clone_callback_func *clone_cb;
SLIST_ENTRY(clone_defcb) next;
};
@@ -85,16 +94,29 @@
SLIST_HEAD_INITIALIZER(clone_defcbh);
void
-clone_setdefcallback(const char *ifprefix, clone_callback_func *p)
+clone_setdefcallback_prefix(const char *ifprefix, clone_callback_func *p)
{
struct clone_defcb *dcp;
dcp = malloc(sizeof(*dcp));
strlcpy(dcp->ifprefix, ifprefix, IFNAMSIZ-1);
+ dcp->clone_mt = MT_PREFIX;
dcp->clone_cb = p;
SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
}
+void
+clone_setdefcallback_filter(clone_match_func *filter, clone_callback_func *p)
+{
+ struct clone_defcb *dcp;
+
+ dcp = malloc(sizeof(*dcp));
+ dcp->ifmatch = filter;
+ dcp->clone_mt = MT_FILTER;
+ dcp->clone_cb = p;
+ SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
+}
+
/*
* Do the actual clone operation. Any parameters must have been
* setup by now. If a callback has been setup to do the work
@@ -114,8 +136,14 @@
if (clone_cb == NULL) {
/* Try to find a default callback */
SLIST_FOREACH(dcp, &clone_defcbh, next) {
- if (strncmp(dcp->ifprefix, ifr.ifr_name,
- strlen(dcp->ifprefix)) == 0) {
+ if ((dcp->clone_mt == MT_PREFIX) &&
+ (strncmp(dcp->ifprefix, ifr.ifr_name,
+ strlen(dcp->ifprefix)) == 0)) {
+ clone_cb = dcp->clone_cb;
+ break;
+ }
+ if ((dcp->clone_mt == MT_FILTER) &&
+ dcp->ifmatch(ifr.ifr_name)) {
clone_cb = dcp->clone_cb;
break;
}
Index: head/sbin/ifconfig/ifconfig.h
===================================================================
--- head/sbin/ifconfig/ifconfig.h
+++ head/sbin/ifconfig/ifconfig.h
@@ -145,8 +145,10 @@
void ifmaybeload(const char *name);
+typedef int clone_match_func(const char *);
typedef void clone_callback_func(int, struct ifreq *);
-void clone_setdefcallback(const char *, clone_callback_func *);
+void clone_setdefcallback_prefix(const char *, clone_callback_func *);
+void clone_setdefcallback_filter(clone_match_func *, clone_callback_func *);
void sfp_status(int s, struct ifreq *ifr, int verbose);
Index: head/sbin/ifconfig/ifconfig.8
===================================================================
--- head/sbin/ifconfig/ifconfig.8
+++ head/sbin/ifconfig/ifconfig.8
@@ -582,7 +582,7 @@
is a synonym for enabling all available WOL mechanisms.
To disable WOL use
.Fl wol .
-.It Cm vlanmtu , vlanhwtag, vlanhwfilter, vlanhwcsum, vlanhwtso
+.It Cm vlanmtu , vlanhwtag , vlanhwfilter , vlanhwcsum , vlanhwtso
If the driver offers user-configurable VLAN support, enable
reception of extended frames, tag processing in hardware,
frame filtering in hardware, checksum offloading, or TSO on VLAN,
@@ -592,7 +592,7 @@
not on a
.Xr vlan 4
interface itself.
-.It Fl vlanmtu , vlanhwtag , vlanhwfilter , vlanhwtso
+.It Fl vlanmtu , vlanhwtag, vlanhwfilter, vlanhwtso
If the driver offers user-configurable VLAN support, disable
reception of extended frames, tag processing in hardware,
frame filtering in hardware, or TSO on VLAN,
@@ -2696,7 +2696,7 @@
Set the VLAN tag value to
.Ar vlan_tag .
This value is a 12-bit VLAN Identifier (VID) which is used to create an 802.1Q
-VLAN header for packets sent from the
+or 802.1ad VLAN header for packets sent from the
.Xr vlan 4
interface.
Note that
@@ -2704,6 +2704,15 @@
and
.Cm vlandev
must both be set at the same time.
+.It Cm vlanproto Ar vlan_proto
+Set the VLAN encapsulation protocol to
+.Ar vlan_proto .
+Supported encapsulation protocols are currently
+.Dq 802.1Q
+and
+.Dq 802.1ad .
+The default encapsulation protocol is
+.Dq 802.1Q .
.It Cm vlanpcp Ar priority_code_point
Priority code point
.Pq Dv PCP
Index: head/sbin/ifconfig/ifieee80211.c
===================================================================
--- head/sbin/ifconfig/ifieee80211.c
+++ head/sbin/ifconfig/ifieee80211.c
@@ -6069,5 +6069,5 @@
for (i = 0; i < nitems(ieee80211_cmds); i++)
cmd_register(&ieee80211_cmds[i]);
af_register(&af_ieee80211);
- clone_setdefcallback("wlan", wlan_create);
+ clone_setdefcallback_prefix("wlan", wlan_create);
}
Index: head/sbin/ifconfig/ifvlan.c
===================================================================
--- head/sbin/ifconfig/ifvlan.c
+++ head/sbin/ifconfig/ifvlan.c
@@ -66,8 +66,12 @@
#define NOTAG ((u_short) -1)
+static const char proto_8021Q[] = "802.1q";
+static const char proto_8021ad[] = "802.1ad";
+
static struct vlanreq params = {
.vlr_tag = NOTAG,
+ .vlr_proto = ETHERTYPE_VLAN,
};
static int
@@ -87,6 +91,17 @@
if (getvlan(s, &ifr, &vreq) == -1)
return;
printf("\tvlan: %d", vreq.vlr_tag);
+ printf(" vlanproto: ");
+ switch (vreq.vlr_proto) {
+ case ETHERTYPE_VLAN:
+ printf(proto_8021Q);
+ break;
+ case ETHERTYPE_QINQ:
+ printf(proto_8021ad);
+ break;
+ default:
+ printf("0x%04x", vreq.vlr_proto);
+ }
if (ioctl(s, SIOCGVLANPCP, (caddr_t)&ifr) != -1)
printf(" vlanpcp: %u", ifr.ifr_vlan_pcp);
printf(" parent interface: %s", vreq.vlr_parent[0] == '\0' ?
@@ -94,9 +109,49 @@
printf("\n");
}
+static int
+vlan_match_ethervid(const char *name)
+{
+ return (strchr(name, '.') != NULL);
+}
+
static void
+vlan_parse_ethervid(const char *name)
+{
+ char ifname[IFNAMSIZ];
+ char *cp;
+ int vid;
+
+ strlcpy(ifname, name, IFNAMSIZ);
+ if ((cp = strrchr(ifname, '.')) == NULL)
+ return;
+ /*
+ * Don't mix vlan/vlandev parameters with dot notation.
+ */
+ if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0')
+ errx(1, "ambiguous vlan specification");
+ /*
+ * Derive params from interface name: "parent.vid".
+ */
+ *cp++ = '\0';
+ if ((*cp < '1') || (*cp > '9'))
+ errx(1, "invalid vlan tag");
+
+ vid = *cp++ - '0';
+ while ((*cp >= '0') && (*cp <= '9'))
+ vid = (vid * 10) + (*cp++ - '0');
+ if ((*cp != '\0') || (vid & ~0xFFF))
+ errx(1, "invalid vlan tag");
+
+ strlcpy(params.vlr_parent, ifname, IFNAMSIZ);
+ params.vlr_tag = (vid & 0xFFF);
+}
+
+static void
vlan_create(int s, struct ifreq *ifr)
{
+ vlan_parse_ethervid(ifr->ifr_name);
+
if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') {
/*
* One or both parameters were specified, make sure both.
@@ -159,6 +214,24 @@
}
static
+DECL_CMD_FUNC(setvlanproto, val, d)
+{
+ struct vlanreq vreq;
+
+ if (strncasecmp(proto_8021Q, val,
+ strlen(proto_8021Q)) == 0) {
+ params.vlr_proto = ETHERTYPE_VLAN;
+ } else if (strncasecmp(proto_8021ad, val,
+ strlen(proto_8021ad)) == 0) {
+ params.vlr_proto = ETHERTYPE_QINQ;
+ } else
+ errx(1, "invalid value for vlanproto");
+
+ if (getvlan(s, &ifr, &vreq) != -1)
+ vlan_set(s, &ifr);
+}
+
+static
DECL_CMD_FUNC(setvlanpcp, val, d)
{
u_long ul;
@@ -195,10 +268,12 @@
static struct cmd vlan_cmds[] = {
DEF_CLONE_CMD_ARG("vlan", setvlantag),
DEF_CLONE_CMD_ARG("vlandev", setvlandev),
+ DEF_CLONE_CMD_ARG("vlanproto", setvlanproto),
DEF_CMD_ARG("vlanpcp", setvlanpcp),
/* NB: non-clone cmds */
DEF_CMD_ARG("vlan", setvlantag),
DEF_CMD_ARG("vlandev", setvlandev),
+ DEF_CMD_ARG("vlanproto", setvlanproto),
/* XXX For compatibility. Should become DEF_CMD() some day. */
DEF_CMD_OPTARG("-vlandev", unsetvlandev),
DEF_CMD("vlanmtu", IFCAP_VLAN_MTU, setifcap),
@@ -227,5 +302,6 @@
cmd_register(&vlan_cmds[i]);
af_register(&af_vlan);
callback_register(vlan_cb, NULL);
- clone_setdefcallback("vlan", vlan_create);
+ clone_setdefcallback_prefix("vlan", vlan_create);
+ clone_setdefcallback_filter(vlan_match_ethervid, vlan_create);
}
Index: head/sbin/ifconfig/ifvxlan.c
===================================================================
--- head/sbin/ifconfig/ifvxlan.c
+++ head/sbin/ifconfig/ifvxlan.c
@@ -642,5 +642,5 @@
cmd_register(&vxlan_cmds[i]);
af_register(&af_vxlan);
callback_register(vxlan_cb, NULL);
- clone_setdefcallback("vxlan", vxlan_create);
+ clone_setdefcallback_prefix("vxlan", vxlan_create);
}
Index: head/sys/net/ethernet.h
===================================================================
--- head/sys/net/ethernet.h
+++ head/sys/net/ethernet.h
@@ -428,6 +428,7 @@
struct route;
struct sockaddr;
struct bpf_if;
+struct ether_8021q_tag;
extern uint32_t ether_crc32_le(const uint8_t *, size_t);
extern uint32_t ether_crc32_be(const uint8_t *, size_t);
@@ -441,10 +442,16 @@
extern char *ether_sprintf(const u_int8_t *);
void ether_vlan_mtap(struct bpf_if *, struct mbuf *,
void *, u_int);
-struct mbuf *ether_vlanencap(struct mbuf *, uint16_t);
-bool ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p,
- uint16_t vid, uint8_t pcp);
+struct mbuf *ether_vlanencap_proto(struct mbuf *, uint16_t, uint16_t);
+bool ether_8021q_frame(struct mbuf **mp, struct ifnet *ife,
+ struct ifnet *p, struct ether_8021q_tag *);
void ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr);
+
+static __inline struct mbuf *ether_vlanencap(struct mbuf *m, uint16_t tag)
+{
+
+ return ether_vlanencap_proto(m, tag, ETHERTYPE_VLAN);
+}
/* new ethernet interface attached event */
typedef void (*ether_ifattach_event_handler_t)(void *, struct ifnet *);
Index: head/sys/net/if_clone.c
===================================================================
--- head/sys/net/if_clone.c
+++ head/sys/net/if_clone.c
@@ -571,7 +571,7 @@
/*
* A utility function to extract unit numbers from interface names of
- * the form name###.
+ * the form name###[.###].
*
* Returns 0 on success and an error on failure.
*/
@@ -582,7 +582,9 @@
int cutoff = INT_MAX / 10;
int cutlim = INT_MAX % 10;
- for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++);
+ if ((cp = strrchr(name, '.')) == NULL)
+ cp = name;
+ for (; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++);
if (*cp == '\0') {
*unit = -1;
} else if (cp[0] == '0' && cp[1] != '\0') {
Index: head/sys/net/if_ethersubr.c
===================================================================
--- head/sys/net/if_ethersubr.c
+++ head/sys/net/if_ethersubr.c
@@ -441,12 +441,19 @@
static bool
ether_set_pcp(struct mbuf **mp, struct ifnet *ifp, uint8_t pcp)
{
+ struct ether_8021q_tag qtag;
struct ether_header *eh;
eh = mtod(*mp, struct ether_header *);
if (ntohs(eh->ether_type) == ETHERTYPE_VLAN ||
- ether_8021q_frame(mp, ifp, ifp, 0, pcp))
+ ntohs(eh->ether_type) == ETHERTYPE_QINQ)
return (true);
+
+ qtag.vid = 0;
+ qtag.pcp = pcp;
+ qtag.proto = ETHERTYPE_VLAN;
+ if (ether_8021q_frame(mp, ifp, ifp, &qtag))
+ return (true);
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
return (false);
}
@@ -616,9 +623,9 @@
* If the hardware did not process an 802.1Q tag, do this now,
* to allow 802.1P priority frames to be passed to the main input
* path correctly.
- * TODO: Deal with Q-in-Q frames, but not arbitrary nesting levels.
*/
- if ((m->m_flags & M_VLANTAG) == 0 && etype == ETHERTYPE_VLAN) {
+ if ((m->m_flags & M_VLANTAG) == 0 &&
+ ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ))) {
struct ether_vlan_header *evl;
if (m->m_len < sizeof(*evl) &&
@@ -1303,7 +1310,7 @@
}
struct mbuf *
-ether_vlanencap(struct mbuf *m, uint16_t tag)
+ether_vlanencap_proto(struct mbuf *m, uint16_t tag, uint16_t proto)
{
struct ether_vlan_header *evl;
@@ -1325,7 +1332,7 @@
evl = mtod(m, struct ether_vlan_header *);
bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN,
(char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN);
- evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
+ evl->evl_encap_proto = htons(proto);
evl->evl_tag = htons(tag);
return (m);
}
@@ -1354,7 +1361,7 @@
bool
ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p,
- uint16_t vid, uint8_t pcp)
+ struct ether_8021q_tag *qtag)
{
struct m_tag *mtag;
int n;
@@ -1391,7 +1398,7 @@
* If PCP is set in mbuf, use it
*/
if ((*mp)->m_flags & M_VLANTAG) {
- pcp = EVL_PRIOFTAG((*mp)->m_pkthdr.ether_vtag);
+ qtag->pcp = EVL_PRIOFTAG((*mp)->m_pkthdr.ether_vtag);
}
/*
@@ -1403,14 +1410,15 @@
*/
if (vlan_mtag_pcp && (mtag = m_tag_locate(*mp, MTAG_8021Q,
MTAG_8021Q_PCP_OUT, NULL)) != NULL)
- tag = EVL_MAKETAG(vid, *(uint8_t *)(mtag + 1), 0);
+ tag = EVL_MAKETAG(qtag->vid, *(uint8_t *)(mtag + 1), 0);
else
- tag = EVL_MAKETAG(vid, pcp, 0);
- if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
+ tag = EVL_MAKETAG(qtag->vid, qtag->pcp, 0);
+ if ((p->if_capenable & IFCAP_VLAN_HWTAGGING) &&
+ (qtag->proto == ETHERTYPE_VLAN)) {
(*mp)->m_pkthdr.ether_vtag = tag;
(*mp)->m_flags |= M_VLANTAG;
} else {
- *mp = ether_vlanencap(*mp, tag);
+ *mp = ether_vlanencap_proto(*mp, tag, qtag->proto);
if (*mp == NULL) {
if_printf(ife, "unable to prepend 802.1Q header");
return (false);
Index: head/sys/net/if_vlan.c
===================================================================
--- head/sys/net/if_vlan.c
+++ head/sys/net/if_vlan.c
@@ -17,7 +17,7 @@
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
@@ -185,17 +185,17 @@
struct ifvlantrunk *ifv_trunk;
struct ifnet *ifv_ifp;
#define TRUNK(ifv) ((ifv)->ifv_trunk)
-#define PARENT(ifv) ((ifv)->ifv_trunk->parent)
+#define PARENT(ifv) (TRUNK(ifv)->parent)
void *ifv_cookie;
int ifv_pflags; /* special flags we have set on parent */
int ifv_capenable;
int ifv_encaplen; /* encapsulation length */
int ifv_mtufudge; /* MTU fudged by this much */
int ifv_mintu; /* min transmission unit */
- uint16_t ifv_proto; /* encapsulation ethertype */
- uint16_t ifv_tag; /* tag to apply on packets leaving if */
- uint16_t ifv_vid; /* VLAN ID */
- uint8_t ifv_pcp; /* Priority Code Point (PCP). */
+ struct ether_8021q_tag ifv_qtag;
+#define ifv_proto ifv_qtag.proto
+#define ifv_vid ifv_qtag.vid
+#define ifv_pcp ifv_qtag.pcp
struct task lladdr_task;
CK_SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead;
#ifndef VLAN_ARRAY
@@ -222,9 +222,9 @@
static eventhandler_tag iflladdr_tag;
/*
- * if_vlan uses two module-level synchronizations primitives to allow concurrent
- * modification of vlan interfaces and (mostly) allow for vlans to be destroyed
- * while they are being used for tx/rx. To accomplish this in a way that has
+ * if_vlan uses two module-level synchronizations primitives to allow concurrent
+ * modification of vlan interfaces and (mostly) allow for vlans to be destroyed
+ * while they are being used for tx/rx. To accomplish this in a way that has
* acceptable performance and cooperation with other parts of the network stack
* there is a non-sleepable epoch(9) and an sx(9).
*
@@ -244,7 +244,7 @@
static struct sx _VLAN_SX_ID;
#define VLAN_LOCKING_INIT() \
- sx_init(&_VLAN_SX_ID, "vlan_sx")
+ sx_init_flags(&_VLAN_SX_ID, "vlan_sx", SX_RECURSE)
#define VLAN_LOCKING_DESTROY() \
sx_destroy(&_VLAN_SX_ID)
@@ -306,7 +306,8 @@
const struct sockaddr *dst, struct route *ro);
static void vlan_unconfig(struct ifnet *ifp);
static void vlan_unconfig_locked(struct ifnet *ifp, int departing);
-static int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag);
+static int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag,
+ uint16_t proto);
static void vlan_link_state(struct ifnet *ifp);
static void vlan_capabilities(struct ifvlan *ifv);
static void vlan_trunk_capabilities(struct ifnet *ifp);
@@ -760,7 +761,7 @@
/*
* Return a driver specific cookie for this interface. Synchronization
- * with setcookie must be provided by the driver.
+ * with setcookie must be provided by the driver.
*/
static void *
vlan_cookie(struct ifnet *ifp)
@@ -811,16 +812,6 @@
}
/*
- * Recalculate the cached VLAN tag exposed via the MIB.
- */
-static void
-vlan_tag_recalculate(struct ifvlan *ifv)
-{
-
- ifv->ifv_tag = EVL_MAKETAG(ifv->ifv_vid, ifv->ifv_pcp, 0);
-}
-
-/*
* VLAN support can be loaded as a module. The only place in the
* system that's intimately aware of this is ether_input. We hook
* into this code through vlan_input_p which is defined there and
@@ -867,7 +858,7 @@
#else
"hash tables with chaining"
#endif
-
+
"\n");
break;
case MOD_UNLOAD:
@@ -926,7 +917,7 @@
#endif
/*
- * Check for <etherif>.<vlan> style interface names.
+ * Check for <etherif>.<vlan>[.<vlan> ...] style interface names.
*/
static struct ifnet *
vlan_clone_match_ethervid(const char *name, int *vidp)
@@ -937,7 +928,7 @@
int vid;
strlcpy(ifname, name, IFNAMSIZ);
- if ((cp = strchr(ifname, '.')) == NULL)
+ if ((cp = strrchr(ifname, '.')) == NULL)
return (NULL);
*cp = '\0';
if ((ifp = ifunit_ref(ifname)) == NULL)
@@ -990,6 +981,7 @@
int unit;
int error;
int vid;
+ uint16_t proto;
struct ifvlan *ifv;
struct ifnet *ifp;
struct ifnet *p;
@@ -998,14 +990,15 @@
struct vlanreq vlr;
static const u_char eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */
+ proto = ETHERTYPE_VLAN;
+
/*
- * There are 3 (ugh) ways to specify the cloned device:
+ * There are two ways to specify the cloned device:
* o pass a parameter block with the clone request.
- * o specify parameters in the text of the clone device name
* o specify no parameters and get an unattached device that
* must be configured separately.
- * The first technique is preferred; the latter two are
- * supported for backwards compatibility.
+ * The first technique is preferred; the latter is supported
+ * for backwards compatibility.
*
* XXXRW: Note historic use of the word "tag" here. New ioctls may be
* called for.
@@ -1023,10 +1016,8 @@
return (error);
}
vid = vlr.vlr_tag;
+ proto = vlr.vlr_proto;
wildcard = (unit < 0);
- } else if ((p = vlan_clone_match_ethervid(name, &vid)) != NULL) {
- unit = -1;
- wildcard = 0;
} else {
p = NULL;
error = ifc_name2unit(name, &unit);
@@ -1092,7 +1083,7 @@
sdl->sdl_type = IFT_L2VLAN;
if (p != NULL) {
- error = vlan_config(ifv, p, vid);
+ error = vlan_config(ifv, p, vid, proto);
if_rele(p);
if (error != 0) {
/*
@@ -1117,8 +1108,10 @@
vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
{
struct ifvlan *ifv = ifp->if_softc;
- int unit = ifp->if_dunit;
+ if (ifp->if_vlantrunk)
+ return (EBUSY);
+
ether_ifdetach(ifp); /* first, remove it from system-wide lists */
vlan_unconfig(ifp); /* now it can be unconfigured and freed */
/*
@@ -1130,7 +1123,7 @@
NET_EPOCH_WAIT();
if_free(ifp);
free(ifv, M_VLAN);
- ifc_free_unit(ifc, unit);
+ ifc_free_unit(ifc, ifp->if_dunit);
return (0);
}
@@ -1196,7 +1189,7 @@
return (ENETDOWN);
}
- if (!ether_8021q_frame(&m, ifp, p, ifv->ifv_vid, ifv->ifv_pcp)) {
+ if (!ether_8021q_frame(&m, ifp, p, &ifv->ifv_qtag)) {
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
return (0);
}
@@ -1223,12 +1216,19 @@
NET_EPOCH_ASSERT();
+ /*
+ * Find the first non-VLAN parent interface.
+ */
ifv = ifp->if_softc;
- if (TRUNK(ifv) == NULL) {
- m_freem(m);
- return (ENETDOWN);
- }
- p = PARENT(ifv);
+ do {
+ if (TRUNK(ifv) == NULL) {
+ m_freem(m);
+ return (ENETDOWN);
+ }
+ p = PARENT(ifv);
+ ifv = p->if_softc;
+ } while (p->if_type == IFT_L2VLAN);
+
return p->if_output(ifp, m, dst, ro);
}
@@ -1357,7 +1357,8 @@
}
static int
-vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid)
+vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid,
+ uint16_t proto)
{
struct epoch_tracker et;
struct ifvlantrunk *trunk;
@@ -1369,6 +1370,7 @@
* they handle the tagging and headers themselves.
*/
if (p->if_type != IFT_ETHER &&
+ p->if_type != IFT_L2VLAN &&
(p->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
return (EPROTONOSUPPORT);
if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS)
@@ -1400,11 +1402,10 @@
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;
- ifv->ifv_proto = ETHERTYPE_VLAN;
+ ifv->ifv_proto = proto;
ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
ifv->ifv_mintu = ETHERMIN;
ifv->ifv_pflags = 0;
@@ -1915,7 +1916,7 @@
break;
}
oldmtu = ifp->if_mtu;
- error = vlan_config(ifv, p, vlr.vlr_tag);
+ error = vlan_config(ifv, p, vlr.vlr_tag, vlr.vlr_proto);
if_rele(p);
/*
@@ -1943,11 +1944,12 @@
strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname,
sizeof(vlr.vlr_parent));
vlr.vlr_tag = ifv->ifv_vid;
+ vlr.vlr_proto = ifv->ifv_proto;
}
VLAN_SUNLOCK();
error = copyout(&vlr, ifr_data_get_ptr(ifr), sizeof(vlr));
break;
-
+
case SIOCSIFFLAGS:
/*
* We should propagate selected flags to the parent,
@@ -2001,7 +2003,6 @@
}
ifv->ifv_pcp = ifr->ifr_vlan_pcp;
ifp->if_pcp = ifv->ifv_pcp;
- vlan_tag_recalculate(ifv);
/* broadcast event about PCP change */
EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_PCP);
break;
Index: head/sys/net/if_vlan_var.h
===================================================================
--- head/sys/net/if_vlan_var.h
+++ head/sys/net/if_vlan_var.h
@@ -69,6 +69,7 @@
struct vlanreq {
char vlr_parent[IFNAMSIZ];
u_short vlr_tag;
+ u_short vlr_proto;
};
#define SIOCSETVLAN SIOCSIFGENERIC
#define SIOCGETVLAN SIOCGIFGENERIC
@@ -122,6 +123,15 @@
#define MTAG_8021Q 1326104895
#define MTAG_8021Q_PCP_IN 0 /* Input priority. */
#define MTAG_8021Q_PCP_OUT 1 /* Output priority. */
+
+/*
+ * 802.1q full tag. Proto and vid are stored in host byte order.
+ */
+struct ether_8021q_tag {
+ uint16_t proto;
+ uint16_t vid;
+ uint8_t pcp;
+};
#define VLAN_CAPABILITIES(_ifp) do { \
if ((_ifp)->if_vlantrunk != NULL) \
Index: head/tests/sys/net/if_vlan.sh
===================================================================
--- head/tests/sys/net/if_vlan.sh
+++ head/tests/sys/net/if_vlan.sh
@@ -36,7 +36,185 @@
vnet_cleanup
}
+# Simple Q-in-Q (802.1Q over 802.1ad)
+
+atf_test_case "qinq_simple" "cleanup"
+qinq_simple_head()
+{
+ atf_set descr 'Simple Q-in-Q test (802.1Q over 802.1ad)'
+ atf_set require.user root
+}
+
+qinq_simple_body()
+{
+ vnet_init
+
+ epair_qinq=$(vnet_mkepair)
+
+ vnet_mkjail jqinq0 ${epair_qinq}a
+ vnet_mkjail jqinq1 ${epair_qinq}b
+
+ vlan5a=$(jexec jqinq0 ifconfig vlan create \
+ vlandev ${epair_qinq}a vlan 5 vlanproto 802.1ad)
+ vlan42a=$(jexec jqinq0 ifconfig vlan create \
+ vlandev ${vlan5a} vlan 42 vlanproto 802.1q)
+ jexec jqinq0 ifconfig ${epair_qinq}a up
+ jexec jqinq0 ifconfig ${vlan5a} up
+ jexec jqinq0 ifconfig ${vlan42a} 10.5.42.1/24 up
+
+ vlan5b=$(jexec jqinq1 ifconfig vlan create \
+ vlandev ${epair_qinq}b vlan 5 vlanproto 802.1ad)
+ vlan42b=$(jexec jqinq1 ifconfig vlan create \
+ vlandev ${vlan5b} vlan 42 vlanproto 802.1q)
+ jexec jqinq1 ifconfig ${epair_qinq}b up
+ jexec jqinq1 ifconfig ${vlan5b} up
+ jexec jqinq1 ifconfig ${vlan42b} 10.5.42.2/24 up
+
+ atf_check -s exit:0 -o ignore jexec jqinq1 ping -c 1 10.5.42.1
+}
+
+qinq_simple_cleanup()
+{
+ vnet_cleanup
+}
+
+# Deep Q-in-Q (802.1Q over 802.1ad over 802.1ad)
+
+atf_test_case "qinq_deep" "cleanup"
+qinq_deep_head()
+{
+ atf_set descr 'Deep Q-in-Q test (802.1Q over 802.1ad over 802.1ad)'
+ atf_set require.user root
+}
+
+qinq_deep_body()
+{
+ vnet_init
+
+ epair_qinq=$(vnet_mkepair)
+
+ vnet_mkjail jqinq2 ${epair_qinq}a
+ vnet_mkjail jqinq3 ${epair_qinq}b
+
+ vlan5a=$(jexec jqinq2 ifconfig vlan create \
+ vlandev ${epair_qinq}a vlan 5 vlanproto 802.1ad)
+ vlan6a=$(jexec jqinq2 ifconfig vlan create \
+ vlandev ${vlan5a} vlan 6 vlanproto 802.1ad)
+ vlan42a=$(jexec jqinq2 ifconfig vlan create \
+ vlandev ${vlan6a} vlan 42 vlanproto 802.1q)
+ jexec jqinq2 ifconfig ${epair_qinq}a up
+ jexec jqinq2 ifconfig ${vlan5a} up
+ jexec jqinq2 ifconfig ${vlan6a} up
+ jexec jqinq2 ifconfig ${vlan42a} 10.6.42.1/24 up
+
+ vlan5b=$(jexec jqinq3 ifconfig vlan create \
+ vlandev ${epair_qinq}b vlan 5 vlanproto 802.1ad)
+ vlan6b=$(jexec jqinq3 ifconfig vlan create \
+ vlandev ${vlan5b} vlan 6 vlanproto 802.1ad)
+ vlan42b=$(jexec jqinq3 ifconfig vlan create \
+ vlandev ${vlan6b} vlan 42 vlanproto 802.1q)
+ jexec jqinq3 ifconfig ${epair_qinq}b up
+ jexec jqinq3 ifconfig ${vlan5b} up
+ jexec jqinq3 ifconfig ${vlan6b} up
+ jexec jqinq3 ifconfig ${vlan42b} 10.6.42.2/24 up
+
+ atf_check -s exit:0 -o ignore jexec jqinq3 ping -c 1 10.6.42.1
+}
+
+qinq_deep_cleanup()
+{
+ vnet_cleanup
+}
+
+# Legacy Q-in-Q (802.1Q over 802.1Q)
+
+atf_test_case "qinq_legacy" "cleanup"
+qinq_legacy_head()
+{
+ atf_set descr 'Legacy Q-in-Q test (802.1Q over 802.1Q)'
+ atf_set require.user root
+}
+
+qinq_legacy_body()
+{
+ vnet_init
+
+ epair_qinq=$(vnet_mkepair)
+
+ vnet_mkjail jqinq4 ${epair_qinq}a
+ vnet_mkjail jqinq5 ${epair_qinq}b
+
+ vlan5a=$(jexec jqinq4 ifconfig vlan create \
+ vlandev ${epair_qinq}a vlan 5)
+ vlan42a=$(jexec jqinq4 ifconfig vlan create \
+ vlandev ${vlan5a} vlan 42)
+ jexec jqinq4 ifconfig ${epair_qinq}a up
+ jexec jqinq4 ifconfig ${vlan5a} up
+ jexec jqinq4 ifconfig ${vlan42a} 10.5.42.1/24 up
+
+ vlan5b=$(jexec jqinq5 ifconfig vlan create \
+ vlandev ${epair_qinq}b vlan 5)
+ vlan42b=$(jexec jqinq5 ifconfig vlan create \
+ vlandev ${vlan5b} vlan 42)
+ jexec jqinq5 ifconfig ${epair_qinq}b up
+ jexec jqinq5 ifconfig ${vlan5b} up
+ jexec jqinq5 ifconfig ${vlan42b} 10.5.42.2/24 up
+
+ atf_check -s exit:0 -o ignore jexec jqinq5 ping -c 1 10.5.42.1
+}
+
+qinq_legacy_cleanup()
+{
+ vnet_cleanup
+}
+
+# Simple Q-in-Q with dot notation
+
+atf_test_case "qinq_dot" "cleanup"
+qinq_dot_head()
+{
+ atf_set descr 'Simple Q-in-Q test with dot notation'
+ atf_set require.user root
+}
+
+qinq_dot_body()
+{
+ vnet_init
+
+ epair_qinq=$(vnet_mkepair)
+
+ vnet_mkjail jqinq6 ${epair_qinq}a
+ vnet_mkjail jqinq7 ${epair_qinq}b
+
+ jexec jqinq6 ifconfig vlan5 create \
+ vlandev ${epair_qinq}a vlan 5 vlanproto 802.1ad
+ jexec jqinq6 ifconfig vlan5.42 create \
+ vlanproto 802.1q
+ jexec jqinq6 ifconfig ${epair_qinq}a up
+ jexec jqinq6 ifconfig vlan5 up
+ jexec jqinq6 ifconfig vlan5.42 10.5.42.1/24 up
+
+ vlan5b=$(jexec jqinq7 ifconfig vlan create \
+ vlandev ${epair_qinq}b vlan 5 vlanproto 802.1ad)
+ vlan42b=$(jexec jqinq7 ifconfig vlan create \
+ vlandev ${vlan5b} vlan 42 vlanproto 802.1q)
+ jexec jqinq7 ifconfig ${epair_qinq}b up
+ jexec jqinq7 ifconfig ${vlan5b} up
+ jexec jqinq7 ifconfig ${vlan42b} 10.5.42.2/24 up
+
+ atf_check -s exit:0 -o ignore jexec jqinq7 ping -c 1 10.5.42.1
+}
+
+qinq_dot_cleanup()
+{
+ vnet_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "basic"
+ atf_add_test_case "qinq_simple"
+ atf_add_test_case "qinq_deep"
+ atf_add_test_case "qinq_legacy"
+ atf_add_test_case "qinq_dot"
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 25, 6:43 AM (19 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16129032
Default Alt Text
D26436.diff (26 KB)
Attached To
Mode
D26436: Add support for stacked VLANs (IEEE 802.1ad, AKA Q-in-Q).
Attached
Detach File
Event Timeline
Log In to Comment