[dpdk-dev,v3,1/3] add new xstats API retrieving by id

Message ID 1491221393-10305-2-git-send-email-jacekx.piasecki@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Jacek Piasecki April 3, 2017, 12:09 p.m. UTC
  From: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>

Extended xstats API in ethdev library to allow grouping of stats
logically so they can be retrieved per logical grouping – managed
by the application.
Changed existing functions rte_eth_xstats_get_names and
rte_eth_xstats_get to use a new list of arguments: array of ids
and array of values. ABI versioning mechanism was used to
support backward compatibility.
Introduced two new functions rte_eth_xstats_get_all and
rte_eth_xstats_get_names_all which keeps functionality of the
previous ones (respectively rte_eth_xstats_get and
rte_eth_xstats_get_names) but use new API inside.
Both functions marked as deprecated.
Introduced new function: rte_eth_xstats_get_id_by_name
to retrieve xstats ids by its names.

test-pmd: add support for new xstats API retrieving by id in
testpmd application: xstats_get() and
xstats_get_names() call with modified parameters.

proc_info: add support for new xstats API retrieving by id to
proc_info application. There is a new argument --xstats-ids
in proc_info command line to retrieve statistics given by ids.
E.g. --xstats-ids="1,3,5,7,8"

Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 app/proc_info/main.c                   | 148 +++++++++++-
 app/test-pmd/config.c                  |  19 +-
 lib/librte_ether/Makefile              |   2 +-
 lib/librte_ether/rte_ethdev.c          | 422 +++++++++++++++++++++++++--------
 lib/librte_ether/rte_ethdev.h          | 176 +++++++++++++-
 lib/librte_ether/rte_ether_version.map |  12 +
 6 files changed, 646 insertions(+), 133 deletions(-)
  

Comments

Van Haaren, Harry April 3, 2017, 12:37 p.m. UTC | #1
> From: Piasecki, JacekX

> Sent: Monday, April 3, 2017 1:10 PM

> To: dev@dpdk.org

> Cc: Van Haaren, Harry <harry.van.haaren@intel.com>; Jastrzebski, MichalX K

> <michalx.k.jastrzebski@intel.com>; Piasecki, JacekX <jacekx.piasecki@intel.com>; Kozak, KubaX

> <kubax.kozak@intel.com>; Kulasek, TomaszX <tomaszx.kulasek@intel.com>

> Subject: [PATCH v3 1/3] add new xstats API retrieving by id

> 

> From: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>

> 

> Extended xstats API in ethdev library to allow grouping of stats

> logically so they can be retrieved per logical grouping – managed

> by the application.

> Changed existing functions rte_eth_xstats_get_names and

> rte_eth_xstats_get to use a new list of arguments: array of ids

> and array of values. ABI versioning mechanism was used to

> support backward compatibility.

> Introduced two new functions rte_eth_xstats_get_all and

> rte_eth_xstats_get_names_all which keeps functionality of the

> previous ones (respectively rte_eth_xstats_get and

> rte_eth_xstats_get_names) but use new API inside.

> Both functions marked as deprecated.

> Introduced new function: rte_eth_xstats_get_id_by_name

> to retrieve xstats ids by its names.

> 

> test-pmd: add support for new xstats API retrieving by id in

> testpmd application: xstats_get() and

> xstats_get_names() call with modified parameters.

> 

> proc_info: add support for new xstats API retrieving by id to

> proc_info application. There is a new argument --xstats-ids

> in proc_info command line to retrieve statistics given by ids.

> E.g. --xstats-ids="1,3,5,7,8"

> 

> Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>

> Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>

> Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>

> ---

>  app/proc_info/main.c                   | 148 +++++++++++-

>  app/test-pmd/config.c                  |  19 +-

>  lib/librte_ether/Makefile              |   2 +-

>  lib/librte_ether/rte_ethdev.c          | 422 +++++++++++++++++++++++++--------

>  lib/librte_ether/rte_ethdev.h          | 176 +++++++++++++-

>  lib/librte_ether/rte_ether_version.map |  12 +

>  6 files changed, 646 insertions(+), 133 deletions(-)


I gather this patchset contains various changes at once to avoid breaking compile due to function changes. All 3 of patchset compiled and working with ixgbe,

Acked-by: Harry van Haaren <harry.van.haaren@intel.com>
  
Thomas Monjalon April 4, 2017, 3:03 p.m. UTC | #2
2017-04-03 14:09, Jacek Piasecki:
> From: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
> 
> Extended xstats API in ethdev library to allow grouping of stats
> logically so they can be retrieved per logical grouping – managed
> by the application.
> Changed existing functions rte_eth_xstats_get_names and
> rte_eth_xstats_get to use a new list of arguments: array of ids
> and array of values. ABI versioning mechanism was used to
> support backward compatibility.
> Introduced two new functions rte_eth_xstats_get_all and
> rte_eth_xstats_get_names_all which keeps functionality of the
> previous ones (respectively rte_eth_xstats_get and
> rte_eth_xstats_get_names) but use new API inside.

Sorry, I still do not understand why we should complicate the API.
What is not possible with the existing API?

The v1 was submitted in the last days of the proposal deadline,
v2 in the last minutes of integration deadline,
and v3 is submitted after the deadline.

Given it is late and it is still difficult to understand the benefit,
I think it won't make the release 17.05.
  
Van Haaren, Harry April 4, 2017, 3:45 p.m. UTC | #3
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]

> Sent: Tuesday, April 4, 2017 4:04 PM

> To: Piasecki, JacekX <jacekx.piasecki@intel.com>; Jastrzebski, MichalX K

> <michalx.k.jastrzebski@intel.com>

> Cc: dev@dpdk.org; Van Haaren, Harry <harry.van.haaren@intel.com>; Kozak, KubaX

> <kubax.kozak@intel.com>; Kulasek, TomaszX <tomaszx.kulasek@intel.com>

> Subject: Re: [dpdk-dev] [PATCH v3 1/3] add new xstats API retrieving by id

> 

> 2017-04-03 14:09, Jacek Piasecki:

> > From: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>

> >

> > Extended xstats API in ethdev library to allow grouping of stats

> > logically so they can be retrieved per logical grouping – managed

