Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Mar 2026 16:15:35 +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: d50d0c002b98 - main - ip_mroute: Start moving globals into a structure
Message-ID:  <69caa1a7.3b9c2.3d515715@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=d50d0c002b982f193e36ede9fa2669d5dcf8467b

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

    ip_mroute: Start moving globals into a structure
    
    I would like to support per-FIB multicast routing tables, such that one
    can run a routing daemon per-FIB, with each daemon oblivious to the
    existence of others.  Currently the multicast routing code is completely
    unaware of FIBs.
    
    To that end, start collecting various global variables in ip_mroute.c
    into a per-VNET struct mfctable.  In a future patch this will be
    expanded into an array of mfctable structures, one per FIB.  For now,
    all of the state is collected into V_mfctables[0].
    
    Each mfctable contains, among other things:
    - a pointer to the routing socket, if routing is enabled,
    - a hash table of routing cache entries,
    - an table of network interfaces participating in the routing
      configuration
    
    This change has no functional effect, it is just factoring out these
    global variables to make the subsequent patches simpler.
    
    MFC after:      2 weeks
    Sponsored by:   Stormshield
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D55237
---
 sys/netinet/ip_mroute.c | 473 +++++++++++++++++++++++++++---------------------
 1 file changed, 266 insertions(+), 207 deletions(-)

diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index 7a197e20a62f..6e5b739f1da8 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -169,8 +169,26 @@ SYSCTL_VNET_PCPUSTAT(_net_inet_ip, OID_AUTO, mrtstat, struct mrtstat,
     mrtstat, "IPv4 Multicast Forwarding Statistics (struct mrtstat, "
     "netinet/ip_mroute.h)");
 
-VNET_DEFINE_STATIC(struct socket *, ip_mrouter);
-#define	V_ip_mrouter		VNET(ip_mrouter)
+struct mfctable {
+	struct socket	*router;
+	LIST_HEAD(mfchashhdr, mfc) *mfchashtbl;
+	u_char		*nexpire;
+	vifi_t		numvifs;
+	struct vif	viftable[MAXVIFS];
+
+	struct buf_ring	*bw_upcalls;
+	struct mtx	bw_upcalls_mtx;
+
+	struct ifnet	*register_if;
+	vifi_t		register_vif;
+
+	uint32_t	api_config;
+	int		pim_assert_enabled;
+	struct timeval	pim_assert_interval;
+};
+
+VNET_DEFINE_STATIC(struct mfctable *, mfctables);
+#define	V_mfctables		VNET(mfctables)
 
 VNET_DEFINE_STATIC(u_long, mfchash);
 #define	V_mfchash		VNET(mfchash)
@@ -182,28 +200,17 @@ VNET_DEFINE_STATIC(u_long, mfchash);
 static u_long mfchashsize = MFCHASHSIZE;	/* Hash size */
 SYSCTL_ULONG(_net_inet_ip, OID_AUTO, mfchashsize, CTLFLAG_RDTUN,
     &mfchashsize, 0, "IPv4 Multicast Forwarding Table hash size");
-VNET_DEFINE_STATIC(u_char *, nexpire);		/* 0..mfchashsize-1 */
-#define	V_nexpire		VNET(nexpire)
-VNET_DEFINE_STATIC(LIST_HEAD(mfchashhdr, mfc)*, mfchashtbl);
-#define	V_mfchashtbl		VNET(mfchashtbl)
+
 VNET_DEFINE_STATIC(struct taskqueue *, task_queue);
 #define	V_task_queue		VNET(task_queue)
 VNET_DEFINE_STATIC(struct task, task);
 #define	V_task		VNET(task)
 
-VNET_DEFINE_STATIC(vifi_t, numvifs);
-#define	V_numvifs		VNET(numvifs)
-VNET_DEFINE_STATIC(struct vif *, viftable);
-#define	V_viftable		VNET(viftable)
-
 static eventhandler_tag if_detach_event_tag = NULL;
 
 VNET_DEFINE_STATIC(struct callout, expire_upcalls_ch);
 #define	V_expire_upcalls_ch	VNET(expire_upcalls_ch)
 
-VNET_DEFINE_STATIC(struct mtx, buf_ring_mtx);
-#define	V_buf_ring_mtx	VNET(buf_ring_mtx)
-
 #define		EXPIRE_TIMEOUT	(hz / 4)	/* 4x / second		*/
 #define		UPCALL_EXPIRE	6		/* number of timeouts	*/
 
@@ -218,10 +225,6 @@ static MALLOC_DEFINE(M_BWMETER, "bwmeter", "multicast upcall bw meters");
  */
 VNET_DEFINE_STATIC(struct callout, bw_upcalls_ch);
 #define	V_bw_upcalls_ch		VNET(bw_upcalls_ch)
-VNET_DEFINE_STATIC(struct buf_ring *, bw_upcalls_ring);
-#define	V_bw_upcalls_ring    	VNET(bw_upcalls_ring)
-VNET_DEFINE_STATIC(struct mtx, bw_upcalls_ring_mtx);
-#define	V_bw_upcalls_ring_mtx    	VNET(bw_upcalls_ring_mtx)
 
 #define BW_UPCALLS_PERIOD (hz)		/* periodical flush of bw upcalls */
 
@@ -296,11 +299,6 @@ static struct pim_encap_pimhdr pim_encap_pimhdr = {
     0				/* flags */
 };
 
-VNET_DEFINE_STATIC(vifi_t, reg_vif_num) = VIFI_INVALID;
-#define	V_reg_vif_num		VNET(reg_vif_num)
-VNET_DEFINE_STATIC(struct ifnet *, multicast_register_if);
-#define	V_multicast_register_if	VNET(multicast_register_if)
-
 /*
  * Private variables.
  */
@@ -332,14 +330,16 @@ static void	free_bw_list(struct bw_meter *);
 static int	get_sg_cnt(struct sioc_sg_req *);
 static int	get_vif_cnt(struct sioc_vif_req *);
 static void	if_detached_event(void *, struct ifnet *);
