this has the ifq count the statistics kept for output packets that we currently count on an ifnet.
unlike the ifnet stats, these are all maintained by the ifq as a matter of course except for the output errors counter. this means drivers wont have to account for outgoing packets like they do now, and they will be counted consistently with the number of bytes transmitted. errors can be updated by an interfaces start routine safely because it is serialised by the ifq_serialiazer. since most stats are protected by the mutex you can take the mutex to read the stats consistently. unfortunately there's no mechanism to serialise the read of the errors, but im not sure we care a lot. we could just read it twice to see if it stays th same. this only updates the stats at the moment. their values dont replace or get rolled into the ifnet stats yet. they are updated though. eg: (gdb) print $1->arpcom.ac_if.if_snd $2 = {ifq_if = 0x40011aae048, ifq_mtx = {mtx_owner = 0x0, mtx_wantipl = 12, mtx_oldipl = 2}, ifq_ops = 0x1693920, ifq_q = 0x40011a93700, ifq_len = 0, ifq_oactive = 0, ifq_packets = 0, ifq_bytes = 1908, ifq_qdrops = 619139, ifq_errors = 0, ifq_mcasts = 0, ifq_task_mtx = { mtx_owner = 0x3, mtx_wantipl = 0, mtx_oldipl = 0}, ifq_task_list = { tqh_first = 0xc00000002, tqh_last = 0x0}, ifq_serializer = 0x40011aae2d8, ifq_start = {t_entry = {tqe_next = 0x0, tqe_prev = 0xffffffffffffffff}, t_func = 0xffffffffffffffff, t_arg = 0x11fa4a0, t_flags = 1024}, ifq_restart = {t_entry = { tqe_next = 0x0, tqe_prev = 0x0}, t_func = 0, t_arg = 0x11fa500, t_flags = 1024}, ifq_maxlen = 0} i want to mvoe the stats here because ifnets will end up with multiple send rings represented by ifq structures. rather than serialise at the ifnet level for statistics, we can collect them on the rings where we have to serialise anyway and aggregate them for userland later. this in turn means we dont need to maintain per-cpu stats for ifnets. ok? Index: ifq.c =================================================================== RCS file: /cvs/src/sys/net/ifq.c,v retrieving revision 1.4 diff -u -p -r1.4 ifq.c --- ifq.c 29 Dec 2015 12:35:43 -0000 1.4 +++ ifq.c 20 Jan 2017 01:36:06 -0000 @@ -172,7 +172,7 @@ ifq_init(struct ifqueue *ifq, struct ifn ifq->ifq_if = ifp; mtx_init(&ifq->ifq_mtx, IPL_NET); - ifq->ifq_drops = 0; + ifq->ifq_qdrops = 0; /* default to priq */ ifq->ifq_ops = &priq_ops; @@ -214,7 +214,7 @@ ifq_attach(struct ifqueue *ifq, const st while ((m = ml_dequeue(&ml)) != NULL) { if (ifq->ifq_ops->ifqop_enq(ifq, m) != 0) { - ifq->ifq_drops++; + ifq->ifq_qdrops++; ml_enqueue(&free_ml, m); } else ifq->ifq_len++; @@ -246,10 +246,15 @@ ifq_enqueue_try(struct ifqueue *ifq, str mtx_enter(&ifq->ifq_mtx); rv = ifq->ifq_ops->ifqop_enq(ifq, m); - if (rv == 0) + if (rv == 0) { ifq->ifq_len++; - else - ifq->ifq_drops++; + + ifq->ifq_packets++; + ifq->ifq_bytes += m->m_pkthdr.len; + if (ISSET(m->m_flags, M_MCAST)) + ifq->ifq_mcasts++; + } else + ifq->ifq_qdrops++; mtx_leave(&ifq->ifq_mtx); return (rv); @@ -330,7 +335,7 @@ ifq_purge(struct ifqueue *ifq) ifq->ifq_ops->ifqop_purge(ifq, &ml); rv = ifq->ifq_len; ifq->ifq_len = 0; - ifq->ifq_drops += rv; + ifq->ifq_qdrops += rv; mtx_leave(&ifq->ifq_mtx); KASSERT(rv == ml_len(&ml)); Index: ifq.h =================================================================== RCS file: /cvs/src/sys/net/ifq.h,v retrieving revision 1.5 diff -u -p -r1.5 ifq.h --- ifq.h 20 Jan 2016 17:27:16 -0000 1.5 +++ ifq.h 20 Jan 2017 01:36:06 -0000 @@ -28,11 +28,17 @@ struct ifqueue { /* mbuf handling */ struct mutex ifq_mtx; - uint64_t ifq_drops; const struct ifq_ops *ifq_ops; void *ifq_q; unsigned int ifq_len; unsigned int ifq_oactive; + + /* statistics */ + uint64_t ifq_packets; + uint64_t ifq_bytes; + uint64_t ifq_qdrops; + uint64_t ifq_errors; + uint64_t ifq_mcasts; /* work serialisation */ struct mutex ifq_task_mtx;