Make udp6 stats per-cpu.

This commit is contained in:
thorpej 2008-04-15 04:43:25 +00:00
parent 79cf86c8af
commit c2da059bc6
6 changed files with 161 additions and 62 deletions

View File

@ -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 <sys/cdefs.h>
__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 <netinet6/ip6_private.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/udp6_var.h>
#include <netinet6/udp6_private.h>
#include <netinet6/scope6_var.h>
#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);
}

View File

@ -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 <sys/cdefs.h>
__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 <netinet6/ip6_var.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/udp6_var.h>
#include <netinet6/udp6_private.h>
#include <netinet/icmp6.h>
#include <netinet6/ip6protosw.h>
#include <netinet6/scope6_var.h>
@ -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;

View File

@ -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 <sys/percpu.h>
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_ */

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/malloc.h>
@ -94,6 +94,7 @@ __KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.81 2008/02/27 19:54:27 matt Exp $"
#include <netinet6/in6_pcb.h>
#include <netinet/icmp6.h>
#include <netinet6/udp6_var.h>
#include <netinet6/udp6_private.h>
#include <netinet6/ip6protosw.h>
#include <netinet/in_offload.h>
@ -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);
}

View File

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

View File

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