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 <[email protected]>
---
 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

Reply via email to