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)