-static int	ip_mdq(struct mbuf *, struct ifnet *, struct mfc *, vifi_t);
+static int	ip_mdq(struct mfctable *, struct mbuf *, struct ifnet *,
+		    struct mfc *, vifi_t);
 static int	ip_mrouter_init(struct socket *, int);
 static __inline struct mfc *
-		mfc_find(struct in_addr *, struct in_addr *);
+		mfc_find(const struct mfctable *mfct, const struct in_addr *,
+		    const struct in_addr *);
 static void	phyint_send(struct ip *, struct vif *, struct mbuf *);
 static struct mbuf *
 		pim_register_prepare(struct ip *, struct mbuf *);
-static int	pim_register_send(struct ip *, struct vif *,
+static int	pim_register_send(struct mfctable *, struct ip *, struct vif *,
 		    struct mbuf *, struct mfc *);
 static int	pim_register_send_rp(struct ip *, struct vif *,
 		    struct mbuf *, struct mfc *);
@@ -363,29 +363,20 @@ static const uint32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF |
 					 MRT_MFC_FLAGS_BORDER_VIF |
 					 MRT_MFC_RP |
 					 MRT_MFC_BW_UPCALL);
-VNET_DEFINE_STATIC(uint32_t, mrt_api_config);
-#define	V_mrt_api_config	VNET(mrt_api_config)
-VNET_DEFINE_STATIC(int, pim_assert_enabled);
-#define	V_pim_assert_enabled	VNET(pim_assert_enabled)
-static struct timeval pim_assert_interval = { 3, 0 };	/* Rate limit */
 
 /*
  * Find a route for a given origin IP address and multicast group address.
  * Statistics must be updated by the caller.
  */
