Use underlying ports counters to get lagg statistics instead of

per-packet accounting.
This introduce user-visible changes like aggregating error counters.

Reviewed by:	asomers (prev.version), glebius
CR:		D781
MFC after:	2 weeks
Sponsored by:	Yandex LLC
This commit is contained in:
Alexander V. Chernikov 2014-09-27 13:57:48 +00:00
parent 4007b77e37
commit 7d6cc45c9b
3 changed files with 80 additions and 61 deletions

View File

@ -115,6 +115,7 @@ static int lagg_ether_cmdmulti(struct lagg_port *, int);
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, ift_counter cnt);
static int lagg_transmit(struct ifnet *, struct mbuf *);
static void lagg_qflush(struct ifnet *);
static int lagg_media_change(struct ifnet *);
@ -158,8 +159,6 @@ static struct mbuf *lagg_lacp_input(struct lagg_softc *, struct lagg_port *,
struct mbuf *);
static void lagg_lacp_lladdr(struct lagg_softc *);
static void lagg_callout(void *);
/* lagg protocol table */
static const struct lagg_proto {
lagg_proto pr_num;
@ -456,11 +455,6 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
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;
@ -490,16 +484,9 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
lagg_proto_attach(sc, LAGG_PROTO_DEFAULT);
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);
@ -512,6 +499,7 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
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;
@ -531,8 +519,6 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
SLIST_INSERT_HEAD(&lagg_list, sc, sc_entries);
mtx_unlock(&lagg_list_mtx);
callout_reset(&sc->sc_callout, hz, lagg_callout, sc);
return (0);
}
@ -561,22 +547,12 @@ lagg_clone_destroy(struct ifnet *ifp)
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);
}
@ -712,7 +688,8 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
{
struct lagg_softc *sc_ptr;
struct lagg_port *lp, *tlp;
int error;
int error, i;
uint64_t *pval;
LAGG_WLOCK_ASSERT(sc);
@ -836,6 +813,10 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
lagg_capabilities(sc);
lagg_linkstate(sc);
/* Read port counters */
pval = lp->port_counters.val;
for (i = IFCOUNTER_IPACKETS; i <= IFCOUNTER_LAST; 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);
@ -877,6 +858,8 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport)
struct lagg_port *lp_ptr;
struct lagg_llq *llq;
struct ifnet *ifp = lp->lp_ifp;
uint64_t *pval, vdiff;
int i;
LAGG_WLOCK_ASSERT(sc);
@ -899,6 +882,13 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport)
ifp->if_output = lp->lp_output;
ifp->if_lagg = NULL;
/* Update detached port counters */
pval = lp->port_counters.val;
for (i = IFCOUNTER_IPACKETS; i <= IFCOUNTER_LAST; i++, pval++) {
vdiff = ifp->if_get_counter(ifp, i) - *pval;
sc->detached_counters.val[i - 1] += vdiff;
}
/* Finally, remove the port from the lagg */
SLIST_REMOVE(&sc->sc_ports, lp, lagg_port, lp_entries);
sc->sc_count--;
@ -1011,6 +1001,61 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return (EINVAL);
}
/*
* Requests counter @cnt data.
*
* Counter value is calculated the following way:
* 1) for each port, sum difference between current and "initial" measurements.
* 2) add lagg logical interface counters.
* 3) add data from detached_counters array.
*
* We also do the following things on ports attach/detach:
* 1) On port attach we store all counters it has into port_counter array.
* 2) On port detach we add the different between "initial" and
* current counters data to detached_counters array.
*/
static uint64_t
lagg_get_counter(struct ifnet *ifp, ift_counter cnt)
{
struct lagg_softc *sc;
struct lagg_port *lp;
struct ifnet *lpifp;
struct rm_priotracker tracker;
uint64_t newval, oldval, vsum;
if (cnt <= 0 || cnt > IFCOUNTER_LAST)
return (if_get_counter_default(ifp, cnt));
sc = (struct lagg_softc *)ifp->if_softc;
LAGG_RLOCK(sc, &tracker);
vsum = 0;
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
/* Saved attached value */
oldval = lp->port_counters.val[cnt - 1];
/* current value */
lpifp = lp->lp_ifp;
newval = lpifp->if_get_counter(lpifp, cnt);
/* Calculate diff and save new */
vsum += newval - oldval;
}
/*
* Add counter data which might be added by upper
* layer protocols operating on logical interface.
*/
vsum += if_get_counter_default(ifp, cnt);
/*
* Add counter data from detached ports counters
*/
vsum += sc->detached_counters.val[cnt - 1];
LAGG_RUNLOCK(sc, &tracker);
return (vsum);
}
/*
* For direct output to child ports.
*/
@ -1449,11 +1494,7 @@ lagg_transmit(struct ifnet *ifp, struct mbuf *m)
error = lagg_proto_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);
@ -1489,9 +1530,6 @@ lagg_input(struct ifnet *ifp, struct mbuf *m)
m = lagg_proto_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;
@ -2124,16 +2162,3 @@ lagg_lacp_input(struct lagg_softc *sc, struct lagg_port *lp, struct mbuf *m)
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);
}

View File

@ -140,8 +140,6 @@ struct lagg_reqflags {
#ifdef _KERNEL
#include <sys/counter.h>
/*
* Internal kernel part
*/
@ -187,10 +185,13 @@ struct lagg_llq {
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 */
@ -202,11 +203,6 @@ struct lagg_softc {
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;
@ -220,6 +216,7 @@ struct lagg_softc {
struct sysctl_oid *sc_oid; /* sysctl tree oid */
int use_flowid; /* use M_FLOWID */
int flowid_shift; /* shift the flowid */
struct lagg_counters detached_counters; /* detached ports sum */
};
struct lagg_port {
@ -241,6 +238,7 @@ struct lagg_port {
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;
};
@ -254,11 +252,6 @@ struct lagg_port {
#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 );

View File

@ -109,6 +109,7 @@ typedef enum {
IFCOUNTER_OQDROPS,
IFCOUNTER_NOPROTO,
} ift_counter;
#define IFCOUNTER_LAST IFCOUNTER_NOPROTO
typedef struct ifnet * if_t;