tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: bridges, vlans, and xen, oh my!
>> Conceptually, what I want is a vlan interface that selects for
>> untagged packets on input and does not add any tag on output
> I've been bugged by that in the past, too. [...]
> It should actually be very easy to do, I just never got around taking
> the time to do it.
It is easy. I have most of it working now. The only part that's
missing is some syntactic sugar in ifconfig; with what I have now, you
need to tell ifconfig "vlan 65535" to get an untagged-packets vlan.
(65535 is out of range; vlan tags run from 0 to 4095.)
Patches, relative to the 4.0 source tree, follow my signature. I think
I've got everything; if these don't work, let me know details and I'll
see if I missed something, or what.
/~\ The ASCII der Mouse
\ / Ribbon Campaign
X Against HTML mouse%rodents-montreal.org@localhost
/ \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
diff -u -r base/sys/net/if_ether.h new/sys/net/if_ether.h
--- base/sys/net/if_ether.h Thu Nov 23 20:04:30 2006
+++ new/sys/net/if_ether.h Sat Jun 21 00:42:49 2008
@@ -157,6 +157,7 @@
capabilities to enable */
int ec_nvlans; /* # VLANs on this interface */
+ int ec_untaggedvlan; /* "untagged" vlan configured */
#ifdef MBUFTRACE
struct mowner ec_rx_mowner; /* mbufs received */
struct mowner ec_tx_mowner; /* mbufs transmitted */
diff -u -r base/sys/net/if_ethersubr.c new/sys/net/if_ethersubr.c
--- base/sys/net/if_ethersubr.c Tue Feb 27 18:16:42 2007
+++ new/sys/net/if_ethersubr.c Sat Jun 21 00:42:50 2008
@@ -773,6 +773,20 @@
}
#endif /* NAGR > 0 */
+#if NVLAN > 0
+ /*
+ * If an untagged vlan is configured,
+ * vlan_input wants the packet regardless of etype.
+ *
+ * Note that nothing is ever "received" on the parent interface
+ * when an untagged vlan is configured.
+ */
+ if (((struct ethercom *)ifp)->ec_untaggedvlan) {
+ vlan_input(ifp,m);
+ return;
+ }
+#endif /* NVLAN > 0 */
+
/*
* Handle protocols that expect to have the Ethernet header
* (and possibly FCS) intact.
diff -u -r base/sys/net/if_vlan.c new/sys/net/if_vlan.c
--- base/sys/net/if_vlan.c Wed Nov 15 20:33:40 2006
+++ new/sys/net/if_vlan.c Sat Jun 21 00:43:50 2008
@@ -177,7 +177,7 @@
static int vlan_clone_create(struct if_clone *, int);
static int vlan_clone_destroy(struct ifnet *);
-static int vlan_config(struct ifvlan *, struct ifnet *);
+static int vlan_config(struct ifvlan *, struct ifnet *, u_int16_t);
static int vlan_ioctl(struct ifnet *, u_long, caddr_t);
static void vlan_start(struct ifnet *);
static void vlan_unconfig(struct ifnet *);
@@ -269,7 +269,7 @@
* Configure a VLAN interface. Must be called at splnet().
*/
static int
-vlan_config(struct ifvlan *ifv, struct ifnet *p)
+vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
{
struct ifnet *ifp = &ifv->ifv_if;
int error;
@@ -277,6 +277,8 @@
if (ifv->ifv_p != NULL)
return (EBUSY);
+ ifv->ifv_tag = tag;
+
switch (p->if_type) {
case IFT_ETHER:
{
@@ -286,6 +288,9 @@
ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
ifv->ifv_mintu = ETHERMIN;
+ if (tag == EVL_UNTAGGED)
+ ec->ec_untaggedvlan = 1;
+
/*
* If the parent supports the VLAN_MTU capability,
* i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
@@ -368,6 +373,7 @@
vlan_unconfig(struct ifnet *ifp)
{
struct ifvlan *ifv = ifp->if_softc;
+ struct ifvlan *ifv2;
if (ifv->ifv_p == NULL)
return;
@@ -399,6 +405,17 @@
}
}
+ if (ifv->ifv_tag == EVL_UNTAGGED) {
+ ec->ec_untaggedvlan = 0;
+ for (ifv2 = LIST_FIRST(&ifv_list); ifv2 != NULL;
+ ifv2 = LIST_NEXT(ifv2, ifv_list))
+ if ( (ifv2->ifv_p == ifv->ifv_p) &&
+ (ifv2->ifv_tag == EVL_UNTAGGED) ) {
+ ec->ec_untaggedvlan = 1;
+ break;
+ }
+ }
+
ether_ifdetach(ifp);
vlan_reset_linkname(ifp);
break;
@@ -526,17 +543,17 @@
vlan_unconfig(ifp);
break;
}
- if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
- error = EINVAL; /* check for valid tag */
+ if ( (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) &&
+ (vlr.vlr_tag != EVL_UNTAGGED) ) { /* check for valid tag */
+ error = EINVAL;
break;
}
if ((pr = ifunit(vlr.vlr_parent)) == 0) {
error = ENOENT;
break;
}
- if ((error = vlan_config(ifv, pr)) != 0)
+ if ((error = vlan_config(ifv, pr, vlr.vlr_tag)) != 0)
break;
- ifv->ifv_tag = vlr.vlr_tag;
ifp->if_flags |= IFF_RUNNING;
/* Update promiscuous mode, if necessary. */
@@ -738,85 +755,90 @@
bpf_mtap(ifp->if_bpf, m);
#endif
/*
- * If the parent can insert the tag itself, just mark
- * the tag in the mbuf header.
+ * EVL_UNTAGGED means "don't tag" on output.
*/
- if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
- struct m_tag *mtag;
-
- mtag = m_tag_get(PACKET_TAG_VLAN, sizeof(u_int),
- M_NOWAIT);
- if (mtag == NULL) {
- ifp->if_oerrors++;
- m_freem(m);
- continue;
- }
- *(u_int *)(mtag + 1) = ifv->ifv_tag;
- m_tag_prepend(m, mtag);
- } else {
+ if (ifv->ifv_tag != EVL_UNTAGGED) {
/*
- * insert the tag ourselves
+ * If the parent can insert the tag itself, just mark
+ * the tag in the mbuf header.
*/
- M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
- if (m == NULL) {
- printf("%s: unable to prepend encap header",
- ifv->ifv_p->if_xname);
- ifp->if_oerrors++;
- continue;
- }
-
- switch (p->if_type) {
- case IFT_ETHER:
- {
- struct ether_vlan_header *evl;
+ if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
+ struct m_tag *mtag;
- if (m->m_len < sizeof(struct ether_vlan_header))
- m = m_pullup(m,
- sizeof(struct ether_vlan_header));
- if (m == NULL) {
- printf("%s: unable to pullup encap "
- "header", ifv->ifv_p->if_xname);
+ mtag = m_tag_get(PACKET_TAG_VLAN, sizeof(u_int),
+ M_NOWAIT);
+ if (mtag == NULL) {
ifp->if_oerrors++;
+ m_freem(m);
continue;
}
-
- /*
- * Transform the Ethernet header into an
- * Ethernet header with 802.1Q encapsulation.
- */
- memmove(mtod(m, caddr_t),
- mtod(m, caddr_t) + ifv->ifv_encaplen,
- sizeof(struct ether_header));
- evl = mtod(m, struct ether_vlan_header *);
- evl->evl_proto = evl->evl_encap_proto;
- evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
- evl->evl_tag = htons(ifv->ifv_tag);
-
+ *(u_int *)(mtag + 1) = ifv->ifv_tag;
+ m_tag_prepend(m, mtag);
+ } else {
/*
- * To cater for VLAN-aware layer 2 ethernet
- * switches which may need to strip the tag
- * before forwarding the packet, make sure
- * the packet+tag is at least 68 bytes long.
- * This is necessary because our parent will
- * only pad to 64 bytes (ETHER_MIN_LEN) and
- * some switches will not pad by themselves
- * after deleting a tag.
+ * insert the tag ourselves
*/
- if (m->m_pkthdr.len <
- (ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN)) {
- m_copyback(m, m->m_pkthdr.len,
- (ETHER_MIN_LEN +
- ETHER_VLAN_ENCAP_LEN) -
- m->m_pkthdr.len,
- vlan_zero_pad_buff);
+ M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
+ if (m == NULL) {
+ printf("%s: unable to prepend encap
header",
+ ifv->ifv_p->if_xname);
+ ifp->if_oerrors++;
+ continue;
}
- break;
- }
+
+ switch (p->if_type) {
+ case IFT_ETHER:
+ {
+ struct ether_vlan_header *evl;
+
+ if (m->m_len < sizeof(struct
ether_vlan_header))
+ m = m_pullup(m,
+ sizeof(struct
ether_vlan_header));
+ if (m == NULL) {
+ printf("%s: unable to pullup
encap "
+ "header",
ifv->ifv_p->if_xname);
+ ifp->if_oerrors++;
+ continue;
+ }
+
+ /*
+ * Transform the Ethernet header into an
+ * Ethernet header with 802.1Q
encapsulation.
+ */
+ memmove(mtod(m, caddr_t),
+ mtod(m, caddr_t) +
ifv->ifv_encaplen,
+ sizeof(struct ether_header));
+ evl = mtod(m, struct ether_vlan_header
*);
+ evl->evl_proto = evl->evl_encap_proto;
+ evl->evl_encap_proto =
htons(ETHERTYPE_VLAN);
+ evl->evl_tag = htons(ifv->ifv_tag);
+
+ /*
+ * To cater for VLAN-aware layer 2
ethernet
+ * switches which may need to strip the
tag
+ * before forwarding the packet, make
sure
+ * the packet+tag is at least 68 bytes
long.
+ * This is necessary because our parent
will
+ * only pad to 64 bytes (ETHER_MIN_LEN)
and
+ * some switches will not pad by
themselves
+ * after deleting a tag.
+ */
+ if (m->m_pkthdr.len <
+ (ETHER_MIN_LEN +
ETHER_VLAN_ENCAP_LEN)) {
+ m_copyback(m, m->m_pkthdr.len,
+ (ETHER_MIN_LEN +
+ ETHER_VLAN_ENCAP_LEN) -
+ m->m_pkthdr.len,
+ vlan_zero_pad_buff);
+ }
+ break;
+ }
#ifdef DIAGNOSTIC
- default:
- panic("vlan_start: impossible");
+ default:
+ panic("vlan_start: impossible");
#endif
+ }
}
}
@@ -870,16 +892,20 @@
return;
}
evl = mtod(m, struct ether_vlan_header *);
- KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
-
- tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
-
- /*
- * Restore the original ethertype. We'll remove
- * the encapsulation after we've found the vlan
- * interface corresponding to the tag.
- */
- evl->evl_encap_proto = evl->evl_proto;
+ if ( ((struct ethercom *)ifp)->ec_untaggedvlan &&
+ (ntohs(evl->evl_encap_proto) != ETHERTYPE_VLAN) ) {
+ tag = EVL_UNTAGGED;
+ } else {
+ KASSERT(ntohs(evl->evl_encap_proto) ==
ETHERTYPE_VLAN);
+ tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
+ /*
+ * Restore the original ethertype. We'll
+ * remove the encapsulation after we've
+ * found the vlan interface corresponding
+ * to the tag.
+ */
+ evl->evl_encap_proto = evl->evl_proto;
+ }
break;
}
@@ -905,10 +931,10 @@
}
/*
- * Now, remove the encapsulation header. The original
- * header has already been fixed up above.
+ * Now, remove the encapsulation header (except for untagged vlans).
+ * The original header has already been fixed up above.
*/
- if (mtag == NULL) {
+ if ((mtag == NULL) && (tag != EVL_UNTAGGED)) {
memmove(mtod(m, caddr_t) + ifv->ifv_encaplen,
mtod(m, caddr_t), sizeof(struct ether_header));
m_adj(m, ifv->ifv_encaplen);
diff -u -r base/sys/net/if_vlanvar.h new/sys/net/if_vlanvar.h
--- base/sys/net/if_vlanvar.h Sun Dec 11 07:24:51 2005
+++ new/sys/net/if_vlanvar.h Sat Jun 21 00:43:51 2008
@@ -80,6 +80,8 @@
#define EVL_VLANOFTAG(tag) ((tag) & 4095)
#define EVL_PRIOFTAG(tag) (((tag) >> 13) & 7)
+/* This does not appear in packets; it is for vlr_tag/ifv_tag use. */
+#define EVL_UNTAGGED 65535
/* Configuration structure for SIOCSETVLAN and SIOCGETVLAN ioctls. */
struct vlanreq {
- Prev by Date:
Re: bridges, vlans, and xen, oh my!
- Next by Date:
Re: bridges, vlans, and xen, oh my!
- Previous by Thread:
Re: bridges, vlans, and xen, oh my!
- Next by Thread:
Re: bridges, vlans, and xen, oh my!
- Indexes:
Home |
Main Index |
Thread Index |
Old Index