vlan(4) broken.

Gary Allan dragonfly at gallan.plus.com
Fri Dec 30 05:09:35 PST 2005


Matthew Dillon wrote:
   Gary, and anyone else who can test VLAN support, please try this
   patch and tell me if it works.
						-Matt

Index: net/vlan/if_vlan.c

Hello,

Thank you for your help. I have successfully tested your patch with 
several NICs vr(4), fxp(4), xl(4) and re(4). I've added support for 
honoring the VLAN_MTU and VLAN_HWTAGGING parent interface flags. I was 
able to test VLAN_MTU and VLAN_HWTAGGING handling with re(4). This means 
we no longer have to manually set LINK0 on the vlan interface to enable 
hardware support. I have also updated the man page.

The only issue I can find is that tcpdump(1) listening on the parent 
interface does not display the fact that the packets are encapsulated.

  ifconfig vlan10 create vlan 10 vlandev vr0
  ifconfig vlan10 inet 192.168.10.10 netmask 255.255.255.0
  ping 192.168.10.20&
  tcpdump -n -i vr0 icmp

This matches no packets so it seems the packets are being passed to 
bpf(4) encapsulated. (Devices supporting VLAN_HWTAGGING would be an 
exception.)

  tcpdump -n -i vr0
  tcpdump -n -i vr0 vlan
Both display the following: (-v and -vv are similar.)

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vr0, link-type EN10MB (Ethernet), capture size 96 bytes
12:32:42.324429 IP 192.168.10.10 > 192.168.10.20: icmp 64: echo request 
seq 39680
12:32:43.325558 IP 192.168.10.10 > 192.168.10.20: icmp 64: echo request 
seq 39936

FreeBSD 4 displays:

tcpdump: listening on fxp0
23:04:37.370155 802.1Q vlan#10 P0 192.168.10.24 > 192.168.10.20: icmp: 
echo request
23:04:38.378513 802.1Q vlan#10 P0 192.168.10.24 > 192.168.10.20: icmp: 
echo request

I don't know if this is a bug or is just due to DragonFly using a newer 
version of tcpdump. It had me thinking bpf handling wasn't working for a 
while.

Regards

Gary
Index: sys/net/vlan/if_vlan.c
===================================================================
RCS file: /home/dcvs/src/sys/net/vlan/if_vlan.c,v
retrieving revision 1.18
diff -u -r1.18 if_vlan.c
--- sys/net/vlan/if_vlan.c	28 Nov 2005 17:13:46 -0000	1.18
+++ sys/net/vlan/if_vlan.c	30 Dec 2005 00:24:00 -0000
@@ -303,13 +303,11 @@
 			altq_etherclassify(&p->if_snd, m, &pktattr);
 
 		/*
-		 * If the LINK0 flag is set, it means the underlying interface
-		 * can do VLAN tag insertion itself and doesn't require us to
-	 	 * create a special header for it. In this case, we just pass
-		 * the packet along. However, we need some way to tell the
-		 * interface where the packet came from so that it knows how
-		 * to find the VLAN tag to use, so we set the rcvif in the
-		 * mbuf header to our ifnet.
+		 * If underlying interface can do VLAN tag insertion itself,
+		 * just pass the packet along. However, we need some way to
+		 * tell the interface where the packet came from so that it
+		 * knows how to find the VLAN tag to use, so we set the rcvif 
+		 * in the mbuf header to our ifnet.
 		 *
 		 * Note: we also set the M_PROTO1 flag in the mbuf to let
 		 * the parent driver know that the rcvif pointer is really
@@ -320,7 +318,7 @@
 		 * following potentially bogus rcvif pointers off into
 		 * never-never land.
 		 */
