Module Name:    src
Committed By:   darran
Date:           Fri May 29 04:57:05 UTC 2009

Modified Files:
        src/sys/dev/pci: if_wm.c
        src/sys/net: if_ethersubr.c
        src/sys/net/agr: ieee8023ad_lacp.c if_agr.c if_agrether.c
            if_agrvar_impl.h

Log Message:
Add vlan support and hardware offload capabilities to agr.
These changes allow vlans to be layered above agr, with the attach
and detach propogated to the member ports in the aggregation.
Note the agr interface must be up before the vlan is attached.

Adds SIOCINITIFADDR support to the wm driver for setting the AF_LINK
address, necessary for agr to be able to set the mac addresses of each
port to the agr address (i.e. so it can receive all intended traffic
at the hardware level).

Adds support for disabling the LACP protocol by setting LINK1 on the agr
interface (e.g. ifconfig agr0 link1).

In consultation with t...@.


To generate a diff of this commit:
cvs rdiff -u -r1.174 -r1.175 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.171 -r1.172 src/sys/net/if_ethersubr.c
cvs rdiff -u -r1.8 -r1.9 src/sys/net/agr/ieee8023ad_lacp.c
cvs rdiff -u -r1.22 -r1.23 src/sys/net/agr/if_agr.c
cvs rdiff -u -r1.6 -r1.7 src/sys/net/agr/if_agrether.c
cvs rdiff -u -r1.7 -r1.8 src/sys/net/agr/if_agrvar_impl.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.174 src/sys/dev/pci/if_wm.c:1.175
--- src/sys/dev/pci/if_wm.c:1.174	Tue Apr  7 18:42:30 2009
+++ src/sys/dev/pci/if_wm.c	Fri May 29 04:57:04 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.174 2009/04/07 18:42:30 msaitoh Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.175 2009/05/29 04:57:04 darran Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.174 2009/04/07 18:42:30 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.175 2009/05/29 04:57:04 darran Exp $");
 
 #include "bpfilter.h"
 #include "rnd.h"
@@ -2366,6 +2366,8 @@
 {
 	struct wm_softc *sc = ifp->if_softc;
 	struct ifreq *ifr = (struct ifreq *) data;
+	struct ifaddr *ifa = (struct ifaddr *)data;
+	struct sockaddr_dl *sdl;
 	int s, error;
 
 	s = splnet();
@@ -2387,6 +2389,18 @@
 		}
 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
 		break;
+	case SIOCINITIFADDR:
+		if (ifa->ifa_addr->sa_family == AF_LINK) {
+			sdl = satosdl(ifp->if_dl->ifa_addr);
+			(void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, 
+					LLADDR(satosdl(ifa->ifa_addr)),
+					ifp->if_addrlen);
+			/* unicast address is first multicast entry */
+			wm_set_filter(sc);
+			error = 0;
+			break;
+		}
+		/* Fall through for rest */
 	default:
 		if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
 			break;

Index: src/sys/net/if_ethersubr.c
diff -u src/sys/net/if_ethersubr.c:1.171 src/sys/net/if_ethersubr.c:1.172
--- src/sys/net/if_ethersubr.c:1.171	Tue Apr 28 21:26:51 2009
+++ src/sys/net/if_ethersubr.c	Fri May 29 04:57:04 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ethersubr.c,v 1.171 2009/04/28 21:26:51 dyoung Exp $	*/
+/*	$NetBSD: if_ethersubr.c,v 1.172 2009/05/29 04:57:04 darran Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.171 2009/04/28 21:26:51 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.172 2009/05/29 04:57:04 darran Exp $");
 
 #include "opt_inet.h"
 #include "opt_atalk.h"
@@ -735,6 +735,15 @@
 	}
 #endif
 
+#if NAGR > 0
+	if (ifp->if_agrprivate &&
+	    __predict_true(etype != ETHERTYPE_SLOWPROTOCOLS)) {
+		m->m_flags &= ~M_PROMISC;
+		agr_input(ifp, m);
+		return;
+	}
+#endif /* NAGR > 0 */
+
 	/*
 	 * If VLANs are configured on the interface, check to
 	 * see if the device performed the decapsulation and
@@ -753,15 +762,6 @@
 		return;
 	}
 
-#if NAGR > 0
-	if (ifp->if_agrprivate &&
-	    __predict_true(etype != ETHERTYPE_SLOWPROTOCOLS)) {
-		m->m_flags &= ~M_PROMISC;
-		agr_input(ifp, m);
-		return;
-	}
-#endif /* NAGR > 0 */
-
 	/*
 	 * Handle protocols that expect to have the Ethernet header
 	 * (and possibly FCS) intact.

Index: src/sys/net/agr/ieee8023ad_lacp.c
diff -u src/sys/net/agr/ieee8023ad_lacp.c:1.8 src/sys/net/agr/ieee8023ad_lacp.c:1.9
--- src/sys/net/agr/ieee8023ad_lacp.c:1.8	Sun Aug 26 22:59:09 2007
+++ src/sys/net/agr/ieee8023ad_lacp.c	Fri May 29 04:57:05 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: ieee8023ad_lacp.c,v 1.8 2007/08/26 22:59:09 dyoung Exp $	*/
+/*	$NetBSD: ieee8023ad_lacp.c,v 1.9 2009/05/29 04:57:05 darran Exp $	*/
 
 /*-
  * Copyright (c)2005 YAMAMOTO Takashi,
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ieee8023ad_lacp.c,v 1.8 2007/08/26 22:59:09 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ieee8023ad_lacp.c,v 1.9 2009/05/29 04:57:05 darran Exp $");
 
 #include <sys/param.h>
 #include <sys/callout.h>
@@ -101,9 +101,17 @@
 	if (__predict_false(port->port_flags & AGRPORT_DETACHING)) {
 		goto bad;
 	}
+
 	sc = AGR_SC_FROM_PORT(port);
 	KASSERT(port);
 
+	/* running static config? */
+	if (AGR_STATIC(sc)) {
+		/* static config, no lacp */
+		goto bad;
+	}
+
+
 	if (m->m_pkthdr.len != sizeof(*du)) {
 		goto bad;
 	}
