git: 0bd0c3295ac0 - main - ng_ether: refactor to use interface EVENTHANDLER(9)s

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Mon, 22 Dec 2025 02:23:49 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=0bd0c3295ac09f759f2816b73cbd2d950e3bef7e

commit 0bd0c3295ac09f759f2816b73cbd2d950e3bef7e
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-12-21 22:13:58 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-12-22 02:23:14 +0000

    ng_ether: refactor to use interface EVENTHANDLER(9)s
---
 sys/net/ethernet.h      |   4 --
 sys/net/if.c            |   5 --
 sys/net/if_bridge.c     |   2 -
 sys/net/if_ethersubr.c  |  32 -----------
 sys/netgraph/ng_ether.c | 141 ++++++++++++++++++++++--------------------------
 5 files changed, 64 insertions(+), 120 deletions(-)

diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h
index 01485cf26e06..85e0ddb74144 100644
--- a/sys/net/ethernet.h
+++ b/sys/net/ethernet.h
@@ -460,10 +460,6 @@ extern	uint32_t ether_crc32_be(const uint8_t *, size_t);
 extern	void ether_demux(struct ifnet *, struct mbuf *);
 extern	void ether_ifattach(struct ifnet *, const u_int8_t *);
 extern	void ether_ifdetach(struct ifnet *);
-#ifdef VIMAGE
-struct vnet;
-extern	void ether_reassign(struct ifnet *, struct vnet *, char *);
-#endif
 extern	int  ether_ioctl(struct ifnet *, u_long, caddr_t);
 extern	int  ether_output(struct ifnet *, struct mbuf *,
 	    const struct sockaddr *, struct route *);
diff --git a/sys/net/if.c b/sys/net/if.c
index 1dea00da3cf2..4ddf8a69b3f0 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -239,7 +239,6 @@ static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions");
 static struct sx ifdescr_sx;
 SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr");
 
-void	(*ng_ether_link_state_p)(struct ifnet *ifp, int state);
 void	(*lagg_linkstate_p)(struct ifnet *ifp, int state);
 /* These are external hooks for CARP. */
 void	(*carp_linkstate_p)(struct ifnet *ifp);
@@ -2031,10 +2030,6 @@ do_link_state_change(void *arg, int pending)
 	rt_ifmsg(ifp, 0);
 	if (ifp->if_vlantrunk != NULL)
 		(*vlan_link_state_p)(ifp);
-
-	if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) &&
-	    ifp->if_l2com != NULL)
-		(*ng_ether_link_state_p)(ifp, link_state);
 	if (ifp->if_carp)
 		(*carp_linkstate_p)(ifp);
 	if (ifp->if_bridge)
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index d7911a348d87..9a468a8eb462 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -801,8 +801,6 @@ bridge_reassign(struct ifnet *ifp, struct vnet *newvnet, char *arg)
 	}
 
 	BRIDGE_UNLOCK(sc);
-
-	ether_reassign(ifp, newvnet, arg);
 }
 #endif
 
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 9c157bf3d3c2..da9264aa4a23 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -98,8 +98,6 @@ VNET_DEFINE(pfil_head_t, link_pfil_head);	/* Packet filter hooks */
 void	(*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
 void	(*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m);
 int	(*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);
-void	(*ng_ether_attach_p)(struct ifnet *ifp);
-void	(*ng_ether_detach_p)(struct ifnet *ifp);
 
 /* if_bridge(4) support */
 void	(*bridge_dn_p)(struct mbuf *, struct ifnet *);
@@ -988,9 +986,6 @@ ether_ifattach(struct ifnet *ifp, const u_int8_t *lla)
 	ifp->if_input = ether_input;
 	ifp->if_resolvemulti = ether_resolvemulti;
 	ifp->if_requestencap = ether_requestencap;
-#ifdef VIMAGE
-	ifp->if_reassign = ether_reassign;
-#endif
 	if (ifp->if_baudrate == 0)
 		ifp->if_baudrate = IF_Mbps(10);		/* just a default */
 	ifp->if_broadcastaddr = etherbroadcastaddr;
@@ -1006,8 +1001,6 @@ ether_ifattach(struct ifnet *ifp, const u_int8_t *lla)
 		bcopy(lla, ifp->if_hw_addr, ifp->if_addrlen);
 
 	bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN);