-		if (ifp->if_flags & IFF_LINK0) {
+		if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
 			m->m_pkthdr.rcvif = ifp;
 			m->m_flags |= M_PROTO1;
 		} else {
@@ -379,10 +377,8 @@
 {
 	struct bpf_if *bif;
 	struct ifvlan *ifv;
-	struct ether_header *eh = mtod(m, struct ether_header *);
 	struct ifnet *rcvif;
 
-	m_adj(m, ETHER_HDR_LEN);
 	rcvif = m->m_pkthdr.rcvif;
 
 	ASSERT_SERIALIZED(rcvif->if_serializer);
@@ -392,14 +388,18 @@
 	 * bpf tap if active.
 	 */
 	if ((bif = rcvif->if_bpf) != NULL) {
+		struct ether_header *eh;
 		struct ether_vlan_header evh;
 
+		eh = mtod(m, struct ether_header *);
+		m_adj(m, ETHER_HDR_LEN);
 		bcopy(eh, &evh, 2*ETHER_ADDR_LEN);
 		evh.evl_encap_proto = htons(ETHERTYPE_VLAN);
 		evh.evl_tag = htons(t);
 		evh.evl_proto = eh->ether_type;
-
 		bpf_ptap(bif, m, &evh, ETHER_HDR_LEN + EVL_ENCAPLEN);
+		/* XXX assumes data was left intact */
+		M_PREPEND(m, ETHER_HDR_LEN, MB_WAIT); 
 	}
 
 	for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
@@ -423,7 +423,7 @@
 	ifv->ifv_if.if_ipackets++;
 	lwkt_serialize_exit(rcvif->if_serializer);
 	lwkt_serialize_enter(ifv->ifv_if.if_serializer);
-	ether_input(&ifv->ifv_if, eh, m);
+	ether_input(&ifv->ifv_if, NULL, m);
 	lwkt_serialize_exit(ifv->ifv_if.if_serializer);
 	lwkt_serialize_enter(rcvif->if_serializer);
 	return 0;
@@ -434,6 +434,7 @@
 {
 	struct ifvlan *ifv;
 	struct ifnet *rcvif;
+	struct ether_header eh_copy;
 
 	rcvif = m->m_pkthdr.rcvif;
 	ASSERT_SERIALIZED(rcvif->if_serializer);
@@ -455,20 +456,22 @@
 	/*
 	 * Having found a valid vlan interface corresponding to
 	 * the given source interface and vlan tag, remove the
-	 * encapsulation, and run the real packet through
-	 * ether_input() a second time (it had better be
+	 * remaining encapsulation (ether_vlan_header minus the ether_header
+	 * that had already been removed) and run the real packet
+	 * through ether_input() a second time (it had better be
 	 * reentrant!).
 	 */
+	eh_copy = *eh;
+	eh_copy.ether_type = mtod(m, u_int16_t *)[1];	/* evl_proto */
 	m->m_pkthdr.rcvif = &ifv->ifv_if;
-	eh->ether_type = mtod(m, u_int16_t *)[1];
-	m->m_data += EVL_ENCAPLEN;
-	m->m_len -= EVL_ENCAPLEN;
-	m->m_pkthdr.len -= EVL_ENCAPLEN;
+	m_adj(m, EVL_ENCAPLEN);
+	M_PREPEND(m, ETHER_HDR_LEN, MB_WAIT); 
+	*(struct ether_header *)mtod(m, void *) = eh_copy;
 
 	ifv->ifv_if.if_ipackets++;
 	lwkt_serialize_exit(rcvif->if_serializer);
 	lwkt_serialize_enter(ifv->ifv_if.if_serializer);
-	ether_input(&ifv->ifv_if, eh, m);
+	ether_input(&ifv->ifv_if, NULL, m);
 	lwkt_serialize_exit(ifv->ifv_if.if_serializer);
 	lwkt_serialize_enter(rcvif->if_serializer);
 	return 0;
@@ -484,7 +487,7 @@
 	if (ifv->ifv_p)
 		return EBUSY;
 	ifv->ifv_p = p;
-	if (p->if_data.ifi_hdrlen == sizeof(struct ether_vlan_header))
+	if (p->if_capenable & IFCAP_VLAN_MTU)
 		ifv->ifv_if.if_mtu = p->if_mtu;
 	else
 		ifv->ifv_if.if_mtu = p->if_data.ifi_mtu - EVL_ENCAPLEN;
Index: share/man/man4/vlan.4
===================================================================
RCS file: /home/dcvs/src/share/man/man4/vlan.4,v
retrieving revision 1.4
diff -u -r1.4 vlan.4
--- share/man/man4/vlan.4	8 Jul 2004 00:14:49 -0000	1.4
+++ share/man/man4/vlan.4	30 Dec 2005 00:00:41 -0000
@@ -71,18 +71,22 @@
 .Pp
 The
 .Nm
-driver supports physical devices that do
-the VLAN demultiplexing in firmware.
-The
-.Cm link0
-flag should be set on a
-.Nm
-interface
-.Pq Em not on its parent
-using
-.Xr ifconfig 8
-in that case to indicate that hardware support for
-the 802.1Q VLANs is present in its parent.
+driver supports efficient operation over parent interfaces that can provide
+help in processing VLANs.
+Such interfaces are automatically recognized by their capabilities.
+Depending on the level of sophistication found in a physical
+interface, it may do full VLAN processing or just be able to
+receive and transmit frames exceeding the maximum Ethernet frame size
+by the length of a 802.1Q header.
+The capabilities may be user-controlled by the respective parameters to
+.Xr ifconfig 8 ,
+.Cm vlanhwtag
+and
+.Cm vlanmtu .
+However, a physical interface is not obliged to react to them:
+It may have either capability enabled permanently without
+a way to turn it off.
+The whole issue is very specific to a particular device and its driver.
 .\"
 .Ss "Selecting the Right Network Interface Card to Run VLANs Through"
 By now, the only NICs that have both hardware support and proper
@@ -93,6 +97,7 @@
 .Xr em 4 ,
 .Xr gx 4 ,
 .Xr nge 4 ,
+.Xr re 4 ,
 .Xr ti 4 ,
 and
 .Xr txp 4 .




More information about the Bugs mailing list