Module Name:    src
Committed By:   yamaguchi
Date:           Mon Nov  8 06:22:16 UTC 2021

Modified Files:
        src/sys/net/lagg: if_lagg.c

Log Message:
lagg: renew MAC addresses to change the value of interface type

The interface type(ifnet::if_type) is changed on adding to lagg(4)
and deleting from it.


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/net/lagg/if_lagg.c

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.18 src/sys/net/lagg/if_lagg.c:1.19
--- src/sys/net/lagg/if_lagg.c:1.18	Mon Nov  8 06:17:05 2021
+++ src/sys/net/lagg/if_lagg.c	Mon Nov  8 06:22:16 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_lagg.c,v 1.18 2021/11/08 06:17:05 yamaguchi Exp $	*/
+/*	$NetBSD: if_lagg.c,v 1.19 2021/11/08 06:22:16 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2005, 2006 Reyk Floeter <r...@openbsd.org>
@@ -20,7 +20,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.18 2021/11/08 06:17:05 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.19 2021/11/08 06:22:16 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -31,6 +31,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 
 #include <sys/types.h>
 
 #include <sys/cprng.h>
+#include <sys/cpu.h>
 #include <sys/device.h>
 #include <sys/evcnt.h>
 #include <sys/hash.h>
@@ -133,6 +134,7 @@ static const struct lagg_proto lagg_prot
 	},
 };
 
+static int	lagg_chg_sadl(struct ifnet *, uint8_t *, size_t);
 static struct mbuf *
 		lagg_input_ethernet(struct ifnet *, struct mbuf *);
 static int	lagg_clone_create(struct if_clone *, int);
@@ -2086,8 +2088,8 @@ lagg_port_setsadl(struct lagg_port *lp, 
 			break;
 		}
 
-		if_set_sadl(ifp_port, lladdr,
-		    ETHER_ADDR_LEN, false);
+		lagg_chg_sadl(ifp_port,
+		    lladdr, ETHER_ADDR_LEN);
 
 		if (!ISSET(ifp_port->if_flags, IFF_RUNNING)) {
 			break;
@@ -2123,11 +2125,11 @@ lagg_port_unsetsadl(struct lagg_port *lp
 
 	switch (lp->lp_iftype) {
 	case IFT_ETHER:
-		/* reset if_type before if_set_sadl */
+		/* reset if_type before changing ifp->if_sadl */
 		ifp_port->if_type = lp->lp_iftype;
 