-	if (ng_ether_attach_p != NULL)
-		(*ng_ether_attach_p)(ifp);
 
 	/* Announce Ethernet MAC address if non-zero. */
 	for (i = 0; i < ifp->if_addrlen; i++)
@@ -1035,35 +1028,10 @@ ether_ifdetach(struct ifnet *ifp)
 	sdl = (struct sockaddr_dl *)(ifp->if_addr->ifa_addr);
 	uuid_ether_del(LLADDR(sdl));
 
-	if (ifp->if_l2com != NULL) {
-		KASSERT(ng_ether_detach_p != NULL,
-		    ("ng_ether_detach_p is NULL"));
-		(*ng_ether_detach_p)(ifp);
-	}
-
 	bpfdetach(ifp);
 	if_detach(ifp);
 }
 
-#ifdef VIMAGE
-void
-ether_reassign(struct ifnet *ifp, struct vnet *new_vnet, char *unused __unused)
-{
-
-	if (ifp->if_l2com != NULL) {
-		KASSERT(ng_ether_detach_p != NULL,
-		    ("ng_ether_detach_p is NULL"));
-		(*ng_ether_detach_p)(ifp);
-	}
-
-	if (ng_ether_attach_p != NULL) {
-		CURVNET_SET_QUIET(new_vnet);
-		(*ng_ether_attach_p)(ifp);
-		CURVNET_RESTORE();
-	}
-}
-#endif
-
 SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
     "Ethernet");
diff --git a/sys/netgraph/ng_ether.c b/sys/netgraph/ng_ether.c
index 80a0d3411ee8..fc388c6cdd70 100644
--- a/sys/netgraph/ng_ether.c
+++ b/sys/netgraph/ng_ether.c
@@ -92,17 +92,11 @@ typedef struct private *priv_p;
 extern	void	(*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
 extern	void	(*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m);
 extern	int	(*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);
-extern	void	(*ng_ether_attach_p)(struct ifnet *ifp);
-extern	void	(*ng_ether_detach_p)(struct ifnet *ifp);
-extern	void	(*ng_ether_link_state_p)(struct ifnet *ifp, int state);
 
 /* Functional hooks called from if_ethersubr.c */
 static void	ng_ether_input(struct ifnet *ifp, struct mbuf **mp);
 static void	ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m);
 static int	ng_ether_output(struct ifnet *ifp, struct mbuf **mp);
-static void	ng_ether_attach(struct ifnet *ifp);
-static void	ng_ether_detach(struct ifnet *ifp); 
-static void	ng_ether_link_state(struct ifnet *ifp, int state); 
 
 /* Other functions */
 static int	ng_ether_rcv_lower(hook_p node, item_p item);
@@ -117,7 +111,8 @@ static ng_rcvdata_t	ng_ether_rcvdata;
 static ng_disconnect_t	ng_ether_disconnect;
 static int		ng_ether_mod_event(module_t mod, int event, void *data);
 
-static eventhandler_tag	ng_ether_ifnet_arrival_cookie;
+static eventhandler_tag	ifnet_arrival_tag, ifnet_departure_tag,
+    ifnet_rename_tag, ifnet_linkstate_tag;
 
 /* List of commands and how to convert arguments to/from ASCII */
 static const struct ng_cmdlist ng_ether_cmdlist[] = {
@@ -299,13 +294,19 @@ ng_ether_output(struct ifnet *ifp, struct mbuf **mp)
  * A new Ethernet interface has been attached.
  * Create a new node for it, etc.
  */
-static void
-ng_ether_attach(struct ifnet *ifp)
+static int
+ng_ether_attach(struct ifnet *ifp, void *arg __unused)
 {
 	char name[IFNAMSIZ];
 	priv_p priv;
 	node_p node;
 
+	if ((ifp)->if_type != IFT_ETHER &&
+	    (ifp)->if_type != IFT_L2VLAN &&
+	    (ifp)->if_type != IFT_BRIDGE)
+		return (0);
+	MPASS(IFP2NG(ifp) == NULL);
+
 	/*
 	 * Do not create / attach an ether node to this ifnet if
 	 * a netgraph node with the same name already exists.
@@ -316,25 +317,17 @@ ng_ether_attach(struct ifnet *ifp)
 	ng_ether_sanitize_ifname(ifp->if_xname, name);
 	if ((node = ng_name2noderef(NULL, name)) != NULL) {
 		NG_NODE_UNREF(node);
-		return;
+		return (0);
 	}
 
-	/* Create node */
-	KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
 	if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) {
 		log(LOG_ERR, "%s: can't %s for %s\n",
 		    __func__, "create node", ifp->if_xname);
-		return;
+		return (0);
 	}
 
 	/* Allocate private data */
-	priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
-	if (priv == NULL) {
-		log(LOG_ERR, "%s: can't %s for %s\n",
-		    __func__, "allocate memory", ifp->if_xname);
-		NG_NODE_UNREF(node);
-		return;
-	}
+	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
 	NG_NODE_SET_PRIVATE(node, priv);
 	priv->ifp = ifp;
 	IFP2NG(ifp) = node;
@@ -343,17 +336,38 @@ ng_ether_attach(struct ifnet *ifp)
 	/* Try to give the node the same name as the interface */
 	if (ng_name_node(node, name) != 0)
 		log(LOG_WARNING, "%s: can't name node %s\n", __func__, name);
+
+	return (0);
 }
 
