Author: glebius
Date: Tue Oct 15 11:37:57 2013
New Revision: 256525
URL: http://svnweb.freebsd.org/changeset/base/256525

Log:
  - Utilize counter(9) to accumulate statistics on interface addresses. Add
    four counters to struct ifaddr. This kills '+=' on a variables shared
    between processors for every packet.
  - Nuke struct if_data from struct ifaddr.
  - In ip_input() do not put a reference on ifaddr, instead update statistics
    right now in place and do IN_IFADDR_RUNLOCK(). These removes atomic(9)
    for every packet. [1]
  - To properly support NET_RT_IFLISTL sysctl used by getifaddrs(3), in
    rtsock.c fill if_data fields using counter_u64_fetch().
  - Accidentially fix bug in COMPAT_32 version of NET_RT_IFLISTL, which
    took if_data not from the ifaddr, but from ifaddr's ifnet. [2]
  
  Submitted by: melifaro [1], pluknet[2]
  Sponsored by: Netflix
  Sponsored by: Nginx, Inc.

Modified:
  head/sys/net/if.c
  head/sys/net/if_var.h
  head/sys/net/rtsock.c
  head/sys/netinet/ip_input.c
  head/sys/netinet/ip_output.c
  head/sys/netinet6/ip6_input.c
  head/sys/netinet6/ip6_output.c

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c   Tue Oct 15 11:25:12 2013        (r256524)
+++ head/sys/net/if.c   Tue Oct 15 11:37:57 2013        (r256525)
@@ -1428,10 +1428,28 @@ ifa_alloc(size_t size, int flags)
        if (ifa == NULL)
                return (NULL);
 
+       if ((ifa->ifa_opackets = counter_u64_alloc(flags)) == NULL)
+               goto fail;
+       if ((ifa->ifa_ipackets = counter_u64_alloc(flags)) == NULL)
+               goto fail;
+       if ((ifa->ifa_obytes = counter_u64_alloc(flags)) == NULL)
+               goto fail;
+       if ((ifa->ifa_ibytes = counter_u64_alloc(flags)) == NULL)
+               goto fail;
+
        refcount_init(&ifa->ifa_refcnt, 1);
-       ifa->if_data.ifi_datalen = sizeof(ifa->if_data);
 
        return (ifa);
+
+fail:
+       /* free(NULL) is okay */
+       counter_u64_free(ifa->ifa_opackets);
+       counter_u64_free(ifa->ifa_ipackets);
+       counter_u64_free(ifa->ifa_obytes);
+       counter_u64_free(ifa->ifa_ibytes);
+       free(ifa, M_IFADDR);
+
+       return (NULL);
 }
 
 void
@@ -1446,6 +1464,10 @@ ifa_free(struct ifaddr *ifa)
 {
 
        if (refcount_release(&ifa->ifa_refcnt)) {
+               counter_u64_free(ifa->ifa_opackets);
+               counter_u64_free(ifa->ifa_ipackets);
+               counter_u64_free(ifa->ifa_obytes);
+               counter_u64_free(ifa->ifa_ibytes);
                free(ifa, M_IFADDR);
        }
 }

Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h       Tue Oct 15 11:25:12 2013        (r256524)
+++ head/sys/net/if_var.h       Tue Oct 15 11:37:57 2013        (r256525)
@@ -83,6 +83,7 @@ struct        vnet;
 #include <sys/buf_ring.h>
 #include <net/vnet.h>
 #endif /* _KERNEL */
+#include <sys/counter.h>
 #include <sys/lock.h>          /* XXX */
 #include <sys/mutex.h>         /* XXX */
 #include <sys/rwlock.h>                /* XXX */
