From fc9c7b4f3a2b286f7e743559d6fb4c2d87040bb3 Mon Sep 17 00:00:00 2001 From: Hiten Pandya Date: Mon, 3 May 2004 15:18:25 +0000 Subject: [PATCH] Make IP statistics counters per-CPU so they can be updated safely. * For SMP, we index into the array with the current CPU's as ipstats_ary[gd->gd_cpuid], and for UP we just return struct at ipstats_ary[0] (CPU-0). * Rename the structure from ipstat to ip_stats. * Wrap function definition of CPU counter aggregation in a macro called CPU_STATS_FUNC() to avoid duplication. * Retain support for resetting the counters using netstat(1). --- sys/netinet/ip_flow.c | 4 ++- sys/netinet/ip_input.c | 47 +++++++++++++++++++++++++-- sys/netinet/ip_var.h | 21 ++++++++++-- usr.bin/netstat/inet.c | 72 ++++++++++++++++++++++++++---------------- usr.bin/systat/ip.c | 14 ++++---- 5 files changed, 117 insertions(+), 41 deletions(-) diff --git a/sys/netinet/ip_flow.c b/sys/netinet/ip_flow.c index d9e3c357c4..89ee4308f7 100644 --- a/sys/netinet/ip_flow.c +++ b/sys/netinet/ip_flow.c @@ -34,13 +34,15 @@ * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/netinet/ip_flow.c,v 1.9.2.2 2001/11/04 17:35:31 luigi Exp $ - * $DragonFly: src/sys/netinet/ip_flow.c,v 1.3 2004/04/22 04:35:45 dillon Exp $ + * $DragonFly: src/sys/netinet/ip_flow.c,v 1.4 2004/05/03 15:18:25 hmp Exp $ */ #include #include #include #include +#include +#include #include #include #include diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 106e4949f4..fb7efafceb 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -32,7 +32,7 @@ * * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 * $FreeBSD: src/sys/netinet/ip_input.c,v 1.130.2.52 2003/03/07 07:01:28 silby Exp $ - * $DragonFly: src/sys/netinet/ip_input.c,v 1.23 2004/04/24 07:05:56 hsu Exp $ + * $DragonFly: src/sys/netinet/ip_input.c,v 1.24 2004/05/03 15:18:25 hmp Exp $ */ #define _IP_VHL @@ -55,6 +55,8 @@ #include #include #include +#include +#include #include #include #include @@ -181,9 +183,30 @@ SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); -struct ipstat ipstat; +struct ip_stats ipstats_ary[MAXCPU]; +#ifdef SMP +static int +sysctl_ipstats(SYSCTL_HANDLER_ARGS) +{ + int cpu, error = 0; + + for (cpu = 0; cpu < ncpus; ++cpu) { + if ((error = SYSCTL_OUT(req, (void *)&ipstats_ary[cpu], + sizeof(struct ip_stats)))) + break; + if ((error = SYSCTL_IN(req, (void *)&ipstats_ary[cpu], + sizeof(struct ip_stats)))) + break; + } + + return (error); +} +SYSCTL_PROC(_net_inet_ip, IPCTL_STATS, stats, (CTLTYPE_OPAQUE | CTLFLAG_RW), + 0, 0, sysctl_ipstats, "S,ip_stats", "IP statistics"); +#else SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW, - &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); + &ipstat, ip_stats, "IP statistics"); +#endif /* Packet reassembly stuff */ #define IPREASS_NHASH_LOG2 6 @@ -261,6 +284,9 @@ ip_init() { struct ipprotosw *pr; int i; +#ifdef SMP + int cpu; +#endif TAILQ_INIT(&in_ifaddrhead); in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask); @@ -294,6 +320,21 @@ ip_init() #endif ipintrq.ifq_maxlen = ipqmaxlen; + /* + * Initialize IP statistics. + * + * It is layed out as an array which is has one element for UP, + * and SMP_MAXCPU elements for SMP. This allows us to retain + * the access mechanism from userland for both UP and SMP. + */ +#ifdef SMP + for (cpu = 0; cpu < ncpus; ++cpu) { + bzero(&ipstats_ary[cpu], sizeof(struct ip_stats)); + } +#else + bzero(&ipstat, sizeof(struct ip_stats)); +#endif + netisr_register(NETISR_IP, ip_mport, ip_input_handler); } diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 56e4493905..6cf58fe494 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -32,7 +32,7 @@ * * @(#)ip_var.h 8.2 (Berkeley) 1/9/95 * $FreeBSD: src/sys/netinet/ip_var.h,v 1.50.2.13 2003/08/24 08:24:38 hsu Exp $ - * $DragonFly: src/sys/netinet/ip_var.h,v 1.6 2004/03/06 07:30:43 hsu Exp $ + * $DragonFly: src/sys/netinet/ip_var.h,v 1.7 2004/05/03 15:18:25 hmp Exp $ */ #ifndef _NETINET_IP_VAR_H_ @@ -98,7 +98,23 @@ struct ip_moptions { u_long imo_multicast_vif; /* vif num outgoing multicasts */ }; -struct ipstat { +#ifdef _KERNEL + +#if defined(SMP) +#define _GD mycpu +#define ipstat ipstats_ary[_GD->gd_cpuid] +#else /* !SMP */ +#define ipstat ipstats_ary[0] +#endif + +struct ip_stats; +extern struct ip_stats ipstats_ary[MAXCPU]; +#endif + +/* + * IP Statistics. + */ +struct ip_stats { u_long ips_total; /* total packets received */ u_long ips_badsum; /* checksum bad */ u_long ips_tooshort; /* packet too short */ @@ -144,7 +160,6 @@ struct route; struct sockopt; struct lwkt_port; -extern struct ipstat ipstat; #ifndef RANDOM_IP_ID extern u_short ip_id; /* ip packet ctr, for ids */ #endif diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index 6da4db300b..d1b3160164 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -32,7 +32,7 @@ * * @(#)inet.c 8.5 (Berkeley) 5/24/95 * $FreeBSD: src/usr.bin/netstat/inet.c,v 1.37.2.11 2003/11/27 14:46:49 ru Exp $ - * $DragonFly: src/usr.bin/netstat/inet.c,v 1.12 2004/04/07 17:01:27 dillon Exp $ + * $DragonFly: src/usr.bin/netstat/inet.c,v 1.13 2004/05/03 15:18:25 hmp Exp $ */ #include @@ -340,27 +340,30 @@ protopr(u_long proto, /* for sysctl version we pass proto # */ free(buf); } -void -tcp_stats_agg(struct tcp_stats *ary, struct tcp_stats *ttl, int cpucnt) -{ - int i, off, siz; - siz = sizeof(struct tcp_stats); - - if (!ary && !ttl) - return; - - bzero(ttl, siz); - if (cpucnt == 1) { - *ttl = ary[0]; - } else { - for (i = 0; i < cpucnt; ++i) { - for (off = 0; off < siz; off += sizeof(u_long)) { - *(u_long *)((char *)(*(&ttl)) + off) += - *(u_long *)((char *)&ary[i] + off); - } - } - } +#define CPU_STATS_FUNC(proto,type) \ +static void \ +proto ##_stats_agg(type *ary, type *ttl, int cpucnt) \ +{ \ + int i, off, siz; \ + siz = sizeof(type); \ + \ + if (!ary && !ttl) \ + return; \ + \ + bzero(ttl, siz); \ + if (cpucnt == 1) { \ + *ttl = ary[0]; \ + } else { \ + for (i = 0; i < cpucnt; ++i) { \ + for (off = 0; off < siz; off += sizeof(u_long)) { \ + *(u_long *)((char *)(*(&ttl)) + off) += \ + *(u_long *)((char *)&ary[i] + off); \ + } \ + } \ + } \ } +CPU_STATS_FUNC(tcp, struct tcp_stats); +CPU_STATS_FUNC(ip, struct ip_stats); /* * Dump TCP statistics structure. @@ -563,16 +566,30 @@ udp_stats(u_long off __unused, char *name, int af __unused) void ip_stats(u_long off __unused, char *name, int af __unused) { - struct ipstat ipstat, zerostat; - size_t len = sizeof ipstat; + struct ip_stats ipstat, *stattmp; + struct ip_stats zerostat[SMP_MAXCPU]; + size_t len = sizeof(struct ip_stats) * SMP_MAXCPU; + int cpucnt; if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.ip.stats"); + memset(zerostat, 0, len); + if ((stattmp = malloc(len)) == NULL) { return; + } else { + if (sysctlbyname("net.inet.ip.stats", stattmp, &len, + zflag ? zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.ip.stats"); + free(stattmp); + return; + } else { + if ((stattmp = realloc(stattmp, len)) == NULL) { + warn("ip_stats"); + return; + } + } } + cpucnt = len / sizeof(struct ip_stats); + ip_stats_agg(stattmp, &ipstat, cpucnt); printf("%s:\n", name); @@ -614,6 +631,7 @@ ip_stats(u_long off __unused, char *name, int af __unused) p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n"); p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n"); p(ips_badaddr, "\t%lu datagram%s with bad address in header\n"); + free(stattmp); #undef p #undef p1a } diff --git a/usr.bin/systat/ip.c b/usr.bin/systat/ip.c index bc37eb0a19..1cad48258c 100644 --- a/usr.bin/systat/ip.c +++ b/usr.bin/systat/ip.c @@ -32,7 +32,7 @@ * * @(#)mbufs.c 8.1 (Berkeley) 6/6/93 * $FreeBSD: src/usr.bin/systat/ip.c,v 1.3.2.1 2001/04/25 12:42:18 ru Exp $ - * $DragonFly: src/usr.bin/systat/ip.c,v 1.4 2003/10/04 20:36:51 hmp Exp $ + * $DragonFly: src/usr.bin/systat/ip.c,v 1.5 2004/05/03 15:18:25 hmp Exp $ */ #include @@ -55,7 +55,7 @@ #include "mode.h" struct stat { - struct ipstat i; + struct ip_stats i; struct udpstat u; }; @@ -254,15 +254,15 @@ initip(void) len = 0; if (sysctl(name, 4, 0, &len, 0, 0) < 0) { - error("sysctl getting ipstat size failed"); + error("sysctl getting ip_stats size failed"); return 0; } if (len > sizeof curstat.i) { - error("ipstat structure has grown--recompile systat!"); + error("ip_stats structure has grown--recompile systat!"); return 0; } if (sysctl(name, 4, &initstat.i, &len, 0, 0) < 0) { - error("sysctl getting ipstat failed"); + error("sysctl getting ip_stats failed"); return 0; } name[2] = IPPROTO_UDP; @@ -274,7 +274,7 @@ initip(void) return 0; } if (len > sizeof curstat.u) { - error("ipstat structure has grown--recompile systat!"); + error("ip_stats structure has grown--recompile systat!"); return 0; } if (sysctl(name, 4, &initstat.u, &len, 0, 0) < 0) { @@ -298,7 +298,7 @@ resetip(void) len = sizeof initstat.i; if (sysctl(name, 4, &initstat.i, &len, 0, 0) < 0) { - error("sysctl getting ipstat failed"); + error("sysctl getting ip_stat failed"); } name[2] = IPPROTO_UDP; name[3] = UDPCTL_STATS; -- 2.41.0