kern/102540: PATCH - supporting vlan(4) by ng_fec(4)

Artemiev Igor ai at bmc.brk.ru
Sat Aug 26 11:10:24 UTC 2006


>Number:         102540
>Category:       kern
>Synopsis:       PATCH - supporting vlan(4) by ng_fec(4)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Aug 26 11:10:23 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Artemiev Igor
>Release:        FreeBSD 6.1-STABLE i386
>Organization:
Bryansk Medical Center
>Environment:
System: FreeBSD stalker.bmc.brk.ru 6.1-STABLE FreeBSD 6.1-STABLE #3: Wed May 10 12:30:40 MSD 2006 root at stalker.bmc.brk.ru:/usr/obj/usr/src/sys/stalker.KERNEL i386

>Description:
       ng_fec(4) does not work with vlan(4), because ng_fec_start does not
       distinguish marked mbuf, also there is no support VLAN_HWTAGGING and
       VLAN_MTU capability for bundle even if underlying interfaces support it.
>How-To-Repeat:
        The host A, connected to cisco trunk:
        ngctl -f -<<-EOF
                mkpeer fec dummy fec
                msg fec0: add_iface "bge0"
                msg fec0: add_iface "bge1"
                msg fec0: set_mode_mac
        EOF
        ifconfig vlan2 create
        ifconfig vlan2 inet 10.0.0.1/8 vlan 2 vlandev fec0
        ifconfig fec0 up
        ifconfig vlan2 up

        The host B, connected to cisco trunk:
        ifconfig vlan2 create
        ifconfig vlan2 inet 10.0.0.2/8 vlan 2 vlandev fxp0

        ping 10.0.0.1 - no reply

>Fix:
	Apply a followed patch. After :
        ngctl -f -<<-EOF
                mkpeer fec dummy fec
                msg fec0: add_iface "bge0"
                msg fec0: add_iface "bge1"
                msg fec0: set_mode_mac
        EOF
        ifconfig vlan2 create
        ifconfig vlan2 inet 10.0.0.1/8 vlan 2 vlandev fec0
        ifconfig fec0 up
        ifconfig vlan2 up

        The host B, connected to cisco trunk:
        ifconfig vlan2 create
        ifconfig vlan2 inet 10.0.0.2/8 vlan 2 vlandev fxp0

	ifconfig fec0
	
	fec0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        	options=18<VLAN_MTU,VLAN_HWTAGGING>
        	ether 00:17:a4:3b:09:3c
        	media: Ethernet none
        	status: active                     

        ping 10.0.0.1 - working, because both bge0 and bge1 support 
	VLAN_MTU and VLAN_HWTAGGING fec0 derived their capabilities.
	If undelying device changes the capabilities, the call ifconfig 
	{vlantag|vlanmtu} updates capabilities at fec interface.

--- sys/netgraph/ng_fec.h.orig	Sat Aug 26 12:33:03 2006
+++ sys/netgraph/ng_fec.h	Sat Aug 26 12:33:33 2006
@@ -92,11 +92,6 @@
 #define NG_FEC_MTU_MAX			65535
 #define NG_FEC_MTU_DEFAULT		1500
 
-/* Special flags for mbufs. */
-#define M_FEC_MAC			0x2000
-#define M_FEC_INET			0x4000
-#define M_FEC_INET6			0x8000
-
 /* Netgraph commands */
 enum {
 	NGM_FEC_ADD_IFACE,
--- sys/netgraph/ng_fec.c.orig	Sat Aug 26 12:32:57 2006
+++ sys/netgraph/ng_fec.c	Sat Aug 26 14:17:22 2006
@@ -195,6 +195,8 @@
 static void	ng_fec_tick(void *arg);
 static int	ng_fec_addport(struct ng_fec_private *priv, char *iface);
 static int	ng_fec_delport(struct ng_fec_private *priv, char *iface);
+static void 	ng_fec_update_opts(struct ng_fec_bundle *b,
+			struct ifnet *ifp);
 
 #ifdef DEBUG
 static void	ng_fec_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
@@ -439,9 +441,41 @@
 	new->fec_ifstat = -1;
 	TAILQ_INSERT_TAIL(&b->ng_fec_ports, new, fec_list);
 
+	ng_fec_update_opts(b, ifp);
+
 	return(0);
 }
 