@@ -794,7 +795,6 @@ struct ifaddr {
        struct  sockaddr *ifa_dstaddr;  /* other end of p-to-p link */
 #define        ifa_broadaddr   ifa_dstaddr     /* broadcast address interface 
*/
        struct  sockaddr *ifa_netmask;  /* used to determine subnet */
-       struct  if_data if_data;        /* not all members are meaningful */
        struct  ifnet *ifa_ifp;         /* back-pointer to interface */
        struct  carp_softc *ifa_carp;   /* pointer to CARP data */
        TAILQ_ENTRY(ifaddr) ifa_link;   /* queue macro glue */
@@ -805,6 +805,11 @@ struct ifaddr {
        int     ifa_metric;             /* cost of going out this interface */
        int (*ifa_claim_addr)           /* check if an addr goes to this if */
                (struct ifaddr *, struct sockaddr *);
+
+       counter_u64_t   ifa_ipackets;
+       counter_u64_t   ifa_opackets;    
+       counter_u64_t   ifa_ibytes;
+       counter_u64_t   ifa_obytes;
 };
 #endif
 

Modified: head/sys/net/rtsock.c
==============================================================================
--- head/sys/net/rtsock.c       Tue Oct 15 11:25:12 2013        (r256524)
+++ head/sys/net/rtsock.c       Tue Oct 15 11:37:57 2013        (r256525)
@@ -1751,7 +1751,17 @@ sysctl_iflist_ifaml(struct ifaddr *ifa, 
                    offsetof(struct ifa_msghdrl32, ifam_data);
                ifam32->ifam_metric = ifa->ifa_metric;
 
-               copy_ifdata32(&ifa->ifa_ifp->if_data, &ifam32->ifam_data);
+               bzero(&ifam32->ifam_data, sizeof(ifam32->ifam_data));
+               ifam32->ifam_data.ifi_datalen = sizeof(struct if_data32);
+               ifam32->ifam_data.ifi_ipackets =
+                   counter_u64_fetch(ifa->ifa_ipackets);
+               ifam32->ifam_data.ifi_opackets =
+                   counter_u64_fetch(ifa->ifa_opackets);
+               ifam32->ifam_data.ifi_ibytes =
+                   counter_u64_fetch(ifa->ifa_ibytes);
+               ifam32->ifam_data.ifi_obytes =
+                   counter_u64_fetch(ifa->ifa_obytes);
+
                /* Fixup if_data carp(4) vhid. */
                if (carp_get_vhid_p != NULL)
                        ifam32->ifam_data.ifi_vhid = (*carp_get_vhid_p)(ifa);
@@ -1769,7 +1779,13 @@ sysctl_iflist_ifaml(struct ifaddr *ifa, 
        ifam->ifam_data_off = offsetof(struct ifa_msghdrl, ifam_data);
        ifam->ifam_metric = ifa->ifa_metric;
 
-       ifam->ifam_data = ifa->if_data;
+       bzero(&ifam->ifam_data, sizeof(ifam->ifam_data));
+       ifam->ifam_data.ifi_datalen = sizeof(struct if_data);
+       ifam->ifam_data.ifi_ipackets = counter_u64_fetch(ifa->ifa_ipackets);
+       ifam->ifam_data.ifi_opackets = counter_u64_fetch(ifa->ifa_opackets);
+       ifam->ifam_data.ifi_ibytes = counter_u64_fetch(ifa->ifa_ibytes);
+       ifam->ifam_data.ifi_obytes = counter_u64_fetch(ifa->ifa_obytes);
+
        /* Fixup if_data carp(4) vhid. */
        if (carp_get_vhid_p != NULL)
                ifam->ifam_data.ifi_vhid = (*carp_get_vhid_p)(ifa);

Modified: head/sys/netinet/ip_input.c
==============================================================================
--- head/sys/netinet/ip_input.c Tue Oct 15 11:25:12 2013        (r256524)
+++ head/sys/netinet/ip_input.c Tue Oct 15 11:37:57 2013        (r256525)
@@ -603,7 +603,9 @@ passin:
                 */
                if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr && 
                    (!checkif || ia->ia_ifp == ifp)) {
-                       ifa_ref(&ia->ia_ifa);
+                       counter_u64_add(ia->ia_ifa.ifa_ipackets, 1);
+                       counter_u64_add(ia->ia_ifa.ifa_ibytes,
+                           m->m_pkthdr.len);
                        /* IN_IFADDR_RUNLOCK(); */
                        goto ours;
                }
@@ -626,13 +628,17 @@ passin:
                        ia = ifatoia(ifa);
                        if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
                            ip->ip_dst.s_addr) {
-                               ifa_ref(ifa);
+                               counter_u64_add(ia->ia_ifa.ifa_ipackets, 1);
+                               counter_u64_add(ia->ia_ifa.ifa_ibytes,
+                                   m->m_pkthdr.len);
                                IF_ADDR_RUNLOCK(ifp);
                                goto ours;
                        }
 #ifdef BOOTP_COMPAT
                        if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) {
-                               ifa_ref(ifa);
+                               counter_u64_add(ia->ia_ifa.ifa_ipackets, 1);
+                               counter_u64_add(ia->ia_ifa.ifa_ibytes,
+                                   m->m_pkthdr.len);
                                IF_ADDR_RUNLOCK(ifp);
                                goto ours;
                        }
@@ -717,20 +723,10 @@ ours:
         * IPSTEALTH: Process non-routing options only
         * if the packet is destined for us.
         */
-       if (V_ipstealth && hlen > sizeof (struct ip) && ip_dooptions(m, 1)) {
-               if (ia != NULL)
-                       ifa_free(&ia->ia_ifa);
+       if (V_ipstealth && hlen > sizeof (struct ip) && ip_dooptions(m, 1))
                return;
-       }
 #endif /* IPSTEALTH */
 
