git: a223d6c489c7 - main - ip6_mroute: Start putting global variables into a structure
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 30 Mar 2026 16:15:36 UTC
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)
{