RFC: ARP Statistics
George Neville-Neil
gnn at neville-neil.com
Wed Aug 12 13:57:16 UTC 2009
Howdy,
Here is a small patch that updates the kernel and the netstat(1)
program to print out protocol
statistics for ARP. I'd be interested in any feedback people have on
this.
Sample output:
netstat -s -p arp
arp:
469 ARP requests sent
2117 ARP replies received
0 total packets dropped due to no ARP entry
469 ARP entrys timed out
0 Duplicate IPs seen
Best,
George
Index: usr.bin/netstat/inet.c
===================================================================
--- usr.bin/netstat/inet.c (revision 196095)
+++ usr.bin/netstat/inet.c (working copy)
@@ -49,6 +49,7 @@
#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>
@@ -871,6 +872,44 @@
#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 p1a(f, m) if (arpstat.f || sflag <= 1) \
+ printf(m, arpstat.f)
+
+ p(arp_requests, "\t%lu ARP request%s sent\n");
+ p(arp_replies, "\t%lu ARP replie%s received\n");
+ p(arp_dropped, "\t%lu total packet%s dropped due to no ARP entry\n");
+ p(arp_timeout, "\t%lu ARP entry%s timed out\n");
+ p(arp_dupips, "\t%lu Duplicate IP%s seen\n");
+#undef p
+#undef p1a
+}
+
+
+
static const char *icmpnames[ICMP_MAXTYPE + 1] = {
"echo reply", /* RFC 792 */
"#1",
Index: usr.bin/netstat/main.c
===================================================================
--- usr.bin/netstat/main.c (revision 196095)
+++ usr.bin/netstat/main.c (working copy)
@@ -184,6 +184,8 @@
{ .n_name = "_sctpstat" },
#define N_MFCTABLESIZE 54
{ .n_name = "_mfctablesize" },
+#define N_ARPSTAT 55
+ { .n_name = "_arpstat" },
{ .n_name = NULL },
};
@@ -232,6 +234,8 @@
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 }
};
Index: usr.bin/netstat/netstat.h
===================================================================
--- usr.bin/netstat/netstat.h (revision 196095)
+++ usr.bin/netstat/netstat.h (working copy)
@@ -75,6 +75,7 @@
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);
Index: sys/netinet/if_ether.c
===================================================================
--- sys/netinet/if_ether.c (revision 196095)
+++ sys/netinet/if_ether.c (working copy)
@@ -80,6 +80,7 @@
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 */
@@ -108,6 +109,11 @@
&VNET_NAME(arp_proxyall), 0,
"Enable proxy ARP for all suitable requests");
+struct arpstat arpstat; /* ARP statistics, see if_arp.h */
+SYSCTL_STRUCT(_net_link_ether_arp, OID_AUTO, stats, CTLFLAG_RW,
+ &arpstat, arpstat,
+ "ARP statistics (struct arpstat, net/if_arp.h)");
+
static void arp_init(void);
void arprequest(struct ifnet *,
struct in_addr *, struct in_addr *, u_char *);
@@ -127,6 +133,7 @@
#ifdef AF_INET
void arp_ifscrub(struct ifnet *ifp, uint32_t addr);
+
/*
* called by in_ifscrub to remove entry from the table when
* the interface goes away
@@ -165,12 +172,13 @@
ifp = lle->lle_tbl->llt_ifp;
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.arp_timeout++;
+ } else {
/*
* Still valid, just drop our reference
*/
@@ -238,6 +246,7 @@
sa.sa_len = 2;
m->m_flags |= M_BCAST;
(*ifp->if_output)(ifp, m, &sa, NULL);
+ arpstat.arp_requests++;
}
/*
@@ -339,8 +348,10 @@
* latest one.
*/
if (m != NULL) {
- if (la->la_hold != NULL)
+ if (la->la_hold != NULL) {
m_freem(la->la_hold);
+ arpstat.arp_dropped++;
+ }
la->la_hold = m;
if (renew == 0 && (flags & LLE_EXCLUSIVE)) {
flags &= ~LLE_EXCLUSIVE;
@@ -413,6 +424,7 @@
ar = mtod(m, struct arphdr *);
}
+ arpstat.arp_replies++;
switch (ntohs(ar->ar_pro)) {
#ifdef INET
case ETHERTYPE_IP:
@@ -603,6 +615,7 @@
ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
inet_ntoa(isaddr), ifp->if_xname);
itaddr = myaddr;
+ arpstat.arp_dupips++;
goto reply;
}
if (ifp->if_flags & IFF_STATICARP)
@@ -821,7 +834,7 @@
static void
arp_init(void)
{
-
+ bzero(&arpstat, sizeof(arpstat));
netisr_register(&arp_nh);
}
SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0);
Index: sys/net/if_arp.h
===================================================================
--- sys/net/if_arp.h (revision 196095)
+++ sys/net/if_arp.h (working copy)
@@ -108,6 +108,16 @@
#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 arp_requests; /* # of ARP requests sent by this host */
+ u_long arp_replies; /* # of ARP replies received by this host */
+ /* Abnormal event and error counting */
+ u_long arp_dropped; /* # of packets dropped while waiting for a
reply */
+ u_long arp_timeout; /* # of times an entry is removed due to timeout
*/
+ u_long arp_dupips; /* # of duplicate IPs detected. */
+};
+
#endif /* !_NET_IF_ARP_H_ */
More information about the freebsd-net
mailing list