Make IGMP stats per-cpu.
This commit is contained in:
parent
881a947288
commit
83dd106948
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: igmp.c,v 1.45 2007/04/25 00:11:18 dyoung Exp $ */
|
||||
/* $NetBSD: igmp.c,v 1.46 2008/04/15 16:02:03 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -40,7 +40,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.45 2007/04/25 00:11:18 dyoung Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.46 2008/04/15 16:02:03 thorpej Exp $");
|
||||
|
||||
#include "opt_mrouting.h"
|
||||
|
||||
@ -49,6 +49,8 @@ __KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.45 2007/04/25 00:11:18 dyoung Exp $");
|
||||
#include <sys/socket.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/percpu.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
@ -67,7 +69,16 @@ __KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.45 2007/04/25 00:11:18 dyoung Exp $");
|
||||
|
||||
POOL_INIT(igmp_rti_pool, sizeof(struct router_info), 0, 0, 0, "igmppl", NULL,
|
||||
IPL_SOFTNET);
|
||||
struct igmpstat igmpstat;
|
||||
|
||||
static percpu_t *igmpstat_percpu;
|
||||
|
||||
#define IGMP_STATINC(x) \
|
||||
do { \
|
||||
uint64_t *_igmps_ = percpu_getref(igmpstat_percpu); \
|
||||
_igmps_[x]++; \
|
||||
percpu_putref(igmpstat_percpu); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
int igmp_timers_are_running;
|
||||
static LIST_HEAD(, router_info) rti_head = LIST_HEAD_INITIALIZER(rti_head);
|
||||
|
||||
@ -139,6 +150,13 @@ rti_delete(struct ifnet *ifp) /* MUST be called at splsoftnet */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
igmp_init(void)
|
||||
{
|
||||
|
||||
igmpstat_percpu = percpu_alloc(sizeof(uint64_t) * IGMP_NSTATS);
|
||||
}
|
||||
|
||||
void
|
||||
igmp_input(struct mbuf *m, ...)
|
||||
{
|
||||
@ -161,7 +179,7 @@ igmp_input(struct mbuf *m, ...)
|
||||
proto = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
++igmpstat.igps_rcv_total;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_TOTAL);
|
||||
|
||||
/*
|
||||
* Validate lengths
|
||||
@ -169,14 +187,14 @@ igmp_input(struct mbuf *m, ...)
|
||||
minlen = iphlen + IGMP_MINLEN;
|
||||
ip_len = ntohs(ip->ip_len);
|
||||
if (ip_len < minlen) {
|
||||
++igmpstat.igps_rcv_tooshort;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_TOOSHORT);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
if (((m->m_flags & M_EXT) && (ip->ip_src.s_addr & IN_CLASSA_NET) == 0)
|
||||
|| m->m_len < minlen) {
|
||||
if ((m = m_pullup(m, minlen)) == 0) {
|
||||
++igmpstat.igps_rcv_tooshort;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_TOOSHORT);
|
||||
return;
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
@ -190,7 +208,7 @@ igmp_input(struct mbuf *m, ...)
|
||||
igmp = mtod(m, struct igmp *);
|
||||
/* No need to assert alignment here. */
|
||||
if (in_cksum(m, ip_len - iphlen)) {
|
||||
++igmpstat.igps_rcv_badsum;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_BADSUM);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
@ -200,7 +218,7 @@ igmp_input(struct mbuf *m, ...)
|
||||
switch (igmp->igmp_type) {
|
||||
|
||||
case IGMP_HOST_MEMBERSHIP_QUERY:
|
||||
++igmpstat.igps_rcv_queries;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_QUERIES);
|
||||
|
||||
if (ifp->if_flags & IFF_LOOPBACK)
|
||||
break;
|
||||
@ -213,7 +231,7 @@ igmp_input(struct mbuf *m, ...)
|
||||
rti->rti_age = 0;
|
||||
|
||||
if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) {
|
||||
++igmpstat.igps_rcv_badqueries;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_BADQUERIES);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
@ -238,7 +256,7 @@ igmp_input(struct mbuf *m, ...)
|
||||
}
|
||||
} else {
|
||||
if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
|
||||
++igmpstat.igps_rcv_badqueries;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_BADQUERIES);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
@ -288,14 +306,14 @@ igmp_input(struct mbuf *m, ...)
|
||||
break;
|
||||
|
||||
case IGMP_v1_HOST_MEMBERSHIP_REPORT:
|
||||
++igmpstat.igps_rcv_reports;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_REPORTS);
|
||||
|
||||
if (ifp->if_flags & IFF_LOOPBACK)
|
||||
break;
|
||||
|
||||
if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
|
||||
!in_hosteq(igmp->igmp_group, ip->ip_dst)) {
|
||||
++igmpstat.igps_rcv_badreports;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_BADREPORTS);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
@ -322,7 +340,7 @@ igmp_input(struct mbuf *m, ...)
|
||||
IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
|
||||
if (inm != NULL) {
|
||||
inm->inm_timer = 0;
|
||||
++igmpstat.igps_rcv_ourreports;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_OURREPORTS);
|
||||
|
||||
switch (inm->inm_state) {
|
||||
case IGMP_IDLE_MEMBER:
|
||||
@ -354,14 +372,14 @@ igmp_input(struct mbuf *m, ...)
|
||||
break;
|
||||
#endif
|
||||
|
||||
++igmpstat.igps_rcv_reports;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_REPORTS);
|
||||
|
||||
if (ifp->if_flags & IFF_LOOPBACK)
|
||||
break;
|
||||
|
||||
if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
|
||||
!in_hosteq(igmp->igmp_group, ip->ip_dst)) {
|
||||
++igmpstat.igps_rcv_badreports;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_BADREPORTS);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
@ -390,7 +408,7 @@ igmp_input(struct mbuf *m, ...)
|
||||
IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
|
||||
if (inm != NULL) {
|
||||
inm->inm_timer = 0;
|
||||
++igmpstat.igps_rcv_ourreports;
|
||||
IGMP_STATINC(IGMP_STAT_RCV_OURREPORTS);
|
||||
|
||||
switch (inm->inm_state) {
|
||||
case IGMP_DELAYING_MEMBER:
|
||||
@ -573,7 +591,7 @@ igmp_sendpkt(struct in_multi *inm, int type)
|
||||
|
||||
ip_output(m, NULL, NULL, IP_MULTICASTOPTS, &imo, NULL);
|
||||
|
||||
++igmpstat.igps_snd_reports;
|
||||
IGMP_STATINC(IGMP_STAT_SND_REPORTS);
|
||||
}
|
||||
|
||||
void
|
||||
@ -581,3 +599,63 @@ igmp_purgeif(struct ifnet *ifp) /* MUST be called at splsoftnet() */
|
||||
{
|
||||
rti_delete(ifp); /* manipulates pools */
|
||||
}
|
||||
|
||||
static void
|
||||
igmpstat_convert_to_user_cb(void *v1, void *v2, struct cpu_info *ci)
|
||||
{
|
||||
uint64_t *igmpsc = v1;
|
||||
uint64_t *igmps = v2;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < IGMP_NSTATS; i++)
|
||||
igmps[i] += igmpsc[i];
|
||||
}
|
||||
|
||||
static void
|
||||
igmpstat_convert_to_user(uint64_t *igmps)
|
||||
{
|
||||
|
||||
memset(igmps, 0, sizeof(uint64_t) * IGMP_NSTATS);
|
||||
percpu_foreach(igmpstat_percpu, igmpstat_convert_to_user_cb, igmps);
|
||||
}
|
||||
|
||||
static int
|
||||
sysctl_net_inet_igmp_stats(SYSCTLFN_ARGS)
|
||||
{
|
||||
struct sysctlnode node;
|
||||
uint64_t igmps[IGMP_NSTATS];
|
||||
|
||||
igmpstat_convert_to_user(igmps);
|
||||
node = *rnode;
|
||||
node.sysctl_data = igmps;
|
||||
node.sysctl_size = sizeof(igmps);
|
||||
return (sysctl_lookup(SYSCTLFN_CALL(&node)));
|
||||
}
|
||||
|
||||
SYSCTL_SETUP(sysctl_net_inet_igmp_setup, "sysctl net.inet.igmp subtree setup")
|
||||
{
|
||||
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "net", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_NET, CTL_EOL);
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "inet", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_NET, PF_INET, CTL_EOL);
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "igmp",
|
||||
SYSCTL_DESCR("Internet Group Management Protocol"),
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_NET, PF_INET, IPPROTO_IGMP, CTL_EOL);
|
||||
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_STRUCT, "stats",
|
||||
SYSCTL_DESCR("IGMP statistics"),
|
||||
sysctl_net_inet_igmp_stats, 0, NULL, 0,
|
||||
CTL_NET, PF_INET, IPPROTO_IGMP, CTL_CREATE, CTL_EOL);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: igmp_var.h,v 1.22 2005/12/10 23:36:23 elad Exp $ */
|
||||
/* $NetBSD: igmp_var.h,v 1.23 2008/04/15 16:02:03 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
@ -85,21 +85,19 @@
|
||||
* MULTICAST 1.3
|
||||
*/
|
||||
|
||||
struct igmpstat {
|
||||
u_quad_t igps_rcv_total; /* total IGMP messages received */
|
||||
u_quad_t igps_rcv_tooshort; /* received with too few bytes */
|
||||
u_quad_t igps_rcv_badsum; /* received with bad checksum */
|
||||
u_quad_t igps_rcv_queries; /* received membership queries */
|
||||
u_quad_t igps_rcv_badqueries; /* received invalid queries */
|
||||
u_quad_t igps_rcv_reports; /* received membership reports */
|
||||
u_quad_t igps_rcv_badreports; /* received invalid reports */
|
||||
u_quad_t igps_rcv_ourreports; /* received reports for our groups */
|
||||
u_quad_t igps_snd_reports; /* sent membership reports */
|
||||
};
|
||||
#define IGMP_STAT_RCV_TOTAL 1 /* total IGMP messages received */
|
||||
#define IGMP_STAT_RCV_TOOSHORT 2 /* received with too few bytes */
|
||||
#define IGMP_STAT_RCV_BADSUM 3 /* received with bad checksum */
|
||||
#define IGMP_STAT_RCV_QUERIES 4 /* received membership queries */
|
||||
#define IGMP_STAT_RCV_BADQUERIES 5 /* received invalid queries */
|
||||
#define IGMP_STAT_RCV_REPORTS 6 /* received membership reports */
|
||||
#define IGMP_STAT_RCV_BADREPORTS 7 /* received invalid reports */
|
||||
#define IGMP_STAT_RCV_OURREPORTS 8 /* received reports for our groups */
|
||||
#define IGMP_STAT_SND_REPORTS 9 /* sent membership reports */
|
||||
|
||||
#define IGMP_NSTATS 10
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern struct igmpstat igmpstat;
|
||||
|
||||
/*
|
||||
* Macro to compute a random timer value between 1 and (IGMP_MAX_REPORTING_
|
||||
* DELAY * countdown frequency). We assume that the routine random()
|
||||
@ -113,12 +111,13 @@ extern struct igmpstat igmpstat;
|
||||
#define IGMP_HDR_ALIGNED_P(ig) ((((vaddr_t) (ig)) & 3) == 0)
|
||||
#endif
|
||||
|
||||
void igmp_init(void);
|
||||
void igmp_input(struct mbuf *, ...);
|
||||
int igmp_joingroup(struct in_multi *);
|
||||
void igmp_leavegroup(struct in_multi *);
|
||||
void igmp_fasttimo(void);
|
||||
void igmp_slowtimo(void);
|
||||
void igmp_purgeif(struct ifnet *);
|
||||
#endif
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_NETINET_IGMP_VAR_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: in_proto.c,v 1.91 2007/10/05 03:28:13 dyoung Exp $ */
|
||||
/* $NetBSD: in_proto.c,v 1.92 2008/04/15 16:02:03 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -61,7 +61,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.91 2007/10/05 03:28:13 dyoung Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.92 2008/04/15 16:02:03 thorpej Exp $");
|
||||
|
||||
#include "opt_mrouting.h"
|
||||
#include "opt_eon.h" /* ISO CLNL over IP */
|
||||
@ -310,6 +310,7 @@ const struct protosw inetsw[] = {
|
||||
.pr_usrreq = rip_usrreq,
|
||||
.pr_fasttimo = igmp_fasttimo,
|
||||
.pr_slowtimo = igmp_slowtimo,
|
||||
.pr_init = igmp_init,
|
||||
},
|
||||
#ifdef PIM
|
||||
{ .pr_type = SOCK_RAW,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: inet.c,v 1.86 2008/04/15 15:17:54 thorpej Exp $ */
|
||||
/* $NetBSD: inet.c,v 1.87 2008/04/15 16:02:04 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983, 1988, 1993
|
||||
@ -34,7 +34,7 @@
|
||||
#if 0
|
||||
static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: inet.c,v 1.86 2008/04/15 15:17:54 thorpej Exp $");
|
||||
__RCSID("$NetBSD: inet.c,v 1.87 2008/04/15 16:02:04 thorpej Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -601,26 +601,35 @@ icmp_stats(u_long off, char *name)
|
||||
void
|
||||
igmp_stats(u_long off, char *name)
|
||||
{
|
||||
struct igmpstat igmpstat;
|
||||
uint64_t igmpstat[IGMP_NSTATS];
|
||||
|
||||
if (use_sysctl) {
|
||||
size_t size = sizeof(igmpstat);
|
||||
|
||||
if (sysctlbyname("net.inet.igmp.stats", igmpstat, &size,
|
||||
NULL, 0) == -1)
|
||||
err(1, "net.inet.igmp.stats");
|
||||
} else {
|
||||
if (off == 0)
|
||||
return;
|
||||
kread(off, (char *)&igmpstat, sizeof (igmpstat));
|
||||
kread(off, (char *)igmpstat, sizeof (igmpstat));
|
||||
}
|
||||
|
||||
printf("%s:\n", name);
|
||||
|
||||
#define p(f, m) if (igmpstat.f || sflag <= 1) \
|
||||
printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
|
||||
#define py(f, m) if (igmpstat.f || sflag <= 1) \
|
||||
printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
|
||||
p(igps_rcv_total, "\t%llu message%s received\n");
|
||||
p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
|
||||
p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
|
||||
py(igps_rcv_queries, "\t%llu membership quer%s received\n");
|
||||
py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
|
||||
p(igps_rcv_reports, "\t%llu membership report%s received\n");
|
||||
p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
|
||||
p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
|
||||
p(igps_snd_reports, "\t%llu membership report%s sent\n");
|
||||
#define p(f, m) if (igmpstat[f] || sflag <= 1) \
|
||||
printf(m, (unsigned long long)igmpstat[f], plural(igmpstat[f]))
|
||||
#define py(f, m) if (igmpstat[f] || sflag <= 1) \
|
||||
printf(m, (unsigned long long)igmpstat[f], igmpstat[f] != 1 ? "ies" : "y")
|
||||
p(IGMP_STAT_RCV_TOTAL, "\t%llu message%s received\n");
|
||||
p(IGMP_STAT_RCV_TOOSHORT, "\t%llu message%s received with too few bytes\n");
|
||||
p(IGMP_STAT_RCV_BADSUM, "\t%llu message%s received with bad checksum\n");
|
||||
py(IGMP_STAT_RCV_QUERIES, "\t%llu membership quer%s received\n");
|
||||
py(IGMP_STAT_RCV_BADQUERIES, "\t%llu membership quer%s received with invalid field(s)\n");
|
||||
p(IGMP_STAT_RCV_REPORTS, "\t%llu membership report%s received\n");
|
||||
p(IGMP_STAT_RCV_BADREPORTS, "\t%llu membership report%s received with invalid field(s)\n");
|
||||
p(IGMP_STAT_RCV_OURREPORTS, "\t%llu membership report%s received for groups to which we belong\n");
|
||||
p(IGMP_STAT_SND_REPORTS, "\t%llu membership report%s sent\n");
|
||||
#undef p
|
||||
#undef py
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user