-static __inline struct mfc *
-mfc_find(struct in_addr *o, struct in_addr *g)
+static struct mfc *
+mfc_find(const struct mfctable *mfct, const struct in_addr *o,
+    const struct in_addr *g)
 {
 	struct mfc *rt;
 
-	/*
-	 * Might be called both RLOCK and WLOCK.
-	 * Check if any, it's caller responsibility
-	 * to choose correct option.
-	 */
 	MRW_LOCK_ASSERT();
 
-	LIST_FOREACH(rt, &V_mfchashtbl[MFCHASH(*o, *g)], mfc_hash) {
+	LIST_FOREACH(rt, &mfct->mfchashtbl[MFCHASH(*o, *g)], mfc_hash) {
 		if (in_hosteq(rt->mfc_origin, *o) &&
 		    in_hosteq(rt->mfc_mcastgrp, *g) &&
 		    buf_ring_empty(rt->mfc_stall_ring))
@@ -403,8 +394,7 @@ mfc_alloc(void)
 	if (rt == NULL)
 		return rt;
 
-	rt->mfc_stall_ring = buf_ring_alloc(MAX_UPQ, M_MRTABLE,
-	    M_NOWAIT, &V_buf_ring_mtx);
+	rt->mfc_stall_ring = buf_ring_alloc(MAX_UPQ, M_MRTABLE, M_NOWAIT, NULL);
 	if (rt->mfc_stall_ring == NULL) {
 		free(rt, M_MRTABLE);
 		return NULL;
@@ -419,6 +409,7 @@ mfc_alloc(void)
 static int
 X_ip_mrouter_set(struct socket *so, struct sockopt *sopt)
 {
+	struct mfctable *mfct;
 	int error, optval;
 	vifi_t vifi;
 	struct vifctl vifc;
@@ -426,7 +417,8 @@ X_ip_mrouter_set(struct socket *so, struct sockopt *sopt)
 	struct bw_upcall bw_upcall;
 	uint32_t i;
 
-	if (so != V_ip_mrouter && sopt->sopt_name != MRT_INIT)
+	mfct = &V_mfctables[0];
+	if (so != mfct->router && sopt->sopt_name != MRT_INIT)
 		return EPERM;
 
 	error = 0;
@@ -458,7 +450,7 @@ X_ip_mrouter_set(struct socket *so, struct sockopt *sopt)
 		 * select data size depending on API version.
 		 */
 		if (sopt->sopt_name == MRT_ADD_MFC &&
-		    V_mrt_api_config & MRT_API_FLAGS_ALL) {
+		    (mfct->api_config & MRT_API_FLAGS_ALL) != 0) {
 			error = sooptcopyin(sopt, &mfc, sizeof(struct mfcctl2),
 			    sizeof(struct mfcctl2));
 		} else {
@@ -515,24 +507,27 @@ X_ip_mrouter_set(struct socket *so, struct sockopt *sopt)
 static int
 X_ip_mrouter_get(struct socket *so, struct sockopt *sopt)
 {
+	struct mfctable *mfct;
 	int error;
 
+	mfct = &V_mfctables[0];
+
 	switch (sopt->sopt_name) {
 	case MRT_VERSION:
 		error = sooptcopyout(sopt, &mrt_api_version,
 		    sizeof mrt_api_version);
 		break;
 	case MRT_ASSERT:
-		error = sooptcopyout(sopt, &V_pim_assert_enabled,
-		    sizeof V_pim_assert_enabled);
+		error = sooptcopyout(sopt, &mfct->pim_assert_enabled,
+		    sizeof(mfct->pim_assert_enabled));
 		break;
 	case MRT_API_SUPPORT:
 		error = sooptcopyout(sopt, &mrt_api_support,
 		    sizeof mrt_api_support);
 		break;
 	case MRT_API_CONFIG:
-		error = sooptcopyout(sopt, &V_mrt_api_config,
-		    sizeof V_mrt_api_config);
+		error = sooptcopyout(sopt, &mfct->api_config,
+		    sizeof(mfct->api_config));
 		break;
 	default:
 		error = EOPNOTSUPP;
@@ -577,7 +572,7 @@ get_sg_cnt(struct sioc_sg_req *req)
 	struct mfc *rt;
 
 	MRW_RLOCK();
-	rt = mfc_find(&req->src, &req->grp);
+	rt = mfc_find(&V_mfctables[0], &req->src, &req->grp);
 	if (rt == NULL) {
 		MRW_RUNLOCK();
 		req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
@@ -596,18 +591,20 @@ get_sg_cnt(struct sioc_sg_req *req)
 static int
 get_vif_cnt(struct sioc_vif_req *req)
 {
+	struct mfctable *mfct;
 	struct vif *vif;
 	vifi_t vifi;
 
+	mfct = &V_mfctables[0];
 	vifi = req->vifi;
 
 	MRW_RLOCK();
-	if (vifi >= V_numvifs) {
+	if (vifi >= mfct->numvifs) {
 		MRW_RUNLOCK();
 		return EINVAL;
 	}
 
-	vif = &V_viftable[vifi];
+	vif = &mfct->viftable[vifi];
 	mtx_lock(&vif->v_mtx);
 	req->icount = vif->v_pkt_in;
 	req->ocount = vif->v_pkt_out;
@@ -622,10 +619,13 @@ get_vif_cnt(struct sioc_vif_req *req)
 static void
 if_detached_event(void *arg __unused, struct ifnet *ifp)
 {
+	struct mfctable *mfct;
 	vifi_t vifi;
 	u_long i, vifi_cnt = 0;
 	struct ifnet *free_ptr, *multi_leave;
 
+	mfct = &V_mfctables[0];
+
 	MRW_WLOCK();
 	if (!V_ip_mrouting_enabled) {
 		MRW_WUNLOCK();
@@ -641,13 +641,14 @@ if_detached_event(void *arg __unused, struct ifnet *ifp)
 	 * 4. Free vif state. This should disable ALLMULTI on the interface.
 	 */
 restart:
-	for (vifi = 0; vifi < V_numvifs; vifi++) {
-		if (V_viftable[vifi].v_ifp != ifp)
+	for (vifi = 0; vifi < mfct->numvifs; vifi++) {
+		if (mfct->viftable[vifi].v_ifp != ifp)
 			continue;
 		for (i = 0; i < mfchashsize; i++) {
 			struct mfc *rt, *nrt;
 
-			LIST_FOREACH_SAFE(rt, &V_mfchashtbl[i], mfc_hash, nrt) {
+			LIST_FOREACH_SAFE(rt, &mfct->mfchashtbl[i], mfc_hash,
+			    nrt) {
 				if (rt->mfc_parent == vifi) {
 					expire_mfc(rt);
 				}
@@ -693,12 +694,14 @@ ip_mrouter_upcall_thread(void *arg, int pending __unused)
 static int
 ip_mrouter_init(struct socket *so, int version)
 {
+	struct mfctable *mfct;
 
 	CTR2(KTR_IPMF, "%s: so %p", __func__, so);
 
 	if (version != 1)
 		return ENOPROTOOPT;
 
+	mfct = &V_mfctables[0];
 	MRW_TEARDOWN_WLOCK();
 	MRW_WLOCK();
 
@@ -708,25 +711,26 @@ ip_mrouter_init(struct socket *so, int version)
 		return ENOPROTOOPT;
 	}
 
-	if (V_ip_mrouter != NULL) {
+	if (mfct->router != NULL) {
 		MRW_WUNLOCK();
 		MRW_TEARDOWN_WUNLOCK();
 		return EADDRINUSE;
 	}
 
-	V_mfchashtbl = hashinit_flags(mfchashsize, M_MRTABLE, &V_mfchash,
+	mfct->mfchashtbl = hashinit_flags(mfchashsize, M_MRTABLE, &V_mfchash,
 	    HASH_NOWAIT);
-	if (V_mfchashtbl == NULL) {
+	if (mfct->mfchashtbl == NULL) {
 		MRW_WUNLOCK();
 		MRW_TEARDOWN_WUNLOCK();
 		return (ENOMEM);
 	}
 
 	/* Create upcall ring */
-	mtx_init(&V_bw_upcalls_ring_mtx, "mroute upcall buf_ring mtx", NULL, MTX_DEF);
-	V_bw_upcalls_ring = buf_ring_alloc(BW_UPCALLS_MAX, M_MRTABLE,
-	    M_NOWAIT, &V_bw_upcalls_ring_mtx);
-	if (!V_bw_upcalls_ring) {
+	mtx_init(&mfct->bw_upcalls_mtx, "mroute upcall buf_ring mtx", NULL,
+	    MTX_DEF);
+	mfct->bw_upcalls = buf_ring_alloc(BW_UPCALLS_MAX, M_MRTABLE, M_NOWAIT,
+	    &mfct->bw_upcalls_mtx);
+	if (mfct->bw_upcalls == NULL) {
 		MRW_WUNLOCK();
 		MRW_TEARDOWN_WUNLOCK();
 		return (ENOMEM);
@@ -741,13 +745,11 @@ ip_mrouter_init(struct socket *so, int version)
 	callout_reset(&V_bw_upcalls_ch, BW_UPCALLS_PERIOD, expire_bw_upcalls_send,
 	    curvnet);
 
-	V_ip_mrouter = so;
+	mfct->router = so;
+	mfct->pim_assert_interval.tv_sec = 3;
 	V_ip_mrouting_enabled = true;
 	atomic_add_int(&ip_mrouter_cnt, 1);
 
-	/* This is a mutex required by buf_ring init, but not used internally */
-	mtx_init(&V_buf_ring_mtx, "mroute buf_ring mtx", NULL, MTX_DEF);
-
 	MRW_WUNLOCK();
 	MRW_TEARDOWN_WUNLOCK();
 
@@ -762,14 +764,17 @@ ip_mrouter_init(struct socket *so, int version)
 static void
 X_ip_mrouter_done(struct socket *so)
 {
+	struct mfctable *mfct;
 	struct ifnet **ifps;
 	int nifp;
 	u_long i;
 	vifi_t vifi;
 	struct bw_upcall *bu;
 
+	mfct = &V_mfctables[0];
+
 	MRW_TEARDOWN_WLOCK();
-	if (so != V_ip_mrouter) {
+	if (so != mfct->router) {
 		MRW_TEARDOWN_WUNLOCK();
 		return;
 	}
@@ -777,10 +782,10 @@ X_ip_mrouter_done(struct socket *so)
 	/*
 	 * Detach/disable hooks to the reset of the system.
 	 */
-	V_ip_mrouter = NULL;
+	mfct->router = NULL;
 	V_ip_mrouting_enabled = false;
 	atomic_subtract_int(&ip_mrouter_cnt, 1);
-	V_mrt_api_config = 0;
+	mfct->api_config = 0;
 
 	/*
 	 * Wait for all epoch sections to complete to ensure the new value of
@@ -800,11 +805,11 @@ X_ip_mrouter_done(struct socket *so)
 	taskqueue_cancel(V_task_queue, &V_task, NULL);
 
 	/* Destroy upcall ring */
-	while ((bu = buf_ring_dequeue_mc(V_bw_upcalls_ring)) != NULL) {
+	while ((bu = buf_ring_dequeue_mc(mfct->bw_upcalls)) != NULL) {
 		free(bu, M_MRTABLE);
 	}
-	buf_ring_free(V_bw_upcalls_ring, M_MRTABLE);
-	mtx_destroy(&V_bw_upcalls_ring_mtx);
+	buf_ring_free(mfct->bw_upcalls, M_MRTABLE);
+	mtx_destroy(&mfct->bw_upcalls_mtx);
 
 	/*
 	 * For each phyint in use, prepare to disable promiscuous reception
@@ -813,16 +818,19 @@ X_ip_mrouter_done(struct socket *so)
 	 * sx locks in their ioctl routines, which is not allowed while holding
 	 * a non-sleepable lock.
 	 */
-	KASSERT(V_numvifs <= MAXVIFS, ("More vifs than possible"));
-	for (vifi = 0, nifp = 0; vifi < V_numvifs; vifi++) {
-		if (!in_nullhost(V_viftable[vifi].v_lcl_addr) &&
-		    !(V_viftable[vifi].v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) {
-			ifps[nifp++] = V_viftable[vifi].v_ifp;
+	KASSERT(mfct->numvifs <= MAXVIFS, ("More vifs than possible"));
+	for (vifi = 0, nifp = 0; vifi < mfct->numvifs; vifi++) {
+		struct vif *vif;
+
+		vif = &mfct->viftable[vifi];
+		if (!in_nullhost(vif->v_lcl_addr) &&
+		    (vif->v_flags & (VIFF_TUNNEL | VIFF_REGISTER)) == 0) {
+			ifps[nifp++] = vif->v_ifp;
 		}
 	}
-	bzero((caddr_t)V_viftable, sizeof(*V_viftable) * MAXVIFS);
-	V_numvifs = 0;
-	V_pim_assert_enabled = 0;
+	bzero(mfct->viftable, sizeof(*mfct->viftable) * MAXVIFS);
+	mfct->numvifs = 0;
+	mfct->pim_assert_enabled = 0;
 
 	callout_stop(&V_expire_upcalls_ch);
 	callout_stop(&V_bw_upcalls_ch);
@@ -834,18 +842,15 @@ X_ip_mrouter_done(struct socket *so)
 	for (i = 0; i < mfchashsize; i++) {
 		struct mfc *rt, *nrt;
 
-		LIST_FOREACH_SAFE(rt, &V_mfchashtbl[i], mfc_hash, nrt) {
+		LIST_FOREACH_SAFE(rt, &mfct->mfchashtbl[i], mfc_hash, nrt) {
 			expire_mfc(rt);
 		}
 	}
-	free(V_mfchashtbl, M_MRTABLE);
-	V_mfchashtbl = NULL;
-
-	bzero(V_nexpire, sizeof(V_nexpire[0]) * mfchashsize);
+	free(mfct->mfchashtbl, M_MRTABLE);
+	mfct->mfchashtbl = NULL;
 
-	V_reg_vif_num = VIFI_INVALID;
-
-	mtx_destroy(&V_buf_ring_mtx);
+	bzero(mfct->nexpire, sizeof(mfct->nexpire[0]) * mfchashsize);
+	mfct->register_vif = VIFI_INVALID;
 
 	MRW_WUNLOCK();
 	MRW_TEARDOWN_WUNLOCK();
@@ -870,7 +875,7 @@ set_assert(int i)
 	if ((i != 1) && (i != 0))
 		return EINVAL;
 
-	V_pim_assert_enabled = i;
+	V_mfctables[0].pim_assert_enabled = i;
 
 	return 0;
 }
@@ -881,6 +886,7 @@ set_assert(int i)
 int
 set_api_config(uint32_t *apival)
 {
+	struct mfctable *mfct;
 	u_long i;
 
 	/*
@@ -890,11 +896,12 @@ set_api_config(uint32_t *apival)
 	 *  - pim_assert is not enabled
 	 *  - the MFC table is empty
 	 */
-	if (V_numvifs > 0) {
+	mfct = &V_mfctables[0];
+	if (mfct->numvifs > 0) {
 		*apival = 0;
 		return EPERM;
 	}
-	if (V_pim_assert_enabled) {
+	if (mfct->pim_assert_enabled) {
 		*apival = 0;
 		return EPERM;
 	}
@@ -902,7 +909,7 @@ set_api_config(uint32_t *apival)
 	MRW_RLOCK();
 
 	for (i = 0; i < mfchashsize; i++) {
-		if (LIST_FIRST(&V_mfchashtbl[i]) != NULL) {
+		if (LIST_FIRST(&mfct->mfchashtbl[i]) != NULL) {
 			MRW_RUNLOCK();
 			*apival = 0;
 			return EPERM;
@@ -911,8 +918,8 @@ set_api_config(uint32_t *apival)
 
 	MRW_RUNLOCK();
 
-	V_mrt_api_config = *apival & mrt_api_support;
-	*apival = V_mrt_api_config;
+	mfct->api_config = *apival & mrt_api_support;
+	*apival = mfct->api_config;
 
 	return 0;
 }
@@ -923,7 +930,8 @@ set_api_config(uint32_t *apival)
 static int
 add_vif(struct vifctl *vifcp)
 {
-	struct vif *vifp = V_viftable + vifcp->vifc_vifi;
+	struct mfctable *mfct;
+	struct vif *vifp;
 	struct sockaddr_in sin = {sizeof sin, AF_INET};
 	struct ifaddr *ifa;
 	struct ifnet *ifp;
@@ -931,6 +939,10 @@ add_vif(struct vifctl *vifcp)
 
 	if (vifcp->vifc_vifi >= MAXVIFS)
 		return EINVAL;
+
+	mfct = &V_mfctables[0];
+	vifp = &mfct->viftable[vifcp->vifc_vifi];
+
 	/* rate limiting is no longer supported by this code */
 	if (vifcp->vifc_rate_limit != 0) {
 		log(LOG_ERR, "rate limiting is no longer supported\n");
@@ -967,11 +979,11 @@ add_vif(struct vifctl *vifcp)
 		CTR1(KTR_IPMF, "%s: tunnels are no longer supported", __func__);
 		return EOPNOTSUPP;
 	} else if (vifcp->vifc_flags & VIFF_REGISTER) {
-		ifp = V_multicast_register_if = if_alloc(IFT_LOOP);
+		ifp = mfct->register_if = if_alloc(IFT_LOOP);
 		CTR2(KTR_IPMF, "%s: add register vif for ifp %p", __func__, ifp);
-		if (V_reg_vif_num == VIFI_INVALID) {
-			if_initname(V_multicast_register_if, "register_vif", 0);
-			V_reg_vif_num = vifcp->vifc_vifi;
+		if (mfct->register_vif == VIFI_INVALID) {
+			if_initname(mfct->register_if, "register_vif", 0);
+			mfct->register_vif = vifcp->vifc_vifi;
 		}
 	} else {		/* Make sure the interface supports multicast */
 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
@@ -987,7 +999,7 @@ add_vif(struct vifctl *vifcp)
 
 	if (!in_nullhost(vifp->v_lcl_addr)) {
 		if (ifp)
-			V_multicast_register_if = NULL;
+			mfct->register_if = NULL;
 		MRW_WUNLOCK();
 		if (ifp)
 			if_free(ifp);
@@ -1008,8 +1020,8 @@ add_vif(struct vifctl *vifcp)
 	mtx_init(&vifp->v_mtx, vifp->v_mtx_name, NULL, MTX_DEF);
 
 	/* Adjust numvifs up if the vifi is higher than numvifs */
-	if (V_numvifs <= vifcp->vifc_vifi)
-		V_numvifs = vifcp->vifc_vifi + 1;
+	if (mfct->numvifs <= vifcp->vifc_vifi)
+		mfct->numvifs = vifcp->vifc_vifi + 1;
 
 	MRW_WUNLOCK();
 
@@ -1026,17 +1038,19 @@ add_vif(struct vifctl *vifcp)
 static int
 del_vif_locked(vifi_t vifi, struct ifnet **ifp_multi_leave, struct ifnet **ifp_free)
 {
+	struct mfctable *mfct;
 	struct vif *vifp;
 
+	mfct = &V_mfctables[0];
 	*ifp_free = NULL;
 	*ifp_multi_leave = NULL;
 
 	MRW_WLOCK_ASSERT();
 
-	if (vifi >= V_numvifs) {
+	if (vifi >= mfct->numvifs) {
 		return EINVAL;
 	}
-	vifp = &V_viftable[vifi];
+	vifp = &mfct->viftable[vifi];
 	if (in_nullhost(vifp->v_lcl_addr)) {
 		return EADDRNOTAVAIL;
 	}
@@ -1045,10 +1059,10 @@ del_vif_locked(vifi_t vifi, struct ifnet **ifp_multi_leave, struct ifnet **ifp_f
 		*ifp_multi_leave = vifp->v_ifp;
 
 	if (vifp->v_flags & VIFF_REGISTER) {
-		V_reg_vif_num = VIFI_INVALID;
+		mfct->register_vif = VIFI_INVALID;
 		if (vifp->v_ifp) {
-			if (vifp->v_ifp == V_multicast_register_if)
-				V_multicast_register_if = NULL;
+			if (vifp->v_ifp == mfct->register_if)
+				mfct->register_if = NULL;
 			*ifp_free = vifp->v_ifp;
 		}
 	}
@@ -1060,10 +1074,10 @@ del_vif_locked(vifi_t vifi, struct ifnet **ifp_multi_leave, struct ifnet **ifp_f
 	CTR2(KTR_IPMF, "%s: delete vif %d", __func__, (int)vifi);
 
 	/* Adjust numvifs down */
-	for (vifi = V_numvifs; vifi > 0; vifi--)
-		if (!in_nullhost(V_viftable[vifi-1].v_lcl_addr))
+	for (vifi = mfct->numvifs; vifi > 0; vifi--)
+		if (!in_nullhost(mfct->viftable[vifi - 1].v_lcl_addr))
 			break;
-	V_numvifs = vifi;
+	mfct->numvifs = vifi;
 
 	return 0;
 }
@@ -1091,18 +1105,18 @@ del_vif(vifi_t vifi)
  * update an mfc entry without resetting counters and S,G addresses.
  */
 static void
-update_mfc_params(struct mfc *rt, struct mfcctl2 *mfccp)
+update_mfc_params(struct mfctable *mfct, struct mfc *rt, struct mfcctl2 *mfccp)
 {
 	int i;
 
 	rt->mfc_parent = mfccp->mfcc_parent;
-	for (i = 0; i < V_numvifs; i++) {
+	for (i = 0; i < mfct->numvifs; i++) {
 		rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
-		rt->mfc_flags[i] = mfccp->mfcc_flags[i] & V_mrt_api_config &
+		rt->mfc_flags[i] = mfccp->mfcc_flags[i] & mfct->api_config &
 			MRT_MFC_FLAGS_ALL;
 	}
 	/* set the RP address */
-	if (V_mrt_api_config & MRT_MFC_RP)
+	if (mfct->api_config & MRT_MFC_RP)
 		rt->mfc_rp = mfccp->mfcc_rp;
 	else
 		rt->mfc_rp.s_addr = INADDR_ANY;
@@ -1112,12 +1126,12 @@ update_mfc_params(struct mfc *rt, struct mfcctl2 *mfccp)
  * fully initialize an mfc entry from the parameter.
  */
 static void
-init_mfc_params(struct mfc *rt, struct mfcctl2 *mfccp)
+init_mfc_params(struct mfctable *mfct, struct mfc *rt, struct mfcctl2 *mfccp)
 {
 	rt->mfc_origin     = mfccp->mfcc_origin;
 	rt->mfc_mcastgrp   = mfccp->mfcc_mcastgrp;
 
-	update_mfc_params(rt, mfccp);
+	update_mfc_params(mfct, rt, mfccp);
 
 	/* initialize pkt counters per src-grp */
 	rt->mfc_pkt_cnt    = 0;
@@ -1156,13 +1170,16 @@ static int
 add_mfc(struct mfcctl2 *mfccp)
 {
 	struct mfc *rt;
+	struct mfctable *mfct;
 	struct rtdetq *rte;
 	u_long hash = 0;
 	u_short nstl;
 	struct epoch_tracker et;
 
+	mfct = &V_mfctables[0];
+
 	MRW_WLOCK();
-	rt = mfc_find(&mfccp->mfcc_origin, &mfccp->mfcc_mcastgrp);
+	rt = mfc_find(mfct, &mfccp->mfcc_origin, &mfccp->mfcc_mcastgrp);
 
 	/* If an entry already exists, just update the fields */
 	if (rt) {
@@ -1170,7 +1187,7 @@ add_mfc(struct mfcctl2 *mfccp)
 		    __func__, ntohl(mfccp->mfcc_origin.s_addr),
 		    (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
 		    mfccp->mfcc_parent);
-		update_mfc_params(rt, mfccp);
+		update_mfc_params(mfct, rt, mfccp);
 		MRW_WUNLOCK();
 		return (0);
 	}
@@ -1181,7 +1198,7 @@ add_mfc(struct mfcctl2 *mfccp)
 	nstl = 0;
 	hash = MFCHASH(mfccp->mfcc_origin, mfccp->mfcc_mcastgrp);
 	NET_EPOCH_ENTER(et);
-	LIST_FOREACH(rt, &V_mfchashtbl[hash], mfc_hash) {
+	LIST_FOREACH(rt, &mfct->mfchashtbl[hash], mfc_hash) {
 		if (in_hosteq(rt->mfc_origin, mfccp->mfcc_origin) &&
 		    in_hosteq(rt->mfc_mcastgrp, mfccp->mfcc_mcastgrp) &&
 		    !buf_ring_empty(rt->mfc_stall_ring)) {
@@ -1194,15 +1211,15 @@ add_mfc(struct mfcctl2 *mfccp)
 			if (nstl++)
 				CTR1(KTR_IPMF, "%s: multiple matches", __func__);
 
-			init_mfc_params(rt, mfccp);
+			init_mfc_params(mfct, rt, mfccp);
 			rt->mfc_expire = 0;	/* Don't clean this guy up */
-			V_nexpire[hash]--;
+			mfct->nexpire[hash]--;
 
 			/* Free queued packets, but attempt to forward them first. */
 			while (!buf_ring_empty(rt->mfc_stall_ring)) {
 				rte = buf_ring_dequeue_mc(rt->mfc_stall_ring);
 				if (rte->ifp != NULL)
-					ip_mdq(rte->m, rte->ifp, rt, -1);
+					ip_mdq(mfct, rte->m, rte->ifp, rt, -1);
 				m_freem(rte->m);
 				free(rte, M_MRTABLE);
 			}
@@ -1215,12 +1232,12 @@ add_mfc(struct mfcctl2 *mfccp)
 	 */
 	if (nstl == 0) {
 		CTR1(KTR_IPMF, "%s: adding mfc w/o upcall", __func__);
-		LIST_FOREACH(rt, &V_mfchashtbl[hash], mfc_hash) {
+		LIST_FOREACH(rt, &mfct->mfchashtbl[hash], mfc_hash) {
 			if (in_hosteq(rt->mfc_origin, mfccp->mfcc_origin) &&
 			    in_hosteq(rt->mfc_mcastgrp, mfccp->mfcc_mcastgrp)) {
-				init_mfc_params(rt, mfccp);
+				init_mfc_params(mfct, rt, mfccp);
 				if (rt->mfc_expire)
-					V_nexpire[hash]--;
+					mfct->nexpire[hash]--;
 				rt->mfc_expire = 0;
 				break; /* XXX */
 			}
@@ -1233,14 +1250,14 @@ add_mfc(struct mfcctl2 *mfccp)
 				return (ENOBUFS);
 			}
 
-			init_mfc_params(rt, mfccp);
+			init_mfc_params(mfct, rt, mfccp);
 
 			rt->mfc_expire     = 0;
 			rt->mfc_bw_meter_leq = NULL;
 			rt->mfc_bw_meter_geq = NULL;
 
 			/* insert new entry at head of hash chain */
-			LIST_INSERT_HEAD(&V_mfchashtbl[hash], rt, mfc_hash);
+			LIST_INSERT_HEAD(&mfct->mfchashtbl[hash], rt, mfc_hash);
 		}
 	}
 
@@ -1255,6 +1272,7 @@ add_mfc(struct mfcctl2 *mfccp)
 static int
 del_mfc(struct mfcctl2 *mfccp)
 {
+	struct mfctable *mfct;
 	struct in_addr origin;
 	struct in_addr mcastgrp;
 	struct mfc *rt;
@@ -1265,9 +1283,11 @@ del_mfc(struct mfcctl2 *mfccp)
 	CTR3(KTR_IPMF, "%s: delete mfc orig 0x%08x group %lx", __func__,
 			ntohl(origin.s_addr), (u_long)ntohl(mcastgrp.s_addr));
 
+	mfct = &V_mfctables[0];
 	MRW_WLOCK();
 
-	LIST_FOREACH(rt, &V_mfchashtbl[MFCHASH(origin, mcastgrp)], mfc_hash) {
+	LIST_FOREACH(rt, &mfct->mfchashtbl[MFCHASH(origin, mcastgrp)],
+	    mfc_hash) {
 		if (in_hosteq(rt->mfc_origin, origin) &&
 		    in_hosteq(rt->mfc_mcastgrp, mcastgrp))
 			break;
@@ -1321,6 +1341,7 @@ X_ip_mforward(struct ip *ip, struct ifnet *ifp, struct mbuf *m,
     struct ip_moptions *imo)
 {
 	struct mfc *rt;
+	struct mfctable *mfct;
 	int error;
 	vifi_t vifi;
 	struct mbuf *mb0;
@@ -1347,14 +1368,16 @@ X_ip_mforward(struct ip *ip, struct ifnet *ifp, struct mbuf *m,
 		return (1);
 	}
 
+	mfct = &V_mfctables[0];
+
 	/*
 	 * BEGIN: MCAST ROUTING HOT PATH
 	 */
 	MRW_RLOCK();
-	if (imo && ((vifi = imo->imo_multicast_vif) < V_numvifs)) {
+	if (imo && ((vifi = imo->imo_multicast_vif) < mfct->numvifs)) {
 		if (ip->ip_ttl < MAXTTL)
 			ip->ip_ttl++; /* compensate for -1 in *_send routines */
-		error = ip_mdq(m, ifp, NULL, vifi);
+		error = ip_mdq(mfct, m, ifp, NULL, vifi);
 		MRW_RUNLOCK();
 		return error;
 	}
@@ -1373,11 +1396,11 @@ mfc_find_retry:
 	 * Determine forwarding vifs from the forwarding cache table
 	 */
 	MRTSTAT_INC(mrts_mfc_lookups);
-	rt = mfc_find(&ip->ip_src, &ip->ip_dst);
+	rt = mfc_find(mfct, &ip->ip_src, &ip->ip_dst);
 
 	/* Entry exists, so forward if necessary */
 	if (rt != NULL) {
-		error = ip_mdq(m, ifp, rt, -1);
+		error = ip_mdq(mfct, m, ifp, rt, -1);
 		/* Generic unlock here as we might release R or W lock */
 		MRW_UNLOCK();
 		return error;
@@ -1427,8 +1450,7 @@ mfc_find_retry:
 
 	/* is there an upcall waiting for this flow ? */
 	hash = MFCHASH(ip->ip_src, ip->ip_dst);
-	LIST_FOREACH(rt, &V_mfchashtbl[hash], mfc_hash)
-	{
+	LIST_FOREACH(rt, &mfct->mfchashtbl[hash], mfc_hash) {
 		if (in_hosteq(ip->ip_src, rt->mfc_origin) &&
 		    in_hosteq(ip->ip_dst, rt->mfc_mcastgrp) &&
 		    !buf_ring_empty(rt->mfc_stall_ring))
@@ -1445,10 +1467,10 @@ mfc_find_retry:
 		 * Locate the vifi for the incoming interface for this packet.
 		 * If none found, drop packet.
 		 */
-		for (vifi = 0; vifi < V_numvifs &&
-		    V_viftable[vifi].v_ifp != ifp; vifi++)
+		for (vifi = 0; vifi < mfct->numvifs &&
+		    mfct->viftable[vifi].v_ifp != ifp; vifi++)
 			;
-		if (vifi >= V_numvifs) /* vif not found, drop packet */
+		if (vifi >= mfct->numvifs) /* vif not found, drop packet */
 			goto non_fatal;
 
 		/* no upcall, so make a new entry */
@@ -1474,7 +1496,7 @@ mfc_find_retry:
 		MRTSTAT_INC(mrts_upcalls);
 
 		k_igmpsrc.sin_addr = ip->ip_src;
-		if (socket_send(V_ip_mrouter, mm, &k_igmpsrc) < 0) {
+		if (socket_send(mfct->router, mm, &k_igmpsrc) < 0) {
 			CTR0(KTR_IPMF, "ip_mforward: socket queue full");
 			MRTSTAT_INC(mrts_upq_sockfull);
 			fail1: free(rt, M_MRTABLE);
@@ -1488,8 +1510,8 @@ mfc_find_retry:
 		rt->mfc_origin.s_addr = ip->ip_src.s_addr;
 		rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr;
 		rt->mfc_expire = UPCALL_EXPIRE;
-		V_nexpire[hash]++;
-		for (i = 0; i < V_numvifs; i++) {
+		mfct->nexpire[hash]++;
+		for (i = 0; i < mfct->numvifs; i++) {
 			rt->mfc_ttls[i] = 0;
 			rt->mfc_flags[i] = 0;
 		}
@@ -1509,7 +1531,7 @@ mfc_find_retry:
 		buf_ring_enqueue(rt->mfc_stall_ring, rte);
 
 		/* Add RT to hashtable as it didn't exist before */
-		LIST_INSERT_HEAD(&V_mfchashtbl[hash], rt, mfc_hash);
+		LIST_INSERT_HEAD(&mfct->mfchashtbl[hash], rt, mfc_hash);
 	} else {
 		/* determine if queue has overflowed */
 		if (buf_ring_full(rt->mfc_stall_ring)) {
@@ -1537,19 +1559,21 @@ mfc_find_retry:
 static void
 expire_upcalls(void *arg)
 {
+	struct mfctable *mfct;
 	u_long i;
 
 	CURVNET_SET((struct vnet *) arg);
 
-	/*This callout is always run with MRW_WLOCK taken. */
+	MRW_LOCK_ASSERT();
 
+	mfct = &V_mfctables[0];
 	for (i = 0; i < mfchashsize; i++) {
 		struct mfc *rt, *nrt;
 
-		if (V_nexpire[i] == 0)
+		if (mfct->nexpire[i] == 0)
 			continue;
 
-		LIST_FOREACH_SAFE(rt, &V_mfchashtbl[i], mfc_hash, nrt) {
+		LIST_FOREACH_SAFE(rt, &mfct->mfchashtbl[i], mfc_hash, nrt) {
 			if (buf_ring_empty(rt->mfc_stall_ring))
 				continue;
 
@@ -1575,7 +1599,8 @@ expire_upcalls(void *arg)
  * Packet forwarding routine once entry in the cache is made
  */
 static int
-ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif)
+ip_mdq(struct mfctable *mfct, struct mbuf *m, struct ifnet *ifp, struct mfc *rt,
+    vifi_t xmt_vif)
 {
 	struct ip *ip = mtod(m, struct ip *);
 	struct vif *vif;
@@ -1591,11 +1616,12 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif)
 	 *
 	 * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.)
 	 */
-	if (xmt_vif < V_numvifs) {
-		if (V_viftable[xmt_vif].v_flags & VIFF_REGISTER)
-			pim_register_send(ip, V_viftable + xmt_vif, m, rt);
+	if (xmt_vif < mfct->numvifs) {
+		if (mfct->viftable[xmt_vif].v_flags & VIFF_REGISTER)
+			pim_register_send(mfct, ip, &mfct->viftable[xmt_vif], m,
+			    rt);
 		else
-			phyint_send(ip, V_viftable + xmt_vif, m);
+			phyint_send(ip, &mfct->viftable[xmt_vif], m);
 		return 1;
 	}
 
@@ -1603,8 +1629,8 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif)
 	 * Don't forward if it didn't arrive from the parent vif for its origin.
 	 */
 	vifi = rt->mfc_parent;
-	vif = &V_viftable[vifi];
-	if (vifi >= V_numvifs || vif->v_ifp != ifp) {
+	vif = &mfct->viftable[vifi];
+	if (vifi >= mfct->numvifs || vif->v_ifp != ifp) {
 		CTR4(KTR_IPMF, "%s: rx on wrong ifp %p (vifi %d, v_ifp %p)",
 				__func__, ifp, (int)vifi, vif->v_ifp);
 		MRTSTAT_INC(mrts_wrong_if);
@@ -1617,21 +1643,23 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif)
 		 * can complete the SPT switch, regardless of the type
 		 * of the iif (broadcast media, GRE tunnel, etc).
 		 */
-		if (V_pim_assert_enabled && (vifi < V_numvifs) &&
+		if (mfct->pim_assert_enabled && (vifi < mfct->numvifs) &&
 		    vif->v_ifp != NULL) {
-			if (ifp == V_multicast_register_if)
+			if (ifp == mfct->register_if)
 				PIMSTAT_INC(pims_rcv_registers_wrongiif);
 
 			/* Get vifi for the incoming packet */
-			for (vifi = 0; vifi < V_numvifs && V_viftable[vifi].v_ifp != ifp; vifi++)
+			for (vifi = 0; vifi < mfct->numvifs &&
+			    mfct->viftable[vifi].v_ifp != ifp; vifi++)
 				;
-			if (vifi >= V_numvifs)
+			if (vifi >= mfct->numvifs)
 				return 0;	/* The iif is not found: ignore the packet. */
 
 			if (rt->mfc_flags[vifi] & MRT_MFC_FLAGS_DISABLE_WRONGVIF)
 				return 0;	/* WRONGVIF disabled: ignore the packet */
 
-			if (ratecheck(&rt->mfc_last_assert, &pim_assert_interval)) {
+			if (ratecheck(&rt->mfc_last_assert,
+			    &mfct->pim_assert_interval)) {
 				struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET };
 				struct igmpmsg *im;
 				int hlen = ip->ip_hl << 2;
@@ -1650,7 +1678,8 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif)
 				MRTSTAT_INC(mrts_upcalls);
 
 				k_igmpsrc.sin_addr = im->im_src;
-				if (socket_send(V_ip_mrouter, mm, &k_igmpsrc) < 0) {
+				if (socket_send(mfct->router, mm,
+				    &k_igmpsrc) < 0) {
 					CTR1(KTR_IPMF, "%s: socket queue full", __func__);
 					MRTSTAT_INC(mrts_upq_sockfull);
 					return ENOBUFS;
@@ -1680,13 +1709,13 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif)
 	 *		- the ttl exceeds the vif's threshold
 	 *		- there are group members downstream on interface
 	 */
-	for (vifi = 0; vifi < V_numvifs; vifi++)
+	for (vifi = 0; vifi < mfct->numvifs; vifi++)
 		if ((rt->mfc_ttls[vifi] > 0) && (ip->ip_ttl > rt->mfc_ttls[vifi])) {
-			vif = &V_viftable[vifi];
+			vif = &mfct->viftable[vifi];
*** 425 LINES SKIPPED ***


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69caa1a7.3b9c2.3d515715>