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 */