From 76f193cd692e42617fb7f33b9581e7e5a3da58f0 Mon Sep 17 00:00:00 2001 From: bms Date: Thu, 19 Mar 2009 01:43:03 +0000 Subject: 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 --- sys/netinet6/ip6_mroute.c | 396 +++++++++++++++++++++++++++++++--------------- 1 file changed, 267 insertions(+), 129 deletions(-) (limited to 'sys/netinet6/ip6_mroute.c') 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 #include #include +#include #include #include #include @@ -114,6 +115,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -130,20 +132,18 @@ static MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry"); /* XXX: this is a very common idiom; move to ? */ #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); -- cgit v1.1