+/* Update interfaces capabilities in bundle */
+static void 
+ng_fec_update_opts(struct ng_fec_bundle *b, struct ifnet *ifp)
+{
+    	struct ng_fec_portlist *p;
+    	int with_hwtag = 0, with_mtu = 0;
+	/* See if the interface is already in the bundle */
+	TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) {
+	    	struct ifnet *bifp = p->fec_if;
+		if(bifp->if_capenable & IFCAP_VLAN_MTU)
+		    	with_mtu++;
+		if(bifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+		    	with_hwtag++;
+	}
+	if(b->fec_ifcnt == 0) 
+	    	return;
+
+	if(b->fec_ifcnt > with_hwtag) 
+	    	ifp->if_capenable &= ~IFCAP_VLAN_HWTAGGING;
+	else 	
+	    	ifp->if_capenable |= IFCAP_VLAN_HWTAGGING;
+		
+	if(b->fec_ifcnt > with_mtu) 
+	    	ifp->if_capenable &= ~IFCAP_VLAN_MTU;
+	else 	
+	    	ifp->if_capenable |= IFCAP_VLAN_MTU;
+	
+	return;    
+}
+
 static int
 ng_fec_delport(struct ng_fec_private *priv, char *iface)
 {
@@ -504,6 +538,8 @@
 	if (b->fec_ifcnt == 0)
 		b->fec_if_output = NULL;
 
+	ng_fec_update_opts(b, ifp);
+
 	return(0);
 }
 
@@ -678,7 +714,8 @@
 ng_fec_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
 	struct ifreq *const ifr = (struct ifreq *) data;
-	int s, error = 0;
+	int error = 0;
+	int ifcap;
 	struct ng_fec_private	*priv;
 	struct ng_fec_bundle	*b;
 
@@ -688,7 +725,7 @@
 #ifdef DEBUG
 	ng_fec_print_ioctl(ifp, command, data);
 #endif
-	s = splimp();
+	mtx_lock(&ng_fec_mtx);
 	switch (command) {
 
 	/* These two are mostly handled at a higher layer */
@@ -745,12 +782,17 @@
 	case SIOCSIFPHYS:
 		error = EOPNOTSUPP;
 		break;
-
+	case SIOCSIFCAP:
+		ifcap =  ifp->if_capenable;
+		ng_fec_update_opts(b, ifp);
+		if(ifcap != ifp->if_capenable)
+		    	ng_fec_init(priv);
+		break;
 	default:
 		error = EINVAL;
 		break;
 	}
-	(void) splx(s);
+	mtx_unlock(&ng_fec_mtx);
 	return (error);
 }
 
@@ -840,40 +882,21 @@
 	}
 
 	b = &priv->fec_bundle;
-
 	switch (b->fec_btype) {
 	case FEC_BTYPE_MAC:
-		m->m_flags |= M_FEC_MAC;
-		break;
 #ifdef INET
 	case FEC_BTYPE_INET:
-		/*
-		 * We can't use the INET address port selection
-		 * scheme if this isn't an INET packet.
-		 */
-		if (dst->sa_family == AF_INET)
-			m->m_flags |= M_FEC_INET;
 #ifdef INET6
-		else if (dst->sa_family == AF_INET6)
-			m->m_flags |= M_FEC_INET6;
+	case FEC_BTYPE_INET6:
 #endif
-		else {
-#ifdef DEBUG
-			if_printf(ifp, "can't do inet aggregation of non "
-			    "inet packet\n");
 #endif
-			m->m_flags |= M_FEC_MAC;
-		}
 		break;
-#endif
 	default:
-		if_printf(ifp, "bogus hash type: %d\n",
-		    b->fec_btype);
+		if_printf(ifp, "bogus hash type: %d\n", b->fec_btype);
 		m_freem(m);
 		return(EINVAL);
 		break;
 	}
