diff --git a/sys/net/if.c b/sys/net/if.c index 831dc3f390b0..a7fb2a95feec 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -468,6 +468,10 @@ if_alloc(u_char type) refcount_init(&ifp->if_refcount, 1); /* Index reference. */ ifnet_setbyindex(ifp->if_index, ifp); + + for (int i = 0; i < IFCOUNTERS; i++) + ifp->if_counters[i] = counter_u64_alloc(M_WAITOK); + return (ifp); } @@ -495,6 +499,10 @@ if_free_internal(struct ifnet *ifp) IF_AFDATA_DESTROY(ifp); IF_ADDR_LOCK_DESTROY(ifp); ifq_delete(&ifp->if_snd); + + for (int i = 0; i < IFCOUNTERS; i++) + counter_u64_free(ifp->if_counters[i]); + free(ifp, M_IFNET); } @@ -1460,39 +1468,15 @@ if_rtdel(struct radix_node *rn, void *arg) } /* - * Return counter values from old racy non-pcpu counters. + * Return counter values from counter(9)s stored in ifnet. */ uint64_t if_get_counter_default(struct ifnet *ifp, ift_counter cnt) { - switch (cnt) { - case IFCOUNTER_IPACKETS: - return (ifp->if_ipackets); - case IFCOUNTER_IERRORS: - return (ifp->if_ierrors); - case IFCOUNTER_OPACKETS: - return (ifp->if_opackets); - case IFCOUNTER_OERRORS: - return (ifp->if_oerrors); - case IFCOUNTER_COLLISIONS: - return (ifp->if_collisions); - case IFCOUNTER_IBYTES: - return (ifp->if_ibytes); - case IFCOUNTER_OBYTES: - return (ifp->if_obytes); - case IFCOUNTER_IMCASTS: - return (ifp->if_imcasts); - case IFCOUNTER_OMCASTS: - return (ifp->if_omcasts); - case IFCOUNTER_IQDROPS: - return (ifp->if_iqdrops); - case IFCOUNTER_OQDROPS: - return (ifp->if_oqdrops); - case IFCOUNTER_NOPROTO: - return (ifp->if_noproto); - } - panic("%s: unknown counter %d", __func__, cnt); + KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); + + return (counter_u64_fetch(ifp->if_counters[cnt])); } /* @@ -1503,46 +1487,9 @@ void if_inc_counter(struct ifnet *ifp, ift_counter cnt, int64_t inc) { - switch (cnt) { - case IFCOUNTER_IPACKETS: - ifp->if_ipackets += inc; - break; - case IFCOUNTER_IERRORS: - ifp->if_ierrors += inc; - break; - case IFCOUNTER_OPACKETS: - ifp->if_opackets += inc; - break; - case IFCOUNTER_OERRORS: - ifp->if_oerrors += inc; - break; - case IFCOUNTER_COLLISIONS: - ifp->if_collisions += inc; - break; - case IFCOUNTER_IBYTES: - ifp->if_ibytes += inc; - break; - case IFCOUNTER_OBYTES: - ifp->if_obytes += inc; - break; - case IFCOUNTER_IMCASTS: - ifp->if_imcasts += inc; - break; - case IFCOUNTER_OMCASTS: - ifp->if_omcasts += inc; - break; - case IFCOUNTER_IQDROPS: - ifp->if_iqdrops += inc; - break; - case IFCOUNTER_OQDROPS: - ifp->if_oqdrops += inc; - break; - case IFCOUNTER_NOPROTO: - ifp->if_noproto += inc; - break; - default: - panic("%s: unknown counter %d", __func__, cnt); - } + KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); + + counter_u64_add(ifp->if_counters[cnt], inc); } /* @@ -3596,14 +3543,14 @@ if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust) IF_LOCK(ifq); if (_IF_QFULL(ifq)) { IF_UNLOCK(ifq); - ifp->if_oqdrops++; + if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); m_freem(m); return (0); } if (ifp != NULL) { - ifp->if_obytes += m->m_pkthdr.len + adjust; + if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len + adjust); if (m->m_flags & (M_BCAST|M_MCAST)) - ifp->if_omcasts++; + if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); active = ifp->if_drv_flags & IFF_DRV_OACTIVE; } _IF_ENQUEUE(ifq, m); diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index d58fb3916ad7..571284b380d0 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -815,7 +815,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) /* Read port counters */ pval = lp->port_counters.val; - for (i = IFCOUNTER_IPACKETS; i <= IFCOUNTER_LAST; i++, pval++) + for (i = 0; i < IFCOUNTERS; i++, pval++) *pval = ifp->if_get_counter(ifp, i); /* Add multicast addresses and interface flags to this port */ lagg_ether_cmdmulti(lp, 1); @@ -884,9 +884,9 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport) /* Update detached port counters */ pval = lp->port_counters.val; - for (i = IFCOUNTER_IPACKETS; i <= IFCOUNTER_LAST; i++, pval++) { + for (i = 0; i <= IFCOUNTERS; i++, pval++) { vdiff = ifp->if_get_counter(ifp, i) - *pval; - sc->detached_counters.val[i - 1] += vdiff; + sc->detached_counters.val[i] += vdiff; } /* Finally, remove the port from the lagg */ @@ -1023,8 +1023,8 @@ lagg_get_counter(struct ifnet *ifp, ift_counter cnt) struct rm_priotracker tracker; uint64_t newval, oldval, vsum; - if (cnt <= 0 || cnt > IFCOUNTER_LAST) - return (if_get_counter_default(ifp, cnt)); + /* Revise this when we've got non-generic counters. */ + KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); sc = (struct lagg_softc *)ifp->if_softc; LAGG_RLOCK(sc, &tracker); @@ -1032,7 +1032,7 @@ lagg_get_counter(struct ifnet *ifp, ift_counter cnt) vsum = 0; SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { /* Saved attached value */ - oldval = lp->port_counters.val[cnt - 1]; + oldval = lp->port_counters.val[cnt]; /* current value */ lpifp = lp->lp_ifp; newval = lpifp->if_get_counter(lpifp, cnt); @@ -1049,7 +1049,7 @@ lagg_get_counter(struct ifnet *ifp, ift_counter cnt) /* * Add counter data from detached ports counters */ - vsum += sc->detached_counters.val[cnt - 1]; + vsum += sc->detached_counters.val[cnt]; LAGG_RUNLOCK(sc, &tracker); diff --git a/sys/net/if_lagg.h b/sys/net/if_lagg.h index 658d8b49e618..5aeae571da77 100644 --- a/sys/net/if_lagg.h +++ b/sys/net/if_lagg.h @@ -186,7 +186,7 @@ struct lagg_llq { }; struct lagg_counters { - uint64_t val[IFCOUNTER_LAST]; + uint64_t val[IFCOUNTERS]; }; struct lagg_softc { diff --git a/sys/net/if_var.h b/sys/net/if_var.h index ebaa0f697a54..46398dd33c69 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -96,7 +96,7 @@ VNET_DECLARE(struct pfil_head, link_pfil_hook); /* packet filter hooks */ #endif /* _KERNEL */ typedef enum { - IFCOUNTER_IPACKETS = 1, + IFCOUNTER_IPACKETS = 0, IFCOUNTER_IERRORS, IFCOUNTER_OPACKETS, IFCOUNTER_OERRORS, @@ -108,8 +108,8 @@ typedef enum { IFCOUNTER_IQDROPS, IFCOUNTER_OQDROPS, IFCOUNTER_NOPROTO, + IFCOUNTERS /* Array size. */ } ift_counter; -#define IFCOUNTER_LAST IFCOUNTER_NOPROTO typedef struct ifnet * if_t; @@ -228,28 +228,15 @@ struct ifnet { (struct ifnet *, struct vnet *, char *); if_get_counter_t if_get_counter; /* get counter values */ + /* Statistics. */ + counter_u64_t if_counters[IFCOUNTERS]; + /* Stuff that's only temporary and doesn't belong here. */ u_int if_hw_tsomax; /* TSO total burst length * limit in bytes. A value of * zero means no limit. Have * to find a better place for * it eventually. */ - /* - * Old, racy and expensive statistics, should not be used in - * new drivers. - */ - uint64_t if_ipackets; /* packets received on interface */ - uint64_t if_ierrors; /* input errors on interface */ - uint64_t if_opackets; /* packets sent on interface */ - uint64_t if_oerrors; /* output errors on interface */ - uint64_t if_collisions; /* collisions on csma interfaces */ - uint64_t if_ibytes; /* total number of octets received */ - uint64_t if_obytes; /* total number of octets sent */ - uint64_t if_imcasts; /* packets received via multicast */ - uint64_t if_omcasts; /* packets sent via multicast */ - uint64_t if_iqdrops; /* dropped on input */ - uint64_t if_oqdrops; /* dropped on output */ - uint64_t if_noproto; /* destined for unsupported protocol */ /* TSO fields for segment limits. If a field is zero below, there is no limit. */ u_int if_hw_tsomaxsegcount; /* TSO maximum segment count */ diff --git a/sys/net/ifq.h b/sys/net/ifq.h index b787ea1cfa81..14ef8b25033a 100644 --- a/sys/net/ifq.h +++ b/sys/net/ifq.h @@ -41,7 +41,12 @@ #include /* XXX */ #include /* struct ifqueue */ +/* + * Couple of ugly extra definitions that are required since ifq.h + * is splitted from if_var.h. + */ #define IF_DUNIT_NONE -1 +void if_inc_counter(struct ifnet *, ift_counter, int64_t inc); #include @@ -245,13 +250,13 @@ do { \ mflags = (m)->m_flags; \ IFQ_ENQUEUE(&(ifp)->if_snd, m, err); \ if ((err) == 0) { \ - (ifp)->if_obytes += len + (adj); \ + if_inc_counter((ifp), IFCOUNTER_OBYTES, len + (adj)); \ if (mflags & M_MCAST) \ - (ifp)->if_omcasts++; \ + if_inc_counter((ifp), IFCOUNTER_OMCASTS, 1); \ if (((ifp)->if_drv_flags & IFF_DRV_OACTIVE) == 0) \ if_start(ifp); \ } else \ - ifp->if_oqdrops++; \ + if_inc_counter((ifp), IFCOUNTER_OQDROPS, 1); \ } while (0) #define IFQ_HANDOFF(ifp, m, err) \ @@ -318,7 +323,7 @@ drbr_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m) if (ALTQ_IS_ENABLED(&ifp->if_snd)) { IFQ_ENQUEUE(&ifp->if_snd, m, error); if (error) - ifp->if_oqdrops++; + if_inc_counter((ifp), IFCOUNTER_OQDROPS, 1); return (error); } #endif