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
This commit is contained in:
Bruce M Simpson 2007-02-10 13:59:13 +00:00
parent fc8405c644
commit 0948f0a28f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=166622
5 changed files with 62 additions and 45 deletions

View File

@ -21,6 +21,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 7.x IS SLOW:
developers choose to disable these features on build machines developers choose to disable these features on build machines
to maximize performance. 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: 20070207:
Support for IPIP tunnels (VIFF_TUNNEL) in IPv4 multicast routing Support for IPIP tunnels (VIFF_TUNNEL) in IPv4 multicast routing
has been removed. Its functionality may be achieved by explicitly has been removed. Its functionality may be achieved by explicitly

View File

@ -807,10 +807,7 @@ device stf #6to4 IPv6 over IPv4 encapsulation
# Internet family options: # Internet family options:
# #
# MROUTING enables the kernel multicast packet forwarder, which works # MROUTING enables the kernel multicast packet forwarder, which works
# with mrouted(8). # with mrouted and XORP.
#
# PIM enables Protocol Independent Multicast in the kernel.
# Requires MROUTING enabled.
# #
# IPFIREWALL enables support for IP firewall construction, in # IPFIREWALL enables support for IP firewall construction, in
# conjunction with the `ipfw' program. IPFIREWALL_VERBOSE sends # conjunction with the `ipfw' program. IPFIREWALL_VERBOSE sends
@ -854,7 +851,6 @@ device stf #6to4 IPv6 over IPv4 encapsulation
# using the trpt(8) utility. # using the trpt(8) utility.
# #
options MROUTING # Multicast routing options MROUTING # Multicast routing
options PIM # Protocol Independent Multicast
options IPFIREWALL #firewall options IPFIREWALL #firewall
options IPFIREWALL_VERBOSE #enable logging to syslogd(8) options IPFIREWALL_VERBOSE #enable logging to syslogd(8)
options IPFIREWALL_VERBOSE_LIMIT=100 #limit verbosity options IPFIREWALL_VERBOSE_LIMIT=100 #limit verbosity

View File

@ -352,7 +352,6 @@ ETHER_8023 opt_ef.h
ETHER_8022 opt_ef.h ETHER_8022 opt_ef.h
ETHER_SNAP opt_ef.h ETHER_SNAP opt_ef.h
MROUTING opt_mrouting.h MROUTING opt_mrouting.h
PIM opt_mrouting.h
INET opt_inet.h INET opt_inet.h
INET6 opt_inet6.h INET6 opt_inet6.h
IPSEC opt_ipsec.h IPSEC opt_ipsec.h

View File

