get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/23569/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 23569,
    "url": "http://patches.dpdk.org/api/patches/23569/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1491928644-10383-2-git-send-email-michalx.k.jastrzebski@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1491928644-10383-2-git-send-email-michalx.k.jastrzebski@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1491928644-10383-2-git-send-email-michalx.k.jastrzebski@intel.com",
    "date": "2017-04-11T16:37:22",
    "name": "[dpdk-dev,v5,1/3] ethdev: new xstats API add retrieving by ID",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "7224616d29f7b9e180b80efef05bd5242aa18e58",
    "submitter": {
        "id": 74,
        "url": "http://patches.dpdk.org/api/people/74/?format=api",
        "name": "Michal Jastrzebski",
        "email": "michalx.k.jastrzebski@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1491928644-10383-2-git-send-email-michalx.k.jastrzebski@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/23569/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/23569/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 6D5ECD292;\n\tTue, 11 Apr 2017 18:41:29 +0200 (CEST)",
            "from mga03.intel.com (mga03.intel.com [134.134.136.65])\n\tby dpdk.org (Postfix) with ESMTP id AD429CF90\n\tfor <dev@dpdk.org>; Tue, 11 Apr 2017 18:41:25 +0200 (CEST)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t11 Apr 2017 09:41:24 -0700",
            "from gklab-246-020.igk.intel.com (HELO Sent) ([10.217.246.20])\n\tby orsmga002.jf.intel.com with SMTP; 11 Apr 2017 09:41:12 -0700",
            "by Sent (sSMTP sendmail emulation); Tue, 11 Apr 2017 18:37:37 +0200"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.37,186,1488873600\"; d=\"scan'208\";a=\"72630036\"",
        "From": "Michal Jastrzebski <michalx.k.jastrzebski@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "deepak.k.jain@intel.com, harry.van.haaren@intel.com,\n\tJacek Piasecki <jacekx.piasecki@intel.com>,\n\tKuba Kozak <kubax.kozak@intel.com>,\n\tTomasz Kulasek <tomaszx.kulasek@intel.com>",
        "Date": "Tue, 11 Apr 2017 18:37:22 +0200",
        "Message-Id": "<1491928644-10383-2-git-send-email-michalx.k.jastrzebski@intel.com>",
        "X-Mailer": "git-send-email 1.9.1",
        "In-Reply-To": "<1491928644-10383-1-git-send-email-michalx.k.jastrzebski@intel.com>",
        "References": "<1491847180-24784-2-git-send-email-jacekx.piasecki@intel.com>\n\t<1491928644-10383-1-git-send-email-michalx.k.jastrzebski@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v5 1/3] ethdev: new xstats API add retrieving by\n\tID",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Jacek Piasecki <jacekx.piasecki@intel.com>\n\nExtended xstats API in ethdev library to allow grouping of stats\nlogically so they can be retrieved per logical grouping  managed\nby the application.\nChanged existing functions rte_eth_xstats_get_names and\nrte_eth_xstats_get to use a new list of arguments: array of ids\nand array of values. ABI versioning mechanism was used to\nsupport backward compatibility.\nIntroduced two new functions rte_eth_xstats_get_all and\nrte_eth_xstats_get_names_all which keeps functionality of the\nprevious ones (respectively rte_eth_xstats_get and\nrte_eth_xstats_get_names) but use new API inside.\nBoth functions marked as deprecated.\nIntroduced new function: rte_eth_xstats_get_id_by_name\nto retrieve xstats ids by its names.\n\ntest-pmd: add support for new xstats API retrieving by id in\ntestpmd application: xstats_get() and\nxstats_get_names() call with modified parameters.\n\nproc_info: add support for new xstats API retrieving by id to\nproc_info application. There is a new argument --xstats-ids\nin proc_info command line to retrieve statistics given by ids.\nE.g. --xstats-ids=\"1,3,5,7,8\"\n\ndoc: add description for modified xstats API\nDocumentation change for modified extended statistics API functions.\nThe old API only allows retrieval of *all* of the NIC statistics\nat once. Given this requires a MMIO read PCI transaction per statistic\nit is an inefficient way of retrieving just a few key statistics.\nOften a monitoring agent only has an interest in a few key statistics,\nand the old API forces wasting CPU time and PCIe bandwidth in retrieving\n*all* statistics; even those that the application didn't explicitly\nshow an interest in.\nThe new, more flexible API allow retrieval of statistics per ID.\nIf a PMD wishes, it can be implemented to read just the required\nNIC registers. As a result, the monitoring application no longer wastes\nPCIe bandwidth and CPU time.\n\nSigned-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>\nSigned-off-by: Kuba Kozak <kubax.kozak@intel.com>\nSigned-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>\n---\n app/proc_info/main.c                    | 150 ++++++++++-\n app/test-pmd/config.c                   |  19 +-\n doc/guides/prog_guide/poll_mode_drv.rst | 174 +++++++++++--\n lib/librte_ether/rte_ethdev.c           | 430 ++++++++++++++++++++++++--------\n lib/librte_ether/rte_ethdev.h           | 170 ++++++++++++-\n lib/librte_ether/rte_ether_version.map  |   5 +\n 6 files changed, 794 insertions(+), 154 deletions(-)",
    "diff": "diff --git a/app/proc_info/main.c b/app/proc_info/main.c\nindex d576b42..d0eae4b 100644\n--- a/app/proc_info/main.c\n+++ b/app/proc_info/main.c\n@@ -86,6 +86,14 @@\n static uint32_t reset_xstats;\n /**< Enable memory info. */\n static uint32_t mem_info;\n+/**< Enable displaying xstat name. */\n+static uint32_t enable_xstats_name;\n+static char *xstats_name;\n+\n+/**< Enable xstats by ids. */\n+#define MAX_NB_XSTATS_IDS 1024\n+static uint32_t nb_xstats_ids;\n+static uint64_t xstats_ids[MAX_NB_XSTATS_IDS];\n \n /**< display usage */\n static void\n@@ -97,8 +105,9 @@\n \t\t\"  --stats: to display port statistics, enabled by default\\n\"\n \t\t\"  --xstats: to display extended port statistics, disabled by \"\n \t\t\t\"default\\n\"\n-\t\t\"  --metrics: to display derived metrics of the ports, disabled by \"\n-\t\t\t\"default\\n\"\n+\t\t\"  --xstats-name NAME: to display single xstat value by NAME\\n\"\n+\t\t\"  --xstats-ids IDLIST: to display xstat values by id. \"\n+\t\t\t\"The argument is comma-separated list of xstat ids to print out.\\n\"\n \t\t\"  --stats-reset: to reset port statistics\\n\"\n \t\t\"  --xstats-reset: to reset port extended statistics\\n\"\n \t\t\"  --collectd-format: to print statistics to STDOUT in expected by collectd format\\n\"\n@@ -132,6 +141,33 @@\n \n }\n \n+/*\n+ * Parse ids value list into array\n+ */\n+static int\n+parse_xstats_ids(char *list, uint64_t *ids, int limit) {\n+\tint length;\n+\tchar *token;\n+\tchar *ctx = NULL;\n+\tchar *endptr;\n+\n+\tlength = 0;\n+\ttoken = strtok_r(list, \",\", &ctx);\n+\twhile (token != NULL) {\n+\t\tids[length] = strtoull(token, &endptr, 10);\n+\t\tif (*endptr != '\\0')\n+\t\t\treturn -EINVAL;\n+\n+\t\tlength++;\n+\t\tif (length >= limit)\n+\t\t\treturn -E2BIG;\n+\n+\t\ttoken = strtok_r(NULL, \",\", &ctx);\n+\t}\n+\n+\treturn length;\n+}\n+\n static int\n proc_info_preparse_args(int argc, char **argv)\n {\n@@ -178,7 +214,9 @@\n \t\t{\"xstats\", 0, NULL, 0},\n \t\t{\"metrics\", 0, NULL, 0},\n \t\t{\"xstats-reset\", 0, NULL, 0},\n+\t\t{\"xstats-name\", required_argument, NULL, 1},\n \t\t{\"collectd-format\", 0, NULL, 0},\n+\t\t{\"xstats-ids\", 1, NULL, 1},\n \t\t{\"host-id\", 0, NULL, 0},\n \t\t{NULL, 0, 0, 0}\n \t};\n@@ -224,7 +262,28 @@\n \t\t\t\t\tMAX_LONG_OPT_SZ))\n \t\t\t\treset_xstats = 1;\n \t\t\tbreak;\n+\t\tcase 1:\n+\t\t\t/* Print xstat single value given by name*/\n+\t\t\tif (!strncmp(long_option[option_index].name,\n+\t\t\t\t\t\"xstats-name\", MAX_LONG_OPT_SZ)) {\n+\t\t\t\tenable_xstats_name = 1;\n+\t\t\t\txstats_name = optarg;\n+\t\t\t\tprintf(\"name:%s:%s\\n\",\n+\t\t\t\t\t\tlong_option[option_index].name,\n+\t\t\t\t\t\toptarg);\n+\t\t\t} else if (!strncmp(long_option[option_index].name,\n+\t\t\t\t\t\"xstats-ids\",\n+\t\t\t\t\tMAX_LONG_OPT_SZ))\t{\n+\t\t\t\tnb_xstats_ids = parse_xstats_ids(optarg,\n+\t\t\t\t\t\txstats_ids, MAX_NB_XSTATS_IDS);\n+\n+\t\t\t\tif (nb_xstats_ids <= 0) {\n+\t\t\t\t\tprintf(\"xstats-id list parse error.\\n\");\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n \n+\t\t\t}\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\tproc_info_usage(prgname);\n \t\t\treturn -1;\n@@ -351,20 +410,82 @@ static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,\n }\n \n static void\n+nic_xstats_by_name_display(uint8_t port_id, char *name)\n+{\n+\tuint64_t id;\n+\n+\tprintf(\"###### NIC statistics for port %-2d, statistic name '%s':\\n\",\n+\t\t\t   port_id, name);\n+\n+\tif (rte_eth_xstats_get_id_by_name(port_id, name, &id) == 0)\n+\t\tprintf(\"%s: %\"PRIu64\"\\n\", name, id);\n+\telse\n+\t\tprintf(\"Statistic not found...\\n\");\n+\n+}\n+\n+static void\n+nic_xstats_by_ids_display(uint8_t port_id, uint64_t *ids, int len)\n+{\n+\tstruct rte_eth_xstat_name *xstats_names;\n+\tuint64_t *values;\n+\tint ret, i;\n+\tstatic const char *nic_stats_border = \"########################\";\n+\n+\tvalues = malloc(sizeof(values) * len);\n+\tif (values == NULL) {\n+\t\tprintf(\"Cannot allocate memory for xstats\\n\");\n+\t\treturn;\n+\t}\n+\n+\txstats_names = malloc(sizeof(struct rte_eth_xstat_name) * len);\n+\tif (xstats_names == NULL) {\n+\t\tprintf(\"Cannot allocate memory for xstat names\\n\");\n+\t\tfree(values);\n+\t\treturn;\n+\t}\n+\n+\tif (len != rte_eth_xstats_get_names(\n+\t\t\tport_id, xstats_names, len, ids)) {\n+\t\tprintf(\"Cannot get xstat names\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tprintf(\"###### NIC extended statistics for port %-2d #########\\n\",\n+\t\t\t   port_id);\n+\tprintf(\"%s############################\\n\", nic_stats_border);\n+\tret = rte_eth_xstats_get(port_id, ids, values, len);\n+\tif (ret < 0 || ret > len) {\n+\t\tprintf(\"Cannot get xstats\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tfor (i = 0; i < len; i++)\n+\t\tprintf(\"%s: %\"PRIu64\"\\n\",\n+\t\t\txstats_names[i].name,\n+\t\t\tvalues[i]);\n+\n+\tprintf(\"%s############################\\n\", nic_stats_border);\n+err:\n+\tfree(values);\n+\tfree(xstats_names);\n+}\n+\n+static void\n nic_xstats_display(uint8_t port_id)\n {\n \tstruct rte_eth_xstat_name *xstats_names;\n-\tstruct rte_eth_xstat *xstats;\n+\tuint64_t *values;\n \tint len, ret, i;\n \tstatic const char *nic_stats_border = \"########################\";\n \n-\tlen = rte_eth_xstats_get_names(port_id, NULL, 0);\n+\tlen = rte_eth_xstats_get_names(port_id, NULL, 0, NULL);\n \tif (len < 0) {\n \t\tprintf(\"Cannot get xstats count\\n\");\n \t\treturn;\n \t}\n-\txstats = malloc(sizeof(xstats[0]) * len);\n-\tif (xstats == NULL) {\n+\tvalues = malloc(sizeof(values) * len);\n+\tif (values == NULL) {\n \t\tprintf(\"Cannot allocate memory for xstats\\n\");\n \t\treturn;\n \t}\n@@ -372,11 +493,11 @@ static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,\n \txstats_names = malloc(sizeof(struct rte_eth_xstat_name) * len);\n \tif (xstats_names == NULL) {\n \t\tprintf(\"Cannot allocate memory for xstat names\\n\");\n-\t\tfree(xstats);\n+\t\tfree(values);\n \t\treturn;\n \t}\n \tif (len != rte_eth_xstats_get_names(\n-\t\t\tport_id, xstats_names, len)) {\n+\t\t\tport_id, xstats_names, len, NULL)) {\n \t\tprintf(\"Cannot get xstat names\\n\");\n \t\tgoto err;\n \t}\n@@ -385,7 +506,7 @@ static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,\n \t\t\t   port_id);\n \tprintf(\"%s############################\\n\",\n \t\t\t   nic_stats_border);\n-\tret = rte_eth_xstats_get(port_id, xstats, len);\n+\tret = rte_eth_xstats_get(port_id, NULL, values, len);\n \tif (ret < 0 || ret > len) {\n \t\tprintf(\"Cannot get xstats\\n\");\n \t\tgoto err;\n@@ -401,18 +522,18 @@ static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,\n \t\t\t\t\t\t  xstats_names[i].name);\n \t\t\tsprintf(buf, \"PUTVAL %s/dpdkstat-port.%u/%s-%s N:%\"\n \t\t\t\tPRIu64\"\\n\", host_id, port_id, counter_type,\n-\t\t\t\txstats_names[i].name, xstats[i].value);\n+\t\t\t\txstats_names[i].name, values[i]);\n \t\t\twrite(stdout_fd, buf, strlen(buf));\n \t\t} else {\n \t\t\tprintf(\"%s: %\"PRIu64\"\\n\", xstats_names[i].name,\n-\t\t\t       xstats[i].value);\n+\t\t\t\t\tvalues[i]);\n \t\t}\n \t}\n \n \tprintf(\"%s############################\\n\",\n \t\t\t   nic_stats_border);\n err:\n-\tfree(xstats);\n+\tfree(values);\n \tfree(xstats_names);\n }\n \n@@ -551,6 +672,11 @@ static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,\n \t\t\t\tnic_stats_clear(i);\n \t\t\telse if (reset_xstats)\n \t\t\t\tnic_xstats_clear(i);\n+\t\t\telse if (enable_xstats_name)\n+\t\t\t\tnic_xstats_by_name_display(i, xstats_name);\n+\t\t\telse if (nb_xstats_ids > 0)\n+\t\t\t\tnic_xstats_by_ids_display(i, xstats_ids,\n+\t\t\t\t\t\tnb_xstats_ids);\n \t\t\telse if (enable_metrics)\n \t\t\t\tmetrics_display(i);\n \t\t}\ndiff --git a/app/test-pmd/config.c b/app/test-pmd/config.c\nindex 4d873cd..ef07925 100644\n--- a/app/test-pmd/config.c\n+++ b/app/test-pmd/config.c\n@@ -264,9 +264,9 @@ struct rss_type_info {\n void\n nic_xstats_display(portid_t port_id)\n {\n-\tstruct rte_eth_xstat *xstats;\n \tint cnt_xstats, idx_xstat;\n \tstruct rte_eth_xstat_name *xstats_names;\n+\tuint64_t *values;\n \n \tprintf(\"###### NIC extended statistics for port %-2d\\n\", port_id);\n \tif (!rte_eth_dev_is_valid_port(port_id)) {\n@@ -275,7 +275,7 @@ struct rss_type_info {\n \t}\n \n \t/* Get count */\n-\tcnt_xstats = rte_eth_xstats_get_names(port_id, NULL, 0);\n+\tcnt_xstats = rte_eth_xstats_get_names(port_id, NULL, 0, NULL);\n \tif (cnt_xstats  < 0) {\n \t\tprintf(\"Error: Cannot get count of xstats\\n\");\n \t\treturn;\n@@ -288,23 +288,24 @@ struct rss_type_info {\n \t\treturn;\n \t}\n \tif (cnt_xstats != rte_eth_xstats_get_names(\n-\t\t\tport_id, xstats_names, cnt_xstats)) {\n+\t\t\tport_id, xstats_names, cnt_xstats, NULL)) {\n \t\tprintf(\"Error: Cannot get xstats lookup\\n\");\n \t\tfree(xstats_names);\n \t\treturn;\n \t}\n \n \t/* Get stats themselves */\n-\txstats = malloc(sizeof(struct rte_eth_xstat) * cnt_xstats);\n-\tif (xstats == NULL) {\n+\tvalues = malloc(sizeof(values) * cnt_xstats);\n+\tif (values == NULL) {\n \t\tprintf(\"Cannot allocate memory for xstats\\n\");\n \t\tfree(xstats_names);\n \t\treturn;\n \t}\n-\tif (cnt_xstats != rte_eth_xstats_get(port_id, xstats, cnt_xstats)) {\n+\tif (cnt_xstats != rte_eth_xstats_get(port_id, NULL, values,\n+\t\t\tcnt_xstats)) {\n \t\tprintf(\"Error: Unable to get xstats\\n\");\n \t\tfree(xstats_names);\n-\t\tfree(xstats);\n+\t\tfree(values);\n \t\treturn;\n \t}\n \n@@ -312,9 +313,9 @@ struct rss_type_info {\n \tfor (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++)\n \t\tprintf(\"%s: %\"PRIu64\"\\n\",\n \t\t\txstats_names[idx_xstat].name,\n-\t\t\txstats[idx_xstat].value);\n+\t\t\tvalues[idx_xstat]);\n \tfree(xstats_names);\n-\tfree(xstats);\n+\tfree(values);\n }\n \n void\ndiff --git a/doc/guides/prog_guide/poll_mode_drv.rst b/doc/guides/prog_guide/poll_mode_drv.rst\nindex e48c121..3372f30 100644\n--- a/doc/guides/prog_guide/poll_mode_drv.rst\n+++ b/doc/guides/prog_guide/poll_mode_drv.rst\n@@ -334,24 +334,20 @@ The Ethernet device API exported by the Ethernet PMDs is described in the *DPDK\n Extended Statistics API\n ~~~~~~~~~~~~~~~~~~~~~~~\n \n-The extended statistics API allows each individual PMD to expose a unique set\n-of statistics. Accessing these from application programs is done via two\n-functions:\n-\n-* ``rte_eth_xstats_get``: Fills in an array of ``struct rte_eth_xstat``\n-  with extended statistics.\n-* ``rte_eth_xstats_get_names``: Fills in an array of\n-  ``struct rte_eth_xstat_name`` with extended statistic name lookup\n-  information.\n-\n-Each ``struct rte_eth_xstat`` contains an identifier and value pair, and\n-each ``struct rte_eth_xstat_name`` contains a string. Each identifier\n-within the ``struct rte_eth_xstat`` lookup array must have a corresponding\n-entry in the ``struct rte_eth_xstat_name`` lookup array. Within the latter\n-the index of the entry is the identifier the string is associated with.\n-These identifiers, as well as the number of extended statistic exposed, must\n-remain constant during runtime. Note that extended statistic identifiers are\n-driver-specific, and hence might not be the same for different ports.\n+The extended statistics API allows a PMD to expose all statistics that are\n+available to it, including statistics that are unique to the device.\n+Each statistic has three properties ``name``, ``id`` and ``value``:\n+\n+* ``name``: A human readable string formatted by the scheme detailed below.\n+* ``id``: An integer that represents only that statistic.\n+* ``value``: A unsigned 64-bit integer that is the value of the statistic.\n+\n+The API consists of various ``rte_eth_xstats_*()`` functions, and allows an\n+application to be flexible in how it retrieves statistics.\n+\n+\n+Scheme for Human Readable Names\n+_______________________________\n \n A naming scheme exists for the strings exposed to clients of the API. This is\n to allow scraping of the API for statistics of interest. The naming scheme uses\n@@ -363,8 +359,8 @@ strings split by a single underscore ``_``. The scheme is as follows:\n * detail n\n * unit\n \n-Examples of common statistics xstats strings, formatted to comply to the scheme\n-proposed above:\n+Examples of common statistics xstats strings, formatted to comply to the\n+above scheme:\n \n * ``rx_bytes``\n * ``rx_crc_errors``\n@@ -378,7 +374,7 @@ associated with the receive side of the NIC.  The second component ``packets``\n indicates that the unit of measure is packets.\n \n A more complicated example: ``tx_size_128_to_255_packets``. In this example,\n-``tx`` indicates transmission, ``size``  is the first detail, ``128`` etc are\n+``tx`` indicates transmission, ``size``  is the first detail, ``128`` etc. are\n more details, and ``packets`` indicates that this is a packet counter.\n \n Some additions in the metadata scheme are as follows:\n@@ -392,3 +388,139 @@ Some additions in the metadata scheme are as follows:\n An example where queue numbers are used is as follows: ``tx_q7_bytes`` which\n indicates this statistic applies to queue number 7, and represents the number\n of transmitted bytes on that queue.\n+\n+API Design\n+__________\n+\n+The xstats API uses the ``name``, ``id``, and ``value`` to allow performant\n+lookup of specific statistics. Performant lookup means two things;\n+\n+* No string comparisons with the ``name`` of the statistic in fast-path\n+* Allow requesting of only the statistics of interest\n+\n+The API ensures these requirements are met by mapping the ``name`` of the\n+statistic to a unique ``id``, which is used as a key for lookup in the fast-path.\n+The API allows applications to request an array of ``id`` values, so that the\n+PMD only performs the required calculations. Expected usage is that the\n+application scans the ``name`` of each statistic, and caches the ``id``\n+if it has an interest in that statistic. On the fast-path, the integer can be used\n+to retrieve the actual ``value`` of the statistic that the ``id`` represents.\n+\n+API Functions\n+_____________\n+\n+The API is built out of a small number of functions, which can be used to\n+retrieve the number of statistics and the names, IDs and values of those\n+statistics.\n+\n+* ``rte_eth_xstats_get_names()``: returns the names of the statistics. When given a\n+  ``NULL`` parameter the function returns the number of statistics that are available.\n+\n+* ``rte_eth_xstats_get_id_by_name()``: Searches for the statistic ID that matches\n+  ``xstat_name``. If found, the ``id`` integer is set.\n+\n+* ``rte_eth_xstats_get()``: Fills in an array of ``uint64_t`` values\n+  with matching the provided ``ids`` array. If the ``ids`` array is NULL, it\n+  returns all statistics that are available.\n+\n+\n+Application Usage\n+_________________\n+\n+Imagine an application that wants to view the dropped packet count. If no\n+packets are dropped, the application does not read any other metrics for\n+performance reasons. If packets are dropped, the application has a particular\n+set of statistics that it requests. This \"set\" of statistics allows the app to\n+decide what next steps to perform. The following code-snippets show how the\n+xstats API can be used to achieve this goal.\n+\n+First step is to get all statistics names and list them:\n+\n+.. code-block:: c\n+\n+    struct rte_eth_xstat_name *xstats_names;\n+    uint64_t *values;\n+    int len, i;\n+\n+    /* Get number of stats */\n+    len = rte_eth_xstats_get_names(port_id, NULL, NULL, 0);\n+    if (len < 0) {\n+        printf(\"Cannot get xstats count\\n\");\n+        goto err;\n+    }\n+\n+    xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * len);\n+    if (xstats_names == NULL) {\n+        printf(\"Cannot allocate memory for xstat names\\n\");\n+        goto err;\n+    }\n+\n+    /* Retrieve xstats names, passing NULL for IDs to return all statistics */\n+    if (len != rte_eth_xstats_get_names(port_id, xstats_names, NULL, len)) {\n+        printf(\"Cannot get xstat names\\n\");\n+        goto err;\n+    }\n+\n+    values = malloc(sizeof(values) * len);\n+    if (values == NULL) {\n+        printf(\"Cannot allocate memory for xstats\\n\");\n+        goto err;\n+    }\n+\n+    /* Getting xstats values */\n+    if (len != rte_eth_xstats_get(port_id, NULL, values, len)) {\n+        printf(\"Cannot get xstat values\\n\");\n+        goto err;\n+    }\n+\n+    /* Print all xstats names and values */\n+    for (i = 0; i < len; i++) {\n+        printf(\"%s: %\"PRIu64\"\\n\", xstats_names[i].name, values[i]);\n+    }\n+\n+The application has access to the names of all of the statistics that the PMD\n+exposes. The application can decide which statistics are of interest, cache the\n+ids of those statistics by looking up the name as follows:\n+\n+.. code-block:: c\n+\n+    uint64_t id;\n+    uint64_t value;\n+    const char *xstat_name = \"rx_errors\";\n+\n+    if(!rte_eth_xstats_get_id_by_name(port_id, xstat_name, &id)) {\n+        rte_eth_xstats_get(port_id, &id, &value, 1);\n+        printf(\"%s: %\"PRIu64\"\\n\", xstat_name, value);\n+    }\n+    else {\n+        printf(\"Cannot find xstats with a given name\\n\");\n+        goto err;\n+    }\n+\n+The API provides flexibility to the application so that it can look up multiple\n+statistics using an array containing multiple ``id`` numbers. This reduces the\n+function call overhead of retrieving statistics, and makes lookup of multiple\n+statistics simpler for the application.\n+\n+.. code-block:: c\n+\n+    #define APP_NUM_STATS 4\n+    /* application cached these ids previously; see above */\n+    uint64_t ids_array[APP_NUM_STATS] = {3,4,7,21};\n+    uint64_t value_array[APP_NUM_STATS];\n+\n+    /* Getting multiple xstats values from array of IDs */\n+    rte_eth_xstats_get(port_id, ids_array, value_array, APP_NUM_STATS);\n+\n+    uint32_t i;\n+    for(i = 0; i < APP_NUM_STATS; i++) {\n+        printf(\"%d: %\"PRIu64\"\\n\", ids_array[i], value_array[i]);\n+    }\n+\n+\n+This array lookup API for xstats allows the application create multiple\n+\"groups\" of statistics, and look up the values of those IDs using a single API\n+call. As an end result, the application is able to achieve its goal of\n+monitoring a single statistic (\"rx_errors\" in this case), and if that shows\n+packets being dropped, it can easily retrieve a \"set\" of statistics using the\n+IDs array parameter to ``rte_eth_xstats_get`` function.\ndiff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c\nindex 4e1e6dc..0653cf7 100644\n--- a/lib/librte_ether/rte_ethdev.c\n+++ b/lib/librte_ether/rte_ethdev.c\n@@ -1454,12 +1454,19 @@ struct rte_eth_dev *\n \n \tRTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);\n \tdev = &rte_eth_devices[port_id];\n+\tif (dev->dev_ops->xstats_get_names_by_ids != NULL) {\n+\t\tcount = (*dev->dev_ops->xstats_get_names_by_ids)(dev, NULL,\n+\t\t\t\tNULL, 0);\n+\t\tif (count < 0)\n+\t\t\treturn count;\n+\t}\n \tif (dev->dev_ops->xstats_get_names != NULL) {\n \t\tcount = (*dev->dev_ops->xstats_get_names)(dev, NULL, 0);\n \t\tif (count < 0)\n \t\t\treturn count;\n \t} else\n \t\tcount = 0;\n+\n \tcount += RTE_NB_STATS;\n \tcount += RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS) *\n \t\t RTE_NB_RXQ_STATS;\n@@ -1469,150 +1476,367 @@ struct rte_eth_dev *\n }\n \n int\n-rte_eth_xstats_get_names(uint8_t port_id,\n-\tstruct rte_eth_xstat_name *xstats_names,\n-\tunsigned size)\n+rte_eth_xstats_get_id_by_name(uint8_t port_id, const char *xstat_name,\n+\t\tuint64_t *id)\n {\n-\tstruct rte_eth_dev *dev;\n-\tint cnt_used_entries;\n-\tint cnt_expected_entries;\n-\tint cnt_driver_entries;\n-\tuint32_t idx, id_queue;\n-\tuint16_t num_q;\n+\tint cnt_xstats, idx_xstat;\n \n-\tcnt_expected_entries = get_xstats_count(port_id);\n-\tif (xstats_names == NULL || cnt_expected_entries < 0 ||\n-\t\t\t(int)size < cnt_expected_entries)\n-\t\treturn cnt_expected_entries;\n+\tRTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);\n \n-\t/* port_id checked in get_xstats_count() */\n-\tdev = &rte_eth_devices[port_id];\n-\tcnt_used_entries = 0;\n+\tif (!id) {\n+\t\tRTE_PMD_DEBUG_TRACE(\"Error: id pointer is NULL\\n\");\n+\t\treturn -1;\n+\t}\n \n-\tfor (idx = 0; idx < RTE_NB_STATS; idx++) {\n-\t\tsnprintf(xstats_names[cnt_used_entries].name,\n-\t\t\tsizeof(xstats_names[0].name),\n-\t\t\t\"%s\", rte_stats_strings[idx].name);\n-\t\tcnt_used_entries++;\n+\tif (!xstat_name) {\n+\t\tRTE_PMD_DEBUG_TRACE(\"Error: xstat_name pointer is NULL\\n\");\n+\t\treturn -1;\n \t}\n-\tnum_q = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);\n-\tfor (id_queue = 0; id_queue < num_q; id_queue++) {\n-\t\tfor (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) {\n+\n+\t/* Get count */\n+\tcnt_xstats = rte_eth_xstats_get_names(port_id, NULL, 0, NULL);\n+\tif (cnt_xstats  < 0) {\n+\t\tRTE_PMD_DEBUG_TRACE(\"Error: Cannot get count of xstats\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\t/* Get id-name lookup table */\n+\tstruct rte_eth_xstat_name xstats_names[cnt_xstats];\n+\n+\tif (cnt_xstats != rte_eth_xstats_get_names(\n+\t\t\tport_id, xstats_names, cnt_xstats, NULL)) {\n+\t\tRTE_PMD_DEBUG_TRACE(\"Error: Cannot get xstats lookup\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tfor (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++) {\n+\t\tif (!strcmp(xstats_names[idx_xstat].name, xstat_name)) {\n+\t\t\t*id = idx_xstat;\n+\t\t\treturn 0;\n+\t\t};\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n+int\n+rte_eth_xstats_get_names_v1607(uint8_t port_id,\n+\tstruct rte_eth_xstat_name *xstats_names,\n+\tunsigned int size)\n+{\n+\treturn rte_eth_xstats_get_names(port_id, xstats_names, size, NULL);\n+}\n+VERSION_SYMBOL(rte_eth_xstats_get_names, _v1607, 16.07);\n+\n+int\n+rte_eth_xstats_get_names_v1705(uint8_t port_id,\n+\tstruct rte_eth_xstat_name *xstats_names, unsigned int size,\n+\tuint64_t *ids)\n+{\n+\t/* Get all xstats */\n+\tif (!ids) {\n+\t\tstruct rte_eth_dev *dev;\n+\t\tint cnt_used_entries;\n+\t\tint cnt_expected_entries;\n+\t\tint cnt_driver_entries;\n+\t\tuint32_t idx, id_queue;\n+\t\tuint16_t num_q;\n+\n+\t\tcnt_expected_entries = get_xstats_count(port_id);\n+\t\tif (xstats_names == NULL || cnt_expected_entries < 0 ||\n+\t\t\t\t(int)size < cnt_expected_entries)\n+\t\t\treturn cnt_expected_entries;\n+\n+\t\t/* port_id checked in get_xstats_count() */\n+\t\tdev = &rte_eth_devices[port_id];\n+\t\tcnt_used_entries = 0;\n+\n+\t\tfor (idx = 0; idx < RTE_NB_STATS; idx++) {\n \t\t\tsnprintf(xstats_names[cnt_used_entries].name,\n \t\t\t\tsizeof(xstats_names[0].name),\n-\t\t\t\t\"rx_q%u%s\",\n-\t\t\t\tid_queue, rte_rxq_stats_strings[idx].name);\n+\t\t\t\t\"%s\", rte_stats_strings[idx].name);\n \t\t\tcnt_used_entries++;\n \t\t}\n+\t\tnum_q = RTE_MIN(dev->data->nb_rx_queues,\n+\t\t\t\tRTE_ETHDEV_QUEUE_STAT_CNTRS);\n+\t\tfor (id_queue = 0; id_queue < num_q; id_queue++) {\n+\t\t\tfor (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) {\n+\t\t\t\tsnprintf(xstats_names[cnt_used_entries].name,\n+\t\t\t\t\tsizeof(xstats_names[0].name),\n+\t\t\t\t\t\"rx_q%u%s\",\n+\t\t\t\t\tid_queue,\n+\t\t\t\t\trte_rxq_stats_strings[idx].name);\n+\t\t\t\tcnt_used_entries++;\n+\t\t\t}\n+\n+\t\t}\n+\t\tnum_q = RTE_MIN(dev->data->nb_tx_queues,\n+\t\t\t\tRTE_ETHDEV_QUEUE_STAT_CNTRS);\n+\t\tfor (id_queue = 0; id_queue < num_q; id_queue++) {\n+\t\t\tfor (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) {\n+\t\t\t\tsnprintf(xstats_names[cnt_used_entries].name,\n+\t\t\t\t\tsizeof(xstats_names[0].name),\n+\t\t\t\t\t\"tx_q%u%s\",\n+\t\t\t\t\tid_queue,\n+\t\t\t\t\trte_txq_stats_strings[idx].name);\n+\t\t\t\tcnt_used_entries++;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (dev->dev_ops->xstats_get_names_by_ids != NULL) {\n+\t\t\t/* If there are any driver-specific xstats, append them\n+\t\t\t * to end of list.\n+\t\t\t */\n+\t\t\tcnt_driver_entries =\n+\t\t\t\t(*dev->dev_ops->xstats_get_names_by_ids)(\n+\t\t\t\tdev,\n+\t\t\t\txstats_names + cnt_used_entries,\n+\t\t\t\tNULL,\n+\t\t\t\tsize - cnt_used_entries);\n+\t\t\tif (cnt_driver_entries < 0)\n+\t\t\t\treturn cnt_driver_entries;\n+\t\t\tcnt_used_entries += cnt_driver_entries;\n+\n+\t\t} else if (dev->dev_ops->xstats_get_names != NULL) {\n+\t\t\t/* If there are any driver-specific xstats, append them\n+\t\t\t * to end of list.\n+\t\t\t */\n+\t\t\tcnt_driver_entries = (*dev->dev_ops->xstats_get_names)(\n+\t\t\t\tdev,\n+\t\t\t\txstats_names + cnt_used_entries,\n+\t\t\t\tsize - cnt_used_entries);\n+\t\t\tif (cnt_driver_entries < 0)\n+\t\t\t\treturn cnt_driver_entries;\n+\t\t\tcnt_used_entries += cnt_driver_entries;\n+\t\t}\n \n+\t\treturn cnt_used_entries;\n \t}\n-\tnum_q = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);\n-\tfor (id_queue = 0; id_queue < num_q; id_queue++) {\n-\t\tfor (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) {\n-\t\t\tsnprintf(xstats_names[cnt_used_entries].name,\n-\t\t\t\tsizeof(xstats_names[0].name),\n-\t\t\t\t\"tx_q%u%s\",\n-\t\t\t\tid_queue, rte_txq_stats_strings[idx].name);\n-\t\t\tcnt_used_entries++;\n+\t/* Get only xstats given by IDS */\n+\telse {\n+\t\tuint16_t len, i;\n+\t\tstruct rte_eth_xstat_name *xstats_names_copy;\n+\n+\t\tlen = rte_eth_xstats_get_names_v1705(port_id, NULL, 0, NULL);\n+\n+\t\txstats_names_copy =\n+\t\t\t\tmalloc(sizeof(struct rte_eth_xstat_name) * len);\n+\t\tif (!xstats_names_copy) {\n+\t\t\tRTE_PMD_DEBUG_TRACE(\n+\t\t\t     \"ERROR: can't allocate memory for values_copy\\n\");\n+\t\t\tfree(xstats_names_copy);\n+\t\t\treturn -1;\n \t\t}\n+\n+\t\trte_eth_xstats_get_names_v1705(port_id, xstats_names_copy,\n+\t\t\t\tlen, NULL);\n+\n+\t\tfor (i = 0; i < size; i++) {\n+\t\t\tif (ids[i] >= len) {\n+\t\t\t\tRTE_PMD_DEBUG_TRACE(\n+\t\t\t\t\t\"ERROR: id value isn't valid\\n\");\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tstrcpy(xstats_names[i].name,\n+\t\t\t\t\txstats_names_copy[ids[i]].name);\n+\t\t}\n+\t\tfree(xstats_names_copy);\n+\t\treturn size;\n \t}\n+}\n+BIND_DEFAULT_SYMBOL(rte_eth_xstats_get_names, _v1705, 17.05);\n \n-\tif (dev->dev_ops->xstats_get_names != NULL) {\n-\t\t/* If there are any driver-specific xstats, append them\n-\t\t * to end of list.\n-\t\t */\n-\t\tcnt_driver_entries = (*dev->dev_ops->xstats_get_names)(\n-\t\t\tdev,\n-\t\t\txstats_names + cnt_used_entries,\n-\t\t\tsize - cnt_used_entries);\n-\t\tif (cnt_driver_entries < 0)\n-\t\t\treturn cnt_driver_entries;\n-\t\tcnt_used_entries += cnt_driver_entries;\n+MAP_STATIC_SYMBOL(int\n+\t\trte_eth_xstats_get_names(uint8_t port_id,\n+\t\t\tstruct rte_eth_xstat_name *xstats_names,\n+\t\t\tunsigned int size,\n+\t\t\tuint64_t *ids), rte_eth_xstats_get_names_v1705);\n+\n+/* retrieve ethdev extended statistics */\n+int\n+rte_eth_xstats_get_v22(uint8_t port_id, struct rte_eth_xstat *xstats,\n+\tunsigned int n)\n+{\n+\tuint64_t *values_copy;\n+\tuint16_t size, i;\n+\n+\tvalues_copy = malloc(sizeof(values_copy) * n);\n+\tif (!values_copy) {\n+\t\tRTE_PMD_DEBUG_TRACE(\n+\t\t\t\t\"ERROR: Cannot allocate memory for xstats\\n\");\n+\t\treturn -1;\n \t}\n+\tsize = rte_eth_xstats_get(port_id, 0, values_copy, n);\n \n-\treturn cnt_used_entries;\n+\tfor (i = 0; i < n; i++) {\n+\t\txstats[i].id = i;\n+\t\txstats[i].value = values_copy[i];\n+\t}\n+\tfree(values_copy);\n+\treturn size;\n }\n+VERSION_SYMBOL(rte_eth_xstats_get, _v22, 2.2);\n \n /* retrieve ethdev extended statistics */\n int\n-rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,\n-\tunsigned n)\n+rte_eth_xstats_get_v1705(uint8_t port_id, uint64_t *ids, uint64_t *values,\n+\tunsigned int n)\n {\n-\tstruct rte_eth_stats eth_stats;\n-\tstruct rte_eth_dev *dev;\n-\tunsigned count = 0, i, q;\n-\tsigned xcount = 0;\n-\tuint64_t val, *stats_ptr;\n-\tuint16_t nb_rxqs, nb_txqs;\n+\t/* If need all xstats */\n+\tif (!ids) {\n+\t\tstruct rte_eth_stats eth_stats;\n+\t\tstruct rte_eth_dev *dev;\n+\t\tunsigned int count = 0, i, q;\n+\t\tsigned int xcount = 0;\n+\t\tuint64_t val, *stats_ptr;\n+\t\tuint16_t nb_rxqs, nb_txqs;\n \n-\tRTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);\n+\t\tRTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);\n+\t\tdev = &rte_eth_devices[port_id];\n \n-\tdev = &rte_eth_devices[port_id];\n+\t\tnb_rxqs = RTE_MIN(dev->data->nb_rx_queues,\n+\t\t\t\tRTE_ETHDEV_QUEUE_STAT_CNTRS);\n+\t\tnb_txqs = RTE_MIN(dev->data->nb_tx_queues,\n+\t\t\t\tRTE_ETHDEV_QUEUE_STAT_CNTRS);\n \n-\tnb_rxqs = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);\n-\tnb_txqs = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);\n+\t\t/* Return generic statistics */\n+\t\tcount = RTE_NB_STATS + (nb_rxqs * RTE_NB_RXQ_STATS) +\n+\t\t\t(nb_txqs * RTE_NB_TXQ_STATS);\n \n-\t/* Return generic statistics */\n-\tcount = RTE_NB_STATS + (nb_rxqs * RTE_NB_RXQ_STATS) +\n-\t\t(nb_txqs * RTE_NB_TXQ_STATS);\n \n-\t/* implemented by the driver */\n-\tif (dev->dev_ops->xstats_get != NULL) {\n-\t\t/* Retrieve the xstats from the driver at the end of the\n-\t\t * xstats struct.\n-\t\t */\n-\t\txcount = (*dev->dev_ops->xstats_get)(dev,\n-\t\t\t\t     xstats ? xstats + count : NULL,\n-\t\t\t\t     (n > count) ? n - count : 0);\n+\t\t/* implemented by the driver */\n+\t\tif (dev->dev_ops->xstats_get_by_ids != NULL) {\n+\t\t\t/* Retrieve the xstats from the driver at the end of the\n+\t\t\t * xstats struct. Retrieve all xstats.\n+\t\t\t */\n+\t\t\txcount = (*dev->dev_ops->xstats_get_by_ids)(dev,\n+\t\t\t\t\tNULL,\n+\t\t\t\t\tvalues ? values + count : NULL,\n+\t\t\t\t\t(n > count) ? n - count : 0);\n+\n+\t\t\tif (xcount < 0)\n+\t\t\t\treturn xcount;\n+\t\t/* implemented by the driver */\n+\t\t} else if (dev->dev_ops->xstats_get != NULL) {\n+\t\t\t/* Retrieve the xstats from the driver at the end of the\n+\t\t\t * xstats struct. Retrieve all xstats.\n+\t\t\t * Compatibility for PMD without xstats_get_by_ids\n+\t\t\t */\n+\t\t\tunsigned int size = (n > count) ? n - count : 1;\n+\t\t\tstruct rte_eth_xstat xstats[size];\n \n-\t\tif (xcount < 0)\n-\t\t\treturn xcount;\n-\t}\n+\t\t\txcount = (*dev->dev_ops->xstats_get)(dev,\n+\t\t\t\t\tvalues ? xstats : NULL,\tsize);\n \n-\tif (n < count + xcount || xstats == NULL)\n-\t\treturn count + xcount;\n+\t\t\tif (xcount < 0)\n+\t\t\t\treturn xcount;\n+\n+\t\t\tif (values != NULL)\n+\t\t\t\tfor (i = 0 ; i < (unsigned int)xcount; i++)\n+\t\t\t\t\tvalues[i + count] = xstats[i].value;\n+\t\t}\n \n-\t/* now fill the xstats structure */\n-\tcount = 0;\n-\trte_eth_stats_get(port_id, &eth_stats);\n+\t\tif (n < count + xcount || values == NULL)\n+\t\t\treturn count + xcount;\n \n-\t/* global stats */\n-\tfor (i = 0; i < RTE_NB_STATS; i++) {\n-\t\tstats_ptr = RTE_PTR_ADD(&eth_stats,\n-\t\t\t\t\trte_stats_strings[i].offset);\n-\t\tval = *stats_ptr;\n-\t\txstats[count++].value = val;\n-\t}\n+\t\t/* now fill the xstats structure */\n+\t\tcount = 0;\n+\t\trte_eth_stats_get(port_id, &eth_stats);\n \n-\t/* per-rxq stats */\n-\tfor (q = 0; q < nb_rxqs; q++) {\n-\t\tfor (i = 0; i < RTE_NB_RXQ_STATS; i++) {\n+\t\t/* global stats */\n+\t\tfor (i = 0; i < RTE_NB_STATS; i++) {\n \t\t\tstats_ptr = RTE_PTR_ADD(&eth_stats,\n-\t\t\t\t\trte_rxq_stats_strings[i].offset +\n-\t\t\t\t\tq * sizeof(uint64_t));\n+\t\t\t\t\t\trte_stats_strings[i].offset);\n \t\t\tval = *stats_ptr;\n-\t\t\txstats[count++].value = val;\n+\t\t\tvalues[count++] = val;\n \t\t}\n+\n+\t\t/* per-rxq stats */\n+\t\tfor (q = 0; q < nb_rxqs; q++) {\n+\t\t\tfor (i = 0; i < RTE_NB_RXQ_STATS; i++) {\n+\t\t\t\tstats_ptr = RTE_PTR_ADD(&eth_stats,\n+\t\t\t\t\t    rte_rxq_stats_strings[i].offset +\n+\t\t\t\t\t    q * sizeof(uint64_t));\n+\t\t\t\tval = *stats_ptr;\n+\t\t\t\tvalues[count++] = val;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* per-txq stats */\n+\t\tfor (q = 0; q < nb_txqs; q++) {\n+\t\t\tfor (i = 0; i < RTE_NB_TXQ_STATS; i++) {\n+\t\t\t\tstats_ptr = RTE_PTR_ADD(&eth_stats,\n+\t\t\t\t\t    rte_txq_stats_strings[i].offset +\n+\t\t\t\t\t    q * sizeof(uint64_t));\n+\t\t\t\tval = *stats_ptr;\n+\t\t\t\tvalues[count++] = val;\n+\t\t\t}\n+\t\t}\n+\n+\t\treturn count + xcount;\n \t}\n+\t/* Need only xstats given by IDS array */\n+\telse {\n+\t\tuint16_t i, size;\n+\t\tuint64_t *values_copy;\n \n-\t/* per-txq stats */\n-\tfor (q = 0; q < nb_txqs; q++) {\n-\t\tfor (i = 0; i < RTE_NB_TXQ_STATS; i++) {\n-\t\t\tstats_ptr = RTE_PTR_ADD(&eth_stats,\n-\t\t\t\t\trte_txq_stats_strings[i].offset +\n-\t\t\t\t\tq * sizeof(uint64_t));\n-\t\t\tval = *stats_ptr;\n-\t\t\txstats[count++].value = val;\n+\t\tsize = rte_eth_xstats_get_v1705(port_id, NULL, NULL, 0);\n+\n+\t\tvalues_copy = malloc(sizeof(values_copy) * size);\n+\t\tif (!values_copy) {\n+\t\t\tRTE_PMD_DEBUG_TRACE(\n+\t\t\t    \"ERROR: can't allocate memory for values_copy\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\trte_eth_xstats_get_v1705(port_id, NULL, values_copy, size);\n+\n+\t\tfor (i = 0; i < n; i++) {\n+\t\t\tif (ids[i] >= size) {\n+\t\t\t\tRTE_PMD_DEBUG_TRACE(\n+\t\t\t\t\t\"ERROR: id value isn't valid\\n\");\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tvalues[i] = values_copy[ids[i]];\n \t\t}\n+\t\tfree(values_copy);\n+\t\treturn n;\n+\t}\n+}\n+BIND_DEFAULT_SYMBOL(rte_eth_xstats_get, _v1705, 17.05);\n+\n+MAP_STATIC_SYMBOL(int\n+\t\trte_eth_xstats_get(uint8_t port_id, uint64_t *ids,\n+\t\tuint64_t *values, unsigned int n), rte_eth_xstats_get_v1705);\n+\n+__rte_deprecated int\n+rte_eth_xstats_get_all(uint8_t port_id, struct rte_eth_xstat *xstats,\n+\tunsigned int n)\n+{\n+\tuint64_t *values_copy;\n+\tuint16_t size, i;\n+\n+\tvalues_copy = malloc(sizeof(values_copy) * n);\n+\tif (!values_copy) {\n+\t\tRTE_PMD_DEBUG_TRACE(\n+\t\t\t\t\"ERROR: Cannot allocate memory for xstats\\n\");\n+\t\treturn -1;\n \t}\n+\tsize = rte_eth_xstats_get(port_id, 0, values_copy, n);\n \n-\tfor (i = 0; i < count; i++)\n+\tfor (i = 0; i < n; i++) {\n \t\txstats[i].id = i;\n-\t/* add an offset to driver-specific stats */\n-\tfor ( ; i < count + xcount; i++)\n-\t\txstats[i].id += count;\n+\t\txstats[i].value = values_copy[i];\n+\t}\n+\tfree(values_copy);\n+\treturn size;\n+}\n \n-\treturn count + xcount;\n+__rte_deprecated int\n+rte_eth_xstats_get_names_all(uint8_t port_id,\n+\t\tstruct rte_eth_xstat_name *xstats_names, unsigned int n)\n+{\n+\treturn rte_eth_xstats_get_names(port_id, xstats_names, n, NULL);\n }\n \n /* reset ethdev extended statistics */\ndiff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h\nindex d072538..0ef9d20 100644\n--- a/lib/librte_ether/rte_ethdev.h\n+++ b/lib/librte_ether/rte_ethdev.h\n@@ -186,6 +186,7 @@\n #include \"rte_ether.h\"\n #include \"rte_eth_ctrl.h\"\n #include \"rte_dev_info.h\"\n+#include \"rte_compat.h\"\n \n struct rte_mbuf;\n \n@@ -1118,6 +1119,10 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,\n \tstruct rte_eth_xstat *stats, unsigned n);\n /**< @internal Get extended stats of an Ethernet device. */\n \n+typedef int (*eth_xstats_get_by_ids_t)(struct rte_eth_dev *dev,\n+\t\tuint64_t *ids, uint64_t *values, unsigned int n);\n+/**< @internal Get extended stats of an Ethernet device. */\n+\n typedef void (*eth_xstats_reset_t)(struct rte_eth_dev *dev);\n /**< @internal Reset extended stats of an Ethernet device. */\n \n@@ -1125,6 +1130,17 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,\n \tstruct rte_eth_xstat_name *xstats_names, unsigned size);\n /**< @internal Get names of extended stats of an Ethernet device. */\n \n+typedef int (*eth_xstats_get_names_by_ids_t)(struct rte_eth_dev *dev,\n+\tstruct rte_eth_xstat_name *xstats_names, uint64_t *ids,\n+\tunsigned int size);\n+/**< @internal Get names of extended stats of an Ethernet device. */\n+\n+typedef int (*eth_xstats_get_by_name_t)(struct rte_eth_dev *dev,\n+\t\tstruct rte_eth_xstat_name *xstats_names,\n+\t\tstruct rte_eth_xstat *xstat,\n+\t\tconst char *name);\n+/**< @internal Get xstat specified by name of an Ethernet device. */\n+\n typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,\n \t\t\t\t\t     uint16_t queue_id,\n \t\t\t\t\t     uint8_t stat_idx,\n@@ -1466,8 +1482,8 @@ struct eth_dev_ops {\n \teth_stats_reset_t          stats_reset;   /**< Reset generic device statistics. */\n \teth_xstats_get_t           xstats_get;    /**< Get extended device statistics. */\n \teth_xstats_reset_t         xstats_reset;  /**< Reset extended device statistics. */\n-\teth_xstats_get_names_t     xstats_get_names;\n-\t/**< Get names of extended statistics. */\n+\teth_xstats_get_names_t\t   xstats_get_names;\n+\t/**< Get names of extended device statistics. */\n \teth_queue_stats_mapping_set_t queue_stats_mapping_set;\n \t/**< Configure per queue stat counter mapping. */\n \n@@ -1563,6 +1579,12 @@ struct eth_dev_ops {\n \teth_timesync_adjust_time   timesync_adjust_time; /** Adjust the device clock. */\n \teth_timesync_read_time     timesync_read_time; /** Get the device clock time. */\n \teth_timesync_write_time    timesync_write_time; /** Set the device clock time. */\n+\teth_xstats_get_by_ids_t    xstats_get_by_ids;\n+\t/**< Get extended device statistics by ID. */\n+\teth_xstats_get_names_by_ids_t xstats_get_names_by_ids;\n+\t/**< Get name of extended device statistics by ID. */\n+\teth_xstats_get_by_name_t   xstats_get_by_name;\n+\t/**< Get extended device statistics by name. */\n };\n \n /**\n@@ -2324,8 +2346,55 @@ int rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,\n  */\n void rte_eth_stats_reset(uint8_t port_id);\n \n+\n /**\n- * Retrieve names of extended statistics of an Ethernet device.\n+* Gets the ID of a statistic from its name.\n+*\n+* Note this function searches for the statistics using string compares, and\n+* as such should not be used on the fast-path. For fast-path retrieval of\n+* specific statistics, store the ID as provided in *id* from this function,\n+* and pass the ID to rte_eth_xstats_get()\n+*\n+* @param port_id The port to look up statistics from\n+* @param xstat_name The name of the statistic to return\n+* @param[out] id A pointer to an app-supplied uint64_t which should be\n+*                set to the ID of the stat if the stat exists.\n+* @return\n+*    0 on success\n+*    -ENODEV for invalid port_id,\n+*    -EINVAL if the xstat_name doesn't exist in port_id\n+*/\n+int rte_eth_xstats_get_id_by_name(uint8_t port_id, const char *xstat_name,\n+\t\tuint64_t *id);\n+\n+/**\n+ * Retrieve all extended statistics of an Ethernet device.\n+ *\n+ * @param port_id\n+ *   The port identifier of the Ethernet device.\n+ * @param xstats\n+ *   A pointer to a table of structure of type *rte_eth_xstat*\n+ *   to be filled with device statistics ids and values: id is the\n+ *   index of the name string in xstats_names (see rte_eth_xstats_get_names()),\n+ *   and value is the statistic counter.\n+ *   This parameter can be set to NULL if n is 0.\n+ * @param n\n+ *   The size of the xstats array (number of elements).\n+ * @return\n+ *   - A positive value lower or equal to n: success. The return value\n+ *     is the number of entries filled in the stats table.\n+ *   - A positive value higher than n: error, the given statistics table\n+ *     is too small. The return value corresponds to the size that should\n+ *     be given to succeed. The entries in the table are not valid and\n+ *     shall not be used by the caller.\n+ *   - A negative value on error (invalid port id).\n+ */\n+__rte_deprecated\n+int rte_eth_xstats_get_all(uint8_t port_id, struct rte_eth_xstat *xstats,\n+\tunsigned int n);\n+\n+/**\n+ * Retrieve names of all extended statistics of an Ethernet device.\n  *\n  * @param port_id\n  *   The port identifier of the Ethernet device.\n@@ -2333,7 +2402,7 @@ int rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,\n  *   An rte_eth_xstat_name array of at least *size* elements to\n  *   be filled. If set to NULL, the function returns the required number\n  *   of elements.\n- * @param size\n+ * @param n\n  *   The size of the xstats_names array (number of elements).\n  * @return\n  *   - A positive value lower or equal to size: success. The return value\n@@ -2344,9 +2413,8 @@ int rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,\n  *     shall not be used by the caller.\n  *   - A negative value on error (invalid port id).\n  */\n-int rte_eth_xstats_get_names(uint8_t port_id,\n-\t\tstruct rte_eth_xstat_name *xstats_names,\n-\t\tunsigned size);\n+__rte_deprecated int rte_eth_xstats_get_names_all(uint8_t port_id,\n+\t\tstruct rte_eth_xstat_name *xstats_names, unsigned int n);\n \n /**\n  * Retrieve extended statistics of an Ethernet device.\n@@ -2370,8 +2438,92 @@ int rte_eth_xstats_get_names(uint8_t port_id,\n  *     shall not be used by the caller.\n  *   - A negative value on error (invalid port id).\n  */\n-int rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,\n-\t\tunsigned n);\n+int rte_eth_xstats_get_v22(uint8_t port_id, struct rte_eth_xstat *xstats,\n+\tunsigned int n);\n+\n+/**\n+ * Retrieve extended statistics of an Ethernet device.\n+ *\n+ * @param port_id\n+ *   The port identifier of the Ethernet device.\n+ * @param ids\n+ *   A pointer to an ids array passed by application. This tells wich\n+ *   statistics values function should retrieve. This parameter\n+ *   can be set to NULL if n is 0. In this case function will retrieve\n+ *   all avalible statistics.\n+ * @param values\n+ *   A pointer to a table to be filled with device statistics values.\n+ * @param n\n+ *   The size of the ids array (number of elements).\n+ * @return\n+ *   - A positive value lower or equal to n: success. The return value\n+ *     is the number of entries filled in the stats table.\n+ *   - A positive value higher than n: error, the given statistics table\n+ *     is too small. The return value corresponds to the size that should\n+ *     be given to succeed. The entries in the table are not valid and\n+ *     shall not be used by the caller.\n+ *   - A negative value on error (invalid port id).\n+ */\n+int rte_eth_xstats_get_v1705(uint8_t port_id, uint64_t *ids, uint64_t *values,\n+\tunsigned int n);\n+\n+int rte_eth_xstats_get(uint8_t port_id, uint64_t *ids, uint64_t *values,\n+\tunsigned int n);\n+\n+/**\n+ * Retrieve extended statistics of an Ethernet device.\n+ *\n+ * @param port_id\n+ *   The port identifier of the Ethernet device.\n+ * @param xstats_names\n+ *   A pointer to a table of structure of type *rte_eth_xstat*\n+ *   to be filled with device statistics ids and values: id is the\n+ *   index of the name string in xstats_names (see rte_eth_xstats_get_names()),\n+ *   and value is the statistic counter.\n+ *   This parameter can be set to NULL if n is 0.\n+ * @param n\n+ *   The size of the xstats array (number of elements).\n+ * @return\n+ *   - A positive value lower or equal to n: success. The return value\n+ *     is the number of entries filled in the stats table.\n+ *   - A positive value higher than n: error, the given statistics table\n+ *     is too small. The return value corresponds to the size that should\n+ *     be given to succeed. The entries in the table are not valid and\n+ *     shall not be used by the caller.\n+ *   - A negative value on error (invalid port id).\n+ */\n+int rte_eth_xstats_get_names_v1607(uint8_t port_id,\n+\t\tstruct rte_eth_xstat_name *xstats_names, unsigned int n);\n+\n+/**\n+ * Retrieve names of extended statistics of an Ethernet device.\n+ *\n+ * @param port_id\n+ *   The port identifier of the Ethernet device.\n+ * @param xstats_names\n+ *   An rte_eth_xstat_name array of at least *size* elements to\n+ *   be filled. If set to NULL, the function returns the required number\n+ *   of elements.\n+ * @param ids\n+ *   IDs array given by app to retrieve specific statistics\n+ * @param size\n+ *   The size of the xstats_names array (number of elements).\n+ * @return\n+ *   - A positive value lower or equal to size: success. The return value\n+ *     is the number of entries filled in the stats table.\n+ *   - A positive value higher than size: error, the given statistics table\n+ *     is too small. The return value corresponds to the size that should\n+ *     be given to succeed. The entries in the table are not valid and\n+ *     shall not be used by the caller.\n+ *   - A negative value on error (invalid port id).\n+ */\n+int rte_eth_xstats_get_names_v1705(uint8_t port_id,\n+\tstruct rte_eth_xstat_name *xstats_names, unsigned int size,\n+\tuint64_t *ids);\n+\n+int rte_eth_xstats_get_names(uint8_t port_id,\n+\tstruct rte_eth_xstat_name *xstats_names, unsigned int size,\n+\tuint64_t *ids);\n \n /**\n  * Reset extended statistics of an Ethernet device.\ndiff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map\nindex 0ea3856..f4d0136 100644\n--- a/lib/librte_ether/rte_ether_version.map\n+++ b/lib/librte_ether/rte_ether_version.map\n@@ -159,5 +159,10 @@ DPDK_17.05 {\n \tglobal:\n \n \trte_eth_find_next;\n+\trte_eth_xstats_get_names;\n+\trte_eth_xstats_get;\n+\trte_eth_xstats_get_all;\n+\trte_eth_xstats_get_names_all;\n+\trte_eth_xstats_get_id_by_name;\n \n } DPDK_17.02;\n",
    "prefixes": [
        "dpdk-dev",
        "v5",
        "1/3"
    ]
}