patch 'eal: fix index for non-EAL lcores' has been queued to stable release 25.11.3

Kevin Traynor ktraynor at redhat.com
Tue Jul 28 17:56:03 CEST 2026


Hi,

FYI, your patch has been queued to stable release 25.11.3

Note it hasn't been pushed to http://dpdk.org/browse/dpdk-stable yet.
It will be pushed if I get no objections before 08/01/26. So please
shout if anyone has objections.

Also note that after the patch there's a diff of the upstream commit vs the
patch applied to the branch. This will indicate if there was any rebasing
needed to apply to the stable branch. If there were code changes for rebasing
(ie: not only metadata diffs), please double check that the rebase was
correctly done.

Queued patches are on a temporary branch at:
https://github.com/kevintraynor/dpdk-stable

This queued commit can be viewed at:
https://github.com/kevintraynor/dpdk-stable/commit/bcb09e44329ca450cc59ce12c691fbb27d982c2e

Thanks.

Kevin

---
>From bcb09e44329ca450cc59ce12c691fbb27d982c2e Mon Sep 17 00:00:00 2001
From: Maxime Peim <maxime.peim at gmail.com>
Date: Wed, 17 Jun 2026 10:09:49 +0200
Subject: [PATCH] eal: fix index for non-EAL lcores

[ upstream commit b482a764c613c7921710061114c1dbe3d96568c3 ]

Threads registered via rte_thread_register() are assigned a valid
lcore_id by eal_lcore_non_eal_allocate(), but their core_index in
lcore_config is left at -1. This value was set during rte_eal_cpu_init()
for lcores with ROLE_OFF (undetected CPUs) and is never updated when the
lcore is later allocated to a non-EAL thread.

As a result, rte_lcore_index() returns -1 for registered non-EAL
threads. Libraries that use rte_lcore_index() to select per-lcore
caches fall back to a shared global path when it returns -1, causing
severe contention under concurrent access from multiple registered
threads.

A concrete example is the mlx5 indexed memory pool (mlx5_ipool), which
uses rte_lcore_index() in mlx5_ipool_malloc_cache() to select a per-core
cache slot. When core_index is -1, all registered threads are funneled
into a single shared slot protected by a spinlock. In testing with VPP
(which registers worker threads via rte_thread_register()), this caused
async flow rule insertion throughput to drop from ~6.4M rules/sec to
~1.2M rules/sec with 4 workers -- a 5x regression attributable entirely
to spinlock contention in the ipool allocator.

Fix by tracking currently allocated core_index values in a bitset and
assigning non-EAL threads the first free index. Keep the bitset in sync
when initial EAL lcores are configured, when EAL core-list parsing
remaps lcores, and when non-EAL registration fails or releases an lcore.

Fixes: 5c307ba2a5b1 ("eal: register non-EAL threads as lcores")

Signed-off-by: Maxime Peim <maxime.peim at gmail.com>
Acked-by: David Marchand <david.marchand at redhat.com>
---
 lib/eal/common/eal_common_lcore.c   | 19 ++++++++++++++++++-
 lib/eal/common/eal_common_options.c |  5 +++++
 lib/eal/common/eal_private.h        |  3 +++
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/lib/eal/common/eal_common_lcore.c b/lib/eal/common/eal_common_lcore.c
index 39411f9370..b5f59a6380 100644
--- a/lib/eal/common/eal_common_lcore.c
+++ b/lib/eal/common/eal_common_lcore.c
@@ -7,6 +7,7 @@
 #include <string.h>
 
-#include <rte_common.h>
+#include <rte_bitset.h>
 #include <rte_branch_prediction.h>
+#include <rte_common.h>
 #include <rte_errno.h>
 #include <rte_lcore.h>
@@ -185,4 +186,7 @@ rte_eal_cpu_init(void)
 		CPU_SET(lcore_id, &lcore_config[lcore_id].cpuset);
 
+		/* This is the first time we discover the lcores, so the bitset should be zeroed */
+		rte_bitset_set(config->core_indices, count);
+
 		/* By default, each detected core is enabled */
 		config->lcore_role[lcore_id] = ROLE_RTE;
@@ -374,9 +378,18 @@ eal_lcore_non_eal_allocate(void)
 	struct lcore_callback *prev;
 	unsigned int lcore_id;
+	int core_index = -1;
 
 	rte_rwlock_write_lock(&lcore_lock);
+	core_index = rte_bitset_find_first_clear(cfg->core_indices, RTE_MAX_LCORE);
+	if (core_index == -1) {
+		EAL_LOG(DEBUG, "No core_index available.");
+		lcore_id = RTE_MAX_LCORE;
+		goto out;
+	}
 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
 		if (cfg->lcore_role[lcore_id] != ROLE_OFF)
 			continue;
+		rte_bitset_set(cfg->core_indices, core_index);
+		lcore_config[lcore_id].core_index = core_index;
 		cfg->lcore_role[lcore_id] = ROLE_NON_EAL;
 		cfg->lcore_count++;
