Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Mar 2026 16:15:41 +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: 0bb9c2b665d9 - main - ip6_mroute: FIBify
Message-ID:  <69caa1ad.3c307.55d18a69@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=0bb9c2b665d90934ae16eee152b6b4f4f4be0dd5

commit 0bb9c2b665d90934ae16eee152b6b4f4f4be0dd5
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-03-30 13:31:55 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-03-30 16:08:21 +0000

    ip6_mroute: FIBify
    
    Modify the control plane (ioctl and socket option handlers) to use the
    routing socket FIB to index into the mfctable array.  Modify the
    forwarding plane to use the mbuf's FIB to determine which routing table
    to use.
    
    MFC after:      2 weeks
    Sponsored by:   Stormshield
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D55242
---
 sys/netinet6/in6.c        |  17 +++---
 sys/netinet6/ip6_mroute.c | 131 +++++++++++++++++++++++++++-------------------
 sys/netinet6/ip6_mroute.h |   2 +-
 sys/netinet6/raw_ip6.c    |   2 +-
 4 files changed, 85 insertions(+), 67 deletions(-)

diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index eb6c327de76f..cf2720cac036 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -279,17 +279,6 @@ in6_control_ioctl(u_long cmd, void *data,
 		ifra->ifra_vhid = 0;
 	}
 
