DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [RFC PATCH] ethdev: fix ports enumeration
@ 2018-03-09 22:22 Thomas Monjalon
  2018-04-05 15:33 ` [dpdk-dev] [PATCH v2 0/3] " Thomas Monjalon
  0 siblings, 1 reply; 6+ messages in thread
From: Thomas Monjalon @ 2018-03-09 22:22 UTC (permalink / raw)
  To: dev

Some DPDK applications wrongly assume these requirements:
    - no hotplug, i.e. ports are never detached
    - all allocated ports are available to the application

Such application iterates over ports by its own mean.
The most common pattern is to request the port count and
assume ports with index in the range [0..count[ can be used.

There are three consequences when using such wrong design:
    - new ports having an index higher than the port count won't be seen
    - old ports being detached (RTE_ETH_DEV_UNUSED) can be seen as ghosts
    - failsafe sub-devices (RTE_ETH_DEV_DEFERRED) will be seen by the application

Such mistake will be less common with growing hotplug awareness.
All applications and examples inside this repository - except testpmd -
must be fixed to use the iterator RTE_ETH_FOREACH_DEV.

In order to fix this common mistake in all external applications,
the function rte_eth_dev_count is deprecated and replaced by
the new functions rte_eth_dev_count_avail and rte_eth_dev_count_total.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>

---

This RFC fixes only procinfo and skeleton example.
Next version of this patch should fix all occurences.

This RFC gather all ideas in one patch, but next version
will be more detailed and split.
---
 app/proc_info/main.c                    |  2 +-
 examples/skeleton/Makefile              |  3 +++
 examples/skeleton/basicfwd.c            | 12 ++++--------
 lib/librte_ether/rte_ethdev.c           | 18 ++++++++++++++++++
 lib/librte_ether/rte_ethdev.h           | 23 +++++++++++++++++++++++
 lib/librte_ether/rte_ethdev_version.map |  4 +++-
 6 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/app/proc_info/main.c b/app/proc_info/main.c
index 2f53e3caa..d508db957 100644
--- a/app/proc_info/main.c
+++ b/app/proc_info/main.c
@@ -636,7 +636,7 @@ main(int argc, char **argv)
 	if (enabled_port_mask == 0)
 		enabled_port_mask = 0xffff;
 
-	for (i = 0; i < nb_ports; i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		if (enabled_port_mask & (1 << i)) {
 			if (enable_stats)
 				nic_stats_display(i);
diff --git a/examples/skeleton/Makefile b/examples/skeleton/Makefile
index bd980ec9b..a4a1860cb 100644
--- a/examples/skeleton/Makefile
+++ b/examples/skeleton/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS)
 
 # workaround for a gcc bug with noreturn attribute
diff --git a/examples/skeleton/basicfwd.c b/examples/skeleton/basicfwd.c
index e62cc0a59..1c1eb08ef 100644
--- a/examples/skeleton/basicfwd.c
+++ b/examples/skeleton/basicfwd.c
@@ -42,9 +42,6 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_txconf txconf;
 
-	if (port >= rte_eth_dev_count())
-		return -1;
-
 	rte_eth_dev_info_get(port, &dev_info);
 	if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
 		port_conf.txmode.offloads |=
@@ -106,14 +103,13 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 static __attribute__((noreturn)) void
 lcore_main(void)
 {
-	const uint16_t nb_ports = rte_eth_dev_count();
 	uint16_t port;
 
 	/*
 	 * Check that the port is on the same NUMA node as the polling thread
 	 * for best performance.
 	 */
-	for (port = 0; port < nb_ports; port++)
+	RTE_ETH_FOREACH_DEV(port)
 		if (rte_eth_dev_socket_id(port) > 0 &&
 				rte_eth_dev_socket_id(port) !=
 						(int)rte_socket_id())
@@ -130,7 +126,7 @@ lcore_main(void)
 		 * Receive packets on a port and forward them on the paired
 		 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
 		 */
-		for (port = 0; port < nb_ports; port++) {
+		RTE_ETH_FOREACH_DEV(port) {
 
 			/* Get burst of RX packets, from first port of pair. */
 			struct rte_mbuf *bufs[BURST_SIZE];
@@ -174,7 +170,7 @@ main(int argc, char *argv[])
 	argv += ret;
 
 	/* Check that there is an even number of ports to send/receive on. */
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports < 2 || (nb_ports & 1))
 		rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
 
@@ -186,7 +182,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* Initialize all ports. */
-	for (portid = 0; portid < nb_ports; portid++)
+	RTE_ETH_FOREACH_DEV(portid)
 		if (port_init(portid, mbuf_pool) != 0)
 			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n",
 					portid);
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 0590f0c10..583427559 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -529,6 +529,12 @@ rte_eth_dev_get_sec_ctx(uint8_t port_id)
 
 uint16_t
 rte_eth_dev_count(void)
+{
+	return rte_eth_dev_count_avail();
+}
+
+uint16_t
+rte_eth_dev_count_avail(void)
 {
 	uint16_t p;
 	uint16_t count;
@@ -541,6 +547,18 @@ rte_eth_dev_count(void)
 	return count;
 }
 
+uint16_t
+rte_eth_dev_count_total(void)
+{
+	uint16_t port, count = 0;
+
+	for (port = 0; port < RTE_MAX_ETHPORTS; port++)
+		if (rte_eth_devices[port].state != RTE_ETH_DEV_UNUSED)
+			count++;
+
+	return count;
+}
+
 int
 rte_eth_dev_get_name_by_port(uint16_t port_id, char *name)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 036153306..cba37fe34 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1362,8 +1362,31 @@ int __rte_experimental rte_eth_dev_owner_get(const uint16_t port_id,
  * @return
  *   - The total number of usable Ethernet devices.
  */
+__rte_deprecated
 uint16_t rte_eth_dev_count(void);
 
+/**
+ * Get the number of ports which are usable for the application.
+ *
+ * These devices must be iterated by using the macro
+ * ``RTE_ETH_FOREACH_DEV`` or ``RTE_ETH_FOREACH_DEV_OWNED_BY``
+ * to deal with non-contiguous ranges of devices.
+ *
+ * @return
+ *   The count of available Ethernet devices.
+ */
+uint16_t __rte_experimental rte_eth_dev_count_avail(void);
+
+/**
+ * Get the total number of ports which are allocated.
+ *
+ * Some devices may not be available for the application.
+ *
+ * @return
+ *   The total count of Ethernet devices.
+ */
+uint16_t __rte_experimental rte_eth_dev_count_total(void);
+
 /**
  * Attach a new Ethernet device specified by arguments.
  *
diff --git a/lib/librte_ether/rte_ethdev_version.map b/lib/librte_ether/rte_ethdev_version.map
index 87f02fb74..c9a18ab5a 100644
--- a/lib/librte_ether/rte_ethdev_version.map
+++ b/lib/librte_ether/rte_ethdev_version.map
@@ -207,6 +207,8 @@ DPDK_18.02 {
 EXPERIMENTAL {
 	global:
 
+	rte_eth_dev_count_avail;
+	rte_eth_dev_count_total;
 	rte_eth_dev_is_removed;
 	rte_eth_dev_owner_delete;
 	rte_eth_dev_owner_get;
@@ -229,4 +231,4 @@ EXPERIMENTAL {
 	rte_mtr_stats_read;
 	rte_mtr_stats_update;
 
-} DPDK_17.11;
+} DPDK_18.02;
-- 
2.16.2

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dpdk-dev] [PATCH v2 0/3] ethdev: fix ports enumeration
  2018-03-09 22:22 [dpdk-dev] [RFC PATCH] ethdev: fix ports enumeration Thomas Monjalon
@ 2018-04-05 15:33 ` Thomas Monjalon
  2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 1/3] fix ethdev " Thomas Monjalon
                     ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Thomas Monjalon @ 2018-04-05 15:33 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit

Some DPDK applications wrongly assume these requirements:
  - no hotplug, i.e. ports are never detached
  - all allocated ports are available to the application

Such application iterates over ports by its own mean.
The most common pattern is to request the port count and
assume ports with index in the range [0..count[ can be used.

There are three consequences when using such wrong design:
  - new ports having an index higher than the port count won't be seen
  - old ports being detached (RTE_ETH_DEV_UNUSED) can be seen as ghosts
  - failsafe sub-devices (RTE_ETH_DEV_DEFERRED) will be seen by the application

Such mistake will be less common with growing hotplug awareness.
All applications and examples inside this repository - except testpmd -
must be fixed to use the iterator RTE_ETH_FOREACH_DEV,
and to use the function rte_eth_dev_is_valid_port.

In order to fix this common mistake in all external applications,
the function rte_eth_dev_count is deprecated, while introducing
the new functions rte_eth_dev_count_avail and rte_eth_dev_count_total.

-- 
The RFC was sent one month ago with only couple of apps updated.
V2 does the same change with all apps updated.


Thomas Monjalon (3):
  fix ethdev ports enumeration
  fix ethdev port id validation
  ethdev: deprecate port count function

 app/pdump/main.c                                   |  3 +-
 app/proc-info/main.c                               |  4 +-
 app/test-eventdev/test_perf_atq.c                  |  2 +-
 app/test-eventdev/test_perf_common.c               | 12 ++---
 app/test-eventdev/test_perf_queue.c                |  2 +-
 app/test-eventdev/test_pipeline_atq.c              |  4 +-
 app/test-eventdev/test_pipeline_common.c           | 16 +++---
 app/test-eventdev/test_pipeline_queue.c            |  6 +--
 app/test-pmd/cmdline.c                             | 57 ++--------------------
 app/test-pmd/testpmd.c                             | 13 ++---
 doc/guides/rel_notes/release_18_05.rst             |  7 +++
 doc/guides/sample_app_ug/flow_classify.rst         | 14 ++----
 doc/guides/sample_app_ug/kernel_nic_interface.rst  | 10 ----
 doc/guides/sample_app_ug/l2_forward_job_stats.rst  |  7 +--
 .../sample_app_ug/l2_forward_real_virtual.rst      |  7 +--
 doc/guides/sample_app_ug/link_status_intr.rst      |  6 +--
 doc/guides/sample_app_ug/quota_watermark.rst       |  2 +-
 doc/guides/sample_app_ug/rxtx_callbacks.rst        |  3 --
 doc/guides/sample_app_ug/skeleton.rst              | 11 ++---
 drivers/net/bonding/Makefile                       |  1 +
 drivers/net/bonding/meson.build                    |  2 +
 drivers/net/bonding/rte_eth_bond_args.c            |  4 +-
 drivers/net/mvpp2/mrvl_ethdev.c                    |  2 +-
 examples/bbdev_app/main.c                          | 10 ++--
 examples/bond/Makefile                             |  3 ++
 examples/bond/main.c                               |  8 +--
 examples/bond/meson.build                          |  1 +
 examples/distributor/Makefile                      |  3 ++
 examples/distributor/main.c                        | 29 ++++++-----
 examples/distributor/meson.build                   |  1 +
 examples/ethtool/ethtool-app/Makefile              |  1 +
 examples/ethtool/ethtool-app/ethapp.c              | 10 ++--
 examples/ethtool/ethtool-app/main.c                |  2 +-
 examples/eventdev_pipeline/main.c                  | 25 +++++-----
 .../eventdev_pipeline/pipeline_worker_generic.c    |  7 ++-
 examples/eventdev_pipeline/pipeline_worker_tx.c    |  6 +--
 examples/exception_path/Makefile                   |  3 ++
 examples/exception_path/main.c                     | 10 ++--
 examples/exception_path/meson.build                |  1 +
 examples/flow_classify/flow_classify.c             | 17 +++----
 examples/flow_filtering/Makefile                   |  3 ++
 examples/flow_filtering/main.c                     |  4 +-
 examples/flow_filtering/meson.build                |  1 +
 examples/ip_fragmentation/Makefile                 |  3 ++
 examples/ip_fragmentation/main.c                   | 14 +++---
 examples/ip_fragmentation/meson.build              |  1 +
 examples/ip_pipeline/init.c                        |  4 +-
 examples/ip_reassembly/Makefile                    |  3 ++
 examples/ip_reassembly/main.c                      | 12 ++---
 examples/ip_reassembly/meson.build                 |  1 +
 examples/ipsec-secgw/ipsec-secgw.c                 | 24 ++++-----
 examples/ipv4_multicast/Makefile                   |  3 ++
 examples/ipv4_multicast/main.c                     | 10 ++--
 examples/ipv4_multicast/meson.build                |  1 +
 examples/kni/Makefile                              |  3 ++
 examples/kni/main.c                                | 24 ++++-----
 examples/kni/meson.build                           |  1 +
 examples/l2fwd-cat/Makefile                        |  2 +
 examples/l2fwd-cat/l2fwd-cat.c                     | 11 ++---
 examples/l2fwd-cat/meson.build                     |  1 +
 examples/l2fwd-crypto/Makefile                     |  3 ++
 examples/l2fwd-crypto/main.c                       | 22 ++++-----
 examples/l2fwd-crypto/meson.build                  |  1 +
 examples/l2fwd-jobstats/Makefile                   |  4 +-
 examples/l2fwd-jobstats/main.c                     | 21 ++++----
 examples/l2fwd-jobstats/meson.build                |  1 +
 examples/l2fwd-keepalive/Makefile                  |  3 ++
 examples/l2fwd-keepalive/main.c                    | 21 ++++----
 examples/l2fwd-keepalive/meson.build               |  1 +
 examples/l2fwd/Makefile                            |  3 ++
 examples/l2fwd/main.c                              | 23 +++++----
 examples/l2fwd/meson.build                         |  1 +
 examples/l3fwd-acl/Makefile                        |  3 ++
 examples/l3fwd-acl/main.c                          | 18 +++----
 examples/l3fwd-acl/meson.build                     |  1 +
 examples/l3fwd-power/Makefile                      |  3 ++
 examples/l3fwd-power/main.c                        | 23 +++++----
 examples/l3fwd-power/meson.build                   |  1 +
 examples/l3fwd-vf/Makefile                         |  3 ++
 examples/l3fwd-vf/main.c                           | 15 +++---
 examples/l3fwd-vf/meson.build                      |  1 +
 examples/l3fwd/Makefile                            |  3 ++
 examples/l3fwd/main.c                              | 20 ++++----
 examples/l3fwd/meson.build                         |  1 +
 examples/link_status_interrupt/Makefile            |  3 ++
 examples/link_status_interrupt/main.c              |  2 +-
 examples/link_status_interrupt/meson.build         |  1 +
 .../client_server_mp/mp_client/Makefile            |  1 +
 .../client_server_mp/mp_client/client.c            |  2 +-
 .../client_server_mp/mp_server/Makefile            |  1 +
 .../client_server_mp/mp_server/init.c              |  2 +-
 examples/multi_process/l2fwd_fork/Makefile         |  1 +
 examples/multi_process/l2fwd_fork/main.c           | 24 +++++----
 examples/multi_process/symmetric_mp/Makefile       |  1 +
 examples/multi_process/symmetric_mp/main.c         |  8 +--
 examples/netmap_compat/bridge/Makefile             |  1 +
 examples/netmap_compat/bridge/bridge.c             |  2 +-
 examples/packet_ordering/Makefile                  |  3 ++
 examples/packet_ordering/main.c                    | 27 +++++-----
 examples/packet_ordering/meson.build               |  1 +
 examples/performance-thread/l3fwd-thread/Makefile  |  1 +
 examples/performance-thread/l3fwd-thread/main.c    | 18 +++----
 examples/ptpclient/Makefile                        |  3 ++
 examples/ptpclient/meson.build                     |  1 +
 examples/ptpclient/ptpclient.c                     |  6 +--
 examples/qos_sched/Makefile                        |  3 ++
 examples/qos_sched/init.c                          |  2 +-
 examples/qos_sched/meson.build                     |  1 +
 examples/quota_watermark/qw/Makefile               |  1 +
 examples/quota_watermark/qw/init.c                 |  2 +-
 examples/rxtx_callbacks/Makefile                   |  3 ++
 examples/rxtx_callbacks/main.c                     | 13 +++--
 examples/rxtx_callbacks/meson.build                |  1 +
 examples/server_node_efd/node/Makefile             |  1 +
 examples/server_node_efd/node/node.c               |  2 +-
 examples/server_node_efd/server/Makefile           |  1 +
 examples/server_node_efd/server/init.c             |  2 +-
 examples/skeleton/Makefile                         |  3 ++
 examples/skeleton/basicfwd.c                       | 11 ++---
 examples/skeleton/meson.build                      |  3 ++
 examples/tep_termination/Makefile                  |  3 ++
 examples/tep_termination/main.c                    | 11 ++---
 examples/tep_termination/meson.build               |  1 +
 examples/tep_termination/vxlan_setup.c             |  2 +-
 examples/vhost/Makefile                            |  3 ++
 examples/vhost/main.c                              | 14 +++---
 examples/vhost/meson.build                         |  1 +
 examples/vm_power_manager/Makefile                 |  1 +
 examples/vm_power_manager/channel_monitor.c        |  5 +-
 examples/vm_power_manager/main.c                   | 12 ++---
 examples/vmdq/Makefile                             |  3 ++
 examples/vmdq/main.c                               | 12 ++---
 examples/vmdq/meson.build                          |  1 +
 examples/vmdq_dcb/Makefile                         |  3 ++
 examples/vmdq_dcb/main.c                           | 12 ++---
 examples/vmdq_dcb/meson.build                      |  1 +
 lib/librte_ether/rte_ethdev.c                      | 25 ++++++++--
 lib/librte_ether/rte_ethdev.h                      | 23 +++++++++
 lib/librte_ether/rte_ethdev_version.map            |  4 +-
 lib/librte_eventdev/rte_event_eth_rx_adapter.c     | 13 ++---
 lib/librte_kni/rte_kni.c                           |  4 +-
 lib/librte_latencystats/Makefile                   |  1 +
 lib/librte_latencystats/meson.build                |  1 +
 lib/librte_latencystats/rte_latencystats.c         |  6 +--
 test/test/test_event_eth_rx_adapter.c              | 10 ++--
 test/test/test_kni.c                               |  2 +-
 test/test/test_link_bonding_mode4.c                |  2 +-
 test/test/test_link_bonding_rssconf.c              |  2 +-
 test/test/test_pmd_perf.c                          |  6 +--
 test/test/test_pmd_ring.c                          |  4 +-
 150 files changed, 530 insertions(+), 470 deletions(-)

-- 
2.16.2

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dpdk-dev] [PATCH v2 1/3] fix ethdev ports enumeration
  2018-04-05 15:33 ` [dpdk-dev] [PATCH v2 0/3] " Thomas Monjalon
@ 2018-04-05 15:33   ` Thomas Monjalon
  2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 2/3] fix ethdev port id validation Thomas Monjalon
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Thomas Monjalon @ 2018-04-05 15:33 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit

Some DPDK applications wrongly assume these requirements:
    - no hotplug, i.e. ports are never detached
    - all allocated ports are available to the application

