Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Mar 2026 16:15:36 +0000
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: a223d6c489c7 - main - ip6_mroute: Start putting global variables into a structure
Message-ID:  <69caa1a8.3bf3e.c1eaaab@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by markj:

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

commit a223d6c489c7ea9a384f3d2bbda1b05b00d4502d
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-03-30 13:29:01 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-03-30 16:08:20 +0000

    ip6_mroute: Start putting global variables into a structure
    
    As in the IPv4 version of this change, I added a struct mf6ctable
    structure which holds all global routing table state, soon to become
    per-FIB state.
    
    Note that much of the v6 multicast routing code was not VNETified; this
    change fixes that too.
    
    MFC after:      2 weeks
    Sponsored by:   Stormshield
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D55238
---
 sys/netinet6/ip6_mroute.c | 391 +++++++++++++++++++++++++++-------------------
 1 file changed, 229 insertions(+), 162 deletions(-)

diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
index a8313e1753a6..912bbfda2486 100644
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -106,6 +106,7 @@
 #include <net/if_var.h>
 #include <net/if_private.h>
 #include <net/if_types.h>
+#include <net/route.h>
 #include <net/vnet.h>
 
 #include <netinet/in.h>
@@ -124,9 +125,13 @@
 
 static MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry");
 
-static int	ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
+struct mf6ctable;
+
+static int	ip6_mdq(struct mf6ctable *, struct mbuf *, struct ifnet *,
+		    struct mf6c *);
 static void	phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
-static int	register_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
+static int	register_send(struct mf6ctable *, struct ip6_hdr *, mifi_t,
+		    struct mbuf *);
 static int	set_pim6(int *);
 static int	socket_send(struct socket *, struct mbuf *,
 		    struct sockaddr_in6 *);
@@ -146,9 +151,6 @@ static const struct encap_config ipv6_encap_cfg = {
 	.input = pim6_input
 };
 
-VNET_DEFINE_STATIC(int, ip6_mrouter_ver) = 0;
-#define	V_ip6_mrouter_ver	VNET(ip6_mrouter_ver)
-
 SYSCTL_DECL(_net_inet6);
 SYSCTL_DECL(_net_inet6_ip6);
 static SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim,
@@ -172,15 +174,6 @@ static struct sx mrouter6_mtx;
 #define	MROUTER6_LOCK_INIT()	sx_init(MROUTER6_LOCKPTR(), "mrouter6")
 #define	MROUTER6_LOCK_DESTROY()	sx_destroy(MROUTER6_LOCKPTR())
 
-VNET_DEFINE_STATIC(struct socket *, ip6_mrouter);
-#define	V_ip6_mrouter		VNET(ip6_mrouter)
-
-static struct mf6c *mf6ctable[MF6CTBLSIZ];
-SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mf6ctable, CTLFLAG_RD,
-    &mf6ctable, sizeof(mf6ctable), "S,*mf6ctable[MF6CTBLSIZ]",
-    "IPv6 Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], "
-    "netinet6/ip6_mroute.h)");
-
 static struct mtx mfc6_mtx;
 #define	MFC6_LOCKPTR()		(&mfc6_mtx)
 #define	MFC6_LOCK()		mtx_lock(MFC6_LOCKPTR())
@@ -191,9 +184,42 @@ static struct mtx mfc6_mtx;
 				    NULL, MTX_DEF)
 #define	MFC6_LOCK_DESTROY()	mtx_destroy(MFC6_LOCKPTR())
 
-static u_char n6expire[MF6CTBLSIZ];
+struct mf6ctable {
+	struct socket	*router;
+	int		router_ver;
+	struct mf6c	*mfchashtbl[MF6CTBLSIZ];
+	u_char		nexpire[MF6CTBLSIZ];
+	int		nummifs;
+	struct mif6	miftable[MAXMIFS];
+
+	/*
+	 * 'Interfaces' associated with decapsulator (so we can tell packets
+	 * that went through it from ones that get reflected by a broken
+	 * gateway).  Different from IPv4 register_if, these interfaces are
+	 * linked into the system ifnet list, because per-interface IPv6
+	 * statistics are maintained in ifp->if_afdata.  But it does not have
+	 * any routes point to them.  I.e., packets can't be sent this way.
+	 * They only exist as a placeholder for multicast source verification.
+	 */
+	struct ifnet	*register_if;
+	mifi_t		register_mif;
+};
+
+VNET_DEFINE_STATIC(struct mf6ctable *, mfctables);
+#define	V_mfctables		VNET(mfctables)
+
+static int
+sysctl_mfctable(SYSCTL_HANDLER_ARGS)
+{
+	return (SYSCTL_OUT(req, &V_mfctables[0].mfchashtbl,
+	    sizeof(V_mfctables[0].mfchashtbl)));
+}
+SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, mf6ctable,
+    CTLTYPE_OPAQUE | CTLFLAG_RD,
+    NULL, 0, sysctl_mfctable, "S,*mf6c[MF6CTBLSIZ]",
+    "IPv6 Multicast Forwarding Table (struct mf6c *[MF6CTBLSIZ], "
+    "netinet6/ip6_mroute.h)");
 
