Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 12 Aug 2009 09:43:54 -0400
From:      George Neville-Neil <gnn@neville-neil.com>
To:        net@freebsd.org
Subject:   RFC: ARP Statistics
Message-ID:  <533A2900-CDAC-4BFB-952B-45FB18E19B7E@neville-neil.com>

next in thread | raw e-mail | index | archive | help
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_ */




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?533A2900-CDAC-4BFB-952B-45FB18E19B7E>