-		if_set_sadl(ifp_port, lp->lp_lladdr,
-		    ETHER_ADDR_LEN, false);
+		lagg_chg_sadl(ifp_port,
+		    lp->lp_lladdr, ETHER_ADDR_LEN);
 
 		if (!ISSET(ifp_port->if_flags, IFF_RUNNING)) {
 			break;
@@ -2237,7 +2239,7 @@ lagg_sadl_update(struct lagg_softc *sc, 
 	if (lagg_lladdr_equal(lladdr_prev, lladdr) == false)
 		return;
 
-	if_set_sadl(ifp, sc->sc_lladdr, ETHER_ADDR_LEN, false);
+	lagg_chg_sadl(ifp, sc->sc_lladdr, ETHER_ADDR_LEN);
 
 	LAGG_PORTS_FOREACH(sc, lp) {
 		IFNET_LOCK(lp->lp_ifp);
@@ -2899,6 +2901,120 @@ lagg_workq_wait(struct workqueue *wq, st
 	workqueue_wait(wq, &lw->lw_cookie);
 }
 
+static int
+lagg_chg_sadl(struct ifnet *ifp, uint8_t *lla, size_t lla_len)
+{
+	struct psref psref_cur, psref_next;
+	struct ifaddr *ifa_cur, *ifa_next, *ifa_lla;
+	const struct sockaddr_dl *sdl, *nsdl;
+	int s, error;
+
+	KASSERT(!cpu_intr_p() && !cpu_softintr_p());
+	KASSERT(IFNET_LOCKED(ifp));
+	KASSERT(ifp->if_addrlen == lla_len);
+
+	error = 0;
+	ifa_lla = NULL;
+
+	while (1) {
+		s = pserialize_read_enter();
+		IFADDR_READER_FOREACH(ifa_cur, ifp) {
+			sdl = satocsdl(ifa_cur->ifa_addr);
+			if (sdl->sdl_family != AF_LINK)
+				continue;
+
+			if (sdl->sdl_type != ifp->if_type) {
+				ifa_acquire(ifa_cur, &psref_cur);
+				break;
+			}
+		}
+		pserialize_read_exit(s);
+
+		if (ifa_cur == NULL)
+			break;
+
+		ifa_next = if_dl_create(ifp, &nsdl);
+		if (ifa_next == NULL) {
+			error = ENOMEM;
+			ifa_release(ifa_cur, &psref_cur);
+			goto done;
+		}
+		ifa_acquire(ifa_next, &psref_next);
+		(void)sockaddr_dl_setaddr(__UNCONST(nsdl), nsdl->sdl_len,
+		    CLLADDR(sdl), ifp->if_addrlen);
+		ifa_insert(ifp, ifa_next);
+
+		if (ifa_lla == NULL &&
+		    memcmp(CLLADDR(sdl), lla, lla_len) == 0) {
+			ifa_lla = ifa_next;
+			ifaref(ifa_lla);
+		}
+
+		if (ifa_cur == ifp->if_dl)
+			if_activate_sadl(ifp, ifa_next, nsdl);
+
+		if (ifa_cur == ifp->if_hwdl) {
+			ifp->if_hwdl = ifa_next;
+			ifaref(ifa_next);
+			ifafree(ifa_cur);
+		}
+
+		ifaref(ifa_cur);
+		ifa_release(ifa_cur, &psref_cur);
+		ifa_remove(ifp, ifa_cur);
+		KASSERTMSG(ifa_cur->ifa_refcnt == 1,
+		    "ifa_refcnt=%d", ifa_cur->ifa_refcnt);
+		ifafree(ifa_cur);
+		ifa_release(ifa_next, &psref_next);
+	}
+
+	if (ifa_lla != NULL) {
+		ifa_next = ifa_lla;
+
+		ifa_acquire(ifa_next, &psref_next);
+		ifafree(ifa_lla);
+
+		nsdl = satocsdl(ifa_next->ifa_addr);
+	} else {
+		ifa_next = if_dl_create(ifp, &nsdl);
+		if (ifa_next == NULL) {
+			error = ENOMEM;
+			goto done;
+		}
+		ifa_acquire(ifa_next, &psref_next);
+		(void)sockaddr_dl_setaddr(__UNCONST(nsdl),
+		    nsdl->sdl_len, lla, ifp->if_addrlen);
+		ifa_insert(ifp, ifa_next);
+	}
+
+	if (ifa_next != ifp->if_dl) {
+		ifa_cur = ifp->if_dl;
+		if (ifa_cur != NULL)
+			ifa_acquire(ifa_cur, &psref_cur);
+
+		if_activate_sadl(ifp, ifa_next, nsdl);
+
+		if (ifa_cur != NULL) {
+			if (ifa_cur != ifp->if_hwdl) {
+				ifaref(ifa_cur);
+				ifa_release(ifa_cur, &psref_cur);
+				ifa_remove(ifp, ifa_cur);
+				KASSERTMSG(ifa_cur->ifa_refcnt == 1,
+				    "ifa_refcnt=%d",
+				    ifa_cur->ifa_refcnt);
+				ifafree(ifa_cur);
+			} else {
+				ifa_release(ifa_cur, &psref_cur);
+			}
+		}
+	}
+
+	ifa_release(ifa_next, &psref_next);
+
+done:
+	return error;
+}
+
 /*
  * Module infrastructure
  */

Reply via email to