diff options
author | gnn <gnn@FreeBSD.org> | 2009-09-03 21:10:57 +0000 |
---|---|---|
committer | gnn <gnn@FreeBSD.org> | 2009-09-03 21:10:57 +0000 |
commit | 60eb51e7a3e3a1dfacd9d9284b7e21e1fe4de011 (patch) | |
tree | adac442cdf92025f0d2ded02f1a96f79bc1b1cfc /sys | |
parent | 5d151fa1f9e0bab1181b49200884097a9b1874ac (diff) | |
download | FreeBSD-src-60eb51e7a3e3a1dfacd9d9284b7e21e1fe4de011.zip FreeBSD-src-60eb51e7a3e3a1dfacd9d9284b7e21e1fe4de011.tar.gz |
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if_arp.h | 27 | ||||
-rw-r--r-- | sys/netinet/if_ether.c | 31 |
2 files changed, 51 insertions, 7 deletions
diff --git a/sys/net/if_arp.h b/sys/net/if_arp.h index 1e18804..2bb6358 100644 --- a/sys/net/if_arp.h +++ b/sys/net/if_arp.h @@ -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_ */ diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index e118cec..c170c7a 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -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*60); /* once resolved, good for 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, OID_AUTO, useloopback, CTLFLAG_RW, 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_addr *sip, struct in_addr *tip, 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: |