@@ -400,4 +413,6 @@ eal_lcore_non_eal_allocate(void)
 		EAL_LOG(DEBUG, "Initialization refused for lcore %u.",
 			lcore_id);
+		rte_bitset_clear(cfg->core_indices, lcore_config[lcore_id].core_index);
+		lcore_config[lcore_id].core_index = -1;
 		cfg->lcore_role[lcore_id] = ROLE_OFF;
 		cfg->lcore_count--;
@@ -421,4 +436,6 @@ eal_lcore_non_eal_release(unsigned int lcore_id)
 	TAILQ_FOREACH(callback, &lcore_callbacks, next)
 		callback_uninit(callback, lcore_id);
+	rte_bitset_clear(cfg->core_indices, lcore_config[lcore_id].core_index);
+	lcore_config[lcore_id].core_index = -1;
 	cfg->lcore_role[lcore_id] = ROLE_OFF;
 	cfg->lcore_count--;
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index c53d10fd27..3e742aa2fb 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -830,4 +830,5 @@ eal_parse_service_coremask(const char *coremask)
 			return -1;
 
+	rte_bitset_clear_all(cfg->core_indices, RTE_MAX_LCORE);
 	for (; idx < RTE_MAX_LCORE; idx++)
 		lcore_config[idx].core_index = -1;
@@ -856,4 +857,5 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
 
 	/* set everything to disabled first, then set up values */
+	rte_bitset_clear_all(cfg->core_indices, RTE_MAX_LCORE);
 	for (i = 0; i < RTE_MAX_LCORE; i++) {
 		cfg->lcore_role[i] = ROLE_OFF;
@@ -885,4 +887,5 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
 			}
 
+			rte_bitset_set(cfg->core_indices, count);
 			cfg->lcore_role[lcore_id] = ROLE_RTE;
 			lcore_config[lcore_id].core_index = count;
@@ -1307,4 +1310,5 @@ eal_parse_lcores(const char *lcores)
 
 	/* Reset lcore config */
+	rte_bitset_clear_all(cfg->core_indices, RTE_MAX_LCORE);
 	for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
 		cfg->lcore_role[idx] = ROLE_OFF;
@@ -1371,4 +1375,5 @@ eal_parse_lcores(const char *lcores)
 
 			if (cfg->lcore_role[idx] != ROLE_RTE) {
+				rte_bitset_set(cfg->core_indices, count);
 				lcore_config[idx].core_index = count;
 				cfg->lcore_role[idx] = ROLE_RTE;
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index e032dd10c9..2b7a4fddbc 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -12,4 +12,5 @@
 
 #include <dev_driver.h>
+#include <rte_bitset.h>
 #include <rte_lcore.h>
 #include <rte_log.h>
@@ -45,4 +46,6 @@ extern struct lcore_config lcore_config[RTE_MAX_LCORE];
  */
 struct rte_config {
+	RTE_BITSET_DECLARE(core_indices,
+			   RTE_MAX_LCORE); /**< bitset of currently allocated core_indices */
 	uint32_t main_lcore;         /**< Id of the main lcore */
 	uint32_t lcore_count;        /**< Number of available logical cores. */
-- 
2.55.0

---
  Diff of the applied patch vs upstream commit (please double-check if non-empty:
---
--- -	2026-07-28 16:54:51.782378114 +0100
+++ 0033-eal-fix-index-for-non-EAL-lcores.patch	2026-07-28 16:54:50.772728764 +0100
@@ -1 +1 @@
-From b482a764c613c7921710061114c1dbe3d96568c3 Mon Sep 17 00:00:00 2001
+From bcb09e44329ca450cc59ce12c691fbb27d982c2e Mon Sep 17 00:00:00 2001
@@ -5,0 +6,2 @@
+[ upstream commit b482a764c613c7921710061114c1dbe3d96568c3 ]
+
@@ -33 +34,0 @@
-Cc: stable at dpdk.org
@@ -98 +99 @@
-index 1049838d73..42cdef632f 100644
+index c53d10fd27..3e742aa2fb 100644
@@ -101 +102 @@
-@@ -912,4 +912,5 @@ eal_parse_service_coremask(const char *coremask)
+@@ -830,4 +830,5 @@ eal_parse_service_coremask(const char *coremask)
@@ -107 +108 @@
-@@ -938,4 +939,5 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
+@@ -856,4 +857,5 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
@@ -113 +114 @@
-@@ -967,4 +969,5 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
+@@ -885,4 +887,5 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
@@ -119 +120 @@
-@@ -1389,4 +1392,5 @@ eal_parse_lcores(const char *lcores)
+@@ -1307,4 +1310,5 @@ eal_parse_lcores(const char *lcores)
@@ -125 +126 @@
-@@ -1453,4 +1457,5 @@ eal_parse_lcores(const char *lcores)
+@@ -1371,4 +1375,5 @@ eal_parse_lcores(const char *lcores)
@@ -132 +133 @@
-index 0c0544beaf..6340bab8be 100644
+index e032dd10c9..2b7a4fddbc 100644



More information about the stable mailing list