-
 	/*
 	 * Pass the frame to the output vector for all the protocol
 	 * handling. This will put the ethernet header on the packet
@@ -898,7 +921,6 @@
 	struct mbuf *m, struct ifnet **ifp)
 {
 	struct ether_header	*eh;
-	struct mbuf		*m0;
 #ifdef INET
 	struct ip		*ip;
 #ifdef INET6
@@ -907,7 +929,7 @@
 #endif
 
 	struct ng_fec_portlist	*p;
-	int			port = 0, mask;
+	int			port = -1, mask;
 
 	/*
 	 * If there are only two ports, mask off all but the
@@ -925,43 +947,39 @@
 #endif
 #endif
 
-	/*
-	 * The fg_fec_output() routine is supposed to leave a
-	 * flag for us in the mbuf that tells us what hash to
-	 * use, but sometimes a new mbuf is prepended to the
-	 * chain, so we have to search every mbuf in the chain
-	 * to find the flags.
-	 */
-	m0 = m;
-	while (m0) {
-		if (m0->m_flags & (M_FEC_MAC|M_FEC_INET|M_FEC_INET6))
-			break;
-		m0 = m0->m_next;
-	}
-	if (m0 == NULL)
-		return(EINVAL);
-
-	switch (m0->m_flags & (M_FEC_MAC|M_FEC_INET|M_FEC_INET6)) {
-	case M_FEC_MAC:
-		port = (eh->ether_dhost[5] ^
-		    eh->ether_shost[5]) & mask;
-		break;
 #ifdef INET
-	case M_FEC_INET:
+	if(b->fec_btype == FEC_BTYPE_INET) {
+		if(eh->ether_type == ETHERTYPE_IP) {
+			switch(ip->ip_v) {
+			case 4:    
 		port = (ntohl(ip->ip_dst.s_addr) ^
 		    ntohl(ip->ip_src.s_addr)) & mask;
 		break;
 #ifdef INET6
-	case M_FEC_INET6:
+			case 6:	
 		port = (ip6->ip6_dst.s6_addr[15] ^
 		    ip6->ip6_dst.s6_addr[15]) & mask;
 		break;
 #endif
-#endif
 	default:
-		return(EINVAL);
+#ifdef DEBUG			
+				printf("%s: can't do inet aggregation of "
+				    "inet packet with unknown ip version\n",
+				    __func__);
+#endif				
 			break;
 	}
+		} else {
+#ifdef DEBUG			
+			printf("%s: can't do inet aggregation of non "
+			    "inet packet\n", __func__);
+#endif				
+		}	
+#endif
+	}
+	if(port < 0)		
+		port = (eh->ether_dhost[5] ^
+		    eh->ether_shost[5]) & mask;
 
 	TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) {
 		if (port == p->fec_idx)
@@ -1134,6 +1152,7 @@
 	ifp->if_addrlen = 0;			/* XXX */
 	ifp->if_hdrlen = 0;			/* XXX */
 	ifp->if_baudrate = 100000000;		/* XXX */
+	ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
 	TAILQ_INIT(&ifp->if_addrhead); /* XXX useless - done in if_attach */
 
 	/* Give this node the same name as the interface (if possible) */
@@ -1253,7 +1272,7 @@
 
 	switch (event) {
 	case MOD_LOAD:
-		mtx_init(&ng_fec_mtx, "ng_fec", NULL, MTX_DEF);
+		mtx_init(&ng_fec_mtx, "ng_fec", MTX_NETWORK_LOCK, MTX_DEF);
 		break;
 	case MOD_UNLOAD:
 		mtx_destroy(&ng_fec_mtx);
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list