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:
parent
fc8405c644
commit
0948f0a28f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=166622
7
UPDATING
7
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
|
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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user