-       /* Count the packet in the ip address stats */
-       if (ia != NULL) {
-               ia->ia_ifa.if_ipackets++;
-               ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
-               ifa_free(&ia->ia_ifa);
-       }
-
        /*
         * Attempt reassembly; if it succeeds, proceed.
         * ip_reass() will return a different mbuf.

Modified: head/sys/netinet/ip_output.c
==============================================================================
--- head/sys/netinet/ip_output.c        Tue Oct 15 11:25:12 2013        
(r256524)
+++ head/sys/netinet/ip_output.c        Tue Oct 15 11:37:57 2013        
(r256525)
@@ -610,11 +610,12 @@ passout:
                 */
                if (!(flags & IP_FORWARDING) && ia) {
                        if (m->m_pkthdr.csum_flags & CSUM_TSO)
-                               ia->ia_ifa.if_opackets +=
-                                   m->m_pkthdr.len / m->m_pkthdr.tso_segsz;
+                               counter_u64_add(ia->ia_ifa.ifa_opackets,
+                                   m->m_pkthdr.len / m->m_pkthdr.tso_segsz);
                        else
-                               ia->ia_ifa.if_opackets++;
-                       ia->ia_ifa.if_obytes += m->m_pkthdr.len;
+                               counter_u64_add(ia->ia_ifa.ifa_opackets, 1);
+
+                       counter_u64_add(ia->ia_ifa.ifa_obytes, m->m_pkthdr.len);
                }
 #ifdef MBUF_STRESS_TEST
                if (mbuf_frag_size && m->m_pkthdr.len > mbuf_frag_size)
@@ -651,8 +652,9 @@ passout:
                if (error == 0) {
                        /* Record statistics for this interface address. */
                        if (ia != NULL) {
-                               ia->ia_ifa.if_opackets++;
-                               ia->ia_ifa.if_obytes += m->m_pkthdr.len;
+                               counter_u64_add(ia->ia_ifa.ifa_opackets, 1);
+                               counter_u64_add(ia->ia_ifa.ifa_obytes,
+                                   m->m_pkthdr.len);
                        }
                        /*
                         * Reset layer specific mbuf flags

Modified: head/sys/netinet6/ip6_input.c
==============================================================================
--- head/sys/netinet6/ip6_input.c       Tue Oct 15 11:25:12 2013        
(r256524)
+++ head/sys/netinet6/ip6_input.c       Tue Oct 15 11:37:57 2013        
(r256525)
@@ -724,8 +724,9 @@ passin:
                ia6 = (struct in6_ifaddr *)ifa;
                if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) {
                        /* Count the packet in the ip address stats */
-                       ia6->ia_ifa.if_ipackets++;
-                       ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;
+                       counter_u64_add(ia6->ia_ifa.ifa_ipackets, 1);
+                       counter_u64_add(ia6->ia_ifa.ifa_ibytes,
+                           m->m_pkthdr.len);
 
                        /*
                         * record address information into m_tag.
@@ -840,8 +841,9 @@ passin:
                        ours = 1;
                        deliverifp = ia6->ia_ifp;       /* correct? */
                        /* Count the packet in the ip address stats */
-                       ia6->ia_ifa.if_ipackets++;
-                       ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;
+                       counter_u64_add(ia6->ia_ifa.ifa_ipackets, 1);
+                       counter_u64_add(ia6->ia_ifa.ifa_ibytes,
+                           m->m_pkthdr.len);
                        if (free_ia6)
                                ifa_free(&ia6->ia_ifa);
                        goto hbhcheck;

Modified: head/sys/netinet6/ip6_output.c
==============================================================================
--- head/sys/netinet6/ip6_output.c      Tue Oct 15 11:25:12 2013        
(r256524)
+++ head/sys/netinet6/ip6_output.c      Tue Oct 15 11:37:57 2013        
(r256525)
@@ -1021,8 +1021,9 @@ passout:
                ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
                if (ia6) {
                        /* Record statistics for this interface address. */
-                       ia6->ia_ifa.if_opackets++;
-                       ia6->ia_ifa.if_obytes += m->m_pkthdr.len;
+                       counter_u64_add(ia6->ia_ifa.ifa_opackets, 1);
+                       counter_u64_add(ia6->ia_ifa.ifa_obytes,
+                           m->m_pkthdr.len);
                        ifa_free(&ia6->ia_ifa);
                }
                error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
@@ -1177,8 +1178,9 @@ sendorfree:
                if (error == 0) {
                        /* Record statistics for this interface address. */
                        if (ia) {
-                               ia->ia_ifa.if_opackets++;
-                               ia->ia_ifa.if_obytes += m->m_pkthdr.len;
+                               counter_u64_add(ia->ia_ifa.ifa_opackets, 1);
+                               counter_u64_add(ia->ia_ifa.ifa_obytes,
+                                   m->m_pkthdr.len);
                        }
                        error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
                } else
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to