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:
parent
1975dc405a
commit
443fc3176d
7
UPDATING
7
UPDATING
@ -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
|
||||
|
19
sys/modules/ip6_mroute_mod/Makefile
Normal file
19
sys/modules/ip6_mroute_mod/Makefile
Normal 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>
|
@ -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
@ -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 */
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user