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
next prev 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