From 0948f0a28f3c7aa4d676cec9cdf62562202cc473 Mon Sep 17 00:00:00 2001 From: Bruce M Simpson Date: Sat, 10 Feb 2007 13:59:13 +0000 Subject: [PATCH] Build PIM by default as part of the IPv4 multicast forwarding path. Make PIM dynamically loadable by using encap_attach_func(). PIM may now be loaded into a GENERIC kernel. Tested with: ports/net/pimdd && tcpreplay && wireshark Reviewed by: Pavlin Radoslavov --- UPDATING | 7 ++++ sys/conf/NOTES | 6 +-- sys/conf/options | 1 - sys/netinet/in_proto.c | 10 +---- sys/netinet/ip_mroute.c | 83 ++++++++++++++++++++++++++--------------- 5 files changed, 62 insertions(+), 45 deletions(-) diff --git a/UPDATING b/UPDATING index 4541bc915d93..ad9dec08faa2 100644 --- a/UPDATING +++ b/UPDATING @@ -21,6 +21,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 7.x IS SLOW: developers choose to disable these features on build machines to maximize performance. +20070210: + PIM has been turned on by default in the IPv4 multicast + routing code. The kernel option 'PIM' has now been removed. + PIM is now built by default if option 'MROUTING' is specified. + It may now be loaded into GENERIC kernels by loading the + ip_mroute.ko module. + 20070207: Support for IPIP tunnels (VIFF_TUNNEL) in IPv4 multicast routing has been removed. Its functionality may be achieved by explicitly diff --git a/sys/conf/NOTES b/sys/conf/NOTES index eee9c1195ddd..3174ad472515 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -807,10 +807,7 @@ device stf #6to4 IPv6 over IPv4 encapsulation # Internet family options: # # MROUTING enables the kernel multicast packet forwarder, which works -# with mrouted(8). -# -# PIM enables Protocol Independent Multicast in the kernel. -# Requires MROUTING enabled. +# with mrouted and XORP. # # IPFIREWALL enables support for IP firewall construction, in # conjunction with the `ipfw' program. IPFIREWALL_VERBOSE sends @@ -854,7 +851,6 @@ device stf #6to4 IPv6 over IPv4 encapsulation # using the trpt(8) utility. # options MROUTING # Multicast routing -options PIM # Protocol Independent Multicast options IPFIREWALL #firewall options IPFIREWALL_VERBOSE #enable logging to syslogd(8) options IPFIREWALL_VERBOSE_LIMIT=100 #limit verbosity diff --git a/sys/conf/options b/sys/conf/options index 0abb45915817..6d5e593ec424 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -352,7 +352,6 @@ ETHER_8023 opt_ef.h ETHER_8022 opt_ef.h ETHER_SNAP opt_ef.h MROUTING opt_mrouting.h -PIM opt_mrouting.h INET opt_inet.h INET6 opt_inet6.h IPSEC opt_ipsec.h diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index e66f8b4769d6..28196ef9589b 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -56,9 +56,6 @@ #include #include #include -#ifdef PIM -#include -#endif #include #include #include @@ -345,17 +342,15 @@ struct protosw inetsw[] = { .pr_usrreqs = &rip_usrreqs }, #endif -#ifdef PIM { .pr_type = SOCK_RAW, .pr_domain = &inetdomain, .pr_protocol = IPPROTO_PIM, .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, - .pr_input = pim_input, + .pr_input = encap4_input, .pr_ctloutput = rip_ctloutput, .pr_usrreqs = &rip_usrreqs }, -#endif /* PIM */ #ifdef DEV_PFSYNC { .pr_type = SOCK_RAW, @@ -438,9 +433,6 @@ SYSCTL_NODE(_net_inet, IPPROTO_AH, ipsec, CTLFLAG_RW, 0, "IPSEC"); #endif /* IPSEC */ #endif /* !FAST_IPSEC */ SYSCTL_NODE(_net_inet, IPPROTO_RAW, raw, CTLFLAG_RW, 0, "RAW"); -#ifdef PIM -SYSCTL_NODE(_net_inet, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM"); -#endif #ifdef DEV_PFSYNC SYSCTL_NODE(_net_inet, IPPROTO_PFSYNC, pfsync, CTLFLAG_RW, 0, "PFSYNC"); #endif diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 979509c3519a..6a50ef0ba392 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -58,9 +58,7 @@ #include "opt_mac.h" #include "opt_mrouting.h" -#ifdef PIM #define _PIM_VT 1 -#endif #include #include @@ -91,10 +89,8 @@ #include #include #include -#ifdef PIM #include #include -#endif #include #include @@ -197,12 +193,27 @@ static u_int bw_upcalls_n; /* # of pending upcalls */ static struct callout bw_upcalls_ch; #define BW_UPCALLS_PERIOD (hz) /* periodical flush of bw upcalls */ -#ifdef PIM static struct pimstat pimstat; + +SYSCTL_NODE(_net_inet, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM"); SYSCTL_STRUCT(_net_inet_pim, PIMCTL_STATS, stats, CTLFLAG_RD, &pimstat, pimstat, "PIM Statistics (struct pimstat, netinet/pim_var.h)"); +extern struct domain inetdomain; +struct protosw in_pim_protosw = { + .pr_type = SOCK_RAW, + .pr_domain = &inetdomain, + .pr_protocol = IPPROTO_PIM, + .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, + .pr_input = pim_input, + .pr_output = (pr_output_t*)rip_output, + .pr_ctloutput = rip_ctloutput, + .pr_usrreqs = &rip_usrreqs +}; +static const struct encaptab *pim_encap_cookie; +static int pim_encapcheck(const struct mbuf *, int, int, void *); + /* * Note: the PIM Register encapsulation adds the following in front of a * data packet: @@ -247,7 +258,6 @@ static struct pim_encap_pimhdr pim_encap_pimhdr = { static struct ifnet multicast_register_if; static vifi_t reg_vif_num = VIFI_INVALID; -#endif /* PIM */ /* * Private variables. @@ -296,7 +306,6 @@ static void bw_meter_process(void); static void expire_bw_upcalls_send(void *); static void expire_bw_meter_process(void *); -#ifdef PIM static int pim_register_send(struct ip *, struct vif *, struct mbuf *, struct mfc *); static int pim_register_send_rp(struct ip *, struct vif *, @@ -304,7 +313,6 @@ static int pim_register_send_rp(struct ip *, struct vif *, static int pim_register_send_upcall(struct ip *, struct vif *, struct mbuf *, struct mfc *); static struct mbuf *pim_register_prepare(struct ip *, struct mbuf *); -#endif /* * whether or not special PIM assert processing is enabled. @@ -603,7 +611,7 @@ ip_mrouter_reset(void) callout_init(&bw_meter_ch, NET_CALLOUT_MPSAFE); } -static struct mtx mrouter_mtx; /* used to synch init/done work */ +static struct mtx mrouter_mtx; static void if_detached_event(void *arg __unused, struct ifnet *ifp) @@ -788,9 +796,7 @@ X_ip_mrouter_done(void) bzero(bw_meter_timers, sizeof(bw_meter_timers)); MFC_UNLOCK(); -#ifdef PIM reg_vif_num = VIFI_INVALID; -#endif mtx_unlock(&mrouter_mtx); @@ -883,7 +889,6 @@ add_vif(struct vifctl *vifcp) } /* Find the interface with an address in AF_INET family */ -#ifdef PIM if (vifcp->vifc_flags & VIFF_REGISTER) { /* * XXX: Because VIFF_REGISTER does not really need a valid @@ -891,9 +896,7 @@ add_vif(struct vifctl *vifcp) * check its address. */ ifp = NULL; - } else -#endif - { + } else { sin.sin_addr = vifcp->vifc_lcl_addr; ifa = ifa_ifwithaddr((struct sockaddr *)&sin); if (ifa == NULL) { @@ -907,7 +910,6 @@ add_vif(struct vifctl *vifcp) log(LOG_ERR, "tunnels are no longer supported\n"); VIF_UNLOCK(); return EOPNOTSUPP; -#ifdef PIM } else if (vifcp->vifc_flags & VIFF_REGISTER) { ifp = &multicast_register_if; if (mrtdebug) @@ -918,7 +920,6 @@ add_vif(struct vifctl *vifcp) multicast_register_if.if_flags = IFF_LOOPBACK; reg_vif_num = vifcp->vifc_vifi; } -#endif } else { /* Make sure the interface supports multicast */ if ((ifp->if_flags & IFF_MULTICAST) == 0) { VIF_UNLOCK(); @@ -984,10 +985,8 @@ del_vif_locked(vifi_t vifi) if (!(vifp->v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) if_allmulti(vifp->v_ifp, 0); -#ifdef PIM if (vifp->v_flags & VIFF_REGISTER) reg_vif_num = VIFI_INVALID; -#endif bzero((caddr_t)vifp, sizeof (*vifp)); @@ -1571,12 +1570,10 @@ 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 < numvifs) { -#ifdef PIM if (viftable[xmt_vif].v_flags & VIFF_REGISTER) - pim_register_send(ip, viftable + xmt_vif, m, rt); + pim_register_send(ip, viftable + xmt_vif, m, rt); else -#endif - phyint_send(ip, viftable + xmt_vif, m); + phyint_send(ip, viftable + xmt_vif, m); return 1; } @@ -1603,10 +1600,8 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif) struct timeval now; u_long delta; -#ifdef PIM if (ifp == &multicast_register_if) pimstat.pims_rcv_registers_wrongiif++; -#endif /* Get vifi for the incoming packet */ for (vifi=0; vifi < numvifs && viftable[vifi].v_ifp != ifp; vifi++) @@ -1674,12 +1669,10 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif) if ((rt->mfc_ttls[vifi] > 0) && (ip->ip_ttl > rt->mfc_ttls[vifi])) { viftable[vifi].v_pkt_out++; viftable[vifi].v_bytes_out += plen; -#ifdef PIM if (viftable[vifi].v_flags & VIFF_REGISTER) pim_register_send(ip, viftable + vifi, m, rt); else -#endif - phyint_send(ip, viftable + vifi, m); + phyint_send(ip, viftable + vifi, m); } /* @@ -2516,7 +2509,6 @@ expire_bw_meter_process(void *unused) * End of bandwidth monitoring code */ -#ifdef PIM /* * Send the packet up to the user daemon, or eventually do kernel encapsulation * @@ -2731,6 +2723,24 @@ pim_register_send_rp(struct ip *ip, struct vif *vifp, return 0; } +/* + * pim_encapcheck() is called by the encap4_input() path at runtime to + * determine if a packet is for PIM; allowing PIM to be dynamically loaded + * into the kernel. + */ +static int +pim_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-SMv2 and PIM-DM messages processing. * Receives and verifies the PIM control messages, and passes them @@ -2971,7 +2981,6 @@ pim_input(struct mbuf *m, int off) return; } -#endif /* PIM */ static int ip_mroute_modevent(module_t mod, int type, void *unused) @@ -2982,6 +2991,15 @@ ip_mroute_modevent(module_t mod, int type, void *unused) MFC_LOCK_INIT(); VIF_LOCK_INIT(); ip_mrouter_reset(); + pim_encap_cookie = encap_attach_func(AF_INET, IPPROTO_PIM, + pim_encapcheck, &in_pim_protosw, NULL); + if (pim_encap_cookie == NULL) { + printf("ip_mroute: unable to attach pim encap\n"); + VIF_LOCK_DESTROY(); + MFC_LOCK_DESTROY(); + mtx_destroy(&mrouter_mtx); + return (EINVAL); + } ip_mcast_src = X_ip_mcast_src; ip_mforward = X_ip_mforward; ip_mrouter_done = X_ip_mrouter_done; @@ -3006,6 +3024,11 @@ ip_mroute_modevent(module_t mod, int type, void *unused) if (ip_mrouter) return EINVAL; + if (pim_encap_cookie) { + encap_detach(pim_encap_cookie); + pim_encap_cookie = NULL; + } + X_ip_mrouter_done(); ip_mcast_src = NULL; ip_mforward = NULL;