+ return cnt_used_entries;
+}
+
+/* retrieve ethdev extended statistics names */
+int
+rte_eth_xstats_get_names_by_id(uint16_t port_id,
+ struct rte_eth_xstat_name *xstats_names, unsigned int size,
+ uint64_t *ids)
+{
+ struct rte_eth_xstat_name *xstats_names_copy;
+ unsigned int no_basic_stat_requested = 1;
+ unsigned int no_ext_stat_requested = 1;
+ unsigned int expected_entries;
+ unsigned int basic_count;
+ struct rte_eth_dev *dev;
+ unsigned int i;
+ int ret;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ dev = &rte_eth_devices[port_id];
+
+ basic_count = get_xstats_basic_count(dev);
+ ret = get_xstats_count(port_id);
+ if (ret < 0)
+ return ret;
+ expected_entries = (unsigned int)ret;
+
+ /* Return max number of stats if no ids given */
+ if (!ids) {
+ if (!xstats_names)
+ return expected_entries;
+ else if (xstats_names && size < expected_entries)
+ return expected_entries;
+ }
+
+ if (ids && !xstats_names)
+ return -EINVAL;
+
+ if (ids && dev->dev_ops->xstats_get_names_by_id != NULL && size > 0) {
+ uint64_t ids_copy[size];
+
+ for (i = 0; i < size; i++) {
+ if (ids[i] < basic_count) {
+ no_basic_stat_requested = 0;
+ break;
+ }
+
+ /*
+ * Convert ids to xstats ids that PMD knows.
+ * ids known by user are basic + extended stats.
+ */
+ ids_copy[i] = ids[i] - basic_count;
+ }
+
+ if (no_basic_stat_requested)
+ return (*dev->dev_ops->xstats_get_names_by_id)(dev,
+ xstats_names, ids_copy, size);
+ }
+
+ /* Retrieve all stats */
+ if (!ids) {
+ int num_stats = rte_eth_xstats_get_names(port_id, xstats_names,
+ expected_entries);
+ if (num_stats < 0 || num_stats > (int)expected_entries)
+ return num_stats;
+ else
+ return expected_entries;
+ }
+
+ xstats_names_copy = calloc(expected_entries,
+ sizeof(struct rte_eth_xstat_name));
+
+ if (!xstats_names_copy) {
+ RTE_PMD_DEBUG_TRACE("ERROR: can't allocate memory");
+ return -ENOMEM;
+ }
+
+ if (ids) {
+ for (i = 0; i < size; i++) {
+ if (ids[i] > basic_count) {
+ no_ext_stat_requested = 0;
+ break;
+ }
+ }
+ }
+
+ /* Fill xstats_names_copy structure */
+ if (ids && no_ext_stat_requested) {
+ rte_eth_basic_stats_get_names(dev, xstats_names_copy);
+ } else {
+ ret = rte_eth_xstats_get_names(port_id, xstats_names_copy,
+ expected_entries);
+ if (ret < 0) {
+ free(xstats_names_copy);
+ return ret;
+ }
+ }
+
+ /* Filter stats */
+ for (i = 0; i < size; i++) {
+ if (ids[i] >= expected_entries) {
+ RTE_PMD_DEBUG_TRACE("ERROR: id value isn't valid\n");
+ free(xstats_names_copy);
+ return -1;
+ }
+ xstats_names[i] = xstats_names_copy[ids[i]];
+ }
+
+ free(xstats_names_copy);
+ return size;
+}
+
+int
+rte_eth_xstats_get_names(uint16_t port_id,
+ struct rte_eth_xstat_name *xstats_names,
+ unsigned int size)
+{
+ struct rte_eth_dev *dev;
+ int cnt_used_entries;
+ int cnt_expected_entries;
+ int cnt_driver_entries;
+
+ cnt_expected_entries = get_xstats_count(port_id);
+ if (xstats_names == NULL || cnt_expected_entries < 0 ||
+ (int)size < cnt_expected_entries)
+ return cnt_expected_entries;
+
+ /* port_id checked in get_xstats_count() */
+ dev = &rte_eth_devices[port_id];
+
+ cnt_used_entries = rte_eth_basic_stats_get_names(
+ dev, xstats_names);