[PATCH 6/6] sfxge: implement interface statistics shown by netstat
Andrew Rybchenko
Andrew.Rybchenko at oktetlabs.ru
Tue Mar 18 10:00:45 UTC 2014
sfxge: implement interface statistics shown by netstat
netstat directly reads interface statistics collected
in the ifnet structure members: if_ipackets, if_ierrors, if_iqdrops,
if_opackets, if_oerrors, if_collisions.
The if_oerrors counter should include both errors reported by hardware
and errors happened in software before posting to hardware.
Since statistics is retrieved periodically its counters could be smaller
than counters provided by kernel for IP addresses.
Report IFCAP_HWSTATS capability since driver manages if_ibytes.
Submitted-by: Boris Misenov <Boris.Misenov at oktetlabs.ru>
Sponsored by: Solarflare Communications, Inc.
diff -r 7f58b1a5ea60 -r a3ab0749ffa3 src/driver/freebsd/sfxge.c
--- a/head/sys/dev/sfxge/sfxge.c Mon Mar 10 11:37:12 2014 +0400
+++ b/head/sys/dev/sfxge/sfxge.c Mon Mar 10 11:37:12 2014 +0400
@@ -60,10 +60,10 @@
#define SFXGE_CAP (IFCAP_VLAN_MTU | \
IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | \
IFCAP_JUMBO_MTU | IFCAP_LRO | \
- IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE)
+ IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWSTATS)
#define SFXGE_CAP_ENABLE SFXGE_CAP
#define SFXGE_CAP_FIXED (IFCAP_VLAN_MTU | IFCAP_HWCSUM |
IFCAP_VLAN_HWCSUM | \
- IFCAP_JUMBO_MTU | IFCAP_LINKSTATE)
+ IFCAP_JUMBO_MTU | IFCAP_LINKSTATE | IFCAP_HWSTATS)
MALLOC_DEFINE(M_SFXGE, "sfxge", "Solarflare 10GigE driver");
@@ -274,10 +274,23 @@
}
static void
+sfxge_tick(void *arg)
+{
+ struct sfxge_softc *sc = arg;
+
+ sfxge_port_update_stats(sc);
+ sfxge_tx_update_stats(sc);
+
+ callout_reset(&sc->tick_callout, SFXGE_CALLOUT_TICKS, sfxge_tick, sc);
+}
+
+static void
sfxge_ifnet_fini(struct ifnet *ifp)
{
struct sfxge_softc *sc = ifp->if_softc;
+ callout_drain(&sc->tick_callout);
+
sx_xlock(&sc->softc_lock);
sfxge_stop(sc);
sx_xunlock(&sc->softc_lock);
@@ -321,9 +334,12 @@
mtx_init(&sc->tx_lock, "txq", NULL, MTX_DEF);
#endif
+ callout_init(&sc->tick_callout, TRUE);
+
if ((rc = sfxge_port_ifmedia_init(sc)) != 0)
goto fail;
+ callout_reset(&sc->tick_callout, SFXGE_CALLOUT_TICKS, sfxge_tick, sc);
return 0;
fail:
diff -r 7f58b1a5ea60 -r a3ab0749ffa3 src/driver/freebsd/sfxge.h
--- a/head/sys/dev/sfxge/sfxge.h Mon Mar 10 11:37:12 2014 +0400
+++ b/head/sys/dev/sfxge/sfxge.h Mon Mar 10 11:37:12 2014 +0400
@@ -61,6 +61,9 @@
#ifndef IFCAP_VLAN_HWTSO
#define IFCAP_VLAN_HWTSO 0
#endif
+#ifndef IFCAP_HWSTATS
+#define IFCAP_HWSTATS 0
+#endif
#ifndef IFM_10G_T
#define IFM_10G_T IFM_UNKNOWN
#endif
@@ -100,6 +103,8 @@
#define SFXGE_EV_BATCH 16384
+#define SFXGE_CALLOUT_TICKS 10
+
struct sfxge_evq {
struct sfxge_softc *sc __aligned(CACHE_LINE_SIZE);
struct mtx lock __aligned(CACHE_LINE_SIZE);
@@ -241,6 +246,7 @@
#ifndef SFXGE_HAVE_MQ
struct mtx tx_lock __aligned(CACHE_LINE_SIZE);
#endif
+ struct callout tick_callout;
};
#define SFXGE_LINK_UP(sc) ((sc)->port.link_mode != EFX_LINK_DOWN)
@@ -298,6 +304,7 @@
efx_link_mode_t mode);
extern int sfxge_mac_filter_set(struct sfxge_softc *sc);
extern int sfxge_port_ifmedia_init(struct sfxge_softc *sc);
+extern void sfxge_port_update_stats(struct sfxge_softc *sc);
#define SFXGE_MAX_MTU (9 * 1024)
diff -r 7f58b1a5ea60 -r a3ab0749ffa3 src/driver/freebsd/sfxge_port.c
--- a/head/sys/dev/sfxge/sfxge_port.c Mon Mar 10 11:37:12 2014 +0400
+++ b/head/sys/dev/sfxge/sfxge_port.c Mon Mar 10 11:37:12 2014 +0400
@@ -85,6 +85,40 @@
return rc;
}
+void
+sfxge_port_update_stats(struct sfxge_softc *sc)
+{
+ struct ifnet *ifp;
+ uint64_t *mac_stats;
+
+ mtx_lock(&sc->port.lock);
+ /* Ignore error and use old values */
+ (void)sfxge_mac_stat_update(sc);
+
+ ifp = sc->ifnet;
+ mac_stats = (uint64_t *)sc->port.mac_stats.decode_buf;
+
+ ifp->if_ipackets = mac_stats[EFX_MAC_RX_PKTS];
+ ifp->if_ierrors = mac_stats[EFX_MAC_RX_ERRORS];
+ ifp->if_opackets = mac_stats[EFX_MAC_TX_PKTS];
+ ifp->if_oerrors = mac_stats[EFX_MAC_TX_ERRORS];
+ ifp->if_collisions =
+ mac_stats[EFX_MAC_TX_SGL_COL_PKTS] +
+ mac_stats[EFX_MAC_TX_MULT_COL_PKTS] +
+ mac_stats[EFX_MAC_TX_EX_COL_PKTS] +
+ mac_stats[EFX_MAC_TX_LATE_COL_PKTS];
+ ifp->if_ibytes = mac_stats[EFX_MAC_RX_OCTETS];
+ ifp->if_obytes = mac_stats[EFX_MAC_TX_OCTETS];
+ /* if_imcasts is maintained in net/if_ethersubr.c */
+ ifp->if_omcasts =
+ mac_stats[EFX_MAC_TX_MULTICST_PKTS] +
+ mac_stats[EFX_MAC_TX_BRDCST_PKTS];
+ /* if_iqdrops is maintained in net/if_ethersubr.c */
+ /* if_noproto is maintained in net/if_ethersubr.c */
+
+ mtx_unlock(&sc->port.lock);
+}
+
static int
sfxge_mac_stat_handler(SYSCTL_HANDLER_ARGS)
{
diff -r 7f58b1a5ea60 -r a3ab0749ffa3 src/driver/freebsd/sfxge_tx.c
--- a/head/sys/dev/sfxge/sfxge_tx.c Mon Mar 10 11:37:12 2014 +0400
+++ b/head/sys/dev/sfxge/sfxge_tx.c Mon Mar 10 11:37:12 2014 +0400
@@ -1436,6 +1436,28 @@
}
void
+sfxge_tx_update_stats(struct sfxge_softc *sc)
+{
+ unsigned int index;
+ u_long oerrors = 0;
+ struct sfxge_txq *txq;
+
+ /* Sum across all TX queues */
+ for (index = 0;
+ index < SFXGE_TXQ_IP_TCP_UDP_CKSUM + SFXGE_TX_SCALE(sc);
+ index++) {
+ txq = sc->txq[index];
+ /*
+ * In theory, txq->drops should be obtained under txq lock,
+ * and txq->early_drops should use atomic operation,
+ * but it is just statistics.
+ */
+ oerrors += txq->drops + txq->early_drops;
+ }
+ sc->ifnet->if_oerrors += oerrors;
+}
+
+void
sfxge_tx_fini(struct sfxge_softc *sc)
{
int index;
diff -r 7f58b1a5ea60 -r a3ab0749ffa3 src/driver/freebsd/sfxge_tx.h
--- a/head/sys/dev/sfxge/sfxge_tx.h Mon Mar 10 11:37:12 2014 +0400
+++ b/head/sys/dev/sfxge/sfxge_tx.h Mon Mar 10 11:37:12 2014 +0400
@@ -170,6 +170,7 @@
};
extern int sfxge_tx_packet_add(struct sfxge_txq *, struct mbuf *);
+extern void sfxge_tx_update_stats(struct sfxge_softc *sc);
extern int sfxge_tx_init(struct sfxge_softc *sc);
extern void sfxge_tx_fini(struct sfxge_softc *sc);
More information about the freebsd-net
mailing list