This method can be implemented by a poll mode driver to provide
non-standard statistics (which are not part of the generic statistics
structure). Each statistic is returned in a generic form: "name" and
"value" and can be used to dump PMD-specific statistics in the same way
than ethtool in linux kernel.

If the PMD does not provide the xstats_get and xstats_set functions, the
ethdev API will return the generic statistics in the xstats format
(name, value).

This commit opens the door for a clean-up of the generic statistics
structure, only keeping statistics that are really common to all PMDs
and moving specific ones into the xstats API.

Reviewed-by: David Marchand <david.marchand at 6wind.com>
Signed-off-by: Olivier Matz <olivier.matz at 6wind.com>
---
 lib/librte_ether/rte_ethdev.c | 137 ++++++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h |  60 +++++++++++++++++-
 2 files changed, 195 insertions(+), 2 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index fd1010a..b71b679 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -114,6 +114,48 @@ static uint8_t nb_ports = 0;
 /* spinlock for eth device callbacks */
 static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;

+/* store statistics names and its offset in stats structure  */
+struct rte_eth_xstats_name_off {
+       char name[RTE_ETH_XSTATS_NAME_SIZE];
+       unsigned offset;
+};
+
+static struct rte_eth_xstats_name_off rte_stats_strings[] = {
+        {"rx_packets", offsetof(struct rte_eth_stats, ipackets)},
+        {"tx_packets", offsetof(struct rte_eth_stats, opackets)},
+        {"rx_bytes", offsetof(struct rte_eth_stats, ibytes)},
+        {"tx_bytes", offsetof(struct rte_eth_stats, obytes)},
+        {"tx_errors", offsetof(struct rte_eth_stats, oerrors)},
+        {"rx_missed_errors", offsetof(struct rte_eth_stats, imissed)},
+        {"rx_crc_errors", offsetof(struct rte_eth_stats, ibadcrc)},
+        {"rx_bad_length_errors", offsetof(struct rte_eth_stats, ibadlen)},
+        {"rx_errors", offsetof(struct rte_eth_stats, ierrors)},
+        {"alloc_rx_buff_failed", offsetof(struct rte_eth_stats, rx_nombuf)},
+        {"fdir_match", offsetof(struct rte_eth_stats, fdirmatch)},
+        {"fdir_miss", offsetof(struct rte_eth_stats, fdirmiss)},
+        {"tx_flow_control_xon", offsetof(struct rte_eth_stats, tx_pause_xon)},
+        {"rx_flow_control_xon", offsetof(struct rte_eth_stats, rx_pause_xon)},
+        {"tx_flow_control_xoff", offsetof(struct rte_eth_stats, 
tx_pause_xoff)},
+        {"rx_flow_control_xoff", offsetof(struct rte_eth_stats, 
rx_pause_xoff)},
+};
+#define RTE_NB_STATS (sizeof(rte_stats_strings) / sizeof(rte_stats_strings[0]))
+
+static struct rte_eth_xstats_name_off rte_rxq_stats_strings[] = {
+       {"rx_packets", offsetof(struct rte_eth_stats, q_ipackets)},
+       {"rx_bytes", offsetof(struct rte_eth_stats, q_ibytes)},
+};
+#define RTE_NB_RXQ_STATS (sizeof(rte_rxq_stats_strings) /      \
+               sizeof(rte_rxq_stats_strings[0]))
+
+static struct rte_eth_xstats_name_off rte_txq_stats_strings[] = {
+       {"tx_packets", offsetof(struct rte_eth_stats, q_opackets)},
+       {"tx_bytes", offsetof(struct rte_eth_stats, q_obytes)},
+       {"tx_errors", offsetof(struct rte_eth_stats, q_errors)},
+};
+#define RTE_NB_TXQ_STATS (sizeof(rte_txq_stats_strings) /      \
+               sizeof(rte_txq_stats_strings[0]))
+
+
 /**
  * The user application callback description.
  *
@@ -1201,6 +1243,101 @@ rte_eth_stats_reset(uint8_t port_id)
        (*dev->dev_ops->stats_reset)(dev);
 }

+/* retrieve ethdev extended statistics */
+int
+rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
+       unsigned n)
+{
+       struct rte_eth_stats eth_stats;
+       struct rte_eth_dev *dev;
+       unsigned count, i, q;
+       uint64_t val;
+       char *stats_ptr;
+
+       if (port_id >= nb_ports) {
+               PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+               return -1;
+       }
+       dev = &rte_eth_devices[port_id];
+
+       /* implemented by the driver */
+       if (dev->dev_ops->xstats_get != NULL)
+               return (*dev->dev_ops->xstats_get)(dev, xstats, n);
+
+       /* else, return generic statistics */
+       count = RTE_NB_STATS;
+       count += dev->data->nb_rx_queues * RTE_NB_RXQ_STATS;
+       count += dev->data->nb_tx_queues * RTE_NB_TXQ_STATS;
+       if (n < count)
+               return count;
+
+       /* now fill the xstats structure */
+
+       count = 0;
+       memset(&eth_stats, 0, sizeof(eth_stats));
+       rte_eth_stats_get(port_id, &eth_stats);
+
+       /* global stats */
+       for (i = 0; i < RTE_NB_STATS; i++) {
+               stats_ptr = (char *)&eth_stats + rte_stats_strings[i].offset;
+               val = *(uint64_t *)stats_ptr;
+               snprintf(xstats[count].name, sizeof(xstats[count].name),
+                       "%s", rte_stats_strings[i].name);
+               xstats[count++].value = val;
+       }
+
+       /* per-rxq stats */
+       for (q = 0; q < dev->data->nb_rx_queues; q++) {
+               for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+                       stats_ptr = (char *)&eth_stats;
+                       stats_ptr += rte_rxq_stats_strings[i].offset;
+                       stats_ptr += q * sizeof(uint64_t);
+                       val = *(uint64_t *)stats_ptr;
+                       snprintf(xstats[count].name, sizeof(xstats[count].name),
+                               "rx_queue_%u_%s", q,
+                               rte_rxq_stats_strings[i].name);
+                       xstats[count++].value = val;
+               }
+       }
+
+       /* per-txq stats */
+       for (q = 0; q < dev->data->nb_tx_queues; q++) {
+               for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
+                       stats_ptr = (char *)&eth_stats;
+                       stats_ptr += rte_txq_stats_strings[i].offset;
+                       stats_ptr += q * sizeof(uint64_t);
+                       val = *(uint64_t *)stats_ptr;
+                       snprintf(xstats[count].name, sizeof(xstats[count].name),
+                               "tx_queue_%u_%s", q,
+                               rte_txq_stats_strings[i].name);
+                       xstats[count++].value = val;
+               }
+       }
+
+       return count;
+}
+
+/* reset ethdev extended statistics */
+void
+rte_eth_xstats_reset(uint8_t port_id)
+{
+       struct rte_eth_dev *dev;
+
+       if (port_id >= nb_ports) {
+               PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+               return;
+       }
+       dev = &rte_eth_devices[port_id];
+
+       /* implemented by the driver */
+       if (dev->dev_ops->xstats_reset != NULL) {
+               (*dev->dev_ops->xstats_reset)(dev);
+               return;
+       }
+
+       /* fallback to default */
+       rte_eth_stats_reset(port_id);
+}

 static int
 set_queue_stats_mapping(uint8_t port_id, uint16_t queue_id, uint8_t stat_idx,
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 50df654..4076c33 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -908,6 +908,21 @@ struct rte_eth_dev_info {
        uint32_t tx_offload_capa; /**< Device TX offload capabilities. */
 };

+/** Maximum name length for a extended statitics counter */
+#define RTE_ETH_XSTATS_NAME_SIZE 64
+
+/**
+ * An Ethernet device extended statistic structure
+ *
+ * This structure is used by ethdev->eth_xstats_get() to provide
+ * statistics that are not provided in the generic rte_eth_stats
+ * structure.
+ */
+struct rte_eth_xstats {
+       char name[RTE_ETH_XSTATS_NAME_SIZE];
+       uint64_t value;
+};
+
 struct rte_eth_dev;

 struct rte_eth_dev_callback;
@@ -1028,6 +1043,13 @@ typedef void (*eth_stats_get_t)(struct rte_eth_dev *dev,
 typedef void (*eth_stats_reset_t)(struct rte_eth_dev *dev);
 /**< @internal Reset global I/O statistics of an Ethernet device to 0. */

+typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
+       struct rte_eth_xstats *stats, unsigned n);
+/**< @internal Get extended stats of an Ethernet device. */
+
+typedef void (*eth_xstats_reset_t)(struct rte_eth_dev *dev);
+/**< @internal Reset extended stats of an Ethernet device. */
+
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
                                             uint16_t queue_id,
                                             uint8_t stat_idx,
@@ -1376,8 +1398,10 @@ struct eth_dev_ops {
        eth_allmulticast_enable_t  allmulticast_enable;/**< RX multicast ON. */
        eth_allmulticast_disable_t allmulticast_disable;/**< RX multicast OF. */
        eth_link_update_t          link_update;   /**< Get device link state. */
-       eth_stats_get_t            stats_get;     /**< Get device statistics. */
-       eth_stats_reset_t          stats_reset;   /**< Reset device statistics. 
*/
+       eth_stats_get_t            stats_get;     /**< Get generic device 
statistics. */
+       eth_stats_reset_t          stats_reset;   /**< Reset generic device 
statistics. */
+       eth_xstats_get_t           xstats_get;    /**< Get extended device 
statistics. */
+       eth_xstats_reset_t         xstats_reset;  /**< Reset extended device 
statistics. */
        eth_queue_stats_mapping_set_t queue_stats_mapping_set;
        /**< Configure per queue stat counter mapping. */
        eth_dev_infos_get_t        dev_infos_get; /**< Get device info. */
@@ -2005,6 +2029,38 @@ extern void rte_eth_stats_get(uint8_t port_id, struct 
rte_eth_stats *stats);
 extern void rte_eth_stats_reset(uint8_t port_id);

 /**
+ * Retrieve extended statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *   A pointer to a table of structure of type *rte_eth_xstats*
+ *   to be filled with the values of device statistics names and value.
+ *   This parameter can be set to NULL if n is 0.
+ * @param n
+ *   The size of the stats table, which should be large enough to store
+ *   all the statistics of the device.
+ * @return
+ *   - positive value lower or equal to n: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - positive value higher than n: error, the given statistics table
+ *     is too small. Thereturn value corresponds to the size that should
+ *     be given to succeed. The entries in the table are not valid and
+ *     shall not be used by the caller.
+ *   - negative value on error (invalid port id)
+ */
+extern int rte_eth_xstats_get(uint8_t port_id,
+       struct rte_eth_xstats *xstats, unsigned n);
+
+/**
+ * Reset extended statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ */
+extern void rte_eth_xstats_reset(uint8_t port_id);
+
+/**
  *  Set a mapping for the specified transmit queue to the specified per-queue
  *  statistics counter.
  *
-- 
2.0.1

Reply via email to