DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>,
	Chas Williams <3chas3@gmail.com>,
	"Min Hu (Connor)" <humin29@huawei.com>
Subject: [PATCH 6/8] net/bonding: add extended statistics
Date: Sun, 30 Aug 2026 13:23:48 -0700	[thread overview]
Message-ID: <20260830202636.760014-7-stephen@networkplumber.org> (raw)
In-Reply-To: <20260830202636.760014-1-stephen@networkplumber.org>

The bonding device reported only the sum of its members, so there was
no way to see how traffic was distributed across them.
This patch adds xstats which reports per-member packets/bytes/errors.

Also drop RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS since driver never
implemented per-queue stats.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/rel_notes/release_26_11.rst |   6 ++
 drivers/net/bonding/rte_eth_bond_pmd.c | 113 ++++++++++++++++++++++++-
 2 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 87c7e81bde..83d70872af 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -55,6 +55,12 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added extended statistics to bonding PMD.**
+
+  Extended statistics now report the packets, bytes and errors
+  of each member as ``rx_memberN_*`` and ``tx_memberN_*``.
+  The per-queue entries, which were always zero, are no longer reported.
+
 
 Removed Items
 -------------
diff --git a/drivers/net/bonding/rte_eth_bond_pmd.c b/drivers/net/bonding/rte_eth_bond_pmd.c
index 0e18ded4a5..46bc1db120 100644
--- a/drivers/net/bonding/rte_eth_bond_pmd.c
+++ b/drivers/net/bonding/rte_eth_bond_pmd.c
@@ -2764,6 +2764,111 @@ bond_ethdev_stats_reset(struct rte_eth_dev *dev)
 	return err;
 }
 
