Make ARP stats per-cpu.

This commit is contained in:
thorpej 2008-04-15 15:17:54 +00:00
parent b849cd90e5
commit 881a947288
4 changed files with 172 additions and 94 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_arp.h,v 1.28 2008/02/20 17:05:52 matt Exp $ */
/* $NetBSD: if_arp.h,v 1.29 2008/04/15 15:17:54 thorpej Exp $ */
/*
* Copyright (c) 1986, 1993
@ -101,33 +101,30 @@ struct arpreq {
/*
* Kernel statistics about arp
*/
struct arpstat {
u_quad_t as_sndtotal; /* total packets sent */
u_quad_t as_sndreply; /* replies sent */
u_quad_t as_sndrequest; /* requests sent */
#define ARP_STAT_SNDTOTAL 0 /* total packets sent */
#define ARP_STAT_SNDREPLY 1 /* replies sent */
#define ARP_STAT_SENDREQUEST 2 /* requests sent */
#define ARP_STAT_RCVTOTAL 3 /* total packets received */
#define ARP_STAT_RCVREQUEST 4 /* valid requests received */
#define ARP_STAT_RCVREPLY 5 /* replies received */
#define ARP_STAT_RCVMCAST 6 /* multicast/broadcast received */
#define ARP_STAT_RCVBADPROTO 7 /* unknown protocol type received */
#define ARP_STAT_RCVBADLEN 8 /* bad (short) length received */
#define ARP_STAT_RCVZEROTPA 9 /* received w/ null target ip */
#define ARP_STAT_RCVZEROSPA 10 /* received w/ null source ip */
#define ARP_STAT_RCVNOINT 11 /* couldn't map to interface */
#define ARP_STAT_RCVLOCALSHA 12 /* received from local hw address */
#define ARP_STAT_RCVBCASTSHA 13 /* received w/ broadcast src */
#define ARP_STAT_RCVLOCALSPA 14 /* received for a local ip [dup!] */
#define ARP_STAT_RCVOVERPERM 15 /* attempts to overwrite static info */
#define ARP_STAT_RCVOVERINT 16 /* attempts to overwrite wrong if */
#define ARP_STAT_RCVOVER 17 /* entries overwritten! */
#define ARP_STAT_RCVLENCHG 18 /* changes in hw address len */
#define ARP_STAT_DFRTOTAL 19 /* deferred pending ARP resolution */
#define ARP_STAT_DFRSENT 20 /* deferred, then sent */
#define ARP_STAT_DFRDROPPED 21 /* deferred, then dropped */
#define ARP_STAT_ALLOCFAIL 22 /* failures to allocate llinfo */
u_quad_t as_rcvtotal; /* total packets received */
u_quad_t as_rcvrequest; /* valid requests received */
u_quad_t as_rcvreply; /* replies received */
u_quad_t as_rcvmcast; /* multicast/broadcast received */
u_quad_t as_rcvbadproto; /* unknown protocol type received */
u_quad_t as_rcvbadlen; /* bad (short) length received */
u_quad_t as_rcvzerotpa; /* received w/ null target ip */
u_quad_t as_rcvzerospa; /* received w/ null src ip */
u_quad_t as_rcvnoint; /* couldn't map to interface */
u_quad_t as_rcvlocalsha; /* received from local hw address */
u_quad_t as_rcvbcastsha; /* received w/ broadcast src */
u_quad_t as_rcvlocalspa; /* received for a local ip [dup!] */
u_quad_t as_rcvoverperm; /* attempts to overwrite static info */
u_quad_t as_rcvoverint; /* attempts to overwrite wrong if */
u_quad_t as_rcvover; /* entries overwritten! */
u_quad_t as_rcvlenchg; /* changes in hw add len */
u_quad_t as_dfrtotal; /* deferred pending ARP resolution. */
u_quad_t as_dfrsent; /* deferred, then sent */
u_quad_t as_dfrdropped; /* deferred, then dropped */
u_quad_t as_allocfail; /* Failures to allocate llinfo */
};
#define ARP_NSTATS 23
#endif /* !_NET_IF_ARP_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_arp.c,v 1.131 2008/01/20 18:09:12 joerg Exp $ */
/* $NetBSD: if_arp.c,v 1.132 2008/04/15 15:17:54 thorpej Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@ -75,7 +75,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.131 2008/01/20 18:09:12 joerg Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.132 2008/04/15 15:17:54 thorpej Exp $");
#include "opt_ddb.h"
#include "opt_inet.h"
@ -100,6 +100,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.131 2008/01/20 18:09:12 joerg Exp $");
#include <sys/protosw.h>
#include <sys/domain.h>
#include <sys/sysctl.h>
#include <sys/percpu.h>
#include <net/ethertypes.h>
#include <net/if.h>
@ -169,7 +170,25 @@ int arp_maxtries = 5;
int useloopback = 1; /* use loopback interface for local traffic */
int arpinit_done = 0;
struct arpstat arpstat;
static percpu_t *arpstat_percpu;
#define ARP_STAT_GETREF() percpu_getref(arpstat_percpu)
#define ARP_STAT_PUTREF() percpu_putref(arpstat_percpu)
#define ARP_STATINC(x) \
do { \
uint64_t *_arps_ = ARP_STAT_GETREF(); \
_arps_[x]++; \
ARP_STAT_PUTREF(); \
} while (/*CONSTCOND*/0)
#define ARP_STATADD(x, v) \
do { \
uint64_t *_arps_ = ARP_STAT_GETREF(); \
_arps_[x] += (v); \
ARP_STAT_PUTREF(); \
} while (/*CONSTCOND*/0)
struct callout arptimer_ch;
/* revarp state */
@ -231,7 +250,7 @@ const struct protosw arpsw[] = {
.pr_ctlinput = 0,
.pr_ctloutput = 0,
.pr_usrreq = 0,
.pr_init = 0,
.pr_init = arp_init,
.pr_fasttimo = 0,
.pr_slowtimo = 0,
.pr_drain = arp_drain,
@ -315,11 +334,17 @@ do { \
#define ARP_UNLOCK() arp_unlock()
void
arp_init(void)
{
arpstat_percpu = percpu_alloc(sizeof(uint64_t) * ARP_NSTATS);
}
/*
* ARP protocol drain routine. Called when memory is in short supply.
* Called at splvm();
*/
void
arp_drain(void)
{
@ -344,7 +369,7 @@ arp_drain(void)
}
}
ARP_UNLOCK();
arpstat.as_dfrdropped += count;
ARP_STATADD(ARP_STAT_DFRDROPPED, count);
}
@ -658,6 +683,7 @@ arprequest(struct ifnet *ifp,
struct mbuf *m;
struct arphdr *ah;
struct sockaddr sa;
uint64_t *arps;
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
return;
@ -695,8 +721,10 @@ arprequest(struct ifnet *ifp,
sa.sa_family = AF_ARP;
sa.sa_len = 2;
m->m_flags |= M_BCAST;
arpstat.as_sndtotal++;
arpstat.as_sndrequest++;
arps = ARP_STAT_GETREF();
arps[ARP_STAT_SNDTOTAL]++;
arps[ARP_STAT_SENDREQUEST]++;
ARP_STAT_PUTREF();
(*ifp->if_output)(ifp, m, &sa, NULL);
}
@ -723,7 +751,7 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt, struct mbuf *m,
rt = la->la_rt;
if (la == 0 || rt == 0) {
arpstat.as_allocfail++;
ARP_STATINC(ARP_STAT_ALLOCFAIL);
log(LOG_DEBUG,
"arpresolve: can't allocate llinfo on %s for %s\n",
ifp->if_xname, in_fmtaddr(satocsin(dst)->sin_addr));
@ -748,14 +776,14 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt, struct mbuf *m,
* latest one.
*/
arpstat.as_dfrtotal++;
ARP_STATINC(ARP_STAT_DFRTOTAL);
s = splnet();
mold = la->la_hold;
la->la_hold = m;
splx(s);
if (mold) {
arpstat.as_dfrdropped++;
ARP_STATINC(ARP_STAT_DFRDROPPED);
m_freem(mold);
}
@ -813,7 +841,7 @@ arpintr(void)
panic("arpintr");
MCLAIM(m, &arpdomain.dom_mowner);
arpstat.as_rcvtotal++;
ARP_STATINC(ARP_STAT_RCVTOTAL);
/*
* First, make sure we have at least struct arphdr.
@ -841,11 +869,11 @@ arpintr(void)
in_arpinput(m);
continue;
default:
arpstat.as_rcvbadproto++;
ARP_STATINC(ARP_STAT_RCVBADPROTO);
}
else {
badlen:
arpstat.as_rcvbadlen++;
ARP_STATINC(ARP_STAT_RCVBADLEN);
}
m_freem(m);
}
@ -886,6 +914,7 @@ in_arpinput(struct mbuf *m)
struct mbuf *mold;
void *tha;
int s;
uint64_t *arps;
if (__predict_false(m_makewritable(&m, 0, m->m_pkthdr.len, M_DONTWAIT)))
goto out;
@ -915,7 +944,7 @@ in_arpinput(struct mbuf *m)
memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr));
if (m->m_flags & (M_BCAST|M_MCAST))
arpstat.as_rcvmcast++;
ARP_STATINC(ARP_STAT_RCVMCAST);
/*
* If the target IP address is zero, ignore the packet.
@ -923,7 +952,7 @@ in_arpinput(struct mbuf *m)
* when we are using IP address zero (booting).
*/
if (in_nullhost(itaddr)) {
arpstat.as_rcvzerotpa++;
ARP_STATINC(ARP_STAT_RCVZEROTPA);
goto out;
}
@ -933,7 +962,7 @@ in_arpinput(struct mbuf *m)
* XXX: Should we bother trying to reply to these?
*/
if (in_nullhost(isaddr)) {
arpstat.as_rcvzerospa++;
ARP_STATINC(ARP_STAT_RCVZEROSPA);
goto out;
}
@ -990,7 +1019,7 @@ in_arpinput(struct mbuf *m)
if (ia == NULL) {
IFP_TO_IA(ifp, ia);
if (ia == NULL) {
arpstat.as_rcvnoint++;
ARP_STATINC(ARP_STAT_RCVNOINT);
goto out;
}
}
@ -1000,13 +1029,13 @@ in_arpinput(struct mbuf *m)
/* XXX checks for bridge case? */
if (!memcmp(ar_sha(ah), CLLADDR(ifp->if_sadl), ifp->if_addrlen)) {
arpstat.as_rcvlocalsha++;
ARP_STATINC(ARP_STAT_RCVLOCALSHA);
goto out; /* it's from me, ignore it. */
}
/* XXX checks for bridge case? */
if (!memcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) {
arpstat.as_rcvbcastsha++;
ARP_STATINC(ARP_STAT_RCVBCASTSHA);
log(LOG_ERR,
"%s: arp: link address is broadcast for IP address %s!\n",
ifp->if_xname, in_fmtaddr(isaddr));
@ -1014,7 +1043,7 @@ in_arpinput(struct mbuf *m)
}
if (in_hosteq(isaddr, myaddr)) {
arpstat.as_rcvlocalspa++;
ARP_STATINC(ARP_STAT_RCVLOCALSPA);
log(LOG_ERR,
"duplicate IP address %s sent from link address %s\n",
in_fmtaddr(isaddr), lla_snprintf(ar_sha(ah), ah->ar_hln));
@ -1026,7 +1055,7 @@ in_arpinput(struct mbuf *m)
if (sdl->sdl_alen &&
memcmp(ar_sha(ah), CLLADDR(sdl), sdl->sdl_alen)) {
if (rt->rt_flags & RTF_STATIC) {
arpstat.as_rcvoverperm++;
ARP_STATINC(ARP_STAT_RCVOVERPERM);
log(LOG_INFO,
"%s tried to overwrite permanent arp info"
" for %s\n",
@ -1034,7 +1063,7 @@ in_arpinput(struct mbuf *m)
in_fmtaddr(isaddr));
goto out;
} else if (rt->rt_ifp != ifp) {
arpstat.as_rcvoverint++;
ARP_STATINC(ARP_STAT_RCVOVERINT);
log(LOG_INFO,
"%s on %s tried to overwrite "
"arp info for %s on %s\n",
@ -1043,7 +1072,7 @@ in_arpinput(struct mbuf *m)
rt->rt_ifp->if_xname);
goto out;
} else {
arpstat.as_rcvover++;
ARP_STATINC(ARP_STAT_RCVOVER);
log(LOG_INFO,
"arp info overwritten for %s by %s\n",
in_fmtaddr(isaddr),
@ -1057,13 +1086,13 @@ in_arpinput(struct mbuf *m)
*/
if (sdl->sdl_alen &&
sdl->sdl_alen != ah->ar_hln) {
arpstat.as_rcvlenchg++;
ARP_STATINC(ARP_STAT_RCVLENCHG);
log(LOG_WARNING,
"arp from %s: new addr len %d, was %d",
in_fmtaddr(isaddr), ah->ar_hln, sdl->sdl_alen);
}
if (ifp->if_addrlen != ah->ar_hln) {
arpstat.as_rcvbadlen++;
ARP_STATINC(ARP_STAT_RCVBADLEN);
log(LOG_WARNING,
"arp from %s: addr len: new %d, i/f %d (ignored)",
in_fmtaddr(isaddr), ah->ar_hln,
@ -1110,19 +1139,19 @@ in_arpinput(struct mbuf *m)
splx(s);
if (mold) {
arpstat.as_dfrsent++;
ARP_STATINC(ARP_STAT_DFRSENT);
(*ifp->if_output)(ifp, mold, rt_getkey(rt), rt);
}
}
reply:
if (op != ARPOP_REQUEST) {
if (op == ARPOP_REPLY)
arpstat.as_rcvreply++;
ARP_STATINC(ARP_STAT_RCVREPLY);
out:
m_freem(m);
return;
}
arpstat.as_rcvrequest++;
ARP_STATINC(ARP_STAT_RCVREQUEST);
if (in_hosteq(itaddr, myaddr)) {
/* I am the target */
tha = ar_tha(ah);
@ -1166,8 +1195,10 @@ reply:
m->m_pkthdr.len = m->m_len;
sa.sa_family = AF_ARP;
sa.sa_len = 2;
arpstat.as_sndtotal++;
arpstat.as_sndreply++;
arps = ARP_STAT_GETREF();
arps[ARP_STAT_SNDTOTAL]++;
arps[ARP_STAT_SNDREPLY]++;
ARP_STAT_PUTREF();
(*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
return;
}
@ -1238,7 +1269,7 @@ arplookup1(struct mbuf *m, const struct in_addr *addr, int create, int proxy,
if (rt->rt_flags & RTF_GATEWAY)
why = "host is not on local network";
else if ((rt->rt_flags & RTF_LLINFO) == 0) {
arpstat.as_allocfail++;
ARP_STATINC(ARP_STAT_ALLOCFAIL);
why = "could not allocate llinfo";
} else
why = "gateway route is not ours";
@ -1546,6 +1577,38 @@ db_show_arptab(db_expr_t addr, bool have_addr,
}
#endif
static void
arpstat_convert_to_user_cb(void *v1, void *v2, struct cpu_info *ci)
{
uint64_t *arpsc = v1;
uint64_t *arps = v2;
u_int i;
for (i = 0; i < ARP_NSTATS; i++)
arps[i] += arpsc[i];
}
static void
arpstat_convert_to_user(uint64_t *arps)
{
memset(arps, 0, sizeof(uint64_t) * ARP_NSTATS);
percpu_foreach(arpstat_percpu, arpstat_convert_to_user_cb, arps);
}
static int
sysctl_net_inet_arp_stats(SYSCTLFN_ARGS)
{
struct sysctlnode node;
uint64_t arps[ARP_NSTATS];
arpstat_convert_to_user(arps);
node = *rnode;
node.sysctl_data = arps;
node.sysctl_size = sizeof(arps);
return (sysctl_lookup(SYSCTLFN_CALL(&node)));
}
SYSCTL_SETUP(sysctl_net_inet_arp_setup, "sysctl net.inet.arp subtree setup")
{
const struct sysctlnode *node;
@ -1594,6 +1657,13 @@ SYSCTL_SETUP(sysctl_net_inet_arp_setup, "sysctl net.inet.arp subtree setup")
SYSCTL_DESCR("ARP entry refresh interval"),
NULL, 0, &arpt_refresh, 0,
CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRUCT, "stats",
SYSCTL_DESCR("ARP statistics"),
sysctl_net_inet_arp_stats, 0, NULL, 0,
CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
}
#endif /* INET */

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_inarp.h,v 1.39 2007/03/04 06:03:20 christos Exp $ */
/* $NetBSD: if_inarp.h,v 1.40 2008/04/15 15:17:54 thorpej Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@ -68,6 +68,7 @@ int arpresolve(struct ifnet *, struct rtentry *, struct mbuf *,
void arpintr(void);
void arprequest(struct ifnet *, const struct in_addr *, const struct in_addr *,
const u_int8_t *);
void arp_init(void);
void arp_drain(void);
int arpioctl(u_long, void *);
void arpwhohas(struct ifnet *, struct in_addr *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: inet.c,v 1.85 2008/04/15 06:03:28 thorpej Exp $ */
/* $NetBSD: inet.c,v 1.86 2008/04/15 15:17:54 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.85 2008/04/15 06:03:28 thorpej Exp $");
__RCSID("$NetBSD: inet.c,v 1.86 2008/04/15 15:17:54 thorpej Exp $");
#endif
#endif /* not lint */
@ -720,46 +720,56 @@ pim_stats(u_long off, char *name)
void
arp_stats(u_long off, char *name)
{
struct arpstat arpstat;
uint64_t arpstat[ARP_NSTATS];
if (use_sysctl) {
size_t size = sizeof(arpstat);
if (sysctlbyname("net.inet.arp.stats", arpstat, &size,
NULL, 0) == -1) {
return;
}
} else {
if (off == 0)
return;
kread(off, (char *)arpstat, sizeof(arpstat));
}
if (off == 0)
return;
kread(off, (char *)&arpstat, sizeof (arpstat));
printf("%s:\n", name);
#define ps(f, m) if (arpstat.f || sflag <= 1) \
printf(m, (unsigned long long)arpstat.f)
#define p(f, m) if (arpstat.f || sflag <= 1) \
printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
#define ps(f, m) if (arpstat[f] || sflag <= 1) \
printf(m, (unsigned long long)arpstat[f])
#define p(f, m) if (arpstat[f] || sflag <= 1) \
printf(m, (unsigned long long)arpstat[f], plural(arpstat[f]))
p(as_sndtotal, "\t%llu packet%s sent\n");
p(as_sndreply, "\t\t%llu reply packet%s\n");
p(as_sndrequest, "\t\t%llu request packet%s\n");
p(ARP_STAT_SNDTOTAL, "\t%llu packet%s sent\n");
p(ARP_STAT_SNDREPLY, "\t\t%llu reply packet%s\n");
p(ARP_STAT_SENDREQUEST, "\t\t%llu request packet%s\n");
p(as_rcvtotal, "\t%llu packet%s received\n");
p(as_rcvreply, "\t\t%llu reply packet%s\n");
p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
p(ARP_STAT_RCVTOTAL, "\t%llu packet%s received\n");
p(ARP_STAT_RCVREPLY, "\t\t%llu reply packet%s\n");
p(ARP_STAT_RCVREQUEST, "\t\t%llu valid request packet%s\n");
p(ARP_STAT_RCVMCAST, "\t\t%llu broadcast/multicast packet%s\n");
p(ARP_STAT_RCVBADPROTO, "\t\t%llu packet%s with unknown protocol type\n");
p(ARP_STAT_RCVBADLEN, "\t\t%llu packet%s with bad (short) length\n");
p(ARP_STAT_RCVZEROTPA, "\t\t%llu packet%s with null target IP address\n");
p(ARP_STAT_RCVZEROSPA, "\t\t%llu packet%s with null source IP address\n");
ps(ARP_STAT_RCVNOINT, "\t\t%llu could not be mapped to an interface\n");
p(ARP_STAT_RCVLOCALSHA, "\t\t%llu packet%s sourced from a local hardware "
"address\n");
p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
p(ARP_STAT_RCVBCASTSHA, "\t\t%llu packet%s with a broadcast "
"source hardware address\n");
p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
p(as_rcvover, "\t\t%llu entry%s overwritten\n");
p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
p(ARP_STAT_RCVLOCALSPA, "\t\t%llu duplicate%s for a local IP address\n");
p(ARP_STAT_RCVOVERPERM, "\t\t%llu attempt%s to overwrite a static entry\n");
p(ARP_STAT_RCVOVERINT, "\t\t%llu packet%s received on wrong interface\n");
p(ARP_STAT_RCVOVER, "\t\t%llu entry%s overwritten\n");
p(ARP_STAT_RCVLENCHG, "\t\t%llu change%s in hardware address length\n");
p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
ps(as_dfrsent, "\t\t%llu sent\n");
ps(as_dfrdropped, "\t\t%llu dropped\n");
p(ARP_STAT_DFRTOTAL, "\t%llu packet%s deferred pending ARP resolution\n");
ps(ARP_STAT_DFRSENT, "\t\t%llu sent\n");
ps(ARP_STAT_DFRDROPPED, "\t\t%llu dropped\n");
p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
p(ARP_STAT_ALLOCFAIL, "\t%llu failure%s to allocate llinfo\n");
#undef ps
#undef p