* [PATCH 26.11 4/4] test/cfgfile: test for long lines in file
From: Bruce Richardson @ 2026-07-06 16:23 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson, Cristian Dumitrescu
In-Reply-To: <20260706162348.460489-1-bruce.richardson@intel.com>
The test_cfgfiles directory already had a line_too_long.ini file in it,
but this a) did not exceed the line length that the library could manage
and b) was not actually used in any test case.
Fix this by expanding the long line so it does trigger an error, and
adding a test case for it.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
app/test/test_cfgfile.c | 20 ++++++++++++++++++++
app/test/test_cfgfiles/line_too_long.ini | 2 +-
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/app/test/test_cfgfile.c b/app/test/test_cfgfile.c
index 12da87aa5a..f056fe2d4d 100644
--- a/app/test/test_cfgfile.c
+++ b/app/test/test_cfgfile.c
@@ -376,6 +376,25 @@ test_cfgfile_invalid_key_value_pair(void)
return 0;
}
+static int
+test_cfgfile_line_too_long(void)
+{
+ struct rte_cfgfile *cfgfile;
+ char filename[PATH_MAX];
+ int ret;
+
+ ret = make_tmp_file(filename, "line_too_long", line_too_long_ini);
+ TEST_ASSERT_SUCCESS(ret, "Failed to setup temp file");
+
+ cfgfile = rte_cfgfile_load(filename, 0);
+ TEST_ASSERT_NULL(cfgfile, "Expected failure did not occur");
+
+ ret = remove(filename);
+ TEST_ASSERT_SUCCESS(ret, "Failed to remove file");
+
+ return 0;
+}
+
static int
test_cfgfile_empty_key_value_pair(void)
{
@@ -555,6 +574,7 @@ unit_test_suite test_cfgfile_suite = {
TEST_CASE(test_cfgfile_invalid_section_header),
TEST_CASE(test_cfgfile_invalid_comment),
TEST_CASE(test_cfgfile_invalid_key_value_pair),
+ TEST_CASE(test_cfgfile_line_too_long),
TEST_CASE(test_cfgfile_empty_key_value_pair),
TEST_CASE(test_cfgfile_missing_section),
TEST_CASE(test_cfgfile_global_properties),
diff --git a/app/test/test_cfgfiles/line_too_long.ini b/app/test/test_cfgfiles/line_too_long.ini
index 1dce164838..2683cd2938 100644
--- a/app/test/test_cfgfiles/line_too_long.ini
+++ b/app/test/test_cfgfiles/line_too_long.ini
@@ -1,3 +1,3 @@
[section1]
; this is section 1
-012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
--
2.53.0
^ permalink raw reply related
* [PATCH 26.11 3/4] test/cfgfile: verify file modification API
From: Bruce Richardson @ 2026-07-06 16:23 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson, Cristian Dumitrescu
In-Reply-To: <20260706162348.460489-1-bruce.richardson@intel.com>
Check that the has_entry API correctly reports the presence of a valid
entry, and then verify that if we use set_entry we can modify the value
- a modification that persists if we use the save API. In the same test,
also check that we can't use add_entry to modify an existing entry, and
that we can't use set_entry to add a missing entry.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
app/test/test_cfgfile.c | 55 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/app/test/test_cfgfile.c b/app/test/test_cfgfile.c
index 5ed116866d..12da87aa5a 100644
--- a/app/test/test_cfgfile.c
+++ b/app/test/test_cfgfile.c
@@ -491,6 +491,60 @@ test_cfgfile_empty_file(void)
return 0;
}
+static int
+test_cfgfile_modify_entry(void)
+{
+ struct rte_cfgfile *cfgfile;
+ struct rte_cfgfile *loaded;
+ const char *value;
+ char filename[PATH_MAX];
+ int ret;
+
+ ret = make_tmp_file(filename, "sample1_set", sample1_ini);
+ TEST_ASSERT_SUCCESS(ret, "Failed to setup temp file");
+
+ cfgfile = rte_cfgfile_load(filename, 0);
+ TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file");
+
+ ret = rte_cfgfile_has_entry(cfgfile, "section2", "key2");
+ TEST_ASSERT(ret == 1, "section2 key2 entry missing");
+
+ ret = rte_cfgfile_has_entry(cfgfile, "section2", "invalid_key");
+ TEST_ASSERT(ret == 0, "section2 'invalid_key' entry should be missing");
+
+ ret = rte_cfgfile_set_entry(cfgfile, "section2", "key2", "value_of_key2");
+ TEST_ASSERT_SUCCESS(ret, "Failed to set section2 key2");
+
+ /* check we can't set a nonexistent key */
+ ret = rte_cfgfile_set_entry(cfgfile, "section2", "invalid_key", "value_of_key4");
+ TEST_ASSERT(ret < 0, "Error, unexpectedly able to set nonexistent 'invalid_key'");
+
+ /* check we can't add an existing key */
+ ret = rte_cfgfile_add_entry(cfgfile, "section2", "key2", "value_of_key2");
+ TEST_ASSERT(ret < 0, "Error, unexpectedly able to add existing key2");
+
+ ret = rte_cfgfile_save(cfgfile, filename);
+ TEST_ASSERT_SUCCESS(ret, "Failed to save cfgfile");
+
+ ret = rte_cfgfile_close(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile");
+
+ loaded = rte_cfgfile_load(filename, 0);
+ TEST_ASSERT_NOT_NULL(loaded, "Failed to reload saved cfgfile");
+
+ value = rte_cfgfile_get_entry(loaded, "section2", "key2");
+ TEST_ASSERT(strcmp("value_of_key2", value) == 0,
+ "Unexpected section2 key2 value: %s", value);
+
+ ret = rte_cfgfile_close(loaded);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close reloaded cfgfile");
+
+ ret = remove(filename);
+ TEST_ASSERT_SUCCESS(ret, "Failed to remove file");
+
+ return 0;
+}
+
static struct
unit_test_suite test_cfgfile_suite = {
.suite_name = "Test Cfgfile Unit Test Suite",
@@ -506,6 +560,7 @@ unit_test_suite test_cfgfile_suite = {
TEST_CASE(test_cfgfile_global_properties),
TEST_CASE(test_cfgfile_empty_file),
TEST_CASE(test_cfgfile_create_add_save_reload),
+ TEST_CASE(test_cfgfile_modify_entry),
TEST_CASES_END()
}
--
2.53.0
^ permalink raw reply related
* [PATCH 26.11 2/4] test/cfgfile: validate config creation APIs
From: Bruce Richardson @ 2026-07-06 16:23 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson, Cristian Dumitrescu
In-Reply-To: <20260706162348.460489-1-bruce.richardson@intel.com>
Add a test case creating a new configfile and then saving that to disk.
Verify the result by reading the file back in and checking entries are
as expected.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
app/test/test_cfgfile.c | 69 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/app/test/test_cfgfile.c b/app/test/test_cfgfile.c
index 2f1c8ec423..5ed116866d 100644
--- a/app/test/test_cfgfile.c
+++ b/app/test/test_cfgfile.c
@@ -197,6 +197,74 @@ test_cfgfile_sample2(void)
return 0;
}
+static int
+test_cfgfile_create_add_save_reload(void)
+{
+ struct rte_cfgfile *cfgfile;
+ struct rte_cfgfile *loaded;
+ const char *value;
+ char filename[PATH_MAX];
+ int ret;
+
+ cfgfile = rte_cfgfile_create(0);
+ TEST_ASSERT_NOT_NULL(cfgfile, "Failed to create cfgfile");
+
+ ret = rte_cfgfile_add_section(cfgfile, "section1");
+ TEST_ASSERT_SUCCESS(ret, "Failed to add section1");
+ ret = rte_cfgfile_add_entry(cfgfile, "section1", "key1", "value1");
+ TEST_ASSERT_SUCCESS(ret, "Failed to add section1 key1");
+ ret = rte_cfgfile_add_entry(cfgfile, "section1", "key2", "value2");
+ TEST_ASSERT_SUCCESS(ret, "Failed to add section1 key2");
+
+ ret = rte_cfgfile_add_section(cfgfile, "section2");
+ TEST_ASSERT_SUCCESS(ret, "Failed to add section2");
+ ret = rte_cfgfile_add_entry(cfgfile, "section2", "key3", "value3");
+ TEST_ASSERT_SUCCESS(ret, "Failed to add section2 key3");
+ ret = rte_cfgfile_add_entry(cfgfile, "section2", "key4", "value4");
+ TEST_ASSERT_SUCCESS(ret, "Failed to add section2 key4");
+
+ ret = make_tmp_file(filename, "create_save", "");
+ TEST_ASSERT_SUCCESS(ret, "Failed to make temporary output file");
+
+ ret = rte_cfgfile_save(cfgfile, filename);
+ TEST_ASSERT_SUCCESS(ret, "Failed to save cfgfile");
+
+ ret = rte_cfgfile_close(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close created cfgfile");
+
+ loaded = rte_cfgfile_load(filename, 0);
+ TEST_ASSERT_NOT_NULL(loaded, "Failed to load saved cfgfile");
+
+ ret = rte_cfgfile_num_sections(loaded, NULL, 0);
+ TEST_ASSERT(ret == 2, "Unexpected number of sections: %d", ret);
+
+ ret = rte_cfgfile_section_num_entries(loaded, "section1");
+ TEST_ASSERT(ret == 2, "Unexpected section1 entries: %d", ret);
+ ret = rte_cfgfile_section_num_entries(loaded, "section2");
+ TEST_ASSERT(ret == 2, "Unexpected section2 entries: %d", ret);
+
+ value = rte_cfgfile_get_entry(loaded, "section1", "key1");
+ TEST_ASSERT(strcmp("value1", value) == 0,
+ "section1 key1 unexpected value: %s", value);
+ value = rte_cfgfile_get_entry(loaded, "section1", "key2");
+ TEST_ASSERT(strcmp("value2", value) == 0,
+ "section1 key2 unexpected value: %s", value);
+ value = rte_cfgfile_get_entry(loaded, "section2", "key3");
+ TEST_ASSERT(strcmp("value3", value) == 0,
+ "section2 key3 unexpected value: %s", value);
+ value = rte_cfgfile_get_entry(loaded, "section2", "key4");
+ TEST_ASSERT(strcmp("value4", value) == 0,
+ "section2 key4 unexpected value: %s", value);
+
+ ret = rte_cfgfile_close(loaded);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close loaded cfgfile");
+
+ ret = remove(filename);
+ TEST_ASSERT_SUCCESS(ret, "Failed to remove file");
+
+ return 0;
+}
+
static int
test_cfgfile_realloc_sections(void)
{
@@ -437,6 +505,7 @@ unit_test_suite test_cfgfile_suite = {
TEST_CASE(test_cfgfile_missing_section),
TEST_CASE(test_cfgfile_global_properties),
TEST_CASE(test_cfgfile_empty_file),
+ TEST_CASE(test_cfgfile_create_add_save_reload),
TEST_CASES_END()
}
--
2.53.0
^ permalink raw reply related
* [PATCH 26.11 1/4] test/cfgfile: improve coverage for listing APIs
From: Bruce Richardson @ 2026-07-06 16:23 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson, Cristian Dumitrescu
In-Reply-To: <20260706162348.460489-1-bruce.richardson@intel.com>
Improve cfgfile unit-test coverage for listing/index APIs, by adding
assertions for section and entry listing behavior, including:
* expected count validation
* listing sections and entries and checking expected results
* index-based listing checks
* sentinel verification to ensure only expected slots are written
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
app/test/test_cfgfile.c | 53 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/app/test/test_cfgfile.c b/app/test/test_cfgfile.c
index 1e56473064..2f1c8ec423 100644
--- a/app/test/test_cfgfile.c
+++ b/app/test/test_cfgfile.c
@@ -93,7 +93,14 @@ static int
test_cfgfile_sample1(void)
{
struct rte_cfgfile *cfgfile;
+ struct rte_cfgfile_entry entries[4];
char filename[PATH_MAX];
+ char sec0[CFG_NAME_LEN] = {0};
+ char sec1[CFG_NAME_LEN] = {0};
+ char sec2[CFG_NAME_LEN] = "sentinel_section_2";
+ char sec3[CFG_NAME_LEN] = "sentinel_section_3";
+ char index_sec[CFG_NAME_LEN] = {0};
+ char *sections[] = { sec0, sec1, sec2, sec3 };
int ret;
ret = make_tmp_file(filename, "sample1", sample1_ini);
@@ -105,6 +112,52 @@ test_cfgfile_sample1(void)
ret = _test_cfgfile_sample(cfgfile);
TEST_ASSERT_SUCCESS(ret, "Failed to validate sample file: %d", ret);
+ ret = rte_cfgfile_num_sections(cfgfile, NULL, 0);
+ TEST_ASSERT(ret == 2, "Unexpected number of sections: %d", ret);
+
+ ret = rte_cfgfile_sections(cfgfile, sections, 4);
+ TEST_ASSERT(ret == 2, "Unexpected listed sections: %d", ret);
+ TEST_ASSERT(strcmp(sec0, "section1") == 0,
+ "Unexpected section at index 0: %s", sec0);
+ TEST_ASSERT(strcmp(sec1, "section2") == 0,
+ "Unexpected section at index 1: %s", sec1);
+ TEST_ASSERT(strcmp(sec2, "sentinel_section_2") == 0,
+ "Unexpected write past listed sections at index 2: %s", sec2);
+ TEST_ASSERT(strcmp(sec3, "sentinel_section_3") == 0,
+ "Unexpected write past listed sections at index 3: %s", sec3);
+
+ ret = rte_cfgfile_section_num_entries_by_index(cfgfile, index_sec, 0);
+ TEST_ASSERT(ret == 1, "Unexpected entry count at index 0: %d", ret);
+ TEST_ASSERT(strcmp(index_sec, "section1") == 0,
+ "Unexpected section name at index 0: %s", index_sec);
+
+ ret = rte_cfgfile_section_num_entries(cfgfile, "section2");
+ TEST_ASSERT(ret == 2, "Unexpected section2 entry count: %d", ret);
+
+ memset(entries, 0x5a, sizeof(entries));
+ ret = rte_cfgfile_section_entries(cfgfile, "section2", entries, 4);
+ TEST_ASSERT(ret == 2, "Unexpected section2 entry count: %d", ret);
+ TEST_ASSERT(strcmp(entries[0].name, "key2") == 0,
+ "Unexpected section2 first key: %s", entries[0].name);
+ TEST_ASSERT(strcmp(entries[0].value, "value2") == 0,
+ "Unexpected section2 first value: %s", entries[0].value);
+ TEST_ASSERT(strcmp(entries[1].name, "key3") == 0,
+ "Unexpected section2 second key: %s", entries[1].name);
+ TEST_ASSERT(strcmp(entries[1].value, "value3") == 0,
+ "Unexpected section2 second value: %s", entries[1].value);
+ TEST_ASSERT((unsigned char)entries[2].name[0] == 0x5a,
+ "Unexpected write past listed entries at index 2");
+ TEST_ASSERT((unsigned char)entries[3].name[0] == 0x5a,
+ "Unexpected write past listed entries at index 3");
+
+ memset(entries, 0x5a, sizeof(entries));
+ memset(index_sec, 0, sizeof(index_sec));
+ ret = rte_cfgfile_section_entries_by_index(cfgfile, 1, index_sec, entries, 4);
+ TEST_ASSERT(ret == 2,
+ "Unexpected entry count for section at index 1: %d", ret);
+ TEST_ASSERT(strcmp(index_sec, "section2") == 0,
+ "Unexpected section name at index 1: %s", index_sec);
+
ret = rte_cfgfile_close(cfgfile);
TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile");
--
2.53.0
^ permalink raw reply related
* [PATCH 26.11 0/4] extra unit tests for cfgfile library
From: Bruce Richardson @ 2026-07-06 16:23 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
There were a few APIs in the cfgfile library which were not being
tested by the unit tests. Add tests to close that, and other, gaps.
Bruce Richardson (4):
test/cfgfile: improve coverage for listing APIs
test/cfgfile: validate config creation APIs
test/cfgfile: verify file modification API
test/cfgfile: test for long lines in file
app/test/test_cfgfile.c | 197 +++++++++++++++++++++++
app/test/test_cfgfiles/line_too_long.ini | 2 +-
2 files changed, 198 insertions(+), 1 deletion(-)
--
2.53.0
^ permalink raw reply
* [PATCH] dev: hide internal type for device comparison
From: David Marchand @ 2026-07-06 15:06 UTC (permalink / raw)
To: dev
rte_dev_cmp_t is a type used only in bus operations.
Since no public API references it, remove it from exported types.
Thanks to this, we can remove the dependency of bus_driver.h to
rte_dev.h.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
app/test/test_vdev.c | 1 +
lib/eal/include/bus_driver.h | 24 +++++++++++++++++++++++-
lib/eal/include/rte_dev.h | 21 ---------------------
3 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/app/test/test_vdev.c b/app/test/test_vdev.c
index c82d996404..c300976ace 100644
--- a/app/test/test_vdev.c
+++ b/app/test/test_vdev.c
@@ -7,6 +7,7 @@
#include <string.h>
#include <rte_common.h>
+#include <rte_dev.h>
#include <rte_kvargs.h>
#include <bus_driver.h>
#include <rte_bus_vdev.h>
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index 4f6521c87f..fa4d711a90 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -7,7 +7,6 @@
#include <rte_bus.h>
#include <rte_compat.h>
-#include <rte_dev.h>
#include <rte_eal.h>
#include <rte_tailq.h>
@@ -15,8 +14,10 @@
extern "C" {
#endif
+struct rte_dev_iterator;
struct rte_devargs;
struct rte_device;
+struct rte_driver;
/** Double linked list of buses */
RTE_TAILQ_HEAD(rte_bus_list, rte_bus);
@@ -49,6 +50,27 @@ typedef int (*rte_bus_scan_t)(void);
*/
typedef int (*rte_bus_probe_t)(struct rte_bus *bus);
+/**
+ * Device comparison function.
+ *
+ * This type of function is used to compare an rte_device with arbitrary
+ * data.
+ *
+ * @param dev
+ * Device handle.
+ *
+ * @param data
+ * Data to compare against. The type of this parameter is determined by
+ * the kind of comparison performed by the function.
+ *
+ * @return
+ * 0 if the device matches the data.
+ * !0 if the device does not match.
+ * <0 if ordering is possible and the device is lower than the data.
+ * >0 if ordering is possible and the device is greater than the data.
+ */
+typedef int (*rte_dev_cmp_t)(const struct rte_device *dev, const void *data);
+
/**
* Device iterator to find a device on a bus.
*
diff --git a/lib/eal/include/rte_dev.h b/lib/eal/include/rte_dev.h
index 7eca5e8cf2..12e205efa7 100644
--- a/lib/eal/include/rte_dev.h
+++ b/lib/eal/include/rte_dev.h
@@ -211,27 +211,6 @@ int rte_eal_hotplug_remove(const char *busname, const char *devname);
*/
int rte_dev_remove(struct rte_device *dev);
-/**
- * Device comparison function.
- *
- * This type of function is used to compare an rte_device with arbitrary
- * data.
- *
- * @param dev
- * Device handle.
- *
- * @param data
- * Data to compare against. The type of this parameter is determined by
- * the kind of comparison performed by the function.
- *
- * @return
- * 0 if the device matches the data.
- * !0 if the device does not match.
- * <0 if ordering is possible and the device is lower than the data.
- * >0 if ordering is possible and the device is greater than the data.
- */
-typedef int (*rte_dev_cmp_t)(const struct rte_device *dev, const void *data);
-
/**
* Iteration context.
*
--
2.54.0
^ permalink raw reply related
* [PATCH] drivers/bus: remove blocklist evaluation when probing a device
From: David Marchand @ 2026-07-06 15:06 UTC (permalink / raw)
To: dev
Cc: Parav Pandit, Xueming Li, Hemant Agrawal, Sachin Saxena,
Chenbo Xia, Nipun Gupta, Long Li, Wei Hu, Chengwen Feng,
Bruce Richardson
.probe_device is called from EAL, that already evaluated if the device
is blocklisted.
Fixes: be29c42523d8 ("bus: implement probe in EAL")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/auxiliary/auxiliary_common.c | 7 -------
drivers/bus/fslmc/fslmc_bus.c | 7 -------
drivers/bus/pci/pci_common.c | 7 -------
drivers/bus/vmbus/vmbus_common.c | 7 -------
4 files changed, 28 deletions(-)
diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
index 80b90a4961..016d124f0b 100644
--- a/drivers/bus/auxiliary/auxiliary_common.c
+++ b/drivers/bus/auxiliary/auxiliary_common.c
@@ -84,13 +84,6 @@ auxiliary_probe_device(struct rte_driver *drv, struct rte_device *dev)
if (!auxiliary_dev_exists(dev->name))
return -ENOENT;
- /* No initialization when marked as blocked, return without error. */
- if (aux_dev->device.devargs != NULL &&
- aux_dev->device.devargs->policy == RTE_DEV_BLOCKED) {
- AUXILIARY_LOG(INFO, "Device is blocked, not initializing");
- return -1;
- }
-
if (aux_dev->device.numa_node < 0 && rte_socket_count() > 1)
AUXILIARY_LOG(INFO, "Device %s is not NUMA-aware", aux_dev->name);
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index 1a0eca30b4..3626b12316 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -513,13 +513,6 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
struct rte_dpaa2_driver *drv = RTE_BUS_DRIVER(driver, *drv);
int ret = 0;
- if (dev->device.devargs &&
- dev->device.devargs->policy == RTE_DEV_BLOCKED) {
- DPAA2_BUS_DEBUG("%s Blocked, skipping",
- dev->device.name);
- return 0;
- }
-
/* FIXME: probe_device should allocate intr_handle */
ret = drv->probe(drv, dev);
if (ret != 0) {
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 0f635e1537..dc8db80d3b 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -193,13 +193,6 @@ pci_probe_device(struct rte_driver *drv, struct rte_device *dev)
loc->domain, loc->bus, loc->devid, loc->function,
pci_dev->device.numa_node);
- /* no initialization when marked as blocked, return without error */
- if (pci_dev->device.devargs != NULL &&
- pci_dev->device.devargs->policy == RTE_DEV_BLOCKED) {
- PCI_LOG(INFO, " Device is blocked, not initializing");
- return 1;
- }
-
if (pci_dev->device.numa_node < 0 && rte_socket_count() > 1)
PCI_LOG(INFO, "Device %s is not NUMA-aware", pci_dev->name);
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index cd6e851e4c..4c64856abb 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -93,13 +93,6 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
VMBUS_LOG(INFO, "VMBUS device %s on NUMA socket %i",
guid, vmbus_dev->device.numa_node);
- /* no initialization when marked as blocked, return without error */
- if (vmbus_dev->device.devargs != NULL &&
- vmbus_dev->device.devargs->policy == RTE_DEV_BLOCKED) {
- VMBUS_LOG(INFO, " Device is blocked, not initializing");
- return 1;
- }
-
/* allocate interrupt handle instance */
vmbus_dev->intr_handle =
rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
--
2.54.0
^ permalink raw reply related
* [PATCH v3 3/3] dts: add verify coverage for cryptodev testing
From: Andrew Bailey @ 2026-07-06 15:02 UTC (permalink / raw)
To: dev, luca.vizzarro, patrickrobb1997; +Cc: knimoji, lylavoie, Andrew Bailey
In-Reply-To: <20260706150205.497924-1-abailey@iol.unh.edu>
Currently, next-DTS only covers throughput testing through the
dpdk-test-crypto application. This series adds coverage for the verify
option to next DTS to allow functional testing for various algorithms of
crypto devices and virtual devices.
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
---
dts/tests/TestSuite_cryptodev_verify.py | 162 ++++++++++++++++++++++++
tests.TestSuite_cryptodev_verify.rst | 8 ++
2 files changed, 170 insertions(+)
create mode 100644 dts/tests/TestSuite_cryptodev_verify.py
create mode 100644 tests.TestSuite_cryptodev_verify.rst
diff --git a/dts/tests/TestSuite_cryptodev_verify.py b/dts/tests/TestSuite_cryptodev_verify.py
new file mode 100644
index 0000000000..0fc405fcc9
--- /dev/null
+++ b/dts/tests/TestSuite_cryptodev_verify.py
@@ -0,0 +1,162 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2026 University of New Hampshire
+
+"""DPDK cryptodev verify test suite.
+
+The main goal of this test suite is to utilize the verify mode of dpdk-test-crypto application
+to ensure functional correctness for various cryptographic operations supported by DPDK
+cryptodev-pmd.
+"""
+
+from api.capabilities import (
+ LinkTopology,
+ requires_link_topology,
+)
+from api.cryptodev import Cryptodev
+from api.cryptodev.config import (
+ AeadAlgName,
+ AuthenticationAlgorithm,
+ AuthenticationOpMode,
+ CipherAlgorithm,
+ DeviceType,
+ EncryptDecryptSwitch,
+ OperationType,
+ TestType,
+ get_device_from_str,
+)
+from api.cryptodev.types import (
+ CryptodevResults,
+)
+from api.test import verify
+from framework.context import get_ctx
+from framework.test_suite import TestSuite, crypto_test
+from framework.testbed_model.virtual_device import VirtualDevice
+
+TOTAL_OPS = 10_000_000
+AES_CBC_DATA = "test_aes_cbc.data"
+AES_GCM_DATA = "test_aes_gcm.data"
+
+
+@requires_link_topology(LinkTopology.NO_LINK)
+class TestCryptodevVerify(TestSuite):
+ """DPDK Crypto Device Testing Suite."""
+
+ def set_up_suite(self) -> None:
+ """Set up the test suite."""
+ self.device_type: DeviceType | None = get_device_from_str(
+ str(get_ctx().sut_node.crypto_device_type)
+ )
+
+ def _verify_output(
+ self,
+ results: list[CryptodevResults],
+ ) -> bool:
+ for result in results:
+ if (
+ getattr(result, "failed_enqueued") > 0
+ or getattr(result, "failed_dequeued") > 0
+ or getattr(result, "failed_ops") > 0
+ ):
+ return False
+ return True
+
+ @crypto_test
+ def aesni_mb_vdev(self) -> None:
+ """aesni_mb_vdev test.
+
+ Steps:
+ * Create a cryptodev instance with aesni_mb virtual device and provided buffer sizes.
+ Verify:
+ * The aes_cbc cipher and sha1_hmac authentication algorithms are working as expected
+ with the dpdk-test-crypto application.
+ """
+ app = Cryptodev(
+ vdevs=[VirtualDevice("crypto_aesni_mb0")],
+ ptest=TestType.verify,
+ test_file=AES_CBC_DATA,
+ test_name="sha1_hmac_buff_32",
+ devtype=DeviceType.crypto_aesni_mb,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=32,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.sha1_hmac,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=64,
+ digest_sz=12,
+ burst_sz=32,
+ buffer_sz=32,
+ total_ops=TOTAL_OPS,
+ )
+
+ verify(
+ self._verify_output(app.run_app(num_vfs=0)), "Failed to verify test sha1_hmac_buff_32"
+ )
+
+ @crypto_test
+ def openssl_vdev(self) -> None:
+ """Openssl vdev test.
+
+ Steps:
+ * Create a cryptodev instance with openssl virtual device and provided buffer sizes.
+ Verify:
+ * The aes_cbc cipher and sha1_hmac authentication algorithms are working as expected
+ with the dpdk-test-crypto application.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ app = Cryptodev(
+ vdevs=[VirtualDevice("crypto_openssl0")],
+ ptest=TestType.verify,
+ test_file=AES_GCM_DATA,
+ test_name="aes_gcm_buff_32",
+ devtype=DeviceType.crypto_openssl,
+ optype=OperationType.aead,
+ aead_algo=AeadAlgName.aes_gcm,
+ aead_op=EncryptDecryptSwitch.encrypt,
+ aead_key_sz=16,
+ aead_aad_sz=16,
+ aead_iv_sz=12,
+ digest_sz=16,
+ burst_sz=32,
+ buffer_sz=32,
+ total_ops=TOTAL_OPS,
+ )
+
+ verify(self._verify_output(app.run_app(num_vfs=0)), "Failed to verify test aes_gcm_buff_32")
+
+ @crypto_test
+ def sha1_hmac_buff_32(self) -> None:
+ """aes_cbc test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The aes_cbc cipher and sha1_hmac authentication algorithms are working as expected
+ with the dpdk-test-crypto application.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ app = Cryptodev(
+ ptest=TestType.verify,
+ test_file=AES_CBC_DATA,
+ test_name="sha1_hmac_buff_32",
+ devtype=self.device_type,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=32,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.sha1_hmac,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=64,
+ digest_sz=20,
+ burst_sz=32,
+ buffer_sz=32,
+ total_ops=TOTAL_OPS,
+ )
+
+ verify(self._verify_output(app.run_app()), "Failed to verify test sha1_hmac_buff_32")
diff --git a/tests.TestSuite_cryptodev_verify.rst b/tests.TestSuite_cryptodev_verify.rst
new file mode 100644
index 0000000000..d0a305a7d5
--- /dev/null
+++ b/tests.TestSuite_cryptodev_verify.rst
@@ -0,0 +1,8 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+
+cryptodev_verify Test Suite
+===========================
+
+.. automodule:: tests.TestSuite_cryptodev_verify
+ :members:
+ :show-inheritance:
--
2.54.0
^ permalink raw reply related
* [PATCH v3 1/3] dts: add directory for test resources
From: Andrew Bailey @ 2026-07-06 15:02 UTC (permalink / raw)
To: dev, luca.vizzarro, patrickrobb1997; +Cc: knimoji, lylavoie, Andrew Bailey
In-Reply-To: <20260514172553.191331-1-abailey@iol.unh.edu>
The crypto verify test suite being added in this series requires an
input vector file. The two vector files added in this commit are
relocated from old DTS to new DTS. This will allow the crypto verify
test suite to access the required vector files for verify testing.
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
---
dts/api/cryptodev/__init__.py | 2 +-
dts/test_resources/test_aes_cbc.data | 27 +++++++++++++++++++++++++++
dts/test_resources/test_aes_gcm.data | 19 +++++++++++++++++++
3 files changed, 47 insertions(+), 1 deletion(-)
create mode 100644 dts/test_resources/test_aes_cbc.data
create mode 100644 dts/test_resources/test_aes_gcm.data
diff --git a/dts/api/cryptodev/__init__.py b/dts/api/cryptodev/__init__.py
index a4fafc3713..4e8ce47de1 100644
--- a/dts/api/cryptodev/__init__.py
+++ b/dts/api/cryptodev/__init__.py
@@ -76,7 +76,7 @@ def vector_directory(self) -> PurePath:
Returns:
The path to the cryptodev vector files.
"""
- return get_ctx().dpdk_build.remote_dpdk_tree_path.joinpath("app/test-crypto-perf/data/")
+ return get_ctx().dpdk_build.remote_dpdk_tree_path.joinpath("dts/test_resources/")
def run_app(self, num_vfs: int = 1) -> list[CryptodevResults]:
"""Run the cryptodev application with the given app parameters.
diff --git a/dts/test_resources/test_aes_cbc.data b/dts/test_resources/test_aes_cbc.data
new file mode 100644
index 0000000000..ac7a89942f
--- /dev/null
+++ b/dts/test_resources/test_aes_cbc.data
@@ -0,0 +1,27 @@
+# Global Section
+plaintext =
+0xff, 0xca, 0xfb, 0xf1, 0x38, 0x20, 0x2f, 0x7b, 0x24, 0x98, 0x26, 0x7d, 0x1d, 0x9f, 0xb3, 0x93,
+0xd9, 0xef, 0xbd, 0xad, 0x4e, 0x40, 0xbd, 0x60, 0xe9, 0x48, 0x59, 0x90, 0x67, 0xd7, 0x2b, 0x7b
+ciphertext =
+0x77, 0xF9, 0xF7, 0x7A, 0xA3, 0xCB, 0x68, 0x1A, 0x11, 0x70, 0xD8, 0x7A, 0xB6, 0xE2, 0x37, 0x7E,
+0xD1, 0x57, 0x1C, 0x8E, 0x85, 0xD8, 0x08, 0xBF, 0x57, 0x1F, 0x21, 0x6C, 0xAD, 0xAD, 0x47, 0x1E
+cipher_key =
+0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A,
+0xd0, 0xe7, 0x4b, 0xfb, 0x5d, 0xe5, 0x0c, 0xe7, 0x6f, 0x21, 0xb5, 0x52, 0x2a, 0xbb, 0xc7, 0xf7
+auth_key =
+0xaf, 0x96, 0x42, 0xf1, 0x8c, 0x50, 0xdc, 0x67, 0x1a, 0x43, 0x47, 0x62, 0xc7, 0x04, 0xab, 0x05,
+0xf5, 0x0c, 0xe7, 0xa2, 0xa6, 0x23, 0xd5, 0x3d, 0x95, 0xd8, 0xcd, 0x86, 0x79, 0xf5, 0x01, 0x47,
+0x4f, 0xf9, 0x1d, 0x9d, 0x36, 0xf7, 0x68, 0x1a, 0x64, 0x44, 0x58, 0x5d, 0xe5, 0x81, 0x15, 0x2a,
+0x41, 0xe4, 0x0e, 0xaa, 0x1f, 0x04, 0x21, 0xff, 0x2c, 0xf3, 0x73, 0x2b, 0x48, 0x1e, 0xd2, 0xf7
+cipher_iv =
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+# Section sha 1 hmac buff 32
+[sha1_hmac_buff_32]
+digest =
+0x36, 0xCA, 0x49, 0x6A, 0xE3, 0x54, 0xD8, 0x4F, 0x0B, 0x76, 0xD8, 0xAA, 0x78, 0xEB, 0x9D, 0x65,
+0x2C, 0xCA, 0x1F, 0x97
+# Section sha 256 hmac buff 32
+[sha256_hmac_buff_32]
+digest =
+0x1C, 0xB2, 0x3D, 0xD1, 0xF9, 0xC7, 0x6C, 0x49, 0x2E, 0xDA, 0x94, 0x8B, 0xF1, 0xCF, 0x96, 0x43,
+0x67, 0x50, 0x39, 0x76, 0xB5, 0xA1, 0xCE, 0xA1, 0xD7, 0x77, 0x10, 0x07, 0x43, 0x37, 0x05, 0xB4
diff --git a/dts/test_resources/test_aes_gcm.data b/dts/test_resources/test_aes_gcm.data
new file mode 100644
index 0000000000..034f4fa91a
--- /dev/null
+++ b/dts/test_resources/test_aes_gcm.data
@@ -0,0 +1,19 @@
+# Global Section
+plaintext =
+0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
+
+ciphertext =
+0x82, 0x7d, 0xb6, 0xdf, 0x77, 0x0a, 0xe6, 0x45, 0x5a, 0xc3, 0x70, 0x9b, 0x27, 0xb2, 0x61, 0x19,
+0xa2, 0x37, 0x0b, 0xf7, 0x42, 0xfc, 0xec, 0xe7, 0xf7, 0x30, 0xe0, 0x3c, 0x05, 0x55, 0xb3, 0x7d
+
+aead_key =
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+aead_iv =
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
+aead_aad =
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+
+[aes_gcm_buff_32]
+digest =
+0x0f, 0xb2, 0x98, 0x59, 0x48, 0xbf, 0x6c, 0x37, 0x5a, 0xad, 0xcd, 0x97, 0x9f, 0xbb, 0xc8, 0x2a
--
2.54.0
^ permalink raw reply related
* [PATCH v3 2/3] dts: fix cryptodev verify parsing
From: Andrew Bailey @ 2026-07-06 15:02 UTC (permalink / raw)
To: dev, luca.vizzarro, patrickrobb1997; +Cc: knimoji, lylavoie, Andrew Bailey
In-Reply-To: <20260706150205.497924-1-abailey@iol.unh.edu>
The previous implementation of gathering the data of verify output did
not properly gather the correct values. This commit amends the faulty
regex with working ones.
Bugzilla ID: 1945
Fixes: 8ee2df9da125 ("dts: add cryptodev package")
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
---
dts/api/cryptodev/__init__.py | 1 +
dts/api/cryptodev/types.py | 20 ++++++++------------
2 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/dts/api/cryptodev/__init__.py b/dts/api/cryptodev/__init__.py
index 4e8ce47de1..90b847d1fb 100644
--- a/dts/api/cryptodev/__init__.py
+++ b/dts/api/cryptodev/__init__.py
@@ -132,6 +132,7 @@ def run_app(self, num_vfs: int = 1) -> list[CryptodevResults]:
case TestType.pmd_cyclecount:
parser = PmdCyclecountResults
case TestType.verify:
+ parser_options |= re.DOTALL
parser = VerifyResults
return [parser.parse(line) for line in re.findall(regex, result.stdout, parser_options)]
diff --git a/dts/api/cryptodev/types.py b/dts/api/cryptodev/types.py
index df73a86fa4..861d46bf13 100644
--- a/dts/api/cryptodev/types.py
+++ b/dts/api/cryptodev/types.py
@@ -160,26 +160,22 @@ class VerifyResults(CryptodevResults):
"""A parser for verify test output."""
#:
- lcore_id: int = field(metadata=TextParser.find_int(r"lcore\s+(?:id.*\n\s+)?(\d+)"))
+ lcore_id: int = field(metadata=TextParser.find_int(r"\s*(\d+)"))
#: buffer size ran with app
buffer_size: int = field(
- metadata=TextParser.find_int(r"Buf(?:.*\n\s+(?:\d+\s+))?(?:fer size:\s+)?(\d+)"),
+ metadata=TextParser.find_int(r"\s*(?:\d+\s+)(\d+)"),
)
#: burst size ran with app
burst_size: int = field(
- metadata=TextParser.find_int(r"Burst(?:.*\n\s+(?:\d+\s+){2})?(?: size:\s+)?(\d+)"),
+ metadata=TextParser.find_int(r"\s*(?:\d+\s+){2}(\d+)"),
)
#: number of packets enqueued
- enqueued: int = field(metadata=TextParser.find_int(r"Enqueued.*\n\s+(?:\d+\s+){3}(\d+)"))
+ enqueued: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){3}(\d+)"))
#: number of packets dequeued
- dequeued: int = field(metadata=TextParser.find_int(r"Dequeued.*\n\s+(?:\d+\s+){4}(\d+)"))
+ dequeued: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){4}(\d+)"))
#: number of packets enqueue failed
- failed_enqueued: int = field(
- metadata=TextParser.find_int(r"Failed Enq.*\n\s+(?:\d+\s+){5}(\d+)")
- )
+ failed_enqueued: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){5}(\d+)"))
#: number of packets dequeue failed
- failed_dequeued: int = field(
- metadata=TextParser.find_int(r"Failed Deq.*\n\s+(?:\d+\s+){6}(\d+)")
- )
+ failed_dequeued: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){6}(\d+)"))
#: total number of failed operations
- failed_ops: int = field(metadata=TextParser.find_int(r"Failed Ops.*\n\s+(?:\d+\s+){7}(\d+)"))
+ failed_ops: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){7}(\d+)"))
--
2.54.0
^ permalink raw reply related
* [PATCH] dev: fix hotplug notification to secondary
From: David Marchand @ 2026-07-06 14:55 UTC (permalink / raw)
To: dev; +Cc: fengchengwen, Thomas Monjalon, Anatoly Burakov
There was a logical error when making some last minute change.
Fix the no_shconf evaluation.
Besides, we currently have no unit test checking device hotplug in the
fast-tests testsuite.
Instead, we rely on rcX tags validations when non regression tests
relying on the multiprocess examples are run.
Add some basic unit test that does not cover all that the examples do
yet provide a first gate on multiprocess changes.
Bugzilla ID: 1963
Fixes: 1a2e26d8701d ("dev: skip multi-process in hotplug")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
MAINTAINERS | 1 +
app/test/meson.build | 1 +
app/test/test.c | 1 +
app/test/test.h | 1 +
app/test/test_dev_hotplug.c | 320 ++++++++++++++++++++++++++++++++
lib/eal/common/eal_common_dev.c | 4 +-
6 files changed, 326 insertions(+), 2 deletions(-)
create mode 100644 app/test/test_dev_hotplug.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 84c528437f..0d77d9f1e6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -177,6 +177,7 @@ F: app/test/test_common.c
F: app/test/test_cpuflags.c
F: app/test/test_cycles.c
F: app/test/test_debug.c
+F: app/test/test_dev_hotplug.c
F: app/test/test_devargs.c
F: app/test/test_eal*
F: app/test/test_errno.c
diff --git a/app/test/meson.build b/app/test/meson.build
index 51abeeb732..4047a14586 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -61,6 +61,7 @@ source_file_deps = {
'test_cryptodev_security_tls_record.c': ['cryptodev', 'security'],
'test_cycles.c': [],
'test_debug.c': [],
+ 'test_dev_hotplug.c': ['net_null'],
'test_devargs.c': ['kvargs'],
'test_dispatcher.c': ['dispatcher'],
'test_distributor.c': ['distributor'],
diff --git a/app/test/test.c b/app/test/test.c
index c610c3588e..597f256128 100644
--- a/app/test/test.c
+++ b/app/test/test.c
@@ -62,6 +62,7 @@ do_recursive_call(void)
} actions[] = {
#ifndef RTE_EXEC_ENV_WINDOWS
{ "run_secondary_instances", test_mp_secondary },
+ { "run_hotplug_secondary", test_dev_hotplug_mp },
#endif
#ifdef RTE_LIB_PDUMP
#ifdef RTE_NET_RING
diff --git a/app/test/test.h b/app/test/test.h
index b29233bb32..78f42d6177 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -216,6 +216,7 @@ int commands_init(void);
int command_valid(const char *cmd);
int test_exit(void);
+int test_dev_hotplug_mp(void);
int test_mp_secondary(void);
int test_panic(void);
int test_timer_secondary(void);
diff --git a/app/test/test_dev_hotplug.c b/app/test/test_dev_hotplug.c
new file mode 100644
index 0000000000..b75761f520
--- /dev/null
+++ b/app/test/test_dev_hotplug.c
@@ -0,0 +1,320 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+
+#include "test.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifndef RTE_EXEC_ENV_LINUX
+
+static int
+test_dev_hotplug_api(void)
+{
+ printf("Hotplug API test only supported on Linux, skipping\n");
+ return TEST_SKIPPED;
+}
+
+int
+test_dev_hotplug_mp(void)
+{
+ printf("Hotplug MP test only supported on Linux, skipping\n");
+ return TEST_SKIPPED;
+}
+
+#else
+
+#include <sys/wait.h>
+
+#include <rte_bus.h>
+#include <rte_dev.h>
+#include <rte_devargs.h>
+#include <rte_eal.h>
+#include <rte_errno.h>
+#include <rte_memzone.h>
+#include <rte_stdatomic.h>
+
+#include "process.h"
+
+#define HOTPLUG_TEST_DEV "net_null0"
+
+static struct rte_device *
+find_device_by_name(const char *name)
+{
+ struct rte_dev_iterator it;
+ struct rte_device *dev;
+ struct rte_devargs da;
+ char filter[32];
+
+ memset(&da, 0, sizeof(da));
+ if (rte_devargs_parse(&da, name) != 0)
+ return NULL;
+
+ snprintf(filter, sizeof(filter), "bus=%s", rte_bus_name(da.bus));
+ rte_devargs_reset(&da);
+
+ RTE_DEV_FOREACH(dev, filter, &it) {
+ if (strcmp(rte_dev_name(dev), name) == 0 && rte_dev_is_probed(dev))
+ return dev;
+ }
+ return NULL;
+}
+
+/*
+ * Scenario A: Basic hotplug API test (single process)
+ *
+ * Tests that rte_dev_probe() and rte_dev_remove() work correctly.
+ * This test runs in a single process and validates basic API functionality.
+ */
+static int
+test_dev_hotplug_api(void)
+{
+ struct rte_device *dev;
+ int ret;
+
+ printf("== Testing rte_dev_probe/rte_dev_remove API ==\n");
+
+ dev = find_device_by_name(HOTPLUG_TEST_DEV);
+ if (dev != NULL) {
+ printf("Device %s already exists, cannot run test\n", HOTPLUG_TEST_DEV);
+ return TEST_FAILED;
+ }
+
+ printf("Probing device %s\n", HOTPLUG_TEST_DEV);
+ ret = rte_dev_probe(HOTPLUG_TEST_DEV);
+ if (ret != 0) {
+ printf("rte_dev_probe(%s) failed: %d (%s)\n",
+ HOTPLUG_TEST_DEV, ret, rte_strerror(-ret));
+ return TEST_FAILED;
+ }
+
+ dev = find_device_by_name(HOTPLUG_TEST_DEV);
+ if (dev == NULL) {
+ printf("Device %s not found after probe\n", HOTPLUG_TEST_DEV);
+ return TEST_FAILED;
+ }
+ printf("Device %s probed successfully\n", HOTPLUG_TEST_DEV);
+
+ printf("Removing device %s\n", HOTPLUG_TEST_DEV);
+ ret = rte_dev_remove(dev);
+ if (ret != 0) {
+ printf("rte_dev_remove(%s) failed: %d (%s)\n",
+ HOTPLUG_TEST_DEV, ret, rte_strerror(-ret));
+ return TEST_FAILED;
+ }
+
+ dev = find_device_by_name(HOTPLUG_TEST_DEV);
+ if (dev != NULL) {
+ printf("Device %s still exists after remove\n", HOTPLUG_TEST_DEV);
+ return TEST_FAILED;
+ }
+ printf("Device %s removed successfully\n", HOTPLUG_TEST_DEV);
+
+ printf("== Hotplug API test passed ==\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Scenario B: Hotplug with multi-process notification
+ *
+ * Tests that when primary probes a device, running secondaries receive
+ * the MP notification and can see the device.
+ *
+ * Sequence:
+ * 1. Primary creates coordination memzone
+ * 2. Primary spawns secondary (via fork+exec)
+ * 3. Secondary signals ready via memzone
+ * 4. Primary probes device
+ * 5. Secondary should receive MP notification and see device
+ * 6. Secondary signals result via memzone
+ * 7. Primary collects result and cleans up
+ */
+
+#define MZ_HOTPLUG_STATE "hotplug_test_state"
+
+/* States for inter-process coordination */
+enum hotplug_test_state {
+ STATE_SECONDARY_READY = 1,
+ STATE_SECONDARY_CHECK_DEVICE,
+ STATE_SECONDARY_DONE,
+};
+
+struct hotplug_state {
+ RTE_ATOMIC(int) state;
+ RTE_ATOMIC(int) secondary_result;
+};
+
+static void
+signal_state(struct hotplug_state *state, int new_state)
+{
+ rte_atomic_store_explicit(&state->state, new_state, rte_memory_order_release);
+}
+
+static void
+wait_for_state(RTE_ATOMIC(int) *state_ptr, int expected_state)
+{
+ while (rte_atomic_load_explicit(state_ptr, rte_memory_order_acquire) != expected_state)
+ usleep(10000);
+}
+
+static int
+run_secondary_hotplug_test(void)
+{
+ const struct rte_memzone *mz;
+ struct hotplug_state *state;
+ struct rte_device *dev;
+ int ret = TEST_FAILED;
+
+ printf("Secondary: starting MP hotplug test\n");
+
+ mz = rte_memzone_lookup(MZ_HOTPLUG_STATE);
+ if (mz == NULL) {
+ printf("Secondary: cannot find coordination memzone\n");
+ return TEST_FAILED;
+ }
+ state = mz->addr;
+
+ printf("Secondary: signaling ready\n");
+ signal_state(state, STATE_SECONDARY_READY);
+
+ printf("Secondary: waiting for device probe\n");
+ wait_for_state(&state->state, STATE_SECONDARY_CHECK_DEVICE);
+
+ /*
+ * Primary has probed the device. If MP notification worked correctly,
+ * we should be able to find the device in our local device list.
+ */
+ printf("Secondary: checking for device %s\n", HOTPLUG_TEST_DEV);
+ dev = find_device_by_name(HOTPLUG_TEST_DEV);
+ if (dev != NULL) {
+ printf("Secondary: device found - MP notification worked!\n");
+ ret = TEST_SUCCESS;
+ } else {
+ printf("Secondary: device NOT found - MP notification failed!\n");
+ ret = TEST_FAILED;
+ }
+
+ rte_atomic_store_explicit(&state->secondary_result, ret, rte_memory_order_relaxed);
+ signal_state(state, STATE_SECONDARY_DONE);
+
+ return ret;
+}
+
+static int
+run_primary_hotplug_test(void)
+{
+ const struct rte_memzone *mz = NULL;
+ int test_result = TEST_FAILED;
+ struct hotplug_state *state;
+ struct rte_device *dev;
+ pid_t pid = -1;
+ int ret;
+
+ printf("Primary: starting MP hotplug test\n");
+
+ mz = rte_memzone_reserve(MZ_HOTPLUG_STATE, sizeof(struct hotplug_state),
+ rte_socket_id(), 0);
+ if (mz == NULL) {
+ printf("Primary: cannot create coordination memzone: %s\n",
+ rte_strerror(rte_errno));
+ goto out;
+ }
+ state = mz->addr;
+ memset(state, 0, sizeof(*state));
+
+ printf("Primary: spawning secondary process\n");
+ pid = fork();
+ if (pid < 0) {
+ printf("Primary: fork failed: %s\n", strerror(errno));
+ goto out;
+ }
+
+ if (pid == 0) {
+ /* Child: exec as secondary */
+ const char *prefix;
+ char core_str[16];
+ char *argv[6];
+
+ prefix = file_prefix_arg();
+ snprintf(core_str, sizeof(core_str), "%u", rte_get_main_lcore());
+
+ argv[0] = strdup(prgname);
+ argv[1] = strdup("-l");
+ argv[2] = strdup(core_str);
+ argv[3] = strdup("--proc-type=secondary");
+ argv[4] = strdup(prefix);
+ argv[5] = NULL;
+
+ if (setenv(RECURSIVE_ENV_VAR, "run_hotplug_secondary", 1) == 0)
+ execv(argv[0], argv);
+ exit(TEST_FAILED);
+ }
+
+ /* Parent: continue as primary */
+
+ printf("Primary: waiting for secondary to be ready\n");
+ wait_for_state(&state->state, STATE_SECONDARY_READY);
+ printf("Primary: secondary is ready\n");
+
+ /* Probe device - this should send MP notification to secondary */
+ printf("Primary: probing device %s\n", HOTPLUG_TEST_DEV);
+ ret = rte_dev_probe(HOTPLUG_TEST_DEV);
+ if (ret != 0) {
+ printf("Primary: rte_dev_probe failed: %d (%s)\n", ret, rte_strerror(-ret));
+ goto out;
+ }
+
+ printf("Primary: device probed, signaling secondary\n");
+ signal_state(state, STATE_SECONDARY_CHECK_DEVICE);
+
+ printf("Primary: waiting for secondary result\n");
+ wait_for_state(&state->state, STATE_SECONDARY_DONE);
+
+ test_result = rte_atomic_load_explicit(&state->secondary_result, rte_memory_order_acquire);
+ printf("Primary: secondary reported %s\n",
+ test_result == TEST_SUCCESS ? "SUCCESS" : "FAILURE");
+
+ dev = find_device_by_name(HOTPLUG_TEST_DEV);
+ if (dev != NULL) {
+ printf("Primary: removing device %s\n", HOTPLUG_TEST_DEV);
+ rte_dev_remove(dev);
+ }
+
+out:
+ if (pid > 0) {
+ int wstatus;
+
+ waitpid(pid, &wstatus, 0);
+ if (WIFEXITED(wstatus))
+ printf("Primary: secondary exited with status %d\n", WEXITSTATUS(wstatus));
+ }
+ rte_memzone_free(mz);
+
+ if (test_result == TEST_SUCCESS)
+ printf("== MP hotplug test passed ==\n");
+ else
+ printf("== MP hotplug test FAILED ==\n");
+
+ return test_result;
+}
+
+int
+test_dev_hotplug_mp(void)
+{
+ printf("== Testing hotplug with multi-process notification ==\n");
+
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+ return run_primary_hotplug_test();
+
+ return run_secondary_hotplug_test();
+}
+
+#endif /* RTE_EXEC_ENV_LINUX */
+
+REGISTER_FAST_TEST(dev_hotplug_api_autotest, NOHUGE_OK, ASAN_OK, test_dev_hotplug_api);
+REGISTER_FAST_TEST(dev_hotplug_mp_autotest, NOHUGE_SKIP, ASAN_SKIP, test_dev_hotplug_mp);
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 9ed62a20e0..b43b0a4bb3 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -269,7 +269,7 @@ rte_dev_probe(const char *devargs)
{
const struct internal_config *internal_conf =
eal_get_internal_configuration();
- bool do_mp = !!internal_conf->no_shconf;
+ bool do_mp = internal_conf->no_shconf == 0;
struct eal_dev_mp_req req;
struct rte_device *dev;
int ret;
@@ -428,7 +428,7 @@ rte_dev_remove(struct rte_device *dev)
{
const struct internal_config *internal_conf =
eal_get_internal_configuration();
- bool do_mp = !!internal_conf->no_shconf;
+ bool do_mp = internal_conf->no_shconf == 0;
struct eal_dev_mp_req req;
char *devargs;
int ret;
--
2.54.0
^ permalink raw reply related
* Re: [v2] crypto/qat: fix IPsec MB header include for ARM
From: Thomas Monjalon @ 2026-07-06 13:44 UTC (permalink / raw)
To: Emma Finn; +Cc: Kai Ji, dev
In-Reply-To: <20260706112727.2746447-1-emma.finn@intel.com>
06/07/2026 13:27, Emma Finn:
> Update the header file to always include the platform-specific
> IPsec MB header. Additionally, guard DOCSIS BPI-related fields
> that depend on IPsec MB so they are not included for ARM build.
>
> Fixes: 03c475d609eb ("crypto/qat: require IPsec MB for HMAC precomputes")
>
> Reported-by: Thomas Monjalon <thomas@monjalon.net>
> Signed-off-by: Emma Finn <emma.finn@intel.com>
> ---
> v2:
> * Add guards around DOCSIS BPI
The guards skip some code, leaving some variables unused or unset.
I've fixed them:
--- a/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h
+++ b/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h
@@ -102,6 +102,9 @@ qat_bpicipher_preprocess(struct qat_sym_session *ctx,
#ifndef RTE_ARCH_ARM
bpi_cipher_ipsec(last_block, dst, iv, last_block_len, ctx->expkey,
ctx->mb_mgr, ctx->docsis_key_len);
+#else
+ RTE_SET_USED(dst);
+ RTE_SET_USED(iv);
#endif
#endif
#if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
--- a/drivers/crypto/qat/qat_sym.h
+++ b/drivers/crypto/qat/qat_sym.h
@@ -242,6 +242,9 @@ qat_bpicipher_postprocess(struct qat_sym_session *ctx,
#ifndef RTE_ARCH_ARM
bpi_cipher_ipsec(last_block, dst, iv, last_block_len, ctx->expkey,
ctx->mb_mgr, ctx->docsis_key_len);
+#else
+ RTE_SET_USED(dst);
+ RTE_SET_USED(iv);
#endif
#endif
#if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
--- a/drivers/crypto/qat/qat_sym_session.c
+++ b/drivers/crypto/qat/qat_sym_session.c
@@ -387,7 +387,8 @@ qat_sym_session_configure_cipher(struct rte_cryptodev *dev,
struct rte_crypto_cipher_xform *cipher_xform = NULL;
enum qat_device_gen qat_dev_gen =
internals->qat_dev->qat_dev_gen;
- int ret, is_wireless = 0;
+ int ret = 0;
+ int is_wireless = 0;
struct icp_qat_fw_la_bulk_req *req_tmpl = &session->fw_req;
struct icp_qat_fw_comn_req_hdr *header = &req_tmpl->comn_hdr;
Applied, thanks.
^ permalink raw reply
* [PATCH v2 3/3] dts: add verify coverage for cryptodev testing
From: Andrew Bailey @ 2026-07-06 13:34 UTC (permalink / raw)
To: dev, luca.vizzarro, patrickrobb1997; +Cc: knimoji, lylavoie, Andrew Bailey
In-Reply-To: <20260706133428.468816-1-abailey@iol.unh.edu>
Currently, next-DTS only covers throughput testing through the
dpdk-test-crypto application. This series adds coverage for the verify
option to next DTS to allow functional testing for various algorithms of
crypto devices and virtual devices.
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
---
dts/tests/TestSuite_cryptodev_verify.py | 160 ++++++++++++++++++++++++
tests.TestSuite_cryptodev_verify.rst | 8 ++
2 files changed, 168 insertions(+)
create mode 100644 dts/tests/TestSuite_cryptodev_verify.py
create mode 100644 tests.TestSuite_cryptodev_verify.rst
diff --git a/dts/tests/TestSuite_cryptodev_verify.py b/dts/tests/TestSuite_cryptodev_verify.py
new file mode 100644
index 0000000000..d93f93d09d
--- /dev/null
+++ b/dts/tests/TestSuite_cryptodev_verify.py
@@ -0,0 +1,160 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2026 University of New Hampshire
+
+"""DPDK cryptodev verify test suite.
+
+The main goal of this test suite is to utilize the verify mode of dpdk-test-crypto application
+to ensure functional correctness for various cryptographic operations supported by DPDK
+cryptodev-pmd.
+"""
+
+from api.capabilities import (
+ LinkTopology,
+ requires_link_topology,
+)
+from api.cryptodev import Cryptodev
+from api.cryptodev.config import (
+ AeadAlgName,
+ AuthenticationAlgorithm,
+ AuthenticationOpMode,
+ CipherAlgorithm,
+ DeviceType,
+ EncryptDecryptSwitch,
+ OperationType,
+ TestType,
+ get_device_from_str,
+)
+from api.cryptodev.types import (
+ CryptodevResults,
+)
+from api.test import verify
+from framework.context import get_ctx
+from framework.test_suite import TestSuite, crypto_test
+from framework.testbed_model.virtual_device import VirtualDevice
+
+TOTAL_OPS = 10_000_000
+AES_CBC_DATA = "test_aes_cbc.data"
+AES_GCM_DATA = "test_aes_gcm.data"
+
+
+@requires_link_topology(LinkTopology.NO_LINK)
+class TestCryptodevVerify(TestSuite):
+ """DPDK Crypto Device Testing Suite."""
+
+ def set_up_suite(self) -> None:
+ """Set up the test suite."""
+ self.device_type: DeviceType | None = get_device_from_str(
+ str(get_ctx().sut_node.crypto_device_type)
+ )
+
+ def _verify_output(
+ self,
+ results: list[CryptodevResults],
+ ) -> bool:
+ for result in results:
+ if (
+ getattr(result, "failed_enqueued") > 0
+ or getattr(result, "failed_dequeued") > 0
+ or getattr(result, "failed_ops") > 0
+ ):
+ return False
+ return True
+
+ @crypto_test
+ def aesni_mb_vdev(self) -> None:
+ """aesni_mb_vdev test.
+
+ Steps:
+ * Create a cryptodev instance with aesni_mb virtual device and provided buffer sizes.
+ Verify:
+ * The aes_cbc cipher and sha1_hmac authentication algorithms are working as expected
+ with the dpdk-test-crypto application.
+ """
+ app = Cryptodev(
+ vdevs=[VirtualDevice("crypto_aesni_mb0")],
+ ptest=TestType.verify,
+ test_file=AES_CBC_DATA,
+ test_name="sha1_hmac_buff_32",
+ devtype=DeviceType.crypto_aesni_mb,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=32,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.sha1_hmac,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=64,
+ digest_sz=12,
+ burst_sz=32,
+ buffer_sz=32,
+ total_ops=TOTAL_OPS,
+ )
+
+ verify(self._verify_output(app.run_app(num_vfs=0)), "Failed to verify test sha1_hmac_buff_32")
+
+ @crypto_test
+ def openssl_vdev(self) -> None:
+ """Openssl vdev test.
+
+ Steps:
+ * Create a cryptodev instance with openssl virtual device and provided buffer sizes.
+ Verify:
+ * The aes_cbc cipher and sha1_hmac authentication algorithms are working as expected
+ with the dpdk-test-crypto application.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ app = Cryptodev(
+ vdevs=[VirtualDevice("crypto_openssl0")],
+ ptest=TestType.verify,
+ test_file=AES_GCM_DATA,
+ test_name="aes_gcm_buff_32",
+ devtype=DeviceType.crypto_openssl,
+ optype=OperationType.aead,
+ aead_algo=AeadAlgName.aes_gcm,
+ aead_op=EncryptDecryptSwitch.encrypt,
+ aead_key_sz=16,
+ aead_aad_sz=16,
+ aead_iv_sz=12,
+ digest_sz=16,
+ burst_sz=32,
+ buffer_sz=32,
+ total_ops=TOTAL_OPS,
+ )
+
+ verify(self._verify_output(app.run_app(num_vfs=0)), "Failed to verify test aes_gcm_buff_32")
+
+ @crypto_test
+ def sha1_hmac_buff_32(self) -> None:
+ """aes_cbc test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The aes_cbc cipher and sha1_hmac authentication algorithms are working as expected
+ with the dpdk-test-crypto application.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ app = Cryptodev(
+ ptest=TestType.verify,
+ test_file=AES_CBC_DATA,
+ test_name="sha1_hmac_buff_32",
+ devtype=self.device_type,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=32,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.sha1_hmac,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=64,
+ digest_sz=20,
+ burst_sz=32,
+ buffer_sz=32,
+ total_ops=TOTAL_OPS,
+ )
+
+ verify(self._verify_output(app.run_app()), "Failed to verify test sha1_hmac_buff_32")
diff --git a/tests.TestSuite_cryptodev_verify.rst b/tests.TestSuite_cryptodev_verify.rst
new file mode 100644
index 0000000000..d0a305a7d5
--- /dev/null
+++ b/tests.TestSuite_cryptodev_verify.rst
@@ -0,0 +1,8 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+
+cryptodev_verify Test Suite
+===========================
+
+.. automodule:: tests.TestSuite_cryptodev_verify
+ :members:
+ :show-inheritance:
--
2.54.0
^ permalink raw reply related
* [PATCH v2 2/3] dts: fix cryptodev verify parsing
From: Andrew Bailey @ 2026-07-06 13:34 UTC (permalink / raw)
To: dev, luca.vizzarro, patrickrobb1997; +Cc: knimoji, lylavoie, Andrew Bailey
In-Reply-To: <20260706133428.468816-1-abailey@iol.unh.edu>
The previous implementation of gathering the data of verify output did
not properly gather the correct values. This commit amends the faulty
regex with working ones.
Bugzilla ID: 1945
Fixes: 8ee2df9da125 ("dts: add cryptodev package")
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
---
dts/api/cryptodev/__init__.py | 1 +
dts/api/cryptodev/types.py | 20 ++++++++------------
2 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/dts/api/cryptodev/__init__.py b/dts/api/cryptodev/__init__.py
index 4e8ce47de1..90b847d1fb 100644
--- a/dts/api/cryptodev/__init__.py
+++ b/dts/api/cryptodev/__init__.py
@@ -132,6 +132,7 @@ def run_app(self, num_vfs: int = 1) -> list[CryptodevResults]:
case TestType.pmd_cyclecount:
parser = PmdCyclecountResults
case TestType.verify:
+ parser_options |= re.DOTALL
parser = VerifyResults
return [parser.parse(line) for line in re.findall(regex, result.stdout, parser_options)]
diff --git a/dts/api/cryptodev/types.py b/dts/api/cryptodev/types.py
index df73a86fa4..861d46bf13 100644
--- a/dts/api/cryptodev/types.py
+++ b/dts/api/cryptodev/types.py
@@ -160,26 +160,22 @@ class VerifyResults(CryptodevResults):
"""A parser for verify test output."""
#:
- lcore_id: int = field(metadata=TextParser.find_int(r"lcore\s+(?:id.*\n\s+)?(\d+)"))
+ lcore_id: int = field(metadata=TextParser.find_int(r"\s*(\d+)"))
#: buffer size ran with app
buffer_size: int = field(
- metadata=TextParser.find_int(r"Buf(?:.*\n\s+(?:\d+\s+))?(?:fer size:\s+)?(\d+)"),
+ metadata=TextParser.find_int(r"\s*(?:\d+\s+)(\d+)"),
)
#: burst size ran with app
burst_size: int = field(
- metadata=TextParser.find_int(r"Burst(?:.*\n\s+(?:\d+\s+){2})?(?: size:\s+)?(\d+)"),
+ metadata=TextParser.find_int(r"\s*(?:\d+\s+){2}(\d+)"),
)
#: number of packets enqueued
- enqueued: int = field(metadata=TextParser.find_int(r"Enqueued.*\n\s+(?:\d+\s+){3}(\d+)"))
+ enqueued: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){3}(\d+)"))
#: number of packets dequeued
- dequeued: int = field(metadata=TextParser.find_int(r"Dequeued.*\n\s+(?:\d+\s+){4}(\d+)"))
+ dequeued: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){4}(\d+)"))
#: number of packets enqueue failed
- failed_enqueued: int = field(
- metadata=TextParser.find_int(r"Failed Enq.*\n\s+(?:\d+\s+){5}(\d+)")
- )
+ failed_enqueued: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){5}(\d+)"))
#: number of packets dequeue failed
- failed_dequeued: int = field(
- metadata=TextParser.find_int(r"Failed Deq.*\n\s+(?:\d+\s+){6}(\d+)")
- )
+ failed_dequeued: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){6}(\d+)"))
#: total number of failed operations
- failed_ops: int = field(metadata=TextParser.find_int(r"Failed Ops.*\n\s+(?:\d+\s+){7}(\d+)"))
+ failed_ops: int = field(metadata=TextParser.find_int(r"\s*(?:\d+\s+){7}(\d+)"))
--
2.54.0
^ permalink raw reply related
* [PATCH v2 1/3] dts: add directory for test resources
From: Andrew Bailey @ 2026-07-06 13:34 UTC (permalink / raw)
To: dev, luca.vizzarro, patrickrobb1997; +Cc: knimoji, lylavoie, Andrew Bailey
In-Reply-To: <20260514172553.191331-1-abailey@iol.unh.edu>
The crypto verify test suite being added in this series requires an
input vector file. The two vector files added in this commit are
relocated from old DTS to new DTS. This will allow the crypto verify
test suite to access the required vector files for verify testing.
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
---
dts/api/cryptodev/__init__.py | 2 +-
dts/test_resources/test_aes_cbc.data | 27 +++++++++++++++++++++++++++
dts/test_resources/test_aes_gcm.data | 19 +++++++++++++++++++
3 files changed, 47 insertions(+), 1 deletion(-)
create mode 100644 dts/test_resources/test_aes_cbc.data
create mode 100644 dts/test_resources/test_aes_gcm.data
diff --git a/dts/api/cryptodev/__init__.py b/dts/api/cryptodev/__init__.py
index a4fafc3713..4e8ce47de1 100644
--- a/dts/api/cryptodev/__init__.py
+++ b/dts/api/cryptodev/__init__.py
@@ -76,7 +76,7 @@ def vector_directory(self) -> PurePath:
Returns:
The path to the cryptodev vector files.
"""
- return get_ctx().dpdk_build.remote_dpdk_tree_path.joinpath("app/test-crypto-perf/data/")
+ return get_ctx().dpdk_build.remote_dpdk_tree_path.joinpath("dts/test_resources/")
def run_app(self, num_vfs: int = 1) -> list[CryptodevResults]:
"""Run the cryptodev application with the given app parameters.
diff --git a/dts/test_resources/test_aes_cbc.data b/dts/test_resources/test_aes_cbc.data
new file mode 100644
index 0000000000..ac7a89942f
--- /dev/null
+++ b/dts/test_resources/test_aes_cbc.data
@@ -0,0 +1,27 @@
+# Global Section
+plaintext =
+0xff, 0xca, 0xfb, 0xf1, 0x38, 0x20, 0x2f, 0x7b, 0x24, 0x98, 0x26, 0x7d, 0x1d, 0x9f, 0xb3, 0x93,
+0xd9, 0xef, 0xbd, 0xad, 0x4e, 0x40, 0xbd, 0x60, 0xe9, 0x48, 0x59, 0x90, 0x67, 0xd7, 0x2b, 0x7b
+ciphertext =
+0x77, 0xF9, 0xF7, 0x7A, 0xA3, 0xCB, 0x68, 0x1A, 0x11, 0x70, 0xD8, 0x7A, 0xB6, 0xE2, 0x37, 0x7E,
+0xD1, 0x57, 0x1C, 0x8E, 0x85, 0xD8, 0x08, 0xBF, 0x57, 0x1F, 0x21, 0x6C, 0xAD, 0xAD, 0x47, 0x1E
+cipher_key =
+0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A,
+0xd0, 0xe7, 0x4b, 0xfb, 0x5d, 0xe5, 0x0c, 0xe7, 0x6f, 0x21, 0xb5, 0x52, 0x2a, 0xbb, 0xc7, 0xf7
+auth_key =
+0xaf, 0x96, 0x42, 0xf1, 0x8c, 0x50, 0xdc, 0x67, 0x1a, 0x43, 0x47, 0x62, 0xc7, 0x04, 0xab, 0x05,
+0xf5, 0x0c, 0xe7, 0xa2, 0xa6, 0x23, 0xd5, 0x3d, 0x95, 0xd8, 0xcd, 0x86, 0x79, 0xf5, 0x01, 0x47,
+0x4f, 0xf9, 0x1d, 0x9d, 0x36, 0xf7, 0x68, 0x1a, 0x64, 0x44, 0x58, 0x5d, 0xe5, 0x81, 0x15, 0x2a,
+0x41, 0xe4, 0x0e, 0xaa, 0x1f, 0x04, 0x21, 0xff, 0x2c, 0xf3, 0x73, 0x2b, 0x48, 0x1e, 0xd2, 0xf7
+cipher_iv =
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+# Section sha 1 hmac buff 32
+[sha1_hmac_buff_32]
+digest =
+0x36, 0xCA, 0x49, 0x6A, 0xE3, 0x54, 0xD8, 0x4F, 0x0B, 0x76, 0xD8, 0xAA, 0x78, 0xEB, 0x9D, 0x65,
+0x2C, 0xCA, 0x1F, 0x97
+# Section sha 256 hmac buff 32
+[sha256_hmac_buff_32]
+digest =
+0x1C, 0xB2, 0x3D, 0xD1, 0xF9, 0xC7, 0x6C, 0x49, 0x2E, 0xDA, 0x94, 0x8B, 0xF1, 0xCF, 0x96, 0x43,
+0x67, 0x50, 0x39, 0x76, 0xB5, 0xA1, 0xCE, 0xA1, 0xD7, 0x77, 0x10, 0x07, 0x43, 0x37, 0x05, 0xB4
diff --git a/dts/test_resources/test_aes_gcm.data b/dts/test_resources/test_aes_gcm.data
new file mode 100644
index 0000000000..034f4fa91a
--- /dev/null
+++ b/dts/test_resources/test_aes_gcm.data
@@ -0,0 +1,19 @@
+# Global Section
+plaintext =
+0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
+
+ciphertext =
+0x82, 0x7d, 0xb6, 0xdf, 0x77, 0x0a, 0xe6, 0x45, 0x5a, 0xc3, 0x70, 0x9b, 0x27, 0xb2, 0x61, 0x19,
+0xa2, 0x37, 0x0b, 0xf7, 0x42, 0xfc, 0xec, 0xe7, 0xf7, 0x30, 0xe0, 0x3c, 0x05, 0x55, 0xb3, 0x7d
+
+aead_key =
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+aead_iv =
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
+aead_aad =
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+
+[aes_gcm_buff_32]
+digest =
+0x0f, 0xb2, 0x98, 0x59, 0x48, 0xbf, 0x6c, 0x37, 0x5a, 0xad, 0xcd, 0x97, 0x9f, 0xbb, 0xc8, 0x2a
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] doc: announce QinQ offloading operations in iavf PMD
From: Bruce Richardson @ 2026-07-06 13:34 UTC (permalink / raw)
To: Anurag Mandal; +Cc: dev, vladimir.medvedkin
In-Reply-To: <20260704131730.457722-1-anurag.mandal@intel.com>
On Sat, Jul 04, 2026 at 01:17:30PM +0000, Anurag Mandal wrote:
> The iavf PMD supports hardware offloading for all QinQ operations.
> QinQ tag stripping and insertion offloads have been added for both
> outer VLAN TPIDs: 0x88a8 (IEEE 802.1ad) & 0x8100 (IEEE 802.1Q).
>
> Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
> ---
> doc/guides/nics/features/iavf.ini | 2 +-
> doc/guides/rel_notes/release_26_07.rst | 1 +
> 2 files changed, 2 insertions(+), 1 deletion(-)
>
Patch applied to dpdk-next-net-intel.
Thanks,
/Bruce
^ permalink raw reply
* Re: [PATCH v2 1/2] dts: update parsing for cryptodev latency
From: Andrew Bailey @ 2026-07-06 13:27 UTC (permalink / raw)
To: patrickrobb1997, luca.vizzarro; +Cc: dev, knimoji
In-Reply-To: <20260706132633.465385-1-abailey@iol.unh.edu>
[-- Attachment #1: Type: text/plain, Size: 81 bytes --]
No changes in the most recent submission, only adding dev to the recipient
list.
[-- Attachment #2: Type: text/html, Size: 125 bytes --]
^ permalink raw reply
* [PATCH v2 2/2] dts: add latency coverage for cryptodev testing
From: Andrew Bailey @ 2026-07-06 13:26 UTC (permalink / raw)
To: patrickrobb1997, luca.vizzarro; +Cc: dev, knimoji, Andrew Bailey
In-Reply-To: <20260706132633.465385-1-abailey@iol.unh.edu>
Currently, next DTS only has cryptodev testing coverage for throughput
metrics. This patch adds a test suite to include latency testing for
crypto devices.
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
Reviewed-by: Patrick Robb <patrickrobb1997@gmail.com>
---
.../dts/tests.TestSuite_cryptodev_latency.rst | 8 +
dts/tests/TestSuite_cryptodev_latency.py | 718 ++++++++++++++++++
2 files changed, 726 insertions(+)
create mode 100644 doc/api/dts/tests.TestSuite_cryptodev_latency.rst
create mode 100644 dts/tests/TestSuite_cryptodev_latency.py
diff --git a/doc/api/dts/tests.TestSuite_cryptodev_latency.rst b/doc/api/dts/tests.TestSuite_cryptodev_latency.rst
new file mode 100644
index 0000000000..1bf4a0f4b0
--- /dev/null
+++ b/doc/api/dts/tests.TestSuite_cryptodev_latency.rst
@@ -0,0 +1,8 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+
+cryptodev_latency Test Suite
+============================
+
+.. automodule:: tests.TestSuite_cryptodev_latency
+ :members:
+ :show-inheritance:
diff --git a/dts/tests/TestSuite_cryptodev_latency.py b/dts/tests/TestSuite_cryptodev_latency.py
new file mode 100644
index 0000000000..411196c4c5
--- /dev/null
+++ b/dts/tests/TestSuite_cryptodev_latency.py
@@ -0,0 +1,718 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2026 University of New Hampshire
+
+"""DPDK cryptodev performance test suite.
+
+The main goal of this test suite is to utilize the dpdk-test-cryptodev application to gather
+performance metrics for various cryptographic operations supported by DPDK cryptodev-pmd.
+It will then compare the results against a predefined baseline given in the test_config file to
+ensure performance standards are met.
+"""
+
+from api.capabilities import (
+ LinkTopology,
+ requires_link_topology,
+)
+from api.cryptodev import Cryptodev
+from api.cryptodev.config import (
+ AeadAlgName,
+ AuthenticationAlgorithm,
+ AuthenticationOpMode,
+ CipherAlgorithm,
+ DeviceType,
+ EncryptDecryptSwitch,
+ ListWrapper,
+ OperationType,
+ TestType,
+ get_device_from_str,
+)
+from api.cryptodev.types import (
+ CryptodevResults,
+)
+from api.test import skip, verify
+from framework.context import get_ctx
+from framework.test_suite import BaseConfig, TestSuite, crypto_test
+from framework.testbed_model.virtual_device import VirtualDevice
+
+config_list: list[dict[str, int | float | str]] = [
+ {"buff_size": 64, "avg_cycles": 99_999.00, "avg_time_us": 9999.0},
+ {"buff_size": 512, "avg_cycles": 99_999.00, "avg_time_us": 9999.0},
+ {"buff_size": 2048, "avg_cycles": 99_999.00, "avg_time_us": 9999.0},
+]
+
+TOTAL_OPS = 10_000_000
+
+
+class Config(BaseConfig):
+ """Performance test metrics.
+
+ Attributes:
+ delta_tolerance: The allowed tolerance below a given baseline.
+ latency_test_parameters: The test parameters to use in the test suite.
+ """
+
+ delta_tolerance: float = 0.05
+
+ latency_test_parameters: dict[str, list[dict[str, int | float | str]]] = {
+ "aes_cbc": config_list,
+ "aes_cbc_sha1_hmac": config_list,
+ "aes_cbc_sha2_hmac": config_list,
+ "aes_docsisbpi": config_list,
+ "aes_gcm": config_list,
+ "kasumi_f8_kasumi_f9": config_list,
+ "snow3g_uea2_snow3g_uia2": config_list,
+ "zuc_eea3_zuc_eia3": config_list,
+ "aesni_gcm_vdev": config_list,
+ "aesni_mb_cipher_then_auth_vdev": config_list,
+ "aesni_mb_vdev": config_list,
+ "kasumi_vdev": config_list,
+ "open_ssl_vdev": config_list,
+ "snow3g_vdev": config_list,
+ "zuc_vdev": config_list,
+ }
+
+
+@requires_link_topology(LinkTopology.NO_LINK)
+class TestCryptodevLatency(TestSuite):
+ """DPDK Crypto Device Testing Suite."""
+
+ config: Config
+
+ def set_up_suite(self) -> None:
+ """Set up the test suite."""
+ self.latency_test_parameters: dict[str, list[dict[str, int | float | str]]] = (
+ self.config.latency_test_parameters
+ )
+ self.delta_tolerance: float = self.config.delta_tolerance
+ self.device_type: DeviceType | None = get_device_from_str(
+ str(get_ctx().sut_node.crypto_device_type)
+ )
+ self.buffer_sizes = {}
+
+ for k, v in self.latency_test_parameters.items():
+ self.buffer_sizes[k] = ListWrapper([int(run["buff_size"]) for run in v])
+
+ def _print_stats(self, test_vals: list[dict[str, int | float | str]]) -> None:
+ element_len = len("Avg Time us Target")
+ border_len = (element_len + 1) * (len(test_vals[0]))
+
+ print(f"{'Latency Results'.center(border_len)}\n{'=' * border_len}")
+ for k, v in test_vals[0].items():
+ print(f"|{k.title():<{element_len}}", end="")
+ print(f"|\n{'='*border_len}")
+
+ for test_val in test_vals:
+ for k, v in test_val.items():
+ print(f"|{v:<{element_len}}", end="")
+ print(f"|\n{'='*border_len}")
+
+ def _verify_latency(
+ self,
+ results: list[CryptodevResults],
+ key: str,
+ ) -> list[dict[str, int | float | str]]:
+ result_list: list[dict[str, int | float | str]] = []
+
+ for result in results:
+ # get the corresponding baseline for the current buffer size
+ parameters: dict[str, int | float | str] = next(
+ filter(
+ lambda x: x["buff_size"] == result.buffer_size,
+ self.latency_test_parameters[key],
+ ),
+ {},
+ )
+ if parameters == {}:
+ raise RuntimeError(
+ f"No test parameters found for {key} with buffer size {result.buffer_size}"
+ )
+ test_result = True
+ expected_cycles = parameters["avg_cycles"]
+ expected_time_us = parameters["avg_time_us"]
+ measured_time_delta = abs(
+ (getattr(result, "avg_time_us") - expected_time_us) / expected_time_us
+ )
+ measured_cycles_delta = abs(
+ (getattr(result, "avg_cycles") - expected_cycles) / expected_cycles
+ )
+
+ # result did not meet the given cycles parameter, check if within delta.
+ if getattr(result, "avg_cycles") > expected_cycles:
+ if self.delta_tolerance < measured_cycles_delta:
+ test_result = False
+ # result did not meet the given time parameter, check if within delta.
+ if getattr(result, "avg_time_us") > expected_time_us:
+ if self.delta_tolerance < measured_time_delta:
+ test_result = False
+ result_list.append(
+ {
+ "Buffer Size": parameters["buff_size"],
+ "delta tolerance": self.delta_tolerance,
+ "cycles delta": round(measured_cycles_delta, 5),
+ "Avg cycles": round(getattr(result, "avg_cycles"), 5),
+ "Avg cycles target": expected_cycles,
+ "time delta": round(measured_time_delta, 5),
+ "Avg time us": round(getattr(result, "avg_time_us"), 5),
+ "Avg time us target": expected_time_us,
+ "passed": "PASS" if test_result else "FAIL",
+ }
+ )
+ return result_list
+
+ @crypto_test
+ def aes_cbc(self) -> None:
+ """aes_cbc latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "aes_cbc" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ devtype=self.device_type,
+ optype=OperationType.cipher_only,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=16,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["aes_cbc"],
+ )
+ results = self._verify_latency(app.run_app(), "aes_cbc")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def aes_cbc_sha1_hmac(self) -> None:
+ """aes_cbc_sha1_hmac latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "aes_cbc_sha1_hmac" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ devtype=self.device_type,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ auth_algo=AuthenticationAlgorithm.sha1_hmac,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=64,
+ digest_sz=12,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["aes_cbc_sha1_hmac"],
+ )
+ results = self._verify_latency(app.run_app(), "aes_cbc_sha1_hmac")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def aes_cbc_sha2_hmac(self) -> None:
+ """aes_cbc_sha2_hmac latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "aes_cbc_sha2_hmac" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ devtype=self.device_type,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.sha2_256_hmac,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=64,
+ digest_sz=32,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["aes_cbc_sha2_hmac"],
+ )
+ results = self._verify_latency(app.run_app(), "aes_cbc_sha2_hmac")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def aes_docsisbpi(self) -> None:
+ """aes_docsisbpi latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "aes_docsisbpi" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ devtype=self.device_type,
+ optype=OperationType.cipher_only,
+ cipher_algo=CipherAlgorithm.aes_docsisbpi,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=32,
+ cipher_iv_sz=16,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["aes_docsisbpi"],
+ )
+ results = self._verify_latency(app.run_app(), "aes_docsisbpi")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def aes_gcm(self) -> None:
+ """aes_gcm latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "aes_gcm" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ devtype=self.device_type,
+ optype=OperationType.aead,
+ aead_algo=AeadAlgName.aes_gcm,
+ aead_op=EncryptDecryptSwitch.encrypt,
+ aead_key_sz=16,
+ aead_iv_sz=12,
+ aead_aad_sz=16,
+ digest_sz=16,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["aes_gcm"],
+ )
+ results = self._verify_latency(app.run_app(), "aes_gcm")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def kasumi_f8_kasumi_f9(self) -> None:
+ """kasumi_f8_kasumi_f9 latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "kasumi_f8_kasumi_f9" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ devtype=self.device_type,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.kasumi_f8,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=8,
+ auth_algo=AuthenticationAlgorithm.kasumi_f9,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=16,
+ digest_sz=4,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["kasumi_f8_kasumi_f9"],
+ )
+ results = self._verify_latency(app.run_app(), "kasumi_f8_kasumi_f9")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def snow3g_uea2_snow3g_uia2(self) -> None:
+ """snow3g_uea2_snow3g_uia2 latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "snow3g_uea2_snow3g_uia2" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ devtype=self.device_type,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.snow3g_uea2,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.snow3g_uia2,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=16,
+ auth_iv_sz=16,
+ digest_sz=4,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["snow3g_uea2_snow3g_uia2"],
+ )
+ results = self._verify_latency(app.run_app(), "snow3g_uea2_snow3g_uia2")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def zuc_eea3_zuc_eia3(self) -> None:
+ """zuc_eea3_zuc_eia3 cipher and auth latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "zuc_eea3_zuc_eia3" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ devtype=self.device_type,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.zuc_eea3,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.zuc_eia3,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=16,
+ auth_iv_sz=16,
+ digest_sz=4,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["zuc_eea3_zuc_eia3"],
+ )
+ results = self._verify_latency(app.run_app(), "zuc_eea3_zuc_eia3")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ # BEGIN VDEV TESTS
+
+ @crypto_test
+ def aesni_gcm_vdev(self) -> None:
+ """aesni_gcm virtual device latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "aesni_gcm_vdev" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ vdevs=[VirtualDevice("crypto_aesni_gcm0")],
+ devtype=DeviceType.crypto_aesni_gcm,
+ optype=OperationType.aead,
+ aead_op=EncryptDecryptSwitch.encrypt,
+ aead_key_sz=16,
+ aead_iv_sz=12,
+ aead_aad_sz=16,
+ digest_sz=16,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["aesni_gcm_vdev"],
+ )
+ results = self._verify_latency(app.run_app(num_vfs=0), "aesni_gcm_vdev")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def aesni_mb_cipher_then_auth_vdev(self) -> None:
+ """aesni_mb vdev cipher and auth latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "aesni_mb_cipher_then_auth_vdev" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ vdevs=[VirtualDevice("crypto_aesni_mb0")],
+ devtype=DeviceType.crypto_aesni_mb,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ auth_algo=AuthenticationAlgorithm.sha1_hmac,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=64,
+ digest_sz=12,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["aesni_mb_cipher_then_auth_vdev"],
+ )
+ results = self._verify_latency(app.run_app(num_vfs=0), "aesni_mb_cipher_then_auth_vdev")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def aesni_mb_vdev(self) -> None:
+ """aesni_mb vdev latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "aesni_mb_vdev" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ vdevs=[VirtualDevice("crypto_aesni_mb0")],
+ devtype=DeviceType.crypto_aesni_mb,
+ optype=OperationType.cipher_only,
+ cipher_algo=CipherAlgorithm.aes_cbc,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=16,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["aesni_mb_vdev"],
+ )
+ results = self._verify_latency(app.run_app(num_vfs=0), "aesni_mb_vdev")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def kasumi_vdev(self) -> None:
+ """Kasumi vdev latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "kasumi_vdev" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ vdevs=[VirtualDevice("crypto_kasumi0")],
+ devtype=DeviceType.crypto_kasumi,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.kasumi_f8,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=8,
+ auth_algo=AuthenticationAlgorithm.kasumi_f9,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=16,
+ digest_sz=4,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["kasumi_vdev"],
+ )
+ results = self._verify_latency(app.run_app(num_vfs=0), "kasumi_vdev")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def open_ssl_vdev(self) -> None:
+ """open_ssl vdev latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "open_ssl_vdev" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ vdevs=[VirtualDevice("crypto_openssl0")],
+ devtype=DeviceType.crypto_openssl,
+ optype=OperationType.aead,
+ aead_algo=AeadAlgName.aes_gcm,
+ aead_op=EncryptDecryptSwitch.encrypt,
+ aead_key_sz=16,
+ aead_iv_sz=16,
+ aead_aad_sz=16,
+ digest_sz=16,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["open_ssl_vdev"],
+ )
+ results = self._verify_latency(app.run_app(num_vfs=0), "open_ssl_vdev")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def snow3g_vdev(self) -> None:
+ """snow3g vdev latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "snow3g_vdev" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ vdevs=[VirtualDevice("crypto_snow3g0")],
+ devtype=DeviceType.crypto_snow3g,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.snow3g_uea2,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.snow3g_uia2,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=16,
+ auth_iv_sz=16,
+ digest_sz=16,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["snow3g_vdev"],
+ )
+ results = self._verify_latency(app.run_app(num_vfs=0), "snow3g_vdev")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
+
+ @crypto_test
+ def zuc_vdev(self) -> None:
+ """Zuc vdev latency test.
+
+ Steps:
+ * Create a cryptodev instance with provided device type and buffer sizes.
+ Verify:
+ * The latency is below or within delta of provided baseline.
+
+ Raises:
+ SkippedTestException: When configuration is not provided.
+ """
+ if "zuc_vdev" not in self.latency_test_parameters:
+ skip("test not configured")
+ app = Cryptodev(
+ ptest=TestType.latency,
+ vdevs=[VirtualDevice("crypto_zuc0")],
+ devtype=DeviceType.crypto_zuc,
+ optype=OperationType.cipher_then_auth,
+ cipher_algo=CipherAlgorithm.zuc_eea3,
+ cipher_op=EncryptDecryptSwitch.encrypt,
+ cipher_key_sz=16,
+ cipher_iv_sz=16,
+ auth_algo=AuthenticationAlgorithm.zuc_eia3,
+ auth_op=AuthenticationOpMode.generate,
+ auth_key_sz=16,
+ auth_iv_sz=16,
+ digest_sz=4,
+ burst_sz=32,
+ total_ops=TOTAL_OPS,
+ buffer_sz=self.buffer_sizes["zuc_vdev"],
+ )
+ results = self._verify_latency(app.run_app(num_vfs=0), "zuc_vdev")
+ self._print_stats(results)
+ for result in results:
+ verify(
+ result["passed"] == "PASS",
+ "latency was greater than the delta tolerance above baseline",
+ )
--
2.54.0
^ permalink raw reply related
* [PATCH v2 1/2] dts: update parsing for cryptodev latency
From: Andrew Bailey @ 2026-07-06 13:26 UTC (permalink / raw)
To: patrickrobb1997, luca.vizzarro; +Cc: dev, knimoji, Andrew Bailey
In-Reply-To: <20260428181501.72434-1-abailey@iol.unh.edu>
Previously, the parsing for cryptodev latency output would fail to parse
due to an incorrect regex. This commit updates this regex to properly
capture the burst size attribute for latency results.
Bugzilla ID: 1938
Fixes: 8ee2df9da125 ("dts: add cryptodev package")
Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
Reviewed-by: Patrick Robb <patrickrobb1997@gmail.com>
---
dts/api/cryptodev/__init__.py | 3 +--
dts/api/cryptodev/types.py | 4 ++--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/dts/api/cryptodev/__init__.py b/dts/api/cryptodev/__init__.py
index a4fafc3713..15cffcb409 100644
--- a/dts/api/cryptodev/__init__.py
+++ b/dts/api/cryptodev/__init__.py
@@ -117,7 +117,6 @@ def run_app(self, num_vfs: int = 1) -> list[CryptodevResults]:
f"dependencies missing for virtual device {self._app_params['vdevs'][0].name}"
)
raise e
-
regex = r"^\s+\d+.*$"
parser_options = re.MULTILINE
parser: type[CryptodevResults]
@@ -126,7 +125,7 @@ def run_app(self, num_vfs: int = 1) -> list[CryptodevResults]:
case TestType.throughput:
parser = ThroughputResults
case TestType.latency:
- regex = r"total operations:.*time[^\n]*"
+ regex = r"total operations:.*?time[^\n]*"
parser_options |= re.DOTALL
parser = LatencyResults
case TestType.pmd_cyclecount:
diff --git a/dts/api/cryptodev/types.py b/dts/api/cryptodev/types.py
index df73a86fa4..7b4fd17cb6 100644
--- a/dts/api/cryptodev/types.py
+++ b/dts/api/cryptodev/types.py
@@ -65,11 +65,11 @@ class LatencyResults(CryptodevResults):
#: buffer size ran with app
buffer_size: int = field(
- metadata=TextParser.find_int(r"Buf(?:.*\n\s+\d+\s+)?(?:fer size:\s+)?(\d+)"),
+ metadata=TextParser.find_int(r"Buffer size:\s+(\d+)"),
)
#: burst size ran with app
burst_size: int = field(
- metadata=TextParser.find_int(rf"Burst(?:.*\n\s+\d+\s+){2}?(?: size:\s+)?(\d+)"),
+ metadata=TextParser.find_int(r"Burst size:\s+(\d+)"),
)
#: total operations ran
total_ops: int = field(metadata=TextParser.find_int(r"total operations:\s+(\d+)"))
--
2.54.0
^ permalink raw reply related
* RE: [PATCH] doc: announce QinQ offloading operations in iavf PMD
From: Mandal, Anurag @ 2026-07-06 13:24 UTC (permalink / raw)
To: Richardson, Bruce; +Cc: dev@dpdk.org, Medvedkin, Vladimir
In-Reply-To: <akuM15sJlImRdy6s@bricha3-mobl1.ger.corp.intel.com>
> -----Original Message-----
> From: Richardson, Bruce <bruce.richardson@intel.com>
> Sent: 06 July 2026 16:39
> To: Mandal, Anurag <anurag.mandal@intel.com>
> Cc: dev@dpdk.org; Medvedkin, Vladimir <vladimir.medvedkin@intel.com>
> Subject: Re: [PATCH] doc: announce QinQ offloading operations in iavf PMD
>
> On Sat, Jul 04, 2026 at 01:17:30PM +0000, Anurag Mandal wrote:
> > The iavf PMD supports hardware offloading for all QinQ operations.
> > QinQ tag stripping and insertion offloads have been added for both
> > outer VLAN TPIDs: 0x88a8 (IEEE 802.1ad) & 0x8100 (IEEE 802.1Q).
> >
> > Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
> > ---
> > doc/guides/nics/features/iavf.ini | 2 +-
> > doc/guides/rel_notes/release_26_07.rst | 1 +
> > 2 files changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/doc/guides/nics/features/iavf.ini
> > b/doc/guides/nics/features/iavf.ini
> > index 0ba6f7dfd7..e324a7aecb 100644
> > --- a/doc/guides/nics/features/iavf.ini
> > +++ b/doc/guides/nics/features/iavf.ini
> > @@ -30,7 +30,7 @@ Traffic manager = Y
> > Inline crypto = P
> > CRC offload = Y
> > VLAN offload = P
> > -QinQ offload = P
> > +QinQ offload = Y
>
> Not sure we can advertise full support. Checking with AI it seems we have some
> gaps, for example, the legacy (non-flex) descriptor scalar Rx - used with X710
> NICs for example - doesn't support reading two tags for QinQ strip.
>
> > L3 checksum offload = Y
> > L4 checksum offload = Y
> > Timestamp offload = Y
> > diff --git a/doc/guides/rel_notes/release_26_07.rst
> > b/doc/guides/rel_notes/release_26_07.rst
> > index cf79eb57bf..d864019244 100644
> > --- a/doc/guides/rel_notes/release_26_07.rst
> > +++ b/doc/guides/rel_notes/release_26_07.rst
> > @@ -139,6 +139,7 @@ New Features
> >
> > * Added support for transmitting LLDP packets based on mbuf packet type.
> > * Implemented AVX2 context descriptor transmit paths.
> > + * Added support for QinQ offloading operations.
>
> Can we tighten this statement up a bit - "Added support for Tx QinQ offload", to
> make it clear that it's only the Tx side support has changed in this release?
>
Hi Bruce,
I have added support for both Rx (strip) and Tx (insertion) for QinQ.
net/iavf: support QinQ strip
net/iavf: support QinQ insertion
Earlier only 0x8100 was supported partially. These commits add 0x88a8 as well as tightens 0x8100.
Thanks,
Anurag
> >
> > * **Updated Intel ice driver.**
> >
> > --
> > 2.34.1
> >
^ permalink raw reply
* [PATCH v3] app/testpmd: support runt and ultra-small frames in txonly
From: Xingui Yang @ 2026-07-06 13:20 UTC (permalink / raw)
To: dev
Cc: stephen, david.marchand, aman.deep.singh, fengchengwen, lihuisong,
liuyonglong, kangfenglong
Allow set txpkts to accept packet lengths as small as one byte,
enabling generation of runt frames and ultra-small packets for
testing NIC padding logic and undersized frame handling.
The txonly engine handles three ranges: normal (>= 42 bytes) with
full Ethernet/IPv4/UDP headers, runt (14-41 bytes) with truncated
headers, and ultra-small (< 14 bytes) filled with a repeating
pattern. Checksum offloads are disabled when headers are incomplete.
Minimum length validation in set_tx_pkt_segments() is relaxed from
42 to 1 byte. Random split and multi-flow still require the full
header stack in the first segment, as enforced by tx_only_begin().
Signed-off-by: Xingui Yang <yangxingui@huawei.com>
Suggested-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/test-pmd/config.c | 18 +++--
app/test-pmd/txonly.c | 79 ++++++++++++++++++---
doc/guides/rel_notes/release_26_07.rst | 5 +-
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 21 ++++++
4 files changed, 104 insertions(+), 19 deletions(-)
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 3df7412ef6..31b33d3956 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -6327,9 +6327,9 @@ set_tx_pkt_segments(unsigned int *seg_lengths, unsigned int nb_segs)
/*
* Check that each segment length is greater or equal than
* the mbuf data size.
- * Check also that the total packet length is greater or equal than the
- * size of an empty UDP/IP packet (sizeof(struct rte_ether_hdr) +
- * 20 + 8).
+ * The total packet length may be as small as one byte, this allows
+ * generating runt frames and ultra-small packets for testing NIC
+ * padding logic and undersized frame handling.
*/
tx_pkt_len = 0;
for (i = 0; i < nb_segs; i++) {
@@ -6341,12 +6341,16 @@ set_tx_pkt_segments(unsigned int *seg_lengths, unsigned int nb_segs)
}
tx_pkt_len = (uint16_t)(tx_pkt_len + seg_lengths[i]);
}
- if (tx_pkt_len < (sizeof(struct rte_ether_hdr) + 20 + 8)) {
- fprintf(stderr, "total packet length=%u < %d - give up\n",
- (unsigned) tx_pkt_len,
- (int)(sizeof(struct rte_ether_hdr) + 20 + 8));
+ if (tx_pkt_len == 0) {
+ fprintf(stderr, "total packet length is zero - give up\n");
return;
}
+ if (tx_pkt_len < (sizeof(struct rte_ether_hdr) + 20 + 8))
+ fprintf(stderr,
+ "Warning: total packet length=%u < %d (full Ether/IP/UDP), "
+ "generating runt or ultra-small frames\n",
+ (unsigned int) tx_pkt_len,
+ (int)(sizeof(struct rte_ether_hdr) + 20 + 8));
for (i = 0; i < nb_segs; i++)
tx_pkt_seg_lengths[i] = (uint16_t) seg_lengths[i];
diff --git a/app/test-pmd/txonly.c b/app/test-pmd/txonly.c
index a4acb85d29..6e102e2447 100644
--- a/app/test-pmd/txonly.c
+++ b/app/test-pmd/txonly.c
@@ -64,6 +64,9 @@ static int32_t timestamp_off; /**< Timestamp dynamic field offset */
static bool timestamp_enable; /**< Timestamp enable */
static uint64_t timestamp_initial[RTE_MAX_ETHPORTS];
+/* Fill pattern for ultra-small packets too small to hold Ethernet header. */
+static const char pad_pattern[] = "0123456789abcdef";
+
static void
copy_buf_to_pkt_segs(void* buf, unsigned len, struct rte_mbuf *pkt,
unsigned offset)
@@ -76,6 +79,12 @@ copy_buf_to_pkt_segs(void* buf, unsigned len, struct rte_mbuf *pkt,
while (offset >= seg->data_len) {
offset -= seg->data_len;
seg = seg->next;
+ /*
+ * The packet may be shorter than the header stack when
+ * generating runt frames; stop once it runs out of segments.
+ */
+ if (seg == NULL)
+ return;
}
copy_len = seg->data_len - offset;
seg_buf = rte_pktmbuf_mtod_offset(seg, char *, offset);
@@ -84,6 +93,8 @@ copy_buf_to_pkt_segs(void* buf, unsigned len, struct rte_mbuf *pkt,
len -= copy_len;
buf = ((char*) buf + copy_len);
seg = seg->next;
+ if (seg == NULL)
+ return;
seg_buf = rte_pktmbuf_mtod(seg, char *);
copy_len = seg->data_len;
}
@@ -192,9 +203,6 @@ pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp,
pkt->ol_flags |= ol_flags;
pkt->vlan_tci = vlan_tci;
pkt->vlan_tci_outer = vlan_tci_outer;
- pkt->l2_len = sizeof(struct rte_ether_hdr);
- pkt->l3_len = sizeof(struct rte_ipv4_hdr);
-
pkt_len = pkt->data_len;
pkt_seg = pkt;
for (i = 1; i < nb_segs; i++) {
@@ -204,15 +212,60 @@ pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp,
pkt_len += pkt_seg->data_len;
}
pkt_seg->next = NULL; /* Last segment of packet. */
+
/*
* Copy headers in first packet segment(s).
+ * For runt frames (pkt_len < full header stack), headers are
+ * truncated to fit, copy_buf_to_pkt_segs stops at the last
+ * segment so no out-of-bounds access occurs. For ultra-small
+ * packets (pkt_len < Ethernet header), a fill pattern is used
+ * instead of headers.
*/
- copy_buf_to_pkt(eth_hdr, sizeof(*eth_hdr), pkt, 0);
- copy_buf_to_pkt(&pkt_ip_hdr, sizeof(pkt_ip_hdr), pkt,
- sizeof(struct rte_ether_hdr));
- copy_buf_to_pkt(&pkt_udp_hdr, sizeof(pkt_udp_hdr), pkt,
- sizeof(struct rte_ether_hdr) +
- sizeof(struct rte_ipv4_hdr));
+ if (pkt_len >= sizeof(struct rte_ether_hdr)) {
+ /*
+ * A runt frame may be too short to carry a full IPv4/UDP
+ * header. Clamp l3_len and drop any checksum offload whose
+ * header is not fully present, so the PMD is never asked to
+ * checksum bytes that are not in the frame. pkt_len is at
+ * least sizeof(rte_ether_hdr), so the subtraction below
+ * cannot underflow.
+ */
+ pkt->l2_len = sizeof(struct rte_ether_hdr);
+ pkt->l3_len = RTE_MIN(sizeof(struct rte_ipv4_hdr),
+ pkt_len - sizeof(struct rte_ether_hdr));
+ if (pkt_len < sizeof(struct rte_ether_hdr) +
+ sizeof(struct rte_ipv4_hdr))
+ pkt->ol_flags &= ~(RTE_MBUF_F_TX_IP_CKSUM |
+ RTE_MBUF_F_TX_L4_MASK);
+ else if (pkt_len < sizeof(struct rte_ether_hdr) +
+ sizeof(struct rte_ipv4_hdr) +
+ sizeof(struct rte_udp_hdr))
+ pkt->ol_flags &= ~RTE_MBUF_F_TX_L4_MASK;
+ copy_buf_to_pkt(eth_hdr, sizeof(*eth_hdr), pkt, 0);
+ copy_buf_to_pkt(&pkt_ip_hdr, sizeof(pkt_ip_hdr), pkt,
+ sizeof(struct rte_ether_hdr));
+ copy_buf_to_pkt(&pkt_udp_hdr, sizeof(pkt_udp_hdr), pkt,
+ sizeof(struct rte_ether_hdr) +
+ sizeof(struct rte_ipv4_hdr));
+ } else {
+ struct rte_mbuf *seg;
+ uint32_t j;
+
+ pkt->l2_len = 0;
+ pkt->l3_len = 0;
+ pkt->ol_flags &= ~(RTE_MBUF_F_TX_IP_CKSUM |
+ RTE_MBUF_F_TX_L4_MASK);
+ seg = pkt;
+ while (seg != NULL) {
+ char *data = rte_pktmbuf_mtod(seg, char *);
+
+ for (j = 0; j < seg->data_len; j++)
+ data[j] = pad_pattern[j %
+ (sizeof(pad_pattern) - 1)];
+ seg = seg->next;
+ }
+ }
+
if (txonly_multi_flow) {
uint16_t src_var = RTE_PER_LCORE(_src_port_var);
struct rte_udp_hdr *udp_hdr;
@@ -405,7 +458,13 @@ tx_only_begin(portid_t pi)
pkt_hdr_len = (uint16_t)(sizeof(struct rte_ether_hdr) +
sizeof(struct rte_ipv4_hdr) +
sizeof(struct rte_udp_hdr));
- pkt_data_len = tx_pkt_length - pkt_hdr_len;
+ /*
+ * tx_pkt_length may be smaller than the full header stack when
+ * generating runt or ultra-small frames; clamp the payload length
+ * to zero in that case so the IP/UDP length fields stay sane.
+ */
+ pkt_data_len = tx_pkt_length > pkt_hdr_len ?
+ tx_pkt_length - pkt_hdr_len : 0;
if ((tx_pkt_split == TX_PKT_SPLIT_RND || txonly_multi_flow) &&
tx_pkt_seg_lengths[0] < pkt_hdr_len) {
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 8b1bdada1a..3fca990f78 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -242,8 +242,9 @@ New Features
* **Updated testpmd application.**
- Added support for setting VLAN priority and CFI/DEI bits
- in ``tx_vlan set``/``tx_qinq set`` commands and ``vlan_tci`` parameter.
+ * Added support for setting VLAN priority and CFI/DEI bits
+ in ``tx_vlan set``/``tx_qinq set`` commands and ``vlan_tci`` parameter.
+ * Added support for runt and ultra-small frames in the txonly mode.
* **Added AI review helpers.**
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 364d348372..b69924c5f9 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -876,6 +876,27 @@ Set the length of each segment of the TX-ONLY packets or length of packet for FL
Where x[,y]* represents a CSV list of values, without white space.
+The total packet length may be set as small as one byte, which is below
+the size of an empty IPv4/UDP packet. This generates runt frames or
+ultra-small packets, which is useful for testing how a driver handles
+undersized frames and NIC padding logic.
+
+Normal packets (>= 42 bytes)
+ Full Ethernet/IPv4/UDP headers with checksum offloads.
+
+Runt frames (14-41 bytes)
+ Ethernet header with truncated or absent IPv4/UDP header.
+ Checksum offloads are automatically disabled.
+
+Ultra-small packets (< 14 bytes)
+ No standard headers; filled with a repeating pattern.
+ Checksum offloads are automatically disabled.
+
+Note that random split (``set txsplit rand``) and multi-flow
+(``set txonly-flows``) still require the first segment to hold the full
+Ethernet/IPv4/UDP header stack, so they cannot be combined with runt
+or ultra-small lengths.
+
set txtimes
~~~~~~~~~~~
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] test/bpf_validate: use unit_test_suite_runner
From: Thomas Monjalon @ 2026-07-06 13:18 UTC (permalink / raw)
To: Marat Khalili; +Cc: dev, Konstantin Ananyev, Stephen Hemminger
In-Reply-To: <20260703083739.5aa77dbf@phoenix.local>
03/07/2026 17:37, Stephen Hemminger:
> On Fri, 3 Jul 2026 16:29:09 +0100
> Marat Khalili <marat.khalili@huawei.com> wrote:
>
> > Due to github CI running out of tmpfs space after adding 29 new BPF
> > validate tests they were temporarily disabled. Restore them as a single
> > test using unit_test_suite_runner.
> >
> > Signed-off-by: Marat Khalili <marat.khalili@huawei.com>
> > ---
>
> Acked-by: Stephen Hemminger <stephen@networkplumber.org>
Applied, thanks.
^ permalink raw reply
* RE: [PATCH v2 0/7] doc: build for all public headers
From: Marat Khalili @ 2026-07-06 13:14 UTC (permalink / raw)
To: Marat Khalili
Cc: dev@dpdk.org, thomas@monjalon.net, bruce.richardson@intel.com
In-Reply-To: <20260706105256.79904-1-marat.khalili@huawei.com>
> Marat Khalili (7):
> doc: detect ignored public headers
> doc: document rte_os.h
> doc: fix typos in rte_bus_pci.h
> doc: fix typos in rte_bus_vmbus.h
Newer version of doxygen in CI discovered additional issues in
rte_avp_common.h, will address in v3 tomorrow.
> doc: add missing globs to doxy-api.conf.in
> doc: add missing drivers to doxy-api.conf.in
> doc: add missing headers to doxy-api-index.md
^ permalink raw reply
* Re: [PATCH v3 3/3] dma/ae4dma: add data path operations
From: Raghavendra Ningoji @ 2026-07-06 12:26 UTC (permalink / raw)
To: fengchengwen, dev
Cc: Raghavendra Ningoji, David Marchand, Bruce Richardson,
Selwin.Sebastian, Bhagyada Modali, Robin Jarry, Thomas Monjalon
In-Reply-To: <4c75c27e-6f02-49c5-aa26-b2495739d93c@huawei.com>
On Fri, 27 Jun 2026 at 08:23, fengchengwen <fengchengwen@huawei.com> wrote:
>
> > This commit adds:
> > - copy enqueue (rte_dma_copy): ...
> I don't think it's necessary to write in such detail because the ops
> implemented are defined by the framework. If needed, you can supplement
> by explaining what special features this driver has.
Condensed the commit log in v4. It now just lists the ops and explains
the driver-specific completion handling (the engine signals completion
by advancing read_idx rather than reliably writing a status word back).
> > + cmd_q->next_write = (uint16_t)((write + 1) % nb);
> the next_write is [0, nb_desc-1], and it will as return value as copy,
> but the dmadev framework expect as [0, 0xFFFF], I doubt your drvier was
> not passed in any DMA test (e.g. dpdk-test, dpdk-dma-perf or examples/dma)
> ...
> > + *last_idx = (uint16_t)((cmd_q->next_read - 1 + nb) % nb);
> the last_idx should be in range of [0, 0xFFFF]
Rather than having two counters,framework counter and h/w slot count in dricer, we had verified
internally by wrapping counters of dma-test apps to h/w slots(32).
But again as you mentioned everything has to go with framework.v4 reworks the
indexing so next_write/next_read are free-running 16-bit counters in
[0, 0xFFFF]:
- rte_dma_copy() returns the pre-increment free-running ring_idx.
- completed()/completed_status() always set last_idx to the last
completed ring_idx (next_read - 1), even when no new op is reaped.
- the HW ring slot is derived as (hw_base + idx) & (nb_desc - 1), and
in-flight as (next_write - next_read), which is why the depth is kept
a power of two.
With this plus RTE_DMA_CAPA_OPS_COPY (patch 2/4), the driver follows
the framework ring-index contract.
> > + case AE4DMA_DMA_ERR_INV_ALIGN:
> > + /* Name matches DPDK public enum spelling. */
> > + return RTE_DMA_STATUS_DATA_POISION;
> Suggest add RTE_DMA_STATUS_INVALID_ALIGN enum in rte_dmadev.h
Agreed that reusing DATA_POISION was wrong. For v4 the alignment error
maps to RTE_DMA_STATUS_ERROR_UNKNOWN so we no longer misuse an
unrelated code. Adding a dedicated RTE_DMA_STATUS_INVALID_ALIGNMENT to
the public rte_dmadev.h touches the dmadev API, so I would prefer to do
that as a separate follow-up patch with its own justification - happy
to send it if you agree.
> > + if (nb < 2 || !rte_is_power_of_2(nb))
> > + return 0;
> No need to check this
Removed; vchan_setup already guarantees a valid power-of-two depth.
burst_capacity now just computes (nb - 1) - in_flight.
Thanks,
Raghavendra
^ permalink raw reply
* Re: [PATCH v3 2/3] dma/ae4dma: add control path operations
From: Raghavendra Ningoji @ 2026-07-06 12:25 UTC (permalink / raw)
To: fengchengwen, dev
Cc: Raghavendra Ningoji, David Marchand, Bruce Richardson,
Selwin.Sebastian, Bhagyada Modali, Robin Jarry, Thomas Monjalon
In-Reply-To: <6db5bccd-f82a-4a31-ab4c-b3addbcbcc94@huawei.com>
On Fri, 27 Jun 2026 at 08:09, fengchengwen <fengchengwen@huawei.com> wrote:
>
> > - dev_info_get: advertise RTE_DMA_CAPA_MEM_TO_MEM and the fixed
> > ring depth.
>
> It seemed declare support 2~32 depth, not fixed
Right. The commit log is reworded in v4 to say the device supports a
2 to 32 descriptor range (rounded up to a power of two), not a fixed
depth.
> > + if (sizeof(struct rte_dma_conf) != conf_sz)
> > + return -EINVAL;
> This may break ABI compatible
> ...
> > + if (sizeof(struct rte_dma_vchan_conf) != qconf_sz)
> > + return -EINVAL;
> This may break ABI compatible
Both changed to "conf_sz < sizeof(...)" / "qconf_sz < sizeof(...)" in
dev_configure and vchan_setup.
> > + if (max_desc < 2)
> > + return -EINVAL;
> No need to do this because rte_dma_vchan_setup already do it.
> ...
> > + if (max_desc > AE4DMA_DESCRIPTORS_PER_CMDQ) {
> No need to do this because rte_dma_vchan_setup already do it.
Removed both. The framework clamps nb_desc to the advertised
[min_desc, max_desc] range before calling us.
The power-of-two rounding is kept, though: the framework-visible ring
index is free-running and the HW ring slot is derived from it by
masking ((hw_base + idx) & (nb_desc - 1)), which is only correct for a
power-of-two depth. I added a comment to that effect.
> > + info->dev_capa = RTE_DMA_CAPA_MEM_TO_MEM;
>
> You need also decalre support RTE_DMA_CAP_OPS_COPY, please use dpdk-test
> dmadev_autotest to test it. The dpdk-dma-perf could also test dmadev.
Added. v4 advertises RTE_DMA_CAPA_MEM_TO_MEM | RTE_DMA_CAPA_OPS_COPY.
Together with the data-path ring-index fix in patch 3/4, the device now
correctly reports memory-to-memory copy operation support.
On testing: with these fixes the device passes the DMA API tests and
dpdk-dma-perf. The "DMA dev instance" test suite enqueues 32-deep
bursts, but the AE4DMA ring holds 32 descriptors and reserves one slot
(full when (write + 1) % max == read), so at most 31 can be
outstanding. That suite is therefore skipped on this hardware; patch
4/4 makes its setup return TEST_SKIPPED rather than a hard failure,
matching the existing behaviour of the burst_capacity test (which
already skips below 64).
> > + if (size < sizeof(*rte_stats))
> > + return -EINVAL;
> > + if (rte_stats == NULL)
> > + return -EINVAL;
> No need to do this check because rte_dma_stats_get already check it
> Please make such check on other ops.
Removed the NULL/size checks in stats_get, and likewise the redundant
size check in dev_info_get (the framework validates the pointer and
passes a fixed size).
Thanks,
Raghavendra
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox