Skip to content

Commit

Permalink
Add ARP statistics to the kernel and netstat.
Browse files Browse the repository at this point in the history
New counters now exist for:
requests sent
replies sent
requests received
replies received
packets received
total packets dropped due to no ARP entry
entrys timed out
Duplicate IPs seen

The new statistics are seen in the netstat command
when it is given the -s command line switch.

MFC after:	2 weeks
In collaboration with: bz
  • Loading branch information
gvnn3 committed Sep 3, 2009
1 parent ce531e6 commit 54fc657
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 7 deletions.
27 changes: 26 additions & 1 deletion sys/net/if_arp.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,31 @@ struct arpcom {
#define IFP2AC(ifp) ((struct arpcom *)(ifp->if_l2com))
#define AC2IFP(ac) ((ac)->ac_ifp)

#endif
#endif /* _KERNEL */

struct arpstat {
/* Normal things that happen: */
u_long txrequests; /* # of ARP requests sent by this host. */
u_long txreplies; /* # of ARP replies sent by this host. */
u_long rxrequests; /* # of ARP requests received by this host. */
u_long rxreplies; /* # of ARP replies received by this host. */
u_long received; /* # of ARP packets received by this host. */

u_long arp_spares[4]; /* For either the upper or lower half. */
/* Abnormal event and error counting: */
u_long dropped; /* # of packets dropped waiting for a reply. */
u_long timeouts; /* # of times with entries removed */
/* due to timeout. */
u_long dupips; /* # of duplicate IPs detected. */
};

/*
* In-kernel consumers can use these accessor macros directly to update
* stats.
*/
#define ARPSTAT_ADD(name, val) V_arpstat.name += (val)
#define ARPSTAT_SUB(name, val) V_arpstat.name -= (val)
#define ARPSTAT_INC(name) ARPSTAT_ADD(name, 1)
#define ARPSTAT_DEC(name) ARPSTAT_SUB(name, 1)

#endif /* !_NET_IF_ARP_H_ */
31 changes: 25 additions & 6 deletions sys/netinet/if_ether.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$");

SYSCTL_DECL(_net_link_ether);
SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, "");
SYSCTL_NODE(_net_link_ether, PF_ARP, arp, CTLFLAG_RW, 0, "");

VNET_DEFINE(int, useloopback) = 1; /* use loopback interface for
* local traffic */
Expand All @@ -89,10 +90,12 @@ static VNET_DEFINE(int, arpt_keep) = (20*60); /* once resolved, good for 20
* minutes */
static VNET_DEFINE(int, arp_maxtries) = 5;
static VNET_DEFINE(int, arp_proxyall);
static VNET_DEFINE(struct arpstat, arpstat); /* ARP statistics, see if_arp.h */

#define V_arpt_keep VNET(arpt_keep)
#define V_arp_maxtries VNET(arp_maxtries)
#define V_arp_proxyall VNET(arp_proxyall)
#define V_arpstat VNET(arpstat)

SYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW,
&VNET_NAME(arpt_keep), 0,
Expand All @@ -107,6 +110,9 @@ SYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,
SYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
&VNET_NAME(arp_proxyall), 0,
"Enable proxy ARP for all suitable requests");
SYSCTL_VNET_STRUCT(_net_link_ether_arp, OID_AUTO, stats, CTLFLAG_RW,
&VNET_NAME(arpstat), arpstat,
"ARP statistics (struct arpstat, net/if_arp.h)");

static void arp_init(void);
void arprequest(struct ifnet *,
Expand Down Expand Up @@ -163,20 +169,23 @@ arptimer(void *arg)
return;
}
ifp = lle->lle_tbl->llt_ifp;
CURVNET_SET(ifp->if_vnet);
IF_AFDATA_LOCK(ifp);
LLE_WLOCK(lle);
if (((lle->la_flags & LLE_DELETED)
|| (time_second >= lle->la_expire))
&& (!callout_pending(&lle->la_timer) &&
callout_active(&lle->la_timer)))
if (((lle->la_flags & LLE_DELETED) ||
(time_second >= lle->la_expire)) &&
(!callout_pending(&lle->la_timer) &&
callout_active(&lle->la_timer))) {
(void) llentry_free(lle);
else {
ARPSTAT_INC(timeouts);
} else {
/*
* Still valid, just drop our reference
*/
LLE_FREE_LOCKED(lle);
}
IF_AFDATA_UNLOCK(ifp);
CURVNET_RESTORE();
}

