DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 06/10] test/devargs: check driver presence with public API
From: Bruce Richardson @ 2026-07-17 10:14 UTC (permalink / raw)
  To: David Marchand; +Cc: dev
In-Reply-To: <CAJFAV8zaL+CVOaZ7THPc1yzjC-PYn072sUuSF25WngPdRNBLmw@mail.gmail.com>

On Fri, Jul 17, 2026 at 12:08:01PM +0200, David Marchand wrote:
> On Fri, 17 Jul 2026 at 11:56, Bruce Richardson
> <bruce.richardson@intel.com> wrote:
> >
> > On Fri, Jul 17, 2026 at 11:30:01AM +0200, David Marchand wrote:
> > > Let's avoid calling internal drivers API.
> > >
> > > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > > ---
> > Acked-by: Bruce Richardson <bruce.richardson@intel.com>
> >
> > One suggestion inline below.
> >
> > >  app/test/test_devargs.c | 10 +++++++---
> > >  1 file changed, 7 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
> > > index 0bd14c24ec..6c194ecfc6 100644
> > > --- a/app/test/test_devargs.c
> > > +++ b/app/test/test_devargs.c
> > > @@ -10,7 +10,7 @@
> > >  #include <rte_common.h>
> > >  #include <rte_devargs.h>
> > >  #include <rte_kvargs.h>
> > > -#include <bus_driver.h>
> > > +#include <rte_bus.h>
> > >  #include <rte_class.h>
> > >
> > >  #include "test.h"
> > > @@ -167,14 +167,18 @@ test_valid_devargs(void)
> > >               { "net_ring0,iface=test,path=/class/bus/,queues=1",
> > >                 0, 0, 3, "vdev", "net_ring0", NULL },
> > >       };
> > > -     struct rte_bus *vdev_bus = rte_bus_find_by_name("vdev");
> > > +     struct rte_devargs da;
> > >       int ret;
> > >
> > >       ret = test_valid_devargs_cases(list, RTE_DIM(list));
> > > -     if (vdev_bus != NULL && vdev_bus->parse("net_ring0", NULL) == 0)
> > > +
> > > +     memset(&da, 0, sizeof(da));
> > > +     if (rte_devargs_parse(&da, "net_ring0") == 0)
> >
> > From what I/AI can see, there is nothing in this test case that requires
> 
> (you could write it as "From what A?I can see")
> 
> > the ring PMD specifically. I think it would be good if it were updated to
> > use net/null, so that we standardize on our basic unit tests only relying
> > upon that PMD, rather than requiring a variety of drivers. WDYT?
> 
> There may be a hidden (capillotracté) reason.
> Passing path=/class/bus/ seems to be intended at catching errors in
> devargs parsing.
> No argument in net/null could accept such string.
> 
Not a path string, no, though it can take other parameters. Do we
specifically want/need it to take a path string?

/Bruce

^ permalink raw reply

* Re: [PATCH 06/10] test/devargs: check driver presence with public API
From: David Marchand @ 2026-07-17 10:08 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: dev
In-Reply-To: <aln8LkIk5q74OlpT@bricha3-mobl1.ger.corp.intel.com>

On Fri, 17 Jul 2026 at 11:56, Bruce Richardson
<bruce.richardson@intel.com> wrote:
>
> On Fri, Jul 17, 2026 at 11:30:01AM +0200, David Marchand wrote:
> > Let's avoid calling internal drivers API.
> >
> > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > ---
> Acked-by: Bruce Richardson <bruce.richardson@intel.com>
>
> One suggestion inline below.
>
> >  app/test/test_devargs.c | 10 +++++++---
> >  1 file changed, 7 insertions(+), 3 deletions(-)
> >
> > diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
> > index 0bd14c24ec..6c194ecfc6 100644
> > --- a/app/test/test_devargs.c
> > +++ b/app/test/test_devargs.c
> > @@ -10,7 +10,7 @@
> >  #include <rte_common.h>
> >  #include <rte_devargs.h>
> >  #include <rte_kvargs.h>
> > -#include <bus_driver.h>
> > +#include <rte_bus.h>
> >  #include <rte_class.h>
> >
> >  #include "test.h"
> > @@ -167,14 +167,18 @@ test_valid_devargs(void)
> >               { "net_ring0,iface=test,path=/class/bus/,queues=1",
> >                 0, 0, 3, "vdev", "net_ring0", NULL },
> >       };
> > -     struct rte_bus *vdev_bus = rte_bus_find_by_name("vdev");
> > +     struct rte_devargs da;
> >       int ret;
> >
> >       ret = test_valid_devargs_cases(list, RTE_DIM(list));
> > -     if (vdev_bus != NULL && vdev_bus->parse("net_ring0", NULL) == 0)
> > +
> > +     memset(&da, 0, sizeof(da));
> > +     if (rte_devargs_parse(&da, "net_ring0") == 0)
>
> From what I/AI can see, there is nothing in this test case that requires

(you could write it as "From what A?I can see")

> the ring PMD specifically. I think it would be good if it were updated to
> use net/null, so that we standardize on our basic unit tests only relying
> upon that PMD, rather than requiring a variety of drivers. WDYT?

There may be a hidden (capillotracté) reason.
Passing path=/class/bus/ seems to be intended at catching errors in
devargs parsing.
No argument in net/null could accept such string.


-- 
David Marchand


^ permalink raw reply

* [PATCH 2/2] net/tap: drain queue FD in Rx interrupt mode
From: Maxime Leroy @ 2026-07-17  9:58 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, stable, Maxime Leroy
In-Reply-To: <20260717095842.419130-1-maxime@leroys.fr>

The tap Rx path is driven by a SIGIO trigger: pmd_rx_burst() returns
without reading the queue fd unless tap_trigger, bumped by the O_ASYNC
signal handler, has advanced. That avoids a readv() on every empty poll.

In Rx interrupt mode the application blocks on the queue fd through epoll
and polls only after a wakeup. The epoll wakeup and the trigger are
distinct signals, so the burst can return 0 right after a wakeup because
the trigger has not advanced, leaving the fd readable with no further
edge: traffic stalls.

When the port is configured for Rx interrupts, drain the fd
unconditionally in the burst and do not arm the SIGIO trigger on the data
queue fd. A data queue fd can be closed and recreated on a later setup,
so the mode must stay constant to keep every fd on the same SIGIO policy:
it is fixed at configure time and a later change is rejected. Close and
reopen the port to switch modes.

Fixes: 4870a8cdd968 ("net/tap: support Rx interrupt")
Cc: stable@dpdk.org

Signed-off-by: Maxime Leroy <maxime@leroys.fr>
---
 drivers/net/tap/rte_eth_tap.c | 18 +++++++++++++++++-
 drivers/net/tap/rte_eth_tap.h |  2 ++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 99ede19e49..ea9ef76335 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -254,6 +254,10 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 		goto error;
 	}
 