@ -56,9 +56,6 @@
#include <netinet/ip_var.h> #include <netinet/ip_var.h>
#include <netinet/ip_icmp.h> #include <netinet/ip_icmp.h>
#include <netinet/igmp_var.h> #include <netinet/igmp_var.h>
#ifdef PIM
#include <netinet/pim_var.h>
#endif
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <netinet/tcp_timer.h> #include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h> #include <netinet/tcp_var.h>
@ -345,17 +342,15 @@ struct protosw inetsw[] = {
.pr_usrreqs = &rip_usrreqs .pr_usrreqs = &rip_usrreqs
}, },
#endif #endif
#ifdef PIM
{ {
.pr_type = SOCK_RAW, .pr_type = SOCK_RAW,
.pr_domain = &inetdomain, .pr_domain = &inetdomain,
.pr_protocol = IPPROTO_PIM, .pr_protocol = IPPROTO_PIM,
.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
.pr_input = pim_input, .pr_input = encap4_input,
.pr_ctloutput = rip_ctloutput, .pr_ctloutput = rip_ctloutput,
.pr_usrreqs = &rip_usrreqs .pr_usrreqs = &rip_usrreqs
}, },
#endif /* PIM */
#ifdef DEV_PFSYNC #ifdef DEV_PFSYNC
{ {
.pr_type = SOCK_RAW, .pr_type = SOCK_RAW,
@ -438,9 +433,6 @@ SYSCTL_NODE(_net_inet, IPPROTO_AH, ipsec, CTLFLAG_RW, 0, "IPSEC");
#endif /* IPSEC */ #endif /* IPSEC */
#endif /* !FAST_IPSEC */ #endif /* !FAST_IPSEC */
SYSCTL_NODE(_net_inet, IPPROTO_RAW, raw, CTLFLAG_RW, 0, "RAW"); 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 #ifdef DEV_PFSYNC
SYSCTL_NODE(_net_inet, IPPROTO_PFSYNC, pfsync, CTLFLAG_RW, 0, "PFSYNC"); SYSCTL_NODE(_net_inet, IPPROTO_PFSYNC, pfsync, CTLFLAG_RW, 0, "PFSYNC");
#endif #endif

View File

@ -58,9 +58,7 @@
#include "opt_mac.h" #include "opt_mac.h"
#include "opt_mrouting.h" #include "opt_mrouting.h"
#ifdef PIM
#define _PIM_VT 1 #define _PIM_VT 1
#endif
#include <sys/param.h> #include <sys/param.h>
#include <sys/kernel.h> #include <sys/kernel.h>
@ -91,10 +89,8 @@
#include <netinet/ip_mroute.h> #include <netinet/ip_mroute.h>
#include <netinet/ip_var.h> #include <netinet/ip_var.h>
#include <netinet/ip_options.h> #include <netinet/ip_options.h>
#ifdef PIM
#include <netinet/pim.h> #include <netinet/pim.h>
#include <netinet/pim_var.h> #include <netinet/pim_var.h>
#endif
#include <netinet/udp.h> #include <netinet/udp.h>
#include <machine/in_cksum.h> #include <machine/in_cksum.h>
@ -197,12 +193,27 @@ static u_int bw_upcalls_n; /* # of pending upcalls */
static struct callout bw_upcalls_ch; static struct callout bw_upcalls_ch;
#define BW_UPCALLS_PERIOD (hz) /* periodical flush of bw upcalls */ #define BW_UPCALLS_PERIOD (hz) /* periodical flush of bw upcalls */
#ifdef PIM
static struct pimstat pimstat; 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, SYSCTL_STRUCT(_net_inet_pim, PIMCTL_STATS, stats, CTLFLAG_RD,
&pimstat, pimstat, &pimstat, pimstat,
"PIM Statistics (struct pimstat, netinet/pim_var.h)"); "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 * Note: the PIM Register encapsulation adds the following in front of a
* data packet: * data packet:
@ -247,7 +258,6 @@ static struct pim_encap_pimhdr pim_encap_pimhdr = {
static struct ifnet multicast_register_if; static struct ifnet multicast_register_if;
static vifi_t reg_vif_num = VIFI_INVALID; static vifi_t reg_vif_num = VIFI_INVALID;
#endif /* PIM */
/* /*
* Private variables. * Private variables.
@ -296,7 +306,6 @@ static void bw_meter_process(void);
static void expire_bw_upcalls_send(void *); static void expire_bw_upcalls_send(void *);
static void expire_bw_meter_process(void *); static void expire_bw_meter_process(void *);
#ifdef PIM
static int pim_register_send(struct ip *, struct vif *, static int pim_register_send(struct ip *, struct vif *,
struct mbuf *, struct mfc *); struct mbuf *, struct mfc *);
static int pim_register_send_rp(struct ip *, struct vif *, 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 *, static int pim_register_send_upcall(struct ip *, struct vif *,
struct mbuf *, struct mfc *); struct mbuf *, struct mfc *);
static struct mbuf *pim_register_prepare(struct ip *, struct mbuf *); static struct mbuf *pim_register_prepare(struct ip *, struct mbuf *);
#endif
/* /*
* whether or not special PIM assert processing is enabled. * 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); 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 static void
if_detached_event(void *arg __unused, struct ifnet *ifp) 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)); bzero(bw_meter_timers, sizeof(bw_meter_timers));
MFC_UNLOCK(); MFC_UNLOCK();
#ifdef PIM
reg_vif_num = VIFI_INVALID; reg_vif_num = VIFI_INVALID;
#endif
mtx_unlock(&mrouter_mtx); mtx_unlock(&mrouter_mtx);
@ -883,7 +889,6 @@ add_vif(struct vifctl *vifcp)
} }
/* Find the interface with an address in AF_INET family */ /* Find the interface with an address in AF_INET family */
#ifdef PIM
if (vifcp->vifc_flags & VIFF_REGISTER) { if (vifcp->vifc_flags & VIFF_REGISTER) {
/* /*
* XXX: Because VIFF_REGISTER does not really need a valid * XXX: Because VIFF_REGISTER does not really need a valid
@ -891,9 +896,7 @@ add_vif(struct vifctl *vifcp)
* check its address. * check its address.
*/ */
ifp = NULL; ifp = NULL;
} else } else {
#endif
{
sin.sin_addr = vifcp->vifc_lcl_addr; sin.sin_addr = vifcp->vifc_lcl_addr;
ifa = ifa_ifwithaddr((struct sockaddr *)&sin); ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
if (ifa == NULL) { if (ifa == NULL) {
@ -907,7 +910,6 @@ add_vif(struct vifctl *vifcp)
log(LOG_ERR, "tunnels are no longer supported\n"); log(LOG_ERR, "tunnels are no longer supported\n");
VIF_UNLOCK(); VIF_UNLOCK();
return EOPNOTSUPP; return EOPNOTSUPP;
#ifdef PIM
} else if (vifcp->vifc_flags & VIFF_REGISTER) { } else if (vifcp->vifc_flags & VIFF_REGISTER) {
ifp = &multicast_register_if; ifp = &multicast_register_if;
if (mrtdebug) if (mrtdebug)
@ -918,7 +920,6 @@ add_vif(struct vifctl *vifcp)
multicast_register_if.if_flags = IFF_LOOPBACK; multicast_register_if.if_flags = IFF_LOOPBACK;
reg_vif_num = vifcp->vifc_vifi; reg_vif_num = vifcp->vifc_vifi;
} }
#endif
} else { /* Make sure the interface supports multicast */ } else { /* Make sure the interface supports multicast */
if ((ifp->if_flags & IFF_MULTICAST) == 0) { if ((ifp->if_flags & IFF_MULTICAST) == 0) {
VIF_UNLOCK(); VIF_UNLOCK();
@ -984,10 +985,8 @@ del_vif_locked(vifi_t vifi)
if (!(vifp->v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) if (!(vifp->v_flags & (VIFF_TUNNEL | VIFF_REGISTER)))
if_allmulti(vifp->v_ifp, 0); if_allmulti(vifp->v_ifp, 0);
#ifdef PIM
if (vifp->v_flags & VIFF_REGISTER) if (vifp->v_flags & VIFF_REGISTER)
reg_vif_num = VIFI_INVALID; reg_vif_num = VIFI_INVALID;
#endif
bzero((caddr_t)vifp, sizeof (*vifp)); 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.) * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.)
*/ */
if (xmt_vif < numvifs) { if (xmt_vif < numvifs) {
#ifdef PIM
if (viftable[xmt_vif].v_flags & VIFF_REGISTER) 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 else
#endif phyint_send(ip, viftable + xmt_vif, m);
phyint_send(ip, viftable + xmt_vif, m);
return 1; return 1;
} }
@ -1603,10 +1600,8 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif)
struct timeval now; struct timeval now;
u_long delta; u_long delta;
#ifdef PIM
if (ifp == &multicast_register_if) if (ifp == &multicast_register_if)
pimstat.pims_rcv_registers_wrongiif++; pimstat.pims_rcv_registers_wrongiif++;
#endif
/* Get vifi for the incoming packet */ /* Get vifi for the incoming packet */
for (vifi=0; vifi < numvifs && viftable[vifi].v_ifp != ifp; vifi++) 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])) { if ((rt->mfc_ttls[vifi] > 0) && (ip->ip_ttl > rt->mfc_ttls[vifi])) {
viftable[vifi].v_pkt_out++; viftable[vifi].v_pkt_out++;
viftable[vifi].v_bytes_out += plen; viftable[vifi].v_bytes_out += plen;
#ifdef PIM
if (viftable[vifi].v_flags & VIFF_REGISTER) if (viftable[vifi].v_flags & VIFF_REGISTER)
pim_register_send(ip, viftable + vifi, m, rt); pim_register_send(ip, viftable + vifi, m, rt);
else 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 * End of bandwidth monitoring code
*/ */
#ifdef PIM
/* /*
* Send the packet up to the user daemon, or eventually do kernel encapsulation * 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; 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. * PIM-SMv2 and PIM-DM messages processing.
* Receives and verifies the PIM control messages, and passes them * Receives and verifies the PIM control messages, and passes them
@ -2971,7 +2981,6 @@ pim_input(struct mbuf *m, int off)
return; return;
} }
#endif /* PIM */
static int static int
ip_mroute_modevent(module_t mod, int type, void *unused) 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(); MFC_LOCK_INIT();
VIF_LOCK_INIT(); VIF_LOCK_INIT();
ip_mrouter_reset(); 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_mcast_src = X_ip_mcast_src;
ip_mforward = X_ip_mforward; ip_mforward = X_ip_mforward;
ip_mrouter_done = X_ip_mrouter_done; ip_mrouter_done = X_ip_mrouter_done;
@ -3006,6 +3024,11 @@ ip_mroute_modevent(module_t mod, int type, void *unused)
if (ip_mrouter) if (ip_mrouter)
return EINVAL; return EINVAL;
if (pim_encap_cookie) {
encap_detach(pim_encap_cookie);
pim_encap_cookie = NULL;
}
X_ip_mrouter_done(); X_ip_mrouter_done();
ip_mcast_src = NULL; ip_mcast_src = NULL;
ip_mforward = NULL; ip_mforward = NULL;