Index | Thread | Search

From:
Jan Klemkow <jan@openbsd.org>
Subject:
ice(4): add kstat counter
To:
tech@openbsd.org
Date:
Tue, 7 Jul 2026 23:10:09 +0200

Download raw body.

Thread
  • Jan Klemkow:

    ice(4): add kstat counter

Hi,

This diff exports most hardware kstat counters from ice(4) interfaces.
So, we improve debugging of these interfaces.

ok?

bye,
jan

Index: dev/pci/if_ice.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_ice.c,v
diff -u -p -r1.69 if_ice.c
--- dev/pci/if_ice.c	23 Jun 2026 14:40:40 -0000	1.69
+++ dev/pci/if_ice.c	7 Jul 2026 21:03:13 -0000
@@ -51,6 +51,7 @@
 
 #include "bpfilter.h"
 #include "vlan.h"
+#include "kstat.h"
 
 #include <sys/param.h>
 #include <sys/atomic.h>
@@ -70,6 +71,10 @@
 #include <machine/bus.h>
 #include <machine/intr.h>
 
+#if NKSTAT > 0
+#include <sys/kstat.h>
+#endif
+
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcidevs.h>
@@ -340,6 +345,8 @@ struct ice_softc {
 	int rebuild_ticks;
 
 	int sw_intr[ICE_MAX_VECTORS];
+	struct kstat *sc_kstat_port;
+	struct kstat *sc_kstat_vsi;
 };
 
 static int ice_rxrinfo(struct ice_softc *, struct if_rxrinfo *);
@@ -24125,7 +24132,7 @@ ice_update_link_status(struct ice_softc 
 				ice_set_default_local_lldp_mib(sc);
 
 			ifp->if_baudrate = baudrate;
-			ifp->if_link_state = LINK_STATE_UP;
+			ifp->if_link_state = LINK_STATE_FULL_DUPLEX;
 			if_link_state_change(ifp);
 #if 0
 			ice_rdma_link_change(sc, LINK_STATE_UP, baudrate);
@@ -28900,6 +28907,279 @@ ice_update_stats(struct ice_softc *sc)
 #endif
 }
 