+#define BOND_MEMBER_STAT_PREFIX_LEN (sizeof("rx_member") - 1 + 5 + 1)
+
+struct bond_member_stats_name_off {
+	char name[RTE_ETH_XSTATS_NAME_SIZE - BOND_MEMBER_STAT_PREFIX_LEN];
+	size_t offset;
+};
+
+static const struct bond_member_stats_name_off bond_member_rxq_stats_strings[] = {
+	{ "packets", offsetof(struct rte_eth_stats, ipackets) },
+	{ "bytes", offsetof(struct rte_eth_stats, ibytes) },
+	{ "errors", offsetof(struct rte_eth_stats, ierrors) },
+};
+
+#define BOND_NB_MEMBER_RX_STATS RTE_DIM(bond_member_rxq_stats_strings)
+
+static const struct bond_member_stats_name_off bond_member_txq_stats_strings[] = {
+	{ "packets", offsetof(struct rte_eth_stats, opackets) },
+	{ "bytes", offsetof(struct rte_eth_stats, obytes) },
+	{ "errors", offsetof(struct rte_eth_stats, oerrors) },
+};
+
+#define BOND_NB_MEMBER_TX_STATS RTE_DIM(bond_member_txq_stats_strings)
+
+#define BOND_NB_MEMBER_STATS (BOND_NB_MEMBER_RX_STATS + BOND_NB_MEMBER_TX_STATS)
+
+static int
+bond_ethdev_xstats_get_names(struct rte_eth_dev *dev,
+			     struct rte_eth_xstat_name *xstats_names,
+			     unsigned int limit)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	unsigned int count = internals->member_count * BOND_NB_MEMBER_STATS;
+	unsigned int i, j;
+
+	if (xstats_names == NULL || limit < count)
+		return count;
+
+	count = 0;
+	for (i = 0; i < internals->member_count; i++) {
+		uint16_t member_id = internals->members[i].port_id;
+
+		for (j = 0; j < BOND_NB_MEMBER_RX_STATS; j++)
+			snprintf(xstats_names[count++].name,
+				 RTE_ETH_XSTATS_NAME_SIZE, "rx_member%u_%s",
+				 member_id, bond_member_rxq_stats_strings[j].name);
+
+		for (j = 0; j < BOND_NB_MEMBER_TX_STATS; j++)
+			snprintf(xstats_names[count++].name,
+				 RTE_ETH_XSTATS_NAME_SIZE, "tx_member%u_%s",
+				 member_id, bond_member_txq_stats_strings[j].name);
+	}
+
+	return count;
+}
+
+static int
+bond_ethdev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
+		       unsigned int n)
+{
+	const struct bond_dev_private *internals = dev->data->dev_private;
+	unsigned int count = internals->member_count * BOND_NB_MEMBER_STATS;
+	unsigned int i, j;
+
+	if (xstats == NULL || n < count)
+		return count;
+
+	count = 0;
+	for (i = 0; i < internals->member_count; i++) {
+		struct rte_eth_stats member_stats;
+		uint16_t member_id = internals->members[i].port_id;
+
+		/* If member query fails just report zero. */
+		if (rte_eth_stats_get(member_id, &member_stats) < 0)
+			memset(&member_stats, 0, sizeof(member_stats));
+
+		for (j = 0; j < BOND_NB_MEMBER_RX_STATS; j++) {
+			xstats[count].id = count;
+			xstats[count].value = *(const uint64_t *)((const char *)&member_stats +
+					bond_member_rxq_stats_strings[j].offset);
+			count++;
+		}
+
+		for (j = 0; j < BOND_NB_MEMBER_TX_STATS; j++) {
+			xstats[count].id = count;
+			xstats[count].value = *(const uint64_t *)((const char *)&member_stats +
+					bond_member_txq_stats_strings[j].offset);
+			count++;
+		}
+	}
+
+	return count;
+}
+
+static int
+bond_ethdev_xstats_reset(struct rte_eth_dev *dev)
+{
+	const struct bond_dev_private *internals = dev->data->dev_private;
+	uint16_t i;
+
+	for (i = 0; i < internals->member_count; i++)
+		rte_eth_stats_reset(internals->members[i].port_id);
+
+	return 0;
+}
+
 static int
 bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
 {
@@ -3710,6 +3815,8 @@ static const struct eth_dev_ops secondary_dev_ops = {
 	.dev_infos_get        = bond_ethdev_info,
 	.link_update          = bond_ethdev_link_update,
 	.stats_get            = bond_ethdev_stats_get,
+	.xstats_get           = bond_ethdev_xstats_get,
+	.xstats_get_names     = bond_ethdev_xstats_get_names,
 	.reta_query           = bond_ethdev_rss_reta_query,
 	.rss_hash_conf_get    = bond_ethdev_rss_hash_conf_get,
 	.eth_dev_priv_dump    = bond_ethdev_priv_dump,
@@ -3729,6 +3836,9 @@ const struct eth_dev_ops default_dev_ops = {
 	.link_update          = bond_ethdev_link_update,
 	.stats_get            = bond_ethdev_stats_get,
 	.stats_reset          = bond_ethdev_stats_reset,
+	.xstats_get           = bond_ethdev_xstats_get,
+	.xstats_get_names     = bond_ethdev_xstats_get_names,
+	.xstats_reset         = bond_ethdev_xstats_reset,
 	.promiscuous_enable   = bond_ethdev_promiscuous_enable,
 	.promiscuous_disable  = bond_ethdev_promiscuous_disable,
 	.allmulticast_enable  = bond_ethdev_allmulticast_enable,
@@ -3780,8 +3890,7 @@ bond_alloc(struct rte_vdev_device *dev, uint8_t mode)
 	}
 
 	eth_dev->dev_ops = &default_dev_ops;
-	eth_dev->data->dev_flags = RTE_ETH_DEV_INTR_LSC |
-					RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
+	eth_dev->data->dev_flags = RTE_ETH_DEV_INTR_LSC;
 
 	rte_spinlock_init(&internals->lock);
 	rte_spinlock_init(&internals->lsc_lock);
-- 
2.53.0


  parent reply	other threads:[~2026-08-30 20:27 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-08 17:42 [RFC PATCH] net/bonding: reject control operations in secondary Weijun Pan
2026-07-22 23:10 ` Stephen Hemminger
2026-07-26 17:32 ` Stephen Hemminger
2026-08-23 15:16 ` [RFC PATCH v2] net/bonding: restrict secondary control operations Weijun Pan
2026-08-23 15:43   ` Stephen Hemminger
2026-08-24  2:39     ` Weijun Pan
2026-08-24 16:15   ` Stephen Hemminger
2026-08-26 16:10   ` [RFC PATCH v3] " Weijun Pan
2026-08-26 17:53     ` Stephen Hemminger
2026-08-30  1:14     ` [RFC PATCH v4 1/2] net/bonding: skip unavailable member stats Weijun Pan
2026-08-30  1:14       ` [RFC PATCH v4 2/2] net/bonding: restrict secondary control operations Weijun Pan
2026-08-30  4:29         ` Stephen Hemminger
2026-08-30  4:22       ` [RFC PATCH v4 1/2] net/bonding: skip unavailable member stats Stephen Hemminger
2026-08-30 16:35       ` [RFC PATCH v5 " Weijun Pan
2026-08-30 16:35         ` [RFC PATCH v5 2/2] net/bonding: restrict secondary control operations Weijun Pan
2026-08-30 20:23 ` [PATCH 0/8] net/bonding: fixes and per-member statistics Stephen Hemminger
2026-08-30 20:23   ` [PATCH 1/8] net/bonding: fix TLB member ordering with unusable member Stephen Hemminger
2026-08-30 20:23   ` [PATCH 2/8] net/bonding: skip unavailable member stats Stephen Hemminger
2026-08-30 20:23   ` [PATCH 3/8] net/bonding: skip unavailable members in device info Stephen Hemminger
2026-08-30 20:23   ` [PATCH 4/8] net/bonding: use atomic link status accessors Stephen Hemminger
2026-08-30 20:23   ` [PATCH 5/8] net/bonding: restrict control operations in secondary process Stephen Hemminger
2026-08-30 20:23   ` Stephen Hemminger [this message]
2026-08-30 20:23   ` [PATCH 7/8] test/bonding: add extended statistics test Stephen Hemminger
2026-08-30 20:23   ` [PATCH 8/8] doc: add bonding features matrix Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 0/8] net/bonding: fixes and per-member stats Stephen Hemminger
2026-08-31 16:06   ` [PATCH v2 1/8] net/bonding: fix TLB member ordering with unusable member Stephen Hemminger
2026-08-31 16:06   ` [PATCH v2 2/8] net/bonding: skip unavailable member stats Stephen Hemminger
2026-08-31 16:06   ` [PATCH v2 3/8] net/bonding: skip unavailable members in device info Stephen Hemminger
2026-08-31 16:06   ` [PATCH v2 4/8] net/bonding: use atomic link status accessors Stephen Hemminger
2026-08-31 16:06   ` [PATCH v2 5/8] net/bonding: restrict control ops in secondary process Stephen Hemminger
2026-08-31 16:06   ` [PATCH v2 6/8] net/bonding: add extended statistics Stephen Hemminger
2026-08-31 16:06   ` [PATCH v2 7/8] test/bonding: add extended statistics test Stephen Hemminger
2026-08-31 16:06   ` [PATCH v2 8/8] doc: add bonding features matrix Stephen Hemminger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260830202636.760014-7-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=3chas3@gmail.com \
    --cc=dev@dpdk.org \
    --cc=humin29@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox