From owner-freebsd-net@FreeBSD.ORG Wed Aug 12 13:57:16 2009 Return-Path: Delivered-To: net@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9B370106564A for ; Wed, 12 Aug 2009 13:57:16 +0000 (UTC) (envelope-from gnn@neville-neil.com) Received: from mail.meer.net (mail.meer.net [64.13.141.3]) by mx1.freebsd.org (Postfix) with ESMTP id 84CB78FC4A for ; Wed, 12 Aug 2009 13:57:16 +0000 (UTC) Received: from mail2.meer.net (mail2.meer.net [64.13.141.16]) by mail.meer.net (8.13.3/8.13.3/meer) with ESMTP id n7CDhtv6020183 for ; Wed, 12 Aug 2009 06:43:55 -0700 (PDT) (envelope-from gnn@neville-neil.com) Received: from gnnmac.hudson-trading.com (209.249.190.8.available.above.net [209.249.190.8] (may be forged)) (authenticated bits=0) by mail2.meer.net (8.14.1/8.14.3) with ESMTP id n7CDht5m012430 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NO) for ; Wed, 12 Aug 2009 06:43:55 -0700 (PDT) (envelope-from gnn@neville-neil.com) Message-Id: <533A2900-CDAC-4BFB-952B-45FB18E19B7E@neville-neil.com> From: George Neville-Neil To: net@freebsd.org Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v936) Date: Wed, 12 Aug 2009 09:43:54 -0400 X-Mailer: Apple Mail (2.936) Cc: Subject: RFC: ARP Statistics X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 12 Aug 2009 13:57:16 -0000 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 #include +#include #include #include #include @@ -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_ */