Module Name:    src
Committed By:   yamaguchi
Date:           Tue Oct 12 08:26:47 UTC 2021

Modified Files:
        src/sys/net/lagg: files.lagg if_lagg.c if_laggproto.h

Log Message:
lagg: update capabilities of ifnet and ethercom

Commonly capabilities of all child interface are configured
to a lagg interface.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/net/lagg/files.lagg
cvs rdiff -u -r1.11 -r1.12 src/sys/net/lagg/if_lagg.c
cvs rdiff -u -r1.6 -r1.7 src/sys/net/lagg/if_laggproto.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/net/lagg/files.lagg
diff -u src/sys/net/lagg/files.lagg:1.1 src/sys/net/lagg/files.lagg:1.2
--- src/sys/net/lagg/files.lagg:1.1	Mon May 17 04:07:43 2021
+++ src/sys/net/lagg/files.lagg	Tue Oct 12 08:26:47 2021
@@ -1,7 +1,8 @@
-#	$NetBSD: files.lagg,v 1.1 2021/05/17 04:07:43 yamaguchi Exp $
+#	$NetBSD: files.lagg,v 1.2 2021/10/12 08:26:47 yamaguchi Exp $
 
 file	net/lagg/if_lagg.c		lagg & ether	needs-flag
 file	net/lagg/if_lagg_lacp.c		lagg & ether
 file	net/lagg/if_laggproto.c		lagg
 
 defflag opt_lagg.h			LAGG_DEBUG LACP_DEBUG
+defparam opt_lagg.h			LAGG_SETCAPS_RETRY

Index: src/sys/net/lagg/if_lagg.c
diff -u src/sys/net/lagg/if_lagg.c:1.11 src/sys/net/lagg/if_lagg.c:1.12
--- src/sys/net/lagg/if_lagg.c:1.11	Tue Oct  5 04:17:58 2021
+++ src/sys/net/lagg/if_lagg.c	Tue Oct 12 08:26:47 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_lagg.c,v 1.11 2021/10/05 04:17:58 yamaguchi Exp $	*/
+/*	$NetBSD: if_lagg.c,v 1.12 2021/10/12 08:26:47 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2005, 2006 Reyk Floeter <[email protected]>
@@ -20,7 +20,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.11 2021/10/05 04:17:58 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.12 2021/10/12 08:26:47 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -194,6 +194,7 @@ static void	lagg_port_teardown(struct la
 static void	lagg_port_syncvlan(struct lagg_softc *, struct lagg_port *);
 static void	lagg_port_purgevlan(struct lagg_softc *, struct lagg_port *);
 static void	lagg_lladdr_update(struct lagg_softc *);
+static void	lagg_capabilities_update(struct lagg_softc *);
 
 static struct if_clone	 lagg_cloner =
     IF_CLONE_INITIALIZER("lagg", lagg_clone_create, lagg_clone_destroy);
@@ -215,6 +216,10 @@ static enum lagg_iftypes
 #define LAGG_DPRINTF(_sc, _fmt, _args...)	__nothing
 #endif
 
+#ifndef LAGG_SETCAPS_RETRY
+#define LAGG_SETCAPS_RETRY	(LAGG_MAX_PORTS * 2)
+#endif
+
 static size_t
 lagg_sizeof_softc(enum lagg_iftypes ift)
 {
@@ -1806,6 +1811,181 @@ lagg_port_purgevlan(struct lagg_softc *s
 }
 
 static int
+lagg_setifcaps(struct lagg_port *lp, uint64_t cap)
+{
+	struct ifcapreq ifcr;
+	int error;
+
+	if (lp->lp_ifp->if_capenable == cap)
+		return 0;
+
+	memset(&ifcr, 0, sizeof(ifcr));
+	ifcr.ifcr_capenable = cap;
+
+	IFNET_LOCK(lp->lp_ifp);
+	error = LAGG_PORT_IOCTL(lp, SIOCSIFCAP, &ifcr);
+	IFNET_UNLOCK(lp->lp_ifp);
+
+	return error;
+}
+
+static int
+lagg_setethcaps(struct lagg_port *lp, int cap)
+{
+	struct ethercom *ec;
+	struct eccapreq eccr;
+	int error;
+
+	KASSERT(lp->lp_iftype == IFT_ETHER);
+	ec = (struct ethercom *)lp->lp_ifp;
+
+	if (ec->ec_capenable == cap)
+		return 0;
+
+	memset(&eccr, 0, sizeof(eccr));
+	eccr.eccr_capenable = cap;
+
+	IFNET_LOCK(lp->lp_ifp);
+	error = LAGG_PORT_IOCTL(lp, SIOCSETHERCAP, &eccr);
+	IFNET_UNLOCK(lp->lp_ifp);
+
+	return error;
+}
+
+static void
+lagg_ifcap_update(struct lagg_softc *sc)
+{
+	struct ifnet *ifp;
+	struct lagg_port *lp;
+	uint64_t cap, ena, pena;
+	size_t i;
+
+	KASSERT(LAGG_LOCKED(sc));
+
+	/* Get common capabilities for the lagg ports */
+	ena = ~(uint64_t)0;
+	cap = ~(uint64_t)0;
+	LAGG_PORTS_FOREACH(sc, lp) {
+		ena &= lp->lp_ifp->if_capenable;
+		cap &= lp->lp_ifp->if_capabilities;
+	}
+
+	if (ena == ~(uint64_t)0)
+		ena = 0;
+	if (cap == ~(uint64_t)0)
+		cap = 0;
+
+	/*
+	 * Apply common enabled capabilities back to the lagg ports.
+	 * May require several iterations if they are dependent.
+	 */
+	for (i = 0; i < LAGG_SETCAPS_RETRY; i++) {
+		pena = ena;
+		LAGG_PORTS_FOREACH(sc, lp) {
+			lagg_setifcaps(lp, ena);
+			ena &= lp->lp_ifp->if_capenable;
+		}
+
+		if (pena == ena)
+			break;
+	}
+
+	if (pena != ena) {
+		lagg_log(sc, LOG_DEBUG, "couldn't set "
+		    "capabilities 0x%08"PRIx64, pena);
+	}
+
+	ifp = &sc->sc_if;
+
+	if (ifp->if_capabilities != cap ||
+	    ifp->if_capenable != ena) {
+		ifp->if_capabilities = cap;
+		ifp->if_capenable = ena;
+
+		lagg_log(sc, LOG_DEBUG,"capabilities "
+		    "0x%08"PRIx64" enabled 0x%08"PRIx64,
+		    cap, ena);
+	}
+}
+
+static void
+lagg_ethercap_update(struct lagg_softc *sc)
+{
+	struct ethercom *ec;
+	struct lagg_port *lp;
+	int cap, ena, pena;
+	size_t i;
+
+	KASSERT(LAGG_LOCKED(sc));
+
+	if (sc->sc_if.if_type != IFT_ETHER)
+		return;
+
+	/* Get common enabled capabilities for the lagg ports */
+	ena = ~0;
+	cap = ~0;
+	LAGG_PORTS_FOREACH(sc, lp) {
+		if (lp->lp_iftype == IFT_ETHER) {
+			ec = (struct ethercom *)lp->lp_ifp;
+			ena &= ec->ec_capenable;
+			cap &= ec->ec_capabilities;
+		} else {
+			ena = 0;
+			cap = 0;
+		}
+	}
+
+	if (ena == ~0)
+		ena = 0;
+	if (cap == ~0)
+		cap = 0;
+
+	/*
+	 * Apply common enabled capabilities back to the lagg ports.
+	 * May require several iterations if they are dependent.
+	 */
+	for (i = 0; i < LAGG_SETCAPS_RETRY; i++) {
+		pena = ena;
+		LAGG_PORTS_FOREACH(sc, lp) {
+			if (lp->lp_iftype != IFT_ETHER)
+				continue;
+
+			ec = (struct ethercom *)lp->lp_ifp;
+			lagg_setethcaps(lp, ena);
+			ena &= ec->ec_capenable;
+		}
+
+		if (pena == ena)
+			break;
+	}
+
+	if (pena != ena) {
+		lagg_log(sc, LOG_DEBUG, "couldn't set "
+		    "ether capabilities 0x%08x", pena);
+	}
+
+	ec = (struct ethercom *)&sc->sc_if;
+
+	if (ec->ec_capabilities != cap ||
+	    ec->ec_capenable != ena) {
+		ec->ec_capabilities = cap;
+		ec->ec_capenable = ena;
+
+		lagg_log(sc, LOG_DEBUG,
+		    "ether capabilities 0x%08x"
+		    " enabled 0x%08x", cap, ena);
+	}
+}
+
+static void
+lagg_capabilities_update(struct lagg_softc *sc)
+{
+
+	lagg_ifcap_update(sc);
+	lagg_ethercap_update(sc);
+}
+
+static int
 lagg_setup_mtu(struct lagg_softc *sc, struct lagg_port *lp)
 {
 	struct ifnet *ifp_port;
@@ -2056,8 +2236,13 @@ lagg_port_setup(struct lagg_softc *sc,
 	lp->lp_output = ifp_port->if_output;
 	lp->lp_ifcapenable = ifp_port->if_capenable;
 	lp->lp_mtu = ifp_port->if_mtu;
-	if (lp->lp_iftype == IFT_ETHER)
+	if (lp->lp_iftype == IFT_ETHER) {
+		struct ethercom *ec;
+		ec = (struct ethercom *)ifp_port;
+
 		lagg_lladdr_cpy(lp->lp_lladdr, CLLADDR(ifp_port->if_sadl));
+		lp->lp_eccapenable = ec->ec_capenable;
+	}
 
 	ifp_port->if_type = if_type;
 	ifp_port->if_ioctl = lagg_port_ioctl;
@@ -2103,6 +2288,7 @@ lagg_port_setup(struct lagg_softc *sc,
 	}
 
 	lagg_proto_startport(sc, lp);
+	lagg_capabilities_update(sc);
 
 	return 0;
 
@@ -2196,24 +2382,30 @@ lagg_port_teardown(struct lagg_softc *sc
 	if (ifp_port->if_ioctl == lagg_port_ioctl)
 		ifp_port->if_ioctl = lp->lp_ioctl;
 	ifp_port->if_output = lp->lp_output;
-	ifp_port->if_capenable = lp->lp_ifcapenable;
 	lagg_teardown_mtu(sc, lp);
-	lagg_port_setsadl(lp, lp->lp_lladdr, iftype_changed);
 	IFNET_UNLOCK(ifp_port);
 
-	lagg_proto_freeport(sc, lp);
-	kmem_free(lp, sizeof(*lp));
-
 	if (stopped) {
 		ifp_port->if_init(ifp_port);
 	}
 
 	if (is_ifdetach == false) {
+		lagg_setifcaps(lp, lp->lp_ifcapenable);
+		if (lp->lp_iftype == IFT_ETHER)
+			lagg_setethcaps(lp, lp->lp_eccapenable);
+
 		IFNET_LOCK(ifp_port);
+		if (ifp_port->if_type == IFT_ETHER)
+			lagg_port_setsadl(lp, lp->lp_lladdr, iftype_changed);
+
 		lagg_in6_ifattach(ifp_port);
 		IFNET_UNLOCK(ifp_port);
 	}
 
+	lagg_capabilities_update(sc);
+
+	lagg_proto_freeport(sc, lp);
+	kmem_free(lp, sizeof(*lp));
 }
 
 static int
@@ -2411,6 +2603,7 @@ lagg_port_ioctl(struct ifnet *ifp, u_lon
 		break;
 	case SIOCSIFCAP:
 	case SIOCSIFMTU:
+	case SIOCSETHERCAP:
 		/* Do not allow the setting to be cahanged once joined */
 		error = EINVAL;
 		break;

Index: src/sys/net/lagg/if_laggproto.h
diff -u src/sys/net/lagg/if_laggproto.h:1.6 src/sys/net/lagg/if_laggproto.h:1.7
--- src/sys/net/lagg/if_laggproto.h:1.6	Thu Sep 30 04:29:17 2021
+++ src/sys/net/lagg/if_laggproto.h	Tue Oct 12 08:26:47 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_laggproto.h,v 1.6 2021/09/30 04:29:17 yamaguchi Exp $	*/
+/*	$NetBSD: if_laggproto.h,v 1.7 2021/10/12 08:26:47 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2021 Internet Initiative Japan Inc.
@@ -76,12 +76,14 @@ struct lagg_port {
 
 	u_char			 lp_iftype;
 	uint8_t			 lp_lladdr[ETHER_ADDR_LEN];
+	int			 lp_eccapenable;
+	uint64_t		 lp_ifcapenable;
+	uint64_t		 lp_mtu;
+
 	int			(*lp_ioctl)(struct ifnet *, u_long, void *);
 	int			(*lp_output)(struct ifnet *, struct mbuf *,
 				    const struct sockaddr *,
 				    const struct rtentry *);
-	uint64_t		 lp_ifcapenable;
-	uint64_t		 lp_mtu;
 
 	SIMPLEQ_ENTRY(lagg_port)
 				 lp_entry;

Reply via email to