Make IPv6 multicast forwarding dynamically loadable from a GENERIC kernel.
It is built in the same module as IPv4 multicast forwarding, i.e. ip_mroute.ko, if and only if IPv6 support is enabled for loadable modules. Export IPv6 forwarding structs to userland netstat(1) via sysctl(9).
This commit is contained in:
parent
c553ec0508
commit
3e83ac6653
@ -1760,7 +1760,7 @@ netinet/ip_icmp.c optional inet
|
||||
netinet/ip_input.c optional inet
|
||||
netinet/ip_ipsec.c optional ipsec
|
||||
netinet/ip_ipsec.c optional fast_ipsec
|
||||
netinet/ip_mroute.c optional mrouting
|
||||
netinet/ip_mroute.c optional mrouting inet | mrouting inet6
|
||||
netinet/ip_options.c optional inet
|
||||
netinet/ip_output.c optional inet
|
||||
netinet/raw_ip.c optional inet
|
||||
@ -1815,7 +1815,7 @@ netinet6/in6_src.c optional inet6
|
||||
netinet6/ip6_forward.c optional inet6
|
||||
netinet6/ip6_id.c optional inet6
|
||||
netinet6/ip6_input.c optional inet6
|
||||
netinet6/ip6_mroute.c optional inet6
|
||||
netinet6/ip6_mroute.c optional mrouting inet6
|
||||
netinet6/ip6_output.c optional inet6
|
||||
netinet6/ipcomp_core.c optional ipsec
|
||||
netinet6/ipcomp_input.c optional ipsec
|
||||
|
@ -1,13 +1,26 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../netinet
|
||||
.PATH: ${.CURDIR}/../../netinet ${.CURDIR}/../../netinet6
|
||||
|
||||
KMOD= ip_mroute
|
||||
SRCS= ip_mroute.c opt_mac.h opt_mrouting.h
|
||||
|
||||
SRCS= ip_mroute.c
|
||||
SRCS+= opt_inet.h opt_mac.h opt_mrouting.h
|
||||
SRCS+= opt_inet6.h
|
||||
|
||||
.if !defined(MK_INET6_SUPPORT) || ${MK_INET6_SUPPORT} != "no"
|
||||
SRCS+= ip6_mroute.c
|
||||
.endif
|
||||
|
||||
.if !defined(KERNBUILDDIR)
|
||||
opt_inet.h:
|
||||
echo "#define INET 1" > ${.TARGET}
|
||||
opt_mrouting.h:
|
||||
echo "#define MROUTING 1" > ${.TARGET}
|
||||
echo "#define MROUTING 1" > ${.TARGET}
|
||||
.if !defined(MK_INET6_SUPPORT) || ${MK_INET6_SUPPORT} != "no"
|
||||
opt_inet6.h:
|
||||
echo "#define INET6 1" > ${.TARGET}
|
||||
.endif
|
||||
.endif
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
@ -55,6 +55,8 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_mac.h"
|
||||
#include "opt_mrouting.h"
|
||||
|
||||
@ -92,6 +94,12 @@
|
||||
#include <netinet/pim.h>
|
||||
#include <netinet/pim_var.h>
|
||||
#include <netinet/udp.h>
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet6/ip6_mroute.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
#include <machine/in_cksum.h>
|
||||
|
||||
#include <security/mac/mac_framework.h>
|
||||
@ -217,6 +225,19 @@ struct protosw in_pim_protosw = {
|
||||
.pr_usrreqs = &rip_usrreqs
|
||||
};
|
||||
static const struct encaptab *pim_encap_cookie;
|
||||
|
||||
#ifdef INET6
|
||||
/* ip6_mroute.c glue */
|
||||
extern struct in6_protosw in6_pim_protosw;
|
||||
static const struct encaptab *pim6_encap_cookie;
|
||||
|
||||
extern int X_ip6_mrouter_set(struct socket *, struct sockopt *);
|
||||
extern int X_ip6_mrouter_get(struct socket *, struct sockopt *);
|
||||
extern int X_ip6_mrouter_done(void);
|
||||
extern int X_ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
|
||||
extern int X_mrt6_ioctl(int, caddr_t);
|
||||
#endif
|
||||
|
||||
static int pim_encapcheck(const struct mbuf *, int, int, void *);
|
||||
|
||||
/*
|
||||
@ -2737,7 +2758,7 @@ pim_register_send_rp(struct ip *ip, struct vif *vifp,
|
||||
}
|
||||
|
||||
/*
|
||||
* pim_encapcheck() is called by the encap4_input() path at runtime to
|
||||
* pim_encapcheck() is called by the encap[46]_input() path at runtime to
|
||||
* determine if a packet is for PIM; allowing PIM to be dynamically loaded
|
||||
* into the kernel.
|
||||
*/
|
||||
@ -2995,6 +3016,10 @@ pim_input_to_daemon:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: This is common code for dealing with initialization for both
|
||||
* the IPv4 and IPv6 multicast forwarding paths. It could do with cleanup.
|
||||
*/
|
||||
static int
|
||||
ip_mroute_modevent(module_t mod, int type, void *unused)
|
||||
{
|
||||
@ -3006,6 +3031,7 @@ ip_mroute_modevent(module_t mod, int type, void *unused)
|
||||
ip_mrouter_reset();
|
||||
TUNABLE_ULONG_FETCH("net.inet.pim.squelch_wholepkt",
|
||||
&pim_squelch_wholepkt);
|
||||
|
||||
pim_encap_cookie = encap_attach_func(AF_INET, IPPROTO_PIM,
|
||||
pim_encapcheck, &in_pim_protosw, NULL);
|
||||
if (pim_encap_cookie == NULL) {
|
||||
@ -3015,13 +3041,40 @@ ip_mroute_modevent(module_t mod, int type, void *unused)
|
||||
mtx_destroy(&mrouter_mtx);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
pim6_encap_cookie = encap_attach_func(AF_INET6, IPPROTO_PIM,
|
||||
pim_encapcheck, (struct protosw *)&in6_pim_protosw, NULL);
|
||||
if (pim6_encap_cookie == NULL) {
|
||||
printf("ip_mroute: unable to attach pim6 encap\n");
|
||||
if (pim_encap_cookie) {
|
||||
encap_detach(pim_encap_cookie);
|
||||
pim_encap_cookie = NULL;
|
||||
}
|
||||
VIF_LOCK_DESTROY();
|
||||
MFC_LOCK_DESTROY();
|
||||
mtx_destroy(&mrouter_mtx);
|
||||
return (EINVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
ip_mcast_src = X_ip_mcast_src;
|
||||
ip_mforward = X_ip_mforward;
|
||||
ip_mrouter_done = X_ip_mrouter_done;
|
||||
ip_mrouter_get = X_ip_mrouter_get;
|
||||
ip_mrouter_set = X_ip_mrouter_set;
|
||||
|
||||
#ifdef INET6
|
||||
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;
|
||||
#endif
|
||||
|
||||
ip_rsvp_force_done = X_ip_rsvp_force_done;
|
||||
ip_rsvp_vif = X_ip_rsvp_vif;
|
||||
|
||||
legal_vif_num = X_legal_vif_num;
|
||||
mrt_ioctl = X_mrt_ioctl;
|
||||
rsvp_input_p = X_rsvp_input;
|
||||
@ -3036,29 +3089,49 @@ ip_mroute_modevent(module_t mod, int type, void *unused)
|
||||
* just loaded and then unloaded w/o starting up a user
|
||||
* process we still need to cleanup.
|
||||
*/
|
||||
if (ip_mrouter)
|
||||
if (ip_mrouter
|
||||
#ifdef INET6
|
||||
|| ip6_mrouter
|
||||
#endif
|
||||
)
|
||||
return EINVAL;
|
||||
|
||||
#ifdef INET6
|
||||
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;
|
||||
#endif
|
||||
|
||||
if (pim_encap_cookie) {
|
||||
encap_detach(pim_encap_cookie);
|
||||
pim_encap_cookie = NULL;
|
||||
}
|
||||
|
||||
X_ip_mrouter_done();
|
||||
ip_mcast_src = NULL;
|
||||
ip_mforward = NULL;
|
||||
ip_mrouter_done = NULL;
|
||||
ip_mrouter_get = NULL;
|
||||
ip_mrouter_set = NULL;
|
||||
|
||||
ip_rsvp_force_done = NULL;
|
||||
ip_rsvp_vif = NULL;
|
||||
|
||||
legal_vif_num = NULL;
|
||||
mrt_ioctl = NULL;
|
||||
rsvp_input_p = NULL;
|
||||
|
||||
VIF_LOCK_DESTROY();
|
||||
MFC_LOCK_DESTROY();
|
||||
mtx_destroy(&mrouter_mtx);
|
||||
break;
|
||||
|
||||
default:
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ in6_control(so, cmd, data, ifp, td)
|
||||
switch (cmd) {
|
||||
case SIOCGETSGCNT_IN6:
|
||||
case SIOCGETMIFCNT_IN6:
|
||||
return (mrt6_ioctl(cmd, data));
|
||||
return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP);
|
||||
}
|
||||
|
||||
switch(cmd) {
|
||||
|
@ -335,7 +335,7 @@ struct ip6protosw inet6sw[] = {
|
||||
.pr_domain = &inet6domain,
|
||||
.pr_protocol = IPPROTO_PIM,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
|
||||
.pr_input = pim6_input,
|
||||
.pr_input = encap6_input,
|
||||
.pr_output = rip6_output,
|
||||
.pr_ctloutput = rip6_ctloutput,
|
||||
.pr_usrreqs = &rip6_usrreqs
|
||||
|
@ -696,7 +696,8 @@ passin:
|
||||
* ip6_mforward() returns a non-zero value, the packet
|
||||
* must be discarded, else it may be accepted below.
|
||||
*/
|
||||
if (ip6_mrouter && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) {
|
||||
if (ip6_mrouter && ip6_mforward &&
|
||||
ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) {
|
||||
ip6stat.ip6s_cantforward++;
|
||||
m_freem(m);
|
||||
return;
|
||||
|
@ -96,6 +96,7 @@
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
@ -114,6 +115,7 @@
|
||||
#include <netinet6/scope6_var.h>
|
||||
#include <netinet6/nd6.h>
|
||||
#include <netinet6/ip6_mroute.h>
|
||||
#include <netinet6/ip6protosw.h>
|
||||
#include <netinet6/pim6.h>
|
||||
#include <netinet6/pim6_var.h>
|
||||
|
||||
@ -130,6 +132,18 @@ static int socket_send __P((struct socket *, struct mbuf *,
|
||||
static int register_send __P((struct ip6_hdr *, struct mif6 *,
|
||||
struct mbuf *));
|
||||
|
||||
extern struct domain inet6domain;
|
||||
struct ip6protosw in6_pim_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inet6domain,
|
||||
.pr_protocol = IPPROTO_PIM,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
|
||||
.pr_input = pim6_input,
|
||||
.pr_output = rip6_output,
|
||||
.pr_ctloutput = rip6_ctloutput,
|
||||
.pr_usrreqs = &rip6_usrreqs
|
||||
};
|
||||
|
||||
/*
|
||||
* Globals. All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
|
||||
* except for netstat or debugging purposes.
|
||||
@ -137,14 +151,32 @@ static int register_send __P((struct ip6_hdr *, struct mif6 *,
|
||||
struct socket *ip6_mrouter = NULL;
|
||||
int ip6_mrouter_ver = 0;
|
||||
int ip6_mrtproto = IPPROTO_PIM; /* for netstat only */
|
||||
|
||||
SYSCTL_DECL(_net_inet6);
|
||||
SYSCTL_DECL(_net_inet6_ip6);
|
||||
SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM");
|
||||
|
||||
struct mrt6stat mrt6stat;
|
||||
SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW,
|
||||
&mrt6stat, mrt6stat,
|
||||
"Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)");
|
||||
|
||||
#define NO_RTE_FOUND 0x1
|
||||
#define RTE_FOUND 0x2
|
||||
|
||||
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], "
|
||||
"netinet6/ip6_mroute.h)");
|
||||
|
||||
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)");
|
||||
|
||||
#ifdef MRT6DEBUG
|
||||
u_int mrt6debug = 0; /* debug level */
|
||||
#define DEBUG_MFC 0x02
|
||||
@ -187,6 +219,10 @@ static mifi_t nummifs = 0;
|
||||
static mifi_t reg_mif_num = (mifi_t)-1;
|
||||
|
||||
static struct pim6stat pim6stat;
|
||||
SYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RD,
|
||||
&pim6stat, pim6stat,
|
||||
"PIM Statistics (struct pim6stat, netinet6/pim_var.h)");
|
||||
|
||||
static int pim6;
|
||||
|
||||
/*
|
||||
@ -261,13 +297,17 @@ static int del_m6fc __P((struct mf6cctl *));
|
||||
|
||||
static struct callout expire_upcalls_ch;
|
||||
|
||||
int X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m);
|
||||
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);
|
||||
|
||||
/*
|
||||
* Handle MRT setsockopt commands to modify the multicast routing tables.
|
||||
*/
|
||||
int
|
||||
ip6_mrouter_set(so, sopt)
|
||||
struct socket *so;
|
||||
struct sockopt *sopt;
|
||||
X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
|
||||
{
|
||||
int error = 0;
|
||||
int optval;
|
||||
@ -290,7 +330,7 @@ ip6_mrouter_set(so, sopt)
|
||||
error = ip6_mrouter_init(so, optval, sopt->sopt_name);
|
||||
break;
|
||||
case MRT6_DONE:
|
||||
error = ip6_mrouter_done();
|
||||
error = X_ip6_mrouter_done();
|
||||
break;
|
||||
case MRT6_ADD_MIF:
|
||||
error = sooptcopyin(sopt, &mifc, sizeof(mifc), sizeof(mifc));
|
||||
@ -335,9 +375,7 @@ ip6_mrouter_set(so, sopt)
|
||||
* Handle MRT getsockopt commands
|
||||
*/
|
||||
int
|
||||
ip6_mrouter_get(so, sopt)
|
||||
struct socket *so;
|
||||
struct sockopt *sopt;
|
||||
X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
@ -356,9 +394,7 @@ ip6_mrouter_get(so, sopt)
|
||||
* Handle ioctl commands to obtain information from the cache
|
||||
*/
|
||||
int
|
||||
mrt6_ioctl(cmd, data)
|
||||
int cmd;
|
||||
caddr_t data;
|
||||
X_mrt6_ioctl(int cmd, caddr_t data)
|
||||
{
|
||||
switch (cmd) {
|
||||
case SIOCGETSGCNT_IN6:
|
||||
@ -478,7 +514,7 @@ ip6_mrouter_init(so, v, cmd)
|
||||
* Disable multicast routing
|
||||
*/
|
||||
int
|
||||
ip6_mrouter_done()
|
||||
X_ip6_mrouter_done(void)
|
||||
{
|
||||
mifi_t mifi;
|
||||
int i;
|
||||
@ -993,10 +1029,7 @@ socket_send(s, mm, src)
|
||||
*/
|
||||
|
||||
int
|
||||
ip6_mforward(ip6, ifp, m)
|
||||
struct ip6_hdr *ip6;
|
||||
struct ifnet *ifp;
|
||||
struct mbuf *m;
|
||||
X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct mf6c *rt;
|
||||
struct mif6 *mifp;
|
||||
|
@ -268,10 +268,10 @@ struct rtdetq { /* XXX: rtdetq is also defined in ip_mroute.h */
|
||||
|
||||
#define MAX_UPQ6 4 /* max. no of pkts in upcall Q */
|
||||
|
||||
int ip6_mrouter_set __P((struct socket *so, struct sockopt *sopt));
|
||||
int ip6_mrouter_get __P((struct socket *so, struct sockopt *sopt));
|
||||
int ip6_mrouter_done __P((void));
|
||||
int mrt6_ioctl __P((int, caddr_t));
|
||||
extern int (*ip6_mrouter_set)(struct socket *so, struct sockopt *sopt);
|
||||
extern int (*ip6_mrouter_get)(struct socket *so, struct sockopt *sopt);
|
||||
extern int (*ip6_mrouter_done)(void);
|
||||
extern int (*mrt6_ioctl)(int, caddr_t);
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_NETINET6_IP6_MROUTE_H_ */
|
||||
|
@ -353,7 +353,9 @@ struct ip6aux *ip6_addaux __P((struct mbuf *));
|
||||
struct ip6aux *ip6_findaux __P((struct mbuf *));
|
||||
void ip6_delaux __P((struct mbuf *));
|
||||
|
||||
int ip6_mforward __P((struct ip6_hdr *, struct ifnet *, struct mbuf *));
|
||||
extern int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *,
|
||||
struct mbuf *);
|
||||
|
||||
int ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *,
|
||||
u_int32_t *));
|
||||
void ip6_savecontrol __P((struct inpcb *, struct mbuf *, struct mbuf **));
|
||||
|
@ -121,6 +121,18 @@ extern u_long rip_recvspace;
|
||||
|
||||
struct rip6stat rip6stat;
|
||||
|
||||
/*
|
||||
* Hooks for multicast forwarding.
|
||||
*/
|
||||
|
||||
struct socket *ip6_mrouter;
|
||||
|
||||
int (*ip6_mrouter_set)(struct socket *, struct sockopt *);
|
||||
int (*ip6_mrouter_get)(struct socket *, struct sockopt *);
|
||||
int (*ip6_mrouter_done)(void);
|
||||
int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *);
|
||||
int (*mrt6_ioctl)(int, caddr_t);
|
||||
|
||||
/*
|
||||
* Setup generic address and protocol structures
|
||||
* for raw_input routine, then pass them along with
|
||||
@ -507,7 +519,8 @@ rip6_ctloutput(so, sopt)
|
||||
case MRT6_ADD_MFC:
|
||||
case MRT6_DEL_MFC:
|
||||
case MRT6_PIM:
|
||||
error = ip6_mrouter_get(so, sopt);
|
||||
error = ip6_mrouter_get ? ip6_mrouter_get(so, sopt) :
|
||||
EOPNOTSUPP;
|
||||
break;
|
||||
case IPV6_CHECKSUM:
|
||||
error = ip6_raw_ctloutput(so, sopt);
|
||||
@ -527,7 +540,8 @@ rip6_ctloutput(so, sopt)
|
||||
case MRT6_ADD_MFC:
|
||||
case MRT6_DEL_MFC:
|
||||
case MRT6_PIM:
|
||||
error = ip6_mrouter_set(so, sopt);
|
||||
error = ip6_mrouter_set ? ip6_mrouter_set(so, sopt) :
|
||||
EOPNOTSUPP;
|
||||
break;
|
||||
case IPV6_CHECKSUM:
|
||||
error = ip6_raw_ctloutput(so, sopt);
|
||||
@ -587,9 +601,9 @@ rip6_detach(struct socket *so)
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("rip6_detach: inp == NULL"));
|
||||
|
||||
/* xxx: RSVP */
|
||||
if (so == ip6_mrouter)
|
||||
if (so == ip6_mrouter && ip6_mrouter_done)
|
||||
ip6_mrouter_done();
|
||||
/* xxx: RSVP */
|
||||
INP_INFO_WLOCK(&ripcbinfo);
|
||||
INP_LOCK(inp);
|
||||
if (inp->in6p_icmp6filt) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user