/*
Expand Down Expand Up @@ -238,6 +247,7 @@ arprequest(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip,
sa.sa_len = 2;
m->m_flags |= M_BCAST;
(*ifp->if_output)(ifp, m, &sa, NULL);
ARPSTAT_INC(txrequests);
}

/*
Expand Down Expand Up @@ -339,8 +349,10 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
* latest one.
*/
if (m != NULL) {
if (la->la_hold != NULL)
if (la->la_hold != NULL) {
m_freem(la->la_hold);
ARPSTAT_INC(dropped);
}
la->la_hold = m;
if (renew == 0 && (flags & LLE_EXCLUSIVE)) {
flags &= ~LLE_EXCLUSIVE;
Expand Down Expand Up @@ -413,6 +425,7 @@ arpintr(struct mbuf *m)
ar = mtod(m, struct arphdr *);
}

ARPSTAT_INC(received);
switch (ntohs(ar->ar_pro)) {
#ifdef INET
case ETHERTYPE_IP:
Expand Down Expand Up @@ -493,6 +506,9 @@ in_arpinput(struct mbuf *m)
(void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr));
(void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr));

if (op == ARPOP_REPLY)
ARPSTAT_INC(rxreplies);

/*
* For a bridge, we want to check the address irrespective
* of the receive interface. (This will change slightly
Expand Down Expand Up @@ -603,6 +619,7 @@ in_arpinput(struct mbuf *m)
ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
inet_ntoa(isaddr), ifp->if_xname);
itaddr = myaddr;
ARPSTAT_INC(dupips);
goto reply;
}
if (ifp->if_flags & IFF_STATICARP)
Expand Down Expand Up @@ -686,6 +703,7 @@ in_arpinput(struct mbuf *m)
reply:
if (op != ARPOP_REQUEST)
goto drop;
ARPSTAT_INC(rxrequests);

if (itaddr.s_addr == myaddr.s_addr) {
/* Shortcut.. the receiving interface is the target. */
Expand Down Expand Up @@ -774,6 +792,7 @@ in_arpinput(struct mbuf *m)
sa.sa_family = AF_ARP;
sa.sa_len = 2;
(*ifp->if_output)(ifp, m, &sa, NULL);
ARPSTAT_INC(txreplies);
return;

drop:
Expand Down
42 changes: 42 additions & 0 deletions usr.bin/netstat/inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>

#include <net/route.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
Expand Down Expand Up @@ -871,6 +872,47 @@ ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
#undef p1a
}

/*
* Dump ARP statistics structure.
*/
void
arp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct arpstat arpstat, zerostat;
size_t len = sizeof(arpstat);

if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.link.ether.arp.stats");
return;
}
} else
kread(off, &arpstat, len);

printf("%s:\n", name);

#define p(f, m) if (arpstat.f || sflag <= 1) \
printf(m, arpstat.f, plural(arpstat.f))
#define p2(f, m) if (arpstat.f || sflag <= 1) \
printf(m, arpstat.f, pluralies(arpstat.f))

p(txrequests, "\t%lu ARP request%s sent\n");
p2(txreplies, "\t%lu ARP repl%s sent\n");
p(rxrequests, "\t%lu ARP request%s received\n");
p2(rxreplies, "\t%lu ARP repl%s received\n");
p(received, "\t%lu ARP packet%s received\n");
p(dropped, "\t%lu total packet%s dropped due to no ARP entry\n");
p(timeouts, "\t%lu ARP entry%s timed out\n");
p(dupips, "\t%lu Duplicate IP%s seen\n");
#undef p
#undef p2
}



static const char *icmpnames[ICMP_MAXTYPE + 1] = {
"echo reply", /* RFC 792 */
"#1",
Expand Down
4 changes: 4 additions & 0 deletions usr.bin/netstat/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ static struct nlist nl[] = {
{ .n_name = "_sctpstat" },
#define N_MFCTABLESIZE 54
{ .n_name = "_mfctablesize" },
#define N_ARPSTAT 55
{ .n_name = "_arpstat" },
{ .n_name = NULL },
};

Expand Down Expand Up @@ -232,6 +234,8 @@ struct protox {
carp_stats, NULL, "carp", 1, 0 },
{ -1, N_PFSYNCSTAT, 1, NULL,
pfsync_stats, NULL, "pfsync", 1, 0 },
{ -1, N_ARPSTAT, 1, NULL,
arp_stats, NULL, "arp", 1, 0 },
{ -1, -1, 0, NULL,
NULL, NULL, NULL, 0, 0 }
};
Expand Down
1 change: 1 addition & 0 deletions usr.bin/netstat/netstat.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ void udp_stats(u_long, const char *, int, int);
void sctp_protopr(u_long, const char *, int, int);
void sctp_stats(u_long, const char *, int, int);
#endif
void arp_stats(u_long, const char *, int, int);
void ip_stats(u_long, const char *, int, int);
void icmp_stats(u_long, const char *, int, int);
void igmp_stats(u_long, const char *, int, int);
Expand Down

0 comments on commit 54fc657

Please sign in to comment.