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:
Bruce M Simpson 2007-02-24 11:38:47 +00:00
parent ceca3a3873
commit 6be2e366d6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=166938
10 changed files with 171 additions and 35 deletions

View File

@ -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

View File

@ -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>

View File

@ -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(struct mbuf *m, int off)
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;
}

View File

@ -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) {

View File

@ -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

View File

@ -696,7 +696,8 @@ ip6_input(m)
* 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;

View File

@ -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;

View File

@ -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_ */

View File

@ -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 **));

View File

@ -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) {