Introduce a number of changes to the MROUTING code.

This is purely a forwarding plane cleanup; no control plane
code is involved.

Summary:
 * Split IPv4 and IPv6 MROUTING support. The static compile-time
   kernel option remains the same, however, the modules may now
   be built for IPv4 and IPv6 separately as ip_mroute_mod and
   ip6_mroute_mod.
 * Clean up the IPv4 multicast forwarding code to use BSD queue
   and hash table constructs. Don't build our own timer abstractions
   when ratecheck() and timevalclear() etc will do.
 * Expose the multicast forwarding cache (MFC) and virtual interface
   table (VIF) as sysctls, to reduce netstat's dependence on libkvm
   for this information for running kernels.
   * bandwidth meters however still require libkvm.
 * Make the MFC hash table size a boot/load-time tunable ULONG,
   net.inet.ip.mfchashsize (defaults to 256).
 * Remove unused members from struct vif and struct mfc.
 * Kill RSVP support, as no current RSVP implementation uses it.
   These stubs could be moved to raw_ip.c.
 * Don't share locks or initialization between IPv4 and IPv6.
 * Don't use a static struct route_in6 in ip6_mroute.c.
   The v6 code is still using a cached struct route_in6, this is
   moved to mif6 for the time being.
 * More cleanup remains to be merged from ip_mroute.c to ip6_mroute.c.

v4 path tested using ports/net/mcast-tools.
v6 changes are mostly mechanical locking and *have not* been tested.
As these changes partially break some kernel ABIs, they will not
be MFCed. There is a lot more work to be done here.

Reviewed by:	Pavlin Radoslavov
This commit is contained in:
Bruce M Simpson 2009-03-19 01:43:03 +00:00
parent 1975dc405a
commit 443fc3176d
10 changed files with 904 additions and 891 deletions

View File

@ -22,6 +22,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 8.x IS SLOW:
to maximize performance. (To disable malloc debugging, run
ln -s aj /etc/malloc.conf.)
20090319:
The multicast forwarding code has been cleaned up. netstat(1)
only relies on KVM now for printing bandwidth upcall meters.
The IPv4 and IPv6 modules are split into ip_mroute_mod and
ip6_mroute_mod respectively. The config(5) options for statically
compiling this code remain the same, i.e. 'options MROUTING'.
20090315:
Support for the IFF_NEEDSGIANT network interface flag has been
removed, which means that non-MPSAFE network device drivers are no

View File

@ -0,0 +1,19 @@
# $FreeBSD$
.include <bsd.own.mk>
.PATH: ${.CURDIR}/../../netinet6
KMOD= ip6_mroute
SRCS= ip6_mroute.c
SRCS+= opt_inet6.h opt_mac.h opt_mrouting.h
.if !defined(KERNBUILDDIR)
opt_inet6.h:
echo "#define INET6 1" > ${.TARGET}
opt_mrouting.h:
echo "#define MROUTING 1" > ${.TARGET}
.endif
.include <bsd.kmod.mk>

View File

@ -8,21 +8,12 @@ KMOD= ip_mroute
SRCS= ip_mroute.c
SRCS+= opt_inet.h opt_mac.h opt_mrouting.h opt_route.h
SRCS+= opt_inet6.h
.if ${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}
.if ${MK_INET6_SUPPORT} != "no"
opt_inet6.h:
echo "#define INET6 1" > ${.TARGET}
.endif
.endif
.include <bsd.kmod.mk>

File diff suppressed because it is too large Load Diff

View File