+static void
+ng_ether_arrival(void *arg __unused, struct ifnet *ifp)
+{
+	(void)ng_ether_attach(ifp, NULL);
+}
+
+#define	RETURN_IF_NOT_ETHERNET_OR_DETACHED(ifp)	do {			\
+	if ((ifp)->if_type != IFT_ETHER &&				\
+	    (ifp)->if_type != IFT_L2VLAN &&				\
+	    (ifp)->if_type != IFT_BRIDGE)				\
+		return;							\
+	if (IFP2NG(ifp) == NULL)					\
+		return;							\
+} while (0)
+
 /*
  * An Ethernet interface is being detached.
  * REALLY Destroy its node.
  */
 static void
-ng_ether_detach(struct ifnet *ifp)
+ng_ether_detach(void *arg __unused, struct ifnet *ifp)
 {
 	const node_p node = IFP2NG(ifp);
-	const priv_p priv = NG_NODE_PRIVATE(node);
+	priv_p priv;
+
+	RETURN_IF_NOT_ETHERNET_OR_DETACHED(ifp);
+
+	priv = NG_NODE_PRIVATE(node);
 
 	taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
 	NG_NODE_REALLY_DIE(node);	/* Force real removal of node */
@@ -372,13 +386,17 @@ ng_ether_detach(struct ifnet *ifp)
  * if_link_state_change() has already checked that the state has changed.
  */
 static void
-ng_ether_link_state(struct ifnet *ifp, int state)
+ng_ether_link_state(void *arg __unused, struct ifnet *ifp, int state)
 {
 	const node_p node = IFP2NG(ifp);
-	const priv_p priv = NG_NODE_PRIVATE(node);
+	priv_p priv;
 	struct ng_mesg *msg;
 	int cmd, dummy_error = 0;
 
+	RETURN_IF_NOT_ETHERNET_OR_DETACHED(ifp);
+
+	priv = NG_NODE_PRIVATE(node);
+
 	if (state == LINK_STATE_UP)
 		cmd = NGM_LINK_IS_UP;
 	else if (state == LINK_STATE_DOWN)
@@ -399,31 +417,17 @@ ng_ether_link_state(struct ifnet *ifp, int state)
 }
 
 /*
- * Interface arrival notification handler.
- * The notification is produced in two cases:
- *  o a new interface arrives
- *  o an existing interface got renamed
- * Currently the first case is handled by ng_ether_attach via special
- * hook ng_ether_attach_p.
+ * Interface has been renamed.
  */
 static void
-ng_ether_ifnet_arrival_event(void *arg __unused, struct ifnet *ifp)
+ng_ether_rename(void *arg __unused, struct ifnet *ifp)
 {
 	char name[IFNAMSIZ];
 	node_p node;
 
-	/* Only ethernet interfaces are of interest. */
-	if (ifp->if_type != IFT_ETHER &&
-	    ifp->if_type != IFT_L2VLAN &&
-	    ifp->if_type != IFT_BRIDGE)
-		return;
+	RETURN_IF_NOT_ETHERNET_OR_DETACHED(ifp);
 
-	/*
-	 * Just return if it's a new interface without an ng_ether companion.
-	 */
 	node = IFP2NG(ifp);
-	if (node == NULL)
-		return;
 
 	/* Try to give the node the same name as the new interface name */
 	ng_ether_sanitize_ifname(ifp->if_xname, name);
@@ -629,7 +633,7 @@ ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook)
 			break;
 		    }
 		case NGM_ETHER_DETACH:
