From c2da059bc646c3c3e2ca679a304d9deb3f6d5177 Mon Sep 17 00:00:00 2001 From: thorpej Date: Tue, 15 Apr 2008 04:43:25 +0000 Subject: [PATCH] Make udp6 stats per-cpu. --- sys/netinet/udp_usrreq.c | 21 +++++++------- sys/netinet6/udp6_output.c | 7 +++-- sys/netinet6/udp6_private.h | 58 +++++++++++++++++++++++++++++++++++++ sys/netinet6/udp6_usrreq.c | 50 +++++++++++++++++++++++++++++--- sys/netinet6/udp6_var.h | 33 ++++++++++----------- usr.bin/netstat/inet6.c | 54 +++++++++++++++++----------------- 6 files changed, 161 insertions(+), 62 deletions(-) create mode 100644 sys/netinet6/udp6_private.h diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 835fa0adafb8..40ff7641dc83 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp_usrreq.c,v 1.167 2008/04/15 03:57:04 thorpej Exp $ */ +/* $NetBSD: udp_usrreq.c,v 1.168 2008/04/15 04:43:25 thorpej Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -61,7 +61,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.167 2008/04/15 03:57:04 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.168 2008/04/15 04:43:25 thorpej Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" @@ -103,6 +103,7 @@ __KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.167 2008/04/15 03:57:04 thorpej Exp #include #include #include +#include #include #endif @@ -464,7 +465,7 @@ udp6_input_checksum(struct mbuf *m, const struct udphdr *uh, int off, int len) goto good; } if (uh->uh_sum == 0) { - udp6stat.udp6s_nosum++; + UDP6_STATINC(UDP6_STAT_NOSUM); goto bad; } @@ -473,7 +474,7 @@ udp6_input_checksum(struct mbuf *m, const struct udphdr *uh, int off, int len) M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) { case M_CSUM_UDPv6|M_CSUM_TCP_UDP_BAD: UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_bad); - udp6stat.udp6s_badsum++; + UDP6_STATINC(UDP6_STAT_BADSUM); goto bad; #if 0 /* notyet */ @@ -492,7 +493,7 @@ udp6_input_checksum(struct mbuf *m, const struct udphdr *uh, int off, int len) */ UDP_CSUM_COUNTER_INCR(&udp6_swcsum); if (in6_cksum(m, IPPROTO_UDP, off, len) != 0) { - udp6stat.udp6s_badsum++; + UDP6_STATINC(UDP6_STAT_BADSUM); goto bad; } } @@ -523,7 +524,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto) } #endif - udp6stat.udp6s_ipackets++; + UDP6_STATINC(UDP6_STAT_IPACKETS); /* check for jumbogram is done in ip6_input. we can trust pkthdr.len */ plen = m->m_pkthdr.len - off; @@ -542,7 +543,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto) ulen = plen; if (plen != ulen) { - udp6stat.udp6s_badlen++; + UDP6_STATINC(UDP6_STAT_BADLEN); goto bad; } @@ -580,10 +581,10 @@ udp6_input(struct mbuf **mp, int *offp, int proto) if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) { if (m->m_flags & M_MCAST) { - udp6stat.udp6s_noportmcast++; + UDP6_STATINC(UDP6_STAT_NOPORTMCAST); goto bad; } - udp6stat.udp6s_noport++; + UDP6_STATINC(UDP6_STAT_NOPORT); icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); m = NULL; } @@ -689,7 +690,7 @@ udp6_sendup(struct mbuf *m, int off /* offset of data portion */, if (opts) m_freem(opts); so->so_rcv.sb_overflowed++; - udp6stat.udp6s_fullsock++; + UDP6_STATINC(UDP6_STAT_FULLSOCK); } else sorwakeup(so); } diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c index ccaf0457f8a6..d25987fa893e 100644 --- a/sys/netinet6/udp6_output.c +++ b/sys/netinet6/udp6_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_output.c,v 1.34 2008/04/12 05:58:23 thorpej Exp $ */ +/* $NetBSD: udp6_output.c,v 1.35 2008/04/15 04:43:25 thorpej Exp $ */ /* $KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.34 2008/04/12 05:58:23 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.35 2008/04/15 04:43:25 thorpej Exp $"); #include "opt_inet.h" @@ -96,6 +96,7 @@ __KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.34 2008/04/12 05:58:23 thorpej Exp #include #include #include +#include #include #include #include @@ -361,7 +362,7 @@ udp6_output(struct in6pcb *in6p, struct mbuf *m, struct mbuf *addr6, m->m_pkthdr.csum_flags = M_CSUM_UDPv6; m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); - udp6stat.udp6s_opackets++; + UDP6_STATINC(UDP6_STAT_OPACKETS); error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions, in6p->in6p_socket, NULL); break; diff --git a/sys/netinet6/udp6_private.h b/sys/netinet6/udp6_private.h new file mode 100644 index 000000000000..3a7fb8005659 --- /dev/null +++ b/sys/netinet6/udp6_private.h @@ -0,0 +1,58 @@ +/* $NetBSD: udp6_private.h,v 1.1 2008/04/15 04:43:25 thorpej Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NETINET_UDP6_PRIVATE_H_ +#define _NETINET_UDP6_PRIVATE_H_ + +#ifdef _KERNEL +#include + +extern percpu_t *udp6stat_percpu; + +/* + * Most UDP6 statistics are exceptional conditions, so this is good enough. + */ +#define UDP6_STATINC(x) \ +do { \ + uint64_t *_udp6s_ = percpu_getref(udp6stat_percpu); \ + _udp6s_[x]++; \ + percpu_putref(udp6stat_percpu); \ +} while (/*CONSTCOND*/0) +#endif /* _KERNEL */ + +#endif /* !_NETINET_UDP6_PRIVATE_H_ */ diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index a9f630589635..82a02525473e 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_usrreq.c,v 1.81 2008/02/27 19:54:27 matt Exp $ */ +/* $NetBSD: udp6_usrreq.c,v 1.82 2008/04/15 04:43:25 thorpej Exp $ */ /* $KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.81 2008/02/27 19:54:27 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.82 2008/04/15 04:43:25 thorpej Exp $"); #include #include @@ -94,6 +94,7 @@ __KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.81 2008/02/27 19:54:27 matt Exp $" #include #include #include +#include #include #include @@ -108,7 +109,8 @@ __KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.81 2008/02/27 19:54:27 matt Exp $" */ extern struct inpcbtable udbtable; -struct udp6stat udp6stat; + +percpu_t *udp6stat_percpu; static void udp6_notify(struct in6pcb *, int); @@ -402,6 +404,38 @@ release: return error; } +static void +udp6stat_convert_to_user_cb(void *v1, void *v2, struct cpu_info *ci) +{ + uint64_t *udp6sc = v1; + uint64_t *udp6s = v2; + u_int i; + + for (i = 0; i < UDP6_NSTATS; i++) + udp6s[i] += udp6sc[i]; +} + +static void +udp6stat_convert_to_user(uint64_t *udp6s) +{ + + memset(udp6s, 0, sizeof(uint64_t) * UDP6_NSTATS); + percpu_foreach(udp6stat_percpu, udp6stat_convert_to_user_cb, udp6s); +} + +static int +sysctl_net_inet6_udp6_stats(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + uint64_t udp6s[UDP6_NSTATS]; + + udp6stat_convert_to_user(udp6s); + node = *rnode; + node.sysctl_data = udp6s; + node.sysctl_size = sizeof(udp6s); + return (sysctl_lookup(SYSCTLFN_CALL(&node))); +} + SYSCTL_SETUP(sysctl_net_inet6_udp6_setup, "sysctl net.inet6.udp6 subtree setup") { sysctl_createv(clog, 0, NULL, NULL, @@ -453,7 +487,15 @@ SYSCTL_SETUP(sysctl_net_inet6_udp6_setup, "sysctl net.inet6.udp6 subtree setup") CTLFLAG_PERMANENT, CTLTYPE_STRUCT, "stats", SYSCTL_DESCR("UDPv6 statistics"), - NULL, 0, &udp6stat, sizeof(udp6stat), + sysctl_net_inet6_udp6_stats, 0, NULL, 0, CTL_NET, PF_INET6, IPPROTO_UDP, UDP6CTL_STATS, CTL_EOL); } + +void +udp6_statinc(u_int stat) +{ + + KASSERT(stat < UDP6_NSTATS); + UDP6_STATINC(stat); +} diff --git a/sys/netinet6/udp6_var.h b/sys/netinet6/udp6_var.h index 0e15756ef75b..9ca468f586e2 100644 --- a/sys/netinet6/udp6_var.h +++ b/sys/netinet6/udp6_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_var.h,v 1.21 2007/02/17 22:34:15 dyoung Exp $ */ +/* $NetBSD: udp6_var.h,v 1.22 2008/04/15 04:43:25 thorpej Exp $ */ /* $KAME: udp6_var.h,v 1.11 2000/06/05 00:14:31 itojun Exp $ */ /* @@ -67,20 +67,19 @@ /* * UDP Kernel structures and variables. */ -struct udp6stat { - /* input statistics: */ - u_quad_t udp6s_ipackets; /* total input packets */ - u_quad_t udp6s_hdrops; /* packet shorter than header */ - u_quad_t udp6s_badsum; /* checksum error */ - u_quad_t udp6s_nosum; /* no checksum */ - u_quad_t udp6s_badlen; /* data length larger than packet */ - u_quad_t udp6s_noport; /* no socket on port */ - u_quad_t udp6s_noportmcast; /* of above, arrived as broadcast */ - u_quad_t udp6s_fullsock; /* not delivered, input socket full */ - u_quad_t udp6ps_pcbcachemiss; /* input packets missing pcb cache */ - /* output statistics: */ - u_quad_t udp6s_opackets; /* total output packets */ -}; + +#define UDP6_STAT_IPACKETS 0 /* total input packets */ +#define UDP6_STAT_HDROPS 1 /* packet shorter than header */ +#define UDP6_STAT_BADSUM 2 /* checksum error */ +#define UDP6_STAT_NOSUM 3 /* no checksum */ +#define UDP6_STAT_BADLEN 4 /* data length larger than packet */ +#define UDP6_STAT_NOPORT 5 /* no socket on port */ +#define UDP6_STAT_NOPORTMCAST 6 /* of above, arrived as multicast */ +#define UDP6_STAT_FULLSOCK 7 /* not delivered, input socket full */ +#define UDP6_STAT_PCBCACHEMISS 8 /* input packets missing pcb cache */ +#define UDP6_STAT_OPACKETS 9 /* total output packets */ + +#define UDP6_NSTATS 10 /* * Names for UDP6 sysctl objects @@ -100,8 +99,6 @@ struct udp6stat { } #ifdef _KERNEL -extern struct udp6stat udp6stat; - void udp6_ctlinput(int, const struct sockaddr *, void *); void udp6_init(void); int udp6_input(struct mbuf **, int *, int); @@ -111,6 +108,8 @@ int udp6_sysctl(int *, u_int, void *, size_t *, void *, size_t); int udp6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *); + +void udp6_statinc(u_int); #endif /* _KERNEL */ #endif /* !_NETINET6_UDP6_VAR_H_ */ diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c index 19fea63db902..c6d8bfdf05b5 100644 --- a/usr.bin/netstat/inet6.c +++ b/usr.bin/netstat/inet6.c @@ -1,4 +1,4 @@ -/* $NetBSD: inet6.c,v 1.45 2008/04/08 23:37:43 thorpej Exp $ */ +/* $NetBSD: inet6.c,v 1.46 2008/04/15 04:43:25 thorpej Exp $ */ /* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */ /* @@ -64,7 +64,7 @@ #if 0 static char sccsid[] = "@(#)inet.c 8.4 (Berkeley) 4/20/94"; #else -__RCSID("$NetBSD: inet6.c,v 1.45 2008/04/08 23:37:43 thorpej Exp $"); +__RCSID("$NetBSD: inet6.c,v 1.46 2008/04/15 04:43:25 thorpej Exp $"); #endif #endif /* not lint */ @@ -430,48 +430,46 @@ tcp6_stats(off, name) * Dump UDP6 statistics structure. */ void -udp6_stats(off, name) - u_long off; - char *name; +udp6_stats(u_long off, char *name) { - struct udp6stat udp6stat; + uint64_t udp6stat[UDP6_NSTATS]; u_quad_t delivered; if (use_sysctl) { size_t size = sizeof(udp6stat); - if (sysctlbyname("net.inet6.udp6.stats", &udp6stat, &size, + if (sysctlbyname("net.inet6.udp6.stats", udp6stat, &size, NULL, 0) == -1) err(1, "net.inet6.udp6.stats"); } else { if (off == 0) return; - kread(off, (char *)&udp6stat, sizeof (udp6stat)); + kread(off, (char *)udp6stat, sizeof (udp6stat)); } printf("%s:\n", name); -#define p(f, m) if (udp6stat.f || sflag <= 1) \ - printf(m, (unsigned long long)udp6stat.f, plural(udp6stat.f)) -#define p1(f, m) if (udp6stat.f || sflag <= 1) \ - printf(m, (unsigned long long)udp6stat.f) - p(udp6s_ipackets, "\t%llu datagram%s received\n"); - p1(udp6s_hdrops, "\t%llu with incomplete header\n"); - p1(udp6s_badlen, "\t%llu with bad data length field\n"); - p1(udp6s_badsum, "\t%llu with bad checksum\n"); - p1(udp6s_nosum, "\t%llu with no checksum\n"); - p1(udp6s_noport, "\t%llu dropped due to no socket\n"); - p(udp6s_noportmcast, +#define p(f, m) if (udp6stat[f] || sflag <= 1) \ + printf(m, (unsigned long long)udp6stat[f], plural(udp6stat[f])) +#define p1(f, m) if (udp6stat[f] || sflag <= 1) \ + printf(m, (unsigned long long)udp6stat[f]) + p(UDP6_STAT_IPACKETS, "\t%llu datagram%s received\n"); + p1(UDP6_STAT_HDROPS, "\t%llu with incomplete header\n"); + p1(UDP6_STAT_BADLEN, "\t%llu with bad data length field\n"); + p1(UDP6_STAT_BADSUM, "\t%llu with bad checksum\n"); + p1(UDP6_STAT_NOSUM, "\t%llu with no checksum\n"); + p1(UDP6_STAT_NOPORT, "\t%llu dropped due to no socket\n"); + p(UDP6_STAT_NOPORTMCAST, "\t%llu multicast datagram%s dropped due to no socket\n"); - p1(udp6s_fullsock, "\t%llu dropped due to full socket buffers\n"); - delivered = udp6stat.udp6s_ipackets - - udp6stat.udp6s_hdrops - - udp6stat.udp6s_badlen - - udp6stat.udp6s_badsum - - udp6stat.udp6s_noport - - udp6stat.udp6s_noportmcast - - udp6stat.udp6s_fullsock; + p1(UDP6_STAT_FULLSOCK, "\t%llu dropped due to full socket buffers\n"); + delivered = udp6stat[UDP6_STAT_IPACKETS] - + udp6stat[UDP6_STAT_HDROPS] - + udp6stat[UDP6_STAT_BADLEN] - + udp6stat[UDP6_STAT_BADSUM] - + udp6stat[UDP6_STAT_NOPORT] - + udp6stat[UDP6_STAT_NOPORTMCAST] - + udp6stat[UDP6_STAT_FULLSOCK]; if (delivered || sflag <= 1) printf("\t%llu delivered\n", (unsigned long long)delivered); - p(udp6s_opackets, "\t%llu datagram%s output\n"); + p(UDP6_STAT_OPACKETS, "\t%llu datagram%s output\n"); #undef p #undef p1 }