-static struct mif6 mif6table[MAXMIFS];
 static int
 sysctl_mif6table(SYSCTL_HANDLER_ARGS)
 {
@@ -203,17 +229,20 @@ sysctl_mif6table(SYSCTL_HANDLER_ARGS)
 	out = malloc(sizeof(struct mif6_sctl) * MAXMIFS, M_TEMP,
 	    M_WAITOK | M_ZERO);
 	for (int i = 0; i < MAXMIFS; i++) {
-		out[i].m6_flags		= mif6table[i].m6_flags;
-		out[i].m6_rate_limit	= mif6table[i].m6_rate_limit;
-		out[i].m6_lcl_addr	= mif6table[i].m6_lcl_addr;
-		if (mif6table[i].m6_ifp != NULL)
-			out[i].m6_ifp	= mif6table[i].m6_ifp->if_index;
+		struct mif6_sctl *outp = &out[i];
+		struct mif6 *mifp = &V_mfctables[0].miftable[i];
+
+		outp->m6_flags = mifp->m6_flags;
+		outp->m6_rate_limit = mifp->m6_rate_limit;
+		outp->m6_lcl_addr = mifp->m6_lcl_addr;
+		if (mifp->m6_ifp != NULL)
+			outp->m6_ifp = mifp->m6_ifp->if_index;
 		else
-			out[i].m6_ifp	= 0;
-		out[i].m6_pkt_in	= mif6table[i].m6_pkt_in;
-		out[i].m6_pkt_out	= mif6table[i].m6_pkt_out;
-		out[i].m6_bytes_in	= mif6table[i].m6_bytes_in;
-		out[i].m6_bytes_out	= mif6table[i].m6_bytes_out;
+			outp->m6_ifp = 0;
+		outp->m6_pkt_in	= mifp->m6_pkt_in;
+		outp->m6_pkt_out = mifp->m6_pkt_out;
+		outp->m6_bytes_in = mifp->m6_bytes_in;
+		outp->m6_bytes_out = mifp->m6_bytes_out;
 	}
 	error = SYSCTL_OUT(req, out, sizeof(struct mif6_sctl) * MAXMIFS);
 	free(out, M_TEMP);
@@ -257,25 +286,6 @@ static void	expire_upcalls(void *);
 #define	EXPIRE_TIMEOUT	(hz / 4)	/* 4x / second */
 #define	UPCALL_EXPIRE	6		/* number of timeouts */
 
-/*
- * 'Interfaces' associated with decapsulator (so we can tell
- * packets that went through it from ones that get reflected
- * by a broken gateway).  Different from IPv4 register_if,
- * these interfaces are linked into the system ifnet list,
- * because per-interface IPv6 statistics are maintained in
- * ifp->if_afdata.  But it does not have any routes point
- * to them.  I.e., packets can't be sent this way.  They
- * only exist as a placeholder for multicast source
- * verification.
- */
-static struct ifnet *multicast_register_if6;
-
-/*
- * Private variables.
- */
-static mifi_t nummifs = 0;
-static mifi_t reg_mif_num = (mifi_t)-1;
-
 static struct pim6stat pim6stat;
 SYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RW,
     &pim6stat, pim6stat,
@@ -335,7 +345,8 @@ static int del_m6if_locked(mifi_t *);
 static int get_mif6_cnt(struct sioc_mif_req6 *);
 static int get_sg_cnt(struct sioc_sg_req6 *);
 
-static struct callout expire_upcalls_ch;
+VNET_DEFINE_STATIC(struct callout, expire_upcalls_ch);
+#define	V_expire_upcalls_ch	VNET(expire_upcalls_ch)
 
 static int X_ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
 static void X_ip6_mrouter_done(struct socket *);
@@ -344,12 +355,13 @@ static int X_ip6_mrouter_get(struct socket *, struct sockopt *);
 static int X_mrt6_ioctl(u_long, caddr_t);
 
 static struct mf6c *
-mf6c_find(const struct in6_addr *origin, const struct in6_addr *group)
+mf6c_find(const struct mf6ctable *mfct, const struct in6_addr *origin,
+    const struct in6_addr *group)
 {
 	MFC6_LOCK_ASSERT();
 
-	for (struct mf6c *rt = mf6ctable[MF6CHASH(*origin, *group)]; rt != NULL;
-	    rt = rt->mf6c_next) {
+	for (struct mf6c *rt = mfct->mfchashtbl[MF6CHASH(*origin, *group)];
+	    rt != NULL; rt = rt->mf6c_next) {
 		if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr, origin) &&
 		    IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr, group) &&
 		    rt->mf6c_stall == NULL)
@@ -365,13 +377,15 @@ mf6c_find(const struct in6_addr *origin, const struct in6_addr *group)
 static int
 X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
 {
+	struct mf6ctable *mfct;
 	int error = 0;
 	int optval;
 	struct mif6ctl mifc;
 	struct mf6cctl mfcc;
 	mifi_t mifi;
 
-	if (so != V_ip6_mrouter && sopt->sopt_name != MRT6_INIT)
+	mfct = &V_mfctables[0];
+	if (so != mfct->router && sopt->sopt_name != MRT6_INIT)
 		return (EPERM);
 
 	switch (sopt->sopt_name) {
@@ -433,9 +447,11 @@ X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
 static int
 X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
 {
+	struct mf6ctable *mfct;
 	int error = 0;
 
-	if (so != V_ip6_mrouter)
+	mfct = &V_mfctables[0];
+	if (so != mfct->router)
 		return (EACCES);
 
 	switch (sopt->sopt_name) {
@@ -486,8 +502,8 @@ get_sg_cnt(struct sioc_sg_req6 *req)
 	ret = 0;
 
 	MFC6_LOCK();
-
-	rt = mf6c_find(&req->src.sin6_addr, &req->grp.sin6_addr);
+	rt = mf6c_find(&V_mfctables[0], &req->src.sin6_addr,
+	    &req->grp.sin6_addr);
 	if (rt == NULL) {
 		ret = ESRCH;
 	} else {
@@ -495,7 +511,6 @@ get_sg_cnt(struct sioc_sg_req6 *req)
 		req->bytecnt = rt->mf6c_byte_cnt;
 		req->wrong_if = rt->mf6c_wrong_if;
 	}
-
 	MFC6_UNLOCK();
 
 	return (ret);
@@ -507,21 +522,25 @@ get_sg_cnt(struct sioc_sg_req6 *req)
 static int
 get_mif6_cnt(struct sioc_mif_req6 *req)
 {
+	struct mf6ctable *mfct;
 	mifi_t mifi;
 	int ret;
 
 	ret = 0;
 	mifi = req->mifi;
 
+	mfct = &V_mfctables[0];
 	MIF6_LOCK();
 
-	if (mifi >= nummifs) {
+	if (mifi >= mfct->nummifs) {
 		ret = EINVAL;
 	} else {
-		req->icount = mif6table[mifi].m6_pkt_in;
-		req->ocount = mif6table[mifi].m6_pkt_out;
-		req->ibytes = mif6table[mifi].m6_bytes_in;
-		req->obytes = mif6table[mifi].m6_bytes_out;
+		struct mif6 *mif = &mfct->miftable[mifi];
+
+		req->icount = mif->m6_pkt_in;
+		req->ocount = mif->m6_pkt_out;
+		req->ibytes = mif->m6_bytes_in;
+		req->obytes = mif->m6_bytes_out;
 	}
 
 	MIF6_UNLOCK();
@@ -546,32 +565,33 @@ set_pim6(int *i)
 static int
 ip6_mrouter_init(struct socket *so, int v, int cmd)
 {
+	struct mf6ctable *mfct;
 
 	MRT6_DLOG(DEBUG_ANY, "%s: socket %p", __func__, so);
 
 	if (v != 1)
 		return (ENOPROTOOPT);
 
+	mfct = &V_mfctables[0];
 	MROUTER6_LOCK();
 
-	if (V_ip6_mrouter != NULL) {
+	if (mfct->router != NULL) {
 		MROUTER6_UNLOCK();
 		return (EADDRINUSE);
 	}
 
 	MFC6_LOCK();
 	V_ip6_mrouting_enabled = true;
-	V_ip6_mrouter = so;
-	V_ip6_mrouter_ver = cmd;
+	mfct->router = so;
+	mfct->router_ver = cmd;
 
-	bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
-	bzero((caddr_t)n6expire, sizeof(n6expire));
+	bzero(&mfct->mfchashtbl, sizeof(mfct->mfchashtbl));
+	bzero(&mfct->nexpire, sizeof(mfct->nexpire));
 
 	V_pim6 = 0;/* used for stubbing out/in pim stuff */
 
-	callout_init_mtx(&expire_upcalls_ch, MFC6_LOCKPTR(), 0);
-	callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
-	    expire_upcalls, NULL);
+	callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls,
+	    curvnet);
 
 	MFC6_UNLOCK();
 	MROUTER6_UNLOCK();
@@ -587,14 +607,16 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
 static void
 X_ip6_mrouter_done(struct socket *so)
 {
+	struct mf6ctable *mfct;
 	mifi_t mifi;
 	u_long i;
 	struct mf6c *rt;
 	struct rtdetq *rte;
 
+	mfct = &V_mfctables[0];
 	MROUTER6_LOCK();
 
-	if (V_ip6_mrouter != so) {
+	if (mfct->router != so) {
 		MROUTER6_UNLOCK();
 		return;
 	}
@@ -603,15 +625,16 @@ X_ip6_mrouter_done(struct socket *so)
 	 * For each phyint in use, disable promiscuous reception of all IPv6
 	 * multicasts.
 	 */
-	for (mifi = 0; mifi < nummifs; mifi++) {
-		if (mif6table[mifi].m6_ifp &&
-		    !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
-			if_allmulti(mif6table[mifi].m6_ifp, 0);
+	for (mifi = 0; mifi < mfct->nummifs; mifi++) {
+		struct mif6 *mif = &mfct->miftable[mifi];
+
+		if (mif->m6_ifp && !(mif->m6_flags & MIFF_REGISTER)) {
+			if_allmulti(mif->m6_ifp, 0);
 		}
 	}
 	MFC6_LOCK();
-	bzero((caddr_t)mif6table, sizeof(mif6table));
-	nummifs = 0;
+	bzero(mfct->miftable, sizeof(mfct->miftable));
+	mfct->nummifs = 0;
 
 	V_pim6 = 0; /* used to stub out/in pim specific code */
 
@@ -619,7 +642,7 @@ X_ip6_mrouter_done(struct socket *so)
 	 * Free all multicast forwarding cache entries.
 	 */
 	for (i = 0; i < MF6CTBLSIZ; i++) {
-		rt = mf6ctable[i];
+		rt = mfct->mfchashtbl[i];
 		while (rt) {
 			struct mf6c *frt;
 
@@ -635,23 +658,21 @@ X_ip6_mrouter_done(struct socket *so)
 			free(frt, M_MRTABLE6);
 		}
 	}
-	bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
-
-	V_ip6_mrouter = NULL;
+	mfct->router = NULL;
+	mfct->router_ver = 0;
 	V_ip6_mrouting_enabled = false;
-	V_ip6_mrouter_ver = 0;
-	MFC6_UNLOCK();
 
-	callout_drain(&expire_upcalls_ch);
+	bzero(mfct->mfchashtbl, sizeof(mfct->mfchashtbl));
+	MFC6_UNLOCK();
 
 	/*
 	 * Reset register interface
 	 */
-	if (reg_mif_num != (mifi_t)-1 && multicast_register_if6 != NULL) {
-		if_detach(multicast_register_if6);
-		if_free(multicast_register_if6);
-		reg_mif_num = (mifi_t)-1;
-		multicast_register_if6 = NULL;
+	if (mfct->register_mif != (mifi_t)-1 && mfct->register_if != NULL) {
+		if_detach(mfct->register_if);
+		if_free(mfct->register_if);
+		mfct->register_mif = (mifi_t)-1;
+		mfct->register_if = NULL;
 	}
 
 	MROUTER6_UNLOCK();
@@ -666,6 +687,7 @@ static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
 static int
 add_m6if(struct mif6ctl *mifcp)
 {
+	struct mf6ctable *mfct;
 	struct epoch_tracker et;
 	struct mif6 *mifp;
 	struct ifnet *ifp;
@@ -677,7 +699,8 @@ add_m6if(struct mif6ctl *mifcp)
 		MIF6_UNLOCK();
 		return (EINVAL);
 	}
-	mifp = mif6table + mifcp->mif6c_mifi;
+	mfct = &V_mfctables[0];
+	mifp = &mfct->miftable[mifcp->mif6c_mifi];
 	if (mifp->m6_ifp != NULL) {
 		MIF6_UNLOCK();
 		return (EADDRINUSE); /* XXX: is it appropriate? */
@@ -692,14 +715,14 @@ add_m6if(struct mif6ctl *mifcp)
 	NET_EPOCH_EXIT(et);	/* XXXGL: unsafe ifp */
 
 	if (mifcp->mif6c_flags & MIFF_REGISTER) {
-		if (reg_mif_num == (mifi_t)-1) {
+		if (mfct->register_mif == (mifi_t)-1) {
 			ifp = if_alloc(IFT_OTHER);
 
 			if_initname(ifp, "register_mif", 0);
 			ifp->if_flags |= IFF_LOOPBACK;
 			if_attach(ifp);
-			multicast_register_if6 = ifp;
-			reg_mif_num = mifcp->mif6c_mifi;
+			mfct->register_if = ifp;
+			mfct->register_mif = mifcp->mif6c_mifi;
 			/*
 			 * it is impossible to guess the ifindex of the
 			 * register interface.  So mif6c_pifi is automatically
@@ -707,7 +730,7 @@ add_m6if(struct mif6ctl *mifcp)
 			 */
 			mifcp->mif6c_pifi = ifp->if_index;
 		} else {
-			ifp = multicast_register_if6;
+			ifp = mfct->register_if;
 		}
 	} else {
 		/* Make sure the interface supports multicast */
@@ -733,8 +756,8 @@ add_m6if(struct mif6ctl *mifcp)
 	mifp->m6_bytes_out = 0;
 
 	/* Adjust nummifs up if the mifi is higher than nummifs */
-	if (nummifs <= mifcp->mif6c_mifi)
-		nummifs = mifcp->mif6c_mifi + 1;
+	if (mfct->nummifs <= mifcp->mif6c_mifi)
+		mfct->nummifs = mifcp->mif6c_mifi + 1;
 
 	MIF6_UNLOCK();
 	MRT6_DLOG(DEBUG_ANY, "mif #%d, phyint %s", mifcp->mif6c_mifi,
@@ -749,14 +772,17 @@ add_m6if(struct mif6ctl *mifcp)
 static int
 del_m6if_locked(mifi_t *mifip)
 {
-	struct mif6 *mifp = mif6table + *mifip;
+	struct mf6ctable *mfct;
+	struct mif6 *mifp;
 	mifi_t mifi;
 	struct ifnet *ifp;
 
 	MIF6_LOCK_ASSERT();
 
-	if (*mifip >= nummifs)
+	mfct = &V_mfctables[0];
+	if (*mifip >= mfct->nummifs)
 		return (EINVAL);
+	mifp = &mfct->miftable[*mifip];
 	if (mifp->m6_ifp == NULL)
 		return (EINVAL);
 
@@ -765,23 +791,23 @@ del_m6if_locked(mifi_t *mifip)
 		ifp = mifp->m6_ifp;
 		if_allmulti(ifp, 0);
 	} else {
-		if (reg_mif_num != (mifi_t)-1 &&
-		    multicast_register_if6 != NULL) {
-			if_detach(multicast_register_if6);
-			if_free(multicast_register_if6);
-			reg_mif_num = (mifi_t)-1;
-			multicast_register_if6 = NULL;
+		if (mfct->register_mif != (mifi_t)-1 &&
+		    mfct->register_if != NULL) {
+			if_detach(mfct->register_if);
+			if_free(mfct->register_if);
+			mfct->register_mif = (mifi_t)-1;
+			mfct->register_if = NULL;
 		}
 	}
 
-	bzero((caddr_t)mifp, sizeof(*mifp));
+	bzero(mifp, sizeof(*mifp));
 
 	/* Adjust nummifs down */
-	for (mifi = nummifs; mifi > 0; mifi--)
-		if (mif6table[mifi - 1].m6_ifp)
+	for (mifi = mfct->nummifs; mifi > 0; mifi--)
+		if (mfct->miftable[mifi - 1].m6_ifp != NULL)
 			break;
-	nummifs = mifi;
-	MRT6_DLOG(DEBUG_ANY, "mif %d, nummifs %d", *mifip, nummifs);
+	mfct->nummifs = mifi;
+	MRT6_DLOG(DEBUG_ANY, "mif %d, nummifs %d", *mifip, mfct->nummifs);
 
 	return (0);
 }
@@ -804,15 +830,17 @@ del_m6if(mifi_t *mifip)
 static int
 add_m6fc(struct mf6cctl *mfccp)
 {
+	struct mf6ctable *mfct;
 	struct mf6c *rt;
 	u_long hash;
 	struct rtdetq *rte;
 	u_short nstl;
 	char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
 
-	MFC6_LOCK();
+	mfct = &V_mfctables[0];
 
-	rt = mf6c_find(&mfccp->mf6cc_origin.sin6_addr,
+	MFC6_LOCK();
+	rt = mf6c_find(mfct, &mfccp->mf6cc_origin.sin6_addr,
 	    &mfccp->mf6cc_mcastgrp.sin6_addr);
 	/* If an entry already exists, just update the fields */
 	if (rt) {
@@ -833,7 +861,7 @@ add_m6fc(struct mf6cctl *mfccp)
 	 */
 	hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
 			mfccp->mf6cc_mcastgrp.sin6_addr);
-	for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
+	for (rt = mfct->mfchashtbl[hash], nstl = 0; rt; rt = rt->mf6c_next) {
 		if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
 				       &mfccp->mf6cc_origin.sin6_addr) &&
 		    IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
@@ -866,12 +894,12 @@ add_m6fc(struct mf6cctl *mfccp)
 			rt->mf6c_wrong_if   = 0;
 
 			rt->mf6c_expire = 0;	/* Don't clean this guy up */
-			n6expire[hash]--;
+			mfct->nexpire[hash]--;
 
 			/* free packets Qed at the end of this entry */
 			for (rte = rt->mf6c_stall; rte != NULL; ) {
 				struct rtdetq *n = rte->next;
-				ip6_mdq(rte->m, rte->ifp, rt);
+				ip6_mdq(mfct, rte->m, rte->ifp, rt);
 				m_freem(rte->m);
 #ifdef UPCALL_TIMING
 				collate(&(rte->t));
@@ -892,7 +920,7 @@ add_m6fc(struct mf6cctl *mfccp)
 		    ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr),
 		    mfccp->mf6cc_parent);
 
-		for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
+		for (rt = mfct->mfchashtbl[hash]; rt; rt = rt->mf6c_next) {
 			if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
 					       &mfccp->mf6cc_origin.sin6_addr)&&
 			    IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
@@ -907,7 +935,7 @@ add_m6fc(struct mf6cctl *mfccp)
 				rt->mf6c_wrong_if   = 0;
 
 				if (rt->mf6c_expire)
-					n6expire[hash]--;
+					mfct->nexpire[hash]--;
 				rt->mf6c_expire	   = 0;
 			}
 		}
@@ -932,8 +960,8 @@ add_m6fc(struct mf6cctl *mfccp)
 			rt->mf6c_stall = NULL;
 
 			/* link into table */
-			rt->mf6c_next  = mf6ctable[hash];
-			mf6ctable[hash] = rt;
+			rt->mf6c_next  = mfct->mfchashtbl[hash];
+			mfct->mfchashtbl[hash] = rt;
 		}
 	}
 
@@ -976,12 +1004,14 @@ del_m6fc(struct mf6cctl *mfccp)
 #ifdef MRT6DEBUG
 	char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
 #endif
+	struct mf6ctable *mfct;
 	struct sockaddr_in6	origin;
 	struct sockaddr_in6	mcastgrp;
 	struct mf6c		*rt;
 	struct mf6c		**nptr;
 	u_long		hash;
 
+	mfct = &V_mfctables[0];
 	origin = mfccp->mf6cc_origin;
 	mcastgrp = mfccp->mf6cc_mcastgrp;
 	hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);
@@ -992,7 +1022,7 @@ del_m6fc(struct mf6cctl *mfccp)
 
 	MFC6_LOCK();
 
-	nptr = &mf6ctable[hash];
+	nptr = &mfct->mfchashtbl[hash];
 	while ((rt = *nptr) != NULL) {
 		if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,
 				       &rt->mf6c_origin.sin6_addr) &&
@@ -1054,6 +1084,7 @@ socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src)
 static int
 X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 {
+	struct mf6ctable *mfct;
 	struct rtdetq *rte;
 	struct mbuf *mb0;
 	struct mf6c *rt;
@@ -1103,18 +1134,19 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 		return (0);
 	}
 
+	mfct = &V_mfctables[0];
 	MFC6_LOCK();
 
 	/*
 	 * Determine forwarding mifs from the forwarding cache table
 	 */
-	rt = mf6c_find(&ip6->ip6_src, &ip6->ip6_dst);
+	rt = mf6c_find(mfct, &ip6->ip6_src, &ip6->ip6_dst);
 	MRT6STAT_INC(mrt6s_mfc_lookups);
 
 	/* Entry exists, so forward if necessary */
 	if (rt) {
 		MFC6_UNLOCK();
-		return (ip6_mdq(m, ifp, rt));
+		return (ip6_mdq(mfct, m, ifp, rt));
 	}
 
 	/*
@@ -1150,7 +1182,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 
 	/* is there an upcall waiting for this packet? */
 	hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
-	for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
+	for (rt = mfct->mfchashtbl[hash]; rt; rt = rt->mf6c_next) {
 		if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
 		    &rt->mf6c_origin.sin6_addr) &&
 		    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
@@ -1192,7 +1224,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 #ifdef MRT6_OINIT
 		oim = NULL;
 #endif
-		switch (V_ip6_mrouter_ver) {
+		switch (mfct->router_ver) {
 #ifdef MRT6_OINIT
 		case MRT6_OINIT:
 			oim = mtod(mm, struct omrt6msg *);
@@ -1214,11 +1246,11 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 		}
 
 		MRT6_DLOG(DEBUG_FORWARD, "getting the iif info in the kernel");
-		for (mifp = mif6table, mifi = 0;
-		    mifi < nummifs && mifp->m6_ifp != ifp; mifp++, mifi++)
-				;
+		for (mifp = mfct->miftable, mifi = 0;
+		    mifi < mfct->nummifs && mifp->m6_ifp != ifp; mifp++, mifi++)
+			;
 
-		switch (V_ip6_mrouter_ver) {
+		switch (mfct->router_ver) {
 #ifdef MRT6_OINIT
 		case MRT6_OINIT:
 			oim->im6_mif = mifi;
@@ -1229,7 +1261,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 			break;
 		}
 
-		if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
+		if (socket_send(mfct->router, mm, &sin6) < 0) {
 			log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
 			    "socket queue full\n");
 			MRT6STAT_INC(mrt6s_upq_sockfull);
@@ -1251,12 +1283,12 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 		rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
 		rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;
 		rt->mf6c_expire = UPCALL_EXPIRE;
-		n6expire[hash]++;
+		mfct->nexpire[hash]++;
 		rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;
 
 		/* link into table */
-		rt->mf6c_next  = mf6ctable[hash];
-		mf6ctable[hash] = rt;
+		rt->mf6c_next = mfct->mfchashtbl[hash];
+		mfct->mfchashtbl[hash] = rt;
 		/* Add this entry to the end of the queue */
 		rt->mf6c_stall = rte;
 	} else {
@@ -1294,21 +1326,24 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
  * Call from the Slow Timeout mechanism, every half second.
  */
 static void
-expire_upcalls(void *unused)
+expire_upcalls(void *arg)
 {
 #ifdef MRT6DEBUG
 	char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
 #endif
+	struct mf6ctable *mfct;
 	struct rtdetq *rte;
 	struct mf6c *mfc, **nptr;
 	u_long i;
 
 	MFC6_LOCK_ASSERT();
+	CURVNET_SET((struct vnet *)arg);
 
+	mfct = &V_mfctables[0];
 	for (i = 0; i < MF6CTBLSIZ; i++) {
-		if (n6expire[i] == 0)
+		if (mfct->nexpire[i] == 0)
 			continue;
-		nptr = &mf6ctable[i];
+		nptr = &mfct->mfchashtbl[i];
 		while ((mfc = *nptr) != NULL) {
 			rte = mfc->mf6c_stall;
 			/*
@@ -1333,7 +1368,7 @@ expire_upcalls(void *unused)
 					rte = n;
 				} while (rte != NULL);
 				MRT6STAT_INC(mrt6s_cache_cleanups);
-				n6expire[i]--;
+				mfct->nexpire[i]--;
 
 				*nptr = mfc->mf6c_next;
 				free(mfc, M_MRTABLE6);
@@ -1342,15 +1377,18 @@ expire_upcalls(void *unused)
 			}
 		}
 	}
-	callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
-	    expire_upcalls, NULL);
+	callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT,
+	    expire_upcalls, curvnet);
+
+	CURVNET_RESTORE();
 }
 
 /*
  * Packet forwarding routine once entry in the cache is made
  */
 static int
-ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
+ip6_mdq(struct mf6ctable *mfct, struct mbuf *m, struct ifnet *ifp,
+    struct mf6c *rt)
 {
 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
 	mifi_t mifi, iif;
@@ -1367,13 +1405,13 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
 	 * for its origin.
 	 */
 	mifi = rt->mf6c_parent;
-	if (mifi >= nummifs || mif6table[mifi].m6_ifp != ifp) {
+	if (mifi >= mfct->nummifs || mfct->miftable[mifi].m6_ifp != ifp) {
 		MRT6STAT_INC(mrt6s_wrong_if);
 		rt->mf6c_wrong_if++;
-		if (mifi >= nummifs)
+		if (mifi >= mfct->nummifs)
 			return (0);
 
-		mifp = &mif6table[mifi];
+		mifp = &mfct->miftable[mifi];
 		MRT6_DLOG(DEBUG_FORWARD,
 		    "wrong if: ifid %d mifi %d mififid %x", ifp->if_index,
 		    mifi, mifp->m6_ifp->if_index);
@@ -1412,7 +1450,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
 			oim = NULL;
 #endif
 			im = NULL;
-			switch (V_ip6_mrouter_ver) {
+			switch (mfct->router_ver) {
 #ifdef MRT6_OINIT
 			case MRT6_OINIT:
 				oim = mtod(mm, struct omrt6msg *);
@@ -1430,12 +1468,12 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
 				return (EINVAL);
 			}
 
-			for (mifp = mif6table, iif = 0;
-			     iif < nummifs && mifp->m6_ifp != ifp;
+			for (mifp = mfct->miftable, iif = 0;
+			     iif < mfct->nummifs && mifp->m6_ifp != ifp;
 			     mifp++, iif++)
 				;
 
-			switch (V_ip6_mrouter_ver) {
+			switch (mfct->router_ver) {
 #ifdef MRT6_OINIT
 			case MRT6_OINIT:
 				oim->im6_mif = iif;
@@ -1450,7 +1488,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
 
 			MRT6STAT_INC(mrt6s_upcalls);
 
-			if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
+			if (socket_send(mfct->router, mm, &sin6) < 0) {
 				MRT6_DLOG(DEBUG_ANY,
 				    "ip6_mrouter socket queue full");
 				MRT6STAT_INC(mrt6s_upq_sockfull);
@@ -1460,14 +1498,16 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
 		return (0);
 	}
 
+	mifp = &mfct->miftable[mifi];
+
 	/* If I sourced this packet, it counts as output, else it was input. */
 	if (m->m_pkthdr.rcvif == NULL) {
 		/* XXX: is rcvif really NULL when output?? */
-		mif6table[mifi].m6_pkt_out++;
-		mif6table[mifi].m6_bytes_out += plen;
+		mifp->m6_pkt_out++;
+		mifp->m6_bytes_out += plen;
 	} else {
-		mif6table[mifi].m6_pkt_in++;
-		mif6table[mifi].m6_bytes_in += plen;
+		mifp->m6_pkt_in++;
+		mifp->m6_bytes_in += plen;
 	}
 	rt->mf6c_pkt_cnt++;
 	rt->mf6c_byte_cnt += plen;
@@ -1483,7 +1523,8 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
 		IP6STAT_INC(ip6s_badscope);
 		return (error);
 	}
-	for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) {
+	for (mifp = mfct->miftable, mifi = 0; mifi < mfct->nummifs;
+	    mifp++, mifi++) {
 		if (IF_ISSET(mifi, &rt->mf6c_ifset)) {
 			/*
 			 * check if the outgoing packet is going to break
@@ -1491,12 +1532,12 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
 			 * XXX For packets through PIM register tunnel
 			 * interface, we believe a routing daemon.
 			 */
-			if (!(mif6table[rt->mf6c_parent].m6_flags &
+			if (!(mfct->miftable[rt->mf6c_parent].m6_flags &
 			      MIFF_REGISTER) &&
-			    !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
-				if (in6_setscope(&src0, mif6table[mifi].m6_ifp,
+			    !(mifp->m6_flags & MIFF_REGISTER)) {
+				if (in6_setscope(&src0, mifp->m6_ifp,
 				    &oszone) ||
-				    in6_setscope(&dst0, mif6table[mifi].m6_ifp,
+				    in6_setscope(&dst0, mifp->m6_ifp,
 				    &odzone) ||
 				    iszone != oszone ||
 				    idzone != odzone) {
@@ -1508,7 +1549,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
 			mifp->m6_pkt_out++;
 			mifp->m6_bytes_out += plen;
 			if (mifp->m6_flags & MIFF_REGISTER)
-				register_send(ip6, mifp, m);
+				register_send(mfct, ip6, mifi, m);
 			else
 				phyint_send(ip6, mifp, m);
 		}
@@ -1619,7 +1660,8 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
 }
 
 static int
-register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
+register_send(struct mf6ctable *mfct, struct ip6_hdr *ip6, mifi_t mifi,
+    struct mbuf *m)
 {
 #ifdef MRT6DEBUG
 	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
@@ -1663,12 +1705,12 @@ register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
 	im6->im6_msgtype      = MRT6MSG_WHOLEPKT;
 	im6->im6_mbz          = 0;
 
-	im6->im6_mif = mif - mif6table;
+	im6->im6_mif = mifi;
 
 	/* iif info is not given for reg. encap.n */
 	MRT6STAT_INC(mrt6s_upcalls);
 
-	if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
+	if (socket_send(mfct->router, mm, &sin6) < 0) {
 		MRT6_DLOG(DEBUG_ANY, "ip6_mrouter socket queue full");
 		MRT6STAT_INC(mrt6s_upq_sockfull);
 		return (ENOBUFS);
@@ -1700,11 +1742,14 @@ pim6_encapcheck(const struct mbuf *m __unused, int off __unused,
 static int
 pim6_input(struct mbuf *m, int off, int proto, void *arg __unused)
 {
-	struct pim *pim; /* pointer to a pim struct */
+	struct mf6ctable *mfct;
+	struct pim *pim;
 	struct ip6_hdr *ip6;
 	int pimlen;
 	int minlen;
 
+	mfct = &V_mfctables[0];
+
 	PIM6STAT_INC(pim6s_rcv_total);
 
 	/*
@@ -1792,9 +1837,10 @@ pim6_input(struct mbuf *m, int off, int proto, void *arg __unused)
 
 		PIM6STAT_INC(pim6s_rcv_registers);
 
-		if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {
+		if (mfct->register_mif >= mfct->nummifs ||
+		    mfct->register_mif == (mifi_t)-1) {
 			MRT6_DLOG(DEBUG_PIM, "register mif not set: %d",
-			    reg_mif_num);
+			    mfct->register_mif);
 			m_freem(m);
 			return (IPPROTO_DONE);
 		}
@@ -1861,10 +1907,10 @@ pim6_input(struct mbuf *m, int off, int proto, void *arg __unused)
 		MRT6_DLOG(DEBUG_PIM, "forwarding decapsulated register: "
 		    "src %s, dst %s, mif %d",
 		    ip6_sprintf(ip6bufs, &eip6->ip6_src),
-		    ip6_sprintf(ip6bufd, &eip6->ip6_dst), reg_mif_num);
+		    ip6_sprintf(ip6bufd, &eip6->ip6_dst), mfct->register_mif);
 
-		if_simloop(mif6table[reg_mif_num].m6_ifp, m,
-				dst.sin6_family, 0);
+		if_simloop(mfct->miftable[mfct->register_mif].m6_ifp, m,
+		    dst.sin6_family, 0);
 
 		/* prepare the register head to send to the mrouting daemon */
 		m = mcp;
@@ -1880,6 +1926,27 @@ pim6_input(struct mbuf *m, int off, int proto, void *arg __unused)
 	return (rip6_input(&m, &off, proto));
 }
 
+static void
+vnet_mroute_init(const void *unused __unused)
+{
+	V_mfctables = mallocarray(V_rt_numfibs, sizeof(*V_mfctables),
+	    M_MRTABLE6, M_WAITOK | M_ZERO);
+
+	callout_init_mtx(&V_expire_upcalls_ch, MFC6_LOCKPTR(), 0);
+}
+VNET_SYSINIT(vnet_mroute6_init, SI_SUB_PROTO_MC, SI_ORDER_ANY, vnet_mroute_init,
+    NULL);
+
+static void
+vnet_mroute_uninit(const void *unused __unused)
+{
+	callout_drain(&V_expire_upcalls_ch);
+	free(V_mfctables, M_MRTABLE6);
+	V_mfctables = NULL;
+}
+VNET_SYSUNINIT(vnet_mroute6_uninit, SI_SUB_PROTO_MC, SI_ORDER_ANY,
+    vnet_mroute_uninit, NULL);
+
 static int
 ip6_mroute_modevent(module_t mod, int type, void *unused)
 {


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69caa1a8.3bf3e.c1eaaab>