summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2014-09-27 13:57:48 +0000
committermelifaro <melifaro@FreeBSD.org>2014-09-27 13:57:48 +0000
commit7d70b89c51d6f8dff25417542c5ec6bf48da64e4 (patch)
tree2c345ca698bf7f73ce5caa9902fc40f5308fc6b5
parentac53ffbd58ec1112dd1fa9786a490a5c84f5ded6 (diff)
downloadFreeBSD-src-7d70b89c51d6f8dff25417542c5ec6bf48da64e4.zip
FreeBSD-src-7d70b89c51d6f8dff25417542c5ec6bf48da64e4.tar.gz
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
-rw-r--r--sys/net/if_lagg.c121
-rw-r--r--sys/net/if_lagg.h19
-rw-r--r--sys/net/if_var.h1
3 files changed, 80 insertions, 61 deletions
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index a6e27ae..834b561 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -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--;
@@ -1012,6 +1002,61 @@ fallback:
}
/*
+ * 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.
*/
static int
@@ -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);
-}
diff --git a/sys/net/if_lagg.h b/sys/net/if_lagg.h
index 1b07f7b..658d8b4 100644
--- a/sys/net/if_lagg.h
+++ b/sys/net/if_lagg.h
@@ -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 );
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 53bac32..ebaa0f6 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -109,6 +109,7 @@ typedef enum {
IFCOUNTER_OQDROPS,
IFCOUNTER_NOPROTO,
} ift_counter;
+#define IFCOUNTER_LAST IFCOUNTER_NOPROTO
typedef struct ifnet * if_t;
OpenPOWER on IntegriCloud