+#if NKSTAT > 0
+
+/* Synced with struct ice_hw_port_stats */
+struct ice_kstat_port_counters {
+	/* struct ice_eth_stats eth; */
+	struct kstat_kv rx_bytes;
+	struct kstat_kv rx_unicast;
+	struct kstat_kv rx_multicast;
+	struct kstat_kv rx_broadcast;
+	struct kstat_kv rx_discards;
+	/* uint64_t rx_unknown_protocol;	N/A */
+	struct kstat_kv tx_bytes;
+	struct kstat_kv tx_unicast;
+	struct kstat_kv tx_multicast;
+	struct kstat_kv tx_broadcast;
+	/* uint64_t tx_discards;		N/A */
+	/* uint64_t tx_errors;			N/A */
+	/* uint64_t rx_no_desc;			N/A */
+	/* uint64_t rx_errors;			N/A */
+
+	struct kstat_kv tx_dropped_link_down;
+	struct kstat_kv crc_errors;
+	struct kstat_kv illegal_bytes;
+	/* error_bytes				N/A */
+	struct kstat_kv mac_local_faults;
+	struct kstat_kv mac_remote_faults;
+	struct kstat_kv rx_len_errors;
+	struct kstat_kv link_xon_rx;
+	struct kstat_kv link_xoff_rx;
+	struct kstat_kv link_xon_tx;
+	struct kstat_kv link_xoff_tx;
+	/* uint64_t priority_xon_rx[8];		skipped, too verbose */
+	/* uint64_t priority_xoff_rx[8];	skipped, too verbose */
+	/* uint64_t priority_xon_tx[8];		skipped, too verbose */
+	/* uint64_t priority_xoff_tx[8];	skipped, too verbose */
+	/* uint64_t priority_xon_2_xoff[8];	skipped, too verbose */
+	struct kstat_kv rx_size_64;
+	struct kstat_kv rx_size_127;
+	struct kstat_kv rx_size_255;
+	struct kstat_kv rx_size_511;
+	struct kstat_kv rx_size_1023;
+	struct kstat_kv rx_size_1522;
+	struct kstat_kv rx_size_big;
+	struct kstat_kv rx_undersize;
+	struct kstat_kv rx_fragments;
+	struct kstat_kv rx_oversize;
+	struct kstat_kv rx_jabber;
+	struct kstat_kv tx_size_64;
+	struct kstat_kv tx_size_127;
+	struct kstat_kv tx_size_255;
+	struct kstat_kv tx_size_511;
+	struct kstat_kv tx_size_1023;
+	struct kstat_kv tx_size_1522;
+	struct kstat_kv tx_size_big;
+	/* uint64_t mac_short_pkt_dropped;	N/A */
+	/* uint32_t tx_lpi_status;		N/A */
+	/* uint32_t rx_lpi_status;		N/A */
+	/* uint64_t tx_lpi_count;		N/A */
+	/* uint64_t rx_lpi_count;		N/A */
+};
+
+static const struct ice_kstat_port_counters ice_kstat_port_counters_tpl = {
+	KSTAT_KV_UNIT_INITIALIZER("rx bytes", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_BYTES),
+	KSTAT_KV_UNIT_INITIALIZER("rx unicast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx multicast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx broadcast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx discards", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx bytes", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_BYTES),
+	KSTAT_KV_UNIT_INITIALIZER("tx unicast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx multicast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx broadcast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx drop no link", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("crc errors", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("illegal bytes", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("mac local errs", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_NONE),
+	KSTAT_KV_UNIT_INITIALIZER("mac remote errs", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_NONE),
+	KSTAT_KV_UNIT_INITIALIZER("rx len errors", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("link xon rx", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("link xoff rx", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("link xon tx", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("link xoff tx", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx size 64", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx size 127", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx size 255", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx size 511", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx size 1023", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx size 1522", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx size big", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx undersize", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx fragments", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx oversize", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx jabber", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx size 64", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx size 127", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx size 255", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx size 511", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx size 1023", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx size 1522", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx size big", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+};
+
+int
+ice_kstat_port_counters_copy(struct kstat *ks, void *dst)
+{
+	struct ice_softc *sc = ks->ks_softc;
+	struct ice_kstat_port_counters *data = dst;
+
+	*data = ice_kstat_port_counters_tpl;
+
+#define ICE_COPY_KSTAT_U64_PATH(path, name) \
+	kstat_kv_u64(&data->name) = sc->stats.cur.path.name
+
+#define ICE_COPY_KSTAT_U64(name) \
+	kstat_kv_u64(&data->name) = sc->stats.cur.name
+
+	ICE_COPY_KSTAT_U64_PATH(eth, rx_bytes);
+	ICE_COPY_KSTAT_U64_PATH(eth, rx_unicast);
+	ICE_COPY_KSTAT_U64_PATH(eth, rx_multicast);
+	ICE_COPY_KSTAT_U64_PATH(eth, rx_broadcast);
+	ICE_COPY_KSTAT_U64_PATH(eth, rx_discards);
+	ICE_COPY_KSTAT_U64_PATH(eth, tx_bytes);
+	ICE_COPY_KSTAT_U64_PATH(eth, tx_unicast);
+	ICE_COPY_KSTAT_U64_PATH(eth, tx_multicast);
+	ICE_COPY_KSTAT_U64_PATH(eth, tx_broadcast);
+
+	ICE_COPY_KSTAT_U64(tx_dropped_link_down);
+	ICE_COPY_KSTAT_U64(crc_errors);
+	ICE_COPY_KSTAT_U64(illegal_bytes);
+	ICE_COPY_KSTAT_U64(mac_local_faults);
+	ICE_COPY_KSTAT_U64(mac_remote_faults);
+	ICE_COPY_KSTAT_U64(rx_len_errors);
+	ICE_COPY_KSTAT_U64(link_xon_rx);
+	ICE_COPY_KSTAT_U64(link_xoff_rx);
+	ICE_COPY_KSTAT_U64(link_xon_tx);
+	ICE_COPY_KSTAT_U64(link_xoff_tx);
+	ICE_COPY_KSTAT_U64(rx_size_64);
+	ICE_COPY_KSTAT_U64(rx_size_127);
+	ICE_COPY_KSTAT_U64(rx_size_255);
+	ICE_COPY_KSTAT_U64(rx_size_511);
+	ICE_COPY_KSTAT_U64(rx_size_1023);
+	ICE_COPY_KSTAT_U64(rx_size_1522);
+	ICE_COPY_KSTAT_U64(rx_size_big);
+	ICE_COPY_KSTAT_U64(rx_undersize);
+	ICE_COPY_KSTAT_U64(rx_fragments);
+	ICE_COPY_KSTAT_U64(rx_oversize);
+	ICE_COPY_KSTAT_U64(rx_jabber);
+	ICE_COPY_KSTAT_U64(tx_size_64);
+	ICE_COPY_KSTAT_U64(tx_size_127);
+	ICE_COPY_KSTAT_U64(tx_size_255);
+	ICE_COPY_KSTAT_U64(tx_size_511);
+	ICE_COPY_KSTAT_U64(tx_size_1023);
+	ICE_COPY_KSTAT_U64(tx_size_1522);
+	ICE_COPY_KSTAT_U64(tx_size_big);
+
+#undef ICE_COPY_KSTAT_U64_PATH
+#undef ICE_COPY_KSTAT_U64
+
+	return (0);
+}
+
+/* Synced with struct ice_eth_stats */
+struct ice_kstat_vsi_counters {
+	struct kstat_kv rx_bytes;
+	struct kstat_kv rx_unicast;
+	struct kstat_kv rx_multicast;
+	struct kstat_kv rx_broadcast;
+	struct kstat_kv rx_discards;
+	/* uint64_t rx_unknown_protocol;	N/A */
+	struct kstat_kv tx_bytes;
+	struct kstat_kv tx_unicast;
+	struct kstat_kv tx_multicast;
+	struct kstat_kv tx_broadcast;
+	/* uint64_t tx_discards;		N/A */
+	struct kstat_kv tx_errors;
+	struct kstat_kv rx_no_desc;
+	struct kstat_kv rx_errors;
+};
+
+struct ice_kstat_vsi_counters ice_kstat_vsi_counters_tpl = {
+	KSTAT_KV_UNIT_INITIALIZER("rx bytes", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_BYTES),
+	KSTAT_KV_UNIT_INITIALIZER("rx unicast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx multicast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx broadcast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx discards", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx bytes", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_BYTES),
+	KSTAT_KV_UNIT_INITIALIZER("tx unicast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx multicast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx broadcast", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("tx errors", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx no desc", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+	KSTAT_KV_UNIT_INITIALIZER("rx errors", KSTAT_KV_T_COUNTER64,
+	    KSTAT_KV_U_PACKETS),
+};
+
+int
+ice_kstat_vsi_counters_copy(struct kstat *ks, void *dst)
+{
+	struct ice_softc *sc = ks->ks_softc;
+	struct ice_kstat_vsi_counters *data = dst;
+
+	*data = ice_kstat_vsi_counters_tpl;
+
+#define ICE_COPY_KSTAT_U64(name) \
+	kstat_kv_u64(&data->name) = sc->pf_vsi.hw_stats.cur.name
+
+	ICE_COPY_KSTAT_U64(rx_bytes);
+	ICE_COPY_KSTAT_U64(rx_unicast);
+	ICE_COPY_KSTAT_U64(rx_multicast);
+	ICE_COPY_KSTAT_U64(rx_broadcast);
+	ICE_COPY_KSTAT_U64(rx_discards);
+	ICE_COPY_KSTAT_U64(tx_bytes);
+	ICE_COPY_KSTAT_U64(tx_unicast);
+	ICE_COPY_KSTAT_U64(tx_multicast);
+	ICE_COPY_KSTAT_U64(tx_broadcast);
+	ICE_COPY_KSTAT_U64(tx_errors);
+	ICE_COPY_KSTAT_U64(rx_no_desc);
+	ICE_COPY_KSTAT_U64(rx_errors);
+
+#undef ICE_COPY_KSTAT_U64
+
+	return (0);
+}
+
+#endif /* NKSTAT > 0 */
+
 /**
  * ice_if_update_admin_status - update admin status
  * @ctx: iflib ctx structure
@@ -30483,6 +30763,36 @@ ice_init_link_configuration(struct ice_s
 	}
 }
 
+#if NKSTAT > 0
+
+int
+ice_kstat_attach(struct ice_softc *sc)
+{
+	sc->sc_kstat_port = kstat_create(sc->sc_dev.dv_xname, 0, "ice-port", 0,
+	    KSTAT_T_KV, 0);
+	if (sc->sc_kstat_port == NULL)
+		return (-1);
+
+	sc->sc_kstat_port->ks_softc = sc;
+	sc->sc_kstat_port->ks_datalen = sizeof(ice_kstat_port_counters_tpl);
+	sc->sc_kstat_port->ks_copy = ice_kstat_port_counters_copy;
+	kstat_install(sc->sc_kstat_port);
+
+	sc->sc_kstat_vsi = kstat_create(sc->sc_dev.dv_xname, 0, "ice-vsi", 0,
+	    KSTAT_T_KV, 0);
+	if (sc->sc_kstat_vsi == NULL)
+		return (-1);
+
+	sc->sc_kstat_vsi->ks_softc = sc;
+	sc->sc_kstat_vsi->ks_datalen = sizeof(ice_kstat_vsi_counters_tpl);
+	sc->sc_kstat_vsi->ks_copy = ice_kstat_vsi_counters_copy;
+	kstat_install(sc->sc_kstat_vsi);
+
+	return (0);
+}
+
+#endif
+
 void
 ice_attach_hook(struct device *self)
 {
@@ -30727,6 +31037,11 @@ ice_attach_hook(struct device *self)
 	if (err)
 		printf("%s: could not set MAC address (error %d)\n",
 		    sc->sc_dev.dv_xname, err);
+
+#if NKSTAT > 0
+	if (ice_kstat_attach(sc))
+		printf("%s: could not attach to kstat\n", sc->sc_dev.dv_xname);
+#endif
 
 	ice_clear_state(&sc->state, ICE_STATE_ATTACHING);
 	return;