> > by the application.

> > Changed existing functions rte_eth_xstats_get_names and

> > rte_eth_xstats_get to use a new list of arguments: array of ids

> > and array of values. ABI versioning mechanism was used to

> > support backward compatibility.

> > Introduced two new functions rte_eth_xstats_get_all and

> > rte_eth_xstats_get_names_all which keeps functionality of the

> > previous ones (respectively rte_eth_xstats_get and

> > rte_eth_xstats_get_names) but use new API inside.

> 

> Sorry, I still do not understand why we should complicate the API.

> What is not possible with the existing API?



The current API only allows retrieval of *all* of the NIC statistics at once. Given this requires a MMIO read PCI transaction per statistic it is an inefficient way of retrieving just a few key statistics. My understanding is that often a monitoring agent only has an interest in a few key statistics, and the current API forces wasting CPU time and PCIe bandwidth in retrieving *all* statistics; even those that the application didn't explicitly show an interest in.

The more flexible API as implemented in this patchset allow retrieval of statistics per ID. If a PMD wishes, it can be implemented to read just the required NIC registers. As a result, the monitoring application no longer wastes PCIe bandwidth and CPU time.


> The v1 was submitted in the last days of the proposal deadline,

> v2 in the last minutes of integration deadline,

> and v3 is submitted after the deadline.

> 

> Given it is late and it is still difficult to understand the benefit,

> I think it won't make the release 17.05.



All in all, the value add to DPDK of this patchset is to enable applications request statistics of interest to them, and to allow PMDs implement the statistic functions more efficiently if they wish. As a bonus, the ethdev and eventdev xstats APIs will have a consistent design, as eventdev already uses this optimized ID based method.

Unless there are serious concerns about the current API (which should have been flagged between a v1 and now), I don't see a reason to not update the API to use this improved method. If there are concerns about how to update applications to the new API, that can be addressed in a documentation patch if the community feels there is value in that?
  
Thomas Monjalon April 4, 2017, 4:18 p.m. UTC | #4
2017-04-04 15:45, Van Haaren, Harry:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > 2017-04-03 14:09, Jacek Piasecki:
> > > From: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
> > >
> > > Extended xstats API in ethdev library to allow grouping of stats
> > > logically so they can be retrieved per logical grouping – managed
> > > by the application.
> > > Changed existing functions rte_eth_xstats_get_names and
> > > rte_eth_xstats_get to use a new list of arguments: array of ids
> > > and array of values. ABI versioning mechanism was used to
> > > support backward compatibility.
> > > Introduced two new functions rte_eth_xstats_get_all and
> > > rte_eth_xstats_get_names_all which keeps functionality of the
> > > previous ones (respectively rte_eth_xstats_get and
> > > rte_eth_xstats_get_names) but use new API inside.
> > 
> > Sorry, I still do not understand why we should complicate the API.
> > What is not possible with the existing API?
> 
> 
> The current API only allows retrieval of *all* of the NIC statistics at once. Given this requires a MMIO read PCI transaction per statistic it is an inefficient way of retrieving just a few key statistics. My understanding is that often a monitoring agent only has an interest in a few key statistics, and the current API forces wasting CPU time and PCIe bandwidth in retrieving *all* statistics; even those that the application didn't explicitly show an interest in.
> 
> The more flexible API as implemented in this patchset allow retrieval of statistics per ID. If a PMD wishes, it can be implemented to read just the required NIC registers. As a result, the monitoring application no longer wastes PCIe bandwidth and CPU time.

Thanks for the explanation.
It has never been explained before.

> > The v1 was submitted in the last days of the proposal deadline,
> > v2 in the last minutes of integration deadline,
> > and v3 is submitted after the deadline.
> > 
> > Given it is late and it is still difficult to understand the benefit,
> > I think it won't make the release 17.05.
> 
> 
> All in all, the value add to DPDK of this patchset is to enable applications request statistics of interest to them, and to allow PMDs implement the statistic functions more efficiently if they wish. As a bonus, the ethdev and eventdev xstats APIs will have a consistent design, as eventdev already uses this optimized ID based method.
> 
> Unless there are serious concerns about the current API (which should have been flagged between a v1 and now), I don't see a reason to not update the API to use this improved method. If there are concerns about how to update applications to the new API, that can be addressed in a documentation patch if the community feels there is value in that?

I have commented on the need of explanation 3 days after the v1.
There was no answer.
So the review stopped at this point.
Then one month later (last Thursday), a v2 appears which
"replaced grouping mechanism to use mechanism based on IDs".
So you cannot say it "should have been flagged between a v1 and now".

Just because of the lack of communication, I do not want to spend these
days reviewing the API. It needs time and it will wait.
  
Jacek Piasecki April 10, 2017, 5:59 p.m. UTC | #5
Extended xstats API in ethdev library to allow grouping of stats logically
so they can be retrieved per logical grouping  managed by the application.
Changed existing functions rte_eth_xstats_get_names and rte_eth_xstats_get
to use a new list of arguments: array of ids and array of values.
ABI versioning mechanism was used to support backward compatibility.
Introduced two new functions rte_eth_xstats_get_all and
rte_eth_xstats_get_names_all which keeps functionality of the previous
ones (respectively rte_eth_xstats_get and rte_eth_xstats_get_names)
but use new API inside. Both functions marked as deprecated. 
Introduced new function: rte_eth_xstats_get_id_by_name to retrieve
xstats ids by its names.
Extended functionality of proc_info application:
--xstats-name NAME: to display single xstat value by NAME
Updated test-pmd application to use new API.

v4 changes:
documentation change after API modification
fix xstats display for PMD without _by_ids() functions
fix ABI validator errors

v3 changes:
checkpatch fixes
removed malloc bug in ethdev
add new command to proc_info and IDs parsing
merged testpmd and proc_info patch with library patch

Jacek Piasecki (3):
  ethdev: new xstats API add retrieving by ID
  net/e1000: new xstats API add ID support for e1000
  net/ixgbe: new xstats API add ID support for ixgbe

 app/proc_info/main.c                    | 150 ++++++++++-
 app/test-pmd/config.c                   |  19 +-
 doc/guides/prog_guide/poll_mode_drv.rst | 174 +++++++++++--
 drivers/net/e1000/igb_ethdev.c          |  92 ++++++-
 drivers/net/ixgbe/ixgbe_ethdev.c        | 179 ++++++++++++++
 lib/librte_ether/Makefile               |   2 +-
 lib/librte_ether/rte_ethdev.c           | 426 ++++++++++++++++++++++++--------
 lib/librte_ether/rte_ethdev.h           | 176 ++++++++++++-
 lib/librte_ether/rte_ether_version.map  |   5 +
 9 files changed, 1066 insertions(+), 157 deletions(-)
  

Patch

diff --git a/app/proc_info/main.c b/app/proc_info/main.c
index ef2098d..3c9fe4a 100644
--- a/app/proc_info/main.c
+++ b/app/proc_info/main.c
@@ -83,6 +83,14 @@ 
 static uint32_t reset_xstats;
 /**< Enable memory info. */
 static uint32_t mem_info;
+/**< Enable displaying xstat name. */
+static uint32_t enable_xstats_name;
+static char *xstats_name;
+
+/**< Enable xstats by ids. */
+#define MAX_NB_XSTATS_IDS 1024
+static uint32_t nb_xstats_ids;
+static uint64_t xstats_ids[MAX_NB_XSTATS_IDS];
 
 /**< display usage */
 static void
@@ -94,6 +102,9 @@ 
 		"  --stats: to display port statistics, enabled by default\n"
 		"  --xstats: to display extended port statistics, disabled by "
 			"default\n"
+		"  --xstats-name NAME: to display single xstat value by NAME\n"
+		"  --xstats-ids IDLIST: to display xstat values by id. "
+			"The argument is comma-separated list of xstat ids to print out.\n"
 		"  --stats-reset: to reset port statistics\n"
 		"  --xstats-reset: to reset port extended statistics\n"
 		"  --collectd-format: to print statistics to STDOUT in expected by collectd format\n"
@@ -127,6 +138,33 @@ 
 
 }
 
+/*
+ * Parse ids value list into array
+ */
+static int
+parse_xstats_ids(char *list, uint64_t *ids, int limit) {
+	int length;
+	char *token;
+	char *ctx = NULL;
+	char *endptr;
+
+	length = 0;
+	token = strtok_r(list, ",", &ctx);
+	while (token != NULL) {
+		ids[length] = strtoull(token, &endptr, 10);
+		if (*endptr != '\0')
+			return -EINVAL;
+
+		length++;
+		if (length >= limit)
+			return -E2BIG;
+
+		token = strtok_r(NULL, ",", &ctx);
+	}
+
+	return length;
+}
+
 static int
 proc_info_preparse_args(int argc, char **argv)
 {
@@ -172,7 +210,9 @@ 
 		{"stats-reset", 0, NULL, 0},
 		{"xstats", 0, NULL, 0},
 		{"xstats-reset", 0, NULL, 0},
+		{"xstats-name", required_argument, NULL, 1},
 		{"collectd-format", 0, NULL, 0},
+		{"xstats-ids", 1, NULL, 1},
 		{"host-id", 0, NULL, 0},
 		{NULL, 0, 0, 0}
 	};
@@ -214,7 +254,28 @@ 
 					MAX_LONG_OPT_SZ))
 				reset_xstats = 1;
 			break;
+		case 1:
+			/* Print xstat single value given by name*/
+			if (!strncmp(long_option[option_index].name,
+					"xstats-name", MAX_LONG_OPT_SZ)) {
+				enable_xstats_name = 1;
+				xstats_name = optarg;
+				printf("name:%s:%s\n",
+						long_option[option_index].name,
+						optarg);
+			} else if (!strncmp(long_option[option_index].name,
+					"xstats-ids",
+					MAX_LONG_OPT_SZ))	{
+				nb_xstats_ids = parse_xstats_ids(optarg,
+						xstats_ids, MAX_NB_XSTATS_IDS);
+
+				if (nb_xstats_ids <= 0) {
+					printf("xstats-id list parse error.\n");
+					return -1;
+				}
 
+			}
+			break;
 		default:
 			proc_info_usage(prgname);
 			return -1;
@@ -341,20 +402,82 @@  static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,
 }
 
 static void
+nic_xstats_by_name_display(uint8_t port_id, char *name)
+{
+	uint64_t id;
+
+	printf("###### NIC statistics for port %-2d, statistic name '%s':\n",
+			   port_id, name);
+
+	if (rte_eth_xstats_get_id_by_name(port_id, name, &id) == 0)
+		printf("%s: %"PRIu64"\n", name, id);
+	else
+		printf("Statistic not found...\n");
+
+}
+
+static void
+nic_xstats_by_ids_display(uint8_t port_id, uint64_t *ids, int len)
+{
+	struct rte_eth_xstat_name *xstats_names;
+	uint64_t *values;
+	int ret, i;
+	static const char *nic_stats_border = "########################";
+
+	values = malloc(sizeof(values) * len);
+	if (values == NULL) {
+		printf("Cannot allocate memory for xstats\n");
+		return;
+	}
+
+	xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * len);
+	if (xstats_names == NULL) {
+		printf("Cannot allocate memory for xstat names\n");
+		free(values);
+		return;
+	}
+
+	if (len != rte_eth_xstats_get_names(
+			port_id, xstats_names, ids, len)) {
+		printf("Cannot get xstat names\n");
+		goto err;
+	}
+
+	printf("###### NIC extended statistics for port %-2d #########\n",
+			   port_id);
+	printf("%s############################\n", nic_stats_border);
+	ret = rte_eth_xstats_get(port_id, ids, values, len);
+	if (ret < 0 || ret > len) {
+		printf("Cannot get xstats\n");
+		goto err;
+	}
+
+	for (i = 0; i < len; i++)
+		printf("%s: %"PRIu64"\n",
+			xstats_names[i].name,
+			values[i]);
+
+	printf("%s############################\n", nic_stats_border);
+err:
+	free(values);
+	free(xstats_names);
+}
+
+static void
 nic_xstats_display(uint8_t port_id)
 {
 	struct rte_eth_xstat_name *xstats_names;
-	struct rte_eth_xstat *xstats;
+	uint64_t *values;
 	int len, ret, i;
 	static const char *nic_stats_border = "########################";
 
-	len = rte_eth_xstats_get_names(port_id, NULL, 0);
+	len = rte_eth_xstats_get_names(port_id, NULL, NULL, 0);
 	if (len < 0) {
 		printf("Cannot get xstats count\n");
 		return;
 	}
-	xstats = malloc(sizeof(xstats[0]) * len);
-	if (xstats == NULL) {
+	values = malloc(sizeof(values) * len);
+	if (values == NULL) {
 		printf("Cannot allocate memory for xstats\n");
 		return;
 	}
@@ -362,11 +485,11 @@  static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,
 	xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * len);
 	if (xstats_names == NULL) {
 		printf("Cannot allocate memory for xstat names\n");
-		free(xstats);
+		free(values);
 		return;
 	}
 	if (len != rte_eth_xstats_get_names(
-			port_id, xstats_names, len)) {
+			port_id, xstats_names, NULL, len)) {
 		printf("Cannot get xstat names\n");
 		goto err;
 	}
@@ -375,7 +498,7 @@  static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,
 			   port_id);
 	printf("%s############################\n",
 			   nic_stats_border);
-	ret = rte_eth_xstats_get(port_id, xstats, len);
+	ret = rte_eth_xstats_get(port_id, NULL, values, len);
 	if (ret < 0 || ret > len) {
 		printf("Cannot get xstats\n");
 		goto err;
@@ -391,18 +514,18 @@  static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,
 						  xstats_names[i].name);
 			sprintf(buf, "PUTVAL %s/dpdkstat-port.%u/%s-%s N:%"
 				PRIu64"\n", host_id, port_id, counter_type,
-				xstats_names[i].name, xstats[i].value);
+				xstats_names[i].name, values[i]);
 			write(stdout_fd, buf, strlen(buf));
 		} else {
 			printf("%s: %"PRIu64"\n", xstats_names[i].name,
-			       xstats[i].value);
+					values[i]);
 		}
 	}
 
 	printf("%s############################\n",
 			   nic_stats_border);
 err:
-	free(xstats);
+	free(values);
 	free(xstats_names);
 }
 
@@ -480,6 +603,11 @@  static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,
 				nic_stats_clear(i);
 			else if (reset_xstats)
 				nic_xstats_clear(i);
+			else if (enable_xstats_name)
+				nic_xstats_by_name_display(i, xstats_name);
+			else if (nb_xstats_ids > 0)
+				nic_xstats_by_ids_display(i, xstats_ids,
+						nb_xstats_ids);
 		}
 	}
 
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 80491fc..c93e04a 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -264,9 +264,9 @@  struct rss_type_info {
 void
 nic_xstats_display(portid_t port_id)
 {
-	struct rte_eth_xstat *xstats;
 	int cnt_xstats, idx_xstat;
 	struct rte_eth_xstat_name *xstats_names;
+	uint64_t *values;
 
 	printf("###### NIC extended statistics for port %-2d\n", port_id);
 	if (!rte_eth_dev_is_valid_port(port_id)) {
@@ -275,7 +275,7 @@  struct rss_type_info {
 	}
 
 	/* Get count */
-	cnt_xstats = rte_eth_xstats_get_names(port_id, NULL, 0);
+	cnt_xstats = rte_eth_xstats_get_names(port_id, NULL, NULL, 0);
 	if (cnt_xstats  < 0) {
 		printf("Error: Cannot get count of xstats\n");
 		return;
@@ -288,23 +288,24 @@  struct rss_type_info {
 		return;
 	}
 	if (cnt_xstats != rte_eth_xstats_get_names(
-			port_id, xstats_names, cnt_xstats)) {
+			port_id, xstats_names, NULL, cnt_xstats)) {
 		printf("Error: Cannot get xstats lookup\n");
 		free(xstats_names);
 		return;
 	}
 
 	/* Get stats themselves */
-	xstats = malloc(sizeof(struct rte_eth_xstat) * cnt_xstats);
-	if (xstats == NULL) {
+	values = malloc(sizeof(values) * cnt_xstats);
+	if (values == NULL) {
 		printf("Cannot allocate memory for xstats\n");
 		free(xstats_names);
 		return;
 	}
-	if (cnt_xstats != rte_eth_xstats_get(port_id, xstats, cnt_xstats)) {
+	if (cnt_xstats != rte_eth_xstats_get(port_id, NULL, values,
+			cnt_xstats)) {
 		printf("Error: Unable to get xstats\n");
 		free(xstats_names);
-		free(xstats);
+		free(values);
 		return;
 	}
 
@@ -312,9 +313,9 @@  struct rss_type_info {
 	for (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++)
 		printf("%s: %"PRIu64"\n",
 			xstats_names[idx_xstat].name,
-			xstats[idx_xstat].value);
+			values[idx_xstat]);
 	free(xstats_names);
-	free(xstats);
+	free(values);
 }
 
 void
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 066114b..5bbf721 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -41,7 +41,7 @@  CFLAGS += $(WERROR_FLAGS)
 
 EXPORT_MAP := rte_ether_version.map
 
-LIBABIVER := 6
+LIBABIVER := 7
 
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index b796e7d..91524c4 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -1449,7 +1449,8 @@  struct rte_eth_dev *
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
 	dev = &rte_eth_devices[port_id];
 	if (dev->dev_ops->xstats_get_names != NULL) {
-		count = (*dev->dev_ops->xstats_get_names)(dev, NULL, 0);
+		count = (*dev->dev_ops->xstats_get_names_by_ids)(dev, NULL,
+				NULL, 0);
 		if (count < 0)
 			return count;
 	} else
@@ -1463,150 +1464,363 @@  struct rte_eth_dev *
 }
 
 int
-rte_eth_xstats_get_names(uint8_t port_id,
-	struct rte_eth_xstat_name *xstats_names,
-	unsigned size)
+rte_eth_xstats_get_id_by_name(uint8_t port_id, const char *xstat_name,
+		uint64_t *id)
 {
-	struct rte_eth_dev *dev;
-	int cnt_used_entries;
-	int cnt_expected_entries;
-	int cnt_driver_entries;
-	uint32_t idx, id_queue;
-	uint16_t num_q;
+	int cnt_xstats, idx_xstat;
 
-	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;
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 
-	/* port_id checked in get_xstats_count() */
-	dev = &rte_eth_devices[port_id];
-	cnt_used_entries = 0;
+	if (!id) {
+		RTE_PMD_DEBUG_TRACE("Error: id pointer is NULL\n");
+		return -1;
+	}
 
-	for (idx = 0; idx < RTE_NB_STATS; idx++) {
-		snprintf(xstats_names[cnt_used_entries].name,
-			sizeof(xstats_names[0].name),
-			"%s", rte_stats_strings[idx].name);
-		cnt_used_entries++;
+	if (!xstat_name) {
+		RTE_PMD_DEBUG_TRACE("Error: xstat_name pointer is NULL\n");
+		return -1;
+	}
+
+	/* Get count */
+	cnt_xstats = rte_eth_xstats_get_names(port_id, NULL, NULL, 0);
+	if (cnt_xstats  < 0) {
+		RTE_PMD_DEBUG_TRACE("Error: Cannot get count of xstats\n");
+		return -1;
 	}
-	num_q = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
-	for (id_queue = 0; id_queue < num_q; id_queue++) {
-		for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) {
+
+	/* Get id-name lookup table */
+	struct rte_eth_xstat_name xstats_names[cnt_xstats];
+
+	if (cnt_xstats != rte_eth_xstats_get_names(
+			port_id, xstats_names, NULL, cnt_xstats)) {
+		RTE_PMD_DEBUG_TRACE("Error: Cannot get xstats lookup\n");
+		return -1;
+	}
+
+	for (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++) {
+		if (!strcmp(xstats_names[idx_xstat].name, xstat_name)) {
+			*id = idx_xstat;
+			return 0;
+		};
+	}
+
+	return -EINVAL;
+}
+
+int
+rte_eth_xstats_get_names_v1705(uint8_t port_id,
+	struct rte_eth_xstat_name *xstats_names, uint64_t *ids,
+	unsigned int size)
+{
+	/* Get all xstats */
+	if (!ids) {
+		struct rte_eth_dev *dev;
+		int cnt_used_entries;
+		int cnt_expected_entries;
+		int cnt_driver_entries;
+		uint32_t idx, id_queue;
+		uint16_t num_q;
+
+		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 = 0;
+
+		for (idx = 0; idx < RTE_NB_STATS; idx++) {
 			snprintf(xstats_names[cnt_used_entries].name,
 				sizeof(xstats_names[0].name),
-				"rx_q%u%s",
-				id_queue, rte_rxq_stats_strings[idx].name);
+				"%s", rte_stats_strings[idx].name);
 			cnt_used_entries++;
 		}
+		num_q = RTE_MIN(dev->data->nb_rx_queues,
+				RTE_ETHDEV_QUEUE_STAT_CNTRS);
+		for (id_queue = 0; id_queue < num_q; id_queue++) {
+			for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) {
+				snprintf(xstats_names[cnt_used_entries].name,
+					sizeof(xstats_names[0].name),
+					"rx_q%u%s",
+					id_queue,
+					rte_rxq_stats_strings[idx].name);
+				cnt_used_entries++;
+			}
+
+		}
+		num_q = RTE_MIN(dev->data->nb_tx_queues,
+				RTE_ETHDEV_QUEUE_STAT_CNTRS);
+		for (id_queue = 0; id_queue < num_q; id_queue++) {
+			for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) {
+				snprintf(xstats_names[cnt_used_entries].name,
+					sizeof(xstats_names[0].name),
+					"tx_q%u%s",
+					id_queue,
+					rte_txq_stats_strings[idx].name);
+				cnt_used_entries++;
+			}
+		}
 
+		if (dev->dev_ops->xstats_get_names_by_ids != NULL) {
+			/* If there are any driver-specific xstats, append them
+			 * to end of list.
+			 */
+			cnt_driver_entries =
+				(*dev->dev_ops->xstats_get_names_by_ids)(
+				dev,
+				xstats_names + cnt_used_entries,
+				NULL,
+				size - cnt_used_entries);
+			if (cnt_driver_entries < 0)
+				return cnt_driver_entries;
+			cnt_used_entries += cnt_driver_entries;
+
+		} else if (dev->dev_ops->xstats_get_names != NULL) {
+			/* If there are any driver-specific xstats, append them
+			 * to end of list.
+			 */
+			cnt_driver_entries = (*dev->dev_ops->xstats_get_names)(
+				dev,
+				xstats_names + cnt_used_entries,
+				size - cnt_used_entries);
+			if (cnt_driver_entries < 0)
+				return cnt_driver_entries;
+			cnt_used_entries += cnt_driver_entries;
+		}
+
+		return cnt_used_entries;
 	}
-	num_q = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
-	for (id_queue = 0; id_queue < num_q; id_queue++) {
-		for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) {
-			snprintf(xstats_names[cnt_used_entries].name,
-				sizeof(xstats_names[0].name),
-				"tx_q%u%s",
-				id_queue, rte_txq_stats_strings[idx].name);
-			cnt_used_entries++;
+	/* Get only xstats given by IDS */
+	else {
+		uint16_t len, i;
+		struct rte_eth_xstat_name *xstats_names_copy;
+
+		len = rte_eth_xstats_get_names_v1705(port_id, NULL, NULL, 0);
+
+		xstats_names_copy =
+				malloc(sizeof(struct rte_eth_xstat_name) * len);
+		if (!xstats_names_copy) {
+			RTE_PMD_DEBUG_TRACE(
+			     "ERROR: can't allocate memory for values_copy\n");
+			free(xstats_names_copy);
+			return -1;
+		}
+
+		rte_eth_xstats_get_names_v1705(port_id, xstats_names_copy,
+				NULL, len);
+
+		for (i = 0; i < size; i++) {
+			if (ids[i] >= len) {
+				RTE_PMD_DEBUG_TRACE(
+					"ERROR: id value isn't valid\n");
+				return -1;
+			}
+			strcpy(xstats_names[i].name,
+					xstats_names_copy[ids[i]].name);
 		}
+		free(xstats_names_copy);
+		return size;
 	}
+}
+MAP_STATIC_SYMBOL(int
+		rte_eth_xstats_get_names(uint8_t port_id,
+			struct rte_eth_xstat_name *xstats_names,
+			uint64_t *ids,
+			unsigned int size), rte_eth_xstats_get_names_v1705);
 
-	if (dev->dev_ops->xstats_get_names != NULL) {
-		/* If there are any driver-specific xstats, append them
-		 * to end of list.
-		 */
-		cnt_driver_entries = (*dev->dev_ops->xstats_get_names)(
-			dev,
-			xstats_names + cnt_used_entries,
-			size - cnt_used_entries);
-		if (cnt_driver_entries < 0)
-			return cnt_driver_entries;
-		cnt_used_entries += cnt_driver_entries;
+int
+rte_eth_xstats_get_names_v1702(uint8_t port_id,
+	struct rte_eth_xstat_name *xstats_names,
+	unsigned int size)
+{
+	return rte_eth_xstats_get_names(port_id, xstats_names, NULL, size);
+}
+VERSION_SYMBOL(rte_eth_xstats_get_names, _v1702, 17.02);
+
+/* retrieve ethdev extended statistics */
+int
+rte_eth_xstats_get_v1702(uint8_t port_id, struct rte_eth_xstat *xstats,
+	unsigned int n)
+{
+	uint64_t *values_copy;
+	uint16_t size, i;
+
+	values_copy = malloc(sizeof(values_copy) * n);
+	if (!values_copy) {
+		RTE_PMD_DEBUG_TRACE(
+				"ERROR: Cannot allocate memory for xstats\n");
+		return -1;
 	}
+	size = rte_eth_xstats_get(port_id, 0, values_copy, n);
 
-	return cnt_used_entries;
+	for (i = 0; i < n; i++) {
+		xstats[i].id = i;
+		xstats[i].value = values_copy[i];
+	}
+	free(values_copy);
+	return size;
 }
+VERSION_SYMBOL(rte_eth_xstats_get, _v1702, 17.02);
 
 /* retrieve ethdev extended statistics */
 int
-rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,
-	unsigned n)
+rte_eth_xstats_get_v1705(uint8_t port_id, uint64_t *ids, uint64_t *values,
+	unsigned int n)
 {
-	struct rte_eth_stats eth_stats;
-	struct rte_eth_dev *dev;
-	unsigned count = 0, i, q;
-	signed xcount = 0;
-	uint64_t val, *stats_ptr;
-	uint16_t nb_rxqs, nb_txqs;
+	/* If need all xstats */
+	if (!ids) {
+		struct rte_eth_stats eth_stats;
+		struct rte_eth_dev *dev;
+		unsigned int count = 0, i, q;
+		signed int xcount = 0;
+		uint64_t val, *stats_ptr;
+		uint16_t nb_rxqs, nb_txqs;
 
-	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+		RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+		dev = &rte_eth_devices[port_id];
 
-	dev = &rte_eth_devices[port_id];
+		nb_rxqs = RTE_MIN(dev->data->nb_rx_queues,
+				RTE_ETHDEV_QUEUE_STAT_CNTRS);
+		nb_txqs = RTE_MIN(dev->data->nb_tx_queues,
+				RTE_ETHDEV_QUEUE_STAT_CNTRS);
 
-	nb_rxqs = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
-	nb_txqs = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS);
+		/* Return generic statistics */
+		count = RTE_NB_STATS + (nb_rxqs * RTE_NB_RXQ_STATS) +
+			(nb_txqs * RTE_NB_TXQ_STATS);
 
-	/* Return generic statistics */
-	count = RTE_NB_STATS + (nb_rxqs * RTE_NB_RXQ_STATS) +
-		(nb_txqs * RTE_NB_TXQ_STATS);
 
-	/* implemented by the driver */
-	if (dev->dev_ops->xstats_get != NULL) {
-		/* Retrieve the xstats from the driver at the end of the
-		 * xstats struct.
-		 */
-		xcount = (*dev->dev_ops->xstats_get)(dev,
-				     xstats ? xstats + count : NULL,
-				     (n > count) ? n - count : 0);
+		/* implemented by the driver */
+		if (dev->dev_ops->xstats_get_by_ids != NULL) {
+			/* Retrieve the xstats from the driver at the end of the
+			 * xstats struct. Retrieve all xstats.
+			 */
+			xcount = (*dev->dev_ops->xstats_get_by_ids)(dev,
+					NULL,
+					values ? values + count : NULL,
+					(n > count) ? n - count : 0);
+
+			if (xcount < 0)
+				return xcount;
+		/* implemented by the driver */
+		} else if (dev->dev_ops->xstats_get != NULL) {
+			/* Retrieve the xstats from the driver at the end of the
+			 * xstats struct. Retrieve all xstats.
+			 * Compatibility for PMD without xstats_get_by_ids
+			 */
+			unsigned int size = (n > count) ? n - count : 1;
+			struct rte_eth_xstat xstats[size];
 
-		if (xcount < 0)
-			return xcount;
-	}
+			xcount = (*dev->dev_ops->xstats_get)(dev,
+					values ? xstats : NULL,	size);
 
-	if (n < count + xcount || xstats == NULL)
-		return count + xcount;
+			if (xcount < 0)
+				return xcount;
 
-	/* now fill the xstats structure */
-	count = 0;
-	rte_eth_stats_get(port_id, &eth_stats);
+			if (values != NULL)
+				for (i = 0 ; i < (unsigned int)xcount; i++)
+					values[i + count] = xstats[i].value;
+		}
 
-	/* global stats */
-	for (i = 0; i < RTE_NB_STATS; i++) {
-		stats_ptr = RTE_PTR_ADD(&eth_stats,
-					rte_stats_strings[i].offset);
-		val = *stats_ptr;
-		xstats[count++].value = val;
-	}
+		if (n < count + xcount || values == NULL)
+			return count + xcount;
 
-	/* per-rxq stats */
-	for (q = 0; q < nb_rxqs; q++) {
-		for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+		/* now fill the xstats structure */
+		count = 0;
+		rte_eth_stats_get(port_id, &eth_stats);
+
+		/* global stats */
+		for (i = 0; i < RTE_NB_STATS; i++) {
 			stats_ptr = RTE_PTR_ADD(&eth_stats,
-					rte_rxq_stats_strings[i].offset +
-					q * sizeof(uint64_t));
+						rte_stats_strings[i].offset);
 			val = *stats_ptr;
-			xstats[count++].value = val;
+			values[count++] = val;
 		}
+
+		/* per-rxq stats */
+		for (q = 0; q < nb_rxqs; q++) {
+			for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
+				stats_ptr = RTE_PTR_ADD(&eth_stats,
+					    rte_rxq_stats_strings[i].offset +
+					    q * sizeof(uint64_t));
+				val = *stats_ptr;
+				values[count++] = val;
+			}
+		}
+
+		/* per-txq stats */
+		for (q = 0; q < nb_txqs; q++) {
+			for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
+				stats_ptr = RTE_PTR_ADD(&eth_stats,
+					    rte_txq_stats_strings[i].offset +
+					    q * sizeof(uint64_t));
+				val = *stats_ptr;
+				values[count++] = val;
+			}
+		}
+
+		return count + xcount;
 	}
+	/* Need only xstats given by IDS array */
+	else {
+		uint16_t i, size;
+		uint64_t *values_copy;
 
-	/* per-txq stats */
-	for (q = 0; q < nb_txqs; q++) {
-		for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
-			stats_ptr = RTE_PTR_ADD(&eth_stats,
-					rte_txq_stats_strings[i].offset +
-					q * sizeof(uint64_t));
-			val = *stats_ptr;
-			xstats[count++].value = val;
+		size = rte_eth_xstats_get_v1705(port_id, NULL, NULL, 0);
+
+		values_copy = malloc(sizeof(values_copy) * size);
+		if (!values_copy) {
+			RTE_PMD_DEBUG_TRACE(
+			    "ERROR: can't allocate memory for values_copy\n");
+			return -1;
+		}
+
+		rte_eth_xstats_get_v1705(port_id, NULL, values_copy, size);
+
+		for (i = 0; i < n; i++) {
+			if (ids[i] >= size) {
+				RTE_PMD_DEBUG_TRACE(
+					"ERROR: id value isn't valid\n");
+				return -1;
+			}
+			values[i] = values_copy[ids[i]];
 		}
+		free(values_copy);
+		return n;
 	}
+}
+MAP_STATIC_SYMBOL(int
+		rte_eth_xstats_get(uint8_t port_id, uint64_t *ids,
+		uint64_t *values, unsigned int n), rte_eth_xstats_get_v1705);
+
+__rte_deprecated int
+rte_eth_xstats_get_all(uint8_t port_id, struct rte_eth_xstat *xstats,
+	unsigned int n)
+{
+	uint64_t *values_copy;
+	uint16_t size, i;
 
-	for (i = 0; i < count; i++)
+	values_copy = malloc(sizeof(values_copy) * n);
+	if (!values_copy) {
+		RTE_PMD_DEBUG_TRACE(
+				"ERROR: Cannot allocate memory for xstats\n");
+		return -1;
+	}
+	size = rte_eth_xstats_get(port_id, 0, values_copy, n);
+
+	for (i = 0; i < n; i++) {
 		xstats[i].id = i;
-	/* add an offset to driver-specific stats */
-	for ( ; i < count + xcount; i++)
-		xstats[i].id += count;
+		xstats[i].value = values_copy[i];
+	}
+	free(values_copy);
+	return size;
+}
 
-	return count + xcount;
+__rte_deprecated int
+rte_eth_xstats_get_names_all(uint8_t port_id,
+		struct rte_eth_xstat_name *xstats_names, unsigned int n)
+{
+	return rte_eth_xstats_get_names(port_id, xstats_names, NULL, n);
 }
 
 /* reset ethdev extended statistics */
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index b3ee872..91c9af6 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -186,6 +186,7 @@ 
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
 #include "rte_dev_info.h"
+#include "rte_compat.h"
 
 struct rte_mbuf;
 
@@ -1118,6 +1119,10 @@  typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+typedef int (*eth_xstats_get_by_ids_t)(struct rte_eth_dev *dev,
+		uint64_t *ids, uint64_t *values, unsigned int 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. */
 
@@ -1125,6 +1130,17 @@  typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+typedef int (*eth_xstats_get_names_by_ids_t)(struct rte_eth_dev *dev,
+	struct rte_eth_xstat_name *xstats_names, uint64_t *ids,
+	unsigned int size);
+/**< @internal Get names of extended stats of an Ethernet device. */
+
+typedef int (*eth_xstats_get_by_name_t)(struct rte_eth_dev *dev,
+		struct rte_eth_xstat_name *xstats_names,
+		struct rte_eth_xstat *xstat,
+		const char *name);
+/**< @internal Get xstat specified by name 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,
@@ -1459,9 +1475,15 @@  struct eth_dev_ops {
 	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_get_by_ids_t    xstats_get_by_ids;
+	/**< Get extended device statistics by ID. */
 	eth_xstats_reset_t         xstats_reset;  /**< Reset extended device statistics. */
-	eth_xstats_get_names_t     xstats_get_names;
-	/**< Get names of extended statistics. */
+	eth_xstats_get_names_t	   xstats_get_names;
+	/**< Get names of extended device statistics. */
+	eth_xstats_get_names_by_ids_t xstats_get_names_by_ids;
+	/**< Get name of extended device statistics by ID. */
+	eth_xstats_get_by_name_t   xstats_get_by_name;
+	/**< Get extended device statistics by name. */
 	eth_queue_stats_mapping_set_t queue_stats_mapping_set;
 	/**< Configure per queue stat counter mapping. */
 
@@ -2287,8 +2309,57 @@  int rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
  */
 void rte_eth_stats_reset(uint8_t port_id);
 
+
 /**
- * Retrieve names of extended statistics of an Ethernet device.
+* Gets the ID of a statistic from its name.
+*
+* Note this function searches for the statistics using string compares, and
+* as such should not be used on the fast-path. For fast-path retrieval of
+* specific statistics, store the ID as provided in *id* from this function,
+* and pass the ID to rte_eth_xstats_get()
+*
+* @param port_id The port to look up statistics from
+* @param xstat_name The name of the statistic to return
+* @param[out] id A pointer to an app-supplied uint64_t which should be
+*                set to the ID of the stat if the stat exists.
+* @return
+*    0 on success
+*    -ENODEV for invalid port_id,
+*    -EINVAL if the xstat_name doesn't exist in port_id
+*/
+int rte_eth_xstats_get_id_by_name(uint8_t port_id, const char *xstat_name,
+		uint64_t *id);
+
+/**
+ * Retrieve all extended statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param xstats
+ *   A pointer to a table of structure of type *rte_eth_xstat*
+ *   to be filled with device statistics ids and values: id is the
+ *   index of the name string in xstats_names (see rte_eth_xstats_get_names()),
+ *   and value is the statistic counter.
+ *   This parameter can be set to NULL if n is 0.
+ * @param n
+ *   The size of the xstats array (number of elements).
+ * @return
+ *   - A positive value lower or equal to n: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - A positive value higher than n: error, the given statistics table
+ *     is too small. The return 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.
+ *   - A negative value on error (invalid port id).
+ */
+__rte_deprecated
+int rte_eth_xstats_get_all(uint8_t port_id, struct rte_eth_xstat *xstats,
+	unsigned int n);
+BIND_DEFAULT_SYMBOL(rte_eth_xstats_get_all, _v1705, 17.05);
+
+
+/**
+ * Retrieve names of all extended statistics of an Ethernet device.
  *
  * @param port_id
  *   The port identifier of the Ethernet device.
@@ -2296,7 +2367,7 @@  int rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
  *   An rte_eth_xstat_name array of at least *size* elements to
  *   be filled. If set to NULL, the function returns the required number
  *   of elements.
- * @param size
+ * @param n
  *   The size of the xstats_names array (number of elements).
  * @return
  *   - A positive value lower or equal to size: success. The return value
@@ -2307,9 +2378,10 @@  int rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
  *     shall not be used by the caller.
  *   - A negative value on error (invalid port id).
  */
-int rte_eth_xstats_get_names(uint8_t port_id,
-		struct rte_eth_xstat_name *xstats_names,
-		unsigned size);
+__rte_deprecated int rte_eth_xstats_get_names_all(uint8_t port_id,
+		struct rte_eth_xstat_name *xstats_names, unsigned int n);
+BIND_DEFAULT_SYMBOL(rte_eth_xstats_get_names_all, _v1705, 17.05);
+
 
 /**
  * Retrieve extended statistics of an Ethernet device.
@@ -2333,8 +2405,94 @@  int rte_eth_xstats_get_names(uint8_t port_id,
  *     shall not be used by the caller.
  *   - A negative value on error (invalid port id).
  */
-int rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstat *xstats,
-		unsigned n);
+int rte_eth_xstats_get_v1702(uint8_t port_id, struct rte_eth_xstat *xstats,
+	unsigned int n);
+
+/**
+ * Retrieve extended statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ids
+ *   A pointer to an ids array passed by application. This tells wich
+ *   statistics values function should retrieve. This parameter
+ *   can be set to NULL if n is 0. In this case function will retrieve
+ *   all avalible statistics.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ * @param n
+ *   The size of the ids array (number of elements).
+ * @return
+ *   - A positive value lower or equal to n: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - A positive value higher than n: error, the given statistics table
+ *     is too small. The return 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.
+ *   - A negative value on error (invalid port id).
+ */
+int rte_eth_xstats_get_v1705(uint8_t port_id, uint64_t *ids, uint64_t *values,
+	unsigned int n);
+
+int rte_eth_xstats_get(uint8_t port_id, uint64_t *ids, uint64_t *values,
+	unsigned int n);
+BIND_DEFAULT_SYMBOL(rte_eth_xstats_get, _v1705, 17.05);
+
+/**
+ * Retrieve extended statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param xstats_names
+ *   A pointer to a table of structure of type *rte_eth_xstat*
+ *   to be filled with device statistics ids and values: id is the
+ *   index of the name string in xstats_names (see rte_eth_xstats_get_names()),
+ *   and value is the statistic counter.
+ *   This parameter can be set to NULL if n is 0.
+ * @param n
+ *   The size of the xstats array (number of elements).
+ * @return
+ *   - A positive value lower or equal to n: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - A positive value higher than n: error, the given statistics table
+ *     is too small. The return 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.
+ *   - A negative value on error (invalid port id).
+ */
+int rte_eth_xstats_get_names_v1702(uint8_t port_id,
+		struct rte_eth_xstat_name *xstats_names, unsigned int n);
+
+/**
+ * Retrieve names of extended statistics of an Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. If set to NULL, the function returns the required number
+ *   of elements.
+ * @param ids
+ *   IDs array given by app to retrieve specific statistics
+ * @param size
+ *   The size of the xstats_names array (number of elements).
+ * @return
+ *   - A positive value lower or equal to size: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - A positive value higher than size: error, the given statistics table
+ *     is too small. The return 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.
+ *   - A negative value on error (invalid port id).
+ */
+int rte_eth_xstats_get_names_v1705(uint8_t port_id,
+	struct rte_eth_xstat_name *xstats_names, uint64_t *ids,
+	unsigned int size);
+
+int rte_eth_xstats_get_names(uint8_t port_id,
+	struct rte_eth_xstat_name *xstats_names, uint64_t *ids,
+	unsigned int size);
+BIND_DEFAULT_SYMBOL(rte_eth_xstats_get_names, _v1705, 17.05);
 
 /**
  * Reset extended statistics of an Ethernet device.
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index c6c9d0d..8a1a330 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -154,3 +154,15 @@  DPDK_17.02 {
 	rte_flow_validate;
 
 } DPDK_16.11;
+
+DPDK_17.05 {
+	global:
+
+	rte_eth_xstats_get_names;
+	rte_eth_xstats_get;
+	rte_eth_xstats_get_all;
+	rte_eth_xstats_get_names_all;
+	rte_eth_xstats_get_id_by_name;
+
+} DPDK_17.02;
+