-			ng_ether_detach(priv->ifp);
+			ng_ether_detach(NULL, priv->ifp);
 			break;
 		default:
 			error = EINVAL;
@@ -810,22 +814,19 @@ ng_ether_mod_event(module_t mod, int event, void *data)
 
 	switch (event) {
 	case MOD_LOAD:
-
-		/* Register function hooks */
-		if (ng_ether_attach_p != NULL) {
-			error = EEXIST;
-			break;
-		}
-		ng_ether_attach_p = ng_ether_attach;
-		ng_ether_detach_p = ng_ether_detach;
 		ng_ether_output_p = ng_ether_output;
 		ng_ether_input_p = ng_ether_input;
 		ng_ether_input_orphan_p = ng_ether_input_orphan;
-		ng_ether_link_state_p = ng_ether_link_state;
 
-		ng_ether_ifnet_arrival_cookie =
-		    EVENTHANDLER_REGISTER(ifnet_arrival_event,
-		    ng_ether_ifnet_arrival_event, NULL, EVENTHANDLER_PRI_ANY);
+		ifnet_arrival_tag = EVENTHANDLER_REGISTER(ifnet_arrival_event,
+		    ng_ether_arrival, NULL, EVENTHANDLER_PRI_ANY);
+		ifnet_departure_tag =
+		    EVENTHANDLER_REGISTER(ifnet_departure_event,
+		    ng_ether_detach, NULL, EVENTHANDLER_PRI_ANY);
+		ifnet_rename_tag = EVENTHANDLER_REGISTER(ifnet_rename_event,
+		    ng_ether_rename, NULL, EVENTHANDLER_PRI_ANY);
+		ifnet_linkstate_tag = EVENTHANDLER_REGISTER(ifnet_link_event,
+		    ng_ether_link_state, NULL, EVENTHANDLER_PRI_ANY);
 		break;
 
 	case MOD_UNLOAD:
@@ -838,16 +839,16 @@ ng_ether_mod_event(module_t mod, int event, void *data)
 		 * is MOD_UNLOAD, so there's no need to detach any nodes.
 		 */
 
-		EVENTHANDLER_DEREGISTER(ifnet_arrival_event,
-		    ng_ether_ifnet_arrival_cookie);
+		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ifnet_arrival_tag);
+		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
+		    ifnet_departure_tag);
+		EVENTHANDLER_DEREGISTER(ifnet_rename_event, ifnet_rename_tag);
+		EVENTHANDLER_DEREGISTER(ifnet_link_event, ifnet_linkstate_tag);
 
 		/* Unregister function hooks */
-		ng_ether_attach_p = NULL;
-		ng_ether_detach_p = NULL;
 		ng_ether_output_p = NULL;
 		ng_ether_input_p = NULL;
 		ng_ether_input_orphan_p = NULL;
-		ng_ether_link_state_p = NULL;
 		break;
 
 	default:
@@ -858,23 +859,9 @@ ng_ether_mod_event(module_t mod, int event, void *data)
 }
 
 static void
-vnet_ng_ether_init(const void *unused)
+ng_ether_vnet_init(void *arg __unused)
 {
-	struct ifnet *ifp;
-
-	/* If module load was rejected, don't attach to vnets. */
-	if (ng_ether_attach_p != ng_ether_attach)
-		return;
-
-	/* Create nodes for any already-existing Ethernet interfaces. */
-	IFNET_RLOCK();
-	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
-		if (ifp->if_type == IFT_ETHER ||
-		    ifp->if_type == IFT_L2VLAN ||
-		    ifp->if_type == IFT_BRIDGE)
-			ng_ether_attach(ifp);
-	}
-	IFNET_RUNLOCK();
+	if_foreach_sleep(NULL, NULL, ng_ether_attach, NULL);
 }
-VNET_SYSINIT(vnet_ng_ether_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
-    vnet_ng_ether_init, NULL);
+VNET_SYSINIT(ng_ether_vnet_init, SI_SUB_PROTO_IF, SI_ORDER_ANY,
+    ng_ether_vnet_init, NULL);