Index: sys/net/if_lagg.h =================================================================== --- sys/net/if_lagg.h +++ sys/net/if_lagg.h @@ -136,8 +136,6 @@ #ifdef _KERNEL -#include - /* * Internal kernel part */ @@ -186,10 +184,13 @@ SLIST_ENTRY(lagg_llq) llq_entries; }; +struct lagg_counters { + uint64_t val[IFCOUNTER_LAST]; +}; + struct lagg_softc { struct ifnet *sc_ifp; /* virtual interface */ struct rmlock sc_mtx; - struct mtx sc_call_mtx; int sc_proto; /* lagg protocol */ u_int sc_count; /* number of ports */ u_int sc_active; /* active port count */ @@ -201,11 +202,6 @@ uint32_t sc_seq; /* sequence counter */ uint32_t sc_flags; - counter_u64_t sc_ipackets; - counter_u64_t sc_opackets; - counter_u64_t sc_ibytes; - counter_u64_t sc_obytes; - SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */ SLIST_ENTRY(lagg_softc) sc_entries; @@ -233,6 +229,8 @@ struct sysctl_oid *sc_oid; /* sysctl tree oid */ int use_flowid; /* use M_FLOWID */ int flowid_shift; /* shift the flowid */ + struct lagg_counters proto_counters; /* ifp counters copy */ + struct lagg_counters agg_counters; /* summary counters */ }; struct lagg_port { @@ -254,6 +252,7 @@ int (*lp_ioctl)(struct ifnet *, u_long, caddr_t); int (*lp_output)(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *); + struct lagg_counters port_counters; /* ifp counters copy */ SLIST_ENTRY(lagg_port) lp_entries; }; @@ -267,11 +266,6 @@ #define LAGG_RLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_RLOCKED) #define LAGG_WLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_WLOCKED) -#define LAGG_CALLOUT_LOCK_INIT(_sc) \ - mtx_init(&(_sc)->sc_call_mtx, "if_lagg callout mutex", NULL,\ - MTX_DEF) -#define LAGG_CALLOUT_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_call_mtx) - extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *); extern void (*lagg_linkstate_p)(struct ifnet *, int ); Index: sys/net/if_lagg.c =================================================================== --- sys/net/if_lagg.c +++ sys/net/if_lagg.c @@ -114,6 +114,7 @@ static int lagg_setflag(struct lagg_port *, int, int, int (*func)(struct ifnet *, int)); static int lagg_setflags(struct lagg_port *, int status); +static uint64_t lagg_get_counter(struct ifnet *ifp, ifnet_counter cnt); static int lagg_transmit(struct ifnet *, struct mbuf *); static void lagg_qflush(struct ifnet *); static int lagg_media_change(struct ifnet *); @@ -155,8 +156,6 @@ struct mbuf *); static void lagg_lacp_lladdr(struct lagg_softc *); -static void lagg_callout(void *); - /* lagg protocol table */ static const struct { int ti_proto; @@ -287,11 +286,6 @@ return (ENOSPC); } - sc->sc_ipackets = counter_u64_alloc(M_WAITOK); - sc->sc_opackets = counter_u64_alloc(M_WAITOK); - sc->sc_ibytes = counter_u64_alloc(M_WAITOK); - sc->sc_obytes = counter_u64_alloc(M_WAITOK); - sysctl_ctx_init(&sc->ctx); snprintf(num, sizeof(num), "%u", unit); sc->use_flowid = def_use_flowid; @@ -331,16 +325,9 @@ } } LAGG_LOCK_INIT(sc); - LAGG_CALLOUT_LOCK_INIT(sc); SLIST_INIT(&sc->sc_ports); TASK_INIT(&sc->sc_lladdr_task, 0, lagg_port_setlladdr, sc); - /* - * This uses the callout lock rather than the rmlock; one can't - * hold said rmlock during SWI. - */ - callout_init_mtx(&sc->sc_callout, &sc->sc_call_mtx, 0); - /* Initialise pseudo media types */ ifmedia_init(&sc->sc_media, 0, lagg_media_change, lagg_media_status); @@ -353,6 +340,7 @@ ifp->if_qflush = lagg_qflush; ifp->if_init = lagg_init; ifp->if_ioctl = lagg_ioctl; + ifp->if_get_counter = lagg_get_counter; ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; ifp->if_capenable = ifp->if_capabilities = IFCAP_HWSTATS; @@ -372,8 +360,6 @@ SLIST_INSERT_HEAD(&lagg_list, sc, sc_entries); mtx_unlock(&lagg_list_mtx); - callout_reset(&sc->sc_callout, hz, lagg_callout, sc); - return (0); } @@ -405,22 +391,12 @@ ether_ifdetach(ifp); if_free(ifp); - /* This grabs sc_callout_mtx, serialising it correctly */ - callout_drain(&sc->sc_callout); - - /* At this point it's drained; we can free this */ - counter_u64_free(sc->sc_ipackets); - counter_u64_free(sc->sc_opackets); - counter_u64_free(sc->sc_ibytes); - counter_u64_free(sc->sc_obytes); - mtx_lock(&lagg_list_mtx); SLIST_REMOVE(&lagg_list, sc, lagg_softc, sc_entries); mtx_unlock(&lagg_list_mtx); taskqueue_drain(taskqueue_swi, &sc->sc_lladdr_task); LAGG_LOCK_DESTROY(sc); - LAGG_CALLOUT_LOCK_DESTROY(sc); free(sc, M_DEVBUF); } @@ -563,6 +539,8 @@ { struct lagg_softc *sc_ptr; struct lagg_port *lp; + uint64_t *pval; + int i; int error = 0; LAGG_WLOCK_ASSERT(sc); @@ -677,6 +655,10 @@ lagg_capabilities(sc); lagg_linkstate(sc); + /* Read port counters */ + pval = lp->port_counters.val; + for (i = IFCOUNTER_IPACKETS; i <= IFCOUNTER_NOPROTO; i++, pval++) + *pval = ifp->if_get_counter(ifp, i); /* Add multicast addresses and interface flags to this port */ lagg_ether_cmdmulti(lp, 1); lagg_setflags(lp, 1); @@ -854,6 +836,57 @@ return (EINVAL); } +static uint64_t +lagg_get_counter(struct ifnet *ifp, ifnet_counter cnt) +{ + struct lagg_softc *sc; + struct lagg_port *lp; + struct ifnet *lpifp; + struct rm_priotracker tracker; + uint64_t newval, *pval, vdiff, vsum; + off_t off; + + if (cnt <= 0 || cnt > IFCOUNTER_LAST) + return (if_get_counter_compat(ifp, cnt)); + off = cnt - 1; + + sc = (struct lagg_softc *)ifp->if_softc; + LAGG_RLOCK(sc, &tracker); + + vsum = 0; + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + /* Saved old value */ + pval = &lp->port_counters.val[off]; + /* New value */ + lpifp = lp->lp_ifp; + newval = lpifp->if_get_counter(lpifp, cnt); + /* Calculate diff and save new */ + vdiff = newval - *pval; + *pval = newval; + vsum += vdiff; + } + + /* + * Add counter data which might be added by upper + * layer protocols operating on logical interface. + */ + pval = &sc->proto_counters.val[off]; + /* Read new value via "legacy" interface */ + newval = if_get_counter_compat(ifp, cnt); + vdiff = newval - *pval; + *pval = newval; + vsum += vdiff; + + /* Update aggregate value */ + pval = &sc->agg_counters.val[off]; + *pval += vsum; + vsum = *pval; + + LAGG_RUNLOCK(sc, &tracker); + + return (vsum); +} + /* * For direct output to child ports. */ @@ -1332,11 +1365,7 @@ error = (*sc->sc_start)(sc, m); LAGG_RUNLOCK(sc, &tracker); - if (error == 0) { - counter_u64_add(sc->sc_opackets, 1); - counter_u64_add(sc->sc_obytes, len); - ifp->if_omcasts += mcast; - } else + if (error != 0) ifp->if_oerrors++; return (error); @@ -1372,9 +1401,6 @@ m = (*sc->sc_input)(sc, lp, m); if (m != NULL) { - counter_u64_add(sc->sc_ipackets, 1); - counter_u64_add(sc->sc_ibytes, m->m_pkthdr.len); - if (scifp->if_flags & IFF_MONITOR) { m_freem(m); m = NULL; @@ -2006,16 +2032,3 @@ return (m); } -static void -lagg_callout(void *arg) -{ - struct lagg_softc *sc = (struct lagg_softc *)arg; - struct ifnet *ifp = sc->sc_ifp; - - ifp->if_ipackets = counter_u64_fetch(sc->sc_ipackets); - ifp->if_opackets = counter_u64_fetch(sc->sc_opackets); - ifp->if_ibytes = counter_u64_fetch(sc->sc_ibytes); - ifp->if_obytes = counter_u64_fetch(sc->sc_obytes); - - callout_reset(&sc->sc_callout, hz, lagg_callout, sc); -} Index: sys/net/if_var.h =================================================================== --- sys/net/if_var.h +++ sys/net/if_var.h @@ -109,6 +109,7 @@ IFCOUNTER_OQDROPS, IFCOUNTER_NOPROTO, } ifnet_counter; +#define IFCOUNTER_LAST IFCOUNTER_NOPROTO typedef struct ifnet * if_t;