summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/ip6_mroute.c
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2009-03-19 01:43:03 +0000
committerbms <bms@FreeBSD.org>2009-03-19 01:43:03 +0000
commit76f193cd692e42617fb7f33b9581e7e5a3da58f0 (patch)
treed8c3186aadc92c08ebcc649765a90704c2e1d233 /sys/netinet6/ip6_mroute.c
parentbe7293a078080bef32e2a64d792bfdfa0c65dead (diff)
downloadFreeBSD-src-76f193cd692e42617fb7f33b9581e7e5a3da58f0.zip
FreeBSD-src-76f193cd692e42617fb7f33b9581e7e5a3da58f0.tar.gz
Introduce a number of changes to the MROUTING code.
This is purely a forwarding plane cleanup; no control plane code is involved. Summary: * Split IPv4 and IPv6 MROUTING support. The static compile-time kernel option remains the same, however, the modules may now be built for IPv4 and IPv6 separately as ip_mroute_mod and ip6_mroute_mod. * Clean up the IPv4 multicast forwarding code to use BSD queue and hash table constructs. Don't build our own timer abstractions when ratecheck() and timevalclear() etc will do. * Expose the multicast forwarding cache (MFC) and virtual interface table (VIF) as sysctls, to reduce netstat's dependence on libkvm for this information for running kernels. * bandwidth meters however still require libkvm. * Make the MFC hash table size a boot/load-time tunable ULONG, net.inet.ip.mfchashsize (defaults to 256). * Remove unused members from struct vif and struct mfc. * Kill RSVP support, as no current RSVP implementation uses it. These stubs could be moved to raw_ip.c. * Don't share locks or initialization between IPv4 and IPv6. * Don't use a static struct route_in6 in ip6_mroute.c. The v6 code is still using a cached struct route_in6, this is moved to mif6 for the time being. * More cleanup remains to be merged from ip_mroute.c to ip6_mroute.c. v4 path tested using ports/net/mcast-tools. v6 changes are mostly mechanical locking and *have not* been tested. As these changes partially break some kernel ABIs, they will not be MFCed. There is a lot more work to be done here. Reviewed by: Pavlin Radoslavov
Diffstat (limited to 'sys/netinet6/ip6_mroute.c')
-rw-r--r--sys/netinet6/ip6_mroute.c396
1 files changed, 267 insertions, 129 deletions
diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
index 18e7aca..29201d6 100644
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -92,6 +92,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
+#include <sys/module.h>
#include <sys/protosw.h>
#include <sys/signalvar.h>
#include <sys/socket.h>
@@ -114,6 +115,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in_var.h>
#include <netinet/icmp6.h>
#include <netinet/vinet.h>
+#include <netinet/ip_encap.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@@ -130,20 +132,18 @@ static MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry");
/* XXX: this is a very common idiom; move to <sys/mbuf.h> ? */
#define M_HASCL(m) ((m)->m_flags & M_EXT)
-static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
-static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
-
-static void pim6_init(void);
-static int set_pim6(int *);
-static int socket_send __P((struct socket *, struct mbuf *,
- struct sockaddr_in6 *));
-static int register_send __P((struct ip6_hdr *, struct mif6 *,
- struct mbuf *));
+static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
+static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
+static void pim6_init(void);
+static int register_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
+static int set_pim6(int *);
+static int socket_send(struct socket *, struct mbuf *,
+ struct sockaddr_in6 *);
extern struct domain inet6domain;
-/* XXX: referenced from ip_mroute.c for dynamically loading this code. */
-struct ip6protosw in6_pim_protosw = {
+static const struct encaptab *pim6_encap_cookie;
+static const struct ip6protosw in6_pim_protosw = {
.pr_type = SOCK_RAW,
.pr_domain = &inet6domain,
.pr_protocol = IPPROTO_PIM,
@@ -154,6 +154,7 @@ struct ip6protosw in6_pim_protosw = {
.pr_init = pim6_init,
.pr_usrreqs = &rip6_usrreqs
};
+static int pim6_encapcheck(const struct mbuf *, int, int, void *);
#ifdef VIMAGE_GLOBALS
static int ip6_mrouter_ver;
@@ -171,18 +172,48 @@ SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW,
#define NO_RTE_FOUND 0x1
#define RTE_FOUND 0x2
+static struct mtx mrouter6_mtx;
+#define MROUTER6_LOCK() mtx_lock(&mrouter6_mtx)
+#define MROUTER6_UNLOCK() mtx_unlock(&mrouter6_mtx)
+#define MROUTER6_LOCK_ASSERT() do { \
+ mtx_assert(&mrouter6_mtx, MA_OWNED); \
+ NET_ASSERT_GIANT(); \
+} while (0)
+#define MROUTER6_LOCK_INIT() \
+ mtx_init(&mrouter6_mtx, "IPv6 multicast forwarding", NULL, MTX_DEF)
+#define MROUTER6_LOCK_DESTROY() mtx_destroy(&mrouter6_mtx)
+
static struct mf6c *mf6ctable[MF6CTBLSIZ];
SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mf6ctable, CTLFLAG_RD,
&mf6ctable, sizeof(mf6ctable), "S,*mf6ctable[MF6CTBLSIZ]",
- "Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], "
+ "IPv6 Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], "
"netinet6/ip6_mroute.h)");
+static struct mtx mfc6_mtx;
+#define MFC6_LOCK() mtx_lock(&mfc6_mtx)
+#define MFC6_UNLOCK() mtx_unlock(&mfc6_mtx)
+#define MFC6_LOCK_ASSERT() do { \
+ mtx_assert(&mfc6_mtx, MA_OWNED); \
+ NET_ASSERT_GIANT(); \
+} while (0)
+#define MFC6_LOCK_INIT() \
+ mtx_init(&mfc6_mtx, "IPv6 multicast forwarding cache", NULL, MTX_DEF)
+#define MFC6_LOCK_DESTROY() mtx_destroy(&mfc6_mtx)
+
static u_char n6expire[MF6CTBLSIZ];
static struct mif6 mif6table[MAXMIFS];
SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mif6table, CTLFLAG_RD,
- &mif6table, sizeof(mif6table), "S,vif[MAXMIFS]",
- "Multicast Interfaces (struct mif[MAXMIFS], netinet6/ip6_mroute.h)");
+ &mif6table, sizeof(mif6table), "S,mif6[MAXMIFS]",
+ "IPv6 Multicast Interfaces (struct mif6[MAXMIFS], netinet6/ip6_mroute.h)");
+
+static struct mtx mif6_mtx;
+#define MIF6_LOCK() mtx_lock(&mif6_mtx)
+#define MIF6_UNLOCK() mtx_unlock(&mif6_mtx)
+#define MIF6_LOCK_ASSERT() mtx_assert(&mif6_mtx, MA_OWNED)
+#define MIF6_LOCK_INIT() \
+ mtx_init(&mif6_mtx, "IPv6 multicast interfaces", NULL, MTX_DEF)
+#define MIF6_LOCK_DESTROY() mtx_destroy(&mif6_mtx)
#ifdef MRT6DEBUG
#ifdef VIMAGE_GLOBALS
@@ -200,11 +231,9 @@ static void expire_upcalls(void *);
#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */
#define UPCALL_EXPIRE 6 /* number of timeouts */
-#ifdef INET
-#ifdef MROUTING
-extern struct socket *ip_mrouter;
-#endif
-#endif
+/*
+ * XXX TODO: maintain a count to if_allmulti() calls in struct ifnet.
+ */
/*
* 'Interfaces' associated with decapsulator (so we can tell
@@ -298,21 +327,22 @@ static u_long upcall_data[UPCALL_MAX + 1];
static void collate();
#endif /* UPCALL_TIMING */
-static int get_sg_cnt(struct sioc_sg_req6 *);
-static int get_mif6_cnt(struct sioc_mif_req6 *);
static int ip6_mrouter_init(struct socket *, int, int);
-static int add_m6if(struct mif6ctl *);
-static int del_m6if(mifi_t *);
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 struct callout expire_upcalls_ch;
-int X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m);
+int X_ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
int X_ip6_mrouter_done(void);
-int X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt);
-int X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt);
-int X_mrt6_ioctl(int cmd, caddr_t data);
+int X_ip6_mrouter_set(struct socket *, struct sockopt *);
+int X_ip6_mrouter_get(struct socket *, struct sockopt *);
+int X_mrt6_ioctl(int, caddr_t);
static void
pim6_init(void)
@@ -419,14 +449,24 @@ X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
int
X_mrt6_ioctl(int cmd, caddr_t data)
{
+ int ret;
+
+ ret = EINVAL;
+
switch (cmd) {
case SIOCGETSGCNT_IN6:
- return (get_sg_cnt((struct sioc_sg_req6 *)data));
+ ret = get_sg_cnt((struct sioc_sg_req6 *)data);
+ break;
+
case SIOCGETMIFCNT_IN6:
- return (get_mif6_cnt((struct sioc_mif_req6 *)data));
+ ret = get_mif6_cnt((struct sioc_mif_req6 *)data);
+ break;
+
default:
- return (EINVAL);
+ break;
}
+
+ return (ret);
}
/*
@@ -436,22 +476,24 @@ static int
get_sg_cnt(struct sioc_sg_req6 *req)
{
struct mf6c *rt;
- int s;
+ int ret;
+
+ ret = 0;
+
+ MFC6_LOCK();
- s = splnet();
MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
- splx(s);
- if (rt != NULL) {
+ if (rt == NULL) {
+ ret = ESRCH;
+ } else {
req->pktcnt = rt->mf6c_pkt_cnt;
req->bytecnt = rt->mf6c_byte_cnt;
req->wrong_if = rt->mf6c_wrong_if;
- } else
- return (ESRCH);
-#if 0
- req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
-#endif
+ }
- return (0);
+ MFC6_UNLOCK();
+
+ return (ret);
}
/*
@@ -460,17 +502,26 @@ get_sg_cnt(struct sioc_sg_req6 *req)
static int
get_mif6_cnt(struct sioc_mif_req6 *req)
{
- mifi_t mifi = req->mifi;
+ mifi_t mifi;
+ int ret;
- if (mifi >= nummifs)
- return (EINVAL);
+ ret = 0;
+ mifi = req->mifi;
- 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;
+ MIF6_LOCK();
- return (0);
+ if (mifi >= 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;
+ }
+
+ MIF6_UNLOCK();
+
+ return (ret);
}
static int
@@ -507,8 +558,12 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
if (v != 1)
return (ENOPROTOOPT);
- if (ip6_mrouter != NULL)
+ MROUTER6_LOCK();
+
+ if (ip6_mrouter != NULL) {
+ MROUTER6_UNLOCK();
return (EADDRINUSE);
+ }
ip6_mrouter = so;
V_ip6_mrouter_ver = cmd;
@@ -522,6 +577,8 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
expire_upcalls, NULL);
+ MROUTER6_UNLOCK();
+
#ifdef MRT6DEBUG
if (V_mrt6debug)
log(LOG_DEBUG, "ip6_mrouter_init\n");
@@ -531,7 +588,7 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
}
/*
- * Disable multicast routing
+ * Disable IPv6 multicast forwarding.
*/
int
X_ip6_mrouter_done(void)
@@ -541,31 +598,22 @@ X_ip6_mrouter_done(void)
int i;
struct mf6c *rt;
struct rtdetq *rte;
- int s;
- s = splnet();
+ MROUTER6_LOCK();
+
+ if (ip6_mrouter == NULL) {
+ MROUTER6_UNLOCK();
+ return (EINVAL);
+ }
/*
* For each phyint in use, disable promiscuous reception of all IPv6
* multicasts.
*/
-#ifdef INET
-#ifdef MROUTING
- /*
- * If there is still IPv4 multicast routing daemon,
- * we remain interfaces to receive all muliticasted packets.
- * XXX: there may be an interface in which the IPv4 multicast
- * daemon is not interested...
- */
- if (!V_ip_mrouter)
-#endif
-#endif
- {
- 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 < nummifs; mifi++) {
+ if (mif6table[mifi].m6_ifp &&
+ !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
+ if_allmulti(mif6table[mifi].m6_ifp, 0);
}
}
bzero((caddr_t)mif6table, sizeof(mif6table));
@@ -578,6 +626,7 @@ X_ip6_mrouter_done(void)
/*
* Free all multicast forwarding cache entries.
*/
+ MFC6_LOCK();
for (i = 0; i < MF6CTBLSIZ; i++) {
rt = mf6ctable[i];
while (rt) {
@@ -595,8 +644,8 @@ X_ip6_mrouter_done(void)
free(frt, M_MRTABLE6);
}
}
-
bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
+ MFC6_UNLOCK();
/*
* Reset register interface
@@ -611,7 +660,7 @@ X_ip6_mrouter_done(void)
ip6_mrouter = NULL;
V_ip6_mrouter_ver = 0;
- splx(s);
+ MROUTER6_UNLOCK();
#ifdef MRT6DEBUG
if (V_mrt6debug)
@@ -632,15 +681,24 @@ add_m6if(struct mif6ctl *mifcp)
INIT_VNET_NET(curvnet);
struct mif6 *mifp;
struct ifnet *ifp;
- int error, s;
+ int error;
- if (mifcp->mif6c_mifi >= MAXMIFS)
+ MIF6_LOCK();
+
+ if (mifcp->mif6c_mifi >= MAXMIFS) {
+ MIF6_UNLOCK();
return (EINVAL);
+ }
mifp = mif6table + mifcp->mif6c_mifi;
- if (mifp->m6_ifp)
+ if (mifp->m6_ifp != NULL) {
+ MIF6_UNLOCK();
return (EADDRINUSE); /* XXX: is it appropriate? */
- if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index)
+ }
+ if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index) {
+ MIF6_UNLOCK();
return (ENXIO);
+ }
+
ifp = ifnet_byindex(mifcp->mif6c_pifi);
if (mifcp->mif6c_flags & MIFF_REGISTER) {
@@ -661,21 +719,20 @@ add_m6if(struct mif6ctl *mifcp)
} else {
ifp = multicast_register_if6;
}
-
- } /* if REGISTER */
- else {
+ } else {
/* Make sure the interface supports multicast */
- if ((ifp->if_flags & IFF_MULTICAST) == 0)
+ if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+ MIF6_UNLOCK();
return (EOPNOTSUPP);
+ }
- s = splnet();
error = if_allmulti(ifp, 1);
- splx(s);
- if (error)
+ if (error) {
+ MIF6_UNLOCK();
return (error);
+ }
}
- s = splnet();
mifp->m6_flags = mifcp->mif6c_flags;
mifp->m6_ifp = ifp;
@@ -684,12 +741,14 @@ add_m6if(struct mif6ctl *mifcp)
mifp->m6_pkt_out = 0;
mifp->m6_bytes_in = 0;
mifp->m6_bytes_out = 0;
- splx(s);
+ bzero(&mifp->m6_route, sizeof(mifp->m6_route));
/* Adjust nummifs up if the mifi is higher than nummifs */
if (nummifs <= mifcp->mif6c_mifi)
nummifs = mifcp->mif6c_mifi + 1;
+ MIF6_UNLOCK();
+
#ifdef MRT6DEBUG
if (V_mrt6debug)
log(LOG_DEBUG,
@@ -705,27 +764,22 @@ add_m6if(struct mif6ctl *mifcp)
* Delete a mif from the mif table
*/
static int
-del_m6if(mifi_t *mifip)
+del_m6if_locked(mifi_t *mifip)
{
struct mif6 *mifp = mif6table + *mifip;
mifi_t mifi;
struct ifnet *ifp;
- int s;
+
+ MIF6_LOCK_ASSERT();
if (*mifip >= nummifs)
return (EINVAL);
if (mifp->m6_ifp == NULL)
return (EINVAL);
- s = splnet();
-
if (!(mifp->m6_flags & MIFF_REGISTER)) {
- /*
- * XXX: what if there is yet IPv4 multicast daemon
- * using the interface?
- */
+ /* XXX: TODO: Maintain an ALLMULTI refcount in struct ifnet. */
ifp = mifp->m6_ifp;
-
if_allmulti(ifp, 0);
} else {
if (reg_mif_num != (mifi_t)-1 &&
@@ -745,8 +799,6 @@ del_m6if(mifi_t *mifip)
break;
nummifs = mifi;
- splx(s);
-
#ifdef MRT6DEBUG
if (V_mrt6debug)
log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs);
@@ -755,6 +807,18 @@ del_m6if(mifi_t *mifip)
return (0);
}
+static int
+del_m6if(mifi_t *mifip)
+{
+ int cc;
+
+ MIF6_LOCK();
+ cc = del_m6if_locked(mifip);
+ MIF6_UNLOCK();
+
+ return (cc);
+}
+
/*
* Add an mfc entry
*/
@@ -765,9 +829,10 @@ add_m6fc(struct mf6cctl *mfccp)
u_long hash;
struct rtdetq *rte;
u_short nstl;
- int s;
char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
+ MFC6_LOCK();
+
MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
mfccp->mf6cc_mcastgrp.sin6_addr, rt);
@@ -783,17 +848,16 @@ add_m6fc(struct mf6cctl *mfccp)
}
#endif
- s = splnet();
rt->mf6c_parent = mfccp->mf6cc_parent;
rt->mf6c_ifset = mfccp->mf6cc_ifset;
- splx(s);
+
+ MFC6_UNLOCK();
return (0);
}
/*
* Find the entry for which the upcall was made and update
*/
- s = splnet();
hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
mfccp->mf6cc_mcastgrp.sin6_addr);
for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
@@ -891,7 +955,7 @@ add_m6fc(struct mf6cctl *mfccp)
rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6,
M_NOWAIT);
if (rt == NULL) {
- splx(s);
+ MFC6_UNLOCK();
return (ENOBUFS);
}
@@ -912,7 +976,8 @@ add_m6fc(struct mf6cctl *mfccp)
mf6ctable[hash] = rt;
}
}
- splx(s);
+
+ MFC6_UNLOCK();
return (0);
}
@@ -953,7 +1018,6 @@ del_m6fc(struct mf6cctl *mfccp)
struct mf6c *rt;
struct mf6c **nptr;
u_long hash;
- int s;
origin = mfccp->mf6cc_origin;
mcastgrp = mfccp->mf6cc_mcastgrp;
@@ -968,7 +1032,7 @@ del_m6fc(struct mf6cctl *mfccp)
}
#endif
- s = splnet();
+ MFC6_LOCK();
nptr = &mf6ctable[hash];
while ((rt = *nptr) != NULL) {
@@ -982,14 +1046,14 @@ del_m6fc(struct mf6cctl *mfccp)
nptr = &rt->mf6c_next;
}
if (rt == NULL) {
- splx(s);
+ MFC6_UNLOCK();
return (EADDRNOTAVAIL);
}
*nptr = rt->mf6c_next;
free(rt, M_MRTABLE6);
- splx(s);
+ MFC6_UNLOCK();
return (0);
}
@@ -1035,7 +1099,6 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
struct mf6c *rt;
struct mif6 *mifp;
struct mbuf *mm;
- int s;
mifi_t mifi;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
@@ -1078,15 +1141,16 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
return (0);
}
+ MFC6_LOCK();
+
/*
* Determine forwarding mifs from the forwarding cache table
*/
- s = splnet();
MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
/* Entry exists, so forward if necessary */
if (rt) {
- splx(s);
+ MFC6_UNLOCK();
return (ip6_mdq(m, ifp, rt));
} else {
/*
@@ -1120,7 +1184,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE6,
M_NOWAIT);
if (rte == NULL) {
- splx(s);
+ MFC6_UNLOCK();
return (ENOBUFS);
}
mb0 = m_copy(m, 0, M_COPYALL);
@@ -1133,7 +1197,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
if (mb0 == NULL) {
free(rte, M_MRTABLE6);
- splx(s);
+ MFC6_UNLOCK();
return (ENOBUFS);
}
@@ -1160,7 +1224,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
if (rt == NULL) {
free(rte, M_MRTABLE6);
m_freem(mb0);
- splx(s);
+ MFC6_UNLOCK();
return (ENOBUFS);
}
/*
@@ -1173,7 +1237,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
free(rte, M_MRTABLE6);
m_freem(mb0);
free(rt, M_MRTABLE6);
- splx(s);
+ MFC6_UNLOCK();
return (ENOBUFS);
}
@@ -1203,7 +1267,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
free(rte, M_MRTABLE6);
m_freem(mb0);
free(rt, M_MRTABLE6);
- splx(s);
+ MFC6_UNLOCK();
return (EINVAL);
}
@@ -1236,7 +1300,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
free(rte, M_MRTABLE6);
m_freem(mb0);
free(rt, M_MRTABLE6);
- splx(s);
+ MFC6_UNLOCK();
return (ENOBUFS);
}
@@ -1269,7 +1333,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
mrt6stat.mrt6s_upq_ovflw++;
free(rte, M_MRTABLE6);
m_freem(mb0);
- splx(s);
+ MFC6_UNLOCK();
return (0);
}
@@ -1284,7 +1348,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
rte->t = tp;
#endif /* UPCALL_TIMING */
- splx(s);
+ MFC6_UNLOCK();
return (0);
}
@@ -1300,9 +1364,8 @@ expire_upcalls(void *unused)
struct rtdetq *rte;
struct mf6c *mfc, **nptr;
int i;
- int s;
- s = splnet();
+ MFC6_LOCK();
for (i = 0; i < MF6CTBLSIZ; i++) {
if (n6expire[i] == 0)
continue;
@@ -1346,7 +1409,7 @@ expire_upcalls(void *unused)
}
}
}
- splx(s);
+ MFC6_UNLOCK();
callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
expire_upcalls, NULL);
}
@@ -1540,8 +1603,6 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
struct mbuf *mb_copy;
struct ifnet *ifp = mifp->m6_ifp;
int error = 0;
- int s = splnet(); /* needs to protect static "ro" below. */
- static struct route_in6 ro;
struct in6_multi *in6m;
struct sockaddr_in6 *dst6;
u_long linkmtu;
@@ -1556,7 +1617,6 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
(M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
if (mb_copy == NULL) {
- splx(s);
return;
}
/* set MCAST flag to the outgoing packet */
@@ -1576,7 +1636,7 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
/* XXX: ip6_output will override ip6->ip6_hlim */
im6o.im6o_multicast_hlim = ip6->ip6_hlim;
im6o.im6o_multicast_loop = 1;
- error = ip6_output(mb_copy, NULL, &ro,
+ error = ip6_output(mb_copy, NULL, &mifp->m6_route,
IPV6_FORWARDING, &im6o, NULL, NULL);
#ifdef MRT6DEBUG
@@ -1584,7 +1644,6 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
mifp - mif6table, error);
#endif
- splx(s);
return;
}
@@ -1592,13 +1651,13 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
* If we belong to the destination multicast group
* on the outgoing interface, loop back a copy.
*/
- dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
+ dst6 = &mifp->m6_route.ro_dst;
IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
if (in6m != NULL) {
dst6->sin6_len = sizeof(struct sockaddr_in6);
dst6->sin6_family = AF_INET6;
dst6->sin6_addr = ip6->ip6_dst;
- ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst);
+ ip6_mloopback(ifp, m, &mifp->m6_route.ro_dst);
}
/*
* Put the packet into the sending queue of the outgoing interface
@@ -1614,7 +1673,7 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
* we need no ND for a multicast forwarded packet...right?
*/
error = (*ifp->if_output)(ifp, mb_copy,
- (struct sockaddr *)&ro.ro_dst, NULL);
+ (struct sockaddr *)&mifp->m6_route.ro_dst, NULL);
#ifdef MRT6DEBUG
if (V_mrt6debug & DEBUG_XMIT)
log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
@@ -1645,8 +1704,6 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
m_freem(mb_copy); /* simply discard the packet */
}
}
-
- splx(s);
}
static int
@@ -1715,6 +1772,24 @@ register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
}
/*
+ * pim6_encapcheck() is called by the encap6_input() path at runtime to
+ * determine if a packet is for PIM; allowing PIM to be dynamically loaded
+ * into the kernel.
+ */
+static int
+pim6_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
+{
+
+#ifdef DIAGNOSTIC
+ KASSERT(proto == IPPROTO_PIM, ("not for IPPROTO_PIM"));
+#endif
+ if (proto != IPPROTO_PIM)
+ return 0; /* not for us; reject the datagram. */
+
+ return 64; /* claim the datagram. */
+}
+
+/*
* PIM sparse mode hook
* Receives the pim control messages, and passes them up to the listening
* socket, using rip6_input.
@@ -1951,3 +2026,66 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
rip6_input(&m, offp, proto);
return (IPPROTO_DONE);
}
+
+static int
+ip6_mroute_modevent(module_t mod, int type, void *unused)
+{
+
+ switch (type) {
+ case MOD_LOAD:
+ MROUTER6_LOCK_INIT();
+ MFC6_LOCK_INIT();
+ MIF6_LOCK_INIT();
+
+ pim6_encap_cookie = encap_attach_func(AF_INET6, IPPROTO_PIM,
+ pim6_encapcheck,
+ (const struct protosw *)&in6_pim_protosw, NULL);
+ if (pim6_encap_cookie == NULL) {
+ printf("ip6_mroute: unable to attach pim6 encap\n");
+ MIF6_LOCK_DESTROY();
+ MFC6_LOCK_DESTROY();
+ MROUTER6_LOCK_DESTROY();
+ return (EINVAL);
+ }
+
+ ip6_mforward = X_ip6_mforward;
+ ip6_mrouter_done = X_ip6_mrouter_done;
+ ip6_mrouter_get = X_ip6_mrouter_get;
+ ip6_mrouter_set = X_ip6_mrouter_set;
+ mrt6_ioctl = X_mrt6_ioctl;
+ break;
+
+ case MOD_UNLOAD:
+ if (ip6_mrouter != NULL)
+ return EINVAL;
+
+ if (pim6_encap_cookie) {
+ encap_detach(pim6_encap_cookie);
+ pim6_encap_cookie = NULL;
+ }
+ X_ip6_mrouter_done();
+ ip6_mforward = NULL;
+ ip6_mrouter_done = NULL;
+ ip6_mrouter_get = NULL;
+ ip6_mrouter_set = NULL;
+ mrt6_ioctl = NULL;
+
+ MIF6_LOCK_DESTROY();
+ MFC6_LOCK_DESTROY();
+ MROUTER6_LOCK_DESTROY();
+ break;
+
+ default:
+ return (EOPNOTSUPP);
+ }
+
+ return (0);
+}
+
+static moduledata_t ip6_mroutemod = {
+ "ip6_mroute",
+ ip6_mroute_modevent,
+ 0
+};
+
+DECLARE_MODULE(ip6_mroute, ip6_mroutemod, SI_SUB_PSEUDO, SI_ORDER_ANY);
OpenPOWER on IntegriCloud