Make IGMP stats per-cpu.

This commit is contained in:
thorpej 2008-04-15 16:02:03 +00:00
parent 881a947288
commit 83dd106948
4 changed files with 140 additions and 53 deletions

View File

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

View File

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

View File

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

View File

@ -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));
}
if (off == 0)
return;
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
}