89#include <sys/callout.h>
91#include <sys/kernel.h>
93#include <sys/malloc.h>
95#include <sys/module.h>
96#include <sys/domain.h>
97#include <sys/protosw.h>
99#include <sys/signalvar.h>
100#include <sys/socket.h>
101#include <sys/socketvar.h>
102#include <sys/sockio.h>
104#include <sys/sysctl.h>
105#include <sys/syslog.h>
106#include <sys/systm.h>
110#include <net/if_var.h>
111#include <net/if_types.h>
114#include <netinet/in.h>
115#include <netinet/in_var.h>
116#include <netinet/icmp6.h>
117#include <netinet/ip_encap.h>
119#include <netinet/ip6.h>
120#include <netinet/in_kdtrace.h>
128static MALLOC_DEFINE(M_MRTABLE6,
"mf6c",
"multicast forwarding cache entry");
130static int ip6_mdq(
struct mbuf *,
struct ifnet *,
struct mf6c *);
131static void phyint_send(
struct ip6_hdr *,
struct mif6 *,
struct mbuf *);
134static int socket_send(
struct socket *,
struct mbuf *,
145 .proto = IPPROTO_PIM,
146 .min_length =
sizeof(
struct ip6_hdr) +
PIM_MINLEN,
153#define V_ip6_mrouter_ver VNET(ip6_mrouter_ver)
158 CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
164 "Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)");
166#define MRT6STAT_INC(name) mrt6stat.name += 1
167#define NO_RTE_FOUND 0x1
171#define MROUTER6_LOCKPTR() (&mrouter6_mtx)
172#define MROUTER6_LOCK() sx_xlock(MROUTER6_LOCKPTR())
173#define MROUTER6_UNLOCK() sx_xunlock(MROUTER6_LOCKPTR())
174#define MROUTER6_LOCK_ASSERT() sx_assert(MROUTER6_LOCKPTR(), SA_XLOCKED
175#define MROUTER6_LOCK_INIT() sx_init(MROUTER6_LOCKPTR(), "mrouter6")
176#define MROUTER6_LOCK_DESTROY() sx_destroy(MROUTER6_LOCKPTR())
181 "IPv6 Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], "
182 "netinet6/ip6_mroute.h)");
185#define MFC6_LOCKPTR() (&mfc6_mtx)
186#define MFC6_LOCK() mtx_lock(MFC6_LOCKPTR())
187#define MFC6_UNLOCK() mtx_unlock(MFC6_LOCKPTR())
188#define MFC6_LOCK_ASSERT() mtx_assert(MFC6_LOCKPTR(), MA_OWNED)
189#define MFC6_LOCK_INIT() mtx_init(MFC6_LOCKPTR(), \
190 "IPv6 multicast forwarding cache", \
192#define MFC6_LOCK_DESTROY() mtx_destroy(MFC6_LOCKPTR())
205 for (
int i = 0; i <
MAXMIFS; i++) {
223 CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
225 "IPv6 Multicast Interfaces (struct mif6_sctl[MAXMIFS], "
226 "netinet6/ip6_mroute.h)");
229#define MIF6_LOCKPTR() (&mif6_mtx)
230#define MIF6_LOCK() mtx_lock(MIF6_LOCKPTR())
231#define MIF6_UNLOCK() mtx_unlock(MIF6_LOCKPTR())
232#define MIF6_LOCK_ASSERT() mtx_assert(MIF6_LOCKPTR(), MA_OWNED)
233#define MIF6_LOCK_INIT() \
234 mtx_init(MIF6_LOCKPTR(), "IPv6 multicast interfaces", NULL, MTX_DEF)
235#define MIF6_LOCK_DESTROY() mtx_destroy(MIF6_LOCKPTR())
239#define V_mrt6debug VNET(mrt6debug)
240#define DEBUG_MFC 0x02
241#define DEBUG_FORWARD 0x04
242#define DEBUG_EXPIRE 0x08
243#define DEBUG_XMIT 0x10
244#define DEBUG_REG 0x20
245#define DEBUG_PIM 0x40
246#define DEBUG_ERR 0x80
247#define DEBUG_ANY 0x7f
248#define MRT6_DLOG(m, fmt, ...) \
249 if (V_mrt6debug & (m)) \
250 log(((m) & DEBUG_ERR) ? LOG_ERR: LOG_DEBUG, \
251 "%s: " fmt "\n", __func__, ##__VA_ARGS__)
253#define MRT6_DLOG(m, fmt, ...)
257#define EXPIRE_TIMEOUT (hz / 4)
258#define UPCALL_EXPIRE 6
288 "PIM Statistics (struct pim6stat, netinet6/pim6_var.h)");
290#define PIM6STAT_INC(name) pim6stat.name += 1
292#define V_pim6 VNET(pim6)
297#define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
298 (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
299 (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \
300 (g).s6_addr32[2] ^ (g).s6_addr32[3])
305#define MF6CFIND(o, g, rt) do { \
306 struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
309 if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \
310 IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \
311 (_rt->mf6c_stall == NULL)) { \
315 _rt = _rt->mf6c_next; \
318 MRT6STAT_INC(mrt6s_mfc_misses); \
327#define TV_DELTA(a, b, delta) do { \
330 delta = (a).tv_usec - (b).tv_usec; \
331 if ((xxs = (a).tv_sec - (b).tv_sec)) { \
340 delta += (1000000 * xxs); \
346#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
347 (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
351static u_long upcall_data[UPCALL_MAX + 1];
352static void collate();
366int X_ip6_mforward(
struct ip6_hdr *,
struct ifnet *,
struct mbuf *);
387 switch (sopt->sopt_name) {
392 error = sooptcopyin(sopt, &optval,
sizeof(optval),
402 error = sooptcopyin(sopt, &mifc,
sizeof(mifc),
sizeof(mifc));
408 error = sooptcopyin(sopt, &mfcc,
sizeof(mfcc),
sizeof(mfcc));
414 error = sooptcopyin(sopt, &mfcc,
sizeof(mfcc),
sizeof(mfcc));
420 error = sooptcopyin(sopt, &mifi,
sizeof(mifi),
sizeof(mifi));
426 error = sooptcopyin(sopt, &optval,
sizeof(optval),
451 switch (sopt->sopt_name) {
543 if ((*i != 1) && (*i != 0))
558 MRT6_DLOG(DEBUG_ANY,
"so_type = %d, pr_protocol = %d",
559 so->so_type, so->so_proto->pr_protocol);
561 if (so->so_type != SOCK_RAW ||
562 so->so_proto->pr_protocol != IPPROTO_ICMPV6)
566 return (ENOPROTOOPT);
616 for (mifi = 0; mifi <
nummifs; mifi++) {
640 free(rte, M_MRTABLE6);
645 free(frt, M_MRTABLE6);
680 struct epoch_tracker et;
692 if (mifp->
m6_ifp != NULL) {
698 if ((ifp = ifnet_byindex(mifcp->
mif6c_pifi)) == NULL) {
707 ifp = if_alloc(IFT_OTHER);
709 if_initname(ifp,
"register_mif", 0);
710 ifp->if_flags |= IFF_LOOPBACK;
725 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
730 error = if_allmulti(ifp, 1);
747 if (nummifs <= mifcp->mif6c_mifi)
788 bzero((caddr_t)mifp,
sizeof(*mifp));
791 for (mifi =
nummifs; mifi > 0; mifi--)
831 MRT6_DLOG(DEBUG_MFC,
"no upcall o %s g %s p %x",
856 "add_m6fc: %s o %s g %s p %x dbx %p\n",
857 "multiple kernel entries",
864 MRT6_DLOG(DEBUG_MFC,
"o %s g %s p %x dbg %p",
891 free(rte, M_MRTABLE6);
902 MRT6_DLOG(DEBUG_MFC,
"no upcall h %lu o %s g %s p %x", hash,
928 rt = (
struct mf6c *)malloc(
sizeof(*rt), M_MRTABLE6,
962collate(
struct timeval *t)
1002 MRT6_DLOG(DEBUG_MFC,
"orig %s mcastgrp %s",
1009 while ((rt = *nptr) != NULL) {
1021 return (EADDRNOTAVAIL);
1025 free(rt, M_MRTABLE6);
1037 if (sbappendaddr(&s->so_rcv,
1038 (
struct sockaddr *)src,
1039 mm, (
struct mbuf *)0) != 0) {
1084 MRT6_DLOG(DEBUG_FORWARD,
"src %s, dst %s, ifindex %d",
1086 ip6_sprintf(ip6bufd, &ip6->ip6_dst), ifp->if_index);
1110 "from %s to %s nxt %d received on %s\n",
1114 if_name(m->m_pkthdr.rcvif));
1124 MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
1138 MRT6_DLOG(DEBUG_FORWARD | DEBUG_MFC,
"no rte s %s g %s",
1146 rte = (
struct rtdetq *)malloc(
sizeof(*rte), M_MRTABLE6, M_NOWAIT);
1151 mb0 = m_copym(
m, 0, M_COPYALL, M_NOWAIT);
1156 if (mb0 && (!M_WRITABLE(mb0) || mb0->m_len <
sizeof(
struct ip6_hdr)))
1157 mb0 = m_pullup(mb0,
sizeof(
struct ip6_hdr));
1159 free(rte, M_MRTABLE6);
1165 hash =
MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
1180 rt = (
struct mf6c *)malloc(
sizeof(*rt), M_MRTABLE6, M_NOWAIT);
1182 free(rte, M_MRTABLE6);
1191 mm = m_copym(mb0, 0,
sizeof(
struct ip6_hdr), M_NOWAIT);
1193 free(rte, M_MRTABLE6);
1195 free(rt, M_MRTABLE6);
1217 im = mtod(mm,
struct mrt6msg *);
1222 free(rte, M_MRTABLE6);
1224 free(rt, M_MRTABLE6);
1229 MRT6_DLOG(DEBUG_FORWARD,
"getting the iif info in the kernel");
1246 log(LOG_WARNING,
"ip6_mforward: ip6_mrouter "
1247 "socket queue full\n");
1249 free(rte, M_MRTABLE6);
1251 free(rt, M_MRTABLE6);
1259 bzero(rt,
sizeof(*rt));
1283 free(rte, M_MRTABLE6);
1316 struct mf6c *mfc, **nptr;
1325 while ((mfc = *nptr) != NULL) {
1335 MRT6_DLOG(DEBUG_EXPIRE,
"expiring (%s %s)",
1345 free(rte, M_MRTABLE6);
1347 }
while (rte != NULL);
1352 free(mfc, M_MRTABLE6);
1368 struct ip6_hdr *ip6 = mtod(m,
struct ip6_hdr *);
1371 int plen = m->m_pkthdr.len;
1373 u_int32_t iszone, idzone, oszone, odzone;
1384 "wrong if: ifid %d mifi %d mififid %x", ifp->if_index,
1402 {
sizeof(
sin6), AF_INET6 };
1410 mm = m_copym(m, 0,
sizeof(
struct ip6_hdr),
1414 mm->m_len <
sizeof(
struct ip6_hdr)))
1415 mm = m_pullup(mm,
sizeof(
struct ip6_hdr));
1432 im = mtod(mm,
struct mrt6msg *);
1464 "ip6_mrouter socket queue full");
1473 if (m->m_pkthdr.rcvif == NULL) {
1488 src0 = ip6->ip6_src;
1489 dst0 = ip6->ip6_dst;
1490 if ((error =
in6_setscope(&src0, ifp, &iszone)) != 0 ||
1534 struct mbuf *mb_copy;
1535 struct ifnet *ifp = mifp->
m6_ifp;
1544 mb_copy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
1546 (!M_WRITABLE(mb_copy) || mb_copy->m_len <
sizeof(
struct ip6_hdr)))
1547 mb_copy = m_pullup(mb_copy,
sizeof(
struct ip6_hdr));
1548 if (mb_copy == NULL) {
1552 mb_copy->m_flags |= M_MCAST;
1561 if (m->m_pkthdr.rcvif == NULL) {
1562 struct ip6_moptions im6o;
1563 struct epoch_tracker et;
1565 im6o.im6o_multicast_ifp = ifp;
1567 im6o.im6o_multicast_hlim = ip6->ip6_hlim;
1568 im6o.im6o_multicast_loop = 1;
1569 NET_EPOCH_ENTER(et);
1591 if (mb_copy->m_pkthdr.len <= linkmtu || linkmtu < IPV6_MMTU) {
1594 bzero(&dst6,
sizeof(dst6));
1599 IP_PROBE(send, NULL, NULL, ip6, ifp, NULL, ip6);
1605 error = (*ifp->if_output)(ifp, mb_copy,
1606 (
struct sockaddr *)&dst6, NULL);
1616 icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, linkmtu);
1618 MRT6_DLOG(DEBUG_XMIT,
" packet too big on %s o %s "
1619 "g %s size %d (discarded)", if_name(ifp),
1622 mb_copy->m_pkthdr.len);
1635 int i, len = m->m_pkthdr.len;
1645 mm = m_gethdr(M_NOWAIT, MT_DATA);
1648 mm->m_data += max_linkhdr;
1649 mm->m_len =
sizeof(
struct ip6_hdr);
1651 if ((mm->m_next = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
1655 i = MHLEN - M_LEADINGSPACE(mm);
1658 mm = m_pullup(mm, i);
1662 mm->m_pkthdr.len = len +
sizeof(
struct ip6_hdr);
1669 im6 = mtod(mm,
struct mrt6msg *);
1679 MRT6_DLOG(DEBUG_ANY,
"ip6_mrouter socket queue full");
1693 int proto __unused,
void *arg __unused)
1696 KASSERT(proto == IPPROTO_PIM, (
"not for IPPROTO_PIM"));
1708pim6_input(
struct mbuf *m,
int off,
int proto,
void *arg __unused)
1711 struct ip6_hdr *ip6;
1720 pimlen = m->m_pkthdr.len - off;
1723 MRT6_DLOG(DEBUG_PIM,
"PIM packet too short");
1725 return (IPPROTO_DONE);
1742 if (m->m_len < off + minlen) {
1743 m = m_pullup(m, off + minlen);
1746 return (IPPROTO_DONE);
1749 ip6 = mtod(m,
struct ip6_hdr *);
1750 pim = (
struct pim *)((caddr_t)ip6 + off);
1752#define PIM6_CHECKSUM
1766 if (
in6_cksum(m, IPPROTO_PIM, off, cksumlen)) {
1768 MRT6_DLOG(DEBUG_PIM,
"invalid checksum");
1770 return (IPPROTO_DONE);
1779 "incorrect version %d, expecting %d",
1782 return (IPPROTO_DONE);
1791 static struct sockaddr_in6 dst = {
sizeof(dst), AF_INET6 };
1794 struct ip6_hdr *eip6;
1804 MRT6_DLOG(DEBUG_PIM,
"register mif not set: %d",
1807 return (IPPROTO_DONE);
1810 reghdr = (u_int32_t *)(
pim + 1);
1813 goto pim6_input_to_daemon;
1821 MRT6_DLOG(DEBUG_ANY | DEBUG_ERR,
"register packet "
1822 "size too small %d from %s",
1825 return (IPPROTO_DONE);
1828 eip6 = (
struct ip6_hdr *) (reghdr + 1);
1829 MRT6_DLOG(DEBUG_PIM,
"eip6: %s -> %s, eip6 plen %d",
1832 ntohs(eip6->ip6_plen));
1835 if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
1837 MRT6_DLOG(DEBUG_ANY,
"invalid IP version (%d) "
1838 "of the inner packet",
1839 (eip6->ip6_vfc & IPV6_VERSION));
1841 return (IPPROTO_DONE);
1847 MRT6_DLOG(DEBUG_PIM,
"inner packet of register "
1848 "is not multicast %s",
1851 return (IPPROTO_DONE);
1859 MRT6_DLOG(DEBUG_ANY | DEBUG_ERR,
"pim register: "
1860 "could not copy register head");
1862 return (IPPROTO_DONE);
1869 MRT6_DLOG(DEBUG_PIM,
"forwarding decapsulated register: "
1870 "src %s, dst %s, mif %d",
1887 pim6_input_to_daemon:
1904 printf(
"ip6_mroute: unable to attach pim6 encap\n");
1939 return (EOPNOTSUPP);
void icmp6_error(struct mbuf *m, int type, int code, int param)
char * ip6_sprintf(char *ip6buf, const struct in6_addr *addr)
#define IN6_IS_ADDR_MC_LINKLOCAL(a)
#define IN6_IS_ADDR_UNSPECIFIED(a)
#define IN6_ARE_ADDR_EQUAL(a, b)
int in6_cksum(struct mbuf *, u_int8_t, u_int32_t, u_int32_t)
#define IN6_IS_ADDR_MULTICAST(a)
#define IN6_IS_ADDR_MC_INTFACELOCAL(a)
#define SIOCGETMIFCNT_IN6
int X_ip6_mrouter_set(struct socket *, struct sockopt *)
#define PIM6STAT_INC(name)
static struct sockaddr_in6 sin6
static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *)
#define MIF6_LOCK_DESTROY()
static struct ifnet * multicast_register_if6
#define V_ip6_mrouter_ver
static struct callout expire_upcalls_ch
static void expire_upcalls(void *)
#define TV_DELTA(a, b, delta)
#define MF6CFIND(o, g, rt)
static const struct encaptab * pim6_encap_cookie
#define MIF6_LOCK_ASSERT()
static int register_send(struct ip6_hdr *, struct mif6 *, struct mbuf *)
static struct sx mrouter6_mtx
#define MRT6STAT_INC(name)
static int set_pim6(int *)
static struct mtx mif6_mtx
DECLARE_MODULE(ip6_mroute, ip6_mroutemod, SI_SUB_PROTO_MC, SI_ORDER_ANY)
#define MROUTER6_LOCK_DESTROY()
int X_ip6_mrouter_get(struct socket *, struct sockopt *)
static int pim6_input(struct mbuf *, int, int, void *)
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 int pim6_encapcheck(const struct mbuf *, int, int, void *)
static u_char n6expire[MF6CTBLSIZ]
static mifi_t reg_mif_num
static int get_mif6_cnt(struct sioc_mif_req6 *)
static struct mtx mfc6_mtx
static int sysctl_mif6table(SYSCTL_HANDLER_ARGS)
static MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry")
static SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "PIM")
static int ip6_mroute_modevent(module_t mod, int type, void *unused)
static const struct encap_config ipv6_encap_cfg
static int del_m6fc(struct mf6cctl *)
static int add_m6fc(struct mf6cctl *)
int X_ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *)
static moduledata_t ip6_mroutemod
#define MROUTER6_LOCK_INIT()
#define MROUTER6_UNLOCK()
#define MRT6_DLOG(m, fmt,...)
static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *)
struct domain inet6domain
SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, mif6table, CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_NEEDGIANT, NULL, 0, sysctl_mif6table, "S,mif6_sctl[MAXMIFS]", "IPv6 Multicast Interfaces (struct mif6_sctl[MAXMIFS], " "netinet6/ip6_mroute.h)")
int X_mrt6_ioctl(u_long, caddr_t)
static int socket_send(struct socket *, struct mbuf *, struct sockaddr_in6 *)
SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW, &mrt6stat, mrt6stat, "Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)")
static int get_sg_cnt(struct sioc_sg_req6 *)
#define MFC6_LOCK_DESTROY()
static struct mf6c * mf6ctable[MF6CTBLSIZ]
static int add_m6if(struct mif6ctl *)
#define MFC6_LOCK_ASSERT()
static int del_m6if(mifi_t *)
int X_ip6_mrouter_done(void)
static int ip6_mrouter_init(struct socket *, int, int)
VNET_DEFINE_STATIC(int, ip6_mrouter_ver)=0
static struct mif6 mif6table[MAXMIFS]
static int del_m6if_locked(mifi_t *)
int(* mrt6_ioctl)(u_long, caddr_t)
#define MF6C_INCOMPLETE_PARENT
int(* ip6_mrouter_set)(struct socket *so, struct sockopt *sopt)
int(* ip6_mrouter_done)(void)
int(* ip6_mrouter_get)(struct socket *so, struct sockopt *sopt)
void ip6_mloopback(struct ifnet *ifp, struct mbuf *m)
int ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro, int flags, struct ip6_moptions *im6o, struct ifnet **ifpp, struct inpcb *inp)
#define IP6STAT_INC(name)
int rip6_input(struct mbuf **, int *, int)
#define V_ip6_log_interval
int(* ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *)
#define PIM_NULL_REGISTER
int in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
struct sockaddr_in6 mf6c_mcastgrp
struct rtdetq * mf6c_stall
struct sockaddr_in6 mf6c_origin
struct sockaddr_in6 mf6cc_origin
struct if_set mf6cc_ifset
struct sockaddr_in6 mf6cc_mcastgrp
struct in6_addr m6_lcl_addr
struct in6_addr m6_lcl_addr
struct in6_addr sin6_addr