if vlan will be allowed to bypass its ifq when outputting packets, it
will still need to count them. if this potential vlan_output exists, it
will support being called concurrently in the system, so we need some
way of counting concurrently.

this adds per cpu counters to struct ifnet. interfaces that want them
can allocate them, and then the interface get data ioctl will look at
them and add them into the numbers collected by the ifqs and the
interface itself.

ok?

Index: if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.568
diff -u -p -r1.568 if.c
--- if.c        29 Nov 2018 00:11:49 -0000      1.568
+++ if.c        11 Dec 2018 01:40:40 -0000
@@ -84,6 +84,7 @@
 #include <sys/domain.h>
 #include <sys/task.h>
 #include <sys/atomic.h>
+#include <sys/percpu.h>
 #include <sys/proc.h>
 
 #include <dev/rndvar.h>
@@ -1103,6 +1104,9 @@ if_detach(struct ifnet *ifp)
        splx(s);
        NET_UNLOCK();
 
+       if (ifp->if_counters != NULL)
+               if_counters_free(ifp);
+
        for (i = 0; i < ifp->if_nifqs; i++)
                ifq_destroy(ifp->if_ifqs[i]);
        if (ifp->if_ifqs != ifp->if_snd.ifq_ifqs) {
@@ -2362,11 +2366,47 @@ ifconf(caddr_t data)
 }
 
 void
+if_counters_alloc(struct ifnet *ifp)
+{
+       KASSERT(ifp->if_counters == NULL);
+
+       ifp->if_counters = counters_alloc(ifc_ncounters);
+}
+
+void
+if_counters_free(struct ifnet *ifp)
+{
+       KASSERT(ifp->if_counters != NULL);
+
+       counters_free(ifp->if_counters, ifc_ncounters);
+       ifp->if_counters = NULL;
+}
+
+void
 if_getdata(struct ifnet *ifp, struct if_data *data)
 {
        unsigned int i;
 
        *data = ifp->if_data;
+
+       if (ifp->if_counters != NULL) {
+               uint64_t counters[ifc_ncounters];
+
+               counters_read(ifp->if_counters, counters, nitems(counters));
+
+               data->ifi_ipackets += counters[ifc_ipackets];
+               data->ifi_ierrors += counters[ifc_ierrors];
+               data->ifi_opackets += counters[ifc_opackets];
+               data->ifi_oerrors += counters[ifc_oerrors];
+               data->ifi_collisions += counters[ifc_collisions];
+               data->ifi_ibytes += counters[ifc_ibytes];
+               data->ifi_obytes += counters[ifc_obytes];
+               data->ifi_imcasts += counters[ifc_imcasts];
+               data->ifi_omcasts += counters[ifc_omcasts];
+               data->ifi_iqdrops += counters[ifc_iqdrops];
+               data->ifi_oqdrops += counters[ifc_oqdrops];
+               data->ifi_noproto += counters[ifc_noproto];
+       }
 
        for (i = 0; i < ifp->if_nifqs; i++) {
                struct ifqueue *ifq = ifp->if_ifqs[i];
Index: if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.90
diff -u -p -r1.90 if_var.h
--- if_var.h    10 Sep 2018 16:18:34 -0000      1.90
+++ if_var.h    11 Dec 2018 01:40:40 -0000
@@ -76,6 +76,7 @@
 struct rtentry;
 struct ifnet;
 struct task;
+struct cpumem;
 
 /*
  * Structure describing a `cloning' interface.
@@ -144,6 +145,7 @@ struct ifnet {                              /* and the 
entries */
        unsigned short if_flags;        /* [N] up/down, broadcast, etc. */
        int     if_xflags;              /* [N] extra softnet flags */
        struct  if_data if_data;        /* stats and other data about if */
+       struct  cpumem *if_counters;    /* per cpu stats */
        uint32_t if_hardmtu;            /* [d] maximum MTU device supports */
        char    if_description[IFDESCRSIZE]; /* [c] interface description */
        u_short if_rtlabelid;           /* [c] next route label */
@@ -202,6 +204,23 @@ struct ifnet {                             /* and the 
entries */
 #define        if_capabilities if_data.ifi_capabilities
 #define        if_rdomain      if_data.ifi_rdomain
 
+enum if_counters {
+       ifc_ipackets,           /* packets received on interface */
+       ifc_ierrors,            /* input errors on interface */
+       ifc_opackets,           /* packets sent on interface */
+       ifc_oerrors,            /* output errors on interface */
+       ifc_collisions,         /* collisions on csma interfaces */
+       ifc_ibytes,             /* total number of octets received */
+       ifc_obytes,             /* total number of octets sent */
+       ifc_imcasts,            /* packets received via multicast */
+       ifc_omcasts,            /* packets sent via multicast */
+       ifc_iqdrops,            /* dropped on input, this interface */
+       ifc_oqdrops,            /* dropped on output, this interface */
+       ifc_noproto,            /* destined for unsupported protocol */
+
+       ifc_ncounters
+};
+
 /*
  * The ifaddr structure contains information about one address
  * of an interface.  They are maintained by the different address families,
@@ -356,6 +375,9 @@ u_int       if_rxr_get(struct if_rxring *, u_i
 int    if_rxr_info_ioctl(struct if_rxrinfo *, u_int, struct if_rxring_info *);
 int    if_rxr_ioctl(struct if_rxrinfo *, const char *, u_int,
            struct if_rxring *);
+
+void   if_counters_alloc(struct ifnet *);
+void   if_counters_free(struct ifnet *);
 
 #endif /* _KERNEL */
 

Reply via email to