Such application iterates over ports by its own mean.
The most common pattern is to request the port count and
assume ports with index in the range [0..count[ can be used.

There are three consequences when using such wrong design:
    - new ports having an index higher than the port count won't be seen
    - old ports being detached (RTE_ETH_DEV_UNUSED) can be seen as ghosts
    - failsafe sub-devices (RTE_ETH_DEV_DEFERRED) will be seen by the application

Such mistake will be less common with growing hotplug awareness.
All applications and examples inside this repository - except testpmd -
must be fixed to use the iterator RTE_ETH_FOREACH_DEV.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 app/proc-info/main.c                               |  2 +-
 app/test-eventdev/test_perf_common.c               | 10 +++++-----
 app/test-eventdev/test_pipeline_common.c           | 10 +++++-----
 app/test-pmd/cmdline.c                             |  4 ++--
 app/test-pmd/testpmd.c                             |  7 ++-----
 doc/guides/sample_app_ug/flow_classify.rst         | 11 +++++------
 doc/guides/sample_app_ug/l2_forward_job_stats.rst  |  2 +-
 .../sample_app_ug/l2_forward_real_virtual.rst      |  2 +-
 doc/guides/sample_app_ug/link_status_intr.rst      |  2 +-
 doc/guides/sample_app_ug/skeleton.rst              |  8 ++++----
 drivers/net/bonding/Makefile                       |  1 +
 drivers/net/bonding/meson.build                    |  2 ++
 drivers/net/bonding/rte_eth_bond_args.c            |  4 ++--
 drivers/net/mvpp2/mrvl_ethdev.c                    |  2 +-
 examples/bond/Makefile                             |  3 +++
 examples/bond/main.c                               |  4 ++--
 examples/bond/meson.build                          |  1 +
 examples/distributor/Makefile                      |  3 +++
 examples/distributor/main.c                        | 21 ++++++++++-----------
 examples/distributor/meson.build                   |  1 +
 examples/ethtool/ethtool-app/Makefile              |  1 +
 examples/ethtool/ethtool-app/ethapp.c              | 10 +++++-----
 examples/eventdev_pipeline/main.c                  | 19 +++++++++----------
 .../eventdev_pipeline/pipeline_worker_generic.c    |  7 +++----
 examples/eventdev_pipeline/pipeline_worker_tx.c    |  2 +-
 examples/exception_path/Makefile                   |  3 +++
 examples/exception_path/main.c                     |  8 ++++----
 examples/exception_path/meson.build                |  1 +
 examples/flow_classify/flow_classify.c             | 11 +++++------
 examples/ip_fragmentation/Makefile                 |  3 +++
 examples/ip_fragmentation/main.c                   | 10 +++++-----
 examples/ip_fragmentation/meson.build              |  1 +
 examples/ip_reassembly/Makefile                    |  3 +++
 examples/ip_reassembly/main.c                      | 10 +++++-----
 examples/ip_reassembly/meson.build                 |  1 +
 examples/ipsec-secgw/ipsec-secgw.c                 | 18 ++++++++----------
 examples/ipv4_multicast/Makefile                   |  3 +++
 examples/ipv4_multicast/main.c                     |  8 ++++----
 examples/ipv4_multicast/meson.build                |  1 +
 examples/kni/Makefile                              |  3 +++
 examples/kni/main.c                                | 14 +++++++-------
 examples/kni/meson.build                           |  1 +
 examples/l2fwd-cat/Makefile                        |  2 ++
 examples/l2fwd-cat/l2fwd-cat.c                     |  7 +++----
 examples/l2fwd-cat/meson.build                     |  1 +
 examples/l2fwd-crypto/Makefile                     |  3 +++
 examples/l2fwd-crypto/main.c                       | 20 +++++++++-----------
 examples/l2fwd-crypto/meson.build                  |  1 +
 examples/l2fwd-jobstats/Makefile                   |  4 +++-
 examples/l2fwd-jobstats/main.c                     | 19 +++++++++----------
 examples/l2fwd-jobstats/meson.build                |  1 +
 examples/l2fwd-keepalive/Makefile                  |  3 +++
 examples/l2fwd-keepalive/main.c                    | 19 +++++++++----------
 examples/l2fwd-keepalive/meson.build               |  1 +
 examples/l2fwd/Makefile                            |  3 +++
 examples/l2fwd/main.c                              | 21 ++++++++++-----------
 examples/l2fwd/meson.build                         |  1 +
 examples/l3fwd-acl/Makefile                        |  3 +++
 examples/l3fwd-acl/main.c                          | 10 +++++-----
 examples/l3fwd-acl/meson.build                     |  1 +
 examples/l3fwd-power/Makefile                      |  3 +++
 examples/l3fwd-power/main.c                        | 15 +++++++--------
 examples/l3fwd-power/meson.build                   |  1 +
 examples/l3fwd-vf/Makefile                         |  3 +++
 examples/l3fwd-vf/main.c                           |  7 +++----
 examples/l3fwd-vf/meson.build                      |  1 +
 examples/l3fwd/Makefile                            |  3 +++
 examples/l3fwd/main.c                              | 12 ++++++------
 examples/l3fwd/meson.build                         |  1 +
 examples/multi_process/l2fwd_fork/Makefile         |  1 +
 examples/multi_process/l2fwd_fork/main.c           | 22 ++++++++++------------
 examples/multi_process/symmetric_mp/Makefile       |  1 +
 examples/multi_process/symmetric_mp/main.c         |  4 ++--
 examples/packet_ordering/Makefile                  |  3 +++
 examples/packet_ordering/main.c                    | 20 ++++++++------------
 examples/packet_ordering/meson.build               |  1 +
 examples/performance-thread/l3fwd-thread/Makefile  |  1 +
 examples/performance-thread/l3fwd-thread/main.c    | 10 +++++-----
 examples/ptpclient/Makefile                        |  3 +++
 examples/ptpclient/meson.build                     |  1 +
 examples/ptpclient/ptpclient.c                     |  2 +-
 examples/rxtx_callbacks/Makefile                   |  3 +++
 examples/rxtx_callbacks/main.c                     |  9 ++++-----
 examples/rxtx_callbacks/meson.build                |  1 +
 examples/skeleton/Makefile                         |  3 +++
 examples/skeleton/basicfwd.c                       |  7 +++----
 examples/skeleton/meson.build                      |  1 +
 examples/tep_termination/Makefile                  |  3 +++
 examples/tep_termination/main.c                    |  2 +-
 examples/tep_termination/meson.build               |  1 +
 examples/vhost/Makefile                            |  3 +++
 examples/vhost/main.c                              |  2 +-
 examples/vhost/meson.build                         |  1 +
 examples/vm_power_manager/Makefile                 |  1 +
 examples/vm_power_manager/channel_monitor.c        |  5 ++---
 examples/vm_power_manager/main.c                   |  8 ++++----
 examples/vmdq/Makefile                             |  3 +++
 examples/vmdq/main.c                               |  2 +-
 examples/vmdq/meson.build                          |  1 +
 examples/vmdq_dcb/Makefile                         |  3 +++
 examples/vmdq_dcb/main.c                           |  2 +-
 examples/vmdq_dcb/meson.build                      |  1 +
 lib/librte_eventdev/rte_event_eth_rx_adapter.c     | 10 +++++-----
 lib/librte_latencystats/Makefile                   |  1 +
 lib/librte_latencystats/meson.build                |  1 +
 lib/librte_latencystats/rte_latencystats.c         |  6 ++----
 test/test/test_event_eth_rx_adapter.c              |  4 ++--
 test/test/test_pmd_perf.c                          |  4 ++--
 test/test/test_pmd_ring.c                          |  2 +-
 109 files changed, 319 insertions(+), 244 deletions(-)

diff --git a/app/proc-info/main.c b/app/proc-info/main.c
index f90c14498..115df9d96 100644
--- a/app/proc-info/main.c
+++ b/app/proc-info/main.c
@@ -636,7 +636,7 @@ main(int argc, char **argv)
 	if (enabled_port_mask == 0)
 		enabled_port_mask = 0xffff;
 
-	for (i = 0; i < nb_ports; i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		if (enabled_port_mask & (1 << i)) {
 			if (enable_stats)
 				nic_stats_display(i);
diff --git a/app/test-eventdev/test_perf_common.c b/app/test-eventdev/test_perf_common.c
index 59fa0a49e..488cf0724 100644
--- a/app/test-eventdev/test_perf_common.c
+++ b/app/test-eventdev/test_perf_common.c
@@ -226,7 +226,7 @@ perf_event_rx_adapter_setup(struct evt_options *opt, uint8_t stride,
 	memset(&queue_conf, 0,
 			sizeof(struct rte_event_eth_rx_adapter_queue_conf));
 	queue_conf.ev.sched_type = opt->sched_type_list[0];
-	for (prod = 0; prod < rte_eth_dev_count(); prod++) {
+	RTE_ETH_FOREACH_DEV(prod) {
 		uint32_t cap;
 
 		ret = rte_event_eth_rx_adapter_caps_get(opt->dev_id,
@@ -465,7 +465,7 @@ perf_elt_init(struct rte_mempool *mp, void *arg __rte_unused,
 int
 perf_ethdev_setup(struct evt_test *test, struct evt_options *opt)
 {
-	int i;
+	uint16_t i;
 	struct test_perf *t = evt_test_priv(test);
 	struct rte_eth_conf port_conf = {
 		.rxmode = {
@@ -496,7 +496,7 @@ perf_ethdev_setup(struct evt_test *test, struct evt_options *opt)
 		return -ENODEV;
 	}
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 
 		if (rte_eth_dev_configure(i, 1, 1,
 					&port_conf)
@@ -527,11 +527,11 @@ perf_ethdev_setup(struct evt_test *test, struct evt_options *opt)
 
 void perf_ethdev_destroy(struct evt_test *test, struct evt_options *opt)
 {
-	int i;
+	uint16_t i;
 	RTE_SET_USED(test);
 
 	if (opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR) {
-		for (i = 0; i < rte_eth_dev_count(); i++) {
+		RTE_ETH_FOREACH_DEV(i) {
 			rte_event_eth_rx_adapter_stop(i);
 			rte_eth_dev_stop(i);
 			rte_eth_dev_close(i);
diff --git a/app/test-eventdev/test_pipeline_common.c b/app/test-eventdev/test_pipeline_common.c
index 6cad9357b..b4dbe3769 100644
--- a/app/test-eventdev/test_pipeline_common.c
+++ b/app/test-eventdev/test_pipeline_common.c
@@ -213,7 +213,7 @@ pipeline_opt_check(struct evt_options *opt, uint64_t nb_queues)
 int
 pipeline_ethdev_setup(struct evt_test *test, struct evt_options *opt)
 {
-	int i;
+	uint16_t i;
 	uint8_t nb_queues = 1;
 	uint8_t mt_state = 0;
 	struct test_pipeline *t = evt_test_priv(test);
@@ -239,7 +239,7 @@ pipeline_ethdev_setup(struct evt_test *test, struct evt_options *opt)
 		return -ENODEV;
 	}
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		struct rte_eth_dev_info dev_info;
 
 		memset(&dev_info, 0, sizeof(struct rte_eth_dev_info));
@@ -337,7 +337,7 @@ pipeline_event_rx_adapter_setup(struct evt_options *opt, uint8_t stride,
 	memset(&queue_conf, 0,
 			sizeof(struct rte_event_eth_rx_adapter_queue_conf));
 	queue_conf.ev.sched_type = opt->sched_type_list[0];
-	for (prod = 0; prod < rte_eth_dev_count(); prod++) {
+	RTE_ETH_FOREACH_DEV(prod) {
 		uint32_t cap;
 
 		ret = rte_event_eth_rx_adapter_caps_get(opt->dev_id,
@@ -453,7 +453,7 @@ pipeline_event_tx_service_setup(struct evt_test *test, struct evt_options *opt,
 void
 pipeline_ethdev_destroy(struct evt_test *test, struct evt_options *opt)
 {
-	int i;
+	uint16_t i;
 	RTE_SET_USED(test);
 	RTE_SET_USED(opt);
 	struct test_pipeline *t = evt_test_priv(test);
@@ -464,7 +464,7 @@ pipeline_ethdev_destroy(struct evt_test *test, struct evt_options *opt)
 		rte_service_component_unregister(t->tx_service.service_id);
 	}
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		rte_event_eth_rx_adapter_stop(i);
 		rte_eth_dev_stop(i);
 		rte_eth_dev_close(i);
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 40b31ad7e..91b1ad340 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -1880,7 +1880,7 @@ cmd_config_rss_parsed(void *parsed_result,
 	struct cmd_config_rss *res = parsed_result;
 	struct rte_eth_rss_conf rss_conf = { .rss_key_len = 0, };
 	int diag;
-	uint8_t i;
+	uint16_t i;
 
 	if (!strcmp(res->value, "all"))
 		rss_conf.rss_hf = ETH_RSS_IP | ETH_RSS_TCP |
@@ -1914,7 +1914,7 @@ cmd_config_rss_parsed(void *parsed_result,
 		return;
 	}
 	rss_conf.rss_key = NULL;
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		diag = rte_eth_dev_rss_hash_update(i, &rss_conf);
 		if (diag < 0)
 			printf("Configuration of RSS hash at ethernet port %d "
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 4c0e2586c..0708c32cb 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -1110,9 +1110,8 @@ run_pkt_fwd_on_lcore(struct fwd_lcore *fc, packet_fwd_t pkt_fwd)
 	uint64_t tics_per_1sec;
 	uint64_t tics_datum;
 	uint64_t tics_current;
-	uint8_t idx_port, cnt_ports;
+	uint16_t idx_port;
 
-	cnt_ports = rte_eth_dev_count();
 	tics_datum = rte_rdtsc();
 	tics_per_1sec = rte_get_timer_hz();
 #endif
@@ -1127,9 +1126,7 @@ run_pkt_fwd_on_lcore(struct fwd_lcore *fc, packet_fwd_t pkt_fwd)
 			tics_current = rte_rdtsc();
 			if (tics_current - tics_datum >= tics_per_1sec) {
 				/* Periodic bitrate calculation */
-				for (idx_port = 0;
-						idx_port < cnt_ports;
-						idx_port++)
+				RTE_ETH_FOREACH_DEV(idx_port)
 					rte_stats_bitrate_calc(bitrate_data,
 						idx_port);
 				tics_datum = tics_current;
diff --git a/doc/guides/sample_app_ug/flow_classify.rst b/doc/guides/sample_app_ug/flow_classify.rst
index 524747741..a0095962c 100644
--- a/doc/guides/sample_app_ug/flow_classify.rst
+++ b/doc/guides/sample_app_ug/flow_classify.rst
@@ -187,7 +187,7 @@ The ``main()`` function also initializes all the ports using the user defined
 
 .. code-block:: c
 
-    for (portid = 0; portid < nb_ports; portid++) {
+    RTE_ETH_FOREACH_DEV(portid) {
         if (port_init(portid, mbuf_pool) != 0) {
             rte_exit(EXIT_FAILURE,
                      "Cannot init port %" PRIu8 "\n", portid);
@@ -424,14 +424,13 @@ following:
     static __attribute__((noreturn)) void
     lcore_main(cls_app)
     {
-        const uint8_t nb_ports = rte_eth_dev_count();
-        uint8_t port;
+        uint16_t port;
 
         /*
          * Check that the port is on the same NUMA node as the polling thread
          * for best performance.
          */
-        for (port = 0; port < nb_ports; port++)
+        RTE_ETH_FOREACH_DEV(port)
             if (rte_eth_dev_socket_id(port) > 0 &&
                 rte_eth_dev_socket_id(port) != (int)rte_socket_id()) {
                 printf("\n\n");
@@ -451,7 +450,7 @@ following:
              * Receive packets on a port and forward them on the paired
              * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
              */
-            for (port = 0; port < nb_ports; port++) {
+            RTE_ETH_FOREACH_DEV(port) {
 
                 /* Get burst of RX packets, from first port of pair. */
                 struct rte_mbuf *bufs[BURST_SIZE];
@@ -501,7 +500,7 @@ The main work of the application is done within the loop:
 .. code-block:: c
 
         for (;;) {
-            for (port = 0; port < nb_ports; port++) {
+            RTE_ETH_FOREACH_DEV(port) {
 
                 /* Get burst of RX packets, from first port of pair. */
                 struct rte_mbuf *bufs[BURST_SIZE];
diff --git a/doc/guides/sample_app_ug/l2_forward_job_stats.rst b/doc/guides/sample_app_ug/l2_forward_job_stats.rst
index bfdf9c8f2..f14a780ae 100644
--- a/doc/guides/sample_app_ug/l2_forward_job_stats.rst
+++ b/doc/guides/sample_app_ug/l2_forward_job_stats.rst
@@ -193,7 +193,7 @@ in the *DPDK Programmer's Guide* and the *DPDK API Reference*.
     /*
      * Each logical core is assigned a dedicated TX queue on each port.
      */
-    for (portid = 0; portid < nb_ports; portid++) {
+    RTE_ETH_FOREACH_DEV(portid) {
         /* skip ports that are not enabled */
         if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
            continue;
diff --git a/doc/guides/sample_app_ug/l2_forward_real_virtual.rst b/doc/guides/sample_app_ug/l2_forward_real_virtual.rst
index f02be05ce..c91f57380 100644
--- a/doc/guides/sample_app_ug/l2_forward_real_virtual.rst
+++ b/doc/guides/sample_app_ug/l2_forward_real_virtual.rst
@@ -213,7 +213,7 @@ in the *DPDK Programmer's Guide* - Rel 1.4 EAR and the *DPDK API Reference*.
      * Each logical core is assigned a dedicated TX queue on each port.
      */
 
-    for (portid = 0; portid < nb_ports; portid++) {
+    RTE_ETH_FOREACH_DEV(portid) {
         /* skip ports that are not enabled */
 
         if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
diff --git a/doc/guides/sample_app_ug/link_status_intr.rst b/doc/guides/sample_app_ug/link_status_intr.rst
index 8fa6d76ce..57673456b 100644
--- a/doc/guides/sample_app_ug/link_status_intr.rst
+++ b/doc/guides/sample_app_ug/link_status_intr.rst
@@ -99,7 +99,7 @@ To fully understand this code, it is recommended to study the chapters that rela
      * Each logical core is assigned a dedicated TX queue on each port.
      */
 
-    for (portid = 0; portid < nb_ports; portid++) {
+    RTE_ETH_FOREACH_DEV(portid) {
         /* skip ports that are not enabled */
 
         if ((lsi_enabled_port_mask & (1 << portid)) == 0)
diff --git a/doc/guides/sample_app_ug/skeleton.rst b/doc/guides/sample_app_ug/skeleton.rst
index 0503584de..d3a3712f4 100644
--- a/doc/guides/sample_app_ug/skeleton.rst
+++ b/doc/guides/sample_app_ug/skeleton.rst
@@ -81,7 +81,7 @@ The ``main()`` function also initializes all the ports using the user defined
 
 .. code-block:: c
 
-    for (portid = 0; portid < nb_ports; portid++) {
+    RTE_ETH_FOREACH_DEV(portid) {
         if (port_init(portid, mbuf_pool) != 0) {
             rte_exit(EXIT_FAILURE,
                      "Cannot init port %" PRIu8 "\n", portid);
@@ -199,7 +199,7 @@ looks like the following:
          * Check that the port is on the same NUMA node as the polling thread
          * for best performance.
          */
-        for (port = 0; port < nb_ports; port++)
+        RTE_ETH_FOREACH_DEV(port)
             if (rte_eth_dev_socket_id(port) > 0 &&
                     rte_eth_dev_socket_id(port) !=
                             (int)rte_socket_id())
@@ -216,7 +216,7 @@ looks like the following:
              * Receive packets on a port and forward them on the paired
              * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
              */
-            for (port = 0; port < nb_ports; port++) {
+            RTE_ETH_FOREACH_DEV(port) {
 
                 /* Get burst of RX packets, from first port of pair. */
                 struct rte_mbuf *bufs[BURST_SIZE];
@@ -246,7 +246,7 @@ The main work of the application is done within the loop:
 .. code-block:: c
 
         for (;;) {
-            for (port = 0; port < nb_ports; port++) {
+            RTE_ETH_FOREACH_DEV(port) {
 
                 /* Get burst of RX packets, from first port of pair. */
                 struct rte_mbuf *bufs[BURST_SIZE];
diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile
index 4a6633ede..44353a1f8 100644
--- a/drivers/net/bonding/Makefile
+++ b/drivers/net/bonding/Makefile
@@ -8,6 +8,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 #
 LIB = librte_pmd_bond.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
diff --git a/drivers/net/bonding/meson.build b/drivers/net/bonding/meson.build
index 44d5fd8e7..98fdd37af 100644
--- a/drivers/net/bonding/meson.build
+++ b/drivers/net/bonding/meson.build
@@ -9,4 +9,6 @@ sources = files('rte_eth_bond_api.c', 'rte_eth_bond_pmd.c',
 deps += 'sched' # needed for rte_bitmap.h
 deps += ['ip_frag', 'cmdline']
 
+allow_experimental_apis = true
+
 install_headers('rte_eth_bond.h', 'rte_eth_bond_8023ad.h')
diff --git a/drivers/net/bonding/rte_eth_bond_args.c b/drivers/net/bonding/rte_eth_bond_args.c
index e99681e2d..eb205c8bb 100644
--- a/drivers/net/bonding/rte_eth_bond_args.c
+++ b/drivers/net/bonding/rte_eth_bond_args.c
@@ -32,7 +32,7 @@ find_port_id_by_pci_addr(const struct rte_pci_addr *pci_addr)
 	struct rte_pci_addr *eth_pci_addr;
 	unsigned i;
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		pci_dev = RTE_ETH_DEV_TO_PCI(&rte_eth_devices[i]);
 		eth_pci_addr = &pci_dev->addr;
 
@@ -50,7 +50,7 @@ find_port_id_by_dev_name(const char *name)
 {
 	unsigned i;
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		if (rte_eth_devices[i].data == NULL)
 			continue;
 
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 6ab515ca9..604b54d1f 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -2805,7 +2805,7 @@ rte_pmd_mrvl_remove(struct rte_vdev_device *vdev)
 
 	RTE_LOG(INFO, PMD, "Removing %s\n", name);
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) { /* FIXME: removing all devices! */
 		char ifname[RTE_ETH_NAME_MAX_LEN];
 
 		rte_eth_dev_get_name_by_port(i, ifname);
diff --git a/examples/bond/Makefile b/examples/bond/Makefile
index 44d10d4f5..e7afce358 100644
--- a/examples/bond/Makefile
+++ b/examples/bond/Makefile
@@ -25,6 +25,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -58,6 +60,7 @@ ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
 CFLAGS_main.o += -Wno-return-type
 endif
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 
 ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
diff --git a/examples/bond/main.c b/examples/bond/main.c
index 455f108ee..d68162f1d 100644
--- a/examples/bond/main.c
+++ b/examples/bond/main.c
@@ -738,7 +738,7 @@ int
 main(int argc, char *argv[])
 {
 	int ret;
-	uint8_t nb_ports, i;
+	uint16_t nb_ports, i;
 
 	/* init EAL */
 	ret = rte_eal_init(argc, argv);
@@ -761,7 +761,7 @@ main(int argc, char *argv[])
 
 	/* initialize all ports */
 	slaves_count = nb_ports;
-	for (i = 0; i < nb_ports; i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		slave_port_init(i, mbuf_pool);
 		slaves[i] = i;
 	}
diff --git a/examples/bond/meson.build b/examples/bond/meson.build
index 8f65e4a8d..82e355a49 100644
--- a/examples/bond/meson.build
+++ b/examples/bond/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += 'pmd_bond'
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/distributor/Makefile b/examples/distributor/Makefile
index 05ea0bfec..cb1bd216d 100644
--- a/examples/distributor/Makefile
+++ b/examples/distributor/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS)
 
 # workaround for a gcc bug with noreturn attribute
diff --git a/examples/distributor/main.c b/examples/distributor/main.c
index c49d680bd..62831a05c 100644
--- a/examples/distributor/main.c
+++ b/examples/distributor/main.c
@@ -198,7 +198,7 @@ lcore_rx(struct lcore_params *p)
 	uint16_t port;
 	struct rte_mbuf *bufs[BURST_SIZE*2];
 
-	for (port = 0; port < nb_ports; port++) {
+	RTE_ETH_FOREACH_DEV(port) {
 		/* skip ports that are not enabled */
 		if ((enabled_port_mask & (1 << port)) == 0)
 			continue;
@@ -295,11 +295,11 @@ flush_one_port(struct output_buffer *outbuf, uint8_t outp)
 }
 
 static inline void
-flush_all_ports(struct output_buffer *tx_buffers, uint16_t nb_ports)
+flush_all_ports(struct output_buffer *tx_buffers)
 {
 	uint16_t outp;
 
-	for (outp = 0; outp < nb_ports; outp++) {
+	RTE_ETH_FOREACH_DEV(outp) {
 		/* skip ports that are not enabled */
 		if ((enabled_port_mask & (1 << outp)) == 0)
 			continue;
@@ -367,11 +367,10 @@ static int
 lcore_tx(struct rte_ring *in_r)
 {
 	static struct output_buffer tx_buffers[RTE_MAX_ETHPORTS];
-	const uint16_t nb_ports = rte_eth_dev_count();
 	const int socket_id = rte_socket_id();
 	uint16_t port;
 
-	for (port = 0; port < nb_ports; port++) {
+	RTE_ETH_FOREACH_DEV(port) {
 		/* skip ports that are not enabled */
 		if ((enabled_port_mask & (1 << port)) == 0)
 			continue;
@@ -386,7 +385,7 @@ lcore_tx(struct rte_ring *in_r)
 	printf("\nCore %u doing packet TX.\n", rte_lcore_id());
 	while (!quit_signal) {
 
-		for (port = 0; port < nb_ports; port++) {
+		RTE_ETH_FOREACH_DEV(port) {
 			/* skip ports that are not enabled */
 			if ((enabled_port_mask & (1 << port)) == 0)
 				continue;
@@ -398,7 +397,7 @@ lcore_tx(struct rte_ring *in_r)
 
 			/* if we get no traffic, flush anything we have */
 			if (unlikely(nb_rx == 0)) {
-				flush_all_ports(tx_buffers, nb_ports);
+				flush_all_ports(tx_buffers);
 				continue;
 			}
 
@@ -446,14 +445,14 @@ print_stats(void)
 	unsigned int i, j;
 	const unsigned int num_workers = rte_lcore_count() - 4;
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		rte_eth_stats_get(i, &eth_stats);
 		app_stats.port_rx_pkts[i] = eth_stats.ipackets;
 		app_stats.port_tx_pkts[i] = eth_stats.opackets;
 	}
 
 	printf("\n\nRX Thread:\n");
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		printf("Port %u Pktsin : %5.2f\n", i,
 				(app_stats.port_rx_pkts[i] -
 				prev_app_stats.port_rx_pkts[i])/1000000.0);
@@ -492,7 +491,7 @@ print_stats(void)
 	printf(" - Dequeued:    %5.2f\n",
 			(app_stats.tx.dequeue_pkts -
 			prev_app_stats.tx.dequeue_pkts)/1000000.0);
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		printf("Port %u Pktsout: %5.2f\n",
 				i, (app_stats.port_tx_pkts[i] -
 				prev_app_stats.port_tx_pkts[i])/1000000.0);
@@ -694,7 +693,7 @@ main(int argc, char *argv[])
 	nb_ports_available = nb_ports;
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			printf("\nSkipping disabled port %d\n", portid);
diff --git a/examples/distributor/meson.build b/examples/distributor/meson.build
index 88c001f56..d036ea0f6 100644
--- a/examples/distributor/meson.build
+++ b/examples/distributor/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += 'distributor'
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/ethtool/ethtool-app/Makefile b/examples/ethtool/ethtool-app/Makefile
index 4cd9efdd5..1d400f19b 100644
--- a/examples/ethtool/ethtool-app/Makefile
+++ b/examples/ethtool/ethtool-app/Makefile
@@ -16,6 +16,7 @@ APP = ethtool
 # all source are stored in SRCS-y
 SRCS-y := main.c ethapp.c
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/ethtool/ethtool-app/ethapp.c b/examples/ethtool/ethtool-app/ethapp.c
index 0c3f1f6e1..4d62f4c17 100644
--- a/examples/ethtool/ethtool-app/ethapp.c
+++ b/examples/ethtool/ethtool-app/ethapp.c
@@ -145,9 +145,9 @@ pcmd_drvinfo_callback(__rte_unused void *ptr_params,
 	__rte_unused void *ptr_data)
 {
 	struct ethtool_drvinfo info;
-	int id_port;
+	uint16_t id_port;
 
-	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
+	RTE_ETH_FOREACH_DEV(id_port) {
 		memset(&info, 0, sizeof(info));
 		if (rte_ethtool_get_drvinfo(id_port, &info)) {
 			printf("Error getting info for port %i\n", id_port);
@@ -167,10 +167,10 @@ pcmd_link_callback(__rte_unused void *ptr_params,
 	__rte_unused struct cmdline *ctx,
 	__rte_unused void *ptr_data)
 {
-	int num_ports = rte_eth_dev_count();
-	int id_port, stat_port;
+	uint16_t id_port;
+	int stat_port;
 
-	for (id_port = 0; id_port < num_ports; id_port++) {
+	RTE_ETH_FOREACH_DEV(id_port) {
 		if (!rte_eth_dev_is_valid_port(id_port))
 			continue;
 		stat_port = rte_ethtool_get_link(id_port);
diff --git a/examples/eventdev_pipeline/main.c b/examples/eventdev_pipeline/main.c
index 2422c1849..bbab99597 100644
--- a/examples/eventdev_pipeline/main.c
+++ b/examples/eventdev_pipeline/main.c
@@ -339,10 +339,9 @@ port_init(uint8_t port, struct rte_mempool *mbuf_pool)
 }
 
 static int
-init_ports(unsigned int num_ports)
+init_ports(uint16_t num_ports)
 {
-	uint8_t portid;
-	unsigned int i;
+	uint16_t portid, i;
 
 	if (!cdata.num_mbuf)
 		cdata.num_mbuf = 16384 * num_ports;
@@ -354,12 +353,12 @@ init_ports(unsigned int num_ports)
 			/* data_room_size */ RTE_MBUF_DEFAULT_BUF_SIZE,
 			rte_socket_id());
 
-	for (portid = 0; portid < num_ports; portid++)
+	RTE_ETH_FOREACH_DEV(portid)
 		if (port_init(portid, mp) != 0)
-			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n",
+			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n",
 					portid);
 
-	for (i = 0; i < num_ports; i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		void *userdata = (void *)(uintptr_t) i;
 		fdata->tx_buf[i] =
 			rte_malloc(NULL, RTE_ETH_TX_BUFFER_SIZE(32), 0);
@@ -375,13 +374,13 @@ init_ports(unsigned int num_ports)
 }
 
 static void
-do_capability_setup(uint16_t nb_ethdev, uint8_t eventdev_id)
+do_capability_setup(uint8_t eventdev_id)
 {
-	int i;
+	uint16_t i;
 	uint8_t mt_unsafe = 0;
 	uint8_t burst = 0;
 
-	for (i = 0; i < nb_ethdev; i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		struct rte_eth_dev_info dev_info;
 		memset(&dev_info, 0, sizeof(struct rte_eth_dev_info));
 
@@ -483,7 +482,7 @@ main(int argc, char **argv)
 		fprintf(stderr, "Warning: More than one eventdev, using idx 0");
 
 
-	do_capability_setup(num_ports, 0);
+	do_capability_setup(0);
 	fdata->cap.check_opt();
 
 	worker_data = rte_calloc(0, cdata.num_workers,
diff --git a/examples/eventdev_pipeline/pipeline_worker_generic.c b/examples/eventdev_pipeline/pipeline_worker_generic.c
index c673160f5..2215e9ebe 100644
--- a/examples/eventdev_pipeline/pipeline_worker_generic.c
+++ b/examples/eventdev_pipeline/pipeline_worker_generic.c
@@ -138,7 +138,7 @@ consumer(void)
 				&packet, 1, 0);
 
 		if (n == 0) {
-			for (i = 0; i < rte_eth_dev_count(); i++)
+			RTE_ETH_FOREACH_DEV(i)
 				rte_eth_tx_buffer_flush(i, 0, fdata->tx_buf[i]);
 			return 0;
 		}
@@ -196,14 +196,13 @@ consumer_burst(void)
 	unsigned int i, j;
 	uint8_t dev_id = cons_data.dev_id;
 	uint8_t port_id = cons_data.port_id;
-	uint16_t nb_ports = rte_eth_dev_count();
 
 	do {
 		uint16_t n = rte_event_dequeue_burst(dev_id, port_id,
 				packets, RTE_DIM(packets), 0);
 
 		if (n == 0) {
-			for (j = 0; j < nb_ports; j++)
+			RTE_ETH_FOREACH_DEV(j)
 				rte_eth_tx_buffer_flush(j, 0, fdata->tx_buf[j]);
 			return 0;
 		}
@@ -521,7 +520,7 @@ generic_opt_check(void)
 		rte_exit(EXIT_FAILURE,
 				"Event dev doesn't support all type queues\n");
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		ret = rte_event_eth_rx_adapter_caps_get(0, i, &cap);
 		if (ret)
 			rte_exit(EXIT_FAILURE,
diff --git a/examples/eventdev_pipeline/pipeline_worker_tx.c b/examples/eventdev_pipeline/pipeline_worker_tx.c
index b254b03f7..fc98128ec 100644
--- a/examples/eventdev_pipeline/pipeline_worker_tx.c
+++ b/examples/eventdev_pipeline/pipeline_worker_tx.c
@@ -735,7 +735,7 @@ worker_tx_opt_check(void)
 		rte_exit(EXIT_FAILURE,
 				"Event dev doesn't support all type queues\n");
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		ret = rte_event_eth_rx_adapter_caps_get(0, i, &cap);
 		if (ret)
 			rte_exit(EXIT_FAILURE,
diff --git a/examples/exception_path/Makefile b/examples/exception_path/Makefile
index ae74781ec..88f709eff 100644
--- a/examples/exception_path/Makefile
+++ b/examples/exception_path/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/exception_path/main.c b/examples/exception_path/main.c
index dda391cd5..996f4939d 100644
--- a/examples/exception_path/main.c
+++ b/examples/exception_path/main.c
@@ -475,7 +475,7 @@ init_port(uint16_t port)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -487,7 +487,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -571,14 +571,14 @@ main(int argc, char** argv)
 		FATAL_ERROR("Port mask requires more ports than available");
 
 	/* Initialise each port */
-	for (port = 0; port < nb_sys_ports; port++) {
+	RTE_ETH_FOREACH_DEV(port) {
 		/* Skip ports that are not enabled */
 		if ((ports_mask & (1 << port)) == 0) {
 			continue;
 		}
 		init_port(port);
 	}
-	check_all_ports_link_status(nb_sys_ports, ports_mask);
+	check_all_ports_link_status(ports_mask);
 
 	/* Launch per-lcore function on every lcore */
 	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
diff --git a/examples/exception_path/meson.build b/examples/exception_path/meson.build
index c34e11e36..2b0a25036 100644
--- a/examples/exception_path/meson.build
+++ b/examples/exception_path/meson.build
@@ -6,6 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/flow_classify/flow_classify.c b/examples/flow_classify/flow_classify.c
index 32d9b1d30..a65ef20f9 100644
--- a/examples/flow_classify/flow_classify.c
+++ b/examples/flow_classify/flow_classify.c
@@ -259,8 +259,7 @@ port_init(uint8_t port, struct rte_mempool *mbuf_pool)
 static __attribute__((noreturn)) void
 lcore_main(struct flow_classifier *cls_app)
 {
-	const uint8_t nb_ports = rte_eth_dev_count();
-	uint8_t port;
+	uint16_t port;
 	int ret;
 	int i = 0;
 
@@ -275,7 +274,7 @@ lcore_main(struct flow_classifier *cls_app)
 	 * Check that the port is on the same NUMA node as the polling thread
 	 * for best performance.
 	 */
-	for (port = 0; port < nb_ports; port++)
+	RTE_ETH_FOREACH_DEV(port)
 		if (rte_eth_dev_socket_id(port) > 0 &&
 			rte_eth_dev_socket_id(port) != (int)rte_socket_id()) {
 			printf("\n\n");
@@ -294,7 +293,7 @@ lcore_main(struct flow_classifier *cls_app)
 		 * on the paired port.
 		 * The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
 		 */
-		for (port = 0; port < nb_ports; port++) {
+		RTE_ETH_FOREACH_DEV(port) {
 			/* Get burst of RX packets, from first port of pair. */
 			struct rte_mbuf *bufs[BURST_SIZE];
 			const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
@@ -754,7 +753,7 @@ main(int argc, char *argv[])
 {
 	struct rte_mempool *mbuf_pool;
 	uint8_t nb_ports;
-	uint8_t portid;
+	uint16_t portid;
 	int ret;
 	int socket_id;
 	struct rte_table_acl_params table_acl_params;
@@ -789,7 +788,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* Initialize all ports. */
-	for (portid = 0; portid < nb_ports; portid++)
+	RTE_ETH_FOREACH_DEV(portid)
 		if (port_init(portid, mbuf_pool) != 0)
 			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n",
 					portid);
diff --git a/examples/ip_fragmentation/Makefile b/examples/ip_fragmentation/Makefile
index 9e89e744c..3b58ced54 100644
--- a/examples/ip_fragmentation/Makefile
+++ b/examples/ip_fragmentation/Makefile
@@ -24,6 +24,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -49,6 +51,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/ip_fragmentation/main.c b/examples/ip_fragmentation/main.c
index d3b1da6c0..f525c3a9c 100644
--- a/examples/ip_fragmentation/main.c
+++ b/examples/ip_fragmentation/main.c
@@ -571,7 +571,7 @@ print_ethaddr(const char *name, struct ether_addr *eth_addr)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -583,7 +583,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -876,7 +876,7 @@ main(int argc, char **argv)
 		rte_exit(EXIT_FAILURE, "Non-existent ports in portmask!\n");
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_conf local_port_conf = port_conf;
 		struct rte_eth_rxconf rxq_conf;
 
@@ -994,7 +994,7 @@ main(int argc, char **argv)
 	printf("\n");
 
 	/* start ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			continue;
 		}
@@ -1016,7 +1016,7 @@ main(int argc, char **argv)
 	if (init_routing_table() < 0)
 		rte_exit(EXIT_FAILURE, "Cannot init routing table\n");
 
-	check_all_ports_link_status(nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 
 	/* launch per-lcore init on every lcore */
 	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
diff --git a/examples/ip_fragmentation/meson.build b/examples/ip_fragmentation/meson.build
index 304203eed..9782a6a7b 100644
--- a/examples/ip_fragmentation/meson.build
+++ b/examples/ip_fragmentation/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps +=  ['ip_frag', 'lpm']
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/ip_reassembly/Makefile b/examples/ip_reassembly/Makefile
index 1e81315f2..6438d977e 100644
--- a/examples/ip_reassembly/Makefile
+++ b/examples/ip_reassembly/Makefile
@@ -24,6 +24,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -49,6 +51,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/ip_reassembly/main.c b/examples/ip_reassembly/main.c
index 350a9739c..ddff35880 100644
--- a/examples/ip_reassembly/main.c
+++ b/examples/ip_reassembly/main.c
@@ -702,7 +702,7 @@ print_ethaddr(const char *name, const struct ether_addr *eth_addr)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -714,7 +714,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -1023,7 +1023,7 @@ main(int argc, char **argv)
 		rte_exit(EXIT_FAILURE, "Non-existent ports in portmask!\n");
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_rxconf rxq_conf;
 		struct rte_eth_conf local_port_conf = port_conf;
 
@@ -1141,7 +1141,7 @@ main(int argc, char **argv)
 	printf("\n");
 
 	/* start ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			continue;
 		}
@@ -1157,7 +1157,7 @@ main(int argc, char **argv)
 	if (init_routing_table() < 0)
 		rte_exit(EXIT_FAILURE, "Cannot init routing table\n");
 
-	check_all_ports_link_status(nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 
 	signal(SIGUSR1, signal_handler);
 	signal(SIGTERM, signal_handler);
diff --git a/examples/ip_reassembly/meson.build b/examples/ip_reassembly/meson.build
index 8ebd48291..8a667c265 100644
--- a/examples/ip_reassembly/meson.build
+++ b/examples/ip_reassembly/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['lpm', 'ip_frag']
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 3a8562ee9..3001d626b 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1173,7 +1173,7 @@ print_ethaddr(const char *name, const struct ether_addr *eth_addr)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -1185,7 +1185,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -1383,7 +1383,7 @@ cryptodevs_init(void)
 		if (sess_sz > max_sess_sz)
 			max_sess_sz = sess_sz;
 	}
-	for (port_id = 0; port_id < rte_eth_dev_count(); port_id++) {
+	RTE_ETH_FOREACH_DEV(port_id) {
 		void *sec_ctx;
 
 		if ((enabled_port_mask & (1 << port_id)) == 0)
@@ -1470,7 +1470,7 @@ cryptodevs_init(void)
 	}
 
 	/* create session pools for eth devices that implement security */
-	for (port_id = 0; port_id < rte_eth_dev_count(); port_id++) {
+	RTE_ETH_FOREACH_DEV(port_id) {
 		if ((enabled_port_mask & (1 << port_id)) &&
 				rte_eth_dev_get_sec_ctx(port_id)) {
 			int socket_id = rte_eth_dev_socket_id(port_id);
@@ -1646,7 +1646,7 @@ main(int32_t argc, char **argv)
 	int32_t ret;
 	uint32_t lcore_id;
 	uint8_t socket_id;
-	uint16_t portid, nb_ports;
+	uint16_t portid;
 
 	/* init EAL */
 	ret = rte_eal_init(argc, argv);
@@ -1665,8 +1665,6 @@ main(int32_t argc, char **argv)
 		rte_exit(EXIT_FAILURE, "Invalid unprotected portmask 0x%x\n",
 				unprotected_port_mask);
 
-	nb_ports = rte_eth_dev_count();
-
 	if (check_params() < 0)
 		rte_exit(EXIT_FAILURE, "check_params failed\n");
 
@@ -1700,7 +1698,7 @@ main(int32_t argc, char **argv)
 		pool_init(&socket_ctx[socket_id], socket_id, NB_MBUF);
 	}
 
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0)
 			continue;
 
@@ -1710,7 +1708,7 @@ main(int32_t argc, char **argv)
 	cryptodevs_init();
 
 	/* start ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0)
 			continue;
 
@@ -1729,7 +1727,7 @@ main(int32_t argc, char **argv)
 			rte_eth_promiscuous_enable(portid);
 	}
 
-	check_all_ports_link_status(nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 
 	/* launch per-lcore init on every lcore */
 	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
diff --git a/examples/ipv4_multicast/Makefile b/examples/ipv4_multicast/Makefile
index a16c62333..236e706b3 100644
--- a/examples/ipv4_multicast/Makefile
+++ b/examples/ipv4_multicast/Makefile
@@ -24,6 +24,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -49,6 +51,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/ipv4_multicast/main.c b/examples/ipv4_multicast/main.c
index c3bcf2c80..23b266bbe 100644
--- a/examples/ipv4_multicast/main.c
+++ b/examples/ipv4_multicast/main.c
@@ -578,7 +578,7 @@ init_mcast_hash(void)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -590,7 +590,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -683,7 +683,7 @@ main(int argc, char **argv)
 	nb_lcores = rte_lcore_count();
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_rxconf rxq_conf;
 		struct rte_eth_conf local_port_conf = port_conf;
 
@@ -786,7 +786,7 @@ main(int argc, char **argv)
 		printf("done:\n");
 	}
 
-	check_all_ports_link_status(nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 
 	/* initialize the multicast hash */
 	int retval = init_mcast_hash();
diff --git a/examples/ipv4_multicast/meson.build b/examples/ipv4_multicast/meson.build
index d9e4c7c21..6969e2c54 100644
--- a/examples/ipv4_multicast/meson.build
+++ b/examples/ipv4_multicast/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += 'hash'
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/kni/Makefile b/examples/kni/Makefile
index 562dc2741..96ae2fc6f 100644
--- a/examples/kni/Makefile
+++ b/examples/kni/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -53,6 +55,7 @@ $(error This application can only operate in a linuxapp environment, \
 please change the definition of the RTE_TARGET environment variable)
 endif
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/kni/main.c b/examples/kni/main.c
index 0d9980ee1..f069788ce 100644
--- a/examples/kni/main.c
+++ b/examples/kni/main.c
@@ -275,7 +275,7 @@ kni_egress(struct kni_port_params *p)
 static int
 main_loop(__rte_unused void *arg)
 {
-	uint8_t i, nb_ports = rte_eth_dev_count();
+	uint16_t i;
 	int32_t f_stop;
 	const unsigned lcore_id = rte_lcore_id();
 	enum lcore_rxtx {
@@ -286,7 +286,7 @@ main_loop(__rte_unused void *arg)
 	};
 	enum lcore_rxtx flag = LCORE_NONE;
 
-	for (i = 0; i < nb_ports; i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		if (!kni_port_params_array[i])
 			continue;
 		if (kni_port_params_array[i]->lcore_rx == (uint8_t)lcore_id) {
@@ -626,7 +626,7 @@ init_port(uint16_t port)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -638,7 +638,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -935,7 +935,7 @@ main(int argc, char** argv)
 	init_kni();
 
 	/* Initialise each port */
-	for (port = 0; port < nb_sys_ports; port++) {
+	RTE_ETH_FOREACH_DEV(port) {
 		/* Skip ports that are not enabled */
 		if (!(ports_mask & (1 << port)))
 			continue;
@@ -947,7 +947,7 @@ main(int argc, char** argv)
 
 		kni_alloc(port);
 	}
-	check_all_ports_link_status(nb_sys_ports, ports_mask);
+	check_all_ports_link_status(ports_mask);
 
 	/* Launch per-lcore function on every lcore */
 	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
@@ -957,7 +957,7 @@ main(int argc, char** argv)
 	}
 
 	/* Release resources */
-	for (port = 0; port < nb_sys_ports; port++) {
+	RTE_ETH_FOREACH_DEV(port) {
 		if (!(ports_mask & (1 << port)))
 			continue;
 		kni_free_kni(port);
diff --git a/examples/kni/meson.build b/examples/kni/meson.build
index c39aead6f..bf3561713 100644
--- a/examples/kni/meson.build
+++ b/examples/kni/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['kni', 'bus_pci']
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/l2fwd-cat/Makefile b/examples/l2fwd-cat/Makefile
index aec770c28..fe0f20073 100644
--- a/examples/l2fwd-cat/Makefile
+++ b/examples/l2fwd-cat/Makefile
@@ -23,6 +23,7 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -D_GNU_SOURCE
 LDFLAGS += -lpqos
 
@@ -55,6 +56,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS)
 
 # workaround for a gcc bug with noreturn attribute
diff --git a/examples/l2fwd-cat/l2fwd-cat.c b/examples/l2fwd-cat/l2fwd-cat.c
index 69339cca8..344292864 100644
--- a/examples/l2fwd-cat/l2fwd-cat.c
+++ b/examples/l2fwd-cat/l2fwd-cat.c
@@ -95,14 +95,13 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 static __attribute__((noreturn)) void
 lcore_main(void)
 {
-	const uint16_t nb_ports = rte_eth_dev_count();
 	uint16_t port;
 
 	/*
 	 * Check that the port is on the same NUMA node as the polling thread
 	 * for best performance.
 	 */
-	for (port = 0; port < nb_ports; port++)
+	RTE_ETH_FOREACH_DEV(port)
 		if (rte_eth_dev_socket_id(port) > 0 &&
 				rte_eth_dev_socket_id(port) !=
 						(int)rte_socket_id())
@@ -119,7 +118,7 @@ lcore_main(void)
 		 * Receive packets on a port and forward them on the paired
 		 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
 		 */
-		for (port = 0; port < nb_ports; port++) {
+		RTE_ETH_FOREACH_DEV(port) {
 
 			/* Get burst of RX packets, from first port of pair. */
 			struct rte_mbuf *bufs[BURST_SIZE];
@@ -186,7 +185,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* Initialize all ports. */
-	for (portid = 0; portid < nb_ports; portid++)
+	RTE_ETH_FOREACH_DEV(portid)
 		if (port_init(portid, mbuf_pool) != 0)
 			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n",
 					portid);
diff --git a/examples/l2fwd-cat/meson.build b/examples/l2fwd-cat/meson.build
index b6deabc97..29e5d0cf7 100644
--- a/examples/l2fwd-cat/meson.build
+++ b/examples/l2fwd-cat/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 ext_deps += cc.find_library('pqos')
+allow_experimental_apis = true
 cflags += '-D_GNU_SOURCE'
 cflags += '-I/usr/local/include' # assume pqos lib installed in /usr/local
 sources = files(
diff --git a/examples/l2fwd-crypto/Makefile b/examples/l2fwd-crypto/Makefile
index a67f087b2..99afdd2e3 100644
--- a/examples/l2fwd-crypto/Makefile
+++ b/examples/l2fwd-crypto/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index 4d8341e29..b1ad19284 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -1721,7 +1721,7 @@ l2fwd_crypto_parse_args(struct l2fwd_crypto_options *options,
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -1733,7 +1733,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -2309,7 +2309,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 static int
 initialize_ports(struct l2fwd_crypto_options *options)
 {
-	uint16_t last_portid, portid;
+	uint16_t last_portid = 0, portid;
 	unsigned enabled_portcount = 0;
 	unsigned nb_ports = rte_eth_dev_count();
 
@@ -2322,7 +2322,7 @@ initialize_ports(struct l2fwd_crypto_options *options)
 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
 		l2fwd_dst_ports[portid] = 0;
 
-	for (last_portid = 0, portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		int retval;
 		struct rte_eth_dev_info dev_info;
 		struct rte_eth_rxconf rxq_conf;
@@ -2426,7 +2426,7 @@ initialize_ports(struct l2fwd_crypto_options *options)
 		return -1;
 	}
 
-	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+	check_all_ports_link_status(l2fwd_enabled_port_mask);
 
 	return enabled_portcount;
 }
@@ -2470,12 +2470,12 @@ reserve_key_memory(struct l2fwd_crypto_options *options)
 int
 main(int argc, char **argv)
 {
-	struct lcore_queue_conf *qconf;
+	struct lcore_queue_conf *qconf = NULL;
 	struct l2fwd_crypto_options options;
 
 	uint8_t nb_cryptodevs, cdev_id;
-	uint16_t nb_ports, portid;
-	unsigned lcore_id, rx_lcore_id;
+	uint16_t portid;
+	unsigned lcore_id, rx_lcore_id = 0;
 	int ret, enabled_cdevcount, enabled_portcount;
 	uint8_t enabled_cdevs[RTE_CRYPTO_MAX_DEVS] = {0};
 
@@ -2516,10 +2516,8 @@ main(int argc, char **argv)
 	if (enabled_portcount < 1)
 		rte_exit(EXIT_FAILURE, "Failed to initial Ethernet ports\n");
 
-	nb_ports = rte_eth_dev_count();
 	/* Initialize the port/queue configuration of each logical core */
-	for (rx_lcore_id = 0, qconf = NULL, portid = 0;
-			portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 
 		/* skip ports that are not enabled */
 		if ((options.portmask & (1 << portid)) == 0)
diff --git a/examples/l2fwd-crypto/meson.build b/examples/l2fwd-crypto/meson.build
index 09438a6a0..6c852ad19 100644
--- a/examples/l2fwd-crypto/meson.build
+++ b/examples/l2fwd-crypto/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += 'cryptodev'
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/l2fwd-jobstats/Makefile b/examples/l2fwd-jobstats/Makefile
index 696a8b21a..a9315d475 100644
--- a/examples/l2fwd-jobstats/Makefile
+++ b/examples/l2fwd-jobstats/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,7 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/l2fwd-jobstats/main.c b/examples/l2fwd-jobstats/main.c
index 2554f448a..248224840 100644
--- a/examples/l2fwd-jobstats/main.c
+++ b/examples/l2fwd-jobstats/main.c
@@ -680,7 +680,7 @@ l2fwd_parse_args(int argc, char **argv)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -692,7 +692,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -742,7 +742,7 @@ main(int argc, char **argv)
 	int ret;
 	char name[RTE_JOBSTATS_NAMESIZE];
 	uint16_t nb_ports;
-	uint16_t nb_ports_available;
+	uint16_t nb_ports_available = 0;
 	uint16_t portid, last_port;
 	uint8_t i;
 
@@ -782,7 +782,7 @@ main(int argc, char **argv)
 	/*
 	 * Each logical core is assigned a dedicated TX queue on each port.
 	 */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
@@ -804,7 +804,7 @@ main(int argc, char **argv)
 	qconf = NULL;
 
 	/* Initialize the port/queue configuration of each logical core */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
@@ -827,10 +827,8 @@ main(int argc, char **argv)
 		printf("Lcore %u: RX port %u\n", rx_lcore_id, portid);
 	}
 
-	nb_ports_available = nb_ports;
-
 	/* Initialise each port */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_dev_info dev_info;
 		struct rte_eth_rxconf rxq_conf;
 		struct rte_eth_txconf txq_conf;
@@ -839,9 +837,10 @@ main(int argc, char **argv)
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
 			printf("Skipping disabled port %u\n", portid);
-			nb_ports_available--;
 			continue;
 		}
+		nb_ports_available++;
+
 		/* init port */
 		printf("Initializing port %u... ", portid);
 		fflush(stdout);
@@ -934,7 +933,7 @@ main(int argc, char **argv)
 			"All available ports are disabled. Please set portmask.\n");
 	}
 
-	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+	check_all_ports_link_status(l2fwd_enabled_port_mask);
 
 	drain_tsc = (hz + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
 
diff --git a/examples/l2fwd-jobstats/meson.build b/examples/l2fwd-jobstats/meson.build
index 1ffd484e2..3653aa7ec 100644
--- a/examples/l2fwd-jobstats/meson.build
+++ b/examples/l2fwd-jobstats/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['jobstats', 'timer']
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/l2fwd-keepalive/Makefile b/examples/l2fwd-keepalive/Makefile
index 4ab67db44..af2895668 100644
--- a/examples/l2fwd-keepalive/Makefile
+++ b/examples/l2fwd-keepalive/Makefile
@@ -25,6 +25,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -50,6 +52,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDFLAGS += -lrt
diff --git a/examples/l2fwd-keepalive/main.c b/examples/l2fwd-keepalive/main.c
index 39b8c3286..e9ad91a1f 100644
--- a/examples/l2fwd-keepalive/main.c
+++ b/examples/l2fwd-keepalive/main.c
@@ -445,7 +445,7 @@ l2fwd_parse_args(int argc, char **argv)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -457,7 +457,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -526,7 +526,7 @@ main(int argc, char **argv)
 	struct lcore_queue_conf *qconf;
 	int ret;
 	uint16_t nb_ports;
-	uint16_t nb_ports_available;
+	uint16_t nb_ports_available = 0;
 	uint16_t portid, last_port;
 	unsigned lcore_id, rx_lcore_id;
 	unsigned nb_ports_in_mask = 0;
@@ -573,7 +573,7 @@ main(int argc, char **argv)
 	/*
 	 * Each logical core is assigned a dedicated TX queue on each port.
 	 */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
@@ -595,7 +595,7 @@ main(int argc, char **argv)
 	qconf = NULL;
 
 	/* Initialize the port/queue configuration of each logical core */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
@@ -619,10 +619,8 @@ main(int argc, char **argv)
 			rx_lcore_id, portid);
 	}
 
-	nb_ports_available = nb_ports;
-
 	/* Initialise each port */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_dev_info dev_info;
 		struct rte_eth_rxconf rxq_conf;
 		struct rte_eth_txconf txq_conf;
@@ -631,9 +629,10 @@ main(int argc, char **argv)
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
 			printf("Skipping disabled port %u\n", portid);
-			nb_ports_available--;
 			continue;
 		}
+		nb_ports_available++;
+
 		/* init port */
 		printf("Initializing port %u... ", portid);
 		fflush(stdout);
@@ -728,7 +727,7 @@ main(int argc, char **argv)
 			"All available ports are disabled. Please set portmask.\n");
 	}
 
-	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+	check_all_ports_link_status(l2fwd_enabled_port_mask);
 
 	struct rte_timer hb_timer, stats_timer;
 
diff --git a/examples/l2fwd-keepalive/meson.build b/examples/l2fwd-keepalive/meson.build
index 6f7b007e1..2dffffaaa 100644
--- a/examples/l2fwd-keepalive/meson.build
+++ b/examples/l2fwd-keepalive/meson.build
@@ -8,6 +8,7 @@
 
 ext_deps += cc.find_library('rt')
 deps += 'timer'
+allow_experimental_apis = true
 sources = files(
 	'main.c', 'shm.c'
 )
diff --git a/examples/l2fwd/Makefile b/examples/l2fwd/Makefile
index a8a47ad4e..1d7760de9 100644
--- a/examples/l2fwd/Makefile
+++ b/examples/l2fwd/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/l2fwd/main.c b/examples/l2fwd/main.c
index e4a4a7c36..f8ca29cf6 100644
--- a/examples/l2fwd/main.c
+++ b/examples/l2fwd/main.c
@@ -444,7 +444,7 @@ l2fwd_parse_args(int argc, char **argv)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -458,7 +458,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 		if (force_quit)
 			return;
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if (force_quit)
 				return;
 			if ((port_mask & (1 << portid)) == 0)
@@ -517,7 +517,7 @@ main(int argc, char **argv)
 	struct lcore_queue_conf *qconf;
 	int ret;
 	uint16_t nb_ports;
-	uint16_t nb_ports_available;
+	uint16_t nb_ports_available = 0;
 	uint16_t portid, last_port;
 	unsigned lcore_id, rx_lcore_id;
 	unsigned nb_ports_in_mask = 0;
@@ -562,7 +562,7 @@ main(int argc, char **argv)
 	/*
 	 * Each logical core is assigned a dedicated TX queue on each port.
 	 */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
@@ -585,7 +585,7 @@ main(int argc, char **argv)
 	qconf = NULL;
 
 	/* Initialize the port/queue configuration of each logical core */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
@@ -610,8 +610,6 @@ main(int argc, char **argv)
 		printf("Lcore %u: RX port %u\n", rx_lcore_id, portid);
 	}
 
-	nb_ports_available = nb_ports;
-
 	nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
 		nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
 
@@ -623,7 +621,7 @@ main(int argc, char **argv)
 		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
 
 	/* Initialise each port */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_rxconf rxq_conf;
 		struct rte_eth_txconf txq_conf;
 		struct rte_eth_conf local_port_conf = port_conf;
@@ -632,9 +630,10 @@ main(int argc, char **argv)
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
 			printf("Skipping disabled port %u\n", portid);
-			nb_ports_available--;
 			continue;
 		}
+		nb_ports_available++;
+
 		/* init port */
 		printf("Initializing port %u... ", portid);
 		fflush(stdout);
@@ -726,7 +725,7 @@ main(int argc, char **argv)
 			"All available ports are disabled. Please set portmask.\n");
 	}
 
-	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+	check_all_ports_link_status(l2fwd_enabled_port_mask);
 
 	ret = 0;
 	/* launch per-lcore init on every lcore */
@@ -738,7 +737,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
 		printf("Closing port %d...", portid);
diff --git a/examples/l2fwd/meson.build b/examples/l2fwd/meson.build
index c34e11e36..2b0a25036 100644
--- a/examples/l2fwd/meson.build
+++ b/examples/l2fwd/meson.build
@@ -6,6 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/l3fwd-acl/Makefile b/examples/l3fwd-acl/Makefile
index 285683f83..eabca1ed7 100644
--- a/examples/l3fwd-acl/Makefile
+++ b/examples/l3fwd-acl/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/l3fwd-acl/main.c b/examples/l3fwd-acl/main.c
index 9aebb3318..3c547cd8e 100644
--- a/examples/l3fwd-acl/main.c
+++ b/examples/l3fwd-acl/main.c
@@ -1805,7 +1805,7 @@ init_mem(unsigned nb_mbuf)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -1817,7 +1817,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -1903,7 +1903,7 @@ main(int argc, char **argv)
 	nb_lcores = rte_lcore_count();
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_conf local_port_conf = port_conf;
 
 		/* skip ports that are not enabled */
@@ -2043,7 +2043,7 @@ main(int argc, char **argv)
 	printf("\n");
 
 	/* start ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0)
 			continue;
 
@@ -2064,7 +2064,7 @@ main(int argc, char **argv)
 			rte_eth_promiscuous_enable(portid);
 	}
 
-	check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 
 	/* launch per-lcore init on every lcore */
 	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
diff --git a/examples/l3fwd-acl/meson.build b/examples/l3fwd-acl/meson.build
index 7096e00c1..68cebd6ce 100644
--- a/examples/l3fwd-acl/meson.build
+++ b/examples/l3fwd-acl/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['acl', 'lpm', 'hash']
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/l3fwd-power/Makefile b/examples/l3fwd-power/Makefile
index 390b7d6b6..d4e1ac64f 100644
--- a/examples/l3fwd-power/Makefile
+++ b/examples/l3fwd-power/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -54,6 +56,7 @@ please change the definition of the RTE_TARGET environment variable)
 all:
 else
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/l3fwd-power/main.c b/examples/l3fwd-power/main.c
index b2a7c79e6..16f4d098c 100644
--- a/examples/l3fwd-power/main.c
+++ b/examples/l3fwd-power/main.c
@@ -341,7 +341,7 @@ static void
 signal_exit_now(int sigtype)
 {
 	unsigned lcore_id;
-	unsigned int portid, nb_ports;
+	unsigned int portid;
 	int ret;
 
 	if (sigtype == SIGINT) {
@@ -357,8 +357,7 @@ signal_exit_now(int sigtype)
 							"core%u\n", lcore_id);
 		}
 
-		nb_ports = rte_eth_dev_count();
-		for (portid = 0; portid < nb_ports; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((enabled_port_mask & (1 << portid)) == 0)
 				continue;
 
@@ -1512,7 +1511,7 @@ init_mem(unsigned nb_mbuf)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -1524,7 +1523,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -1659,7 +1658,7 @@ main(int argc, char **argv)
 	nb_lcores = rte_lcore_count();
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_conf local_port_conf = port_conf;
 
 		/* skip ports that are not enabled */
@@ -1834,7 +1833,7 @@ main(int argc, char **argv)
 	printf("\n");
 
 	/* start ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			continue;
 		}
@@ -1855,7 +1854,7 @@ main(int argc, char **argv)
 		rte_spinlock_init(&(locks[portid]));
 	}
 
-	check_all_ports_link_status(nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 
 	/* launch per-lcore init on every lcore */
 	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
diff --git a/examples/l3fwd-power/meson.build b/examples/l3fwd-power/meson.build
index 61e8daa96..cb50c7ab4 100644
--- a/examples/l3fwd-power/meson.build
+++ b/examples/l3fwd-power/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['power', 'timer', 'lpm', 'hash']
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/l3fwd-vf/Makefile b/examples/l3fwd-vf/Makefile
index dfb1d52d3..d776689fa 100644
--- a/examples/l3fwd-vf/Makefile
+++ b/examples/l3fwd-vf/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3 $(USER_FLAGS)
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/l3fwd-vf/main.c b/examples/l3fwd-vf/main.c
index c69bd62fa..7a9927c34 100644
--- a/examples/l3fwd-vf/main.c
+++ b/examples/l3fwd-vf/main.c
@@ -648,11 +648,10 @@ static void
 signal_handler(int signum)
 {
 	uint16_t portid;
-	uint16_t nb_ports = rte_eth_dev_count();
 
 	/* When we receive a SIGINT signal */
 	if (signum == SIGINT) {
-		for (portid = 0; portid < nb_ports; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			/* skip ports that are not enabled */
 			if ((enabled_port_mask & (1 << portid)) == 0)
 				continue;
@@ -958,7 +957,7 @@ main(int argc, char **argv)
 	nb_lcores = rte_lcore_count();
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_conf local_port_conf = port_conf;
 
 		/* skip ports that are not enabled */
@@ -1063,7 +1062,7 @@ main(int argc, char **argv)
 	printf("\n");
 
 	/* start ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			continue;
 		}
diff --git a/examples/l3fwd-vf/meson.build b/examples/l3fwd-vf/meson.build
index 226286e74..00f3c38f4 100644
--- a/examples/l3fwd-vf/meson.build
+++ b/examples/l3fwd-vf/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['lpm', 'hash']
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/l3fwd/Makefile b/examples/l3fwd/Makefile
index cccdd9dfa..8cc8f6aaa 100644
--- a/examples/l3fwd/Makefile
+++ b/examples/l3fwd/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3 $(USER_FLAGS)
 CFLAGS += $(WERROR_FLAGS)
diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
index e7111fa18..8f7961cec 100644
--- a/examples/l3fwd/main.c
+++ b/examples/l3fwd/main.c
@@ -694,7 +694,7 @@ init_mem(unsigned nb_mbuf)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -708,7 +708,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 		if (force_quit)
 			return;
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if (force_quit)
 				return;
 			if ((port_mask & (1 << portid)) == 0)
@@ -837,7 +837,7 @@ main(int argc, char **argv)
 	setup_l3fwd_lookup_tables();
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_conf local_port_conf = port_conf;
 
 		/* skip ports that are not enabled */
@@ -971,7 +971,7 @@ main(int argc, char **argv)
 	printf("\n");
 
 	/* start ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			continue;
 		}
@@ -1007,7 +1007,7 @@ main(int argc, char **argv)
 	}
 
 
-	check_all_ports_link_status(nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 
 	ret = 0;
 	/* launch per-lcore init on every lcore */
@@ -1020,7 +1020,7 @@ main(int argc, char **argv)
 	}
 
 	/* stop ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0)
 			continue;
 		printf("Closing port %d...", portid);
diff --git a/examples/l3fwd/meson.build b/examples/l3fwd/meson.build
index 6dd4b9022..cbef07f4f 100644
--- a/examples/l3fwd/meson.build
+++ b/examples/l3fwd/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['hash', 'lpm']
+allow_experimental_apis = true
 sources = files(
 	'l3fwd_em.c', 'l3fwd_lpm.c', 'main.c'
 )
diff --git a/examples/multi_process/l2fwd_fork/Makefile b/examples/multi_process/l2fwd_fork/Makefile
index b65582ef1..79d506862 100644
--- a/examples/multi_process/l2fwd_fork/Makefile
+++ b/examples/multi_process/l2fwd_fork/Makefile
@@ -16,6 +16,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/multi_process/l2fwd_fork/main.c b/examples/multi_process/l2fwd_fork/main.c
index bc9ceb5ca..6b130f2f5 100644
--- a/examples/multi_process/l2fwd_fork/main.c
+++ b/examples/multi_process/l2fwd_fork/main.c
@@ -838,7 +838,7 @@ l2fwd_parse_args(int argc, char **argv)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -850,7 +850,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -897,7 +897,7 @@ main(int argc, char **argv)
 	struct lcore_queue_conf *qconf;
 	int ret;
 	uint16_t nb_ports;
-	uint16_t nb_ports_available;
+	uint16_t nb_ports_available = 0;
 	uint16_t portid, last_port;
 	unsigned rx_lcore_id;
 	unsigned nb_ports_in_mask = 0;
@@ -946,7 +946,7 @@ main(int argc, char **argv)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
 	/* create the mbuf pool */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
@@ -969,7 +969,7 @@ main(int argc, char **argv)
 	/*
 	 * Each logical core is assigned a dedicated TX queue on each port.
 	 */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
 			continue;
@@ -992,7 +992,7 @@ main(int argc, char **argv)
 	qconf = NULL;
 
 	/* Initialize the port/queue configuration of each logical core */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct lcore_resource_struct *res;
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
@@ -1025,10 +1025,8 @@ main(int argc, char **argv)
 		printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
 	}
 
-	nb_ports_available = nb_ports;
-
 	/* Initialise each port */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_rxconf rxq_conf;
 		struct rte_eth_txconf txq_conf;
 		struct rte_eth_conf local_port_conf = port_conf;
@@ -1036,9 +1034,9 @@ main(int argc, char **argv)
 		/* skip ports that are not enabled */
 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
 			printf("Skipping disabled port %u\n", (unsigned) portid);
-			nb_ports_available--;
 			continue;
 		}
+		nb_ports_available++;
 		/* init port */
 		printf("Initializing port %u... ", (unsigned) portid);
 		fflush(stdout);
@@ -1129,7 +1127,7 @@ main(int argc, char **argv)
 			"All available ports are disabled. Please set portmask.\n");
 	}
 
-	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+	check_all_ports_link_status(l2fwd_enabled_port_mask);
 
 	/* Record pair lcore */
 	/**
@@ -1140,7 +1138,7 @@ main(int argc, char **argv)
 	 * procedure completed. So, record the pair relationship for those lcores working
 	 * on ports.
 	 **/
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		uint32_t pair_port;
 		unsigned lcore = 0, pair_lcore = 0;
 		unsigned j, find_lcore, find_pair_lcore;
diff --git a/examples/multi_process/symmetric_mp/Makefile b/examples/multi_process/symmetric_mp/Makefile
index 6fb9cc366..6c0fcb55b 100644
--- a/examples/multi_process/symmetric_mp/Makefile
+++ b/examples/multi_process/symmetric_mp/Makefile
@@ -16,6 +16,7 @@ APP = symmetric_mp
 # all source are stored in SRCS-y
 SRCS-y := main.c
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/multi_process/symmetric_mp/main.c b/examples/multi_process/symmetric_mp/main.c
index 1ada4ef51..2fbf08803 100644
--- a/examples/multi_process/symmetric_mp/main.c
+++ b/examples/multi_process/symmetric_mp/main.c
@@ -115,7 +115,7 @@ smp_parse_args(int argc, char **argv)
 	int opt, ret;
 	char **argvopt;
 	int option_index;
-	unsigned i, port_mask = 0;
+	uint16_t i, port_mask = 0;
 	char *prgname = argv[0];
 	static struct option lgopts[] = {
 			{PARAM_NUM_PROCS, 1, 0, 0},
@@ -156,7 +156,7 @@ smp_parse_args(int argc, char **argv)
 		smp_usage(prgname, "Invalid or missing port mask\n");
 
 	/* get the port numbers from the port mask */
-	for(i = 0; i < rte_eth_dev_count(); i++)
+	RTE_ETH_FOREACH_DEV(i)
 		if(port_mask & (1 << i))
 			ports[num_ports++] = (uint8_t)i;
 
diff --git a/examples/packet_ordering/Makefile b/examples/packet_ordering/Makefile
index 3cf1ee1dc..5eb503c25 100644
--- a/examples/packet_ordering/Makefile
+++ b/examples/packet_ordering/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/packet_ordering/main.c b/examples/packet_ordering/main.c
index 97a58ddaf..964e23c2e 100644
--- a/examples/packet_ordering/main.c
+++ b/examples/packet_ordering/main.c
@@ -211,11 +211,10 @@ flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
 
 static inline int
 free_tx_buffers(struct rte_eth_dev_tx_buffer *tx_buffer[]) {
-	const uint8_t nb_ports = rte_eth_dev_count();
-	unsigned port_id;
+	uint16_t port_id;
 
 	/* initialize buffers for all ports */
-	for (port_id = 0; port_id < nb_ports; port_id++) {
+	RTE_ETH_FOREACH_DEV(port_id) {
 		/* skip ports that are not enabled */
 		if ((portmask & (1 << port_id)) == 0)
 			continue;
@@ -228,12 +227,11 @@ free_tx_buffers(struct rte_eth_dev_tx_buffer *tx_buffer[]) {
 static inline int
 configure_tx_buffers(struct rte_eth_dev_tx_buffer *tx_buffer[])
 {
-	const uint8_t nb_ports = rte_eth_dev_count();
-	unsigned port_id;
+	uint16_t port_id;
 	int ret;
 
 	/* initialize buffers for all ports */
-	for (port_id = 0; port_id < nb_ports; port_id++) {
+	RTE_ETH_FOREACH_DEV(port_id) {
 		/* skip ports that are not enabled */
 		if ((portmask & (1 << port_id)) == 0)
 			continue;
@@ -325,8 +323,7 @@ configure_eth_port(uint16_t port_id)
 static void
 print_stats(void)
 {
-	const uint8_t nb_ports = rte_eth_dev_count();
-	unsigned i;
+	uint16_t i;
 	struct rte_eth_stats eth_stats;
 
 	printf("\nRX thread stats:\n");
@@ -355,7 +352,7 @@ print_stats(void)
 	printf(" - Pkts tx failed w/o reorder:		%"PRIu64"\n",
 						app_stats.tx.early_pkts_tx_failed_woro);
 
-	for (i = 0; i < nb_ports; i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		rte_eth_stats_get(i, &eth_stats);
 		printf("\nPort %u stats:\n", i);
 		printf(" - Pkts in:   %"PRIu64"\n", eth_stats.ipackets);
@@ -383,7 +380,6 @@ int_handler(int sig_num)
 static int
 rx_thread(struct rte_ring *ring_out)
 {
-	const uint8_t nb_ports = rte_eth_dev_count();
 	uint32_t seqn = 0;
 	uint16_t i, ret = 0;
 	uint16_t nb_rx_pkts;
@@ -395,7 +391,7 @@ rx_thread(struct rte_ring *ring_out)
 
 	while (!quit_signal) {
 
-		for (port_id = 0; port_id < nb_ports; port_id++) {
+		RTE_ETH_FOREACH_DEV(port_id) {
 			if ((portmask & (1 << port_id)) != 0) {
 
 				/* receive packets */
@@ -665,7 +661,7 @@ main(int argc, char **argv)
 	nb_ports_available = nb_ports;
 
 	/* initialize all ports */
-	for (port_id = 0; port_id < nb_ports; port_id++) {
+	RTE_ETH_FOREACH_DEV(port_id) {
 		/* skip ports that are not enabled */
 		if ((portmask & (1 << port_id)) == 0) {
 			printf("\nSkipping disabled port %d\n", port_id);
diff --git a/examples/packet_ordering/meson.build b/examples/packet_ordering/meson.build
index 6c2fccdcb..a3776946f 100644
--- a/examples/packet_ordering/meson.build
+++ b/examples/packet_ordering/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += 'reorder'
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/performance-thread/l3fwd-thread/Makefile b/examples/performance-thread/l3fwd-thread/Makefile
index 5558043f2..5ac543645 100644
--- a/examples/performance-thread/l3fwd-thread/Makefile
+++ b/examples/performance-thread/l3fwd-thread/Makefile
@@ -18,6 +18,7 @@ SRCS-y := main.c
 
 include $(RTE_SDK)/examples/performance-thread/common/common.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3 -g $(USER_FLAGS) $(INCLUDES) $(WERROR_FLAGS)
 
 # workaround for a gcc bug with noreturn attribute
diff --git a/examples/performance-thread/l3fwd-thread/main.c b/examples/performance-thread/l3fwd-thread/main.c
index c04294cfd..4fafed16d 100644
--- a/examples/performance-thread/l3fwd-thread/main.c
+++ b/examples/performance-thread/l3fwd-thread/main.c
@@ -3411,7 +3411,7 @@ init_mem(unsigned nb_mbuf)
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -3423,7 +3423,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -3522,7 +3522,7 @@ main(int argc, char **argv)
 	nb_lcores = rte_lcore_count();
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct rte_eth_conf local_port_conf = port_conf;
 
 		/* skip ports that are not enabled */
@@ -3654,7 +3654,7 @@ main(int argc, char **argv)
 	printf("\n");
 
 	/* start ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0)
 			continue;
 
@@ -3699,7 +3699,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 
 	if (lthreads_on) {
 		printf("Starting L-Threading Model\n");
diff --git a/examples/ptpclient/Makefile b/examples/ptpclient/Makefile
index 989e2dd40..1c1d9cdbb 100644
--- a/examples/ptpclient/Makefile
+++ b/examples/ptpclient/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/ptpclient/meson.build b/examples/ptpclient/meson.build
index fa0cbe93c..d4171a218 100644
--- a/examples/ptpclient/meson.build
+++ b/examples/ptpclient/meson.build
@@ -6,6 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
+allow_experimental_apis = true
 sources = files(
 	'ptpclient.c'
 )
diff --git a/examples/ptpclient/ptpclient.c b/examples/ptpclient/ptpclient.c
index 83821eb8d..ad98a392f 100644
--- a/examples/ptpclient/ptpclient.c
+++ b/examples/ptpclient/ptpclient.c
@@ -737,7 +737,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* Initialize all ports. */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if ((ptp_enabled_port_mask & (1 << portid)) != 0) {
 			if (port_init(portid, mbuf_pool) == 0) {
 				ptp_enabled_ports[ptp_enabled_port_nb] = portid;
diff --git a/examples/rxtx_callbacks/Makefile b/examples/rxtx_callbacks/Makefile
index e9d30d56f..c72ba66d6 100644
--- a/examples/rxtx_callbacks/Makefile
+++ b/examples/rxtx_callbacks/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS)
 
 # workaround for a gcc bug with noreturn attribute
diff --git a/examples/rxtx_callbacks/main.c b/examples/rxtx_callbacks/main.c
index d2e5e19e6..46dacc7ef 100644
--- a/examples/rxtx_callbacks/main.c
+++ b/examples/rxtx_callbacks/main.c
@@ -24,8 +24,6 @@ static const struct rte_eth_conf port_conf_default = {
 	},
 };
 
-static unsigned nb_ports;
-
 static struct {
 	uint64_t total_cycles;
 	uint64_t total_pkts;
@@ -145,7 +143,7 @@ lcore_main(void)
 {
 	uint16_t port;
 
-	for (port = 0; port < nb_ports; port++)
+	RTE_ETH_FOREACH_DEV(port)
 		if (rte_eth_dev_socket_id(port) > 0 &&
 				rte_eth_dev_socket_id(port) !=
 						(int)rte_socket_id())
@@ -156,7 +154,7 @@ lcore_main(void)
 	printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
 			rte_lcore_id());
 	for (;;) {
-		for (port = 0; port < nb_ports; port++) {
+		RTE_ETH_FOREACH_DEV(port) {
 			struct rte_mbuf *bufs[BURST_SIZE];
 			const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
 					bufs, BURST_SIZE);
@@ -179,6 +177,7 @@ int
 main(int argc, char *argv[])
 {
 	struct rte_mempool *mbuf_pool;
+	uint16_t nb_ports;
 	uint16_t portid;
 
 	/* init EAL */
@@ -200,7 +199,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++)
+	RTE_ETH_FOREACH_DEV(portid)
 		if (port_init(portid, mbuf_pool) != 0)
 			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8"\n",
 					portid);
diff --git a/examples/rxtx_callbacks/meson.build b/examples/rxtx_callbacks/meson.build
index c34e11e36..2b0a25036 100644
--- a/examples/rxtx_callbacks/meson.build
+++ b/examples/rxtx_callbacks/meson.build
@@ -6,6 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/skeleton/Makefile b/examples/skeleton/Makefile
index bd980ec9b..a4a1860cb 100644
--- a/examples/skeleton/Makefile
+++ b/examples/skeleton/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS)
 
 # workaround for a gcc bug with noreturn attribute
diff --git a/examples/skeleton/basicfwd.c b/examples/skeleton/basicfwd.c
index e62cc0a59..11a9b5747 100644
--- a/examples/skeleton/basicfwd.c
+++ b/examples/skeleton/basicfwd.c
@@ -106,14 +106,13 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 static __attribute__((noreturn)) void
 lcore_main(void)
 {
-	const uint16_t nb_ports = rte_eth_dev_count();
 	uint16_t port;
 
 	/*
 	 * Check that the port is on the same NUMA node as the polling thread
 	 * for best performance.
 	 */
-	for (port = 0; port < nb_ports; port++)
+	RTE_ETH_FOREACH_DEV(port)
 		if (rte_eth_dev_socket_id(port) > 0 &&
 				rte_eth_dev_socket_id(port) !=
 						(int)rte_socket_id())
@@ -130,7 +129,7 @@ lcore_main(void)
 		 * Receive packets on a port and forward them on the paired
 		 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
 		 */
-		for (port = 0; port < nb_ports; port++) {
+		RTE_ETH_FOREACH_DEV(port) {
 
 			/* Get burst of RX packets, from first port of pair. */
 			struct rte_mbuf *bufs[BURST_SIZE];
@@ -186,7 +185,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* Initialize all ports. */
-	for (portid = 0; portid < nb_ports; portid++)
+	RTE_ETH_FOREACH_DEV(portid)
 		if (port_init(portid, mbuf_pool) != 0)
 			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n",
 					portid);
diff --git a/examples/skeleton/meson.build b/examples/skeleton/meson.build
index 9bb9ec329..ef46b187e 100644
--- a/examples/skeleton/meson.build
+++ b/examples/skeleton/meson.build
@@ -6,6 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
+allow_experimental_apis = true
 sources = files(
 	'basicfwd.c'
 )
diff --git a/examples/tep_termination/Makefile b/examples/tep_termination/Makefile
index d2c357a1c..2b93446c0 100644
--- a/examples/tep_termination/Makefile
+++ b/examples/tep_termination/Makefile
@@ -25,6 +25,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -55,6 +57,7 @@ $(error This application can only operate in a linuxapp environment, \
 please change the definition of the RTE_TARGET environment variable)
 endif
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -D_GNU_SOURCE
diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index 270739138..cc12cd87a 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -1185,7 +1185,7 @@ main(int argc, char *argv[])
 		vpool_array[queue_id].pool = mbuf_pool;
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			RTE_LOG(INFO, VHOST_PORT,
diff --git a/examples/tep_termination/meson.build b/examples/tep_termination/meson.build
index 68c940aab..24697ec6d 100644
--- a/examples/tep_termination/meson.build
+++ b/examples/tep_termination/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['hash', 'vhost']
+allow_experimental_apis = true
 sources = files(
 	'main.c', 'vxlan.c', 'vxlan_setup.c'
 )
diff --git a/examples/vhost/Makefile b/examples/vhost/Makefile
index 2dc62ebf0..67cc55b1b 100644
--- a/examples/vhost/Makefile
+++ b/examples/vhost/Makefile
@@ -25,6 +25,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -56,6 +58,7 @@ please change the definition of the RTE_TARGET environment variable)
 all:
 else
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O2 -D_FILE_OFFSET_BITS=64
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -D_GNU_SOURCE
diff --git a/examples/vhost/main.c b/examples/vhost/main.c
index 60d862b42..0b5221f1e 100644
--- a/examples/vhost/main.c
+++ b/examples/vhost/main.c
@@ -1477,7 +1477,7 @@ main(int argc, char *argv[])
 	}
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			RTE_LOG(INFO, VHOST_PORT,
diff --git a/examples/vhost/meson.build b/examples/vhost/meson.build
index 3e6e69047..64c84ee12 100644
--- a/examples/vhost/meson.build
+++ b/examples/vhost/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += 'vhost'
+allow_experimental_apis = true
 sources = files(
 	'main.c', 'virtio_net.c'
 )
diff --git a/examples/vm_power_manager/Makefile b/examples/vm_power_manager/Makefile
index ef2a9f959..608d0d9f4 100644
--- a/examples/vm_power_manager/Makefile
+++ b/examples/vm_power_manager/Makefile
@@ -21,6 +21,7 @@ APP = vm_power_mgr
 SRCS-y := main.c vm_power_cli.c power_manager.c channel_manager.c
 SRCS-y += channel_monitor.c
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3 -I$(RTE_SDK)/lib/librte_power/
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/vm_power_manager/channel_monitor.c b/examples/vm_power_manager/channel_monitor.c
index 1c7b6eb2d..73bddd993 100644
--- a/examples/vm_power_manager/channel_monitor.c
+++ b/examples/vm_power_manager/channel_monitor.c
@@ -110,12 +110,11 @@ static int
 get_pfid(struct policy *pol)
 {
 
-	int i, x, ret = 0, nb_ports;
+	int i, x, ret = 0;
 
-	nb_ports = rte_eth_dev_count();
 	for (i = 0; i < pol->pkt.nb_mac_to_monitor; i++) {
 
-		for (x = 0; x < nb_ports; x++) {
+		RTE_ETH_FOREACH_DEV(x) {
 			ret = rte_pmd_i40e_query_vfid_by_mac(x,
 				(struct ether_addr *)&(pol->pkt.vfid[i]));
 			if (ret != -EINVAL) {
diff --git a/examples/vm_power_manager/main.c b/examples/vm_power_manager/main.c
index 8a1e95bd7..4cde828f9 100644
--- a/examples/vm_power_manager/main.c
+++ b/examples/vm_power_manager/main.c
@@ -176,7 +176,7 @@ parse_args(int argc, char **argv)
 }
 
 static void
-check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -189,7 +189,7 @@ check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 		if (force_quit)
 			return;
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		RTE_ETH_FOREACH_DEV(portid) {
 			if (force_quit)
 				return;
 			if ((port_mask & (1 << portid)) == 0)
@@ -287,7 +287,7 @@ main(int argc, char **argv)
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* Initialize ports. */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		struct ether_addr eth;
 		int w, j;
 		int ret;
@@ -339,7 +339,7 @@ main(int argc, char **argv)
 		return 0;
 	}
 
-	check_all_ports_link_status(nb_ports, enabled_port_mask);
+	check_all_ports_link_status(enabled_port_mask);
 	rte_eal_remote_launch(run_monitor, NULL, lcore_id);
 
 	if (power_manager_init() < 0) {
diff --git a/examples/vmdq/Makefile b/examples/vmdq/Makefile
index 87abeab93..e2d114919 100644
--- a/examples/vmdq/Makefile
+++ b/examples/vmdq/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS)
 
 EXTRA_CFLAGS += -O3
diff --git a/examples/vmdq/main.c b/examples/vmdq/main.c
index d94a18314..72845241e 100644
--- a/examples/vmdq/main.c
+++ b/examples/vmdq/main.c
@@ -600,7 +600,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			printf("\nSkipping disabled port %d\n", portid);
diff --git a/examples/vmdq/meson.build b/examples/vmdq/meson.build
index c34e11e36..2b0a25036 100644
--- a/examples/vmdq/meson.build
+++ b/examples/vmdq/meson.build
@@ -6,6 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/vmdq_dcb/Makefile b/examples/vmdq_dcb/Makefile
index bf161cb2b..3bd80a023 100644
--- a/examples/vmdq_dcb/Makefile
+++ b/examples/vmdq_dcb/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS)
 
 # workaround for a gcc bug with noreturn attribute
diff --git a/examples/vmdq_dcb/main.c b/examples/vmdq_dcb/main.c
index bfe72f8c8..2016a9571 100644
--- a/examples/vmdq_dcb/main.c
+++ b/examples/vmdq_dcb/main.c
@@ -662,7 +662,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
 
 	/* initialize all ports */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		/* skip ports that are not enabled */
 		if ((enabled_port_mask & (1 << portid)) == 0) {
 			printf("\nSkipping disabled port %d\n", portid);
diff --git a/examples/vmdq_dcb/meson.build b/examples/vmdq_dcb/meson.build
index c34e11e36..2b0a25036 100644
--- a/examples/vmdq_dcb/meson.build
+++ b/examples/vmdq_dcb/meson.build
@@ -6,6 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/lib/librte_eventdev/rte_event_eth_rx_adapter.c b/lib/librte_eventdev/rte_event_eth_rx_adapter.c
index 9aece9f8c..9297f4c4d 100644
--- a/lib/librte_eventdev/rte_event_eth_rx_adapter.c
+++ b/lib/librte_eventdev/rte_event_eth_rx_adapter.c
@@ -213,7 +213,7 @@ eth_poll_wrr_calc(struct rte_event_eth_rx_adapter *rx_adapter)
 		/* Generate array of all queues to poll, the size of this
 		 * array is poll_q
 		 */
-		for (d = 0; d < rte_eth_dev_count(); d++) {
+		RTE_ETH_FOREACH_DEV(d) {
 			uint16_t nb_rx_queues;
 			struct eth_device_info *dev_info =
 					&rx_adapter->eth_devices[d];
@@ -813,7 +813,7 @@ rx_adapter_ctrl(uint8_t id, int start)
 
 	dev = &rte_eventdevs[rx_adapter->eventdev_id];
 
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		dev_info = &rx_adapter->eth_devices[i];
 		/* if start  check for num dev queues */
 		if (start && !dev_info->nb_dev_queues)
@@ -903,7 +903,7 @@ rte_event_eth_rx_adapter_create_ext(uint8_t id, uint8_t dev_id,
 		return -ENOMEM;
 	}
 	rte_spinlock_init(&rx_adapter->rx_lock);
-	for (i = 0; i < rte_eth_dev_count(); i++)
+	RTE_ETH_FOREACH_DEV(i)
 		rx_adapter->eth_devices[i].dev = &rte_eth_devices[i];
 
 	event_eth_rx_adapter[id] = rx_adapter;
@@ -1174,7 +1174,7 @@ rte_event_eth_rx_adapter_stats_get(uint8_t id,
 
 	dev = &rte_eventdevs[rx_adapter->eventdev_id];
 	memset(stats, 0, sizeof(*stats));
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		dev_info = &rx_adapter->eth_devices[i];
 		if (dev_info->internal_event_port == 0 ||
 			dev->dev_ops->eth_rx_adapter_stats_get == NULL)
@@ -1211,7 +1211,7 @@ rte_event_eth_rx_adapter_stats_reset(uint8_t id)
 		return -EINVAL;
 
 	dev = &rte_eventdevs[rx_adapter->eventdev_id];
-	for (i = 0; i < rte_eth_dev_count(); i++) {
+	RTE_ETH_FOREACH_DEV(i) {
 		dev_info = &rx_adapter->eth_devices[i];
 		if (dev_info->internal_event_port == 0 ||
 			dev->dev_ops->eth_rx_adapter_stats_reset == NULL)
diff --git a/lib/librte_latencystats/Makefile b/lib/librte_latencystats/Makefile
index ae0dbd8f0..8884045c0 100644
--- a/lib/librte_latencystats/Makefile
+++ b/lib/librte_latencystats/Makefile
@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 # library name
 LIB = librte_latencystats.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 LDLIBS += -lm
 LDLIBS += -lpthread
diff --git a/lib/librte_latencystats/meson.build b/lib/librte_latencystats/meson.build
index 286558dd7..0c96e1287 100644
--- a/lib/librte_latencystats/meson.build
+++ b/lib/librte_latencystats/meson.build
@@ -4,3 +4,4 @@
 sources = files('rte_latencystats.c')
 headers = files('rte_latencystats.h')
 deps += ['metrics', 'ethdev']
+allow_experimental_apis = true
diff --git a/lib/librte_latencystats/rte_latencystats.c b/lib/librte_latencystats/rte_latencystats.c
index fc9497659..46c69bf05 100644
--- a/lib/librte_latencystats/rte_latencystats.c
+++ b/lib/librte_latencystats/rte_latencystats.c
@@ -201,7 +201,6 @@ rte_latencystats_init(uint64_t app_samp_intvl,
 	uint16_t pid;
 	uint16_t qid;
 	struct rxtx_cbs *cbs = NULL;
-	const uint16_t nb_ports = rte_eth_dev_count();
 	const char *ptr_strings[NUM_LATENCY_STATS] = {0};
 	const struct rte_memzone *mz = NULL;
 	const unsigned int flags = 0;
@@ -234,7 +233,7 @@ rte_latencystats_init(uint64_t app_samp_intvl,
 	}
 
 	/** Register Rx/Tx callbacks */
-	for (pid = 0; pid < nb_ports; pid++) {
+	RTE_ETH_FOREACH_DEV(pid) {
 		struct rte_eth_dev_info dev_info;
 		rte_eth_dev_info_get(pid, &dev_info);
 		for (qid = 0; qid < dev_info.nb_rx_queues; qid++) {
@@ -266,10 +265,9 @@ rte_latencystats_uninit(void)
 	uint16_t qid;
 	int ret = 0;
 	struct rxtx_cbs *cbs = NULL;
-	const uint16_t nb_ports = rte_eth_dev_count();
 
 	/** De register Rx/Tx callbacks */
-	for (pid = 0; pid < nb_ports; pid++) {
+	RTE_ETH_FOREACH_DEV(pid) {
 		struct rte_eth_dev_info dev_info;
 		rte_eth_dev_info_get(pid, &dev_info);
 		for (qid = 0; qid < dev_info.nb_rx_queues; qid++) {
diff --git a/test/test/test_event_eth_rx_adapter.c b/test/test/test_event_eth_rx_adapter.c
index 006ed3149..1b913a25f 100644
--- a/test/test/test_event_eth_rx_adapter.c
+++ b/test/test/test_event_eth_rx_adapter.c
@@ -119,7 +119,7 @@ init_ports(int num_ports)
 	if (!default_params.mp)
 		return -ENOMEM;
 
-	for (portid = 0; portid < num_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		retval = port_init(portid, default_params.mp);
 		if (retval)
 			return retval;
@@ -179,7 +179,7 @@ static void
 testsuite_teardown(void)
 {
 	uint32_t i;
-	for (i = 0; i < rte_eth_dev_count(); i++)
+	RTE_ETH_FOREACH_DEV(i)
 		rte_eth_dev_stop(i);
 
 	rte_mempool_free(default_params.mp);
diff --git a/test/test/test_pmd_perf.c b/test/test/test_pmd_perf.c
index 911dd762c..0e64a581b 100644
--- a/test/test/test_pmd_perf.c
+++ b/test/test/test_pmd_perf.c
@@ -698,7 +698,7 @@ test_pmd_perf(void)
 
 	reset_count();
 	num = 0;
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if (socketid == -1) {
 			socketid = rte_eth_dev_socket_id(portid);
 			slave_id = alloc_lcore(socketid);
@@ -791,7 +791,7 @@ test_pmd_perf(void)
 			return -1;
 
 	/* port tear down */
-	for (portid = 0; portid < nb_ports; portid++) {
+	RTE_ETH_FOREACH_DEV(portid) {
 		if (socketid != rte_eth_dev_socket_id(portid))
 			continue;
 
diff --git a/test/test/test_pmd_ring.c b/test/test/test_pmd_ring.c
index 4b8910149..0787e4ebf 100644
--- a/test/test/test_pmd_ring.c
+++ b/test/test/test_pmd_ring.c
@@ -473,7 +473,7 @@ test_pmd_ring(void)
 		return -1;
 
 	/* find a port created with the --vdev=net_ring0 command line option */
-	for (port = 0; port < nb_ports; port++) {
+	RTE_ETH_FOREACH_DEV(port) {
 		struct rte_eth_dev_info dev_info;
 
 		rte_eth_dev_info_get(port, &dev_info);
-- 
2.16.2

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dpdk-dev] [PATCH v2 2/3] fix ethdev port id validation
  2018-04-05 15:33 ` [dpdk-dev] [PATCH v2 0/3] " Thomas Monjalon
  2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 1/3] fix ethdev " Thomas Monjalon
@ 2018-04-05 15:33   ` Thomas Monjalon
  2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 3/3] ethdev: deprecate port count function Thomas Monjalon
  2018-04-17 22:22   ` [dpdk-dev] [PATCH v2 0/3] ethdev: fix ports enumeration Thomas Monjalon
  3 siblings, 0 replies; 6+ messages in thread
From: Thomas Monjalon @ 2018-04-05 15:33 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit

Some DPDK applications wrongly assume these requirements:
    - no hotplug, i.e. ports are never detached
    - all allocated ports are available to the application

Such application assume a valid port index is in the range [0..count[.

There are three consequences when using such wrong design:
    - new ports having an index higher than the port count won't be valid
    - old ports being detached (RTE_ETH_DEV_UNUSED) can be valid

Such mistake will be less common with growing hotplug awareness.
All applications and examples inside this repository - except testpmd -
must be fixed to use the function rte_eth_dev_is_valid_port.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 app/pdump/main.c                                   |  3 +-
 app/test-pmd/cmdline.c                             | 51 ----------------------
 doc/guides/sample_app_ug/flow_classify.rst         |  3 --
 doc/guides/sample_app_ug/kernel_nic_interface.rst  | 10 -----
 doc/guides/sample_app_ug/l2_forward_job_stats.rst  |  5 ---
 .../sample_app_ug/l2_forward_real_virtual.rst      |  5 ---
 doc/guides/sample_app_ug/link_status_intr.rst      |  4 --
 doc/guides/sample_app_ug/rxtx_callbacks.rst        |  3 --
 doc/guides/sample_app_ug/skeleton.rst              |  3 +-
 examples/bbdev_app/main.c                          | 10 ++---
 examples/bond/main.c                               |  2 +-
 examples/distributor/main.c                        |  2 +-
 examples/eventdev_pipeline/main.c                  |  2 +-
 examples/flow_classify/flow_classify.c             |  2 +-
 examples/ip_pipeline/init.c                        |  4 +-
 examples/ipsec-secgw/ipsec-secgw.c                 |  6 +--
 examples/kni/main.c                                |  8 ++--
 examples/l2fwd-cat/l2fwd-cat.c                     |  2 +-
 examples/l3fwd-acl/main.c                          |  6 +--
 examples/l3fwd-power/main.c                        |  6 +--
 examples/l3fwd-vf/main.c                           |  6 +--
 examples/l3fwd/main.c                              |  6 +--
 examples/multi_process/symmetric_mp/main.c         |  2 +-
 examples/packet_ordering/main.c                    |  3 +-
 examples/performance-thread/l3fwd-thread/main.c    |  6 +--
 examples/ptpclient/ptpclient.c                     |  2 +-
 examples/rxtx_callbacks/main.c                     |  2 +-
 examples/skeleton/basicfwd.c                       |  2 +-
 examples/tep_termination/main.c                    |  7 ++-
 examples/tep_termination/vxlan_setup.c             |  2 +-
 examples/vhost/main.c                              | 10 +++--
 examples/vm_power_manager/main.c                   |  2 +-
 examples/vmdq/main.c                               |  8 ++--
 examples/vmdq_dcb/main.c                           |  8 ++--
 lib/librte_kni/rte_kni.c                           |  4 +-
 test/test/test_event_eth_rx_adapter.c              |  2 +-
 36 files changed, 61 insertions(+), 148 deletions(-)

diff --git a/app/pdump/main.c b/app/pdump/main.c
index d29de0321..457747f0f 100644
--- a/app/pdump/main.c
+++ b/app/pdump/main.c
@@ -553,11 +553,10 @@ configure_vdev(uint16_t port_id)
 {
 	struct ether_addr addr;
 	const uint16_t rxRings = 0, txRings = 1;
-	const uint8_t nb_ports = rte_eth_dev_count();
 	int ret;
 	uint16_t q;
 
-	if (port_id > nb_ports)
+	if (!rte_eth_dev_is_valid_port(port_id))
 		return -1;
 
 	ret = rte_eth_dev_configure(port_id, rxRings, txRings,
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 91b1ad340..f22fa935c 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -5511,11 +5511,6 @@ static void cmd_set_bond_mon_period_parsed(void *parsed_result,
 	struct cmd_set_bond_mon_period_result *res = parsed_result;
 	int ret;
 
-	if (res->port_num >= nb_ports) {
-		printf("Port id %d must be less than %d\n", res->port_num, nb_ports);
-		return;
-	}
-
 	ret = rte_eth_bond_link_monitoring_set(res->port_num, res->period_ms);
 
 	/* check the return value and print it if is < 0 */
@@ -5572,12 +5567,6 @@ cmd_set_bonding_agg_mode(void *parsed_result,
 	struct cmd_set_bonding_agg_mode_policy_result *res = parsed_result;
 	uint8_t policy = AGG_BANDWIDTH;
 
-	if (res->port_num >= nb_ports) {
-		printf("Port id %d must be less than %d\n",
-				res->port_num, nb_ports);
-		return;
-	}
-
 	if (!strcmp(res->policy, "bandwidth"))
 		policy = AGG_BANDWIDTH;
 	else if (!strcmp(res->policy, "stable"))
@@ -10725,11 +10714,6 @@ cmd_flow_director_mask_parsed(void *parsed_result,
 	struct rte_eth_fdir_masks *mask;
 	struct rte_port *port;
 
-	if (res->port_id > nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
-		return;
-	}
-
 	port = &ports[res->port_id];
 	/** Check if the port is not started **/
 	if (port->port_status != RTE_PORT_STOPPED) {
@@ -10926,11 +10910,6 @@ cmd_flow_director_flex_mask_parsed(void *parsed_result,
 	uint16_t i;
 	int ret;
 
-	if (res->port_id > nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
-		return;
-	}
-
 	port = &ports[res->port_id];
 	/** Check if the port is not started **/
 	if (port->port_status != RTE_PORT_STOPPED) {
@@ -11082,11 +11061,6 @@ cmd_flow_director_flxpld_parsed(void *parsed_result,
 	struct rte_port *port;
 	int ret = 0;
 
-	if (res->port_id > nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
-		return;
-	}
-
 	port = &ports[res->port_id];
 	/** Check if the port is not started **/
 	if (port->port_status != RTE_PORT_STOPPED) {
@@ -14467,11 +14441,6 @@ cmd_ddp_add_parsed(
 	int file_num;
 	int ret = -ENOTSUP;
 
-	if (res->port_id > nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
-		return;
-	}
-
 	if (!all_ports_stopped()) {
 		printf("Please stop all ports first\n");
 		return;
@@ -14549,11 +14518,6 @@ cmd_ddp_del_parsed(
 	uint32_t size;
 	int ret = -ENOTSUP;
 
-	if (res->port_id > nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
-		return;
-	}
-
 	if (!all_ports_stopped()) {
 		printf("Please stop all ports first\n");
 		return;
@@ -14864,11 +14828,6 @@ cmd_ddp_get_list_parsed(
 #endif
 	int ret = -ENOTSUP;
 
-	if (res->port_id > nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
-		return;
-	}
-
 #ifdef RTE_LIBRTE_I40E_PMD
 	size = PROFILE_INFO_SIZE * MAX_PROFILE_NUM + 4;
 	p_list = (struct rte_pmd_i40e_profile_list *)malloc(size);
@@ -14942,11 +14901,6 @@ cmd_cfg_input_set_parsed(
 #endif
 	int ret = -ENOTSUP;
 
-	if (res->port_id > nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
-		return;
-	}
-
 	if (!all_ports_stopped()) {
 		printf("Please stop all ports first\n");
 		return;
@@ -15070,11 +15024,6 @@ cmd_clear_input_set_parsed(
 #endif
 	int ret = -ENOTSUP;
 
-	if (res->port_id > nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
-		return;
-	}
-
 	if (!all_ports_stopped()) {
 		printf("Please stop all ports first\n");
 		return;
diff --git a/doc/guides/sample_app_ug/flow_classify.rst b/doc/guides/sample_app_ug/flow_classify.rst
index a0095962c..003ed0356 100644
--- a/doc/guides/sample_app_ug/flow_classify.rst
+++ b/doc/guides/sample_app_ug/flow_classify.rst
@@ -279,9 +279,6 @@ Forwarding application is shown below:
         int retval;
         uint16_t q;
 
-        if (port >= rte_eth_dev_count())
-            return -1;
-
         /* Configure the Ethernet device. */
         retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
         if (retval != 0)
diff --git a/doc/guides/sample_app_ug/kernel_nic_interface.rst b/doc/guides/sample_app_ug/kernel_nic_interface.rst
index 580d06b5b..fc110997f 100644
--- a/doc/guides/sample_app_ug/kernel_nic_interface.rst
+++ b/doc/guides/sample_app_ug/kernel_nic_interface.rst
@@ -511,11 +511,6 @@ Application may choose to not implement following callbacks:
         int ret;
         struct rte_eth_conf conf;
 
-        if (port_id >= rte_eth_dev_count()) {
-            RTE_LOG(ERR, APP, "Invalid port id %d\n", port_id);
-            return -EINVAL;
-        }
-
         RTE_LOG(INFO, APP, "Change MTU of port %d to %u\n", port_id, new_mtu);
 
         /* Stop specific port */
@@ -559,11 +554,6 @@ Application may choose to not implement following callbacks:
     {
         int ret = 0;
 
-        if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) {
-            RTE_LOG(ERR, APP, "Invalid port id %d\n", port_id);
-            return -EINVAL;
-        }
-
         RTE_LOG(INFO, APP, "Configure network interface of %d %s\n",
 
         port_id, if_up ? "up" : "down");
diff --git a/doc/guides/sample_app_ug/l2_forward_job_stats.rst b/doc/guides/sample_app_ug/l2_forward_job_stats.rst
index f14a780ae..d7219a293 100644
--- a/doc/guides/sample_app_ug/l2_forward_job_stats.rst
+++ b/doc/guides/sample_app_ug/l2_forward_job_stats.rst
@@ -178,11 +178,6 @@ in the *DPDK Programmer's Guide* and the *DPDK API Reference*.
 
 .. code-block:: c
 
-    nb_ports = rte_eth_dev_count();
-
-    if (nb_ports == 0)
-        rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
-
     /* reset l2fwd_dst_ports */
 
     for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
diff --git a/doc/guides/sample_app_ug/l2_forward_real_virtual.rst b/doc/guides/sample_app_ug/l2_forward_real_virtual.rst
index c91f57380..b459d4efe 100644
--- a/doc/guides/sample_app_ug/l2_forward_real_virtual.rst
+++ b/doc/guides/sample_app_ug/l2_forward_real_virtual.rst
@@ -197,11 +197,6 @@ in the *DPDK Programmer's Guide* - Rel 1.4 EAR and the *DPDK API Reference*.
     if (rte_pci_probe() < 0)
         rte_exit(EXIT_FAILURE, "Cannot probe PCI\n");
 
-    nb_ports = rte_eth_dev_count();
-
-    if (nb_ports == 0)
-        rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
-
     /* reset l2fwd_dst_ports */
 
     for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
diff --git a/doc/guides/sample_app_ug/link_status_intr.rst b/doc/guides/sample_app_ug/link_status_intr.rst
index 57673456b..8c11ba4ae 100644
--- a/doc/guides/sample_app_ug/link_status_intr.rst
+++ b/doc/guides/sample_app_ug/link_status_intr.rst
@@ -91,10 +91,6 @@ To fully understand this code, it is recommended to study the chapters that rela
     if (rte_pci_probe() < 0)
         rte_exit(EXIT_FAILURE, "Cannot probe PCI\n");
 
-    nb_ports = rte_eth_dev_count();
-    if (nb_ports == 0)
-        rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
-
     /*
      * Each logical core is assigned a dedicated TX queue on each port.
      */
diff --git a/doc/guides/sample_app_ug/rxtx_callbacks.rst b/doc/guides/sample_app_ug/rxtx_callbacks.rst
index 0bb0d3e00..85d96d8a2 100644
--- a/doc/guides/sample_app_ug/rxtx_callbacks.rst
+++ b/doc/guides/sample_app_ug/rxtx_callbacks.rst
@@ -83,9 +83,6 @@ comments:
         int retval;
         uint16_t q;
 
-        if (port >= rte_eth_dev_count())
-            return -1;
-
         /* Configure the Ethernet device. */
         retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
         if (retval != 0)
diff --git a/doc/guides/sample_app_ug/skeleton.rst b/doc/guides/sample_app_ug/skeleton.rst
index d3a3712f4..959561716 100644
--- a/doc/guides/sample_app_ug/skeleton.rst
+++ b/doc/guides/sample_app_ug/skeleton.rst
@@ -119,7 +119,7 @@ Forwarding application is shown below:
         int retval;
         uint16_t q;
 
-        if (port >= rte_eth_dev_count())
+        if (!rte_eth_dev_is_valid_port(port))
             return -1;
 
         /* Configure the Ethernet device. */
@@ -192,7 +192,6 @@ looks like the following:
     static __attribute__((noreturn)) void
     lcore_main(void)
     {
-        const uint16_t nb_ports = rte_eth_dev_count();
         uint16_t port;
 
         /*
diff --git a/examples/bbdev_app/main.c b/examples/bbdev_app/main.c
index 3c4525695..254cc0676 100644
--- a/examples/bbdev_app/main.c
+++ b/examples/bbdev_app/main.c
@@ -1017,7 +1017,7 @@ int
 main(int argc, char **argv)
 {
 	int ret;
-	unsigned int nb_bbdevs, nb_ports, flags, lcore_id;
+	unsigned int nb_bbdevs, flags, lcore_id;
 	void *sigret;
 	struct app_config_params app_params = def_app_config;
 	struct rte_mempool *ethdev_mbuf_mempool, *bbdev_mbuf_mempool;
@@ -1079,12 +1079,10 @@ main(int argc, char **argv)
 				nb_bbdevs, app_params.bbdev_id);
 	printf("Number of bbdevs detected: %d\n", nb_bbdevs);
 
-	/* Get the number of available ethdev devices */
-	nb_ports = rte_eth_dev_count();
-	if (nb_ports <= app_params.port_id)
+	if (!rte_eth_dev_is_valid_port(app_params.port_id))
 		rte_exit(EXIT_FAILURE,
-				"%u ports detected, cannot use port with ID %u!\n",
-				nb_ports, app_params.port_id);
+				"cannot use port with ID %u!\n",
+				app_params.port_id);
 
 	/* create the mbuf mempool for ethdev pkts */
 	ethdev_mbuf_mempool = rte_pktmbuf_pool_create("ethdev_mbuf_pool",
diff --git a/examples/bond/main.c b/examples/bond/main.c
index d68162f1d..d4097d04d 100644
--- a/examples/bond/main.c
+++ b/examples/bond/main.c
@@ -147,7 +147,7 @@ slave_port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
 	struct rte_eth_txconf txq_conf;
 	struct rte_eth_conf local_port_conf = port_conf;
 
-	if (portid >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(portid))
 		rte_exit(EXIT_FAILURE, "Invalid port\n");
 
 	rte_eth_dev_info_get(portid, &dev_info);
diff --git a/examples/distributor/main.c b/examples/distributor/main.c
index 62831a05c..2e6b09d21 100644
--- a/examples/distributor/main.c
+++ b/examples/distributor/main.c
@@ -116,7 +116,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_txconf txconf;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	rte_eth_dev_info_get(port, &dev_info);
diff --git a/examples/eventdev_pipeline/main.c b/examples/eventdev_pipeline/main.c
index bbab99597..48358a7d2 100644
--- a/examples/eventdev_pipeline/main.c
+++ b/examples/eventdev_pipeline/main.c
@@ -285,7 +285,7 @@ port_init(uint8_t port, struct rte_mempool *mbuf_pool)
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_txconf txconf;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	rte_eth_dev_info_get(port, &dev_info);
diff --git a/examples/flow_classify/flow_classify.c b/examples/flow_classify/flow_classify.c
index a65ef20f9..d0e537e7d 100644
--- a/examples/flow_classify/flow_classify.c
+++ b/examples/flow_classify/flow_classify.c
@@ -200,7 +200,7 @@ port_init(uint8_t port, struct rte_mempool *mbuf_pool)
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_txconf txconf;
 
-	if (port >= rte_eth_dev_count())
+	if (rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	rte_eth_dev_info_get(port, &dev_info);
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index bb07efa13..d562da794 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -1213,7 +1213,7 @@ static int
 kni_config_network_interface(uint16_t port_id, uint8_t if_up) {
 	int ret = 0;
 
-	if (port_id >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port_id))
 		return -EINVAL;
 
 	ret = (if_up) ?
@@ -1227,7 +1227,7 @@ static int
 kni_change_mtu(uint16_t port_id, unsigned int new_mtu) {
 	int ret;
 
-	if (port_id >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port_id))
 		return -EINVAL;
 
 	if (new_mtu > ETHER_MAX_LEN)
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 3001d626b..6bbb920f9 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -848,7 +848,7 @@ static int32_t
 check_params(void)
 {
 	uint8_t lcore;
-	uint16_t portid, nb_ports;
+	uint16_t portid;
 	uint16_t i;
 	int32_t socket_id;
 
@@ -857,8 +857,6 @@ check_params(void)
 		return -1;
 	}
 
-	nb_ports = rte_eth_dev_count();
-
 	for (i = 0; i < nb_lcore_params; ++i) {
 		lcore = lcore_params[i].lcore_id;
 		if (!rte_lcore_is_enabled(lcore)) {
@@ -877,7 +875,7 @@ check_params(void)
 			printf("port %u is not enabled in port mask\n", portid);
 			return -1;
 		}
-		if (portid >= nb_ports) {
+		if (!rte_eth_dev_is_valid_port(portid)) {
 			printf("port %u is not present on the board\n", portid);
 			return -1;
 		}
diff --git a/examples/kni/main.c b/examples/kni/main.c
index f069788ce..1855c64ab 100644
--- a/examples/kni/main.c
+++ b/examples/kni/main.c
@@ -689,7 +689,7 @@ kni_change_mtu(uint16_t port_id, unsigned int new_mtu)
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_rxconf rxq_conf;
 
-	if (port_id >= rte_eth_dev_count()) {
+	if (!rte_eth_dev_is_valid_port(port_id)) {
 		RTE_LOG(ERR, APP, "Invalid port id %d\n", port_id);
 		return -EINVAL;
 	}
@@ -748,7 +748,7 @@ kni_config_network_interface(uint16_t port_id, uint8_t if_up)
 {
 	int ret = 0;
 
-	if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) {
+	if (!rte_eth_dev_is_valid_port(port_id)) {
 		RTE_LOG(ERR, APP, "Invalid port id %d\n", port_id);
 		return -EINVAL;
 	}
@@ -782,7 +782,7 @@ kni_config_mac_address(uint16_t port_id, uint8_t mac_addr[])
 {
 	int ret = 0;
 
-	if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) {
+	if (!rte_eth_dev_is_valid_port(port_id)) {
 		RTE_LOG(ERR, APP, "Invalid port id %d\n", port_id);
 		return -EINVAL;
 	}
@@ -927,7 +927,7 @@ main(int argc, char** argv)
 
 	/* Check if the configured port ID is valid */
 	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
-		if (kni_port_params_array[i] && i >= nb_sys_ports)
+		if (kni_port_params_array[i] && !rte_eth_dev_is_valid_port(i))
 			rte_exit(EXIT_FAILURE, "Configured invalid "
 						"port ID %u\n", i);
 
diff --git a/examples/l2fwd-cat/l2fwd-cat.c b/examples/l2fwd-cat/l2fwd-cat.c
index 344292864..ed4878043 100644
--- a/examples/l2fwd-cat/l2fwd-cat.c
+++ b/examples/l2fwd-cat/l2fwd-cat.c
@@ -39,7 +39,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 	uint16_t nb_rxd = RX_RING_SIZE;
 	uint16_t nb_txd = TX_RING_SIZE;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	/* Configure the Ethernet device. */
diff --git a/examples/l3fwd-acl/main.c b/examples/l3fwd-acl/main.c
index 3c547cd8e..2c891b494 100644
--- a/examples/l3fwd-acl/main.c
+++ b/examples/l3fwd-acl/main.c
@@ -1452,7 +1452,7 @@ check_lcore_params(void)
 }
 
 static int
-check_port_config(const unsigned nb_ports)
+check_port_config(void)
 {
 	unsigned portid;
 	uint16_t i;
@@ -1464,7 +1464,7 @@ check_port_config(const unsigned nb_ports)
 			printf("port %u is not enabled in port mask\n", portid);
 			return -1;
 		}
-		if (portid >= nb_ports) {
+		if (!rte_eth_dev_is_valid_port(portid)) {
 			printf("port %u is not present on the board\n", portid);
 			return -1;
 		}
@@ -1893,7 +1893,7 @@ main(int argc, char **argv)
 
 	nb_ports = rte_eth_dev_count();
 
-	if (check_port_config(nb_ports) < 0)
+	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
 
 	/* Add ACL rules and route entries, build trie */
diff --git a/examples/l3fwd-power/main.c b/examples/l3fwd-power/main.c
index 16f4d098c..d6a092618 100644
--- a/examples/l3fwd-power/main.c
+++ b/examples/l3fwd-power/main.c
@@ -1056,7 +1056,7 @@ check_lcore_params(void)
 }
 
 static int
-check_port_config(const unsigned nb_ports)
+check_port_config(void)
 {
 	unsigned portid;
 	uint16_t i;
@@ -1068,7 +1068,7 @@ check_port_config(const unsigned nb_ports)
 								portid);
 			return -1;
 		}
-		if (portid >= nb_ports) {
+		if (!rte_eth_dev_is_valid_port(portid)) {
 			printf("port %u is not present on the board\n",
 								portid);
 			return -1;
@@ -1652,7 +1652,7 @@ main(int argc, char **argv)
 
 	nb_ports = rte_eth_dev_count();
 
-	if (check_port_config(nb_ports) < 0)
+	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
 
 	nb_lcores = rte_lcore_count();
diff --git a/examples/l3fwd-vf/main.c b/examples/l3fwd-vf/main.c
index 7a9927c34..dd0e057ef 100644
--- a/examples/l3fwd-vf/main.c
+++ b/examples/l3fwd-vf/main.c
@@ -575,7 +575,7 @@ check_lcore_params(void)
 }
 
 static int
-check_port_config(const unsigned nb_ports)
+check_port_config(void)
 {
 	unsigned portid;
 	uint16_t i;
@@ -586,7 +586,7 @@ check_port_config(const unsigned nb_ports)
 			printf("port %u is not enabled in port mask\n", portid);
 			return -1;
 		}
-		if (portid >= nb_ports) {
+		if (!rte_eth_dev_is_valid_port(portid)) {
 			printf("port %u is not present on the board\n", portid);
 			return -1;
 		}
@@ -951,7 +951,7 @@ main(int argc, char **argv)
 
 	nb_ports = rte_eth_dev_count();
 
-	if (check_port_config(nb_ports) < 0)
+	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
 
 	nb_lcores = rte_lcore_count();
diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
index 8f7961cec..ec1da5c18 100644
--- a/examples/l3fwd/main.c
+++ b/examples/l3fwd/main.c
@@ -210,7 +210,7 @@ check_lcore_params(void)
 }
 
 static int
-check_port_config(const unsigned nb_ports)
+check_port_config(void)
 {
 	uint16_t portid;
 	uint16_t i;
@@ -221,7 +221,7 @@ check_port_config(const unsigned nb_ports)
 			printf("port %u is not enabled in port mask\n", portid);
 			return -1;
 		}
-		if (portid >= nb_ports) {
+		if (!rte_eth_dev_is_valid_port(portid)) {
 			printf("port %u is not present on the board\n", portid);
 			return -1;
 		}
@@ -828,7 +828,7 @@ main(int argc, char **argv)
 
 	nb_ports = rte_eth_dev_count();
 
-	if (check_port_config(nb_ports) < 0)
+	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
 
 	nb_lcores = rte_lcore_count();
diff --git a/examples/multi_process/symmetric_mp/main.c b/examples/multi_process/symmetric_mp/main.c
index 2fbf08803..75cad0cca 100644
--- a/examples/multi_process/symmetric_mp/main.c
+++ b/examples/multi_process/symmetric_mp/main.c
@@ -204,7 +204,7 @@ smp_port_init(uint16_t port, struct rte_mempool *mbuf_pool,
 	if (rte_eal_process_type() == RTE_PROC_SECONDARY)
 		return 0;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	printf("# Initialising port %u... ", port);
diff --git a/examples/packet_ordering/main.c b/examples/packet_ordering/main.c
index 964e23c2e..676cb6f71 100644
--- a/examples/packet_ordering/main.c
+++ b/examples/packet_ordering/main.c
@@ -261,7 +261,6 @@ configure_eth_port(uint16_t port_id)
 {
 	struct ether_addr addr;
 	const uint16_t rxRings = 1, txRings = 1;
-	const uint8_t nb_ports = rte_eth_dev_count();
 	int ret;
 	uint16_t q;
 	uint16_t nb_rxd = RX_DESC_PER_QUEUE;
@@ -270,7 +269,7 @@ configure_eth_port(uint16_t port_id)
 	struct rte_eth_txconf txconf;
 	struct rte_eth_conf port_conf = port_conf_default;
 
-	if (port_id > nb_ports)
+	if (!rte_eth_dev_is_valid_port(port_id))
 		return -1;
 
 	rte_eth_dev_info_get(port_id, &dev_info);
diff --git a/examples/performance-thread/l3fwd-thread/main.c b/examples/performance-thread/l3fwd-thread/main.c
index 4fafed16d..699b99d00 100644
--- a/examples/performance-thread/l3fwd-thread/main.c
+++ b/examples/performance-thread/l3fwd-thread/main.c
@@ -2491,7 +2491,7 @@ check_lcore_params(void)
 }
 
 static int
-check_port_config(const unsigned nb_ports)
+check_port_config(void)
 {
 	unsigned portid;
 	uint16_t i;
@@ -2502,7 +2502,7 @@ check_port_config(const unsigned nb_ports)
 			printf("port %u is not enabled in port mask\n", portid);
 			return -1;
 		}
-		if (portid >= nb_ports) {
+		if (!rte_eth_dev_is_valid_port(portid)) {
 			printf("port %u is not present on the board\n", portid);
 			return -1;
 		}
@@ -3516,7 +3516,7 @@ main(int argc, char **argv)
 
 	nb_ports = rte_eth_dev_count();
 
-	if (check_port_config(nb_ports) < 0)
+	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
 
 	nb_lcores = rte_lcore_count();
diff --git a/examples/ptpclient/ptpclient.c b/examples/ptpclient/ptpclient.c
index ad98a392f..55be3f7cd 100644
--- a/examples/ptpclient/ptpclient.c
+++ b/examples/ptpclient/ptpclient.c
@@ -187,7 +187,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 	uint16_t nb_rxd = RX_RING_SIZE;
 	uint16_t nb_txd = TX_RING_SIZE;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	rte_eth_dev_info_get(port, &dev_info);
diff --git a/examples/rxtx_callbacks/main.c b/examples/rxtx_callbacks/main.c
index 46dacc7ef..84b09cf05 100644
--- a/examples/rxtx_callbacks/main.c
+++ b/examples/rxtx_callbacks/main.c
@@ -80,7 +80,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_txconf txconf;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	rte_eth_dev_info_get(port, &dev_info);
diff --git a/examples/skeleton/basicfwd.c b/examples/skeleton/basicfwd.c
index 11a9b5747..5ac1dc820 100644
--- a/examples/skeleton/basicfwd.c
+++ b/examples/skeleton/basicfwd.c
@@ -42,7 +42,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_txconf txconf;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	rte_eth_dev_info_get(port, &dev_info);
diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index cc12cd87a..e86854176 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -515,11 +515,10 @@ check_ports_num(unsigned max_nb_ports)
 	}
 
 	for (portid = 0; portid < nb_ports; portid++) {
-		if (ports[portid] >= max_nb_ports) {
+		if (!rte_eth_dev_is_valid_port(ports[portid])) {
 			RTE_LOG(INFO, VHOST_PORT,
-				"\nSpecified port ID(%u) exceeds max "
-				" system port ID(%u)\n",
-				ports[portid], (max_nb_ports - 1));
+				"\nSpecified port ID(%u) is not valid\n",
+				ports[portid]);
 			ports[portid] = INVALID_PORT_ID;
 			valid_nb_ports--;
 		}
diff --git a/examples/tep_termination/vxlan_setup.c b/examples/tep_termination/vxlan_setup.c
index ba7d92aac..299c29d27 100644
--- a/examples/tep_termination/vxlan_setup.c
+++ b/examples/tep_termination/vxlan_setup.c
@@ -133,7 +133,7 @@ vxlan_port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 	txconf = &dev_info.default_txconf;
 	txconf->txq_flags = ETH_TXQ_FLAGS_IGNORE;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	rx_rings = nb_devices;
diff --git a/examples/vhost/main.c b/examples/vhost/main.c
index 0b5221f1e..7cddac7d2 100644
--- a/examples/vhost/main.c
+++ b/examples/vhost/main.c
@@ -294,7 +294,8 @@ port_init(uint16_t port)
 	printf("pf queue num: %u, configured vmdq pool num: %u, each vmdq pool has %u queues\n",
 		num_pf_queues, num_devices, queues_per_pool);
 
-	if (port >= rte_eth_dev_count()) return -1;
+	if (!rte_eth_dev_is_valid_port(port))
+		return -1;
 
 	rx_rings = (uint16_t)dev_info.max_rx_queues;
 	if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
@@ -667,9 +668,10 @@ static unsigned check_ports_num(unsigned nb_ports)
 	}
 
 	for (portid = 0; portid < num_ports; portid ++) {
-		if (ports[portid] >= nb_ports) {
-			RTE_LOG(INFO, VHOST_PORT, "\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
-				ports[portid], (nb_ports - 1));
+		if (!rte_eth_dev_is_valid_port(ports[portid])) {
+			RTE_LOG(INFO, VHOST_PORT,
+				"\nSpecified port ID(%u) is not valid\n",
+				ports[portid]);
 			ports[portid] = INVALID_PORT_ID;
 			valid_num_ports--;
 		}
diff --git a/examples/vm_power_manager/main.c b/examples/vm_power_manager/main.c
index 4cde828f9..db0ddb01d 100644
--- a/examples/vm_power_manager/main.c
+++ b/examples/vm_power_manager/main.c
@@ -61,7 +61,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_txconf txq_conf;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	rte_eth_dev_info_get(port, &dev_info);
diff --git a/examples/vmdq/main.c b/examples/vmdq/main.c
index 72845241e..2f3eb74f5 100644
--- a/examples/vmdq/main.c
+++ b/examples/vmdq/main.c
@@ -201,7 +201,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 		num_pf_queues, num_pools, queues_per_pool);
 	printf("vmdq queue base: %d pool base %d\n",
 		vmdq_queue_base, vmdq_pool_base);
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	/*
@@ -539,9 +539,9 @@ static unsigned check_ports_num(unsigned nb_ports)
 	}
 
 	for (portid = 0; portid < num_ports; portid++) {
-		if (ports[portid] >= nb_ports) {
-			printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
-				ports[portid], (nb_ports - 1));
+		if (!rte_eth_dev_is_valid_port(ports[portid])) {
+			printf("\nSpecified port ID(%u) is not valid\n",
+				ports[portid]);
 			ports[portid] = INVALID_PORT_ID;
 			valid_num_ports--;
 		}
diff --git a/examples/vmdq_dcb/main.c b/examples/vmdq_dcb/main.c
index 2016a9571..9c68ab089 100644
--- a/examples/vmdq_dcb/main.c
+++ b/examples/vmdq_dcb/main.c
@@ -246,7 +246,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
 			num_pools, queues_per_pool);
 	}
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	retval = get_eth_conf(&port_conf);
@@ -599,9 +599,9 @@ static unsigned check_ports_num(unsigned nb_ports)
 	}
 
 	for (portid = 0; portid < num_ports; portid++) {
-		if (ports[portid] >= nb_ports) {
-			printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
-				ports[portid], (nb_ports - 1));
+		if (!rte_eth_dev_is_valid_port(ports[portid])) {
+			printf("\nSpecified port ID(%u) is not valid\n",
+				ports[portid]);
 			ports[portid] = INVALID_PORT_ID;
 			valid_num_ports--;
 		}
diff --git a/lib/librte_kni/rte_kni.c b/lib/librte_kni/rte_kni.c
index 28674115f..8a8f6c1cc 100644
--- a/lib/librte_kni/rte_kni.c
+++ b/lib/librte_kni/rte_kni.c
@@ -510,7 +510,7 @@ kni_config_mac_address(uint16_t port_id, uint8_t mac_addr[])
 {
 	int ret = 0;
 
-	if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) {
+	if (!rte_eth_dev_is_valid_port(port_id)) {
 		RTE_LOG(ERR, KNI, "Invalid port id %d\n", port_id);
 		return -EINVAL;
 	}
@@ -530,7 +530,7 @@ kni_config_mac_address(uint16_t port_id, uint8_t mac_addr[])
 static int
 kni_config_promiscusity(uint16_t port_id, uint8_t to_on)
 {
-	if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) {
+	if (!rte_eth_dev_is_valid_port(port_id)) {
 		RTE_LOG(ERR, KNI, "Invalid port id %d\n", port_id);
 		return -EINVAL;
 	}
diff --git a/test/test/test_event_eth_rx_adapter.c b/test/test/test_event_eth_rx_adapter.c
index 1b913a25f..2234df0eb 100644
--- a/test/test/test_event_eth_rx_adapter.c
+++ b/test/test/test_event_eth_rx_adapter.c
@@ -51,7 +51,7 @@ port_init(uint8_t port, struct rte_mempool *mp)
 	uint16_t q;
 	struct rte_eth_dev_info dev_info;
 
-	if (port >= rte_eth_dev_count())
+	if (!rte_eth_dev_is_valid_port(port))
 		return -1;
 
 	retval = rte_eth_dev_configure(port, 0, 0, &port_conf);
-- 
2.16.2

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dpdk-dev] [PATCH v2 3/3] ethdev: deprecate port count function
  2018-04-05 15:33 ` [dpdk-dev] [PATCH v2 0/3] " Thomas Monjalon
  2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 1/3] fix ethdev " Thomas Monjalon
  2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 2/3] fix ethdev port id validation Thomas Monjalon
@ 2018-04-05 15:33   ` Thomas Monjalon
  2018-04-17 22:22   ` [dpdk-dev] [PATCH v2 0/3] ethdev: fix ports enumeration Thomas Monjalon
  3 siblings, 0 replies; 6+ messages in thread
From: Thomas Monjalon @ 2018-04-05 15:33 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit

Some DPDK applications wrongly assume these requirements:
    - no hotplug, i.e. ports are never detached
    - all allocated ports are available to the application

Such application iterates over ports by its own mean.
The most common pattern is to request the port count and
assume ports with index in the range [0..count[ can be used.

In order to fix this common mistake in all external applications,
the function rte_eth_dev_count is deprecated, while introducing
the new functions rte_eth_dev_count_avail and rte_eth_dev_count_total.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 app/proc-info/main.c                               |  2 +-
 app/test-eventdev/test_perf_atq.c                  |  2 +-
 app/test-eventdev/test_perf_common.c               |  2 +-
 app/test-eventdev/test_perf_queue.c                |  2 +-
 app/test-eventdev/test_pipeline_atq.c              |  4 ++--
 app/test-eventdev/test_pipeline_common.c           |  6 +++---
 app/test-eventdev/test_pipeline_queue.c            |  6 +++---
 app/test-pmd/cmdline.c                             |  2 +-
 app/test-pmd/testpmd.c                             |  6 +++---
 doc/guides/rel_notes/release_18_05.rst             |  7 ++++++
 doc/guides/sample_app_ug/quota_watermark.rst       |  2 +-
 examples/bond/main.c                               |  2 +-
 examples/distributor/main.c                        |  6 +++---
 examples/ethtool/ethtool-app/main.c                |  2 +-
 examples/eventdev_pipeline/main.c                  |  4 ++--
 examples/eventdev_pipeline/pipeline_worker_tx.c    |  4 ++--
 examples/exception_path/main.c                     |  2 +-
 examples/flow_classify/flow_classify.c             |  4 ++--
 examples/flow_filtering/Makefile                   |  3 +++
 examples/flow_filtering/main.c                     |  4 ++--
 examples/flow_filtering/meson.build                |  1 +
 examples/ip_fragmentation/main.c                   |  4 ++--
 examples/ip_reassembly/main.c                      |  2 +-
 examples/ipv4_multicast/main.c                     |  2 +-
 examples/kni/main.c                                |  2 +-
 examples/l2fwd-cat/l2fwd-cat.c                     |  2 +-
 examples/l2fwd-crypto/main.c                       |  2 +-
 examples/l2fwd-jobstats/main.c                     |  2 +-
 examples/l2fwd-keepalive/main.c                    |  2 +-
 examples/l2fwd/main.c                              |  2 +-
 examples/l3fwd-acl/main.c                          |  2 +-
 examples/l3fwd-power/main.c                        |  2 +-
 examples/l3fwd-vf/main.c                           |  2 +-
 examples/l3fwd/main.c                              |  2 +-
 examples/link_status_interrupt/Makefile            |  3 +++
 examples/link_status_interrupt/main.c              |  2 +-
 examples/link_status_interrupt/meson.build         |  1 +
 .../client_server_mp/mp_client/Makefile            |  1 +
 .../client_server_mp/mp_client/client.c            |  2 +-
 .../client_server_mp/mp_server/Makefile            |  1 +
 .../client_server_mp/mp_server/init.c              |  2 +-
 examples/multi_process/l2fwd_fork/main.c           |  2 +-
 examples/multi_process/symmetric_mp/main.c         |  2 +-
 examples/netmap_compat/bridge/Makefile             |  1 +
 examples/netmap_compat/bridge/bridge.c             |  2 +-
 examples/packet_ordering/main.c                    |  4 ++--
 examples/performance-thread/l3fwd-thread/main.c    |  2 +-
 examples/ptpclient/ptpclient.c                     |  2 +-
 examples/qos_sched/Makefile                        |  3 +++
 examples/qos_sched/init.c                          |  2 +-
 examples/qos_sched/meson.build                     |  1 +
 examples/quota_watermark/qw/Makefile               |  1 +
 examples/quota_watermark/qw/init.c                 |  2 +-
 examples/rxtx_callbacks/main.c                     |  2 +-
 examples/server_node_efd/node/Makefile             |  1 +
 examples/server_node_efd/node/node.c               |  2 +-
 examples/server_node_efd/server/Makefile           |  1 +
 examples/server_node_efd/server/init.c             |  2 +-
 examples/skeleton/basicfwd.c                       |  2 +-
 examples/skeleton/meson.build                      |  2 ++
 examples/tep_termination/main.c                    |  2 +-
 examples/vhost/main.c                              |  2 +-
 examples/vm_power_manager/main.c                   |  2 +-
 examples/vmdq/main.c                               |  2 +-
 examples/vmdq_dcb/main.c                           |  2 +-
 lib/librte_ether/rte_ethdev.c                      | 25 +++++++++++++++++++---
 lib/librte_ether/rte_ethdev.h                      | 23 ++++++++++++++++++++
 lib/librte_ether/rte_ethdev_version.map            |  4 +++-
 lib/librte_eventdev/rte_event_eth_rx_adapter.c     |  3 ++-
 test/test/test_event_eth_rx_adapter.c              |  4 ++--
 test/test/test_kni.c                               |  2 +-
 test/test/test_link_bonding_mode4.c                |  2 +-
 test/test/test_link_bonding_rssconf.c              |  2 +-
 test/test/test_pmd_perf.c                          |  2 +-
 test/test/test_pmd_ring.c                          |  2 +-
 75 files changed, 150 insertions(+), 78 deletions(-)

diff --git a/app/proc-info/main.c b/app/proc-info/main.c
index 115df9d96..539e13243 100644
--- a/app/proc-info/main.c
+++ b/app/proc-info/main.c
@@ -628,7 +628,7 @@ main(int argc, char **argv)
 		return 0;
 	}
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
diff --git a/app/test-eventdev/test_perf_atq.c b/app/test-eventdev/test_perf_atq.c
index b36b22a77..64ac7b982 100644
--- a/app/test-eventdev/test_perf_atq.c
+++ b/app/test-eventdev/test_perf_atq.c
@@ -11,7 +11,7 @@ atq_nb_event_queues(struct evt_options *opt)
 {
 	/* nb_queues = number of producers */
 	return opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR ?
-		rte_eth_dev_count() : evt_nr_active_lcores(opt->plcores);
+		rte_eth_dev_count_avail() : evt_nr_active_lcores(opt->plcores);
 }
 
 static inline __attribute__((always_inline)) void
diff --git a/app/test-eventdev/test_perf_common.c b/app/test-eventdev/test_perf_common.c
index 488cf0724..1736b6b52 100644
--- a/app/test-eventdev/test_perf_common.c
+++ b/app/test-eventdev/test_perf_common.c
@@ -491,7 +491,7 @@ perf_ethdev_setup(struct evt_test *test, struct evt_options *opt)
 	if (opt->prod_type == EVT_PROD_TYPE_SYNT)
 		return 0;
 
-	if (!rte_eth_dev_count()) {
+	if (!rte_eth_dev_count_avail()) {
 		evt_err("No ethernet ports found.");
 		return -ENODEV;
 	}
diff --git a/app/test-eventdev/test_perf_queue.c b/app/test-eventdev/test_perf_queue.c
index db8f2f3e5..e381ed1eb 100644
--- a/app/test-eventdev/test_perf_queue.c
+++ b/app/test-eventdev/test_perf_queue.c
@@ -11,7 +11,7 @@ perf_queue_nb_event_queues(struct evt_options *opt)
 {
 	/* nb_queues = number of producers * number of stages */
 	uint8_t nb_prod = opt->prod_type == EVT_PROD_TYPE_ETH_RX_ADPTR ?
-		rte_eth_dev_count() : evt_nr_active_lcores(opt->plcores);
+		rte_eth_dev_count_avail() : evt_nr_active_lcores(opt->plcores);
 	return nb_prod * opt->nb_stages;
 }
 
diff --git a/app/test-eventdev/test_pipeline_atq.c b/app/test-eventdev/test_pipeline_atq.c
index dd7189776..26dc79f90 100644
--- a/app/test-eventdev/test_pipeline_atq.c
+++ b/app/test-eventdev/test_pipeline_atq.c
@@ -12,7 +12,7 @@ pipeline_atq_nb_event_queues(struct evt_options *opt)
 {
 	RTE_SET_USED(opt);
 
-	return rte_eth_dev_count();
+	return rte_eth_dev_count_avail();
 }
 
 static int
@@ -324,7 +324,7 @@ pipeline_atq_eventdev_setup(struct evt_test *test, struct evt_options *opt)
 	uint8_t nb_worker_queues = 0;
 
 	nb_ports = evt_nr_active_lcores(opt->wlcores);
-	nb_queues = rte_eth_dev_count();
+	nb_queues = rte_eth_dev_count_avail();
 
 	/* One extra port and queueu for Tx service */
 	if (t->mt_unsafe) {
diff --git a/app/test-eventdev/test_pipeline_common.c b/app/test-eventdev/test_pipeline_common.c
index b4dbe3769..719518ff3 100644
--- a/app/test-eventdev/test_pipeline_common.c
+++ b/app/test-eventdev/test_pipeline_common.c
@@ -166,7 +166,7 @@ pipeline_opt_check(struct evt_options *opt, uint64_t nb_queues)
 	 */
 	lcores = 2;
 
-	if (!rte_eth_dev_count()) {
+	if (!rte_eth_dev_count_avail()) {
 		evt_err("test needs minimum 1 ethernet dev");
 		return -1;
 	}
@@ -234,7 +234,7 @@ pipeline_ethdev_setup(struct evt_test *test, struct evt_options *opt)
 	};
 
 	RTE_SET_USED(opt);
-	if (!rte_eth_dev_count()) {
+	if (!rte_eth_dev_count_avail()) {
 		evt_err("No ethernet ports found.\n");
 		return -ENODEV;
 	}
@@ -419,7 +419,7 @@ pipeline_event_tx_service_setup(struct evt_test *test, struct evt_options *opt,
 	tx->dev_id = opt->dev_id;
 	tx->queue_id = tx_queue_id;
 	tx->port_id = tx_port_id;
-	tx->nb_ethports = rte_eth_dev_count();
+	tx->nb_ethports = rte_eth_dev_count_avail();
 	tx->t = t;
 
 	/* Register Tx service */
diff --git a/app/test-eventdev/test_pipeline_queue.c b/app/test-eventdev/test_pipeline_queue.c
index 02fc27cf8..ca5f4578e 100644
--- a/app/test-eventdev/test_pipeline_queue.c
+++ b/app/test-eventdev/test_pipeline_queue.c
@@ -10,7 +10,7 @@
 static __rte_always_inline int
 pipeline_queue_nb_event_queues(struct evt_options *opt)
 {
-	uint16_t eth_count = rte_eth_dev_count();
+	uint16_t eth_count = rte_eth_dev_count_avail();
 
 	return (eth_count * opt->nb_stages) + eth_count;
 }
@@ -333,7 +333,7 @@ pipeline_queue_eventdev_setup(struct evt_test *test, struct evt_options *opt)
 	uint8_t nb_worker_queues = 0;
 
 	nb_ports = evt_nr_active_lcores(opt->wlcores);
-	nb_queues = rte_eth_dev_count() * (nb_stages);
+	nb_queues = rte_eth_dev_count_avail() * (nb_stages);
 
 	/* Extra port for Tx service. */
 	if (t->mt_unsafe) {
@@ -341,7 +341,7 @@ pipeline_queue_eventdev_setup(struct evt_test *test, struct evt_options *opt)
 		nb_ports++;
 		nb_queues++;
 	} else
-		nb_queues += rte_eth_dev_count();
+		nb_queues += rte_eth_dev_count_avail();
 
 	rte_event_dev_info_get(opt->dev_id, &info);
 
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index f22fa935c..6f0419ce1 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -5402,7 +5402,7 @@ static void cmd_create_bonded_device_parsed(void *parsed_result,
 				port_id);
 
 		/* Update number of ports */
-		nb_ports = rte_eth_dev_count();
+		nb_ports = rte_eth_dev_count_avail();
 		reconfig(port_id, res->socket);
 		rte_eth_promiscuous_enable(port_id);
 	}
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 0708c32cb..5e0f24471 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -1873,7 +1873,7 @@ attach_port(char *identifier)
 	reconfig(pi, socket_id);
 	rte_eth_promiscuous_enable(pi);
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	ports[pi].port_status = RTE_PORT_STOPPED;
 
@@ -1901,7 +1901,7 @@ detach_port(portid_t port_id)
 		return;
 	}
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	printf("Port '%s' is detached. Now total ports is %d\n",
 			name, nb_ports);
@@ -2496,7 +2496,7 @@ main(int argc, char** argv)
 	rte_pdump_init(NULL);
 #endif
 
-	nb_ports = (portid_t) rte_eth_dev_count();
+	nb_ports = (portid_t) rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		TESTPMD_LOG(WARNING, "No probed ethernet devices\n");
 
diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
index e5fac1cd1..0c801000a 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -72,6 +72,13 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* ethdev: The function ``rte_eth_dev_count``, often mis-used to iterate
+  over ports, is deprecated and replaced by ``rte_eth_dev_count_avail``.
+  There is also a new function ``rte_eth_dev_count_total`` to get the
+  total number of allocated ports, available or not.
+  The hotplug-proof applications should use ``RTE_ETH_FOREACH_DEV`` or
+  ``RTE_ETH_FOREACH_DEV_OWNED_BY`` as port iterators.
+
 
 ABI Changes
 -----------
diff --git a/doc/guides/sample_app_ug/quota_watermark.rst b/doc/guides/sample_app_ug/quota_watermark.rst
index 8baec4df8..67200e15d 100644
--- a/doc/guides/sample_app_ug/quota_watermark.rst
+++ b/doc/guides/sample_app_ug/quota_watermark.rst
@@ -163,7 +163,7 @@ Then, a call to init_dpdk(), defined in init.c, is made to initialize the poll m
         if (ret < 0)
             rte_exit(EXIT_FAILURE, "rte_pci_probe(): error %d\n", ret);
 
-        if (rte_eth_dev_count() < 2)
+        if (rte_eth_dev_count_avail() < 2)
             rte_exit(EXIT_FAILURE, "Not enough Ethernet port available\n");
     }
 
diff --git a/examples/bond/main.c b/examples/bond/main.c
index d4097d04d..d8edc642b 100644
--- a/examples/bond/main.c
+++ b/examples/bond/main.c
@@ -748,7 +748,7 @@ main(int argc, char *argv[])
 	argc -= ret;
 	argv += ret;
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "Give at least one port\n");
 	else if (nb_ports > MAX_PORTS)
diff --git a/examples/distributor/main.c b/examples/distributor/main.c
index 2e6b09d21..2c5936489 100644
--- a/examples/distributor/main.c
+++ b/examples/distributor/main.c
@@ -193,7 +193,7 @@ struct lcore_params {
 static int
 lcore_rx(struct lcore_params *p)
 {
-	const uint16_t nb_ports = rte_eth_dev_count();
+	const uint16_t nb_ports = rte_eth_dev_count_avail();
 	const int socket_id = rte_socket_id();
 	uint16_t port;
 	struct rte_mbuf *bufs[BURST_SIZE*2];
@@ -542,7 +542,7 @@ lcore_worker(struct lcore_params *p)
 	 * for single port, xor_val will be zero so we won't modify the output
 	 * port, otherwise we send traffic from 0 to 1, 2 to 3, and vice versa
 	 */
-	const unsigned xor_val = (rte_eth_dev_count() > 1);
+	const unsigned xor_val = (rte_eth_dev_count_avail() > 1);
 	struct rte_mbuf *buf[8] __rte_cache_aligned;
 
 	for (i = 0; i < 8; i++)
@@ -678,7 +678,7 @@ main(int argc, char *argv[])
 				"1 lcore for packet TX\n"
 				"and at least 1 lcore for worker threads\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "Error: no ethernet ports detected\n");
 	if (nb_ports != 1 && (nb_ports & 1))
diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
index 702feabe9..c1815bb94 100644
--- a/examples/ethtool/ethtool-app/main.c
+++ b/examples/ethtool/ethtool-app/main.c
@@ -251,7 +251,7 @@ int main(int argc, char **argv)
 	if (cnt_args_parsed < 0)
 		rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
 
-	cnt_ports = rte_eth_dev_count();
+	cnt_ports = rte_eth_dev_count_avail();
 	printf("Number of NICs: %i\n", cnt_ports);
 	if (cnt_ports == 0)
 		rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
diff --git a/examples/eventdev_pipeline/main.c b/examples/eventdev_pipeline/main.c
index 48358a7d2..b698e4ca2 100644
--- a/examples/eventdev_pipeline/main.c
+++ b/examples/eventdev_pipeline/main.c
@@ -429,7 +429,7 @@ int
 main(int argc, char **argv)
 {
 	struct worker_data *worker_data;
-	unsigned int num_ports;
+	uint16_t num_ports;
 	int lcore_id;
 	int err;
 
@@ -451,7 +451,7 @@ main(int argc, char **argv)
 	/* Parse cli options*/
 	parse_app_args(argc, argv);
 
-	num_ports = rte_eth_dev_count();
+	num_ports = rte_eth_dev_count_avail();
 	if (num_ports == 0)
 		rte_panic("No ethernet ports found\n");
 
diff --git a/examples/eventdev_pipeline/pipeline_worker_tx.c b/examples/eventdev_pipeline/pipeline_worker_tx.c
index fc98128ec..3dbde92df 100644
--- a/examples/eventdev_pipeline/pipeline_worker_tx.c
+++ b/examples/eventdev_pipeline/pipeline_worker_tx.c
@@ -422,7 +422,7 @@ setup_eventdev_worker_tx(struct cons_data *cons_data,
 	const uint8_t dev_id = 0;
 	const uint8_t nb_ports = cdata.num_workers;
 	uint8_t nb_slots = 0;
-	uint8_t nb_queues = rte_eth_dev_count();
+	uint8_t nb_queues = rte_eth_dev_count_avail();
 
 	/*
 	 * In case where all type queues are not enabled, use queues equal to
@@ -431,7 +431,7 @@ setup_eventdev_worker_tx(struct cons_data *cons_data,
 	 */
 	if (!atq) {
 		nb_queues *= cdata.num_stages;
-		nb_queues += rte_eth_dev_count();
+		nb_queues += rte_eth_dev_count_avail();
 	}
 
 	struct rte_event_dev_config config = {
diff --git a/examples/exception_path/main.c b/examples/exception_path/main.c
index 996f4939d..2b381a5d8 100644
--- a/examples/exception_path/main.c
+++ b/examples/exception_path/main.c
@@ -559,7 +559,7 @@ main(int argc, char** argv)
 	}
 
 	/* Get number of ports found in scan */
-	nb_sys_ports = rte_eth_dev_count();
+	nb_sys_ports = rte_eth_dev_count_avail();
 	if (nb_sys_ports == 0)
 		FATAL_ERROR("No supported Ethernet device found");
 	/* Find highest port set in portmask */
diff --git a/examples/flow_classify/flow_classify.c b/examples/flow_classify/flow_classify.c
index d0e537e7d..3b087ce76 100644
--- a/examples/flow_classify/flow_classify.c
+++ b/examples/flow_classify/flow_classify.c
@@ -752,7 +752,7 @@ int
 main(int argc, char *argv[])
 {
 	struct rte_mempool *mbuf_pool;
-	uint8_t nb_ports;
+	uint16_t nb_ports;
 	uint16_t portid;
 	int ret;
 	int socket_id;
@@ -776,7 +776,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Invalid flow_classify parameters\n");
 
 	/* Check that there is an even number of ports to send/receive on. */
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports < 2 || (nb_ports & 1))
 		rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
 
diff --git a/examples/flow_filtering/Makefile b/examples/flow_filtering/Makefile
index 01bb4cd81..f41b368fa 100644
--- a/examples/flow_filtering/Makefile
+++ b/examples/flow_filtering/Makefile
@@ -50,6 +50,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -75,6 +77,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/flow_filtering/main.c b/examples/flow_filtering/main.c
index 0bb81a8dd..db03c9c3a 100644
--- a/examples/flow_filtering/main.c
+++ b/examples/flow_filtering/main.c
@@ -232,7 +232,7 @@ int
 main(int argc, char **argv)
 {
 	int ret;
-	uint8_t nr_ports;
+	uint16_t nr_ports;
 	struct rte_flow_error error;
 
 	ret = rte_eal_init(argc, argv);
@@ -243,7 +243,7 @@ main(int argc, char **argv)
 	signal(SIGINT, signal_handler);
 	signal(SIGTERM, signal_handler);
 
-	nr_ports = rte_eth_dev_count();
+	nr_ports = rte_eth_dev_count_avail();
 	if (nr_ports == 0)
 		rte_exit(EXIT_FAILURE, ":: no Ethernet ports found\n");
 	port_id = 0;
diff --git a/examples/flow_filtering/meson.build b/examples/flow_filtering/meson.build
index 407795c42..949493300 100644
--- a/examples/flow_filtering/meson.build
+++ b/examples/flow_filtering/meson.build
@@ -9,3 +9,4 @@
 sources = files(
 	'main.c',
 )
+allow_experimental_apis = true
diff --git a/examples/ip_fragmentation/main.c b/examples/ip_fragmentation/main.c
index f525c3a9c..8952ea456 100644
--- a/examples/ip_fragmentation/main.c
+++ b/examples/ip_fragmentation/main.c
@@ -843,7 +843,7 @@ main(int argc, char **argv)
 	struct rte_eth_txconf *txconf;
 	struct rx_queue *rxq;
 	int socket, ret;
-	unsigned nb_ports;
+	uint16_t nb_ports;
 	uint16_t queueid = 0;
 	unsigned lcore_id = 0, rx_lcore_id = 0;
 	uint32_t n_tx_queue, nb_lcores;
@@ -861,7 +861,7 @@ main(int argc, char **argv)
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "Invalid arguments");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No ports found!\n");
 
diff --git a/examples/ip_reassembly/main.c b/examples/ip_reassembly/main.c
index ddff35880..3e8e79c21 100644
--- a/examples/ip_reassembly/main.c
+++ b/examples/ip_reassembly/main.c
@@ -1008,7 +1008,7 @@ main(int argc, char **argv)
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "Invalid IP reassembly parameters\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No ports found!\n");
 
diff --git a/examples/ipv4_multicast/main.c b/examples/ipv4_multicast/main.c
index 23b266bbe..ad2072f41 100644
--- a/examples/ipv4_multicast/main.c
+++ b/examples/ipv4_multicast/main.c
@@ -674,7 +674,7 @@ main(int argc, char **argv)
 	if (clone_pool == NULL)
 		rte_exit(EXIT_FAILURE, "Cannot init clone mbuf pool\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No physical ports!\n");
 	if (nb_ports > MAX_PORTS)
diff --git a/examples/kni/main.c b/examples/kni/main.c
index 1855c64ab..40d74ae15 100644
--- a/examples/kni/main.c
+++ b/examples/kni/main.c
@@ -921,7 +921,7 @@ main(int argc, char** argv)
 	}
 
 	/* Get number of ports found in scan */
-	nb_sys_ports = rte_eth_dev_count();
+	nb_sys_ports = rte_eth_dev_count_avail();
 	if (nb_sys_ports == 0)
 		rte_exit(EXIT_FAILURE, "No supported Ethernet device found\n");
 
diff --git a/examples/l2fwd-cat/l2fwd-cat.c b/examples/l2fwd-cat/l2fwd-cat.c
index ed4878043..0e6078aad 100644
--- a/examples/l2fwd-cat/l2fwd-cat.c
+++ b/examples/l2fwd-cat/l2fwd-cat.c
@@ -173,7 +173,7 @@ main(int argc, char *argv[])
 	argv += ret;
 
 	/* Check that there is an even number of ports to send/receive on. */
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports < 2 || (nb_ports & 1))
 		rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
 
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index b1ad19284..422044898 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -2311,7 +2311,7 @@ initialize_ports(struct l2fwd_crypto_options *options)
 {
 	uint16_t last_portid = 0, portid;
 	unsigned enabled_portcount = 0;
-	unsigned nb_ports = rte_eth_dev_count();
+	unsigned nb_ports = rte_eth_dev_count_avail();
 
 	if (nb_ports == 0) {
 		printf("No Ethernet ports - bye\n");
diff --git a/examples/l2fwd-jobstats/main.c b/examples/l2fwd-jobstats/main.c
index 248224840..34553faa2 100644
--- a/examples/l2fwd-jobstats/main.c
+++ b/examples/l2fwd-jobstats/main.c
@@ -770,7 +770,7 @@ main(int argc, char **argv)
 	if (l2fwd_pktmbuf_pool == NULL)
 		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
diff --git a/examples/l2fwd-keepalive/main.c b/examples/l2fwd-keepalive/main.c
index e9ad91a1f..a18b707cd 100644
--- a/examples/l2fwd-keepalive/main.c
+++ b/examples/l2fwd-keepalive/main.c
@@ -561,7 +561,7 @@ main(int argc, char **argv)
 	if (l2fwd_pktmbuf_pool == NULL)
 		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
diff --git a/examples/l2fwd/main.c b/examples/l2fwd/main.c
index f8ca29cf6..690843578 100644
--- a/examples/l2fwd/main.c
+++ b/examples/l2fwd/main.c
@@ -545,7 +545,7 @@ main(int argc, char **argv)
 	/* convert to number of cycles */
 	timer_period *= rte_get_timer_hz();
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
diff --git a/examples/l3fwd-acl/main.c b/examples/l3fwd-acl/main.c
index 2c891b494..33ad467d3 100644
--- a/examples/l3fwd-acl/main.c
+++ b/examples/l3fwd-acl/main.c
@@ -1891,7 +1891,7 @@ main(int argc, char **argv)
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
diff --git a/examples/l3fwd-power/main.c b/examples/l3fwd-power/main.c
index d6a092618..596d64548 100644
--- a/examples/l3fwd-power/main.c
+++ b/examples/l3fwd-power/main.c
@@ -1650,7 +1650,7 @@ main(int argc, char **argv)
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
diff --git a/examples/l3fwd-vf/main.c b/examples/l3fwd-vf/main.c
index dd0e057ef..aaafb7bc2 100644
--- a/examples/l3fwd-vf/main.c
+++ b/examples/l3fwd-vf/main.c
@@ -949,7 +949,7 @@ main(int argc, char **argv)
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
index ec1da5c18..bf7dbd814 100644
--- a/examples/l3fwd/main.c
+++ b/examples/l3fwd/main.c
@@ -826,7 +826,7 @@ main(int argc, char **argv)
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
diff --git a/examples/link_status_interrupt/Makefile b/examples/link_status_interrupt/Makefile
index 160682123..d778fcbbf 100644
--- a/examples/link_status_interrupt/Makefile
+++ b/examples/link_status_interrupt/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -48,6 +50,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/link_status_interrupt/main.c b/examples/link_status_interrupt/main.c
index ad0dd390d..f56895680 100644
--- a/examples/link_status_interrupt/main.c
+++ b/examples/link_status_interrupt/main.c
@@ -542,7 +542,7 @@ main(int argc, char **argv)
 	if (lsi_pktmbuf_pool == NULL)
 		rte_panic("Cannot init mbuf pool\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_panic("No Ethernet port - bye\n");
 
diff --git a/examples/link_status_interrupt/meson.build b/examples/link_status_interrupt/meson.build
index c34e11e36..2b0a25036 100644
--- a/examples/link_status_interrupt/meson.build
+++ b/examples/link_status_interrupt/meson.build
@@ -6,6 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
+allow_experimental_apis = true
 sources = files(
 	'main.c'
 )
diff --git a/examples/multi_process/client_server_mp/mp_client/Makefile b/examples/multi_process/client_server_mp/mp_client/Makefile
index 298e1b020..3bfcd75c5 100644
--- a/examples/multi_process/client_server_mp/mp_client/Makefile
+++ b/examples/multi_process/client_server_mp/mp_client/Makefile
@@ -14,6 +14,7 @@ APP = mp_client
 # all source are stored in SRCS-y
 SRCS-y := client.c
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -O3
 CFLAGS += -I$(SRCDIR)/../shared
 
diff --git a/examples/multi_process/client_server_mp/mp_client/client.c b/examples/multi_process/client_server_mp/mp_client/client.c
index 92955e974..c23dd3f37 100644
--- a/examples/multi_process/client_server_mp/mp_client/client.c
+++ b/examples/multi_process/client_server_mp/mp_client/client.c
@@ -220,7 +220,7 @@ main(int argc, char *argv[])
 	if (parse_app_args(argc, argv) < 0)
 		rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
 
-	if (rte_eth_dev_count() == 0)
+	if (rte_eth_dev_count_avail() == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
 	rx_ring = rte_ring_lookup(get_rx_queue_name(client_id));
diff --git a/examples/multi_process/client_server_mp/mp_server/Makefile b/examples/multi_process/client_server_mp/mp_server/Makefile
index 3e244e283..af7246e6b 100644
--- a/examples/multi_process/client_server_mp/mp_server/Makefile
+++ b/examples/multi_process/client_server_mp/mp_server/Makefile
@@ -23,6 +23,7 @@ SRCS-y := main.c init.c args.c
 
 INC := $(sort $(wildcard *.h))
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -O3
 CFLAGS += -I$(SRCDIR)/../shared
 
diff --git a/examples/multi_process/client_server_mp/mp_server/init.c b/examples/multi_process/client_server_mp/mp_server/init.c
index 1c465ccbc..30c8e44bc 100644
--- a/examples/multi_process/client_server_mp/mp_server/init.c
+++ b/examples/multi_process/client_server_mp/mp_server/init.c
@@ -243,7 +243,7 @@ init(int argc, char *argv[])
 	argv += retval;
 
 	/* get total number of ports */
-	total_ports = rte_eth_dev_count();
+	total_ports = rte_eth_dev_count_total();
 
 	/* set up array for port data */
 	mz = rte_memzone_reserve(MZ_PORT_INFO, sizeof(*ports),
diff --git a/examples/multi_process/l2fwd_fork/main.c b/examples/multi_process/l2fwd_fork/main.c
index 6b130f2f5..94318ab61 100644
--- a/examples/multi_process/l2fwd_fork/main.c
+++ b/examples/multi_process/l2fwd_fork/main.c
@@ -941,7 +941,7 @@ main(int argc, char **argv)
 	for (i = 0; i < RTE_MAX_LCORE; i++)
 		lcore_resource[i].lcore_id = i;
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
diff --git a/examples/multi_process/symmetric_mp/main.c b/examples/multi_process/symmetric_mp/main.c
index 75cad0cca..16f21a187 100644
--- a/examples/multi_process/symmetric_mp/main.c
+++ b/examples/multi_process/symmetric_mp/main.c
@@ -418,7 +418,7 @@ main(int argc, char **argv)
 	argv += ret;
 
 	/* determine the NIC devices available */
-	if (rte_eth_dev_count() == 0)
+	if (rte_eth_dev_count_avail() == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
 	/* parse application arguments (those after the EAL ones) */
diff --git a/examples/netmap_compat/bridge/Makefile b/examples/netmap_compat/bridge/Makefile
index a7c9c14a8..071c09dd3 100644
--- a/examples/netmap_compat/bridge/Makefile
+++ b/examples/netmap_compat/bridge/Makefile
@@ -27,6 +27,7 @@ VPATH := $(SRCDIR)/../lib
 SRCS-y := bridge.c
 SRCS-y += compat_netmap.c
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3 -I$(SRCDIR)/../lib -I$(SRCDIR)/../netmap
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/netmap_compat/bridge/bridge.c b/examples/netmap_compat/bridge/bridge.c
index 59c5e4361..cb1882e65 100644
--- a/examples/netmap_compat/bridge/bridge.c
+++ b/examples/netmap_compat/bridge/bridge.c
@@ -236,7 +236,7 @@ int main(int argc, char *argv[])
 	if (ports.num == 0)
 		rte_exit(EXIT_FAILURE, "no ports specified\n");
 
-	if (rte_eth_dev_count() < 1)
+	if (rte_eth_dev_count_avail() < 1)
 		rte_exit(EXIT_FAILURE, "Not enough ethernet ports available\n");
 
 	pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0,
diff --git a/examples/packet_ordering/main.c b/examples/packet_ordering/main.c
index 676cb6f71..7ace7d10e 100644
--- a/examples/packet_ordering/main.c
+++ b/examples/packet_ordering/main.c
@@ -430,7 +430,7 @@ rx_thread(struct rte_ring *ring_out)
 static int
 worker_thread(void *args_ptr)
 {
-	const uint8_t nb_ports = rte_eth_dev_count();
+	const uint16_t nb_ports = rte_eth_dev_count_avail();
 	uint16_t i, ret = 0;
 	uint16_t burst_size = 0;
 	struct worker_thread_args *args;
@@ -644,7 +644,7 @@ main(int argc, char **argv)
 				"1 lcore for packet TX\n"
 				"and at least 1 lcore for worker threads\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "Error: no ethernet ports detected\n");
 	if (nb_ports != 1 && (nb_ports & 1))
diff --git a/examples/performance-thread/l3fwd-thread/main.c b/examples/performance-thread/l3fwd-thread/main.c
index 699b99d00..f51e6b0fd 100644
--- a/examples/performance-thread/l3fwd-thread/main.c
+++ b/examples/performance-thread/l3fwd-thread/main.c
@@ -3514,7 +3514,7 @@ main(int argc, char **argv)
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "init_rx_rings failed\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	if (check_port_config() < 0)
 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
diff --git a/examples/ptpclient/ptpclient.c b/examples/ptpclient/ptpclient.c
index 55be3f7cd..c44013bc1 100644
--- a/examples/ptpclient/ptpclient.c
+++ b/examples/ptpclient/ptpclient.c
@@ -727,7 +727,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE, "Error with PTP initialization\n");
 
 	/* Check that there is an even number of ports to send/receive on. */
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	/* Creates a new mempool in memory to hold the mbufs. */
 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
diff --git a/examples/qos_sched/Makefile b/examples/qos_sched/Makefile
index 0f0a31ff2..e6dfbef1f 100644
--- a/examples/qos_sched/Makefile
+++ b/examples/qos_sched/Makefile
@@ -23,6 +23,8 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
 	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
 
@@ -55,6 +57,7 @@ all:
 clean:
 else
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS_args.o := -D_GNU_SOURCE
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 8914f766f..c9e487975 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -298,7 +298,7 @@ int app_init(void)
 	char ring_name[MAX_NAME_LEN];
 	char pool_name[MAX_NAME_LEN];
 
-	if (rte_eth_dev_count() == 0)
+	if (rte_eth_dev_count_avail() == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet port - bye\n");
 
 	/* load configuration profile */
diff --git a/examples/qos_sched/meson.build b/examples/qos_sched/meson.build
index 289b81ce8..5101652af 100644
--- a/examples/qos_sched/meson.build
+++ b/examples/qos_sched/meson.build
@@ -7,6 +7,7 @@
 # DPDK instance, use 'make'
 
 deps += ['sched', 'cfgfile']
+allow_experimental_apis = true
 sources = files(
 	'app_thread.c', 'args.c', 'cfg_file.c', 'cmdline.c',
 	'init.c', 'main.c', 'stats.c'
diff --git a/examples/quota_watermark/qw/Makefile b/examples/quota_watermark/qw/Makefile
index 84299e594..d0a9b3cf4 100644
--- a/examples/quota_watermark/qw/Makefile
+++ b/examples/quota_watermark/qw/Makefile
@@ -16,6 +16,7 @@ APP = qw
 # all source are stored in SRCS-y
 SRCS-y := args.c init.c main.c
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3 -DQW_SOFTWARE_FC
 CFLAGS += $(WERROR_FLAGS)
 
diff --git a/examples/quota_watermark/qw/init.c b/examples/quota_watermark/qw/init.c
index d4a691839..00725bc95 100644
--- a/examples/quota_watermark/qw/init.c
+++ b/examples/quota_watermark/qw/init.c
@@ -112,7 +112,7 @@ void configure_eth_port(uint16_t port_id)
 void
 init_dpdk(void)
 {
-	if (rte_eth_dev_count() < 2)
+	if (rte_eth_dev_count_avail() < 2)
 		rte_exit(EXIT_FAILURE, "Not enough ethernet port available\n");
 }
 
diff --git a/examples/rxtx_callbacks/main.c b/examples/rxtx_callbacks/main.c
index 84b09cf05..e63ea288f 100644
--- a/examples/rxtx_callbacks/main.c
+++ b/examples/rxtx_callbacks/main.c
@@ -188,7 +188,7 @@ main(int argc, char *argv[])
 	argc -= ret;
 	argv += ret;
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports < 2 || (nb_ports & 1))
 		rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
 
diff --git a/examples/server_node_efd/node/Makefile b/examples/server_node_efd/node/Makefile
index fffbe3576..dc3191a5b 100644
--- a/examples/server_node_efd/node/Makefile
+++ b/examples/server_node_efd/node/Makefile
@@ -14,6 +14,7 @@ APP = node
 # all source are stored in SRCS-y
 SRCS-y := node.c
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -O3
 CFLAGS += -I$(SRCDIR)/../shared
 
diff --git a/examples/server_node_efd/node/node.c b/examples/server_node_efd/node/node.c
index 84f7bcffe..3b97fbd45 100644
--- a/examples/server_node_efd/node/node.c
+++ b/examples/server_node_efd/node/node.c
@@ -320,7 +320,7 @@ main(int argc, char *argv[])
 	if (parse_app_args(argc, argv) < 0)
 		rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
 
-	if (rte_eth_dev_count() == 0)
+	if (rte_eth_dev_count_avail() == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 
 	rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
diff --git a/examples/server_node_efd/server/Makefile b/examples/server_node_efd/server/Makefile
index cbb91ebe8..d5456f920 100644
--- a/examples/server_node_efd/server/Makefile
+++ b/examples/server_node_efd/server/Makefile
@@ -23,6 +23,7 @@ SRCS-y := main.c init.c args.c
 
 INC := $(sort $(wildcard *.h))
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -O3
 CFLAGS += -I$(SRCDIR)/../shared
 
diff --git a/examples/server_node_efd/server/init.c b/examples/server_node_efd/server/init.c
index 07b6882f8..7dfe2fa23 100644
--- a/examples/server_node_efd/server/init.c
+++ b/examples/server_node_efd/server/init.c
@@ -310,7 +310,7 @@ init(int argc, char *argv[])
 	argv += retval;
 
 	/* get total number of ports */
-	total_ports = rte_eth_dev_count();
+	total_ports = rte_eth_dev_count_avail();
 
 	/* set up array for port data */
 	mz = rte_memzone_reserve(MZ_SHARED_INFO, sizeof(*info),
diff --git a/examples/skeleton/basicfwd.c b/examples/skeleton/basicfwd.c
index 5ac1dc820..03bc35856 100644
--- a/examples/skeleton/basicfwd.c
+++ b/examples/skeleton/basicfwd.c
@@ -173,7 +173,7 @@ main(int argc, char *argv[])
 	argv += ret;
 
 	/* Check that there is an even number of ports to send/receive on. */
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports < 2 || (nb_ports & 1))
 		rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
 
diff --git a/examples/skeleton/meson.build b/examples/skeleton/meson.build
index ef46b187e..89ddba2ea 100644
--- a/examples/skeleton/meson.build
+++ b/examples/skeleton/meson.build
@@ -10,3 +10,5 @@ allow_experimental_apis = true
 sources = files(
 	'basicfwd.c'
 )
+
+allow_experimental_apis = true
diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index e86854176..8543a9803 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -1156,7 +1156,7 @@ main(int argc, char *argv[])
 	nb_switching_cores = rte_lcore_count()-1;
 
 	/* Get the number of physical ports. */
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	/*
 	 * Update the global var NB_PORTS and global array PORTS
diff --git a/examples/vhost/main.c b/examples/vhost/main.c
index 7cddac7d2..84e0d6366 100644
--- a/examples/vhost/main.c
+++ b/examples/vhost/main.c
@@ -1448,7 +1448,7 @@ main(int argc, char *argv[])
 		rte_exit(EXIT_FAILURE,"Not enough cores\n");
 
 	/* Get the number of physical ports. */
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	/*
 	 * Update the global var NUM_PORTS and global array PORTS
diff --git a/examples/vm_power_manager/main.c b/examples/vm_power_manager/main.c
index db0ddb01d..c9805a461 100644
--- a/examples/vm_power_manager/main.c
+++ b/examples/vm_power_manager/main.c
@@ -278,7 +278,7 @@ main(int argc, char **argv)
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "Invalid arguments\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
diff --git a/examples/vmdq/main.c b/examples/vmdq/main.c
index 2f3eb74f5..52596dd5e 100644
--- a/examples/vmdq/main.c
+++ b/examples/vmdq/main.c
@@ -580,7 +580,7 @@ main(int argc, char *argv[])
 	if (rte_lcore_count() > RTE_MAX_LCORE)
 		rte_exit(EXIT_FAILURE, "Not enough cores\n");
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	/*
 	 * Update the global var NUM_PORTS and global array PORTS
diff --git a/examples/vmdq_dcb/main.c b/examples/vmdq_dcb/main.c
index 9c68ab089..2626a2f19 100644
--- a/examples/vmdq_dcb/main.c
+++ b/examples/vmdq_dcb/main.c
@@ -642,7 +642,7 @@ main(int argc, char *argv[])
 				" number of cores(1-%d)\n\n", RTE_MAX_LCORE);
 	}
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 
 	/*
 	 * Update the global var NUM_PORTS and global array PORTS
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 2c74f7e04..4f9c6fc64 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -534,6 +534,12 @@ rte_eth_dev_get_sec_ctx(uint16_t port_id)
 
 uint16_t
 rte_eth_dev_count(void)
+{
+	return rte_eth_dev_count_avail();
+}
+
+uint16_t
+rte_eth_dev_count_avail(void)
 {
 	uint16_t p;
 	uint16_t count;
@@ -546,6 +552,18 @@ rte_eth_dev_count(void)
 	return count;
 }
 
+uint16_t
+rte_eth_dev_count_total(void)
+{
+	uint16_t port, count = 0;
+
+	for (port = 0; port < RTE_MAX_ETHPORTS; port++)
+		if (rte_eth_devices[port].state != RTE_ETH_DEV_UNUSED)
+			count++;
+
+	return count;
+}
+
 int
 rte_eth_dev_get_name_by_port(uint16_t port_id, char *name)
 {
@@ -601,7 +619,7 @@ int
 rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
 {
 	int ret = -1;
-	int current = rte_eth_dev_count();
+	int current = rte_eth_dev_count_total();
 	char *name = NULL;
 	char *args = NULL;
 
@@ -619,7 +637,7 @@ rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
 		goto err;
 
 	/* no point looking at the port count if no port exists */
-	if (!rte_eth_dev_count()) {
+	if (!rte_eth_dev_count_total()) {
 		ethdev_log(ERR, "No port found for device (%s)", name);
 		ret = -1;
 		goto err;
@@ -627,8 +645,9 @@ rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
 
 	/* if nothing happened, there is a bug here, since some driver told us
 	 * it did attach a device, but did not create a port.
+	 * FIXME: race condition in case of plug-out of another device
 	 */
-	if (current == rte_eth_dev_count()) {
+	if (current == rte_eth_dev_count_total()) {
 		ret = -1;
 		goto err;
 	}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 5e13dca6a..ffd8b5478 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1360,8 +1360,31 @@ int __rte_experimental rte_eth_dev_owner_get(const uint16_t port_id,
  * @return
  *   - The total number of usable Ethernet devices.
  */
+__rte_deprecated
 uint16_t rte_eth_dev_count(void);
 
+/**
+ * Get the number of ports which are usable for the application.
+ *
+ * These devices must be iterated by using the macro
+ * ``RTE_ETH_FOREACH_DEV`` or ``RTE_ETH_FOREACH_DEV_OWNED_BY``
+ * to deal with non-contiguous ranges of devices.
+ *
+ * @return
+ *   The count of available Ethernet devices.
+ */
+uint16_t __rte_experimental rte_eth_dev_count_avail(void);
+
+/**
+ * Get the total number of ports which are allocated.
+ *
+ * Some devices may not be available for the application.
+ *
+ * @return
+ *   The total count of Ethernet devices.
+ */
+uint16_t __rte_experimental rte_eth_dev_count_total(void);
+
 /**
  * Attach a new Ethernet device specified by arguments.
  *
diff --git a/lib/librte_ether/rte_ethdev_version.map b/lib/librte_ether/rte_ethdev_version.map
index 34df6c8b5..8fe07880f 100644
--- a/lib/librte_ether/rte_ethdev_version.map
+++ b/lib/librte_ether/rte_ethdev_version.map
@@ -206,6 +206,8 @@ DPDK_18.02 {
 EXPERIMENTAL {
 	global:
 
+	rte_eth_dev_count_avail;
+	rte_eth_dev_count_total;
 	rte_eth_dev_is_removed;
 	rte_eth_dev_owner_delete;
 	rte_eth_dev_owner_get;
@@ -228,4 +230,4 @@ EXPERIMENTAL {
 	rte_mtr_stats_read;
 	rte_mtr_stats_update;
 
-} DPDK_17.11;
+} DPDK_18.02;
diff --git a/lib/librte_eventdev/rte_event_eth_rx_adapter.c b/lib/librte_eventdev/rte_event_eth_rx_adapter.c
index 9297f4c4d..1b92fa33d 100644
--- a/lib/librte_eventdev/rte_event_eth_rx_adapter.c
+++ b/lib/librte_eventdev/rte_event_eth_rx_adapter.c
@@ -890,7 +890,8 @@ rte_event_eth_rx_adapter_create_ext(uint8_t id, uint8_t dev_id,
 	rx_adapter->conf_arg = conf_arg;
 	strcpy(rx_adapter->mem_name, mem_name);
 	rx_adapter->eth_devices = rte_zmalloc_socket(rx_adapter->mem_name,
-					rte_eth_dev_count() *
+					/* FIXME: incompatible with hotplug */
+					rte_eth_dev_count_total() *
 					sizeof(struct eth_device_info), 0,
 					socket_id);
 	rte_convert_rss_key((const uint32_t *)default_rss_key,
diff --git a/test/test/test_event_eth_rx_adapter.c b/test/test/test_event_eth_rx_adapter.c
index 2234df0eb..ab5539809 100644
--- a/test/test/test_event_eth_rx_adapter.c
+++ b/test/test/test_event_eth_rx_adapter.c
@@ -164,7 +164,7 @@ testsuite_setup(void)
 	 * so rte_eth_dev_start invokes rte_event_dev_start internally, so
 	 * call init_ports after rte_event_dev_configure
 	 */
-	err = init_ports(rte_eth_dev_count());
+	err = init_ports(rte_eth_dev_count_total());
 	TEST_ASSERT(err == 0, "Port initialization failed err %d\n", err);
 
 	err = rte_event_eth_rx_adapter_caps_get(TEST_DEV_ID, TEST_ETHDEV_ID,
@@ -273,7 +273,7 @@ adapter_queue_add_del(void)
 	queue_config.servicing_weight = 1;
 
 	err = rte_event_eth_rx_adapter_queue_add(TEST_INST_ID,
-						rte_eth_dev_count(),
+						rte_eth_dev_count_total(),
 						-1, &queue_config);
 	TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
 
diff --git a/test/test/test_kni.c b/test/test/test_kni.c
index e4839cdb7..01c6530d9 100644
--- a/test/test/test_kni.c
+++ b/test/test/test_kni.c
@@ -480,7 +480,7 @@ test_kni(void)
 		return -1;
 	}
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0) {
 		printf("no supported nic port found\n");
 		return -1;
diff --git a/test/test/test_link_bonding_mode4.c b/test/test/test_link_bonding_mode4.c
index 426877a2a..33c1fab01 100644
--- a/test/test/test_link_bonding_mode4.c
+++ b/test/test/test_link_bonding_mode4.c
@@ -425,7 +425,7 @@ test_setup(void)
 			TEST_ASSERT(retval >= 0,
 				"Failed to create ring ethdev '%s'\n", name);
 
-			port->port_id = rte_eth_dev_count() - 1;
+			port->port_id = rte_eth_dev_count_avail() - 1;
 		}
 
 		retval = configure_ethdev(port->port_id, 1);
diff --git a/test/test/test_link_bonding_rssconf.c b/test/test/test_link_bonding_rssconf.c
index 4cc08f5a2..6a1a28d23 100644
--- a/test/test/test_link_bonding_rssconf.c
+++ b/test/test/test_link_bonding_rssconf.c
@@ -521,7 +521,7 @@ test_setup(void)
 	FOR_EACH_PORT(n, port) {
 		port = &test_params.slave_ports[n];
 
-		port_id = rte_eth_dev_count();
+		port_id = rte_eth_dev_count_avail();
 		snprintf(name, sizeof(name), SLAVE_DEV_NAME_FMT, port_id);
 
 		retval = rte_vdev_init(name, "size=64,copy=0");
diff --git a/test/test/test_pmd_perf.c b/test/test/test_pmd_perf.c
index 0e64a581b..54bc4f6b0 100644
--- a/test/test/test_pmd_perf.c
+++ b/test/test/test_pmd_perf.c
@@ -676,7 +676,7 @@ test_pmd_perf(void)
 	signal(SIGUSR1, signal_handler);
 	signal(SIGUSR2, signal_handler);
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports < NB_ETHPORTS_USED) {
 		printf("At least %u port(s) used for perf. test\n",
 		       NB_ETHPORTS_USED);
diff --git a/test/test/test_pmd_ring.c b/test/test/test_pmd_ring.c
index 0787e4ebf..219620125 100644
--- a/test/test/test_pmd_ring.c
+++ b/test/test/test_pmd_ring.c
@@ -399,7 +399,7 @@ test_pmd_ring(void)
 	int port, cmdl_port0 = -1;
 	uint8_t nb_ports;
 
-	nb_ports = rte_eth_dev_count();
+	nb_ports = rte_eth_dev_count_avail();
 	printf("nb_ports=%d\n", (int)nb_ports);
 
 	/*  create the rings and eth_rings in the test code.
-- 
2.16.2

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/3] ethdev: fix ports enumeration
  2018-04-05 15:33 ` [dpdk-dev] [PATCH v2 0/3] " Thomas Monjalon
                     ` (2 preceding siblings ...)
  2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 3/3] ethdev: deprecate port count function Thomas Monjalon
@ 2018-04-17 22:22   ` Thomas Monjalon
  3 siblings, 0 replies; 6+ messages in thread
From: Thomas Monjalon @ 2018-04-17 22:22 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit

05/04/2018 17:33, Thomas Monjalon:
> Some DPDK applications wrongly assume these requirements:
>   - no hotplug, i.e. ports are never detached
>   - all allocated ports are available to the application
> 
> Such application iterates over ports by its own mean.
> The most common pattern is to request the port count and
> assume ports with index in the range [0..count[ can be used.
> 
> There are three consequences when using such wrong design:
>   - new ports having an index higher than the port count won't be seen
>   - old ports being detached (RTE_ETH_DEV_UNUSED) can be seen as ghosts
>   - failsafe sub-devices (RTE_ETH_DEV_DEFERRED) will be seen by the application
> 
> Such mistake will be less common with growing hotplug awareness.
> All applications and examples inside this repository - except testpmd -
> must be fixed to use the iterator RTE_ETH_FOREACH_DEV,
> and to use the function rte_eth_dev_is_valid_port.
> 
> In order to fix this common mistake in all external applications,
> the function rte_eth_dev_count is deprecated, while introducing
> the new functions rte_eth_dev_count_avail and rte_eth_dev_count_total.


The RFC was sent on 9th of March, and this v2 is available since 5th of April,
without any comment.

Applied

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-04-17 22:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-09 22:22 [dpdk-dev] [RFC PATCH] ethdev: fix ports enumeration Thomas Monjalon
2018-04-05 15:33 ` [dpdk-dev] [PATCH v2 0/3] " Thomas Monjalon
2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 1/3] fix ethdev " Thomas Monjalon
2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 2/3] fix ethdev port id validation Thomas Monjalon
2018-04-05 15:33   ` [dpdk-dev] [PATCH v2 3/3] ethdev: deprecate port count function Thomas Monjalon
2018-04-17 22:22   ` [dpdk-dev] [PATCH v2 0/3] ethdev: fix ports enumeration Thomas Monjalon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).