@ -70,9 +70,6 @@
#define MRT_ADD_BW_UPCALL 111 /* create bandwidth monitor */
#define MRT_DEL_BW_UPCALL 112 /* delete bandwidth monitor */
#define GET_TIME(t) microtime(&t)
/*
* Types and macros for handling bitmaps with one bit per virtual interface.
*/
@ -253,8 +250,6 @@ struct sioc_vif_req {
struct vif {
u_char v_flags; /* VIFF_ flags defined above */
u_char v_threshold; /* min ttl required to forward on vif*/
u_int v_rate_limit; /* ignored; kept for compatibility */
struct tbf *v_tbf; /* ignored; kept for compatibility */
struct in_addr v_lcl_addr; /* local interface address */
struct in_addr v_rmt_addr; /* remote address (tunnels only) */
struct ifnet *v_ifp; /* pointer to interface */
@ -263,16 +258,13 @@ struct vif {
u_long v_bytes_in; /* # bytes in on interface */
u_long v_bytes_out; /* # bytes out on interface */
struct route v_route; /* cached route */
u_int v_rsvp_on; /* RSVP listening on this vif */
struct socket *v_rsvpd; /* RSVP daemon socket */
};
/*
* The kernel's multicast forwarding cache entry structure
* (A field for the type of service (mfc_tos) is to be added
* at a future point)
*/
struct mfc {
LIST_ENTRY(mfc) mfc_hash;
struct in_addr mfc_origin; /* IP origin of mcasts */
struct in_addr mfc_mcastgrp; /* multicast group associated*/
vifi_t mfc_parent; /* incoming vif */
@ -282,11 +274,11 @@ struct mfc {
u_long mfc_wrong_if; /* wrong if for src-grp */
int mfc_expire; /* time to clean entry up */
struct timeval mfc_last_assert; /* last time I sent an assert*/
struct rtdetq *mfc_stall; /* q of packets awaiting mfc */
struct mfc *mfc_next; /* next mfc entry */
uint8_t mfc_flags[MAXVIFS]; /* the MRT_MFC_FLAGS_* flags */
struct in_addr mfc_rp; /* the RP address */
struct bw_meter *mfc_bw_meter; /* list of bandwidth meters */
u_long mfc_nstall; /* # of packets awaiting mfc */
TAILQ_HEAD(, rtdetq) mfc_stall; /* q of packets awaiting mfc */
};
/*
@ -311,19 +303,11 @@ struct igmpmsg {
* Argument structure used for pkt info. while upcall is made
*/
struct rtdetq {
TAILQ_ENTRY(rtdetq) rte_link;
struct mbuf *m; /* A copy of the packet */
struct ifnet *ifp; /* Interface pkt came in on */
vifi_t xmt_vif; /* Saved copy of imo_multicast_vif */
struct rtdetq *next; /* Next in list of packets */
};
#define MFCTBLSIZ 256
#if (MFCTBLSIZ & (MFCTBLSIZ - 1)) == 0 /* from sys:route.h */
#define MFCHASHMOD(h) ((h) & (MFCTBLSIZ - 1))
#else
#define MFCHASHMOD(h) ((h) % MFCTBLSIZ)
#endif
#define MAX_UPQ 4 /* max. no of pkts in upcall Q */
/*

View File

@ -92,6 +92,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/protosw.h>
#include <sys/signalvar.h>
#include <sys/socket.h>
@ -114,6 +115,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in_var.h>
#include <netinet/icmp6.h>
#include <netinet/vinet.h>
#include <netinet/ip_encap.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@ -130,20 +132,18 @@ static MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry");
/* XXX: this is a very common idiom; move to <sys/mbuf.h> ? */
#define M_HASCL(m) ((m)->m_flags & M_EXT)
static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
static void pim6_init(void);
static int set_pim6(int *);
static int socket_send __P((struct socket *, struct mbuf *,
struct sockaddr_in6 *));
static int register_send __P((struct ip6_hdr *, struct mif6 *,
struct mbuf *));
static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
static void pim6_init(void);
static int register_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
static int set_pim6(int *);
static int socket_send(struct socket *, struct mbuf *,
struct sockaddr_in6 *);
extern struct domain inet6domain;
/* XXX: referenced from ip_mroute.c for dynamically loading this code. */
struct ip6protosw in6_pim_protosw = {
static const struct encaptab *pim6_encap_cookie;
static const struct ip6protosw in6_pim_protosw = {
.pr_type = SOCK_RAW,
.pr_domain = &inet6domain,
.pr_protocol = IPPROTO_PIM,
@ -154,6 +154,7 @@ struct ip6protosw in6_pim_protosw = {
.pr_init = pim6_init,
.pr_usrreqs = &rip6_usrreqs
};
static int pim6_encapcheck(const struct mbuf *, int, int, void *);
#ifdef VIMAGE_GLOBALS
static int ip6_mrouter_ver;
@ -171,18 +172,48 @@ SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW,
#define NO_RTE_FOUND 0x1
#define RTE_FOUND 0x2
static struct mtx mrouter6_mtx;
#define MROUTER6_LOCK() mtx_lock(&mrouter6_mtx)
#define MROUTER6_UNLOCK() mtx_unlock(&mrouter6_mtx)
#define MROUTER6_LOCK_ASSERT() do { \
mtx_assert(&mrouter6_mtx, MA_OWNED); \
NET_ASSERT_GIANT(); \
} while (0)
#define MROUTER6_LOCK_INIT() \
mtx_init(&mrouter6_mtx, "IPv6 multicast forwarding", NULL, MTX_DEF)
#define MROUTER6_LOCK_DESTROY() mtx_destroy(&mrouter6_mtx)
static 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], "
"IPv6 Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], "
"netinet6/ip6_mroute.h)");
static struct mtx mfc6_mtx;
#define MFC6_LOCK() mtx_lock(&mfc6_mtx)
#define MFC6_UNLOCK() mtx_unlock(&mfc6_mtx)
#define MFC6_LOCK_ASSERT() do { \
mtx_assert(&mfc6_mtx, MA_OWNED); \
NET_ASSERT_GIANT(); \
} while (0)
#define MFC6_LOCK_INIT() \
mtx_init(&mfc6_mtx, "IPv6 multicast forwarding cache", NULL, MTX_DEF)
#define MFC6_LOCK_DESTROY() mtx_destroy(&mfc6_mtx)
static 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)");
&mif6table, sizeof(mif6table), "S,mif6[MAXMIFS]",
"IPv6 Multicast Interfaces (struct mif6[MAXMIFS], netinet6/ip6_mroute.h)");
static struct mtx mif6_mtx;
#define MIF6_LOCK() mtx_lock(&mif6_mtx)
#define MIF6_UNLOCK() mtx_unlock(&mif6_mtx)
#define MIF6_LOCK_ASSERT() mtx_assert(&mif6_mtx, MA_OWNED)
#define MIF6_LOCK_INIT() \
mtx_init(&mif6_mtx, "IPv6 multicast interfaces", NULL, MTX_DEF)
#define MIF6_LOCK_DESTROY() mtx_destroy(&mif6_mtx)
#ifdef MRT6DEBUG
#ifdef VIMAGE_GLOBALS
@ -200,11 +231,9 @@ static void expire_upcalls(void *);
#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */
#define UPCALL_EXPIRE 6 /* number of timeouts */
#ifdef INET
#ifdef MROUTING
extern struct socket *ip_mrouter;
#endif
#endif
/*
* XXX TODO: maintain a count to if_allmulti() calls in struct ifnet.
*/
/*
* 'Interfaces' associated with decapsulator (so we can tell
@ -298,21 +327,22 @@ static u_long upcall_data[UPCALL_MAX + 1];
static void collate();
#endif /* UPCALL_TIMING */
static int get_sg_cnt(struct sioc_sg_req6 *);
static int get_mif6_cnt(struct sioc_mif_req6 *);
static int ip6_mrouter_init(struct socket *, int, int);
static int add_m6if(struct mif6ctl *);
static int del_m6if(mifi_t *);
static int add_m6fc(struct mf6cctl *);
static int add_m6if(struct mif6ctl *);
static int del_m6fc(struct mf6cctl *);
static int del_m6if(mifi_t *);
static int del_m6if_locked(mifi_t *);
static int get_mif6_cnt(struct sioc_mif_req6 *);
static int get_sg_cnt(struct sioc_sg_req6 *);
static struct callout expire_upcalls_ch;
int X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m);
int X_ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
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);
int X_ip6_mrouter_set(struct socket *, struct sockopt *);
int X_ip6_mrouter_get(struct socket *, struct sockopt *);
int X_mrt6_ioctl(int, caddr_t);
static void
pim6_init(void)
@ -419,14 +449,24 @@ X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
int
X_mrt6_ioctl(int cmd, caddr_t data)
{
int ret;
ret = EINVAL;
switch (cmd) {
case SIOCGETSGCNT_IN6:
return (get_sg_cnt((struct sioc_sg_req6 *)data));
ret = get_sg_cnt((struct sioc_sg_req6 *)data);
break;
case SIOCGETMIFCNT_IN6:
return (get_mif6_cnt((struct sioc_mif_req6 *)data));
ret = get_mif6_cnt((struct sioc_mif_req6 *)data);
break;
default:
return (EINVAL);
break;
}
return (ret);
}
/*
@ -436,22 +476,24 @@ static int
get_sg_cnt(struct sioc_sg_req6 *req)
{
struct mf6c *rt;
int s;
int ret;
ret = 0;
MFC6_LOCK();
s = splnet();
MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
splx(s);
if (rt != NULL) {
if (rt == NULL) {
ret = ESRCH;
} else {
req->pktcnt = rt->mf6c_pkt_cnt;
req->bytecnt = rt->mf6c_byte_cnt;
req->wrong_if = rt->mf6c_wrong_if;
} else
return (ESRCH);
#if 0
req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
#endif
}
return (0);
MFC6_UNLOCK();
return (ret);
}
/*
@ -460,17 +502,26 @@ get_sg_cnt(struct sioc_sg_req6 *req)
static int
get_mif6_cnt(struct sioc_mif_req6 *req)
{
mifi_t mifi = req->mifi;
mifi_t mifi;
int ret;
if (mifi >= nummifs)
return (EINVAL);
ret = 0;
mifi = req->mifi;
req->icount = mif6table[mifi].m6_pkt_in;
req->ocount = mif6table[mifi].m6_pkt_out;
req->ibytes = mif6table[mifi].m6_bytes_in;
req->obytes = mif6table[mifi].m6_bytes_out;
MIF6_LOCK();
return (0);
if (mifi >= nummifs) {
ret = EINVAL;
} else {
req->icount = mif6table[mifi].m6_pkt_in;
req->ocount = mif6table[mifi].m6_pkt_out;
req->ibytes = mif6table[mifi].m6_bytes_in;
req->obytes = mif6table[mifi].m6_bytes_out;
}
MIF6_UNLOCK();
return (ret);
}
static int
@ -507,8 +558,12 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
if (v != 1)
return (ENOPROTOOPT);
if (ip6_mrouter != NULL)
MROUTER6_LOCK();
if (ip6_mrouter != NULL) {
MROUTER6_UNLOCK();
return (EADDRINUSE);
}
ip6_mrouter = so;
V_ip6_mrouter_ver = cmd;
@ -522,6 +577,8 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
expire_upcalls, NULL);
MROUTER6_UNLOCK();
#ifdef MRT6DEBUG
if (V_mrt6debug)
log(LOG_DEBUG, "ip6_mrouter_init\n");
@ -531,7 +588,7 @@ ip6_mrouter_init(struct socket *so, int v, int cmd)
}
/*
* Disable multicast routing
* Disable IPv6 multicast forwarding.
*/
int
X_ip6_mrouter_done(void)
@ -541,31 +598,22 @@ X_ip6_mrouter_done(void)
int i;
struct mf6c *rt;
struct rtdetq *rte;
int s;
s = splnet();
MROUTER6_LOCK();
if (ip6_mrouter == NULL) {
MROUTER6_UNLOCK();
return (EINVAL);
}
/*
* For each phyint in use, disable promiscuous reception of all IPv6
* multicasts.
*/
#ifdef INET
#ifdef MROUTING
/*
* If there is still IPv4 multicast routing daemon,
* we remain interfaces to receive all muliticasted packets.
* XXX: there may be an interface in which the IPv4 multicast
* daemon is not interested...
*/
if (!V_ip_mrouter)
#endif
#endif
{
for (mifi = 0; mifi < nummifs; mifi++) {
if (mif6table[mifi].m6_ifp &&
!(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
if_allmulti(mif6table[mifi].m6_ifp, 0);
}
for (mifi = 0; mifi < nummifs; mifi++) {
if (mif6table[mifi].m6_ifp &&
!(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
if_allmulti(mif6table[mifi].m6_ifp, 0);
}
}
bzero((caddr_t)mif6table, sizeof(mif6table));
@ -578,6 +626,7 @@ X_ip6_mrouter_done(void)
/*
* Free all multicast forwarding cache entries.
*/
MFC6_LOCK();
for (i = 0; i < MF6CTBLSIZ; i++) {
rt = mf6ctable[i];
while (rt) {
@ -595,8 +644,8 @@ X_ip6_mrouter_done(void)
free(frt, M_MRTABLE6);
}
}
bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
MFC6_UNLOCK();
/*
* Reset register interface
@ -611,7 +660,7 @@ X_ip6_mrouter_done(void)
ip6_mrouter = NULL;
V_ip6_mrouter_ver = 0;
splx(s);
MROUTER6_UNLOCK();
#ifdef MRT6DEBUG
if (V_mrt6debug)
@ -632,15 +681,24 @@ add_m6if(struct mif6ctl *mifcp)
INIT_VNET_NET(curvnet);
struct mif6 *mifp;
struct ifnet *ifp;
int error, s;
int error;
if (mifcp->mif6c_mifi >= MAXMIFS)
MIF6_LOCK();
if (mifcp->mif6c_mifi >= MAXMIFS) {
MIF6_UNLOCK();
return (EINVAL);
}
mifp = mif6table + mifcp->mif6c_mifi;
if (mifp->m6_ifp)
if (mifp->m6_ifp != NULL) {
MIF6_UNLOCK();
return (EADDRINUSE); /* XXX: is it appropriate? */
if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index)
}
if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index) {
MIF6_UNLOCK();
return (ENXIO);
}
ifp = ifnet_byindex(mifcp->mif6c_pifi);
if (mifcp->mif6c_flags & MIFF_REGISTER) {
@ -661,21 +719,20 @@ add_m6if(struct mif6ctl *mifcp)
} else {
ifp = multicast_register_if6;
}
} /* if REGISTER */
else {
} else {
/* Make sure the interface supports multicast */
if ((ifp->if_flags & IFF_MULTICAST) == 0)
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
MIF6_UNLOCK();
return (EOPNOTSUPP);
}
s = splnet();
error = if_allmulti(ifp, 1);
splx(s);
if (error)
if (error) {
MIF6_UNLOCK();
return (error);
}
}
s = splnet();
mifp->m6_flags = mifcp->mif6c_flags;
mifp->m6_ifp = ifp;
@ -684,12 +741,14 @@ add_m6if(struct mif6ctl *mifcp)
mifp->m6_pkt_out = 0;
mifp->m6_bytes_in = 0;
mifp->m6_bytes_out = 0;
splx(s);
bzero(&mifp->m6_route, sizeof(mifp->m6_route));
/* Adjust nummifs up if the mifi is higher than nummifs */
if (nummifs <= mifcp->mif6c_mifi)
nummifs = mifcp->mif6c_mifi + 1;
MIF6_UNLOCK();
#ifdef MRT6DEBUG
if (V_mrt6debug)
log(LOG_DEBUG,
@ -705,27 +764,22 @@ add_m6if(struct mif6ctl *mifcp)
* Delete a mif from the mif table
*/
static int
del_m6if(mifi_t *mifip)
del_m6if_locked(mifi_t *mifip)
{
struct mif6 *mifp = mif6table + *mifip;
mifi_t mifi;
struct ifnet *ifp;
int s;
MIF6_LOCK_ASSERT();
if (*mifip >= nummifs)
return (EINVAL);
if (mifp->m6_ifp == NULL)
return (EINVAL);
s = splnet();
if (!(mifp->m6_flags & MIFF_REGISTER)) {
/*
* XXX: what if there is yet IPv4 multicast daemon
* using the interface?
*/
/* XXX: TODO: Maintain an ALLMULTI refcount in struct ifnet. */
ifp = mifp->m6_ifp;
if_allmulti(ifp, 0);
} else {
if (reg_mif_num != (mifi_t)-1 &&
@ -745,8 +799,6 @@ del_m6if(mifi_t *mifip)
break;
nummifs = mifi;
splx(s);
#ifdef MRT6DEBUG
if (V_mrt6debug)
log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs);
@ -755,6 +807,18 @@ del_m6if(mifi_t *mifip)
return (0);
}
static int
del_m6if(mifi_t *mifip)
{
int cc;
MIF6_LOCK();
cc = del_m6if_locked(mifip);
MIF6_UNLOCK();
return (cc);
}
/*
* Add an mfc entry
*/
@ -765,9 +829,10 @@ add_m6fc(struct mf6cctl *mfccp)
u_long hash;
struct rtdetq *rte;
u_short nstl;
int s;
char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
MFC6_LOCK();
MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
mfccp->mf6cc_mcastgrp.sin6_addr, rt);
@ -783,17 +848,16 @@ add_m6fc(struct mf6cctl *mfccp)
}
#endif
s = splnet();
rt->mf6c_parent = mfccp->mf6cc_parent;
rt->mf6c_ifset = mfccp->mf6cc_ifset;
splx(s);
MFC6_UNLOCK();
return (0);
}
/*
* Find the entry for which the upcall was made and update
*/
s = splnet();
hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
mfccp->mf6cc_mcastgrp.sin6_addr);
for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
@ -891,7 +955,7 @@ add_m6fc(struct mf6cctl *mfccp)
rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6,
M_NOWAIT);
if (rt == NULL) {
splx(s);
MFC6_UNLOCK();
return (ENOBUFS);
}
@ -912,7 +976,8 @@ add_m6fc(struct mf6cctl *mfccp)
mf6ctable[hash] = rt;
}
}
splx(s);
MFC6_UNLOCK();
return (0);
}
@ -953,7 +1018,6 @@ del_m6fc(struct mf6cctl *mfccp)
struct mf6c *rt;
struct mf6c **nptr;
u_long hash;
int s;
origin = mfccp->mf6cc_origin;
mcastgrp = mfccp->mf6cc_mcastgrp;
@ -968,7 +1032,7 @@ del_m6fc(struct mf6cctl *mfccp)
}
#endif
s = splnet();
MFC6_LOCK();
nptr = &mf6ctable[hash];
while ((rt = *nptr) != NULL) {
@ -982,14 +1046,14 @@ del_m6fc(struct mf6cctl *mfccp)
nptr = &rt->mf6c_next;
}
if (rt == NULL) {
splx(s);
MFC6_UNLOCK();
return (EADDRNOTAVAIL);
}
*nptr = rt->mf6c_next;
free(rt, M_MRTABLE6);
splx(s);
MFC6_UNLOCK();
return (0);
}
@ -1035,7 +1099,6 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
struct mf6c *rt;
struct mif6 *mifp;
struct mbuf *mm;
int s;
mifi_t mifi;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
@ -1078,15 +1141,16 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
return (0);
}
MFC6_LOCK();
/*
* Determine forwarding mifs from the forwarding cache table
*/
s = splnet();
MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
/* Entry exists, so forward if necessary */
if (rt) {
splx(s);
MFC6_UNLOCK();
return (ip6_mdq(m, ifp, rt));
} else {
/*
@ -1120,7 +1184,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE6,
M_NOWAIT);
if (rte == NULL) {
splx(s);
MFC6_UNLOCK();
return (ENOBUFS);
}
mb0 = m_copy(m, 0, M_COPYALL);
@ -1133,7 +1197,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
if (mb0 == NULL) {
free(rte, M_MRTABLE6);
splx(s);
MFC6_UNLOCK();
return (ENOBUFS);
}
@ -1160,7 +1224,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
if (rt == NULL) {
free(rte, M_MRTABLE6);
m_freem(mb0);
splx(s);
MFC6_UNLOCK();
return (ENOBUFS);
}
/*
@ -1173,7 +1237,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
free(rte, M_MRTABLE6);
m_freem(mb0);
free(rt, M_MRTABLE6);
splx(s);
MFC6_UNLOCK();
return (ENOBUFS);
}
@ -1203,7 +1267,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
free(rte, M_MRTABLE6);
m_freem(mb0);
free(rt, M_MRTABLE6);
splx(s);
MFC6_UNLOCK();
return (EINVAL);
}
@ -1236,7 +1300,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
free(rte, M_MRTABLE6);
m_freem(mb0);
free(rt, M_MRTABLE6);
splx(s);
MFC6_UNLOCK();
return (ENOBUFS);
}
@ -1269,7 +1333,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
mrt6stat.mrt6s_upq_ovflw++;
free(rte, M_MRTABLE6);
m_freem(mb0);
splx(s);
MFC6_UNLOCK();
return (0);
}
@ -1284,7 +1348,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
rte->t = tp;
#endif /* UPCALL_TIMING */
splx(s);
MFC6_UNLOCK();
return (0);
}
@ -1300,9 +1364,8 @@ expire_upcalls(void *unused)
struct rtdetq *rte;
struct mf6c *mfc, **nptr;
int i;
int s;
s = splnet();
MFC6_LOCK();
for (i = 0; i < MF6CTBLSIZ; i++) {
if (n6expire[i] == 0)
continue;
@ -1346,7 +1409,7 @@ expire_upcalls(void *unused)
}
}
}
splx(s);
MFC6_UNLOCK();
callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
expire_upcalls, NULL);
}
@ -1540,8 +1603,6 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
struct mbuf *mb_copy;
struct ifnet *ifp = mifp->m6_ifp;
int error = 0;
int s = splnet(); /* needs to protect static "ro" below. */
static struct route_in6 ro;
struct in6_multi *in6m;
struct sockaddr_in6 *dst6;
u_long linkmtu;
@ -1556,7 +1617,6 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
(M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
if (mb_copy == NULL) {
splx(s);
return;
}
/* set MCAST flag to the outgoing packet */
@ -1576,7 +1636,7 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
/* XXX: ip6_output will override ip6->ip6_hlim */
im6o.im6o_multicast_hlim = ip6->ip6_hlim;
im6o.im6o_multicast_loop = 1;
error = ip6_output(mb_copy, NULL, &ro,
error = ip6_output(mb_copy, NULL, &mifp->m6_route,
IPV6_FORWARDING, &im6o, NULL, NULL);
#ifdef MRT6DEBUG
@ -1584,7 +1644,6 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
mifp - mif6table, error);
#endif
splx(s);
return;
}
@ -1592,13 +1651,13 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
* If we belong to the destination multicast group
* on the outgoing interface, loop back a copy.
*/
dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
dst6 = &mifp->m6_route.ro_dst;
IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
if (in6m != NULL) {
dst6->sin6_len = sizeof(struct sockaddr_in6);
dst6->sin6_family = AF_INET6;
dst6->sin6_addr = ip6->ip6_dst;
ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst);
ip6_mloopback(ifp, m, &mifp->m6_route.ro_dst);
}
/*
* Put the packet into the sending queue of the outgoing interface
@ -1614,7 +1673,7 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
* we need no ND for a multicast forwarded packet...right?
*/
error = (*ifp->if_output)(ifp, mb_copy,
(struct sockaddr *)&ro.ro_dst, NULL);
(struct sockaddr *)&mifp->m6_route.ro_dst, NULL);
#ifdef MRT6DEBUG
if (V_mrt6debug & DEBUG_XMIT)
log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
@ -1645,8 +1704,6 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
m_freem(mb_copy); /* simply discard the packet */
}
}
splx(s);
}
static int
@ -1714,6 +1771,24 @@ register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
return (0);
}
/*
* pim6_encapcheck() is called by the encap6_input() path at runtime to
* determine if a packet is for PIM; allowing PIM to be dynamically loaded
* into the kernel.
*/
static int
pim6_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 sparse mode hook
* Receives the pim control messages, and passes them up to the listening
@ -1951,3 +2026,66 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
rip6_input(&m, offp, proto);
return (IPPROTO_DONE);
}
static int
ip6_mroute_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
MROUTER6_LOCK_INIT();
MFC6_LOCK_INIT();
MIF6_LOCK_INIT();
pim6_encap_cookie = encap_attach_func(AF_INET6, IPPROTO_PIM,
pim6_encapcheck,
(const struct protosw *)&in6_pim_protosw, NULL);
if (pim6_encap_cookie == NULL) {
printf("ip6_mroute: unable to attach pim6 encap\n");
MIF6_LOCK_DESTROY();
MFC6_LOCK_DESTROY();
MROUTER6_LOCK_DESTROY();
return (EINVAL);
}
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;
break;
case MOD_UNLOAD:
if (ip6_mrouter != NULL)
return EINVAL;
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;
MIF6_LOCK_DESTROY();
MFC6_LOCK_DESTROY();
MROUTER6_LOCK_DESTROY();
break;
default:
return (EOPNOTSUPP);
}
return (0);
}
static moduledata_t ip6_mroutemod = {
"ip6_mroute",
ip6_mroute_modevent,
0
};
DECLARE_MODULE(ip6_mroute, ip6_mroutemod, SI_SUB_PSEUDO, SI_ORDER_ANY);

