diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2020-07-07 00:00:04 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2020-07-07 00:00:04 +0000 |
commit | f435648b783901fc6f430e780bc7c8e0ea202f7c (patch) | |
tree | cce54f8f2798c87d25abf645148b233c025c6d2f /sys/net/ifq.c | |
parent | 4e526a6aa77e6abcee3f8ea6ff3eab4e57605701 (diff) |
add kstats for rx queues (ifiqs) and transmit queues (ifqs).
this means you can observe what the network stack is trying to do
when it's working with a nic driver that supports multiple rings.
a nic with only one set of rings still gets queues though, and this
still exports their stats.
here is a small example of what kstat(8) currently outputs for these
stats:
em0:0:rxq:0
packets: 2292 packets
bytes: 229846 bytes
qdrops: 0 packets
errors: 0 packets
qlen: 0 packets
em0:0:txq:0
packets: 1297 packets
bytes: 193413 bytes
qdrops: 0 packets
errors: 0 packets
qlen: 0 packets
maxqlen: 511 packets
oactive: false
Diffstat (limited to 'sys/net/ifq.c')
-rw-r--r-- | sys/net/ifq.c | 124 |
1 files changed, 123 insertions, 1 deletions
diff --git a/sys/net/ifq.c b/sys/net/ifq.c index 2846d23ed03..5e97c4e2e43 100644 --- a/sys/net/ifq.c +++ b/sys/net/ifq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ifq.c,v 1.40 2020/06/17 06:45:22 dlg Exp $ */ +/* $OpenBSD: ifq.c,v 1.41 2020/07/07 00:00:03 dlg Exp $ */ /* * Copyright (c) 2015 David Gwynne <dlg@openbsd.org> @@ -17,6 +17,7 @@ */ #include "bpfilter.h" +#include "kstat.h" #include <sys/param.h> #include <sys/systm.h> @@ -32,6 +33,10 @@ #include <net/bpf.h> #endif +#if NKSTAT > 0 +#include <sys/kstat.h> +#endif + /* * priq glue */ @@ -188,6 +193,52 @@ ifq_barrier_task(void *p) * ifqueue mbuf queue API */ +#if NKSTAT > 0 +struct ifq_kstat_data { + struct kstat_kv kd_packets; + struct kstat_kv kd_bytes; + struct kstat_kv kd_qdrops; + struct kstat_kv kd_errors; + struct kstat_kv kd_qlen; + struct kstat_kv kd_maxqlen; + struct kstat_kv kd_oactive; +}; + +static const struct ifq_kstat_data ifq_kstat_tpl = { + KSTAT_KV_UNIT_INITIALIZER("packets", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("bytes", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES), + KSTAT_KV_UNIT_INITIALIZER("qdrops", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("errors", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("qlen", + KSTAT_KV_T_UINT32, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("maxqlen", + KSTAT_KV_T_UINT32, KSTAT_KV_U_PACKETS), + KSTAT_KV_INITIALIZER("oactive", KSTAT_KV_T_BOOL), +}; + +int +ifq_kstat_copy(struct kstat *ks, void *dst) +{ + struct ifqueue *ifq = ks->ks_softc; + struct ifq_kstat_data *kd = dst; + + *kd = ifq_kstat_tpl; + kstat_kv_u64(&kd->kd_packets) = ifq->ifq_packets; + kstat_kv_u64(&kd->kd_bytes) = ifq->ifq_bytes; + kstat_kv_u64(&kd->kd_qdrops) = ifq->ifq_qdrops; + kstat_kv_u64(&kd->kd_errors) = ifq->ifq_errors; + kstat_kv_u32(&kd->kd_qlen) = ifq->ifq_len; + kstat_kv_u32(&kd->kd_maxqlen) = ifq->ifq_maxlen; + kstat_kv_bool(&kd->kd_oactive) = ifq->ifq_oactive; + + return (0); +} +#endif + void ifq_init(struct ifqueue *ifq, struct ifnet *ifp, unsigned int idx) { @@ -222,6 +273,18 @@ ifq_init(struct ifqueue *ifq, struct ifnet *ifp, unsigned int idx) ifq_set_maxlen(ifq, IFQ_MAXLEN); ifq->ifq_idx = idx; + +#if NKSTAT > 0 + /* XXX xname vs driver name and unit */ + ifq->ifq_kstat = kstat_create(ifp->if_xname, 0, + "txq", ifq->ifq_idx, KSTAT_T_KV, 0); + KASSERT(ifq->ifq_kstat != NULL); + kstat_set_mutex(ifq->ifq_kstat, &ifq->ifq_mtx); + ifq->ifq_kstat->ks_softc = ifq; + ifq->ifq_kstat->ks_datalen = sizeof(ifq_kstat_tpl); + ifq->ifq_kstat->ks_copy = ifq_kstat_copy; + kstat_install(ifq->ifq_kstat); +#endif } void @@ -265,6 +328,10 @@ ifq_destroy(struct ifqueue *ifq) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); +#if NKSTAT > 0 + kstat_destroy(ifq->ifq_kstat); +#endif + NET_ASSERT_UNLOCKED(); if (!task_del(ifq->ifq_softnet, &ifq->ifq_bundle)) taskq_barrier(ifq->ifq_softnet); @@ -505,6 +572,45 @@ ifq_mfreeml(struct ifqueue *ifq, struct mbuf_list *ml) * ifiq */ +#if NKSTAT > 0 +struct ifiq_kstat_data { + struct kstat_kv kd_packets; + struct kstat_kv kd_bytes; + struct kstat_kv kd_qdrops; + struct kstat_kv kd_errors; + struct kstat_kv kd_qlen; +}; + +static const struct ifiq_kstat_data ifiq_kstat_tpl = { + KSTAT_KV_UNIT_INITIALIZER("packets", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("bytes", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES), + KSTAT_KV_UNIT_INITIALIZER("qdrops", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("errors", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("qlen", + KSTAT_KV_T_UINT32, KSTAT_KV_U_PACKETS), +}; + +int +ifiq_kstat_copy(struct kstat *ks, void *dst) +{ + struct ifiqueue *ifiq = ks->ks_softc; + struct ifiq_kstat_data *kd = dst; + + *kd = ifiq_kstat_tpl; + kstat_kv_u64(&kd->kd_packets) = ifiq->ifiq_packets; + kstat_kv_u64(&kd->kd_bytes) = ifiq->ifiq_bytes; + kstat_kv_u64(&kd->kd_qdrops) = ifiq->ifiq_qdrops; + kstat_kv_u64(&kd->kd_errors) = ifiq->ifiq_errors; + kstat_kv_u32(&kd->kd_qlen) = ml_len(&ifiq->ifiq_ml); + + return (0); +} +#endif + static void ifiq_process(void *); void @@ -525,11 +631,27 @@ ifiq_init(struct ifiqueue *ifiq, struct ifnet *ifp, unsigned int idx) ifiq->ifiq_errors = 0; ifiq->ifiq_idx = idx; + +#if NKSTAT > 0 + /* XXX xname vs driver name and unit */ + ifiq->ifiq_kstat = kstat_create(ifp->if_xname, 0, + "rxq", ifiq->ifiq_idx, KSTAT_T_KV, 0); + KASSERT(ifiq->ifiq_kstat != NULL); + kstat_set_mutex(ifiq->ifiq_kstat, &ifiq->ifiq_mtx); + ifiq->ifiq_kstat->ks_softc = ifiq; + ifiq->ifiq_kstat->ks_datalen = sizeof(ifiq_kstat_tpl); + ifiq->ifiq_kstat->ks_copy = ifiq_kstat_copy; + kstat_install(ifiq->ifiq_kstat); +#endif } void ifiq_destroy(struct ifiqueue *ifiq) { +#if NKSTAT > 0 + kstat_destroy(ifiq->ifiq_kstat); +#endif + NET_ASSERT_UNLOCKED(); if (!task_del(ifiq->ifiq_softnet, &ifiq->ifiq_task)) taskq_barrier(ifiq->ifiq_softnet); |