kern/127815: if_gif does not set vlan attributes from EtherIP encapsulated 802.1 packets

Serge Potapov sp at smartspb.net
Fri Oct 3 12:00:11 UTC 2008


>Number:         127815
>Category:       kern
>Synopsis:       if_gif does not set vlan attributes from EtherIP encapsulated 802.1 packets
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Oct 03 12:00:10 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Serge Potapov
>Release:        7.1-BETA1
>Organization:
Smart Telecom
>Environment:
FreeBSD test89.smartspb.net 7.1-BETA FreeBSD 7.1-BETA #1: Thu Oct  2 12:36:03 MSD 2008     root at test89.smartspb.net:/usr/obj/usr/src/sys/K7_LINAS_SRV_SMP  i386

>Description:
vlan2, mac2 -> interface2
vlan3, mac1 -> interface1

and so on.

When gif interface receives EtherIP encapsulating 802.1Q packet it does
not set m->m_pkthdr.ether_vtag and m->m_flags |= M_VLANTAG.

Chain:

ether<->if_bridge<->gif<->gif<->if_bridge<->ether

transmits vlan tagged packets properly, but if_bridge bridge stores all MAC addresses learned from gif side in vlan1.

In point-to-multipoint environment unicast 802.1Q (vlan_tag != 1) packets received from physical ethernet interface will be always sent over all gif interfaces attached to if_bridge.

>How-To-Repeat:
Simple, but need a lot of equipment.

=
|    em0 +------+ em1  fxp0 +-------+
+--------+ CPE1 +-----------+ HOST1 |
|   $ip1 +------+           +-------+
|
|    em0 +------+ em1  fxp0 +-------+
+--------+ CPE2 +-----------+ HOST2 |
|   $ip3 +------+           +-------+
|
|    em0 +------+ em1  fxp0 +-------+
+--------+ CPE3 +-----------| HOST3 |
|   $ip3 +------+           +-------+
=

CPE1:

ifconfig bridge0 create;
ifconfig em1 up; ifconfig bridge0 addm em1 up
ifconfig gif2 create; ifconfig gif2 tunnel $ip1 $ip2
ifconfig bridge0 addm gif2; ifconfig bridge0 private gif2
ifconfig gif3 create; ifconfig gif3 tunnel $ip1 $ip3
ifconfig bridge0 addm gif3; ifconfig bridge0 private gif3

CPE2:

ifconfig bridge0 create
ifconfig em1 up; ifconfig bridge0 addm1 up
ifconfig gif1 create; ifconfig gif1 tunnel $ip2 $ip1
ifconfig bridge0 addm gif1; ifconfig bridge0 private gif1
ifconfig gif3 create; ifconfig gif3 tunnel $ip2 $ip3
ifconfig bridge0 addm gif3; ifconfig bridge0 private gif3

CPE3:

ifconfig bridge0 create
ifconfig em1 up; ifconfig bridge0 addm1 up
ifconfig gif1 create; ifconfig gif1 tunnel $ip3 $ip1
ifconfig bridge0 addm gif1; ifconfig bridge0 private gif1
ifconfig gif2 create; ifconfig gif2 tunnel $ip3 $ip2
ifconfig bridge0 addm gif2; ifconfig bridge0 private gif2

===================================================================
With plain 802.1 ethernet all works fine (thanks for private flag).
No extra traffic, no loops. Almost poor man's VPLS.

But after:

HOST1:

ifconfig fxp0 up
ifconfig vlan5 create
ifconfig vlan5 10.10.10.1/24 vlan 5 vlandev fxp0

HOST2:

ifconfig fxp0 up
ifconfig vlan5 create
ifconfig vlan5 10.10.10.2/24 vlan 5 vlandev fxp0
ping 10.10.10.1

CPE2 will send all icmp requests received on em1 over gif1 and gif3 [waste]
CPE1 will sens all icmp replies received on em0 over gif2 and gif3 [waste]

CPE3 will receive icmp requests on gif2 and replies on gif1 and send
all packets to em1.
>Fix:
Patch attached.
Not sure about proper place.
After patching vlan MACs stored properly and bridge woriking right.
Not tested too much.


Patch attached with submission follows:

--- /sys/net/if_gif.c.orig	2008-10-03 14:18:50.000000000 +0400
+++ /sys/net/if_gif.c	2008-10-03 11:43:48.000000000 +0400
@@ -81,6 +81,7 @@
 
 #include <netinet/ip_encap.h>
 #include <net/ethernet.h>
+#include <net/if_vlan_var.h>
 #include <net/if_bridgevar.h>
 #include <net/if_gif.h>
 
@@ -560,6 +561,31 @@
 					m->m_flags |= M_MCAST;
 				ifp->if_imcasts++;
 			}
+			/* Check vlan tagging on received frame. */
+			/* Probably should be moved somewhere up. */
+			if (ntohs(eh->ether_type) == ETHERTYPE_VLAN) {
+				/* Copy from if_ethersubr.c */
+				struct ether_vlan_header *evl;
+				if (m->m_len < sizeof(*evl) &&
+				    (m = m_pullup(m, sizeof(*evl))) == NULL) {
+#ifdef DIAGNOSTIC
+					if_printf(ifp, "cannot pullup VLAN header\n");
+#endif
+					ifp->if_ierrors++;
+					m_freem(m);
+					return;
+				}
+
+				evl = mtod(m, struct ether_vlan_header *);
+				m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
+				m->m_flags |= M_VLANTAG;
+
+				bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN,
+				      ETHER_HDR_LEN - ETHER_TYPE_LEN);
+				m_adj(m, ETHER_VLAN_ENCAP_LEN);
+				/* End of copy */
+			}
+			
 			BRIDGE_INPUT(ifp, m);
 
 			if (m != NULL && ifp != oldifp) {


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list