View File

@ -212,7 +212,7 @@ struct mif6 {
u_quad_t m6_pkt_out; /* # pkts out on interface */
u_quad_t m6_bytes_in; /* # bytes in on interface */
u_quad_t m6_bytes_out; /* # bytes out on interface */
struct route_in6 m6_route;/* cached route if this is a tunnel */
struct route_in6 m6_route; /* cached route */
#ifdef notyet
u_int m6_rsvp_on; /* RSVP listening on this vif */
struct socket *m6_rsvpd; /* RSVP daemon socket */

View File

@ -82,8 +82,8 @@ static struct nlist nl[] = {
{ .n_name = "_rt_tables"},
#define N_MRTSTAT 3
{ .n_name = "_mrtstat" },
#define N_MFCTABLE 4
{ .n_name = "_mfctable" },
#define N_MFCHASHTBL 4
{ .n_name = "_mfchashtbl" },
#define N_VIFTABLE 5
{ .n_name = "_viftable" },
#define N_IPX 6
@ -182,6 +182,8 @@ static struct nlist nl[] = {
{ .n_name = "_rip6stat" },
#define N_SCTPSTAT 53
{ .n_name = "_sctpstat" },
#define N_MFCTABLESIZE 54
{ .n_name = "_mfctablesize" },
{ .n_name = NULL },
};
@ -550,7 +552,8 @@ main(int argc, char *argv[])
#endif
} else {
if (af == AF_INET || af == AF_UNSPEC)
mroutepr(nl[N_MFCTABLE].n_value,
mroutepr(nl[N_MFCHASHTBL].n_value,
nl[N_MFCTABLESIZE].n_value,
nl[N_VIFTABLE].n_value);
#ifdef INET6
if (af == AF_INET6 || af == AF_UNSPEC)

View File

@ -67,124 +67,9 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include "netstat.h"
static void print_bw_meter(struct bw_meter *bw_meter, int *banner_printed);
void
mroutepr(u_long mfcaddr, u_long vifaddr)
{
struct mfc *mfctable[MFCTBLSIZ];
struct vif viftable[MAXVIFS];
struct mfc mfc, *m;
struct vif *v;
vifi_t vifi;
int i;
int banner_printed;
int saved_numeric_addr;
vifi_t maxvif = 0;
size_t len;
len = sizeof(mfctable);
if (live) {
if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL,
0) < 0) {
warn("sysctl: net.inet.ip.mfctable");
return;
}
} else
kread(mfcaddr, (char *)mfctable, sizeof(mfctable));
len = sizeof(viftable);
if (live) {
if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL,
0) < 0) {
warn("sysctl: net.inet.ip.viftable");
return;
}
} else
kread(vifaddr, (char *)viftable, sizeof(viftable));
saved_numeric_addr = numeric_addr;
numeric_addr = 1;
banner_printed = 0;
for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
if (v->v_lcl_addr.s_addr == 0)
continue;
maxvif = vifi;
if (!banner_printed) {
printf("\nIPv4 Virtual Interface Table\n"
" Vif Thresh Rate Local-Address "
"Remote-Address Pkts-In Pkts-Out\n");
banner_printed = 1;
}
printf(" %2u %6u %4d %-15.15s",
/* opposite math of add_vif() */
vifi, v->v_threshold, v->v_rate_limit * 1000 / 1024,
routename(v->v_lcl_addr.s_addr));
printf(" %-15.15s", (v->v_flags & VIFF_TUNNEL) ?
routename(v->v_rmt_addr.s_addr) : "");
printf(" %9lu %9lu\n", v->v_pkt_in, v->v_pkt_out);
}
if (!banner_printed)
printf("\nIPv4 Virtual Interface Table is empty\n");
banner_printed = 0;
for (i = 0; i < MFCTBLSIZ; ++i) {
m = mfctable[i];
while(m) {
/* XXX KVM */
kread((u_long)m, (char *)&mfc, sizeof mfc);
if (!banner_printed) {
printf("\nIPv4 Multicast Forwarding Table\n"
" Origin Group "
" Packets In-Vif Out-Vifs:Ttls\n");
banner_printed = 1;
}
printf(" %-15.15s", routename(mfc.mfc_origin.s_addr));
printf(" %-15.15s", routename(mfc.mfc_mcastgrp.s_addr));
printf(" %9lu", mfc.mfc_pkt_cnt);
printf(" %3d ", mfc.mfc_parent);
for (vifi = 0; vifi <= maxvif; vifi++) {
if (mfc.mfc_ttls[vifi] > 0)
printf(" %u:%u", vifi,
mfc.mfc_ttls[vifi]);
}
printf("\n");
/* Print the bw meter information */
{
struct bw_meter bw_meter, *bwm;
int banner_printed2 = 0;
bwm = mfc.mfc_bw_meter;
while (bwm) {
/* XXX KVM */
kread((u_long)bwm, (char *)&bw_meter,
sizeof bw_meter);
print_bw_meter(&bw_meter,
&banner_printed2);
bwm = bw_meter.bm_mfc_next;
}
#if 0 /* Don't ever print it? */
if (! banner_printed2)
printf("\n No Bandwidth Meters\n");
#endif
}
m = mfc.mfc_next;
}
}
if (!banner_printed)
printf("\nIPv4 Multicast Forwarding Table is empty\n");
printf("\n");
numeric_addr = saved_numeric_addr;
}
static void print_bw_meter(struct bw_meter *, int *);
static void print_mfc(struct mfc *, int, int *);
static void
print_bw_meter(struct bw_meter *bw_meter, int *banner_printed)
@ -262,6 +147,193 @@ print_bw_meter(struct bw_meter *bw_meter, int *banner_printed)
printf("\n");
}
static void
print_mfc(struct mfc *m, int maxvif, int *banner_printed)
{
struct bw_meter bw_meter, *bwm;
int bw_banner_printed;
int error;
vifi_t vifi;
bw_banner_printed = 0;
if (! *banner_printed) {
printf("\nIPv4 Multicast Forwarding Table\n"
" Origin Group "
" Packets In-Vif Out-Vifs:Ttls\n");
*banner_printed = 1;
}
printf(" %-15.15s", routename(m->mfc_origin.s_addr));
printf(" %-15.15s", routename(m->mfc_mcastgrp.s_addr));
printf(" %9lu", m->mfc_pkt_cnt);
printf(" %3d ", m->mfc_parent);
for (vifi = 0; vifi <= maxvif; vifi++) {
if (m->mfc_ttls[vifi] > 0)
printf(" %u:%u", vifi, m->mfc_ttls[vifi]);
}
printf("\n");
/*
* XXX We break the rules and try to use KVM to read the
* bandwidth meters, they are not retrievable via sysctl yet.
*/
bwm = m->mfc_bw_meter;
while (bwm != NULL) {
error = kread((u_long)bwm, (char *)&bw_meter,
sizeof(bw_meter));
if (error)
break;
print_bw_meter(&bw_meter, &bw_banner_printed);
bwm = bw_meter.bm_mfc_next;
}
}
void
mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl)
{
struct vif viftable[MAXVIFS];
struct vif *v;
struct mfc *m;
int banner_printed;
int saved_numeric_addr;
size_t len;
vifi_t vifi, maxvif;
saved_numeric_addr = numeric_addr;
numeric_addr = 1;
/*
* TODO:
* The VIF table will move to hanging off the struct if_info for
* each IPv4 configured interface. Currently it is statically
* allocated, and retrieved either using KVM or an opaque SYSCTL.
*
* This can't happen until the API documented in multicast(4)
* is itself refactored. The historical reason why VIFs use
* a separate ifindex space is entirely due to the legacy
* capability of the MROUTING code to create IPIP tunnels on
* the fly to support DVMRP. When gif(4) became available, this
* functionality was deprecated, as PIM does not use it.
*/
maxvif = 0;
len = sizeof(viftable);
if (live) {
if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL,
0) < 0) {
warn("sysctl: net.inet.ip.viftable");
return;
}
} else
kread(pviftbl, (char *)viftable, sizeof(viftable));
banner_printed = 0;
for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
if (v->v_lcl_addr.s_addr == 0)
continue;
maxvif = vifi;
if (!banner_printed) {
printf("\nIPv4 Virtual Interface Table\n"
" Vif Thresh Local-Address "
"Remote-Address Pkts-In Pkts-Out\n");
banner_printed = 1;
}
printf(" %2u %6u %-15.15s",
/* opposite math of add_vif() */
vifi, v->v_threshold,
routename(v->v_lcl_addr.s_addr));
printf(" %-15.15s", (v->v_flags & VIFF_TUNNEL) ?
routename(v->v_rmt_addr.s_addr) : "");
printf(" %9lu %9lu\n", v->v_pkt_in, v->v_pkt_out);
}
if (!banner_printed)
printf("\nIPv4 Virtual Interface Table is empty\n");
banner_printed = 0;
/*
* TODO:
* The MFC table will move into the AF_INET radix trie in future.
* In 8.x, it becomes a dynamically allocated structure referenced
* by a hashed LIST, allowing more than 256 entries w/o kernel tuning.
*
* If retrieved via opaque SYSCTL, the kernel will coalesce it into
* a static table for us.
* If retrieved via KVM, the hash list pointers must be followed.
*/
if (live) {
struct mfc *mfctable;
len = 0;
if (sysctlbyname("net.inet.ip.mfctable", NULL, &len, NULL,
0) < 0) {
warn("sysctl: net.inet.ip.mfctable");
return;
}
mfctable = malloc(len);
if (mfctable == NULL) {
warnx("malloc %lu bytes", (u_long)len);
return;
}
if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL,
0) < 0) {
free(mfctable);
warn("sysctl: net.inet.ip.mfctable");
return;
}
m = mfctable;
while (len >= sizeof(*m)) {
print_mfc(m++, maxvif, &banner_printed);
len -= sizeof(*m);
}
if (len != 0)
warnx("print_mfc: %d trailing bytes", len);
free(mfctable);
} else {
LIST_HEAD(, mfc) *mfchashtbl;
u_long i, mfctablesize;
struct mfc mfc;
int error;
error = kread(pmfctablesize, (char *)&mfctablesize,
sizeof(u_long));
if (error) {
warn("kread: mfctablesize");
return;
}
len = sizeof(*mfchashtbl) * mfctablesize;
mfchashtbl = malloc(len);
if (mfchashtbl == NULL) {
warnx("malloc %lu bytes", (u_long)len);
return;
}
kread(pmfchashtbl, (char *)&mfchashtbl, len);
for (i = 0; i < mfctablesize; i++) {
LIST_FOREACH(m, &mfchashtbl[i], mfc_hash) {
kread((u_long)m, (char *)&mfc, sizeof(mfc));
print_mfc(m, maxvif, &banner_printed);
}
}
free(mfchashtbl);
}
if (!banner_printed)
printf("\nIPv4 Multicast Forwarding Table is empty\n");
printf("\n");
numeric_addr = saved_numeric_addr;
}
void
mrt_stats(u_long mstaddr)
{

View File

@ -160,6 +160,6 @@ void tp_protopr(u_long, const char *, int, int);
void tp_inproto(u_long);
void tp_stats(caddr_t, caddr_t);
void mroutepr(u_long, u_long);
void mroutepr(u_long, u_long, u_long);
void mrt_stats(u_long);
void bpf_stats(char *);