Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 3 Sep 2009 21:10:57 +0000 (UTC)
From:      "George V. Neville-Neil" <gnn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r196797 - in head: sys/net sys/netinet usr.bin/netstat
Message-ID:  <200909032110.n83LAvUF044731@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gnn
Date: Thu Sep  3 21:10:57 2009
New Revision: 196797
URL: http://svn.freebsd.org/changeset/base/196797

Log:
  Add ARP statistics to the kernel and netstat.
  
  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

Modified:
  head/sys/net/if_arp.h
  head/sys/netinet/if_ether.c
  head/usr.bin/netstat/inet.c
  head/usr.bin/netstat/main.c
  head/usr.bin/netstat/netstat.h

Modified: head/sys/net/if_arp.h
==============================================================================
--- head/sys/net/if_arp.h	Thu Sep  3 19:02:17 2009	(r196796)
+++ head/sys/net/if_arp.h	Thu Sep  3 21:10:57 2009	(r196797)
@@ -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_ */

Modified: head/sys/netinet/if_ether.c
==============================================================================
--- head/sys/netinet/if_ether.c	Thu Sep  3 19:02:17 2009	(r196796)
+++ head/sys/netinet/if_ether.c	Thu Sep  3 21:10:57 2009	(r196797)
@@ -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 */
@@ -89,10 +90,12 @@ static VNET_DEFINE(int, arpt_keep) = (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,
@@ -107,6 +110,9 @@ SYSCTL_VNET_INT(_net_link_ether_inet, OI
 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 *,
@@ -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();
 }
 
 /*
@@ -238,6 +247,7 @@ arprequest(struct ifnet *ifp, struct in_
 	sa.sa_len = 2;
 	m->m_flags |= M_BCAST;
 	(*ifp->if_output)(ifp, m, &sa, NULL);
+	ARPSTAT_INC(txrequests);
 }
 
 /*
@@ -339,8 +349,10 @@ retry:
 	 * 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;
@@ -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:
@@ -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
@@ -603,6 +619,7 @@ match:
 		   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)
@@ -686,6 +703,7 @@ match:
 reply:
 	if (op != ARPOP_REQUEST)
 		goto drop;
+	ARPSTAT_INC(rxrequests);
 
 	if (itaddr.s_addr == myaddr.s_addr) {
 		/* Shortcut.. the receiving interface is the target. */
@@ -774,6 +792,7 @@ reply:
 	sa.sa_family = AF_ARP;
 	sa.sa_len = 2;
 	(*ifp->if_output)(ifp, m, &sa, NULL);
+	ARPSTAT_INC(txreplies);
 	return;
 
 drop:

Modified: head/usr.bin/netstat/inet.c
==============================================================================
--- head/usr.bin/netstat/inet.c	Thu Sep  3 19:02:17 2009	(r196796)
+++ head/usr.bin/netstat/inet.c	Thu Sep  3 21:10:57 2009	(r196797)
@@ -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>
@@ -871,6 +872,47 @@ ip_stats(u_long off, const char *name, i
 #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",

Modified: head/usr.bin/netstat/main.c
==============================================================================
--- head/usr.bin/netstat/main.c	Thu Sep  3 19:02:17 2009	(r196796)
+++ head/usr.bin/netstat/main.c	Thu Sep  3 21:10:57 2009	(r196797)
@@ -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 },
 };
 
@@ -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 }
 };

Modified: head/usr.bin/netstat/netstat.h
==============================================================================
--- head/usr.bin/netstat/netstat.h	Thu Sep  3 19:02:17 2009	(r196796)
+++ head/usr.bin/netstat/netstat.h	Thu Sep  3 21:10:57 2009	(r196797)
@@ -75,6 +75,7 @@ void	udp_stats(u_long, const char *, 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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200909032110.n83LAvUF044731>