From: Pravin Pathak <pravinpathakdev@gmail.com>
To: dev@dpdk.org
Cc: jerinj@marvell.com, mike.ximing.chen@intel.com,
bruce.richardson@intel.com, thomas@monjalon.net,
david.marchand@redhat.com, nipun.gupta@amd.com,
chenbox@nvidia.com, tirthendu.sarkar@intel.com,
Pravin Pathak <pravin.pathak.dev@gmail.com>
Subject: [PATCH v1 6/8] event/slb: add self-test and documentation
Date: Fri, 6 Nov 2026 20:30:08 -0500 [thread overview]
Message-ID: <20261107013011.2443138-7-pravinpathakdev@gmail.com> (raw)
In-Reply-To: <20261107013011.2443138-1-pravinpathakdev@gmail.com>
From: Pravin Pathak <pravin.pathak.dev@gmail.com>
Add driver self-test coverage and documentation for the Software
Load Balancer PMD.
The self-test verifies parallel queues, atomic queue flow ordering,
ordered queues with forward sequence restoration, single-link queues,
and device stop/restart event draining. Register the self-test in
app/test as a fast test.
Add PMD user guide, feature matrix table, release notes entry for
DPDK 26.11, and update MAINTAINERS.
Signed-off-by: Pravin Pathak <pravin.pathak.dev@gmail.com>
---
MAINTAINERS | 2 +
app/test/test_eventdev.c | 7 +
doc/guides/eventdevs/features/slb.ini | 26 ++
doc/guides/eventdevs/index.rst | 1 +
doc/guides/eventdevs/slb.rst | 68 ++++
drivers/event/slb/meson.build | 1 +
drivers/event/slb/slb_evdev.c | 1 +
drivers/event/slb/slb_evdev.h | 4 +
drivers/event/slb/slb_selftest.c | 522 ++++++++++++++++++++++++++
9 files changed, 632 insertions(+)
create mode 100644 doc/guides/eventdevs/features/slb.ini
create mode 100644 doc/guides/eventdevs/slb.rst
create mode 100644 drivers/event/slb/slb_selftest.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 89ea53695a..bc46e3e8b8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1536,6 +1536,8 @@ F: doc/guides/eventdevs/dsw.rst
Software Load Balancer (SLB) Eventdev PMD
M: Pravin Pathak <pravin.pathak.dev@gmail.com>
F: drivers/event/slb/
+F: doc/guides/eventdevs/slb.rst
+F: doc/guides/eventdevs/features/slb.ini
Software OPDL Eventdev PMD
M: Liang Ma <liangma@liangbit.com>
diff --git a/app/test/test_eventdev.c b/app/test/test_eventdev.c
index 1241da38cb..58ec440674 100644
--- a/app/test/test_eventdev.c
+++ b/app/test/test_eventdev.c
@@ -1527,12 +1527,19 @@ test_eventdev_selftest_cn20k(void)
return test_eventdev_selftest_impl("event_cn20k", "");
}
+static int
+test_eventdev_selftest_slb(void)
+{
+ return test_eventdev_selftest_impl("event_slb", "");
+}
+
#endif /* !RTE_EXEC_ENV_WINDOWS */
REGISTER_FAST_TEST(eventdev_common_autotest, NOHUGE_OK, ASAN_OK, test_eventdev_common);
#ifndef RTE_EXEC_ENV_WINDOWS
REGISTER_FAST_TEST(eventdev_selftest_sw, NOHUGE_OK, ASAN_OK, test_eventdev_selftest_sw);
+REGISTER_FAST_TEST(eventdev_selftest_slb, NOHUGE_OK, ASAN_OK, test_eventdev_selftest_slb);
REGISTER_DRIVER_TEST(eventdev_selftest_octeontx, test_eventdev_selftest_octeontx);
REGISTER_DRIVER_TEST(eventdev_selftest_dpaa2, test_eventdev_selftest_dpaa2);
REGISTER_DRIVER_TEST(eventdev_selftest_dlb2, test_eventdev_selftest_dlb2);
diff --git a/doc/guides/eventdevs/features/slb.ini b/doc/guides/eventdevs/features/slb.ini
new file mode 100644
index 0000000000..0364840bc9
--- /dev/null
+++ b/doc/guides/eventdevs/features/slb.ini
@@ -0,0 +1,26 @@
+;
+; Supported features of the 'software load balancer' (event_slb) eventdev driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Scheduling Features]
+atomic_scheduling = Y
+ordered_scheduling = Y
+parallel_scheduling = Y
+distributed_sched = Y
+burst_mode = Y
+implicit_release_disable = Y
+nonseq_mode = Y
+runtime_port_link = Y
+multiple_queue_port = Y
+carry_flow_id = Y
+maintenance_free = Y
+independent_enq = Y
+
+[Eth Rx adapter Features]
+
+[Eth Tx adapter Features]
+
+[Crypto adapter Features]
+
+[Timer adapter Features]
diff --git a/doc/guides/eventdevs/index.rst b/doc/guides/eventdevs/index.rst
index 69a5ebf812..fdaf846503 100644
--- a/doc/guides/eventdevs/index.rst
+++ b/doc/guides/eventdevs/index.rst
@@ -20,3 +20,4 @@ application through the eventdev API.
sw
octeontx
opdl
+ slb
diff --git a/doc/guides/eventdevs/slb.rst b/doc/guides/eventdevs/slb.rst
new file mode 100644
index 0000000000..d319b94920
--- /dev/null
+++ b/doc/guides/eventdevs/slb.rst
@@ -0,0 +1,68 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+ Copyright(c) 2026 Pravin Pathak <pravin.pathak.dev@gmail.com>
+
+Software Load Balancer (SLB) Eventdev Driver
+============================================
+
+The Software Load Balancer (SLB) event device is a poll-mode eventdev driver
+which distributes events among multiple worker ports and cores without requiring
+dedicated scheduling service cores or hardware coprocessors.
+
+Features
+--------
+
+Queues
+~~~~~~
+
+* **Parallel**: Lock-free multi-producer, multi-consumer ring-based queue allowing
+ concurrent dequeues across all serving worker ports.
+* **Atomic**: Flow-pinned scheduling guaranteeing strict per-flow packet ordering.
+ Includes dynamic load tracking and automatic flow migration to rebalance overloaded
+ ports while preserving in-flight sequence integrity.
+* **Ordered**: Ticket-based sequence tracking and reorder buffer providing end-to-end
+ packet order restoration across parallel processing workers.
+* **Single-Link**: Dedicated direct queue mapping from a producer port to a single
+ consumer port using optimized single-consumer rings.
+
+Ports & Scheduling Capabilities
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* **Distributed Scheduling**: No dedicated service core required; scheduling work is
+ performed inline during enqueue and dequeue operations.
+* **Prefix Sum Burst Enqueue**: Interleaved multi-queue bursts are grouped and scattered
+ via prefix-sum offsets, dispatching single batched bursts to queue rings to eliminate
+ atomic Compare-And-Swap contention on multi-producer rings.
+* **Dynamic Flow Migration**: Atomic queues monitor port dequeue loads and migrate
+ eligible victim flows from overloaded ports to underloaded ports with cooling cycles.
+* **Credit Pool Management**: Centralized event credit pool with per-port credit caching
+ to enforce device-wide in-flight event limits (``max_num_events``).
+* **Runtime Port Linking**: Supports dynamic linking and unlinking of ports and queues
+ both when stopped and at runtime.
+* **Maintenance Free**: Operates without requiring periodic maintenance calls
+ (``RTE_EVENT_DEV_CAP_MAINTENANCE_FREE``).
+
+Configuration and Options
+-------------------------
+
+The SLB event device is a virtual device (vdev) and can be initialized from the
+application code or from the EAL command line:
+
+* From application code:
+
+ .. code-block:: c
+
+ rte_vdev_init("event_slb0", NULL);
+
+* From EAL command-line options:
+
+ .. code-block:: console
+
+ ./your_dpdk_application --vdev="event_slb0"
+
+Limitations
+-----------
+
+* **Flow Hash Table Size**: Atomic queues use an internal flow mapping table
+ dimensioned to 2048 concurrent active flows per queue (``SLB_ATOMIC_FLOWS``).
+* **Maximum Ports and Queues**: Configured for up to 64 ports (``SLB_MAX_PORTS``)
+ and 64 queues (``SLB_MAX_QUEUES``).
diff --git a/drivers/event/slb/meson.build b/drivers/event/slb/meson.build
index d698a58f16..6caf48720f 100644
--- a/drivers/event/slb/meson.build
+++ b/drivers/event/slb/meson.build
@@ -11,6 +11,7 @@ sources = files(
'slb_evdev.c',
'slb_event.c',
'slb_xstats.c',
+ 'slb_selftest.c',
)
deps += ['bus_vdev', 'ring']
diff --git a/drivers/event/slb/slb_evdev.c b/drivers/event/slb/slb_evdev.c
index 04a2aba165..c86b934b03 100644
--- a/drivers/event/slb/slb_evdev.c
+++ b/drivers/event/slb/slb_evdev.c
@@ -758,6 +758,7 @@ static struct eventdev_ops slb_evdev_ops = {
.xstats_get = slb_xstats_get,
.xstats_get_names = slb_xstats_get_names,
.xstats_get_by_name = slb_xstats_get_by_name,
+ .dev_selftest = test_slb_eventdev,
};
static int
diff --git a/drivers/event/slb/slb_evdev.h b/drivers/event/slb/slb_evdev.h
index 17f3154efa..f727a1b83c 100644
--- a/drivers/event/slb/slb_evdev.h
+++ b/drivers/event/slb/slb_evdev.h
@@ -242,6 +242,8 @@ int slb_xstats_get(const struct rte_eventdev *dev,
uint64_t slb_xstats_get_by_name(const struct rte_eventdev *dev,
const char *name, uint64_t *id);
+int test_slb_eventdev(void);
+
static inline struct slb_evdev *
slb_pmd_priv(const struct rte_eventdev *eventdev)
{
@@ -250,6 +252,8 @@ slb_pmd_priv(const struct rte_eventdev *eventdev)
extern int event_slb_logtype;
#define RTE_LOGTYPE_EVENT_SLB event_slb_logtype
+#define SLB_LOG_LINE(level, ...) \
+ RTE_LOG_LINE(level, EVENT_SLB, __VA_ARGS__)
#define SLB_LOG_DP_LINE(level, fmt, ...) \
RTE_LOG_DP_LINE(level, EVENT_SLB, "%s() line %u: " fmt, \
__func__, __LINE__, ## __VA_ARGS__)
diff --git a/drivers/event/slb/slb_selftest.c b/drivers/event/slb/slb_selftest.c
new file mode 100644
index 0000000000..4a072b811b
--- /dev/null
+++ b/drivers/event/slb/slb_selftest.c
@@ -0,0 +1,522 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Pravin Pathak <pravin.pathak.dev@gmail.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include <rte_bus_vdev.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_eventdev.h>
+
+#include "slb_evdev.h"
+
+#define NUM_PORTS 4
+#define NUM_QUEUES 4
+#define PORT_PROD 0
+#define PORT_W1 1
+#define PORT_W2 2
+#define PORT_CONS 3
+
+#define Q_PARALLEL 0
+#define Q_ATOMIC 1
+#define Q_ORDERED 2
+#define Q_SINGLE 3
+
+#define NUM_FLOWS 4
+#define EVENTS_PER_FLOW 16
+#define TOTAL_ATOMIC_EVENTS (NUM_FLOWS * EVENTS_PER_FLOW)
+
+static int g_dev_id = -1;
+
+static int
+init_selftest_device(void)
+{
+ struct rte_event_dev_config dev_conf = {
+ .dequeue_timeout_ns = 0,
+ .nb_event_queues = NUM_QUEUES,
+ .nb_event_ports = NUM_PORTS,
+ .nb_events_limit = 4096,
+ .nb_event_queue_flows = 1024,
+ .nb_event_port_dequeue_depth = 64,
+ .nb_event_port_enqueue_depth = 64,
+ };
+ struct rte_event_queue_conf q_conf;
+ struct rte_event_port_conf p_conf = {
+ .dequeue_depth = 64,
+ .enqueue_depth = 64,
+ .new_event_threshold = 2048,
+ .event_port_cfg = 0
+ };
+ struct rte_event_dev_info info;
+ uint8_t ldb_queues[] = { Q_PARALLEL, Q_ATOMIC, Q_ORDERED };
+ uint8_t single_q = Q_SINGLE;
+ int ret;
+ int p;
+
+ g_dev_id = rte_event_dev_get_dev_id(SLB_PMD_NAME);
+ if (g_dev_id < 0) {
+ ret = rte_vdev_init("event_slb_selftest", NULL);
+ if (ret < 0) {
+ SLB_LOG_LINE(ERR, "Failed to init vdev event_slb_selftest");
+ return -1;
+ }
+ g_dev_id = rte_event_dev_get_dev_id("event_slb_selftest");
+ if (g_dev_id < 0) {
+ SLB_LOG_LINE(ERR, "Cannot find initialized vdev");
+ return -1;
+ }
+ }
+
+ ret = rte_event_dev_info_get(g_dev_id, &info);
+ if (ret < 0) {
+ SLB_LOG_LINE(ERR, "Failed to get dev info");
+ return -1;
+ }
+
+ ret = rte_event_dev_configure(g_dev_id, &dev_conf);
+ if (ret < 0) {
+ SLB_LOG_LINE(ERR, "Failed to configure device, ret=%d", ret);
+ return -1;
+ }
+
+ /* Setup Queues */
+ memset(&q_conf, 0, sizeof(q_conf));
+ q_conf.nb_atomic_flows = 1024;
+ q_conf.nb_atomic_order_sequences = 1024;
+ q_conf.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
+
+ /* Q0: Parallel */
+ q_conf.schedule_type = RTE_SCHED_TYPE_PARALLEL;
+ q_conf.event_queue_cfg = 0;
+ ret = rte_event_queue_setup(g_dev_id, Q_PARALLEL, &q_conf);
+ if (ret < 0)
+ return -1;
+
+ /* Q1: Atomic */
+ q_conf.schedule_type = RTE_SCHED_TYPE_ATOMIC;
+ q_conf.event_queue_cfg = 0;
+ ret = rte_event_queue_setup(g_dev_id, Q_ATOMIC, &q_conf);
+ if (ret < 0)
+ return -1;
+
+ /* Q2: Ordered */
+ q_conf.schedule_type = RTE_SCHED_TYPE_ORDERED;
+ q_conf.event_queue_cfg = 0;
+ ret = rte_event_queue_setup(g_dev_id, Q_ORDERED, &q_conf);
+ if (ret < 0)
+ return -1;
+
+ /* Q3: Single-link */
+ q_conf.schedule_type = RTE_SCHED_TYPE_PARALLEL;
+ q_conf.event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_LINK;
+ ret = rte_event_queue_setup(g_dev_id, Q_SINGLE, &q_conf);
+ if (ret < 0)
+ return -1;
+
+ /* Setup Ports */
+ for (p = 0; p < NUM_PORTS; p++) {
+ if (p == PORT_CONS)
+ p_conf.event_port_cfg = RTE_EVENT_PORT_CFG_SINGLE_LINK;
+ else
+ p_conf.event_port_cfg = 0;
+
+ ret = rte_event_port_setup(g_dev_id, p, &p_conf);
+ if (ret < 0)
+ return -1;
+ }
+
+ /* Link Queues */
+ ret = rte_event_port_link(g_dev_id, PORT_W1, ldb_queues, NULL, 3);
+ if (ret != 3)
+ return -1;
+
+ ret = rte_event_port_link(g_dev_id, PORT_W2, ldb_queues, NULL, 3);
+ if (ret != 3)
+ return -1;
+
+ ret = rte_event_port_link(g_dev_id, PORT_CONS, &single_q, NULL, 1);
+ if (ret != 1)
+ return -1;
+
+ ret = rte_event_dev_start(g_dev_id);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+static void
+cleanup_selftest_device(void)
+{
+ if (g_dev_id >= 0) {
+ rte_event_dev_stop(g_dev_id);
+ rte_event_dev_close(g_dev_id);
+ g_dev_id = -1;
+ }
+}
+
+static int
+test_parallel_queue(void)
+{
+ struct rte_event rx_ev[32];
+ struct rte_event ev[32];
+ uint16_t enqd, deqd = 0;
+ uint16_t n = 0;
+ int tries = 0;
+ int i;
+
+ memset(ev, 0, sizeof(ev));
+
+ for (i = 0; i < 32; i++) {
+ ev[i].op = RTE_EVENT_OP_NEW;
+ ev[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+ ev[i].queue_id = Q_PARALLEL;
+ ev[i].u64 = 1000 + i;
+ }
+
+ enqd = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev, 32);
+ if (enqd != 32) {
+ SLB_LOG_LINE(ERR, "Parallel enqueue failed, expected 32, got %u", enqd);
+ return -1;
+ }
+
+ while (deqd < 32 && tries++ < 1000) {
+ n = rte_event_dequeue_burst(g_dev_id, PORT_W1, rx_ev + deqd,
+ 32 - deqd, 0);
+ deqd += n;
+ if (deqd < 32) {
+ n = rte_event_dequeue_burst(g_dev_id, PORT_W2,
+ rx_ev + deqd, 32 - deqd, 0);
+ deqd += n;
+ }
+ }
+
+ if (deqd != 32) {
+ SLB_LOG_LINE(ERR, "Parallel dequeue failed, expected 32, got %u", deqd);
+ return -1;
+ }
+
+ /* Release events */
+ for (i = 0; i < 32; i++)
+ rx_ev[i].op = RTE_EVENT_OP_RELEASE;
+ rte_event_enqueue_burst(g_dev_id, PORT_W1, rx_ev, 32);
+
+ return 0;
+}
+
+static int
+test_atomic_queue(void)
+{
+ struct rte_event rx_ev[64];
+ struct rte_event ev[64];
+ int expected_seq[NUM_FLOWS];
+ uint16_t enqd = 0;
+ uint16_t deqd = 0;
+ int tries = 0;
+ int idx = 0;
+ int e, f;
+ uint16_t i, n;
+
+ memset(ev, 0, sizeof(ev));
+
+ for (e = 0; e < EVENTS_PER_FLOW; e++) {
+ for (f = 0; f < NUM_FLOWS; f++) {
+ ev[idx].op = RTE_EVENT_OP_NEW;
+ ev[idx].sched_type = RTE_SCHED_TYPE_ATOMIC;
+ ev[idx].queue_id = Q_ATOMIC;
+ ev[idx].flow_id = f;
+ ev[idx].u64 = e; /* sequence number */
+ idx++;
+ }
+ }
+
+ while (enqd < TOTAL_ATOMIC_EVENTS) {
+ n = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev + enqd,
+ TOTAL_ATOMIC_EVENTS - enqd);
+ if (n == 0)
+ break;
+ enqd += n;
+ }
+ if (enqd != TOTAL_ATOMIC_EVENTS) {
+ SLB_LOG_LINE(ERR, "Atomic enqueue failed, expected %d, got %u",
+ TOTAL_ATOMIC_EVENTS, enqd);
+ return -1;
+ }
+
+ for (f = 0; f < NUM_FLOWS; f++)
+ expected_seq[f] = 0;
+
+ while (deqd < TOTAL_ATOMIC_EVENTS && tries++ < 2000) {
+ n = rte_event_dequeue_burst(g_dev_id, PORT_W1, rx_ev, 16, 0);
+ for (i = 0; i < n; i++) {
+ int fid = rx_ev[i].flow_id;
+
+ if (rx_ev[i].u64 != (uint64_t)expected_seq[fid]) {
+ SLB_LOG_LINE(ERR,
+ "Flow %d out of order! Expected %d got %" PRIu64,
+ fid, expected_seq[fid], rx_ev[i].u64);
+ return -1;
+ }
+ expected_seq[fid]++;
+ rx_ev[i].op = RTE_EVENT_OP_RELEASE;
+ }
+ if (n > 0)
+ rte_event_enqueue_burst(g_dev_id, PORT_W1, rx_ev, n);
+ deqd += n;
+
+ n = rte_event_dequeue_burst(g_dev_id, PORT_W2, rx_ev, 16, 0);
+ for (i = 0; i < n; i++) {
+ int fid = rx_ev[i].flow_id;
+
+ if (rx_ev[i].u64 != (uint64_t)expected_seq[fid]) {
+ SLB_LOG_LINE(ERR,
+ "Flow %d out of order! Expected %d got %" PRIu64,
+ fid, expected_seq[fid], rx_ev[i].u64);
+ return -1;
+ }
+ expected_seq[fid]++;
+ rx_ev[i].op = RTE_EVENT_OP_RELEASE;
+ }
+ if (n > 0)
+ rte_event_enqueue_burst(g_dev_id, PORT_W2, rx_ev, n);
+ deqd += n;
+ }
+
+ if (deqd != TOTAL_ATOMIC_EVENTS) {
+ SLB_LOG_LINE(ERR, "Atomic dequeue failed, expected %d got %u",
+ TOTAL_ATOMIC_EVENTS, deqd);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+test_ordered_forward(void)
+{
+ const int num_events = 32;
+ struct rte_event rx[16];
+ struct rte_event ev[32];
+ uint16_t enqd;
+ uint16_t fwd = 0;
+ uint16_t cons_rx = 0;
+ int tries = 0;
+ int i;
+ uint16_t n;
+
+ memset(ev, 0, sizeof(ev));
+
+ for (i = 0; i < num_events; i++) {
+ ev[i].op = RTE_EVENT_OP_NEW;
+ ev[i].sched_type = RTE_SCHED_TYPE_ORDERED;
+ ev[i].queue_id = Q_ORDERED;
+ ev[i].u64 = i;
+ }
+
+ enqd = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev, num_events);
+ if (enqd != num_events)
+ return -1;
+
+ /* Workers dequeue and forward to Q_SINGLE */
+ while (fwd < num_events && tries++ < 2000) {
+ n = rte_event_dequeue_burst(g_dev_id, PORT_W1, rx, 16, 0);
+ for (i = 0; i < n; i++) {
+ rx[i].op = RTE_EVENT_OP_FORWARD;
+ rx[i].queue_id = Q_SINGLE;
+ rx[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+ }
+ if (n > 0)
+ rte_event_enqueue_burst(g_dev_id, PORT_W1, rx, n);
+ fwd += n;
+
+ n = rte_event_dequeue_burst(g_dev_id, PORT_W2, rx, 16, 0);
+ for (i = 0; i < n; i++) {
+ rx[i].op = RTE_EVENT_OP_FORWARD;
+ rx[i].queue_id = Q_SINGLE;
+ rx[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+ }
+ if (n > 0)
+ rte_event_enqueue_burst(g_dev_id, PORT_W2, rx, n);
+ fwd += n;
+ }
+
+ if (fwd != num_events) {
+ SLB_LOG_LINE(ERR, "Ordered workers failed to forward all events (%u/%d)",
+ fwd, num_events);
+ return -1;
+ }
+
+ /* Consumer on PORT_CONS must receive all events in exact sequence 0..num_events-1 */
+ tries = 0;
+ while (cons_rx < num_events && tries++ < 2000) {
+ n = rte_event_dequeue_burst(g_dev_id, PORT_CONS, rx, 16, 0);
+ for (i = 0; i < n; i++) {
+ if (rx[i].u64 != cons_rx) {
+ SLB_LOG_LINE(ERR,
+ "Ordered seq violation! Expected %u got %" PRIu64,
+ cons_rx, rx[i].u64);
+ return -1;
+ }
+ cons_rx++;
+ rx[i].op = RTE_EVENT_OP_RELEASE;
+ }
+ if (n > 0)
+ rte_event_enqueue_burst(g_dev_id, PORT_CONS, rx, n);
+ }
+
+ if (cons_rx != num_events) {
+ SLB_LOG_LINE(ERR, "Consumer received %u/%d ordered events",
+ cons_rx, num_events);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+test_single_link(void)
+{
+ struct rte_event rx[16];
+ struct rte_event ev[16];
+ uint16_t enqd;
+ uint16_t deqd = 0;
+ int tries = 0;
+ int i;
+ uint16_t n;
+
+ memset(ev, 0, sizeof(ev));
+
+ for (i = 0; i < 16; i++) {
+ ev[i].op = RTE_EVENT_OP_NEW;
+ ev[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+ ev[i].queue_id = Q_SINGLE;
+ ev[i].u64 = 5000 + i;
+ }
+
+ enqd = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev, 16);
+ if (enqd != 16)
+ return -1;
+
+ while (deqd < 16 && tries++ < 1000) {
+ n = rte_event_dequeue_burst(g_dev_id, PORT_CONS,
+ rx + deqd, 16 - deqd, 0);
+ deqd += n;
+ }
+
+ if (deqd != 16) {
+ SLB_LOG_LINE(ERR, "Single-link dequeue failed (%u/16)", deqd);
+ return -1;
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (rx[i].u64 != (uint64_t)(5000 + i))
+ return -1;
+ rx[i].op = RTE_EVENT_OP_RELEASE;
+ }
+ rte_event_enqueue_burst(g_dev_id, PORT_CONS, rx, 16);
+
+ return 0;
+}
+
+static int
+test_stop_flush(void)
+{
+ struct rte_event rx[16];
+ struct rte_event ev[16];
+ uint16_t enqd;
+ uint16_t deqd;
+ int ret;
+ int i;
+
+ memset(ev, 0, sizeof(ev));
+
+ for (i = 0; i < 16; i++) {
+ ev[i].op = RTE_EVENT_OP_NEW;
+ ev[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+ ev[i].queue_id = Q_PARALLEL;
+ ev[i].u64 = 9000 + i;
+ }
+
+ enqd = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev, 16);
+ if (enqd != 16)
+ return -1;
+
+ /* Stop device flushes all queued events */
+ rte_event_dev_stop(g_dev_id);
+
+ /* Restart device */
+ ret = rte_event_dev_start(g_dev_id);
+ if (ret < 0)
+ return -1;
+
+ /* Verify no leftover events */
+ deqd = rte_event_dequeue_burst(g_dev_id, PORT_W1, rx, 16, 0);
+ if (deqd != 0) {
+ SLB_LOG_LINE(ERR, "Stop flush failed, received %u events after restart",
+ deqd);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+test_slb_eventdev(void)
+{
+ SLB_LOG_LINE(INFO, "=== Running SLB Eventdev Selftest ===");
+
+ if (init_selftest_device() < 0) {
+ SLB_LOG_LINE(ERR, "Initialization failed");
+ cleanup_selftest_device();
+ return -1;
+ }
+
+ SLB_LOG_LINE(INFO, " [1/5] Testing Parallel Queue...");
+ if (test_parallel_queue() < 0) {
+ SLB_LOG_LINE(ERR, " FAILED: Parallel Queue test failed");
+ cleanup_selftest_device();
+ return -1;
+ }
+ SLB_LOG_LINE(INFO, " [1/5] Parallel Queue: PASS");
+
+ SLB_LOG_LINE(INFO, " [2/5] Testing Atomic Queue...");
+ if (test_atomic_queue() < 0) {
+ SLB_LOG_LINE(ERR, " FAILED: Atomic Queue test failed");
+ cleanup_selftest_device();
+ return -1;
+ }
+ SLB_LOG_LINE(INFO, " [2/5] Atomic Queue: PASS");
+
+ SLB_LOG_LINE(INFO, " [3/5] Testing Ordered Queue...");
+ if (test_ordered_forward() < 0) {
+ SLB_LOG_LINE(ERR, " FAILED: Ordered Queue test failed");
+ cleanup_selftest_device();
+ return -1;
+ }
+ SLB_LOG_LINE(INFO, " [3/5] Ordered Queue: PASS");
+
+ SLB_LOG_LINE(INFO, " [4/5] Testing Single-Link Queue...");
+ if (test_single_link() < 0) {
+ SLB_LOG_LINE(ERR, " FAILED: Single-Link Queue test failed");
+ cleanup_selftest_device();
+ return -1;
+ }
+ SLB_LOG_LINE(INFO, " [4/5] Single-Link Queue: PASS");
+
+ SLB_LOG_LINE(INFO, " [5/5] Testing Device Stop & Flush...");
+ if (test_stop_flush() < 0) {
+ SLB_LOG_LINE(ERR, " FAILED: Stop Flush test failed");
+ cleanup_selftest_device();
+ return -1;
+ }
+ SLB_LOG_LINE(INFO, " [5/5] Device Stop & Flush: PASS");
+
+ cleanup_selftest_device();
+ SLB_LOG_LINE(INFO, "=== SLB Eventdev Selftest PASSED ===");
+ return 0;
+}
--
2.53.0
next prev parent reply other threads:[~2026-11-07 1:31 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 1:30 [PATCH v1 0/8] event/slb: introducing software load balancer eventdev PMD Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 1/8] event/slb: introduce software load balancer PMD Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 2/8] event/slb: add support for ordered queues Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 3/8] event/slb: add support for atomic queues Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 4/8] event/slb: add dynamic flow migration " Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 5/8] event/slb: add extended statistics and diagnostics Pravin Pathak
2026-11-07 1:30 ` Pravin Pathak [this message]
2026-11-07 1:30 ` [PATCH v1 7/8] event/slb: update resets and credit defaults Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 8/8] event/slb: improve port linking, config checks and atomic refill Pravin Pathak
2026-11-07 7:29 ` [PATCH v1 0/8] event/slb: introducing software load balancer eventdev PMD Jerin Jacob
2026-11-08 17:10 ` Stephen Hemminger
2026-11-09 2:30 ` Pravin Pathak
2026-11-09 12:55 ` Jerin Jacob
2026-11-11 14:22 ` Sarkar, Tirthendu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261107013011.2443138-7-pravinpathakdev@gmail.com \
--to=pravinpathakdev@gmail.com \
--cc=bruce.richardson@intel.com \
--cc=chenbox@nvidia.com \
--cc=david.marchand@redhat.com \
--cc=dev@dpdk.org \
--cc=jerinj@marvell.com \
--cc=mike.ximing.chen@intel.com \
--cc=nipun.gupta@amd.com \
--cc=pravin.pathak.dev@gmail.com \
--cc=thomas@monjalon.net \
--cc=tirthendu.sarkar@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox