Module Name:    src
Committed By:   yamaguchi
Date:           Thu Sep 30 04:23:30 UTC 2021

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

Log Message:
Make a link-layer address of lagg(4) configurable by ifconfig(8)

lagg(4) uses a configured link-layer (MAC) address instead
of a random MAC address generated on creating.
The configured MAC address is copied to all child interface
and used for a system id of LACP.


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/sys/net/lagg/if_lagg.c
cvs rdiff -u -r1.3 -r1.4 src/sys/net/lagg/if_lagg_lacp.c
cvs rdiff -u -r1.4 -r1.5 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/if_lagg.c
diff -u src/sys/net/lagg/if_lagg.c:1.8 src/sys/net/lagg/if_lagg.c:1.9
--- src/sys/net/lagg/if_lagg.c:1.8	Thu Sep 30 04:20:14 2021
+++ src/sys/net/lagg/if_lagg.c	Thu Sep 30 04:23:30 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_lagg.c,v 1.8 2021/09/30 04:20:14 yamaguchi Exp $	*/
+/*	$NetBSD: if_lagg.c,v 1.9 2021/09/30 04:23:30 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.8 2021/09/30 04:20:14 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.9 2021/09/30 04:23:30 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -186,8 +186,13 @@ static int	lagg_ether_addmulti(struct la
 static int	lagg_ether_delmulti(struct lagg_softc *, struct ifreq *);
 static void	lagg_port_syncmulti(struct lagg_softc *, struct lagg_port *);
 static void	lagg_port_purgemulti(struct lagg_softc *, struct lagg_port *);
+static int	lagg_port_setup(struct lagg_softc *, struct lagg_port *,
+		    struct ifnet *);
+static void	lagg_port_teardown(struct lagg_softc *, struct lagg_port *,
+		    bool);
 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 struct if_clone	 lagg_cloner =
     IF_CLONE_INITIALIZER("lagg", lagg_clone_create, lagg_clone_destroy);
@@ -209,7 +214,7 @@ static enum lagg_iftypes
 #define LAGG_DPRINTF(_sc, _fmt, _args...)	__nothing
 #endif
 
-static inline size_t
+static size_t
 lagg_sizeof_softc(enum lagg_iftypes ift)
 {
 	struct lagg_softc *_dummy = NULL;
@@ -229,7 +234,7 @@ lagg_sizeof_softc(enum lagg_iftypes ift)
 	return s;
 }
 
-static inline bool
+static bool
 lagg_debug_enable(struct lagg_softc *sc)
 {
 	if (__predict_false(ISSET(sc->sc_if.if_flags, IFF_DEBUG)))
@@ -238,7 +243,7 @@ lagg_debug_enable(struct lagg_softc *sc)
 	return false;
 }
 
-static inline void
+static void
 lagg_evcnt_attach(struct lagg_softc *sc,
     struct evcnt *ev, const char *name)
 {
@@ -247,7 +252,7 @@ lagg_evcnt_attach(struct lagg_softc *sc,
 	    sc->sc_evgroup, name);
 }
 
-static inline void
+static void
 lagg_in6_ifattach(struct ifnet *ifp)
 {
 
@@ -261,7 +266,7 @@ lagg_in6_ifattach(struct ifnet *ifp)
 #endif
 }
 
-static inline void
+static void
 lagg_in6_ifdetach(struct ifnet *ifp)
 {
 
@@ -274,7 +279,7 @@ lagg_in6_ifdetach(struct ifnet *ifp)
 #endif
 }
 
-static inline int
+static int
 lagg_lp_ioctl(struct lagg_port *lp, u_long cmd, void *data)
 {
 	struct ifnet *ifp_port;
@@ -291,6 +296,23 @@ lagg_lp_ioctl(struct lagg_port *lp, u_lo
 	return error;
 }
 
+static bool
+lagg_lladdr_equal(const uint8_t *a, const uint8_t *b)
+{
+
+	if (memcmp(a, b, ETHER_ADDR_LEN) == 0)
+		return true;
+
+	return false;
+}
+
+static void
+lagg_lladdr_cpy(uint8_t *dst, const uint8_t *src)
+{
+
+	memcpy(dst, src, ETHER_ADDR_LEN);
+}
+
 void
 laggattach(int n)
 {
@@ -386,7 +408,8 @@ lagg_clone_create(struct if_clone *ifc, 
 
 	switch (lagg_iftype) {
 	case LAGG_IF_TYPE_ETHERNET:
-		cprng_fast(sc->sc_lladdr, sizeof(sc->sc_lladdr));
+		cprng_fast(sc->sc_lladdr_rand, sizeof(sc->sc_lladdr_rand));
+		lagg_lladdr_cpy(sc->sc_lladdr, sc->sc_lladdr_rand);
 		ether_set_vlan_cb((struct ethercom *)ifp, lagg_vlan_cb);
 		ether_ifattach(ifp, sc->sc_lladdr);
 		break;
@@ -472,6 +495,8 @@ lagg_init_locked(struct lagg_softc *sc)
 	if (ISSET(ifp->if_flags, IFF_RUNNING))
 		lagg_stop_locked(sc);
 
+	lagg_lladdr_update(sc);
+
 	SET(ifp->if_flags, IFF_RUNNING);
 
 	rv = lagg_proto_up(sc);
@@ -1594,142 +1619,6 @@ lagg_pr_detach(struct lagg_softc *sc)
 		kmem_free(var, sizeof(*var));
 }
 
-static void
-lagg_lladdr_set(struct lagg_softc *sc, struct lagg_port *lp, u_long if_type)
-{
-	struct ifnet *ifp, *ifp_port;
-	const uint8_t *lladdr;
-
-	KASSERT(IFNET_LOCKED(&sc->sc_if));
-	KASSERT(LAGG_LOCKED(sc));
-
-	ifp = &sc->sc_if;
-	ifp_port = lp->lp_ifp;
-
-	if (ifp->if_type != IFT_ETHER)
-		return;
-
-	switch (lp->lp_iftype) {
-	case IFT_ETHER:
-		memcpy(lp->lp_lladdr, CLLADDR(ifp_port->if_sadl),
-		    ETHER_ADDR_LEN);
-
-		if (SIMPLEQ_EMPTY(&sc->sc_ports)) {
-			if_set_sadl(ifp, CLLADDR(ifp_port->if_sadl),
-			    ETHER_ADDR_LEN, 0);
-			LAGG_UNLOCK(sc);
-			/* apply new IPv6LLA */
-			lagg_in6_ifdetach(&sc->sc_if);
-			lagg_in6_ifattach(&sc->sc_if);
-			LAGG_LOCK(sc);
-		}
-
-		lladdr = CLLADDR(ifp->if_sadl);
-
-		if (lp->lp_iftype != if_type ||
-		    memcmp(lp->lp_lladdr, lladdr, ETHER_ADDR_LEN) != 0) {
-			IFNET_LOCK(ifp_port);
-			if_set_sadl(ifp_port, lladdr, ETHER_ADDR_LEN, false);
-			IFNET_UNLOCK(ifp_port);
-		}
-		break;
-	}
-}
-
-static void
-lagg_lladdr_update(struct lagg_softc *sc)
-{
-	struct lagg_port *lp;
-	struct ifnet *ifp_port;
-	const uint8_t *lladdr;
-	bool stopped;
-	int error;
-
-	KASSERT(LAGG_LOCKED(sc));
-	KASSERT(sc->sc_if.if_type == IFT_ETHER);
-
-	lladdr = CLLADDR(sc->sc_if.if_sadl);
-
-	LAGG_PORTS_FOREACH(sc, lp) {
-		ifp_port = lp->lp_ifp;
-
-		if (memcmp(lladdr, CLLADDR(ifp_port->if_sadl),
-		    ETHER_ADDR_LEN) == 0) {
-			continue;
-		}
-
-		IFNET_LOCK(ifp_port);
-		if (ISSET(ifp_port->if_flags, IFF_RUNNING)) {
-			ifp_port->if_stop(ifp_port, 0);
-			stopped = true;
-		} else {
-			stopped = false;
-		}
-
-		if_set_sadl(ifp_port, lladdr, ETHER_ADDR_LEN, false);
-
-		if (stopped) {
-			error = ifp_port->if_init(ifp_port);
-
-			if (error != 0) {
-				lagg_log(sc, LOG_WARNING,
-				    "%s failed to if_init() on %d\n",
-				    ifp_port->if_xname, error);
-			}
-		}
-
-		IFNET_UNLOCK(ifp_port);
-	}
-}
-
-static void
-lagg_lladdr_unset(struct lagg_softc *sc, struct lagg_port *lp, u_int if_type)
-{
-	struct ifnet *ifp, *ifp_port;
-	struct lagg_port *lp0;
-
-	KASSERT(IFNET_LOCKED(&sc->sc_if));
-	KASSERT(LAGG_LOCKED(sc));
-
-	ifp = &sc->sc_if;
-	ifp_port = lp->lp_ifp;
-
-	if (ifp->if_type != IFT_ETHER)
-		return;
-
-	switch (lp->lp_iftype) {
-	case IFT_ETHER:
-		if (memcmp(lp->lp_lladdr, CLLADDR(ifp->if_sadl),
-		    ETHER_ADDR_LEN) == 0) {
-			lp0 = SIMPLEQ_FIRST(&sc->sc_ports);
-			if (lp0 == NULL) {
-				if_set_sadl(ifp, sc->sc_lladdr,
-				    ETHER_ADDR_LEN, 0);
-			} else {
-				if_set_sadl(ifp, lp0->lp_lladdr,
-				    ETHER_ADDR_LEN, 0);
-			}
-
-			LAGG_UNLOCK(sc);
-			lagg_in6_ifdetach(ifp);
-			lagg_in6_ifattach(ifp);
-			LAGG_LOCK(sc);
-
-			lagg_lladdr_update(sc);
-		}
-
-		if (lp->lp_iftype != if_type ||
-		    memcmp(lp->lp_lladdr, CLLADDR(ifp_port->if_sadl),
-		    ETHER_ADDR_LEN) != 0) {
-			IFNET_LOCK(ifp_port);
-			if_set_sadl(ifp_port, lp->lp_lladdr,
-			    ETHER_ADDR_LEN, false);
-			IFNET_UNLOCK(ifp_port);
-		}
-		break;
-	}
-}
-
 static int
 lagg_ether_addmulti(struct lagg_softc *sc, struct ifreq *ifr)
 {
@@ -1891,21 +1780,215 @@ lagg_port_purgevlan(struct lagg_softc *s
 }
 
 static int
-lagg_addport_locked(struct lagg_softc *sc, struct lagg_port *lp)
+lagg_setup_mtu(struct lagg_softc *sc, struct lagg_port *lp)
+{
+	struct ifnet *ifp_port;
+	struct ifreq ifr;
+	int error;
+
+	ifp_port = lp->lp_ifp;
+	KASSERT(IFNET_LOCKED(ifp_port));
+
+	error = 0;
+	memset(&ifr, 0, sizeof(ifr));
+
+	if (SIMPLEQ_EMPTY(&sc->sc_ports)) {
+		ifr.ifr_mtu = lp->lp_mtu;
+	} else {
+		ifr.ifr_mtu = sc->sc_if.if_mtu;
+	}
+
+	if (sc->sc_if.if_mtu != (uint64_t)ifr.ifr_mtu) {
+		sc->sc_if.if_mtu = ifr.ifr_mtu;
+	}
+
+	if (lp->lp_mtu != (uint64_t)ifr.ifr_mtu) {
+		if (lp->lp_ioctl == NULL) {
+			LAGG_DPRINTF(sc, "cannot change MTU for %s\n",
+			    ifp_port->if_xname);
+			return EINVAL;
+		}
+
+		strlcpy(ifr.ifr_name, ifp_port->if_xname, sizeof(ifr.ifr_name));
+		error = lp->lp_ioctl(ifp_port, SIOCSIFMTU, (void *)&ifr);
+		if (error != 0) {
+			LAGG_DPRINTF(sc, "invalid MTU %d for %s\n",
+			    ifr.ifr_mtu, ifp_port->if_xname);
+			return error;
+		}
+	}
+
+	return 0;
+}
+
+static void
+lagg_teardown_mtu(struct lagg_softc *sc, struct lagg_port *lp)
 {
 	struct ifnet *ifp_port;
 	struct ifreq ifr;
+	int error;
+
+	if (lp->lp_ioctl == NULL)
+		return;
+
+	ifp_port = lp->lp_ifp;
+	KASSERT(IFNET_LOCKED(ifp_port));
+
+	if (SIMPLEQ_EMPTY(&sc->sc_ports)) {
+		sc->sc_if.if_mtu = 0;
+	}
+
+	if (ifp_port->if_mtu != lp->lp_mtu) {
+		memset(&ifr, 0, sizeof(ifr));
+		strlcpy(ifr.ifr_name, ifp_port->if_xname, sizeof(ifr.ifr_name));
+		ifr.ifr_mtu = lp->lp_mtu;
+		error = lp->lp_ioctl(ifp_port, SIOCSIFMTU, (void *)&ifr);
+		if (error != 0) {
+			lagg_log(sc, LOG_WARNING,
+			    "failed to reset MTU %d to %s\n",
+			    ifr.ifr_mtu, ifp_port->if_xname);
+		}
+	}
+}
+
+static void
+lagg_port_setsadl(struct lagg_port *lp, uint8_t *lladdr,
+    bool iftype_changed)
+{
+	struct ifnet *ifp_port;
+	bool lladdr_changed;
+	int error;
+
+	ifp_port = lp->lp_ifp;
+
+	KASSERT(LAGG_LOCKED(lp->lp_softc));
+	KASSERT(IFNET_LOCKED(ifp_port));
+
+	lladdr_changed = false;
+	if (iftype_changed) {
+		lladdr_changed = true;
+	} else if (lagg_lladdr_equal(lladdr,
+	    CLLADDR(ifp_port->if_sadl)) == false) {
+		lladdr_changed = true;
+	}
+
+	if (lladdr_changed) {
+		if_set_sadl(ifp_port, lladdr,
+		    ETHER_ADDR_LEN, false);
+		if (ISSET(ifp_port->if_flags, IFF_RUNNING)) {
+			error = ifp_port->if_init(ifp_port);
+			if (error != 0) {
+				lagg_log(lp->lp_softc, LOG_WARNING,
+				    "%s failed to if_init() on %d\n",
+				    ifp_port->if_xname, error);
+			}
+		}
+	}
+}
+
+static void
+lagg_setup_lladdr(struct lagg_softc *sc, struct lagg_port *lp)
+{
+
+	KASSERT(LAGG_LOCKED(sc));
+
+	if (lagg_lladdr_equal(sc->sc_lladdr, sc->sc_lladdr_rand)) {
+		lagg_lladdr_cpy(sc->sc_lladdr, lp->lp_lladdr);
+	}
+}
+
+static void
+lagg_teardown_lladdr(struct lagg_softc *sc, struct lagg_port *lp)
+{
+	struct lagg_port *lp0;
+	uint8_t *lladdr_next;
+
+	KASSERT(LAGG_LOCKED(sc));
+
+	if (lagg_lladdr_equal(sc->sc_lladdr,
+	    lp->lp_lladdr) == false) {
+		return;
+	}
+
+	lladdr_next = sc->sc_lladdr_rand;
+
+	LAGG_PORTS_FOREACH(sc, lp0) {
+		if (lp0->lp_iftype == IFT_ETHER) {
+			lladdr_next = lp0->lp_lladdr;
+			break;
+		}
+	}
+
+	lagg_lladdr_cpy(sc->sc_lladdr, lladdr_next);
+}
+
+static void
+lagg_lladdr_update(struct lagg_softc *sc)
+{
+	struct ifnet *ifp;
+	struct lagg_port *lp;
+	const uint8_t *lladdr;
+
+	ifp = &sc->sc_if;
+
+	KASSERT(LAGG_LOCKED(sc));
+	KASSERT(IFNET_LOCKED(ifp));
+	KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING));
+
+	lladdr = CLLADDR(ifp->if_sadl);
+
+	if (lagg_lladdr_equal(sc->sc_lladdr, lladdr))
+		return;
+
+	lagg_lladdr_cpy(sc->sc_lladdr, lladdr);
+
+	LAGG_PORTS_FOREACH(sc, lp) {
+		if (lp->lp_iftype == IFT_ETHER) {
+			IFNET_LOCK(lp->lp_ifp);
+			lagg_port_setsadl(lp, sc->sc_lladdr, false);
+			IFNET_UNLOCK(lp->lp_ifp);
+		}
+	}
+}
+
+static void
+lagg_sadl_update(struct lagg_softc *sc, uint8_t *lladdr_prev)
+{
+	struct ifnet *ifp;
+	const uint8_t *lladdr;
+
+	ifp = &sc->sc_if;
+
+	KASSERT(LAGG_LOCKED(sc));
+	KASSERT(IFNET_LOCKED(ifp));
+
+	lladdr = CLLADDR(ifp->if_sadl);
+
+	if (lagg_lladdr_equal(sc->sc_lladdr, lladdr))
+		return;
+
+	if (lagg_lladdr_equal(lladdr_prev, lladdr) == false)
+		return;
+
+	if_set_sadl(ifp, sc->sc_lladdr, ETHER_ADDR_LEN, false);
+
+	LAGG_UNLOCK(sc);
+	lagg_in6_ifdetach(ifp);
+	lagg_in6_ifattach(ifp);
+	LAGG_LOCK(sc);
+}
+
+static int
+lagg_port_setup(struct lagg_softc *sc,
+    struct lagg_port *lp, struct ifnet *ifp_port)
+{
 	u_char if_type;
-	uint64_t mtu_port;
 	int error;
-	bool stopped;
+	bool stopped, iftype_changed;
 
-	KASSERT(IFNET_LOCKED(&sc->sc_if));
 	KASSERT(LAGG_LOCKED(sc));
-	KASSERT(lp != NULL);
+	IFNET_ASSERT_UNLOCKED(ifp_port);
 
-	stopped = false;
-	ifp_port = lp->lp_ifp;
 	if (&sc->sc_if == ifp_port) {
 		LAGG_DPRINTF(sc, "cannot add a lagg to itself as a port\n");
 		return EINVAL;
@@ -1931,61 +2014,52 @@ lagg_addport_locked(struct lagg_softc *s
 		return ENOTSUP;
 	}
 
-	mtu_port = ifp_port->if_mtu;
-	if (SIMPLEQ_EMPTY(&sc->sc_ports)) {
-		sc->sc_if.if_mtu = mtu_port;
-	} else if (sc->sc_if.if_mtu != mtu_port) {
-		if (ifp_port->if_ioctl == NULL) {
-			LAGG_DPRINTF(sc, "cannot change MTU for %s\n",
-			    ifp_port->if_xname);
-			return EINVAL;
-		}
-		memset(&ifr, 0, sizeof(ifr));
-		strlcpy(ifr.ifr_name, ifp_port->if_xname, sizeof(ifr.ifr_name));
-		ifr.ifr_mtu = sc->sc_if.if_mtu;
+	error = 0;
+	stopped = false;
+	lp->lp_softc = sc;
+	lp->lp_prio = LAGG_PORT_PRIO;
+	lp->lp_linkstate_hook = if_linkstate_change_establish(ifp_port,
+	    lagg_linkstate_changed, ifp_port);
+	psref_target_init(&lp->lp_psref, lagg_port_psref_class);
 
-		IFNET_LOCK(ifp_port);
-		error = ifp_port->if_ioctl(ifp_port, SIOCSIFMTU, (void *)&ifr);
-		IFNET_UNLOCK(ifp_port);
+	IFNET_LOCK(ifp_port);
+	lp->lp_iftype = ifp_port->if_type;
+	lp->lp_ioctl = ifp_port->if_ioctl;
+	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)
+		lagg_lladdr_cpy(lp->lp_lladdr, CLLADDR(ifp_port->if_sadl));
 
-		if (error != 0) {
-			LAGG_DPRINTF(sc, "invalid MTU for %s\n",
-			    ifp_port->if_xname);
-			return error;
-		}
-	}
+	ifp_port->if_type = if_type;
+	ifp_port->if_ioctl = lagg_port_ioctl;
+	ifp_port->if_output = lagg_port_output;
+
+	iftype_changed = (lp->lp_iftype != ifp_port->if_type);
 
-	IFNET_LOCK(ifp_port);
 	if (ISSET(ifp_port->if_flags, IFF_RUNNING)) {
 		ifp_port->if_stop(ifp_port, 0);
 		stopped = true;
 	}
+
 	/* to delete ipv6 link local address */
 	lagg_in6_ifdetach(ifp_port);
-	IFNET_UNLOCK(ifp_port);
 
-	lp->lp_softc = sc;
-	lp->lp_iftype = ifp_port->if_type;
-	lp->lp_ioctl = ifp_port->if_ioctl;
-	lp->lp_output = ifp_port->if_output;
-	lp->lp_ifcapenable = ifp_port->if_capenable;
-	lp->lp_mtu = mtu_port;
-	lp->lp_prio = LAGG_PORT_PRIO;
-	lp->lp_linkstate_hook = if_linkstate_change_establish(ifp_port,
-	    lagg_linkstate_changed, ifp_port);
-	psref_target_init(&lp->lp_psref, lagg_port_psref_class);
+	error = lagg_setup_mtu(sc, lp);
+	if (error != 0) {
+		goto restore_ipv6lla;
+	}
 
-	IFNET_LOCK(ifp_port);
-	ifp_port->if_type = if_type;
-	ifp_port->if_ioctl = lagg_port_ioctl;
-	ifp_port->if_output = lagg_port_output;
-	IFNET_UNLOCK(ifp_port);
+	if (lp->lp_iftype == IFT_ETHER) {
+		lagg_setup_lladdr(sc, lp);
+		lagg_port_setsadl(lp, sc->sc_lladdr, iftype_changed);
+	}
 
-	lagg_lladdr_set(sc, lp, if_type);
+	IFNET_UNLOCK(ifp_port);
 
 	error = lagg_proto_allocport(sc, lp);
 	if (error != 0)
-		goto restore_lladdr;
+		goto teardown_lladdr;
 
 	lagg_port_syncmulti(sc, lp);
 	lagg_port_syncvlan(sc, lp);
@@ -2012,52 +2086,46 @@ remove_port:
 	lagg_port_purgemulti(sc, lp);
 	lagg_port_purgevlan(sc, lp);
 
-restore_lladdr:
-	lagg_lladdr_unset(sc, lp, if_type);
-	if_linkstate_change_disestablish(ifp_port,
-	    lp->lp_linkstate_hook, NULL);
-	psref_target_destroy(&lp->lp_psref, lagg_port_psref_class);
-
+teardown_lladdr:
 	IFNET_LOCK(ifp_port);
-	ifp_port->if_type = lp->lp_iftype;
-	ifp_port->if_ioctl = lp->lp_ioctl;
-	ifp_port->if_output = lp->lp_output;
+	lagg_teardown_mtu(sc, lp);
+	if (lp->lp_iftype == IFT_ETHER) {
+		/* restore iftype before if_set_sadl */
+		ifp_port->if_type = lp->lp_iftype;
+		lagg_port_setsadl(lp, lp->lp_lladdr, iftype_changed);
+
+		lagg_teardown_lladdr(sc, lp);
+	}
+restore_ipv6lla:
+	KASSERT(IFNET_LOCKED(ifp_port));
+	lagg_in6_ifdetach(ifp_port);
 	if (stopped) {
-		(void)ifp_port->if_init(ifp_port);
+		if (ifp_port->if_init(ifp_port) != 0) {
+			lagg_log(sc, LOG_WARNING,
+			    "couldn't re-start port %s\n",
+			    ifp_port->if_xname);
+		}
 	}
-	lagg_in6_ifattach(ifp_port);
-	IFNET_UNLOCK(ifp_port);
-
-	return error;
-}
-
-static int
-lagg_addport(struct lagg_softc *sc, struct ifnet *ifp_port)
-{
-	struct lagg_port *lp;
-	int error;
-
-	lp = kmem_zalloc(sizeof(*lp), KM_SLEEP);
-	lp->lp_ifp = ifp_port;
+	ifp_port->if_type = lp->lp_iftype;
+	if (ifp_port->if_ioctl == lagg_port_ioctl)
+		ifp_port->if_ioctl = lp->lp_ioctl;
+	ifp_port->if_output = lp->lp_output;
 
-	LAGG_LOCK(sc);
-	error = lagg_addport_locked(sc, lp);
-	LAGG_UNLOCK(sc);
+	IFNET_UNLOCK(ifp_port);
 
-	if (error != 0)
-		kmem_free(lp, sizeof(*lp));
+	psref_target_destroy(&lp->lp_psref, lagg_port_psref_class);
+	if_linkstate_change_disestablish(ifp_port,
+	    lp->lp_linkstate_hook, NULL);
 
 	return error;
 }
 
 static void
-lagg_delport_locked(struct lagg_softc *sc, struct lagg_port *lp,
+lagg_port_teardown(struct lagg_softc *sc, struct lagg_port *lp,
     bool is_ifdetach)
 {
 	struct ifnet *ifp_port;
-	struct ifreq ifr;
-	u_long if_type;
-	bool stopped;
+	bool stopped, iftype_changed;
 
 	KASSERT(LAGG_LOCKED(sc));
 
@@ -2078,35 +2146,26 @@ lagg_delport_locked(struct lagg_softc *s
 	lagg_proto_stopport(sc, lp);
 	psref_target_destroy(&lp->lp_psref, lagg_port_psref_class);
 
+	lagg_port_purgemulti(sc, lp);
+	lagg_port_purgevlan(sc, lp);
+	lagg_teardown_lladdr(sc, lp);
+
+	IFNET_LOCK(ifp_port);
 	if (ISSET(ifp_port->if_flags, IFF_RUNNING)) {
 		ifp_port->if_stop(ifp_port, 0);
 		stopped = true;
 	}
 
-	if (lp->lp_mtu != ifp_port->if_mtu) {
-		memset(&ifr, 0, sizeof(ifr));
-		strlcpy(ifr.ifr_name, ifp_port->if_xname, sizeof(ifr.ifr_name));
-		ifr.ifr_mtu = lp->lp_mtu;
-		(void)lagg_lp_ioctl(lp, SIOCSIFMTU, &ifr);
-	}
-
-	if (SIMPLEQ_EMPTY(&sc->sc_ports)) {
-		sc->sc_if.if_mtu = 0;
-	}
-
-	lagg_port_purgemulti(sc, lp);
-	lagg_port_purgevlan(sc, lp);
-
-	IFNET_LOCK(ifp_port);
-	if_type = ifp_port->if_type;
+	iftype_changed = (ifp_port->if_type != lp->lp_iftype);
 	ifp_port->if_type = lp->lp_iftype;
-	ifp_port->if_ioctl = lp->lp_ioctl;
+	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_lladdr_unset(sc, lp, if_type);
-
 	lagg_proto_freeport(sc, lp);
 	kmem_free(lp, sizeof(*lp));
 
@@ -2119,38 +2178,71 @@ lagg_delport_locked(struct lagg_softc *s
 		lagg_in6_ifattach(ifp_port);
 		IFNET_UNLOCK(ifp_port);
 	}
+
 }
 
-static void
-lagg_delport_all(struct lagg_softc *sc)
+static int
+lagg_addport(struct lagg_softc *sc, struct ifnet *ifp_port)
 {
-	struct lagg_port *lp, *lp0;
+	struct lagg_port *lp;
+	uint8_t lladdr[ETHER_ADDR_LEN];
+	int error;
+
+	lp = kmem_zalloc(sizeof(*lp), KM_SLEEP);
+	lp->lp_ifp = ifp_port;
 
 	LAGG_LOCK(sc);
-	LAGG_PORTS_FOREACH_SAFE(sc, lp, lp0) {
-		lagg_delport_locked(sc, lp, false);
-	}
+	lagg_lladdr_cpy(lladdr, sc->sc_lladdr);
+	error = lagg_port_setup(sc, lp, ifp_port);
+	if (error == 0)
+		lagg_sadl_update(sc, lladdr);
 	LAGG_UNLOCK(sc);
+
+	if (error != 0)
+		kmem_free(lp, sizeof(*lp));
+
+	return error;
 }
 
 static int
 lagg_delport(struct lagg_softc *sc, struct ifnet *ifp_port)
 {
 	struct lagg_port *lp;
+	uint8_t lladdr[ETHER_ADDR_LEN];
 
 	KASSERT(IFNET_LOCKED(&sc->sc_if));
 
+	LAGG_LOCK(sc);
 	lp = ifp_port->if_lagg;
-	if (lp == NULL || lp->lp_softc != sc)
+	if (lp == NULL || lp->lp_softc != sc) {
+		LAGG_UNLOCK(sc);
 		return ENOENT;
+	}
 
-	LAGG_LOCK(sc);
-	lagg_delport_locked(sc, lp, false);
+	lagg_lladdr_cpy(lladdr, sc->sc_lladdr);
+	lagg_port_teardown(sc, lp, false);
+	lagg_sadl_update(sc, lladdr);
 	LAGG_UNLOCK(sc);
 
 	return 0;
 }
 
+static void
+lagg_delport_all(struct lagg_softc *sc)
+{
+	struct lagg_port *lp, *lp0;
+	uint8_t lladdr[ETHER_ADDR_LEN];
+
+	LAGG_LOCK(sc);
+	lagg_lladdr_cpy(lladdr, sc->sc_lladdr);
+	LAGG_PORTS_FOREACH_SAFE(sc, lp, lp0) {
+		lagg_port_teardown(sc, lp, false);
+	}
+
+	lagg_sadl_update(sc, lladdr);
+	LAGG_UNLOCK(sc);
+}
+
 static int
 lagg_get_stats(struct lagg_softc *sc, struct lagg_req *resp,
     size_t nports)
@@ -2318,6 +2410,7 @@ lagg_ifdetach(struct ifnet *ifp_port)
 {
 	struct lagg_port *lp;
 	struct lagg_softc *sc;
+	uint8_t lladdr[ETHER_ADDR_LEN];
 	int s;
 
 	IFNET_ASSERT_UNLOCKED(ifp_port);
@@ -2343,7 +2436,9 @@ lagg_ifdetach(struct ifnet *ifp_port)
 	 * after pserialize_read_exit.
 	 */
 	lp = ifp_port->if_lagg;
-	lagg_delport_locked(sc, lp, true);
+	lagg_lladdr_cpy(lladdr, sc->sc_lladdr);
+	lagg_port_teardown(sc, lp, true);
+	lagg_sadl_update(sc, lladdr);
 	LAGG_UNLOCK(sc);
 	IFNET_UNLOCK(&sc->sc_if);
 }

Index: src/sys/net/lagg/if_lagg_lacp.c
diff -u src/sys/net/lagg/if_lagg_lacp.c:1.3 src/sys/net/lagg/if_lagg_lacp.c:1.4
--- src/sys/net/lagg/if_lagg_lacp.c:1.3	Wed Jun 30 06:39:47 2021
+++ src/sys/net/lagg/if_lagg_lacp.c	Thu Sep 30 04:23:30 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_lagg_lacp.c,v 1.3 2021/06/30 06:39:47 yamaguchi Exp $	*/
+/*	$NetBSD: if_lagg_lacp.c,v 1.4 2021/09/30 04:23:30 yamaguchi Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_lagg_lacp.c,v 1.3 2021/06/30 06:39:47 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lagg_lacp.c,v 1.4 2021/09/30 04:23:30 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_lagg.h"
@@ -535,6 +535,11 @@ lacp_up(struct lagg_proto_softc *xlsc)
 	KASSERT(LAGG_LOCKED(sc));
 
 	LACP_LOCK(lsc);
+	if (memcmp(lsc->lsc_system_mac, LAGG_CLLADDR(sc),
+	    sizeof(lsc->lsc_system_mac)) != 0) {
+		memcpy(lsc->lsc_system_mac, LAGG_CLLADDR(sc),
+		    sizeof(lsc->lsc_system_mac));
+	}
 	lsc->lsc_running = true;
 	callout_schedule(&lsc->lsc_tick, hz);
 	LACP_UNLOCK(lsc);
@@ -566,6 +571,9 @@ lacp_down_locked(struct lacp_softc *lsc)
 		lacp_port_disable(lsc, lp->lp_proto_ctx);
 	}
 
+	memset(lsc->lsc_system_mac, 0,
+	    sizeof(lsc->lsc_system_mac));
+
 	LACP_DPRINTF((lsc, NULL, "lacp stopped\n"));
 }
 
@@ -647,10 +655,6 @@ lacp_allocport(struct lagg_proto_softc *
 	lagg_work_set(&lacpp->lp_work_marker, lacp_marker_work, lsc);
 
 	LACP_LOCK(lsc);
-	if (LAGG_PORTS_EMPTY(sc)) {
-		memcpy(lsc->lsc_system_mac, LAGG_CLLADDR(sc),
-		    sizeof(lsc->lsc_system_mac));
-	}
 	lacp_sm_port_init(lsc, lacpp, lp);
 	LACP_UNLOCK(lsc);
 
@@ -700,9 +704,8 @@ void
 lacp_freeport(struct lagg_proto_softc *xlsc, struct lagg_port *lp)
 {
 	struct lacp_softc *lsc;
-	struct lacp_port *lacpp, *lacpp0;
+	struct lacp_port *lacpp;
 	struct lagg_softc *sc;
-	struct lagg_port *lp0;
 	struct ifreq ifr;
 
 	lsc = (struct lacp_softc *)xlsc;
@@ -720,22 +723,6 @@ lacp_freeport(struct lagg_proto_softc *x
 	(void)lp->lp_ioctl(lp->lp_ifp, SIOCDELMULTI, (void *)&ifr);
 	IFNET_UNLOCK(lp->lp_ifp);
 
-	LACP_LOCK(lsc);
-	if (LAGG_PORTS_EMPTY(sc)) {
-		memset(lsc->lsc_system_mac, 0,
-		    sizeof(lsc->lsc_system_mac));
-	} else if (memcmp(LAGG_CLLADDR(sc), lsc->lsc_system_mac,
-	    sizeof(lsc->lsc_system_mac)) != 0) {
-		memcpy(lsc->lsc_system_mac, LAGG_CLLADDR(sc),
-		    sizeof(lsc->lsc_system_mac));
-		LAGG_PORTS_FOREACH(sc, lp0) {
-			lacpp0 = lp0->lp_proto_ctx;
-			lacpp0->lp_selected = LACP_UNSELECTED;
-			/* reset state of the port at lacp_set_mux() */
-		}
-	}
-	LACP_UNLOCK(lsc);
-
 	lp->lp_proto_ctx = NULL;
 	kmem_free(lacpp, sizeof(*lacpp));
 }

Index: src/sys/net/lagg/if_laggproto.h
diff -u src/sys/net/lagg/if_laggproto.h:1.4 src/sys/net/lagg/if_laggproto.h:1.5
--- src/sys/net/lagg/if_laggproto.h:1.4	Thu Sep 30 03:39:39 2021
+++ src/sys/net/lagg/if_laggproto.h	Thu Sep 30 04:23:30 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_laggproto.h,v 1.4 2021/09/30 03:39:39 yamaguchi Exp $	*/
+/*	$NetBSD: if_laggproto.h,v 1.5 2021/09/30 04:23:30 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2021 Internet Initiative Japan Inc.
@@ -142,7 +142,12 @@ struct lagg_softc {
 	kmutex_t		 sc_lock;
 	struct ifmedia		 sc_media;
 	u_char			 sc_iftype;
+
+	/* interface link-layer address */
 	uint8_t			 sc_lladdr[ETHER_ADDR_LEN];
+	/* generated random lladdr */
+	uint8_t			 sc_lladdr_rand[ETHER_ADDR_LEN];
+
 	LIST_HEAD(, lagg_mc_entry)
 				 sc_mclist;
 	TAILQ_HEAD(, lagg_vlantag)

Reply via email to