+	/* interrupt mode wakes through epoll on the data queue fd, not the SIGIO trigger */
+	if (pmd->intr_mode)
+		return fd;
+
 	/* Find a free realtime signal */
 	for (signo = SIGRTMIN + 1; signo < SIGRTMAX; signo++) {
 		struct sigaction sa;
@@ -477,7 +481,7 @@ pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	unsigned long num_rx_bytes = 0;
 	uint32_t trigger = tap_trigger;
 
-	if (trigger == rxq->trigger_seen)
+	if (!rxq->intr_mode && trigger == rxq->trigger_seen)
 		return 0;
 
 	process_private = rte_eth_devices[rxq->in_port].process_private;
@@ -937,6 +941,16 @@ tap_dev_configure(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 	int intr_mode = !!dev->data->dev_conf.intr_conf.rxq;
 
+	/* The queue fd is created once and its SIGIO trigger is armed for poll
+	 * mode only; the interrupt mode cannot be toggled on an existing port.
+	 */
+	if (pmd->intr_mode_set && pmd->intr_mode != intr_mode) {
+		TAP_LOG(ERR,
+			"%s: Rx interrupt mode is fixed after configure, close and reopen the port to change it",
+			dev->device->name);
+		return -ENOTSUP;
+	}
+
 	if (dev->data->nb_rx_queues != dev->data->nb_tx_queues) {
 		TAP_LOG(ERR,
 			"%s: number of rx queues %d must be equal to number of tx queues %d",
@@ -947,6 +961,7 @@ tap_dev_configure(struct rte_eth_dev *dev)
 	}
 
 	pmd->intr_mode = intr_mode;
+	pmd->intr_mode_set = 1;
 
 	TAP_LOG(INFO, "%s: %s: TX configured queues number: %u",
 		dev->device->name, pmd->name, dev->data->nb_tx_queues);
@@ -1620,6 +1635,7 @@ tap_rx_queue_setup(struct rte_eth_dev *dev,
 	rxq->queue_id = rx_queue_id;
 	rxq->max_rx_segs = max_rx_segs;
 	rxq->rxmode = &dev->data->dev_conf.rxmode;
+	rxq->intr_mode = internals->intr_mode;
 
 	dev->data->rx_queues[rx_queue_id] = rxq;
 	int fd = tap_setup_queue(dev, rx_queue_id, 1);
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 3180719c34..abe22aac9f 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -50,6 +50,7 @@ struct rx_queue {
 	uint16_t queue_id;		/* queue ID*/
 	struct queue_stats stats;        /* Stats for this RX queue */
 	uint16_t max_rx_segs;           /* max scatter segments per packet */
+	uint16_t intr_mode;             /* 1 when Rx queue interrupts are used */
 	struct rte_eth_rxmode *rxmode;  /* RX features */
 	struct rte_mbuf *pool;          /* mbufs pool for this queue */
 	struct tun_pi pi;               /* packet info for iovecs */
@@ -94,6 +95,7 @@ struct pmd_internals {
 
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
 	int intr_mode;                    /* Rx queue interrupt mode */
+	int intr_mode_set;                /* intr_mode locked after configure */
 	int ka_fd;                        /* keep-alive file descriptor */
 	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 };
-- 
2.43.0


^ permalink raw reply related

* [PATCH 1/2] net/tap: support Rx queue interrupt enable/disable
From: Maxime Leroy @ 2026-07-17  9:58 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, stable, Maxime Leroy
In-Reply-To: <20260717095842.419130-1-maxime@leroys.fr>

The driver registers each queue file descriptor for Rx interrupts but
never provided the rx_queue_intr_enable/disable ops, so
rte_eth_dev_rx_intr_enable() returned -ENOTSUP. Applications that arm
queues before sleeping (l3fwd-power and similar) treat that as "no
interrupt support" and fall back to polling, even though the epoll wait
on the queue fd works. The advertised Rx interrupt feature is therefore
unusable through the generic API.

The queue fd is kept readable by the kernel whenever data is available
and is drained by the Rx burst itself, so there is no interrupt source to
arm or mask. Record whether the port was configured for Rx interrupts and
implement both ops to succeed in that mode and return -ENOTSUP otherwise,
so the generic Rx interrupt API works and applications can block on the
queue fd.

Fixes: 4870a8cdd968 ("net/tap: support Rx interrupt")
Cc: stable@dpdk.org

Signed-off-by: Maxime Leroy <maxime@leroys.fr>
---
 drivers/net/tap/rte_eth_tap.c |  5 ++++
 drivers/net/tap/rte_eth_tap.h |  3 +++
 drivers/net/tap/tap_intr.c    | 44 +++++++++++++++++++++++++++++++++++
 3 files changed, 52 insertions(+)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index b93452f168..99ede19e49 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -935,6 +935,7 @@ static int
 tap_dev_configure(struct rte_eth_dev *dev)
 {
 	struct pmd_internals *pmd = dev->data->dev_private;
+	int intr_mode = !!dev->data->dev_conf.intr_conf.rxq;
 
 	if (dev->data->nb_rx_queues != dev->data->nb_tx_queues) {
 		TAP_LOG(ERR,
@@ -945,6 +946,8 @@ tap_dev_configure(struct rte_eth_dev *dev)
 		return -1;
 	}
 
+	pmd->intr_mode = intr_mode;
+
 	TAP_LOG(INFO, "%s: %s: TX configured queues number: %u",
 		dev->device->name, pmd->name, dev->data->nb_tx_queues);
 
@@ -2098,6 +2101,8 @@ static const struct eth_dev_ops ops = {
 	.tx_queue_stop          = tap_tx_queue_stop,
 	.rx_queue_release       = tap_rx_queue_release,
 	.tx_queue_release       = tap_tx_queue_release,
+	.rx_queue_intr_enable   = tap_rx_queue_intr_enable,
+	.rx_queue_intr_disable  = tap_rx_queue_intr_disable,
 	.flow_ctrl_get          = tap_flow_ctrl_get,
 	.flow_ctrl_set          = tap_flow_ctrl_set,
 	.link_update            = tap_link_update,
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index f53a5ad077..3180719c34 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -93,6 +93,7 @@ struct pmd_internals {
 
 
 	struct rte_intr_handle *intr_handle;         /* LSC interrupt handle. */
+	int intr_mode;                    /* Rx queue interrupt mode */
 	int ka_fd;                        /* keep-alive file descriptor */
 	struct rte_mempool *gso_ctx_mp;     /* Mempool for GSO packets */
 };
@@ -104,5 +105,7 @@ struct pmd_process_private {
 /* tap_intr.c */
 
 int tap_rx_intr_vec_set(struct rte_eth_dev *dev, int set);
+int tap_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
+int tap_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);
 
 #endif /* _RTE_ETH_TAP_H_ */
diff --git a/drivers/net/tap/tap_intr.c b/drivers/net/tap/tap_intr.c
index 1908f71f97..7db22b69f5 100644
--- a/drivers/net/tap/tap_intr.c
+++ b/drivers/net/tap/tap_intr.c
@@ -112,3 +112,47 @@ tap_rx_intr_vec_set(struct rte_eth_dev *dev, int set)
 		return tap_rx_intr_vec_install(dev);
 	return 0;
 }
+
+/**
+ * Arm a queue for Rx interrupts.
+ *
+ * @param dev
+ *   Pointer to the tap rte_eth_dev device structure.
+ * @param queue_id
+ *   Rx queue index.
+ *
+ * @return
+ *   0 on success, -ENOTSUP if the port was not configured for Rx interrupts.
+ */
+int
+tap_rx_queue_intr_enable(struct rte_eth_dev *dev,
+			 uint16_t queue_id __rte_unused)
+{
+	struct pmd_internals *pmd = dev->data->dev_private;
+
+	if (!pmd->intr_mode)
+		return -ENOTSUP;
+	return 0;
+}
+
+/**
+ * Disarm a queue from Rx interrupts.
+ *
+ * @param dev
+ *   Pointer to the tap rte_eth_dev device structure.
+ * @param queue_id
+ *   Rx queue index.
+ *
+ * @return
+ *   0 on success, -ENOTSUP if the port was not configured for Rx interrupts.
+ */
+int
+tap_rx_queue_intr_disable(struct rte_eth_dev *dev,
+			  uint16_t queue_id __rte_unused)
+{
+	struct pmd_internals *pmd = dev->data->dev_private;
+
+	if (!pmd->intr_mode)
+		return -ENOTSUP;
+	return 0;
+}
-- 
2.43.0


^ permalink raw reply related

* [PATCH 0/2] net/tap: fix Rx queue interrupt support
From: Maxime Leroy @ 2026-07-17  9:58 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, stable, Maxime Leroy

The tap PMD registers each queue file descriptor for Rx interrupts but the
feature is not actually usable through the generic API. This series fixes
two distinct issues, both against the original Rx interrupt support.

Patch 1 adds the missing rx_queue_intr_enable/disable ops. Without them
rte_eth_dev_rx_intr_enable() returns -ENOTSUP, so applications that arm
queues before sleeping (l3fwd-power and similar) treat tap as having no
interrupt support and fall back to polling.

Patch 2 fixes a traffic stall specific to interrupt mode: the Rx burst
skips reading the queue fd until the SIGIO trigger advances, but in
interrupt mode the application wakes through epoll, a distinct signal, so
the burst can return 0 right after a wakeup and the fd stays readable with
no further edge. The fd is now drained unconditionally in interrupt mode
and the SIGIO trigger is not armed on the data queue fds.

Both patches are candidates for stable.

Maxime Leroy (2):
  net/tap: support Rx queue interrupt enable/disable
  net/tap: drain queue FD in Rx interrupt mode

 drivers/net/tap/rte_eth_tap.c | 23 +++++++++++++++++-
 drivers/net/tap/rte_eth_tap.h |  5 ++++
 drivers/net/tap/tap_intr.c    | 44 +++++++++++++++++++++++++++++++++++
 3 files changed, 71 insertions(+), 1 deletion(-)

-- 
2.43.0


^ permalink raw reply

* Re: [PATCH 06/10] test/devargs: check driver presence with public API
From: Bruce Richardson @ 2026-07-17  9:55 UTC (permalink / raw)
  To: David Marchand; +Cc: dev
In-Reply-To: <20260717093006.229370-7-david.marchand@redhat.com>

On Fri, Jul 17, 2026 at 11:30:01AM +0200, David Marchand wrote:
> Let's avoid calling internal drivers API.
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
Acked-by: Bruce Richardson <bruce.richardson@intel.com>

One suggestion inline below.

>  app/test/test_devargs.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
> index 0bd14c24ec..6c194ecfc6 100644
> --- a/app/test/test_devargs.c
> +++ b/app/test/test_devargs.c
> @@ -10,7 +10,7 @@
>  #include <rte_common.h>
>  #include <rte_devargs.h>
>  #include <rte_kvargs.h>
> -#include <bus_driver.h>
> +#include <rte_bus.h>
>  #include <rte_class.h>
>  
>  #include "test.h"
> @@ -167,14 +167,18 @@ test_valid_devargs(void)
>  		{ "net_ring0,iface=test,path=/class/bus/,queues=1",
>  		  0, 0, 3, "vdev", "net_ring0", NULL },
>  	};
> -	struct rte_bus *vdev_bus = rte_bus_find_by_name("vdev");
> +	struct rte_devargs da;
>  	int ret;
>  
>  	ret = test_valid_devargs_cases(list, RTE_DIM(list));
> -	if (vdev_bus != NULL && vdev_bus->parse("net_ring0", NULL) == 0)
> +
> +	memset(&da, 0, sizeof(da));
> +	if (rte_devargs_parse(&da, "net_ring0") == 0)

From what I/AI can see, there is nothing in this test case that requires
the ring PMD specifically. I think it would be good if it were updated to
use net/null, so that we standardize on our basic unit tests only relying
upon that PMD, rather than requiring a variety of drivers. WDYT?

>  		/* Ring vdev driver enabled. */
>  		ret |= test_valid_devargs_cases(legacy_ring_list,
>  						RTE_DIM(legacy_ring_list));
> +	rte_devargs_reset(&da);
> +
>  	return ret;
>  }
>  
> -- 
> 2.54.0
> 

^ permalink raw reply

* RE: [PATCH 03/10] hash: fix GFNI stubs export
From: Konstantin Ananyev @ 2026-07-17  9:55 UTC (permalink / raw)
  To: David Marchand, dev@dpdk.org
  Cc: Yipeng Wang, Sameh Gobriel, Bruce Richardson, Vladimir Medvedkin,
	Stephen Hemminger
In-Reply-To: <20260717093006.229370-4-david.marchand@redhat.com>


> 
> Internal symbols *can not* be called as part of public ABI.
> The GFNI stubs must be exported so that an application may call them
> through the (inlined) GFNI API without requiring ALLOW_INTERNAL_API.
> 
> Fixes: 944a03a5cfc1 ("hash: fix MSVC link on GFNI stubs")
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
>  lib/hash/rte_thash_gfni.c | 4 ++--
>  lib/hash/rte_thash_gfni.h | 2 --
>  2 files changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/lib/hash/rte_thash_gfni.c b/lib/hash/rte_thash_gfni.c
> index 2003c7b3db..ae55f7f711 100644
> --- a/lib/hash/rte_thash_gfni.c
> +++ b/lib/hash/rte_thash_gfni.c
> @@ -13,7 +13,7 @@ RTE_LOG_REGISTER_SUFFIX(hash_gfni_logtype, gfni, INFO);
>  #define HASH_LOG(level, ...) \
>  	RTE_LOG_LINE(level, HASH, "" __VA_ARGS__)
> 
> -RTE_EXPORT_INTERNAL_SYMBOL(rte_thash_gfni_stub)
> +RTE_EXPORT_SYMBOL(rte_thash_gfni_stub)
>  uint32_t
>  rte_thash_gfni_stub(const uint64_t *mtrx __rte_unused,
>  	const uint8_t *key __rte_unused, int len __rte_unused)
> @@ -29,7 +29,7 @@ rte_thash_gfni_stub(const uint64_t *mtrx __rte_unused,
>  	return 0;
>  }
> 
> -RTE_EXPORT_INTERNAL_SYMBOL(rte_thash_gfni_bulk_stub)
> +RTE_EXPORT_SYMBOL(rte_thash_gfni_bulk_stub)
>  void
>  rte_thash_gfni_bulk_stub(const uint64_t *mtrx __rte_unused,
>  	int len __rte_unused, uint8_t *tuple[] __rte_unused,
> diff --git a/lib/hash/rte_thash_gfni.h b/lib/hash/rte_thash_gfni.h
> index e82378933c..8a72fa9ec6 100644
> --- a/lib/hash/rte_thash_gfni.h
> +++ b/lib/hash/rte_thash_gfni.h
> @@ -22,11 +22,9 @@ extern "C" {
>   * @internal
>   * Stubs only used when GFNI is not available.
>   */
> -__rte_internal
>  uint32_t
>  rte_thash_gfni_stub(const uint64_t *mtrx, const uint8_t *key, int len);
> 
> -__rte_internal
>  void
>  rte_thash_gfni_bulk_stub(const uint64_t *mtrx, int len, uint8_t *tuple[],
>  	uint32_t val[], uint32_t num);
> --

Acked-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>

> 2.54.0


^ permalink raw reply

* Re: [PATCH v3 0/8] doc: clean-up links in guides
From: fengchengwen @ 2026-07-17  9:42 UTC (permalink / raw)
  To: dev
In-Reply-To: <20260716103632.711164-1-thomas@monjalon.net>

Series-acked-by: Chengwen Feng <fengchengwen@huawei.com>

On 7/16/2026 6:31 PM, Thomas Monjalon wrote:
> Links and references to other guide sections had multiple issues,
> all solved in this series.
> 
> The important metric in cleanups is having more deletions than additions:
>  278 files changed, 1054 insertions(+), 1700 deletions(-)
> meaning it should be easier to maintain.
> 
> 
> David Marchand (1):
>   doc: remove unused labels from guides
> 
> Nandini Persad (1):
>   doc: add prefixes to guide labels
> 
> Thomas Monjalon (6):
>   doc: adjust heading underline lengths
>   doc: replace vague references with precise links
>   doc: shorten page references in guides
>   doc: link whole-guide references to pages
>   doc: remove redundant link captions
>   doc: avoid numbered guide references

^ permalink raw reply

* Re: [PATCH] usertools/telemetry: load aliases from config directory
From: fengchengwen @ 2026-07-17  9:40 UTC (permalink / raw)
  To: Thomas Monjalon, dev; +Cc: Bruce Richardson, Robin Jarry
In-Reply-To: <20260717091603.1492650-1-thomas@monjalon.net>

Acked-by: Chengwen Feng <fengchengwen@huawei.com>

On 7/17/2026 5:16 PM, Thomas Monjalon wrote:
> The default path of the telemetry alias file
> was at the top level of the home directory.
> 
> Load aliases from the DPDK configuration directory instead,
> using $XDG_CONFIG_HOME/dpdk/telemetry_aliases
> or $HOME/.config/dpdk/telemetry_aliases.
> 
> Keep --alias-file for users who want to provide an explicit path.
> 
> Fixes: 410d498412e4 ("usertools/telemetry: support aliases for long commands")
> 
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>


^ permalink raw reply

* Re: [PATCH 04/10] test: uninline helper for forking
From: Bruce Richardson @ 2026-07-17  9:39 UTC (permalink / raw)
  To: David Marchand; +Cc: dev, Thomas Monjalon, Reshma Pattan, Stephen Hemminger
In-Reply-To: <20260717093006.229370-5-david.marchand@redhat.com>

On Fri, Jul 17, 2026 at 11:29:59AM +0200, David Marchand wrote:
> There is no reason to keep those helpers inlined.
> 
> Besides, this code relies on internal API.
> So any consumer of process.h requires internal API.
> 
> Move this code in process.c.
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>

^ permalink raw reply

* Re: [PATCH] usertools/telemetry: load aliases from config directory
From: Robin Jarry @ 2026-07-17  9:38 UTC (permalink / raw)
  To: Thomas Monjalon, dev; +Cc: Bruce Richardson, Chengwen Feng
In-Reply-To: <20260717091603.1492650-1-thomas@monjalon.net>

Thomas Monjalon, Jul 17, 2026 at 11:16:
> The default path of the telemetry alias file
> was at the top level of the home directory.
>
> Load aliases from the DPDK configuration directory instead,
> using $XDG_CONFIG_HOME/dpdk/telemetry_aliases
> or $HOME/.config/dpdk/telemetry_aliases.
>
> Keep --alias-file for users who want to provide an explicit path.
>
> Fixes: 410d498412e4 ("usertools/telemetry: support aliases for long commands")
>
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> ---

Acked-by: Robin Jarry <rjarry@redhat.com>


^ permalink raw reply

* Re: [PATCH 03/10] hash: fix GFNI stubs export
From: Bruce Richardson @ 2026-07-17  9:38 UTC (permalink / raw)
  To: David Marchand
  Cc: dev, Yipeng Wang, Sameh Gobriel, Vladimir Medvedkin,
	Stephen Hemminger
In-Reply-To: <20260717093006.229370-4-david.marchand@redhat.com>

On Fri, Jul 17, 2026 at 11:29:58AM +0200, David Marchand wrote:
> Internal symbols *can not* be called as part of public ABI.
> The GFNI stubs must be exported so that an application may call them
> through the (inlined) GFNI API without requiring ALLOW_INTERNAL_API.
> 
> Fixes: 944a03a5cfc1 ("hash: fix MSVC link on GFNI stubs")
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
> ---
>  lib/hash/rte_thash_gfni.c | 4 ++--
>  lib/hash/rte_thash_gfni.h | 2 --
>  2 files changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/lib/hash/rte_thash_gfni.c b/lib/hash/rte_thash_gfni.c
> index 2003c7b3db..ae55f7f711 100644
> --- a/lib/hash/rte_thash_gfni.c
> +++ b/lib/hash/rte_thash_gfni.c
> @@ -13,7 +13,7 @@ RTE_LOG_REGISTER_SUFFIX(hash_gfni_logtype, gfni, INFO);
>  #define HASH_LOG(level, ...) \
>  	RTE_LOG_LINE(level, HASH, "" __VA_ARGS__)
>  
> -RTE_EXPORT_INTERNAL_SYMBOL(rte_thash_gfni_stub)
> +RTE_EXPORT_SYMBOL(rte_thash_gfni_stub)
>  uint32_t
>  rte_thash_gfni_stub(const uint64_t *mtrx __rte_unused,
>  	const uint8_t *key __rte_unused, int len __rte_unused)
> @@ -29,7 +29,7 @@ rte_thash_gfni_stub(const uint64_t *mtrx __rte_unused,
>  	return 0;
>  }
>  
> -RTE_EXPORT_INTERNAL_SYMBOL(rte_thash_gfni_bulk_stub)
> +RTE_EXPORT_SYMBOL(rte_thash_gfni_bulk_stub)
>  void
>  rte_thash_gfni_bulk_stub(const uint64_t *mtrx __rte_unused,
>  	int len __rte_unused, uint8_t *tuple[] __rte_unused,
> diff --git a/lib/hash/rte_thash_gfni.h b/lib/hash/rte_thash_gfni.h
> index e82378933c..8a72fa9ec6 100644
> --- a/lib/hash/rte_thash_gfni.h
> +++ b/lib/hash/rte_thash_gfni.h
> @@ -22,11 +22,9 @@ extern "C" {
>   * @internal
>   * Stubs only used when GFNI is not available.
>   */
> -__rte_internal
>  uint32_t
>  rte_thash_gfni_stub(const uint64_t *mtrx, const uint8_t *key, int len);
>  
> -__rte_internal
>  void
>  rte_thash_gfni_bulk_stub(const uint64_t *mtrx, int len, uint8_t *tuple[],
>  	uint32_t val[], uint32_t num);
> -- 
> 2.54.0
> 

^ permalink raw reply

* Re: [PATCH] usertools/telemetry: load aliases from config directory
From: Bruce Richardson @ 2026-07-17  9:37 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Robin Jarry, Chengwen Feng
In-Reply-To: <20260717091603.1492650-1-thomas@monjalon.net>

On Fri, Jul 17, 2026 at 11:16:03AM +0200, Thomas Monjalon wrote:
> The default path of the telemetry alias file
> was at the top level of the home directory.
> 
> Load aliases from the DPDK configuration directory instead,
> using $XDG_CONFIG_HOME/dpdk/telemetry_aliases
> or $HOME/.config/dpdk/telemetry_aliases.
> 
> Keep --alias-file for users who want to provide an explicit path.
> 
> Fixes: 410d498412e4 ("usertools/telemetry: support aliases for long commands")
> 
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>

Tested without moving my existing alias file - no aliases loaded. Then
tested after moving to .config/dpdk/ and it worked fine.

Doc changes LGTM too.

Tested-by: Bruce Richardson <bruce.richardson@intel.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>


> ---
>  doc/guides/howto/telemetry.rst |  6 ++++--
>  usertools/dpdk-telemetry.py    | 23 +++++++++++++++++------
>  2 files changed, 21 insertions(+), 8 deletions(-)
> 
> diff --git a/doc/guides/howto/telemetry.rst b/doc/guides/howto/telemetry.rst
> index b3f25c1113..fdaede1987 100644
> --- a/doc/guides/howto/telemetry.rst
> +++ b/doc/guides/howto/telemetry.rst
> @@ -154,9 +154,11 @@ and query information using the telemetry client python script.
>  
>       The telemetry script can load aliases at startup from::
>  
> -        $HOME/.dpdk_telemetry_aliases
> +        $XDG_CONFIG_HOME/dpdk/telemetry_aliases
> +
> +     If ``XDG_CONFIG_HOME`` is not set, ``$HOME/.config/dpdk/telemetry_aliases`` is used.
> +     A custom path can also be provided via the ``--alias-file`` script flag.
>  
> -     or from a custom path provided via the ``--alias-file`` script flag.
>       Each alias entry must be in ``alias=command`` format.
>       Empty lines and lines starting with ``#`` are ignored.
>  
> diff --git a/usertools/dpdk-telemetry.py b/usertools/dpdk-telemetry.py
> index 20627b596b..e575f269cb 100755
> --- a/usertools/dpdk-telemetry.py
> +++ b/usertools/dpdk-telemetry.py
> @@ -22,7 +22,7 @@
>  DEFAULT_PREFIX = "rte"
>  CMDS = []
>  ALIASES = {}
> -ALIAS_FILE = ".dpdk_telemetry_aliases"
> +ALIAS_FILE = "telemetry_aliases"
>  MAX_ALIAS_EXPANSIONS = 32
>  
>  BASIC_HELP_TEXT = """Basic usage:
> @@ -46,19 +46,30 @@
>  """
>  
>  
> +def get_default_alias_path():
> +    config_home = os.environ.get("XDG_CONFIG_HOME")
> +    if config_home:
> +        return os.path.join(config_home, "dpdk", ALIAS_FILE)
> +
> +    home = os.environ.get("HOME")
> +    if not home:
> +        return None
> +
> +    return os.path.join(home, ".config", "dpdk", ALIAS_FILE)
> +
> +
>  def load_aliases(alias_path=None):
> -    """Load aliases from $HOME/.dpdk_telemetry_aliases or a custom path if provided"""
> +    """Load aliases from the config directory or a custom path if provided"""
>      aliases = {}
>      if alias_path and not os.path.isfile(alias_path):
>          print("Warning: alias file {} not found, skipping".format(alias_path), file=sys.stderr)
>          return aliases
>  
>      if not alias_path:
> -        home = os.environ.get("HOME")
> -        if not home:
> +        alias_path = get_default_alias_path()
> +        if not alias_path:
>              return aliases
>  
> -        alias_path = os.path.join(home, ALIAS_FILE)
>          if not os.path.isfile(alias_path):
>              return aliases
>  
> @@ -434,7 +445,7 @@ def readline_complete(text, state):
>  )
>  parser.add_argument(
>      "--alias-file",
> -    help=f"Provide a custom alias file instead of $HOME/{ALIAS_FILE}",
> +    help="Provide a custom alias file instead of the default config path",
>  )
>  parser.add_argument(
>      "-i", "--instance", default="0", type=int, help="Provide instance number for DPDK application"
> -- 
> 2.54.0
> 

^ permalink raw reply

* [DPDK/core Bug 1967] [dpdk-26.07] ABI testing dpdk26.07+dpdk25.11 meson_tests/test_fasts vdev_autotest and devargs_autotest both failed
From: bugzilla @ 2026-07-17  9:36 UTC (permalink / raw)
  To: dev
In-Reply-To: <bug-1967-3@http.bugs.dpdk.org/>

http://bugs.dpdk.org/show_bug.cgi?id=1967

David Marchand (david.marchand@redhat.com) changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |WONTFIX
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #2 from David Marchand (david.marchand@redhat.com) ---
As explained above, the breakage is known and we don't intend to fix it.

-- 
You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* Re: [PATCH 00/10] Limit usage of internal API in tests
From: David Marchand @ 2026-07-17  9:35 UTC (permalink / raw)
  To: dev
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

On Fri, 17 Jul 2026 at 11:30, David Marchand <david.marchand@redhat.com> wrote:
>
> This series is aimed at 26.11.
>
> We had a few bug reports related to internal (and experimental) symbols
> issues during 26.07 development.
> See for example https://bugs.dpdk.org/show_bug.cgi?id=1957 or more
> recently https://bugs.dpdk.org/show_bug.cgi?id=1967.
>
> To catch such issues earlier in the CI, this series proposes to run
> the unit tests through meson with the ABI reference unit test binary
> against the current ABI libraries and drivers.

I could have called test-null.sh for checking testpmd too.
For a next revision if any.

>
> For this to work, some unit tests must be skipped (since meson may
> invoke the ABI reference code with tests that were unknown at the time).
>
> A few unit tests were directly dereferencing internal structures and are
> reworked so they use public APIs.
>
> Additionally, unit tests were allowed to use any internal API which has
> hidden a few issues (like a public API backed by internal symbols in the
> hash library).
> So disable the global ALLLOW_INTERNAL_API and move it to code explicitly
> requiring internal API, with the hope it will push us to have better API.
>
> The last patch contains a hack for now, where the cached ABI reference
> is force regenerated with a branch of mine where I backported the
> fixes of this series.


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH] test/dispatcher: transfer impl_opaque field
From: Thomas Monjalon @ 2026-07-17  9:34 UTC (permalink / raw)
  To: Mattias Rönnblom, dev, Jerin Jacob Kollanukkaran
  Cc: hofors, Luka Jankovic, stable
In-Reply-To: <20241211141303.132448-1-mattias.ronnblom@ericsson.com>

> The dispatcher tests failed to transfer the impl_opaque rte_event
> field between the dequeued and enqueued event, in violation with the
> Eventdev API contract.
>
> Fixes: ecca8a0be606 ("lib: introduce dispatcher library")
> Cc: stable@dpdk.org
>
> Signed-off-by: Mattias Rönnblom <mattias.ronnblom@ericsson.com>

Applied, thanks.

(better late than never)

^ permalink raw reply

* [PATCH 10/10] ci: run reference unit tests against ABI
From: David Marchand @ 2026-07-17  9:30 UTC (permalink / raw)
  To: dev; +Cc: Aaron Conole
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

Let's check if unit tests from the reference build can run with the
current release libraries/drivers.

This gives another level of ABI checking, like catching regressions on
experimental or internal ABI symbols that get promoted to stable.

Skip unit tests that were added since the reference (iow v26.03).
$ git diff v26.03..origin/main |
  sed -ne 's/^[+]REGISTER_FAST_TEST(\([^,]*\).*$/\1/p' |
  sort
af_packet_pmd_autotest
bpf_exec_wrong_flags_autotest
bpf_exec_wrong_nb_prog_arg_autotest
bpf_load_null_autotest
bpf_validate_autotest
eal_flags_pagesz_mem_autotest
feature_autotest
pcap_pmd_autotest
reassembly_autotest

As reported in https://bugs.dpdk.org/show_bug.cgi?id=1967, devargs
and vdev autotests are broken due to drivers ABI changes since
those unit tests are directly accessing internal objects.
FIXME: for now, use a branch of mine with backports on 26.03.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 .ci/linux-build.sh          | 28 +++++++++++++++++++++++++---
 .github/workflows/build.yml | 15 +++++++++++++--
 2 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh
index a5e602ed83..f4fb398cd9 100755
--- a/.ci/linux-build.sh
+++ b/.ci/linux-build.sh
@@ -200,23 +200,28 @@ if [ "$ABI_CHECKS" = "true" ]; then
         rm -rf reference
     fi
 
+    # FIXME: force regeneration in CI for this patch
+    if [ ! -e reference/usr/local/bin/dpdk-test ]; then
+        rm -rf reference
+    fi
+
     if [ ! -d reference ]; then
         REF_OPTS="$OPTS"
         # We only care about the drivers and libs, disable developer checks and
         # don't try to link apps.
         REF_OPTS="$REF_OPTS -Dcheck_includes=false"
         REF_OPTS="$REF_OPTS -Ddeveloper_mode=disabled"
-        REF_OPTS="$REF_OPTS -Ddisable_apps=*"
+        REF_OPTS="$REF_OPTS -Denable_apps=test"
         REF_OPTS="$REF_OPTS -Denable_docs=false"
         REF_OPTS="$REF_OPTS -Dexamples="
-        REF_OPTS="$REF_OPTS -Dtests=false"
         refsrcdir=$(readlink -f $(pwd)/../dpdk-$REF_GIT_TAG)
         git clone --single-branch -b "$REF_GIT_TAG" $REF_GIT_REPO $refsrcdir
         meson setup $REF_OPTS $refsrcdir $refsrcdir/build
         ninja -C $refsrcdir/build
         DESTDIR=$(pwd)/reference meson install -C $refsrcdir/build
         find reference/usr/local -name '*.a' -delete
-        rm -rf reference/usr/local/bin
+        rm -rf reference/usr/local/bin/*
+        cp $refsrcdir/build/app/dpdk-test reference/usr/local/bin/dpdk-test
         rm -rf reference/usr/local/share
         echo $REF_GIT_TAG > reference/VERSION
     fi
@@ -233,6 +238,23 @@ if [ "$RUN_TESTS" = "true" ]; then
     catch_ubsan DPDK:fast-tests build/meson-logs/testlog.txt
     check_traces
     [ "$failed" != "true" ]
+
+    if [ "$ABI_CHECKS" = "true" ]; then
+        failed=
+        configure_coredump
+        mv -f build/app/dpdk-test build/app/dpdk-test.ori
+        cp reference/usr/local/bin/dpdk-test build/app/dpdk-test
+        for t in ${ABI_SKIP_TESTS}; do
+            DPDK_TEST_SKIP=${DPDK_TEST_SKIP+$DPDK_TEST_SKIP,}$t
+        done
+        sudo env DPDK_TEST_SKIP="$DPDK_TEST_SKIP" \
+            meson test -C build --suite fast-tests -t 3 --no-stdsplit --print-errorlogs || failed="true"
+        catch_coredump
+        catch_ubsan DPDK:fast-tests build/meson-logs/testlog.txt
+        check_traces
+        mv -f build/app/dpdk-test.ori build/app/dpdk-test
+        [ "$failed" != "true" ]
+    fi
 fi
 
 # Test examples compilation with an installed dpdk
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f0ef39d34f..b311ee26f9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,8 +11,9 @@ defaults:
 
 env:
   REF_GIT_BRANCH: main
-  REF_GIT_REPO: https://github.com/DPDK/dpdk
-  REF_GIT_TAG: v26.03
+  # FIXME
+  REF_GIT_REPO: https://github.com/david-marchand/dpdk
+  REF_GIT_TAG: 26.03
 
 jobs:
   checkpatch:
@@ -39,6 +40,16 @@ jobs:
     env:
       AARCH64: ${{ matrix.config.cross == 'aarch64' }}
       ABI_CHECKS: ${{ contains(matrix.config.checks, 'abi') }}
+      ABI_SKIP_TESTS: |
+        af_packet_pmd_autotest
+        bpf_exec_wrong_flags_autotest
+        bpf_exec_wrong_nb_prog_arg_autotest
+        bpf_load_null_autotest
+        bpf_validate_autotest
+        eal_flags_pagesz_mem_autotest
+        feature_autotest
+        pcap_pmd_autotest
+        reassembly_autotest
       ASAN: ${{ contains(matrix.config.checks, 'asan') }}
       BUILD_32BIT: ${{ matrix.config.cross == 'i386' }}
       BUILD_DEBUG: ${{ contains(matrix.config.checks, 'debug') }}
-- 
2.54.0


^ permalink raw reply related

* [PATCH 09/10] ci: make ABI reference generation faster
From: David Marchand @ 2026-07-17  9:30 UTC (permalink / raw)
  To: dev; +Cc: Aaron Conole, Bruce Richardson
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

Regenerating ABI is not something we do often, but when working on ABI
topics, a lot of time may be wasted on waiting for the reference being
generated.

We only care about shared libraries, avoid building final applications
or examples.
And we don't need to double check headers in the ABI reference.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 .ci/linux-build.sh            | 11 ++++++++++-
 devtools/test-meson-builds.sh |  5 ++++-
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh
index e0b914a142..a5e602ed83 100755
--- a/.ci/linux-build.sh
+++ b/.ci/linux-build.sh
@@ -201,9 +201,18 @@ if [ "$ABI_CHECKS" = "true" ]; then
     fi
 
     if [ ! -d reference ]; then
+        REF_OPTS="$OPTS"
+        # We only care about the drivers and libs, disable developer checks and
+        # don't try to link apps.
+        REF_OPTS="$REF_OPTS -Dcheck_includes=false"
+        REF_OPTS="$REF_OPTS -Ddeveloper_mode=disabled"
+        REF_OPTS="$REF_OPTS -Ddisable_apps=*"
+        REF_OPTS="$REF_OPTS -Denable_docs=false"
+        REF_OPTS="$REF_OPTS -Dexamples="
+        REF_OPTS="$REF_OPTS -Dtests=false"
         refsrcdir=$(readlink -f $(pwd)/../dpdk-$REF_GIT_TAG)
         git clone --single-branch -b "$REF_GIT_TAG" $REF_GIT_REPO $refsrcdir
-        meson setup $OPTS -Dexamples= $refsrcdir $refsrcdir/build
+        meson setup $REF_OPTS $refsrcdir $refsrcdir/build
         ninja -C $refsrcdir/build
         DESTDIR=$(pwd)/reference meson install -C $refsrcdir/build
         find reference/usr/local -name '*.a' -delete
diff --git a/devtools/test-meson-builds.sh b/devtools/test-meson-builds.sh
index 11e4be3f88..8ca7091b47 100755
--- a/devtools/test-meson-builds.sh
+++ b/devtools/test-meson-builds.sh
@@ -206,8 +206,11 @@ build () # <directory> <target cc | cross file> <ABI check> [meson options]
 			fi
 
 			rm -rf $abirefdir/build
+			# We only care about the drivers and libs, disable
+			# developer checks and don't try to link apps.
 			config $abirefdir/src $abirefdir/build ABI $cross \
-				-Dexamples= $*
+				$* -Dcheck_includes=false -Ddeveloper_mode=disabled \
+				-Ddisable_apps=* -Dexamples= -Dtests=false
 			compile $abirefdir/build
 			install_target $abirefdir/build $abirefdir/$targetdir
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH 08/10] test: limit internal API usage
From: David Marchand @ 2026-07-17  9:30 UTC (permalink / raw)
  To: dev
  Cc: Anatoly Burakov, Andrew Rybchenko, Morten Brørup,
	Reshma Pattan, Stephen Hemminger
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

Internal APIs may be used for validating the internals of some
component, but in general, it should be discouraged.

Let's not allow globally internal API in the unit tests.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 app/test/meson.build         | 3 ---
 app/test/process.c           | 2 ++
 app/test/test_devargs.c      | 2 ++
 app/test/test_external_mem.c | 2 ++
 app/test/test_malloc.c       | 2 ++
 app/test/test_mempool.c      | 2 ++
 app/test/test_pdump.c        | 3 +++
 app/test/virtual_pmd.c       | 2 ++
 8 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/app/test/meson.build b/app/test/meson.build
index d8efa93050..e3dfa1d24c 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -286,9 +286,6 @@ foreach arg: extra_flags
     endif
 endforeach
 
-# Enable using internal APIs in unit tests
-cflags += '-DALLOW_INTERNAL_API'
-
 # create a symlink in the app/test directory for the binary, for backward compatibility
 if not is_windows
     custom_target('test_symlink',
diff --git a/app/test/process.c b/app/test/process.c
index 2b6d7ae84b..92c8af702b 100644
--- a/app/test/process.c
+++ b/app/test/process.c
@@ -2,6 +2,8 @@
  * Copyright(c) 2010-2014 Intel Corporation
  */
 
+#define ALLOW_INTERNAL_API
+
 #include <errno.h>  /* errno */
 #include <limits.h> /* PATH_MAX */
 #ifndef RTE_EXEC_ENV_WINDOWS
diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
index 6c194ecfc6..66cf046463 100644
--- a/app/test/test_devargs.c
+++ b/app/test/test_devargs.c
@@ -2,6 +2,8 @@
  * Copyright (c) 2021 NVIDIA Corporation & Affiliates
  */
 
+#define ALLOW_INTERNAL_API
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
diff --git a/app/test/test_external_mem.c b/app/test/test_external_mem.c
index 53300983ed..2c8d0d8e00 100644
--- a/app/test/test_external_mem.c
+++ b/app/test/test_external_mem.c
@@ -2,6 +2,8 @@
  * Copyright(c) 2018 Intel Corporation
  */
 
+#define ALLOW_INTERNAL_API
+
 #include "test.h"
 
 #include <errno.h>
diff --git a/app/test/test_malloc.c b/app/test/test_malloc.c
index da868c8091..151d1a3f2c 100644
--- a/app/test/test_malloc.c
+++ b/app/test/test_malloc.c
@@ -2,6 +2,8 @@
  * Copyright(c) 2010-2019 Intel Corporation
  */
 
+#define ALLOW_INTERNAL_API
+
 #include "test.h"
 
 #include <stdio.h>
diff --git a/app/test/test_mempool.c b/app/test/test_mempool.c
index e54249ce61..f1e8adeef9 100644
--- a/app/test/test_mempool.c
+++ b/app/test/test_mempool.c
@@ -2,6 +2,8 @@
  * Copyright(c) 2010-2014 Intel Corporation
  */
 
+#define ALLOW_INTERNAL_API
+
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/app/test/test_pdump.c b/app/test/test_pdump.c
index 64f1bbf21c..f1c9bd9d7e 100644
--- a/app/test/test_pdump.c
+++ b/app/test/test_pdump.c
@@ -1,6 +1,9 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2018 Intel Corporation
  */
+
+#define ALLOW_INTERNAL_API
+
 #include <stdio.h>
 #include <unistd.h>
 #include <stdint.h>
diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
index aa37e4073c..74bb3516ab 100644
--- a/app/test/virtual_pmd.c
+++ b/app/test/virtual_pmd.c
@@ -2,6 +2,8 @@
  * Copyright(c) 2010-2014 Intel Corporation
  */
 
+#define ALLOW_INTERNAL_API
+
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
 #include <ethdev_driver.h>
-- 
2.54.0


^ permalink raw reply related

* [PATCH 07/10] test/vdev: find device with public API
From: David Marchand @ 2026-07-17  9:30 UTC (permalink / raw)
  To: dev
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

Checking internal API has little sense as users are not supposed to call
those.
Use public API to achieve similar coverage.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 app/test/test_vdev.c | 85 ++++++++------------------------------------
 1 file changed, 15 insertions(+), 70 deletions(-)

diff --git a/app/test/test_vdev.c b/app/test/test_vdev.c
index c300976ace..6951ef7cc3 100644
--- a/app/test/test_vdev.c
+++ b/app/test/test_vdev.c
@@ -2,69 +2,26 @@
  * Copyright 2021 6WIND S.A.
  */
 
-#include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
-#include <rte_common.h>
 #include <rte_dev.h>
-#include <rte_kvargs.h>
-#include <bus_driver.h>
+#include <rte_bus.h>
 #include <rte_bus_vdev.h>
 
 #include "test.h"
 
-#define TEST_VDEV_KEY_NAME "name"
-
-static const char * const valid_keys[] = {
-	TEST_VDEV_KEY_NAME,
-	NULL,
-};
-
-static int
-cmp_dev_name(const struct rte_device *dev, const void *name)
-{
-	return strcmp(rte_dev_name(dev), name);
-}
-
-static int
-cmp_dev_match(const struct rte_device *dev, const void *_kvlist)
-{
-	const struct rte_kvargs *kvlist = _kvlist;
-	const char *key = TEST_VDEV_KEY_NAME;
-	const char *name;
-
-	/* no kvlist arg, all devices match */
-	if (kvlist == NULL)
-		return 0;
-
-	/* if key is present in kvlist and does not match, filter device */
-	name = rte_kvargs_get(kvlist, key);
-	if (name != NULL && strcmp(name, rte_dev_name(dev)) != 0)
-		return -1;
-
-	return 0;
-}
-
 static struct rte_device *
-get_matching_vdev(const char *match_str)
+find_vdev_by_name(const char *name)
 {
-	struct rte_bus *vdev_bus = rte_bus_find_by_name("vdev");
-	struct rte_kvargs *kvargs = NULL;
+	struct rte_dev_iterator it = { 0 };
 	struct rte_device *dev;
 
-	if (match_str != NULL) {
-		kvargs = rte_kvargs_parse(match_str, valid_keys);
-		if (kvargs == NULL) {
-			printf("Failed to parse match string\n");
-			return NULL;
-		}
+	RTE_DEV_FOREACH(dev, "bus=vdev", &it) {
+		if (strcmp(rte_dev_name(dev), name) == 0)
+			return dev;
 	}
-
-	dev = vdev_bus->find_device(vdev_bus, NULL, cmp_dev_match, kvargs);
-	rte_kvargs_free(kvargs);
-
-	return dev;
+	return NULL;
 }
 
 static int
@@ -83,7 +40,7 @@ test_vdev_bus(void)
 		printf("Failed to create vdev net_null_test0\n");
 		goto fail;
 	}
-	dev0 = vdev_bus->find_device(vdev_bus, NULL, cmp_dev_name, "net_null_test0");
+	dev0 = find_vdev_by_name("net_null_test0");
 	if (dev0 == NULL) {
 		printf("Cannot find net_null_test0 vdev\n");
 		goto fail;
@@ -94,44 +51,32 @@ test_vdev_bus(void)
 		printf("Failed to create vdev net_null_test1\n");
 		goto fail;
 	}
-	dev1 = vdev_bus->find_device(vdev_bus, NULL, cmp_dev_name, "net_null_test1");
+	dev1 = find_vdev_by_name("net_null_test1");
 	if (dev1 == NULL) {
 		printf("Cannot find net_null_test1 vdev\n");
 		goto fail;
 	}
 
-	/* try to match vdevs */
-	dev = get_matching_vdev("name=net_null_test0");
+	/* try to find vdevs */
+	dev = find_vdev_by_name("net_null_test0");
 	if (dev != dev0) {
 		printf("Cannot match net_null_test0 vdev\n");
 		goto fail;
 	}
 
-	dev = get_matching_vdev("name=net_null_test1");
+	dev = find_vdev_by_name("net_null_test1");
 	if (dev != dev1) {
 		printf("Cannot match net_null_test1 vdev\n");
 		goto fail;
 	}
 
-	dev = get_matching_vdev("name=unexistant");
+	dev = find_vdev_by_name("nonexistent");
 	if (dev != NULL) {
-		printf("Unexistant vdev should not match\n");
-		goto fail;
-	}
-
-	dev = get_matching_vdev("");
-	if (dev == NULL || dev == dev1) {
-		printf("Cannot match any vdev with empty match string\n");
-		goto fail;
-	}
-
-	dev = get_matching_vdev(NULL);
-	if (dev == NULL || dev == dev1) {
-		printf("Cannot match any vdev with NULL match string\n");
+		printf("Nonexistent vdev should not match\n");
 		goto fail;
 	}
 
-	/* iterate all vdevs, and ensure we find vdev0 and vdev1 */
+	/* iterate all vdevs, and ensure we find dev0 and dev1 */
 	RTE_DEV_FOREACH(dev, "bus=vdev", &dev_iter) {
 		if (dev == dev0)
 			dev0 = NULL;
-- 
2.54.0


^ permalink raw reply related

* [PATCH 05/10] test/bonding: get MAC address with public API
From: David Marchand @ 2026-07-17  9:30 UTC (permalink / raw)
  To: dev; +Cc: Chas Williams, Min Hu (Connor)
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

Replace direct rte_eth_devices[].data->mac_addrs access with
rte_eth_macaddr_get() public API. This removes the dependency
on the internal ethdev_driver.h header.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 app/test/test_link_bonding.c | 35 +++++++++++++----------------------
 1 file changed, 13 insertions(+), 22 deletions(-)

diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 19b064771a..b9c6718e36 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -19,7 +19,6 @@
 #include <rte_common.h>
 #include <rte_debug.h>
 #include <rte_ethdev.h>
-#include <ethdev_driver.h>
 #include <rte_log.h>
 #include <rte_lcore.h>
 #include <rte_memory.h>
@@ -4763,7 +4762,7 @@ test_alb_change_mac_in_reply_sent(void)
 	int retval = 0;
 
 	struct rte_ether_addr bond_mac, client_mac;
-	struct rte_ether_addr *member_mac1, *member_mac2;
+	struct rte_ether_addr member_mac1, member_mac2;
 
 	TEST_ASSERT_SUCCESS(
 			initialize_bonding_device_with_members(BONDING_MODE_ALB,
@@ -4779,9 +4778,7 @@ test_alb_change_mac_in_reply_sent(void)
 				MAX_PKT_BURST);
 	}
 
-	rte_ether_addr_copy(
-			rte_eth_devices[test_params->bonding_port_id].data->mac_addrs,
-			&bond_mac);
+	rte_eth_macaddr_get(test_params->bonding_port_id, &bond_mac);
 
 	/*
 	 * Generating four packets with different mac and ip addresses and sending
@@ -4831,10 +4828,8 @@ test_alb_change_mac_in_reply_sent(void)
 			RTE_ARP_OP_REPLY);
 	rte_eth_tx_burst(test_params->bonding_port_id, 0, &pkt, 1);
 
-	member_mac1 =
-			rte_eth_devices[test_params->member_port_ids[0]].data->mac_addrs;
-	member_mac2 =
-			rte_eth_devices[test_params->member_port_ids[1]].data->mac_addrs;
+	rte_eth_macaddr_get(test_params->member_port_ids[0], &member_mac1);
+	rte_eth_macaddr_get(test_params->member_port_ids[1], &member_mac2);
 
 	/*
 	 * Checking if packets are properly distributed on bonding ports. Packets
@@ -4852,13 +4847,13 @@ test_alb_change_mac_in_reply_sent(void)
 						sizeof(struct rte_ether_hdr));
 
 			if (member_idx%2 == 0) {
-				if (!rte_is_same_ether_addr(member_mac1,
+				if (!rte_is_same_ether_addr(&member_mac1,
 						&arp_pkt->arp_data.arp_sha)) {
 					retval = -1;
 					goto test_end;
 				}
 			} else {
-				if (!rte_is_same_ether_addr(member_mac2,
+				if (!rte_is_same_ether_addr(&member_mac2,
 						&arp_pkt->arp_data.arp_sha)) {
 					retval = -1;
 					goto test_end;
@@ -4885,7 +4880,7 @@ test_alb_reply_from_client(void)
 	int retval = 0;
 
 	struct rte_ether_addr bond_mac, client_mac;
-	struct rte_ether_addr *member_mac1, *member_mac2;
+	struct rte_ether_addr member_mac1, member_mac2;
 
 	TEST_ASSERT_SUCCESS(
 			initialize_bonding_device_with_members(BONDING_MODE_ALB,
@@ -4900,9 +4895,7 @@ test_alb_reply_from_client(void)
 				MAX_PKT_BURST);
 	}
 
-	rte_ether_addr_copy(
-			rte_eth_devices[test_params->bonding_port_id].data->mac_addrs,
-			&bond_mac);
+	rte_eth_macaddr_get(test_params->bonding_port_id, &bond_mac);
 
 	/*
 	 * Generating four packets with different mac and ip addresses and placing
@@ -4963,8 +4956,8 @@ test_alb_reply_from_client(void)
 	rte_eth_rx_burst(test_params->bonding_port_id, 0, pkts_sent, MAX_PKT_BURST);
 	rte_eth_tx_burst(test_params->bonding_port_id, 0, NULL, 0);
 
-	member_mac1 = rte_eth_devices[test_params->member_port_ids[0]].data->mac_addrs;
-	member_mac2 = rte_eth_devices[test_params->member_port_ids[1]].data->mac_addrs;
+	rte_eth_macaddr_get(test_params->member_port_ids[0], &member_mac1);
+	rte_eth_macaddr_get(test_params->member_port_ids[1], &member_mac2);
 
 	/*
 	 * Checking if update ARP packets were properly send on member ports.
@@ -4981,13 +4974,13 @@ test_alb_reply_from_client(void)
 						sizeof(struct rte_ether_hdr));
 
 			if (member_idx%2 == 0) {
-				if (!rte_is_same_ether_addr(member_mac1,
+				if (!rte_is_same_ether_addr(&member_mac1,
 						&arp_pkt->arp_data.arp_sha)) {
 					retval = -1;
 					goto test_end;
 				}
 			} else {
-				if (!rte_is_same_ether_addr(member_mac2,
+				if (!rte_is_same_ether_addr(&member_mac2,
 						&arp_pkt->arp_data.arp_sha)) {
 					retval = -1;
 					goto test_end;
@@ -5035,9 +5028,7 @@ test_alb_receive_vlan_reply(void)
 				MAX_PKT_BURST);
 	}
 
-	rte_ether_addr_copy(
-			rte_eth_devices[test_params->bonding_port_id].data->mac_addrs,
-			&bond_mac);
+	rte_eth_macaddr_get(test_params->bonding_port_id, &bond_mac);
 
 	/*
 	 * Generating packet with double VLAN header and placing it in the rx queue.
-- 
2.54.0


^ permalink raw reply related

* [PATCH 06/10] test/devargs: check driver presence with public API
From: David Marchand @ 2026-07-17  9:30 UTC (permalink / raw)
  To: dev
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

Let's avoid calling internal drivers API.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 app/test/test_devargs.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
index 0bd14c24ec..6c194ecfc6 100644
--- a/app/test/test_devargs.c
+++ b/app/test/test_devargs.c
@@ -10,7 +10,7 @@
 #include <rte_common.h>
 #include <rte_devargs.h>
 #include <rte_kvargs.h>
-#include <bus_driver.h>
+#include <rte_bus.h>
 #include <rte_class.h>
 
 #include "test.h"
@@ -167,14 +167,18 @@ test_valid_devargs(void)
 		{ "net_ring0,iface=test,path=/class/bus/,queues=1",
 		  0, 0, 3, "vdev", "net_ring0", NULL },
 	};
-	struct rte_bus *vdev_bus = rte_bus_find_by_name("vdev");
+	struct rte_devargs da;
 	int ret;
 
 	ret = test_valid_devargs_cases(list, RTE_DIM(list));
-	if (vdev_bus != NULL && vdev_bus->parse("net_ring0", NULL) == 0)
+
+	memset(&da, 0, sizeof(da));
+	if (rte_devargs_parse(&da, "net_ring0") == 0)
 		/* Ring vdev driver enabled. */
 		ret |= test_valid_devargs_cases(legacy_ring_list,
 						RTE_DIM(legacy_ring_list));
+	rte_devargs_reset(&da);
+
 	return ret;
 }
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH 04/10] test: uninline helper for forking
From: David Marchand @ 2026-07-17  9:29 UTC (permalink / raw)
  To: dev; +Cc: Thomas Monjalon, Reshma Pattan, Stephen Hemminger
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

There is no reason to keep those helpers inlined.

Besides, this code relies on internal API.
So any consumer of process.h requires internal API.

Move this code in process.c.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 MAINTAINERS           |   1 +
 app/test/meson.build  |   4 +
 app/test/process.c    | 229 ++++++++++++++++++++++++++++++++++++++++++
 app/test/process.h    | 228 ++---------------------------------------
 app/test/test_pdump.h |   3 +
 5 files changed, 246 insertions(+), 219 deletions(-)
 create mode 100644 app/test/process.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 84c528437f..176f58f64c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1950,6 +1950,7 @@ F: app/test/commands.c
 F: app/test/packet_burst_generator.c
 F: app/test/packet_burst_generator.h
 F: app/test/process.h
+F: app/test/process.c
 F: app/test/test.c
 F: app/test/test.h
 F: app/test/test_pmd_perf.c
diff --git a/app/test/meson.build b/app/test/meson.build
index 51abeeb732..d8efa93050 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -5,6 +5,10 @@
 deps += ['cmdline', 'ring', 'mempool', 'mbuf']
 sources += files('commands.c', 'test.c')
 
+if not is_windows
+    sources += files('process.c')
+endif
+
 # optional dependencies: some files may use these - and so we should link them in -
 # but do not explicitly require them so they are not listed in the per-file lists below
 optional_deps = ['crypto_scheduler', 'lpm']
diff --git a/app/test/process.c b/app/test/process.c
new file mode 100644
index 0000000000..2b6d7ae84b
--- /dev/null
+++ b/app/test/process.c
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <errno.h>  /* errno */
+#include <limits.h> /* PATH_MAX */
+#ifndef RTE_EXEC_ENV_WINDOWS
+#include <sys/wait.h>
+#endif
+#include <stdlib.h> /* NULL */
+#include <string.h> /* strerror */
+#include <unistd.h>
+#include <dirent.h>
+
+#include <rte_string_fns.h> /* strlcpy */
+#include <rte_devargs.h>
+#include <rte_eal.h>
+
+#ifdef RTE_LIB_PDUMP
+#ifdef RTE_NET_RING
+#include <rte_thread.h>
+#include "test_pdump.h"
+#endif
+#endif
+
+#include "test.h"
+#include "process.h"
+
+#define PREFIX_ALLOW "--allow="
+#define PREFIX_DRIVER_PATH "--driver-path="
+
+static int
+add_parameter_allow(char **argv, int max_capacity)
+{
+	struct rte_devargs *devargs;
+	int count = 0;
+
+	RTE_EAL_DEVARGS_FOREACH(NULL, devargs) {
+		if (strlen(devargs->name) == 0)
+			continue;
+
+		if (devargs->data == NULL || strlen(devargs->data) == 0) {
+			if (asprintf(&argv[count], PREFIX_ALLOW"%s", devargs->name) < 0)
+				break;
+		} else {
+			if (asprintf(&argv[count], PREFIX_ALLOW"%s,%s",
+					 devargs->name, devargs->data) < 0)
+				break;
+		}
+
+		if (++count == max_capacity)
+			break;
+	}
+
+	return count;
+}
+
+static int
+add_parameter_driver_path(char **argv, int max_capacity)
+{
+	const char *driver_path;
+	int count = 0;
+
+	RTE_EAL_DRIVER_PATH_FOREACH(driver_path, true) {
+		if (asprintf(&argv[count], PREFIX_DRIVER_PATH"%s", driver_path) < 0)
+			break;
+
+		if (++count == max_capacity)
+			break;
+	}
+
+	return count;
+}
+
+int
+process_dup(const char *const argv[], int numargs, const char *env_value)
+{
+	int num = 0;
+	char **argv_cpy;
+	int allow_num;
+	int driver_path_num;
+	int argv_num;
+	int i, status;
+#ifdef RTE_LIB_PDUMP
+#ifdef RTE_NET_RING
+	rte_thread_t thread;
+	int rc;
+#endif
+#endif
+
+	pid_t pid = fork();
+	if (pid < 0)
+		return -1;
+	else if (pid == 0) {
+		allow_num = rte_devargs_type_count(RTE_DEVTYPE_ALLOWED);
+		driver_path_num = rte_eal_driver_path_count(true);
+		argv_num = numargs + allow_num + driver_path_num + 1;
+		argv_cpy = calloc(argv_num, sizeof(char *));
+		if (!argv_cpy)
+			rte_panic("Memory allocation failed\n");
+
+		/* make a copy of the arguments to be passed to exec */
+		for (i = 0; i < numargs; i++) {
+			argv_cpy[i] = strdup(argv[i]);
+			if (argv_cpy[i] == NULL)
+				rte_panic("Error dup args\n");
+		}
+		if (allow_num > 0)
+			num = add_parameter_allow(&argv_cpy[i], allow_num);
+		num += numargs;
+
+		if (driver_path_num > 0) {
+			int added = add_parameter_driver_path(&argv_cpy[num], driver_path_num);
+			num += added;
+		}
+
+#ifdef RTE_EXEC_ENV_LINUX
+		{
+			const char *procdir = "/proc/self/fd/";
+			struct dirent *dirent;
+			char *endptr;
+			int fd, fdir;
+			DIR *dir;
+
+			/* close all open file descriptors, check /proc/self/fd
+			 * to only call close on open fds. Exclude fds 0, 1 and
+			 * 2
+			 */
+			dir = opendir(procdir);
+			if (dir == NULL) {
+				rte_panic("Error opening %s: %s\n", procdir,
+						strerror(errno));
+			}
+
+			fdir = dirfd(dir);
+			if (fdir < 0) {
+				status = errno;
+				closedir(dir);
+				rte_panic("Error %d obtaining fd for dir %s: %s\n",
+						fdir, procdir,
+						strerror(status));
+			}
+
+			while ((dirent = readdir(dir)) != NULL) {
+
+				if (strcmp(dirent->d_name, ".") == 0 ||
+					strcmp(dirent->d_name, "..") == 0)
+					continue;
+
+				errno = 0;
+				fd = strtol(dirent->d_name, &endptr, 10);
+				if (errno != 0 || endptr[0] != '\0') {
+					printf("Error converting name fd %d %s:\n",
+						fd, dirent->d_name);
+					continue;
+				}
+
+				if (fd == fdir || fd <= 2)
+					continue;
+
+				close(fd);
+			}
+			closedir(dir);
+		}
+#endif
+		printf("Running binary with argv[]:");
+		for (i = 0; i < num; i++)
+			printf("'%s' ", argv_cpy[i]);
+		printf("\n");
+		fflush(stdout);
+
+		/* set the environment variable */
+		if (setenv(RECURSIVE_ENV_VAR, env_value, 1) != 0)
+			rte_panic("Cannot export environment variable\n");
+		if (execv(argv_cpy[0], argv_cpy) < 0)
+			rte_panic("Cannot exec: %s\n", strerror(errno));
+	}
+	/* parent process does a wait */
+#ifdef RTE_LIB_PDUMP
+#ifdef RTE_NET_RING
+	if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
+		rc = rte_thread_create(&thread, NULL, send_pkts, NULL);
+		if (rc != 0) {
+			rte_panic("Cannot start send pkts thread: %s\n",
+				  strerror(rc));
+		}
+	}
+#endif
+#endif
+
+	while (wait(&status) != pid)
+		;
+#ifdef RTE_LIB_PDUMP
+#ifdef RTE_NET_RING
+	if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
+		flag_for_send_pkts = 0;
+		rte_thread_join(thread, NULL);
+	}
+#endif
+#endif
+	return status;
+}
+
+#ifndef RTE_EXEC_ENV_LINUX
+const char *
+file_prefix_arg(void)
+{
+	return "";
+}
+#else /* RTE_EXEC_ENV_LINUX */
+char *
+get_current_prefix(char *prefix, int size)
+{
+	rte_basename(rte_eal_get_runtime_dir(), prefix, size);
+	return prefix;
+}
+
+/* Return a --file-prefix=XXXX argument */
+const char *
+file_prefix_arg(void)
+{
+	static char prefix[NAME_MAX + sizeof("--file-prefix=")];
+	char tmp[NAME_MAX];
+
+	snprintf(prefix, sizeof(prefix), "--file-prefix=%s",
+			get_current_prefix(tmp, sizeof(tmp)));
+	return prefix;
+}
+#endif /* RTE_EXEC_ENV_LINUX */
diff --git a/app/test/process.h b/app/test/process.h
index 3ee899dbc8..cf2f95f035 100644
--- a/app/test/process.h
+++ b/app/test/process.h
@@ -5,73 +5,7 @@
 #ifndef _PROCESS_H_
 #define _PROCESS_H_
 
-#include <errno.h>  /* errno */
-#include <limits.h> /* PATH_MAX */
-#ifndef RTE_EXEC_ENV_WINDOWS
-#include <sys/wait.h>
-#endif
-#include <stdlib.h> /* NULL */
-#include <string.h> /* strerror */
-#include <unistd.h>
-#include <dirent.h>
-
-#include <rte_string_fns.h> /* strlcpy */
-#include <rte_devargs.h>
-#include <rte_eal.h>
-
-#ifdef RTE_LIB_PDUMP
-#ifdef RTE_NET_RING
-#include <rte_thread.h>
-extern uint32_t send_pkts(void *empty);
-extern uint16_t flag_for_send_pkts;
-#endif
-#endif
-
-#define PREFIX_ALLOW "--allow="
-#define PREFIX_DRIVER_PATH "--driver-path="
-
-static int
-add_parameter_allow(char **argv, int max_capacity)
-{
-	struct rte_devargs *devargs;
-	int count = 0;
-
-	RTE_EAL_DEVARGS_FOREACH(NULL, devargs) {
-		if (strlen(devargs->name) == 0)
-			continue;
-
-		if (devargs->data == NULL || strlen(devargs->data) == 0) {
-			if (asprintf(&argv[count], PREFIX_ALLOW"%s", devargs->name) < 0)
-				break;
-		} else {
-			if (asprintf(&argv[count], PREFIX_ALLOW"%s,%s",
-					 devargs->name, devargs->data) < 0)
-				break;
-		}
-
-		if (++count == max_capacity)
-			break;
-	}
-
-	return count;
-}
-
-static int
-add_parameter_driver_path(char **argv, int max_capacity)
-{
-	const char *driver_path;
-	int count = 0;
-
-	RTE_EAL_DRIVER_PATH_FOREACH(driver_path, true) {
-		if (asprintf(&argv[count], PREFIX_DRIVER_PATH"%s", driver_path) < 0)
-			break;
-
-		if (++count == max_capacity)
-			break;
-	}
-
-	return count;
-}
+#include <stdint.h>
 
 /*
  * launches a second copy of the test process using the given argv parameters,
@@ -79,161 +13,17 @@ add_parameter_driver_path(char **argv, int max_capacity)
  * subprocess the source of the call, the env_value parameter is set in the
  * environment as $RTE_TEST
  */
-static inline int
-process_dup(const char *const argv[], int numargs, const char *env_value)
-{
-	int num = 0;
-	char **argv_cpy;
-	int allow_num;
-	int driver_path_num;
-	int argv_num;
-	int i, status;
-#ifdef RTE_LIB_PDUMP
-#ifdef RTE_NET_RING
-	rte_thread_t thread;
-	int rc;
-#endif
-#endif
-
-	pid_t pid = fork();
-	if (pid < 0)
-		return -1;
-	else if (pid == 0) {
-		allow_num = rte_devargs_type_count(RTE_DEVTYPE_ALLOWED);
-		driver_path_num = rte_eal_driver_path_count(true);
-		argv_num = numargs + allow_num + driver_path_num + 1;
-		argv_cpy = calloc(argv_num, sizeof(char *));
-		if (!argv_cpy)
-			rte_panic("Memory allocation failed\n");
-
-		/* make a copy of the arguments to be passed to exec */
-		for (i = 0; i < numargs; i++) {
-			argv_cpy[i] = strdup(argv[i]);
-			if (argv_cpy[i] == NULL)
-				rte_panic("Error dup args\n");
-		}
-		if (allow_num > 0)
-			num = add_parameter_allow(&argv_cpy[i], allow_num);
-		num += numargs;
+int process_dup(const char *const argv[], int numargs, const char *env_value);
 
-		if (driver_path_num > 0) {
-			int added = add_parameter_driver_path(&argv_cpy[num], driver_path_num);
-			num += added;
-		}
+/*
+ * Return a --file-prefix=XXXX argument
+ * Note: only Linux supports file prefixes.
+ */
+const char *file_prefix_arg(void);
 
 #ifdef RTE_EXEC_ENV_LINUX
-		{
-			const char *procdir = "/proc/self/fd/";
-			struct dirent *dirent;
-			char *endptr;
-			int fd, fdir;
-			DIR *dir;
-
-			/* close all open file descriptors, check /proc/self/fd
-			 * to only call close on open fds. Exclude fds 0, 1 and
-			 * 2
-			 */
-			dir = opendir(procdir);
-			if (dir == NULL) {
-				rte_panic("Error opening %s: %s\n", procdir,
-						strerror(errno));
-			}
-
-			fdir = dirfd(dir);
-			if (fdir < 0) {
-				status = errno;
-				closedir(dir);
-				rte_panic("Error %d obtaining fd for dir %s: %s\n",
-						fdir, procdir,
-						strerror(status));
-			}
-
-			while ((dirent = readdir(dir)) != NULL) {
-
-				if (strcmp(dirent->d_name, ".") == 0 ||
-					strcmp(dirent->d_name, "..") == 0)
-					continue;
-
-				errno = 0;
-				fd = strtol(dirent->d_name, &endptr, 10);
-				if (errno != 0 || endptr[0] != '\0') {
-					printf("Error converting name fd %d %s:\n",
-						fd, dirent->d_name);
-					continue;
-				}
-
-				if (fd == fdir || fd <= 2)
-					continue;
-
-				close(fd);
-			}
-			closedir(dir);
-		}
+/* Get current hugepage file prefix */
+char *get_current_prefix(char *prefix, int size);
 #endif
-		printf("Running binary with argv[]:");
-		for (i = 0; i < num; i++)
-			printf("'%s' ", argv_cpy[i]);
-		printf("\n");
-		fflush(stdout);
-
-		/* set the environment variable */
-		if (setenv(RECURSIVE_ENV_VAR, env_value, 1) != 0)
-			rte_panic("Cannot export environment variable\n");
-		if (execv(argv_cpy[0], argv_cpy) < 0)
-			rte_panic("Cannot exec: %s\n", strerror(errno));
-	}
-	/* parent process does a wait */
-#ifdef RTE_LIB_PDUMP
-#ifdef RTE_NET_RING
-	if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
-		rc = rte_thread_create(&thread, NULL, send_pkts, NULL);
-		if (rc != 0) {
-			rte_panic("Cannot start send pkts thread: %s\n",
-				  strerror(rc));
-		}
-	}
-#endif
-#endif
-
-	while (wait(&status) != pid)
-		;
-#ifdef RTE_LIB_PDUMP
-#ifdef RTE_NET_RING
-	if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
-		flag_for_send_pkts = 0;
-		rte_thread_join(thread, NULL);
-	}
-#endif
-#endif
-	return status;
-}
-
-/* Only Linux supports file prefixes. */
-#ifndef RTE_EXEC_ENV_LINUX
-static inline const char *
-file_prefix_arg(void)
-{
-	return "";
-}
-#else /* RTE_EXEC_ENV_LINUX */
-static inline char *
-get_current_prefix(char *prefix, int size)
-{
-	rte_basename(rte_eal_get_runtime_dir(), prefix, size);
-	return prefix;
-}
-
-/* Return a --file-prefix=XXXX argument */
-static inline const char *
-file_prefix_arg(void)
-{
-	static char prefix[NAME_MAX + sizeof("--file-prefix=")];
-	char tmp[NAME_MAX];
-
-	snprintf(prefix, sizeof(prefix), "--file-prefix=%s",
-			get_current_prefix(tmp, sizeof(tmp)));
-	return prefix;
-}
-#endif /* RTE_EXEC_ENV_LINUX */
 
 #endif /* _PROCESS_H_ */
diff --git a/app/test/test_pdump.h b/app/test/test_pdump.h
index 8746d61269..b026dcc6fb 100644
--- a/app/test/test_pdump.h
+++ b/app/test/test_pdump.h
@@ -11,6 +11,9 @@
 /* sample test to send packets to the pdump client recursively */
 uint32_t send_pkts(void *empty);
 
+/* flag to stop send_pkts thread */
+extern uint16_t flag_for_send_pkts;
+
 /* Sample test to create setup for the pdump server tests */
 int test_pdump_init(void);
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH 03/10] hash: fix GFNI stubs export
From: David Marchand @ 2026-07-17  9:29 UTC (permalink / raw)
  To: dev
  Cc: Yipeng Wang, Sameh Gobriel, Bruce Richardson, Vladimir Medvedkin,
	Stephen Hemminger
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

Internal symbols *can not* be called as part of public ABI.
The GFNI stubs must be exported so that an application may call them
through the (inlined) GFNI API without requiring ALLOW_INTERNAL_API.

Fixes: 944a03a5cfc1 ("hash: fix MSVC link on GFNI stubs")

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 lib/hash/rte_thash_gfni.c | 4 ++--
 lib/hash/rte_thash_gfni.h | 2 --
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/lib/hash/rte_thash_gfni.c b/lib/hash/rte_thash_gfni.c
index 2003c7b3db..ae55f7f711 100644
--- a/lib/hash/rte_thash_gfni.c
+++ b/lib/hash/rte_thash_gfni.c
@@ -13,7 +13,7 @@ RTE_LOG_REGISTER_SUFFIX(hash_gfni_logtype, gfni, INFO);
 #define HASH_LOG(level, ...) \
 	RTE_LOG_LINE(level, HASH, "" __VA_ARGS__)
 
-RTE_EXPORT_INTERNAL_SYMBOL(rte_thash_gfni_stub)
+RTE_EXPORT_SYMBOL(rte_thash_gfni_stub)
 uint32_t
 rte_thash_gfni_stub(const uint64_t *mtrx __rte_unused,
 	const uint8_t *key __rte_unused, int len __rte_unused)
@@ -29,7 +29,7 @@ rte_thash_gfni_stub(const uint64_t *mtrx __rte_unused,
 	return 0;
 }
 
-RTE_EXPORT_INTERNAL_SYMBOL(rte_thash_gfni_bulk_stub)
+RTE_EXPORT_SYMBOL(rte_thash_gfni_bulk_stub)
 void
 rte_thash_gfni_bulk_stub(const uint64_t *mtrx __rte_unused,
 	int len __rte_unused, uint8_t *tuple[] __rte_unused,
diff --git a/lib/hash/rte_thash_gfni.h b/lib/hash/rte_thash_gfni.h
index e82378933c..8a72fa9ec6 100644
--- a/lib/hash/rte_thash_gfni.h
+++ b/lib/hash/rte_thash_gfni.h
@@ -22,11 +22,9 @@ extern "C" {
  * @internal
  * Stubs only used when GFNI is not available.
  */
-__rte_internal
 uint32_t
 rte_thash_gfni_stub(const uint64_t *mtrx, const uint8_t *key, int len);
 
-__rte_internal
 void
 rte_thash_gfni_bulk_stub(const uint64_t *mtrx, int len, uint8_t *tuple[],
 	uint32_t val[], uint32_t num);
-- 
2.54.0


^ permalink raw reply related

* [PATCH 02/10] bbdev: add per-queue statistics API
From: David Marchand @ 2026-07-17  9:29 UTC (permalink / raw)
  To: dev; +Cc: Nicolas Chautru
In-Reply-To: <20260717093006.229370-1-david.marchand@redhat.com>

Add rte_bbdev_queue_stats_get() to retrieve statistics for a specific
queue. This allows applications to get per-queue stats without
accessing internal data structures.

Update test-bbdev to use the new API.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 app/test-bbdev/test_bbdev_perf.c       | 38 +++++---------------------
 doc/guides/rel_notes/release_26_07.rst |  5 ++++
 lib/bbdev/rte_bbdev.c                  | 20 ++++++++++++++
 lib/bbdev/rte_bbdev.h                  | 20 ++++++++++++++
 4 files changed, 52 insertions(+), 31 deletions(-)

diff --git a/app/test-bbdev/test_bbdev_perf.c b/app/test-bbdev/test_bbdev_perf.c
index 9fb0a25948..b75d8387bd 100644
--- a/app/test-bbdev/test_bbdev_perf.c
+++ b/app/test-bbdev/test_bbdev_perf.c
@@ -5849,30 +5849,6 @@ validation_test(struct active_device *ad, struct test_op_params *op_params)
 	return validation_latency_test(ad, op_params, false);
 }
 
-static int
-get_bbdev_queue_stats(uint16_t dev_id, uint16_t queue_id,
-		struct rte_bbdev_stats *stats)
-{
-	struct rte_bbdev *dev = &rte_bbdev_devices[dev_id];
-	struct rte_bbdev_stats *q_stats;
-
-	if (queue_id >= dev->data->num_queues)
-		return -1;
-
-	q_stats = &dev->data->queues[queue_id].queue_stats;
-
-	stats->enqueued_count = q_stats->enqueued_count;
-	stats->dequeued_count = q_stats->dequeued_count;
-	stats->enqueue_err_count = q_stats->enqueue_err_count;
-	stats->dequeue_err_count = q_stats->dequeue_err_count;
-	stats->enqueue_warn_count = q_stats->enqueue_warn_count;
-	stats->dequeue_warn_count = q_stats->dequeue_warn_count;
-	stats->acc_offload_cycles = q_stats->acc_offload_cycles;
-	stats->enqueue_depth_avail = q_stats->enqueue_depth_avail;
-
-	return 0;
-}
-
 static int
 offload_latency_test_fft(struct rte_mempool *mempool, struct test_buffers *bufs,
 		struct rte_bbdev_fft_op *ref_op, uint16_t dev_id,
@@ -5906,7 +5882,7 @@ offload_latency_test_fft(struct rte_mempool *mempool, struct test_buffers *bufs,
 					&ops_enq[enq], burst_sz - enq);
 		} while (unlikely(burst_sz != enq));
 
-		ret = get_bbdev_queue_stats(dev_id, queue_id, &stats);
+		ret = rte_bbdev_queue_stats_get(dev_id, queue_id, &stats);
 		TEST_ASSERT_SUCCESS(ret,
 				"Failed to get stats for queue (%u) of device (%u)",
 				queue_id, dev_id);
@@ -5988,7 +5964,7 @@ offload_latency_test_mldts(struct rte_mempool *mempool, struct test_buffers *buf
 					&ops_enq[enq], burst_sz - enq);
 		} while (unlikely(burst_sz != enq));
 
-		ret = get_bbdev_queue_stats(dev_id, queue_id, &stats);
+		ret = rte_bbdev_queue_stats_get(dev_id, queue_id, &stats);
 		TEST_ASSERT_SUCCESS(ret,
 				"Failed to get stats for queue (%u) of device (%u)",
 				queue_id, dev_id);
@@ -6069,7 +6045,7 @@ offload_latency_test_dec(struct rte_mempool *mempool, struct test_buffers *bufs,
 					&ops_enq[enq], burst_sz - enq);
 		} while (unlikely(burst_sz != enq));
 
-		ret = get_bbdev_queue_stats(dev_id, queue_id, &stats);
+		ret = rte_bbdev_queue_stats_get(dev_id, queue_id, &stats);
 		TEST_ASSERT_SUCCESS(ret,
 				"Failed to get stats for queue (%u) of device (%u)",
 				queue_id, dev_id);
@@ -6163,7 +6139,7 @@ offload_latency_test_ldpc_dec(struct rte_mempool *mempool,
 		} while (unlikely(burst_sz != enq));
 
 		enq_sw_last_time = rte_rdtsc_precise() - enq_start_time;
-		ret = get_bbdev_queue_stats(dev_id, queue_id, &stats);
+		ret = rte_bbdev_queue_stats_get(dev_id, queue_id, &stats);
 		TEST_ASSERT_SUCCESS(ret,
 				"Failed to get stats for queue (%u) of device (%u)",
 				queue_id, dev_id);
@@ -6251,7 +6227,7 @@ offload_latency_test_enc(struct rte_mempool *mempool, struct test_buffers *bufs,
 
 		enq_sw_last_time = rte_rdtsc_precise() - enq_start_time;
 
-		ret = get_bbdev_queue_stats(dev_id, queue_id, &stats);
+		ret = rte_bbdev_queue_stats_get(dev_id, queue_id, &stats);
 		TEST_ASSERT_SUCCESS(ret,
 				"Failed to get stats for queue (%u) of device (%u)",
 				queue_id, dev_id);
@@ -6332,7 +6308,7 @@ offload_latency_test_ldpc_enc(struct rte_mempool *mempool,
 		} while (unlikely(burst_sz != enq));
 
 		enq_sw_last_time = rte_rdtsc_precise() - enq_start_time;
-		ret = get_bbdev_queue_stats(dev_id, queue_id, &stats);
+		ret = rte_bbdev_queue_stats_get(dev_id, queue_id, &stats);
 		TEST_ASSERT_SUCCESS(ret,
 				"Failed to get stats for queue (%u) of device (%u)",
 				queue_id, dev_id);
@@ -6482,7 +6458,7 @@ offload_cost_test(struct active_device *ad,
 			rte_get_tsc_hz());
 
 	struct rte_bbdev_stats stats = {0};
-	ret = get_bbdev_queue_stats(ad->dev_id, queue_id, &stats);
+	ret = rte_bbdev_queue_stats_get(ad->dev_id, queue_id, &stats);
 	TEST_ASSERT_SUCCESS(ret,
 			"Failed to get stats for queue (%u) of device (%u)",
 			queue_id, ad->dev_id);
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 6badd6d91b..dbad975d8c 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -190,6 +190,11 @@ New Features
   * Added ``eof`` devarg to use link state to signal end of receive file input.
   * Added unit test suite.
 
+* **Added per-queue statistics API in bbdev.**
+
+  Added ``rte_bbdev_queue_stats_get()`` function to retrieve statistics
+  for a specific queue, complementing the existing device-level statistics API.
+
 * **Updated Marvell cnxk crypto driver.**
 
   * Added support for ML-KEM and ML-DSA on CN20K platform.
diff --git a/lib/bbdev/rte_bbdev.c b/lib/bbdev/rte_bbdev.c
index 90095578cb..3f032a8e32 100644
--- a/lib/bbdev/rte_bbdev.c
+++ b/lib/bbdev/rte_bbdev.c
@@ -819,6 +819,26 @@ rte_bbdev_stats_reset(uint16_t dev_id)
 	return 0;
 }
 
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bbdev_queue_stats_get, 26.07)
+int rte_bbdev_queue_stats_get(uint16_t dev_id, uint16_t queue_id, struct rte_bbdev_stats *stats)
+{
+	struct rte_bbdev *dev = get_dev(dev_id);
+
+	VALID_DEV_OR_RET_ERR(dev, dev_id);
+	VALID_QUEUE_OR_RET_ERR(queue_id, dev);
+
+	if (stats == NULL) {
+		rte_bbdev_log(ERR, "NULL stats structure");
+		return -EINVAL;
+	}
+
+	*stats = dev->data->queues[queue_id].queue_stats;
+
+	rte_bbdev_log_debug("Retrieved stats for queue %u of device %u",
+			    queue_id, dev_id);
+	return 0;
+}
+
 RTE_EXPORT_SYMBOL(rte_bbdev_info_get)
 int
 rte_bbdev_info_get(uint16_t dev_id, struct rte_bbdev_info *dev_info)
diff --git a/lib/bbdev/rte_bbdev.h b/lib/bbdev/rte_bbdev.h
index 36dabf8fa6..9fcfbf4c69 100644
--- a/lib/bbdev/rte_bbdev.h
+++ b/lib/bbdev/rte_bbdev.h
@@ -316,6 +316,26 @@ rte_bbdev_stats_get(uint16_t dev_id, struct rte_bbdev_stats *stats);
 int
 rte_bbdev_stats_reset(uint16_t dev_id);
 
+/**
+ * Retrieve the statistics of a specific queue.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ * @param queue_id
+ *   The index of the queue.
+ * @param stats
+ *   Pointer to structure to where statistics will be copied. On error, this
+ *   location may or may not have been modified.
+ *
+ * @return
+ *   - 0 on success
+ *   - -ENODEV if dev_id is invalid
+ *   - -EINVAL if stats is NULL
+ *   - -ERANGE if queue_id is out of range
+ */
+__rte_experimental
+int rte_bbdev_queue_stats_get(uint16_t dev_id, uint16_t queue_id, struct rte_bbdev_stats *stats);
+
 /** Device information supplied by the device's driver */
 
 /* Structure rte_bbdev_driver_info 8< */
-- 
2.54.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox