RFC: ARP Statistics

Adrian Penisoara ady at freebsd.ady.ro
Thu Aug 13 16:35:09 UTC 2009


Hi,
  Perhaps it would be useful to add a "ARP flip-flop events" field, counting
the "arp: <IP> is on <intf1> but got reply from <ARP> on <intf2>" events.

PS: minor nit/correction: use "ARP cache entries timed out" instead of "ARP
entrys timed out"

Regards,
Adrian Penisoara
EnterpriseBSD

On Wed, Aug 12, 2009 at 3:43 PM, George Neville-Neil
<gnn at neville-neil.com>wrote:

> 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_ */
>
> _______________________________________________
> freebsd-net at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-net
> To unsubscribe, send any mail to "freebsd-net-unsubscribe at freebsd.org"
>


More information about the freebsd-net mailing list