@@ -192,6 +200,12 @@
 	struct lacpdu *du;
 	int error;
 
+	/* running static config? */
+	if (AGR_STATIC(AGR_SC_FROM_PORT(port))) {
+		/* static config, no lacp transmit */
+		return 0;
+	}
+
 	KDASSERT(MHLEN >= sizeof(*du));
 
 	m = m_gethdr(M_DONTWAIT, MT_DATA);

Index: src/sys/net/agr/if_agr.c
diff -u src/sys/net/agr/if_agr.c:1.22 src/sys/net/agr/if_agr.c:1.23
--- src/sys/net/agr/if_agr.c:1.22	Fri Nov  7 00:20:18 2008
+++ src/sys/net/agr/if_agr.c	Fri May 29 04:57:05 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_agr.c,v 1.22 2008/11/07 00:20:18 dyoung Exp $	*/
+/*	$NetBSD: if_agr.c,v 1.23 2009/05/29 04:57:05 darran Exp $	*/
 
 /*-
  * Copyright (c)2005 YAMAMOTO Takashi,
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_agr.c,v 1.22 2008/11/07 00:20:18 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_agr.c,v 1.23 2009/05/29 04:57:05 darran Exp $");
 
 #include "bpfilter.h"
 #include "opt_inet.h"
@@ -49,6 +49,7 @@
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
+#include <net/if_ether.h>
 
 #if defined(INET)
 #include <netinet/in.h>
@@ -109,6 +110,9 @@
 {
 	struct agr_port *port;
 	struct ifnet *ifp;
+#if NVLAN > 0
+	struct m_tag *mtag;
+#endif
 
 	port = ifp_port->if_agrprivate;
 	KASSERT(port);
@@ -122,6 +126,27 @@
 	ifp->if_ipackets++;
 	m->m_pkthdr.rcvif = ifp;
 
+#define DNH_DEBUG
+#if NVLAN > 0
+	/* got a vlan packet? */
+	if ((mtag = m_tag_find(m, PACKET_TAG_VLAN, NULL)) != NULL) {
+#ifdef DNH_DEBUG 
+		printf("%s: vlan tag %d attached\n",
+			ifp->if_xname,
+			htole16((*(u_int *)(mtag + 1)) & 0xffff));
+		printf("%s: vlan input\n", ifp->if_xname);
+#endif
+		vlan_input(ifp, m);
+		return;
+#ifdef DNH_DEBUG 
+	} else {
+		struct ethercom *ec = (void *)ifp;
+		printf("%s: no vlan tag attached, ec_nvlans=%d\n",
+			ifp->if_xname, ec->ec_nvlans);
+#endif
+	}
+#endif
+
 #if NBPFILTER > 0
 	if (ifp->if_bpf) {
 		bpf_mtap(ifp->if_bpf, m);
@@ -213,6 +238,95 @@
  * INTERNAL FUNCTIONS
  */
 
+/*
+ * Enable vlan hardware assist for the specified port.
+ */
+static int
+agr_vlan_add(struct agr_port *port, void *arg)
+{
+	struct ifnet *ifp = port->port_ifp;
+	struct ethercom *ec_port = (void *)ifp;
+	struct ifreq ifr;
+	int error=0;
+
+	if (ec_port->ec_nvlans++ == 0 &&
+	    (ec_port->ec_capabilities & ETHERCAP_VLAN_MTU) != 0) {
+		struct ifnet *p = port->port_ifp;
+		/*
+		 * Enable Tx/Rx of VLAN-sized frames.
+		 */
+		ec_port->ec_capenable |= ETHERCAP_VLAN_MTU;
+		if (p->if_flags & IFF_UP) {
+			ifr.ifr_flags = p->if_flags;
+			error = (*p->if_ioctl)(p, SIOCSIFFLAGS,
+			    (void *) &ifr);
+			if (error) {
+				if (ec_port->ec_nvlans-- == 1)
+					ec_port->ec_capenable &=
+					    ~ETHERCAP_VLAN_MTU;
+				return (error);
+			}
+		}
+	}
+
+	return error;
+}
+
+/*
+ * Disable vlan hardware assist for the specified port.
+ */
+static int
+agr_vlan_del(struct agr_port *port, void *arg)
+{
+	struct ethercom *ec_port = (void *)port->port_ifp;
+	struct ifreq ifr;
+
+	/* Disable vlan support */
+	if (ec_port->ec_nvlans-- == 1) {
+		/*
+		 * Disable Tx/Rx of VLAN-sized frames.
+		 */
+		ec_port->ec_capenable &= ~ETHERCAP_VLAN_MTU;
+		if (port->port_ifp->if_flags & IFF_UP) {
+			ifr.ifr_flags = port->port_ifp->if_flags;
+			(void) (*port->port_ifp->if_ioctl)(port->port_ifp,
+			    SIOCSIFFLAGS, (void *) &ifr);
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * Check for vlan attach/detach.
+ * ec->ec_nvlans is directly modified by the vlan driver.
+ * We keep a local count in sc (sc->sc_nvlans) to detect
+ * when the vlan driver attaches or detaches.
+ * Note the agr interface must be up for this to work.
+ */
+static void
+agr_vlan_check(struct ifnet *ifp, struct agr_softc *sc)
+{
+	struct ethercom *ec = (void *)ifp;
+	int error;
+
+	/* vlans in sync? */
+	if (sc->sc_nvlans == ec->ec_nvlans) {
+		return;
+	}
+
+	if (sc->sc_nvlans == 0) {
+		/* vlan added */
+		error = agr_port_foreach(sc, agr_vlan_add, NULL);
+		sc->sc_nvlans = ec->ec_nvlans;
+	} else if (ec->ec_nvlans == 0) {
+		/* vlan removed */
+		error = agr_port_foreach(sc, agr_vlan_del, NULL);
+		sc->sc_nvlans = 0;
+	}
+}
+
 static int
 agr_clone_create(struct if_clone *ifc, int unit)
 {
@@ -532,6 +646,11 @@
 	 * start to modify ifp_port.
 	 */
 
+	/* XXX this should probably be SIOCALIFADDR but that doesn't 
+	 * appear to work (ENOTTY). We want to change the mac address
+	 * of each port to that of the first port. No need for arps 
+	 * since there are no inet addresses assigned to the ports.
+	 */
 	error = (*ifp_port->if_ioctl)(ifp_port, SIOCINITIFADDR, ifp->if_dl);
 
 	if (error) {
@@ -850,6 +969,12 @@
 #endif
 
 	case SIOCSIFFLAGS:
+		/* Check for a change in vlan status.  This ioctl is the 
+		 * only way we can tell that a vlan has attached or detached.
+		 * Note the agr interface must be up.
+		 */
+		agr_vlan_check(ifp, sc);
+
 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
 			break;
 		agr_config_promisc(sc);

Index: src/sys/net/agr/if_agrether.c
diff -u src/sys/net/agr/if_agrether.c:1.6 src/sys/net/agr/if_agrether.c:1.7
--- src/sys/net/agr/if_agrether.c:1.6	Sun Aug 26 22:59:09 2007
+++ src/sys/net/agr/if_agrether.c	Fri May 29 04:57:05 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_agrether.c,v 1.6 2007/08/26 22:59:09 dyoung Exp $	*/
+/*	$NetBSD: if_agrether.c,v 1.7 2009/05/29 04:57:05 darran Exp $	*/
 
 /*-
  * Copyright (c)2005 YAMAMOTO Takashi,
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_agrether.c,v 1.6 2007/08/26 22:59:09 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_agrether.c,v 1.7 2009/05/29 04:57:05 darran Exp $");
 
 #include <sys/param.h>
 #include <sys/callout.h>
@@ -98,6 +98,18 @@
 	agr_mc_init(sc, &priv->aep_multiaddrs);
 
 	sc->sc_iftprivate = priv;
+	/* inherit ports capabilities
+	 * XXX this really needs to be the intersection of all
+	 * ports capabilities, not just the latest port.
+	 * Okay if ports are the same.
+	 */
+	ifp->if_capabilities = ifp_port->if_capabilities &
+			(IFCAP_TSOv4 | IFCAP_TSOv6 |
+			IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx |
+			IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
+			IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx |
+			IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx |
+			IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx);
 
 	ether_ifattach(ifp, CLLADDR(ifp_port->if_sadl));
 	ec->ec_capabilities =
@@ -149,9 +161,30 @@
 		}
 		ec->ec_capabilities &=
 		    ec_port->ec_capabilities |
-		    ~(ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_MTU);
+		    ~(ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING);
 	}
 
+	/* Enable vlan support */
+	if ((ec->ec_nvlans > 0) && 
+	     ec_port->ec_nvlans++ == 0 &&
+	    (ec_port->ec_capabilities & ETHERCAP_VLAN_MTU) != 0) {
+		struct ifnet *p = port->port_ifp;
+		/*
+		 * Enable Tx/Rx of VLAN-sized frames.
+		 */
+		ec_port->ec_capenable |= ETHERCAP_VLAN_MTU;
+		if (p->if_flags & IFF_UP) {
+			ifr.ifr_flags = p->if_flags;
+			error = (*p->if_ioctl)(p, SIOCSIFFLAGS,
+			    (void *) &ifr);
+			if (error) {
+				if (ec_port->ec_nvlans-- == 1)
+					ec_port->ec_capenable &=
+					    ~ETHERCAP_VLAN_MTU;
+				return (error);
+			}
+		}
+	}
 	/* XXX ETHERCAP_JUMBO_MTU */
 
 	priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK | M_ZERO);
@@ -185,12 +218,27 @@
 agrether_portfini(struct agr_softc *sc, struct agr_port *port)
 {
 	struct ifreq ifr;
+	struct ethercom *ec_port = (void *)port->port_ifp;
 	int error;
 
 	if (port->port_iftprivate == NULL) {
 		return 0;
 	}
 
+	if (ec_port->ec_nvlans > 0) {
+		/* Disable vlan support */
+		ec_port->ec_nvlans = 0;
+		/*
+		 * Disable Tx/Rx of VLAN-sized frames.
+		 */
+		ec_port->ec_capenable &= ~ETHERCAP_VLAN_MTU;
+		if (port->port_ifp->if_flags & IFF_UP) {
+			ifr.ifr_flags = port->port_ifp->if_flags;
+			(void) (*port->port_ifp->if_ioctl)(port->port_ifp,
+			    SIOCSIFFLAGS, (void *) &ifr);
+		}
+	}
+
 	memset(&ifr, 0, sizeof(ifr));
 	ifr.ifr_addr.sa_len = sizeof(ifr.ifr_addr);
 	ifr.ifr_addr.sa_family = AF_UNSPEC;

Index: src/sys/net/agr/if_agrvar_impl.h
diff -u src/sys/net/agr/if_agrvar_impl.h:1.7 src/sys/net/agr/if_agrvar_impl.h:1.8
--- src/sys/net/agr/if_agrvar_impl.h:1.7	Sun May 20 07:57:04 2007
+++ src/sys/net/agr/if_agrvar_impl.h	Fri May 29 04:57:05 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_agrvar_impl.h,v 1.7 2007/05/20 07:57:04 yamt Exp $	*/
+/*	$NetBSD: if_agrvar_impl.h,v 1.8 2009/05/29 04:57:05 darran Exp $	*/
 
 /*-
  * Copyright (c)2005 YAMAMOTO Takashi,
@@ -111,6 +111,7 @@
 	const struct agr_iftype_ops *sc_iftop;
 	uint32_t sc_rr_counter;	/* distributor algorithm specific */
 	void *sc_iftprivate;
+	int sc_nvlans;		/* number of vlans attached */
 	struct ifnet sc_if; /* should be the last. see agr_alloc_softc(). */
 };
 
@@ -135,6 +136,7 @@
 int agr_xmit_frame(struct ifnet *, struct mbuf *); /* XXX */
 
 #define	AGR_ROUNDROBIN(sc)	(((sc)->sc_if.if_flags & IFF_LINK0) != 0)
+#define	AGR_STATIC(sc)		(((sc)->sc_if.if_flags & IFF_LINK1) != 0)
 
 void agrtimer_init(struct agr_softc *);
 void agrtimer_start(struct agr_softc *);

Reply via email to