-	switch (cmd) {
-	case SIOCGETSGCNT_IN6:
-	case SIOCGETMIFCNT_IN6:
-		/*
-		 * XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c.
-		 * We cannot see how that would be needed, so do not adjust the
-		 * KPI blindly; more likely should clean up the IPv4 variant.
-		 */
-		return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP);
-	}
-
 	switch (cmd) {
 	case SIOCAADDRCTL_POLICY:
 	case SIOCDADDRCTL_POLICY:
@@ -615,6 +604,12 @@ int
 in6_control(struct socket *so, u_long cmd, void *data,
     struct ifnet *ifp, struct thread *td)
 {
+	switch (cmd) {
+	case SIOCGETSGCNT_IN6:
+	case SIOCGETMIFCNT_IN6:
+		return (mrt6_ioctl ?
+		    mrt6_ioctl(cmd, data, so->so_fibnum) : EOPNOTSUPP);
+	}
 	return (in6_control_ioctl(cmd, data, ifp, td ? td->td_ucred : NULL));
 }
 
diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
index fff68a7ff47d..52fd319ba4f4 100644
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -216,8 +216,11 @@ static eventhandler_tag rtnumfibs_change_tag;
 static int
 sysctl_mfctable(SYSCTL_HANDLER_ARGS)
 {
-	return (SYSCTL_OUT(req, &V_mfctables[0].mfchashtbl,
-	    sizeof(V_mfctables[0].mfchashtbl)));
+	int fibnum;
+
+	fibnum = curthread->td_proc->p_fibnum;
+	return (SYSCTL_OUT(req, &V_mfctables[fibnum].mfchashtbl,
+	    sizeof(struct mfc6c *) * MF6CTBLSIZ));
 }
 SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, mf6ctable,
     CTLTYPE_OPAQUE | CTLFLAG_RD,
@@ -229,13 +232,15 @@ static int
 sysctl_mif6table(SYSCTL_HANDLER_ARGS)
 {
 	struct mif6_sctl *out;
+	struct mf6ctable *mfct;
 	int error;
 
+	mfct = &V_mfctables[curthread->td_proc->p_fibnum];
 	out = malloc(sizeof(struct mif6_sctl) * MAXMIFS, M_TEMP,
 	    M_WAITOK | M_ZERO);
 	for (int i = 0; i < MAXMIFS; i++) {
 		struct mif6_sctl *outp = &out[i];
-		struct mif6 *mifp = &V_mfctables[0].miftable[i];
+		struct mif6 *mifp = &mfct->miftable[i];
 
 		outp->m6_flags = mifp->m6_flags;
 		outp->m6_rate_limit = mifp->m6_rate_limit;
@@ -287,7 +292,8 @@ VNET_DEFINE_STATIC(u_int, mrt6debug) = 0;	/* debug level */
 #define	MRT6_DLOG(m, fmt, ...)
 #endif
 
-static void	expire_upcalls(void *);
+static void	expire_upcalls(struct mf6ctable *);
+static void	expire_upcalls_all(void *);
 #define	EXPIRE_TIMEOUT	(hz / 4)	/* 4x / second */
 #define	UPCALL_EXPIRE	6		/* number of timeouts */
 
@@ -342,13 +348,13 @@ static void collate(struct timeval *);
 #endif /* UPCALL_TIMING */
 
 static int ip6_mrouter_init(struct socket *, int, int);
-static int add_m6fc(struct mf6cctl *);
-static int add_m6if(struct mif6ctl *);
-static int del_m6fc(struct mf6cctl *);
-static int del_m6if(mifi_t *);
-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 int add_m6fc(struct mf6ctable *, struct mf6cctl *);
+static int add_m6if(struct mf6ctable *, int, struct mif6ctl *);
+static int del_m6fc(struct mf6ctable *, struct mf6cctl *);
+static int del_m6if(struct mf6ctable *, mifi_t *);
+static int del_m6if_locked(struct mf6ctable *, mifi_t *);
+static int get_mif6_cnt(struct mf6ctable *, struct sioc_mif_req6 *);
+static int get_sg_cnt(struct mf6ctable *, struct sioc_sg_req6 *);
 
 VNET_DEFINE_STATIC(struct callout, expire_upcalls_ch);
 #define	V_expire_upcalls_ch	VNET(expire_upcalls_ch)
@@ -357,7 +363,7 @@ static int X_ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
 static void X_ip6_mrouter_done(struct socket *);
 static int X_ip6_mrouter_set(struct socket *, struct sockopt *);
 static int X_ip6_mrouter_get(struct socket *, struct sockopt *);
-static int X_mrt6_ioctl(u_long, caddr_t);
+static int X_mrt6_ioctl(u_long, caddr_t, int);
 
 static struct mf6c *
 mf6c_find(const struct mf6ctable *mfct, const struct in6_addr *origin,
@@ -376,6 +382,17 @@ mf6c_find(const struct mf6ctable *mfct, const struct in6_addr *origin,
 	return (NULL);
 }
 
+static struct mf6ctable *
+somfctable(struct socket *so)
+{
+	int fib;
+
+	fib = atomic_load_int(&so->so_fibnum);
+	KASSERT(fib >= 0 && fib < V_nmfctables,
+	    ("%s: so_fibnum %d out of range", __func__, fib));
+	return (&V_mfctables[fib]);
+}
+
 /*
  * Handle MRT setsockopt commands to modify the multicast routing tables.
  */
@@ -389,7 +406,7 @@ X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
 	struct mf6cctl mfcc;
 	mifi_t mifi;
 
-	mfct = &V_mfctables[0];
+	mfct = somfctable(so);
 	if (so != mfct->router && sopt->sopt_name != MRT6_INIT)
 		return (EPERM);
 
@@ -411,25 +428,25 @@ X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
 		error = sooptcopyin(sopt, &mifc, sizeof(mifc), sizeof(mifc));
 		if (error)
 			break;
-		error = add_m6if(&mifc);
+		error = add_m6if(mfct, so->so_fibnum, &mifc);
 		break;
 	case MRT6_ADD_MFC:
 		error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
 		if (error)
 			break;
-		error = add_m6fc(&mfcc);
+		error = add_m6fc(mfct, &mfcc);
 		break;
 	case MRT6_DEL_MFC:
 		error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
 		if (error)
 			break;
-		error = del_m6fc(&mfcc);
+		error = del_m6fc(mfct, &mfcc);
 		break;
 	case MRT6_DEL_MIF:
 		error = sooptcopyin(sopt, &mifi, sizeof(mifi), sizeof(mifi));
 		if (error)
 			break;
-		error = del_m6if(&mifi);
+		error = del_m6if(mfct, &mifi);
 		break;
 	case MRT6_PIM:
 		error = sooptcopyin(sopt, &optval, sizeof(optval),
@@ -455,7 +472,7 @@ X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
 	struct mf6ctable *mfct;
 	int error = 0;
 
-	mfct = &V_mfctables[0];
+	mfct = somfctable(so);
 	if (so != mfct->router)
 		return (EACCES);
 
@@ -471,24 +488,27 @@ X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
  * Handle ioctl commands to obtain information from the cache
  */
 static int
-X_mrt6_ioctl(u_long cmd, caddr_t data)
+X_mrt6_ioctl(u_long cmd, caddr_t data, int fibnum)
 {
+	struct mf6ctable *mfct;
 	int error;
 
 	error = priv_check(curthread, PRIV_NETINET_MROUTE);
 	if (error)
 		return (error);
-	error = EINVAL;
+
+	mfct = &V_mfctables[fibnum];
 	switch (cmd) {
 	case SIOCGETSGCNT_IN6:
-		error = get_sg_cnt((struct sioc_sg_req6 *)data);
+		error = get_sg_cnt(mfct, (struct sioc_sg_req6 *)data);
 		break;
 
 	case SIOCGETMIFCNT_IN6:
-		error = get_mif6_cnt((struct sioc_mif_req6 *)data);
+		error = get_mif6_cnt(mfct, (struct sioc_mif_req6 *)data);
 		break;
 
 	default:
+		error = EINVAL;
 		break;
 	}
 
@@ -499,7 +519,7 @@ X_mrt6_ioctl(u_long cmd, caddr_t data)
  * returns the packet, byte, rpf-failure count for the source group provided
  */
 static int
-get_sg_cnt(struct sioc_sg_req6 *req)
+get_sg_cnt(struct mf6ctable *mfct, struct sioc_sg_req6 *req)
 {
 	struct mf6c *rt;
 	int ret;
@@ -507,8 +527,7 @@ get_sg_cnt(struct sioc_sg_req6 *req)
 	ret = 0;
 
 	MFC6_LOCK();
-	rt = mf6c_find(&V_mfctables[0], &req->src.sin6_addr,
-	    &req->grp.sin6_addr);
+	rt = mf6c_find(mfct, &req->src.sin6_addr, &req->grp.sin6_addr);
 	if (rt == NULL) {
 		ret = ESRCH;
 	} else {
@@ -525,16 +544,14 @@ get_sg_cnt(struct sioc_sg_req6 *req)
  * returns the input and output packet and byte counts on the mif provided
  */
 static int
-get_mif6_cnt(struct sioc_mif_req6 *req)
+get_mif6_cnt(struct mf6ctable *mfct, 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 >= mfct->nummifs) {
@@ -559,6 +576,7 @@ set_pim6(int *i)
 	if ((*i != 1) && (*i != 0))
 		return (EINVAL);
 
+	/* XXX-MJ */
 	V_pim6 = *i;
 
 	return (0);
@@ -577,7 +595,7 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
 	if (v != 1)
 		return (ENOPROTOOPT);
 
-	mfct = &V_mfctables[0];
+	mfct = somfctable(so);
 	MROUTER6_LOCK();
 
 	if (mfct->router != NULL) {
@@ -595,7 +613,7 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
 
 	V_pim6 = 0;/* used for stubbing out/in pim stuff */
 
-	callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls,
+	callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls_all,
 	    curvnet);
 
 	MFC6_UNLOCK();
@@ -618,7 +636,7 @@ X_ip6_mrouter_done(struct socket *so)
 	struct mf6c *rt;
 	struct rtdetq *rte;
 
-	mfct = &V_mfctables[0];
+	mfct = somfctable(so);
 	MROUTER6_LOCK();
 
 	if (mfct->router != so) {
@@ -690,9 +708,8 @@ static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
  * Add a mif to the mif table
  */
 static int
-add_m6if(struct mif6ctl *mifcp)
+add_m6if(struct mf6ctable *mfct, int fibnum, struct mif6ctl *mifcp)
 {
-	struct mf6ctable *mfct;
 	struct epoch_tracker et;
 	struct mif6 *mifp;
 	struct ifnet *ifp;
@@ -704,7 +721,6 @@ add_m6if(struct mif6ctl *mifcp)
 		MIF6_UNLOCK();
 		return (EINVAL);
 	}
-	mfct = &V_mfctables[0];
 	mifp = &mfct->miftable[mifcp->mif6c_mifi];
 	if (mifp->m6_ifp != NULL) {
 		MIF6_UNLOCK();
@@ -743,6 +759,10 @@ add_m6if(struct mif6ctl *mifcp)
 			MIF6_UNLOCK();
 			return (EOPNOTSUPP);
 		}
+		if (ifp->if_fib != fibnum) {
+			MIF6_UNLOCK();
+			return (EADDRNOTAVAIL);
+		}
 
 		error = if_allmulti(ifp, 1);
 		if (error) {
@@ -775,16 +795,14 @@ add_m6if(struct mif6ctl *mifcp)
  * Delete a mif from the mif table
  */
 static int
-del_m6if_locked(mifi_t *mifip)
+del_m6if_locked(struct mf6ctable *mfct, mifi_t *mifip)
 {
-	struct mf6ctable *mfct;
 	struct mif6 *mifp;
 	mifi_t mifi;
 	struct ifnet *ifp;
 
 	MIF6_LOCK_ASSERT();
 
-	mfct = &V_mfctables[0];
 	if (*mifip >= mfct->nummifs)
 		return (EINVAL);
 	mifp = &mfct->miftable[*mifip];
@@ -818,12 +836,12 @@ del_m6if_locked(mifi_t *mifip)
 }
 
 static int
-del_m6if(mifi_t *mifip)
+del_m6if(struct mf6ctable *mfct, mifi_t *mifip)
 {
 	int cc;
 
 	MIF6_LOCK();
-	cc = del_m6if_locked(mifip);
+	cc = del_m6if_locked(mfct, mifip);
 	MIF6_UNLOCK();
 
 	return (cc);
@@ -833,17 +851,14 @@ del_m6if(mifi_t *mifip)
  * Add an mfc entry
  */
 static int
-add_m6fc(struct mf6cctl *mfccp)
+add_m6fc(struct mf6ctable *mfct, 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];
 
-	mfct = &V_mfctables[0];
-
 	MFC6_LOCK();
 	rt = mf6c_find(mfct, &mfccp->mf6cc_origin.sin6_addr,
 	    &mfccp->mf6cc_mcastgrp.sin6_addr);
@@ -1004,19 +1019,17 @@ collate(struct timeval *t)
  * Delete an mfc entry
  */
 static int
-del_m6fc(struct mf6cctl *mfccp)
+del_m6fc(struct mf6ctable *mfct, 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);
@@ -1139,7 +1152,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 		return (0);
 	}
 
-	mfct = &V_mfctables[0];
+	mfct = &V_mfctables[M_GETFIB(m)];
 	MFC6_LOCK();
 
 	/*
@@ -1331,20 +1344,17 @@ 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 *arg)
+expire_upcalls(struct mf6ctable *mfct)
 {
 #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 (mfct->nexpire[i] == 0)
 			continue;
@@ -1382,8 +1392,21 @@ expire_upcalls(void *arg)
 			}
 		}
 	}
-	callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT,
-	    expire_upcalls, curvnet);
+}
+
+/*
+ * Clean up the cache entry if upcall is not serviced
+ */
+static void
+expire_upcalls_all(void *arg)
+{
+	CURVNET_SET((struct vnet *)arg);
+
+	for (int i = 0; i < V_nmfctables; i++)
+		expire_upcalls(&V_mfctables[i]);
+
+	callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls_all,
+	    curvnet);
 
 	CURVNET_RESTORE();
 }
@@ -1753,7 +1776,7 @@ pim6_input(struct mbuf *m, int off, int proto, void *arg __unused)
 	int pimlen;
 	int minlen;
 
-	mfct = &V_mfctables[0];
+	mfct = &V_mfctables[M_GETFIB(m)];
 
 	PIM6STAT_INC(pim6s_rcv_total);
 
diff --git a/sys/netinet6/ip6_mroute.h b/sys/netinet6/ip6_mroute.h
index fda8c4308e86..c8388c3836bb 100644
--- a/sys/netinet6/ip6_mroute.h
+++ b/sys/netinet6/ip6_mroute.h
@@ -288,7 +288,7 @@ extern int	(*ip6_mrouter_set)(struct socket *so, struct sockopt *sopt);
 extern int	(*ip6_mrouter_get)(struct socket *so, struct sockopt *sopt);
 extern void	(*ip6_mrouter_done)(struct socket *so);
 
-extern int	(*mrt6_ioctl)(u_long, caddr_t);
+extern int	(*mrt6_ioctl)(u_long, caddr_t, int);
 #endif /* _KERNEL */
 
 #endif /* !_NETINET6_IP6_MROUTE_H_ */
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 9e51005d7c2e..a92035831c6c 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -145,7 +145,7 @@ int (*ip6_mrouter_set)(struct socket *, struct sockopt *);
 int (*ip6_mrouter_get)(struct socket *, struct sockopt *);
 void (*ip6_mrouter_done)(struct socket *);
 int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *);
-int (*mrt6_ioctl)(u_long, caddr_t);
+int (*mrt6_ioctl)(u_long, caddr_t, int);
 
 struct rip6_inp_match_ctx {
 	struct ip6_hdr *ip6;


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69caa1ad.3c307.55d18a69>