All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>
Subject: [PATCH v3 02/65] kvargs: add numeric conversion helpers
Date: Wed, 30 Sep 2026 15:40:20 -0700	[thread overview]
Message-ID: <20260930224340.58580-3-stephen@networkplumber.org> (raw)
In-Reply-To: <20260930224340.58580-1-stephen@networkplumber.org>

Drivers which take numeric values in devargs each open code the
conversion from string to integer, and often get it wrong.
A survey of the tree finds at least fifteen separate
implementations of "parse an unsigned integer devarg", of which two are
exported from lib/ and byte for byte identical to each other.

The recurring bugs are:

  - atoi() is used, so overflow is undefined and nothing is validated;
  - errno is checked without being reset first, so an unrelated earlier
    failure rejects a valid value;
  - errno is checked but endptr is not, so "foo" is silently accepted
    as zero;
  - endptr is checked but errno is not, so an overflowing value is
    accepted as ULLONG_MAX;
  - the result is stored into a narrower type with no range check, so
    nb_desc=65537 silently becomes 1;
  - strtoul() is used for an unsigned target, so a leading '-' is
    accepted and wrapped around, and dev_caps_mask=-1 enables
    everything;
  - the value is dereferenced without checking for NULL, so a key given
    with no value segfaults;
  - base 0 is passed, so a leading zero unexpectedly selects octal.

Add a set of helpers matching arg_handler_t, so they can be passed
straight to rte_kvargs_process(), covering the integer types drivers
actually store into. Each validates the whole string and only writes
the target on success, so a caller supplied default survives a bad
argument.

Add rte_kvargs_handle_bool for on/off style arguments. It accepts the
word forms which only sfc supports today, and treats a key given
without a value as true.

Where a driver needs a range narrower than the target type, expose the
underlying rte_kvargs_to_uint and rte_kvargs_to_int.

Octal is deliberately not supported: no driver documents it, and
reading "010" as eight has been a recurring surprise.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test/test_kvargs.c                 | 221 +++++++++++++
 doc/guides/prog_guide/devargs.rst      |  18 +
 doc/guides/rel_notes/release_26_11.rst |  20 ++
 lib/kvargs/rte_kvargs.c                | 441 +++++++++++++++++++++++++
 lib/kvargs/rte_kvargs.h                | 186 +++++++++++
 5 files changed, 886 insertions(+)

diff --git a/app/test/test_kvargs.c b/app/test/test_kvargs.c
index a14b75948a..b74dfd6acb 100644
--- a/app/test/test_kvargs.c
+++ b/app/test/test_kvargs.c
@@ -2,6 +2,8 @@
  * Copyright 2014 6WIND S.A.
  */
 
+#include <errno.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -328,6 +330,221 @@ static int test_invalid_kvargs(void)
 	return -1;
 }
 
+/* Check the numeric conversion helpers on a value passed through kvargs. */
+static int
+handle_one(arg_handler_t handler, const char *value, void *opaque)
+{
+	struct rte_kvargs *kvlist;
+	char args[128];
+	int ret;
+
+	if (value != NULL)
+		snprintf(args, sizeof(args), "k=%s", value);
+	else
+		snprintf(args, sizeof(args), "k");
+
+	kvlist = rte_kvargs_parse(args, NULL);
+	if (kvlist == NULL)
+		return -1;
+
+	ret = rte_kvargs_process_opt(kvlist, "k", handler, opaque);
+	rte_kvargs_free(kvlist);
+
+	/* rte_kvargs_process_opt() flattens the handler error to -1. */
+	return ret;
+}
+
+/* A handler must accept a good value, and leave the target alone otherwise. */
+#define CHECK_GOOD(handler, type, str, expected) do { \
+	type v = (type)0x5a; \
+	TEST_ASSERT_SUCCESS(handle_one(handler, str, &v), \
+			    "%s rejected \"%s\"", #handler, str); \
+	TEST_ASSERT_EQUAL(v, (type)(expected), \
+			  "%s(\"%s\") gave the wrong value", #handler, str); \
+} while (0)
+
+#define CHECK_BAD(handler, type, str) do { \
+	type v = (type)0x5a; \
+	TEST_ASSERT_FAIL(handle_one(handler, str, &v), \
+			 "%s accepted \"%s\"", #handler, str); \
+	TEST_ASSERT_EQUAL(v, (type)0x5a, \
+			  "%s clobbered the target on \"%s\"", #handler, str); \
+} while (0)
+
+static int
+test_handle_unsigned(void)
+{
+	CHECK_GOOD(rte_kvargs_handle_u8, uint8_t, "0", 0);
+	CHECK_GOOD(rte_kvargs_handle_u8, uint8_t, "255", 255);
+	CHECK_GOOD(rte_kvargs_handle_u8, uint8_t, "0xff", 255);
+	CHECK_GOOD(rte_kvargs_handle_u8, uint8_t, "0XFF", 255);
+	CHECK_GOOD(rte_kvargs_handle_u8, uint8_t, "+7", 7);
+	/* A leading zero must not select octal. */
+	CHECK_GOOD(rte_kvargs_handle_u8, uint8_t, "010", 10);
+	CHECK_BAD(rte_kvargs_handle_u8, uint8_t, "256");
+	CHECK_BAD(rte_kvargs_handle_u8, uint8_t, "-1");
+
+	CHECK_GOOD(rte_kvargs_handle_u16, uint16_t, "65535", 65535);
+	CHECK_BAD(rte_kvargs_handle_u16, uint16_t, "65536");
+
+	CHECK_GOOD(rte_kvargs_handle_u32, uint32_t, "4294967295", UINT32_MAX);
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "4294967296");
+
+	CHECK_GOOD(rte_kvargs_handle_u64, uint64_t, "18446744073709551615",
+		   UINT64_MAX);
+	CHECK_GOOD(rte_kvargs_handle_u64, uint64_t, "0xffffffffffffffff",
+		   UINT64_MAX);
+	CHECK_BAD(rte_kvargs_handle_u64, uint64_t, "18446744073709551616");
+
+	CHECK_GOOD(rte_kvargs_handle_uint, unsigned int, "42", 42);
+	CHECK_GOOD(rte_kvargs_handle_size, size_t, "42", 42);
+
+	/* Malformed values, rejected for every width. */
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "abc");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "12abc");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "12 34");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "0x");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "0x0x10");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "0X0X10");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "--1");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "+-1");
+	/* strtoull() would skip the space and negate what follows. */
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "+ 1");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "- 1");
+	CHECK_BAD(rte_kvargs_handle_u32, uint32_t, "+ -1");
+	/* Trailing white space is fine, though. */
+	CHECK_GOOD(rte_kvargs_handle_u32, uint32_t, " 12 ", 12);
+
+	/* A key with no value at all. */
+	{
+		uint32_t v = 0x5a;
+
+		TEST_ASSERT_FAIL(handle_one(rte_kvargs_handle_u32, NULL, &v),
+				 "u32 accepted a key with no value");
+		TEST_ASSERT_EQUAL(v, 0x5aU, "target clobbered");
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_handle_signed(void)
+{
+	CHECK_GOOD(rte_kvargs_handle_i8, int8_t, "-128", -128);
+	CHECK_GOOD(rte_kvargs_handle_i8, int8_t, "127", 127);
+	CHECK_BAD(rte_kvargs_handle_i8, int8_t, "-129");
+	CHECK_BAD(rte_kvargs_handle_i8, int8_t, "128");
+
+	CHECK_GOOD(rte_kvargs_handle_i16, int16_t, "-32768", -32768);
+	CHECK_BAD(rte_kvargs_handle_i16, int16_t, "32768");
+
+	CHECK_GOOD(rte_kvargs_handle_i32, int32_t, "-2147483648", INT32_MIN);
+	CHECK_BAD(rte_kvargs_handle_i32, int32_t, "2147483648");
+
+	/* INT64_MIN has a magnitude one past INT64_MAX. */
+	CHECK_GOOD(rte_kvargs_handle_i64, int64_t, "-9223372036854775808",
+		   INT64_MIN);
+	CHECK_GOOD(rte_kvargs_handle_i64, int64_t, "9223372036854775807",
+		   INT64_MAX);
+	CHECK_BAD(rte_kvargs_handle_i64, int64_t, "9223372036854775808");
+	CHECK_BAD(rte_kvargs_handle_i64, int64_t, "-9223372036854775809");
+
+	/* A sign in front of a hex value. */
+	CHECK_GOOD(rte_kvargs_handle_i32, int32_t, "-0x10", -16);
+	CHECK_BAD(rte_kvargs_handle_i32, int32_t, "-0x0x10");
+
+	CHECK_GOOD(rte_kvargs_handle_int, int, "-1", -1);
+	CHECK_GOOD(rte_kvargs_handle_int, int, "+1", 1);
+	CHECK_BAD(rte_kvargs_handle_int, int, "");
+	CHECK_BAD(rte_kvargs_handle_int, int, "1x");
+	CHECK_BAD(rte_kvargs_handle_int, int, "-");
+	CHECK_BAD(rte_kvargs_handle_int, int, "- 1");
+	CHECK_BAD(rte_kvargs_handle_int, int, "--1");
+
+	CHECK_GOOD(rte_kvargs_handle_long, long, "-1", -1);
+	CHECK_GOOD(rte_kvargs_handle_long, long, "+1", 1);
+	CHECK_BAD(rte_kvargs_handle_long, long, "");
+	CHECK_BAD(rte_kvargs_handle_long, long, "1x");
+
+	CHECK_GOOD(rte_kvargs_handle_ulong, unsigned long, "1", 1);
+	CHECK_GOOD(rte_kvargs_handle_ulong, unsigned long, "0x10", 16);
+	CHECK_BAD(rte_kvargs_handle_ulong, unsigned long, "-1");
+	CHECK_BAD(rte_kvargs_handle_ulong, unsigned long, "1x");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_handle_bool(void)
+{
+	static const char * const yes[] = {
+		"1", "y", "Y", "yes", "YES", "on", "On", "true", "TRUE",
+	};
+	static const char * const no[] = {
+		"0", "n", "N", "no", "NO", "off", "Off", "false", "FALSE",
+	};
+	unsigned int i;
+	bool v;
+
+	for (i = 0; i < RTE_DIM(yes); i++) {
+		v = false;
+		TEST_ASSERT_SUCCESS(handle_one(rte_kvargs_handle_bool, yes[i], &v),
+				    "bool rejected \"%s\"", yes[i]);
+		TEST_ASSERT(v, "\"%s\" should be true", yes[i]);
+	}
+
+	for (i = 0; i < RTE_DIM(no); i++) {
+		v = true;
+		TEST_ASSERT_SUCCESS(handle_one(rte_kvargs_handle_bool, no[i], &v),
+				    "bool rejected \"%s\"", no[i]);
+		TEST_ASSERT(!v, "\"%s\" should be false", no[i]);
+	}
+
+	/* A bare key is enough to enable the option. */
+	v = false;
+	TEST_ASSERT_SUCCESS(handle_one(rte_kvargs_handle_bool, NULL, &v),
+			    "bool rejected a key with no value");
+	TEST_ASSERT(v, "a key with no value should be true");
+
+	/* But a blank value is not a missing one. */
+	CHECK_BAD(rte_kvargs_handle_bool, bool, "");
+	CHECK_BAD(rte_kvargs_handle_bool, bool, "2");
+	CHECK_BAD(rte_kvargs_handle_bool, bool, "yep");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_kvargs_to_range(void)
+{
+	uint64_t u = 0x5a;
+	int64_t s = 0x5a;
+
+	TEST_ASSERT_SUCCESS(rte_kvargs_to_uint("10", 0, 10, &u), "10 in [0,10]");
+	TEST_ASSERT_EQUAL(u, 10U, "wrong value");
+
+	TEST_ASSERT_EQUAL(rte_kvargs_to_uint("11", 0, 10, &u), -ERANGE,
+			  "11 should be out of [0,10]");
+	TEST_ASSERT_EQUAL(u, 10U, "target clobbered on range error");
+
+	TEST_ASSERT_EQUAL(rte_kvargs_to_uint("0", 1, 10, &u), -ERANGE,
+			  "0 should be out of [1,10]");
+	TEST_ASSERT_EQUAL(rte_kvargs_to_uint(NULL, 0, 10, &u), -EINVAL,
+			  "NULL should be rejected");
+	TEST_ASSERT_EQUAL(rte_kvargs_to_uint("x", 0, 10, &u), -EINVAL,
+			  "\"x\" should be rejected");
+	TEST_ASSERT_EQUAL(rte_kvargs_to_uint("5", 0, 10, NULL), -EINVAL,
+			  "a NULL result should be rejected");
+
+	TEST_ASSERT_SUCCESS(rte_kvargs_to_int("-5", -10, 10, &s), "-5 in [-10,10]");
+	TEST_ASSERT_EQUAL(s, -5, "wrong value");
+	TEST_ASSERT_EQUAL(rte_kvargs_to_int("-11", -10, 10, &s), -ERANGE,
+			  "-11 should be out of [-10,10]");
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite kvargs_test_suite  = {
 	.suite_name = "Kvargs Unit Test Suite",
 	.setup = NULL,
@@ -354,6 +571,10 @@ static struct unit_test_suite kvargs_test_suite  = {
 		TEST_CASE(test_parse_empty_elements),
 		TEST_CASE(test_parse_with_only_key),
 		TEST_CASE(test_invalid_kvargs),
+		TEST_CASE(test_handle_unsigned),
+		TEST_CASE(test_handle_signed),
+		TEST_CASE(test_handle_bool),
+		TEST_CASE(test_kvargs_to_range),
 		TEST_CASES_END() /**< NULL terminate unit test array */
 	}
 };
diff --git a/doc/guides/prog_guide/devargs.rst b/doc/guides/prog_guide/devargs.rst
index c8a7224aa0..b73ad20cf6 100644
--- a/doc/guides/prog_guide/devargs.rst
+++ b/doc/guides/prog_guide/devargs.rst
@@ -248,6 +248,24 @@ PMD drivers can parse devargs using the kvargs library:
        return 0;
    }
 
+Rather than writing a handler for each numeric argument, use the
+conversion handlers provided by kvargs, which do the range checking:
+
+.. code-block:: c
+
+   uint16_t queues = 1;
+   bool scalar = false;
+
+   rte_kvargs_process(kvlist, "queues", rte_kvargs_handle_u16, &queues);
+   rte_kvargs_process_opt(kvlist, "scalar", rte_kvargs_handle_bool, &scalar);
+
+Boolean arguments accept ``1``, ``y``, ``yes``, ``on`` and ``true``,
+case insensitively, and their negative counterparts. A bare ``scalar``
+with no value means true, but reaches the handler only through
+rte_kvargs_process_opt(); rte_kvargs_process() rejects a missing value
+first. An empty ``scalar=`` is rejected, since that is what an unset
+shell variable expands to.
+
 For Ethernet devices, use ``rte_eth_devargs_parse()``
 to parse standard Ethernet arguments like representors:
 
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 58b0e588ce..20271cee52 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -138,6 +138,26 @@ New Features
   Added ``rte_bbdev_queue_stats_get()`` function to retrieve statistics
   for a specific queue, complementing the existing device-level statistics API.
 
+* **Added numeric conversion helpers to kvargs.**
+
+  Added a set of ``arg_handler_t`` compatible helpers which convert a device
+  argument value into a numeric variable, so that drivers no longer need to
+  open code the conversion and its validation:
+
+  * ``rte_kvargs_handle_u8``, ``rte_kvargs_handle_u16``,
+    ``rte_kvargs_handle_u32``, ``rte_kvargs_handle_u64``,
+    ``rte_kvargs_handle_uint``, ``rte_kvargs_handle_ulong``
+    and ``rte_kvargs_handle_size``
+  * ``rte_kvargs_handle_i8``, ``rte_kvargs_handle_i16``,
+    ``rte_kvargs_handle_i32``, ``rte_kvargs_handle_i64``,
+    ``rte_kvargs_handle_int`` and ``rte_kvargs_handle_long``
+  * ``rte_kvargs_handle_bool``, accepting ``1``, ``y``, ``yes``, ``on``,
+    ``true`` and their negative counterparts. A bare ``key`` means true;
+    an empty ``key=`` is rejected.
+
+  Added ``rte_kvargs_to_uint`` and ``rte_kvargs_to_int`` for the cases where
+  a driver needs a narrower range than the target type allows.
+
 
 Removed Items
 -------------
diff --git a/lib/kvargs/rte_kvargs.c b/lib/kvargs/rte_kvargs.c
index 4e3198b33f..3b961a19a8 100644
--- a/lib/kvargs/rte_kvargs.c
+++ b/lib/kvargs/rte_kvargs.c
@@ -3,15 +3,28 @@
  * Copyright(c) 2014 6WIND S.A.
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdbool.h>
+#include <stdint.h>
 
 #include <eal_export.h>
+#include <rte_common.h>
+#include <rte_log.h>
 #include <rte_os_shim.h>
 
 #include "rte_kvargs.h"
 
+RTE_LOG_REGISTER_DEFAULT(kvargs_logtype, INFO);
+#define RTE_LOGTYPE_KVARGS kvargs_logtype
+
+#define KVARGS_LOG(level, ...) \
+	RTE_LOG_LINE(level, KVARGS, __VA_ARGS__)
+
 /*
  * Receive a string with a list of arguments following the pattern
  * key=value,key=value,... and insert them into the list.
@@ -309,3 +322,431 @@ rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
 	free(copy);
 	return kvlist;
 }
+
+/*
+ * Determine the base of a numeric value and skip over its prefix.
+ *
+ * Only decimal and 0x/0X hexadecimal are recognized. Octal is deliberately
+ * not supported: no driver documents it, and silently reading "010" as eight
+ * has been a recurring source of surprise.
+ *
+ * Returns the base, and advances *str past the "0x" prefix if there is one.
+ * Returns 0 if what follows the prefix is a second one: strtoull() would
+ * strip that itself, making "0x0x10" sixteen rather than the garbage it is.
+ */
+static int
+kvargs_get_base(const char **str)
+{
+	const char *s = *str;
+
+	if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') &&
+	    isxdigit((unsigned char)s[2])) {
+		s += 2;
+		if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+			return 0;
+		*str = s;
+		return 16;
+	}
+
+	return 10;
+}
+
+/* Skip trailing white space, and tell whether anything else is left. */
+static bool
+kvargs_at_end(const char *str)
+{
+	while (isspace((unsigned char)*str))
+		str++;
+
+	return *str == '\0';
+}
+
+/*
+ * Consume an optional sign, and report whether it was negative.
+ *
+ * strtoull() skips white space and a sign of its own, and negates on '-',
+ * so the sign has to be taken away from it: it is handled here and anything
+ * that follows must be a digit or an 0x prefix. That rejects "+-1" and
+ * "- 1", which strtoull() would otherwise accept.
+ */
+static bool
+kvargs_get_sign(const char **str)
+{
+	const char *s = *str;
+	bool negative;
+
+	while (isspace((unsigned char)*s))
+		s++;
+
+	negative = (*s == '-');
+	if (*s == '-' || *s == '+')
+		s++;
+
+	*str = s;
+	return negative;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_to_uint, 26.11)
+int
+rte_kvargs_to_uint(const char *value, uint64_t min, uint64_t max,
+		   uint64_t *result)
+{
+	const char *str = value;
+	unsigned long long val;
+	char *endptr;
+	int base;
+
+	if (str == NULL || result == NULL)
+		return -EINVAL;
+
+	/* "-1" would otherwise be silently wrapped around to UINT64_MAX. */
+	if (kvargs_get_sign(&str))
+		return -EINVAL;
+
+	base = kvargs_get_base(&str);
+	if (base == 0)
+		return -EINVAL;	/* doubled 0x prefix */
+
+	/* Nothing may sit between the sign and the digits. */
+	if (!isxdigit((unsigned char)*str))
+		return -EINVAL;
+
+	errno = 0;
+	val = strtoull(str, &endptr, base);
+	if (endptr == str)
+		return -EINVAL;	/* no digits in this base */
+	if (errno == ERANGE)
+		return -ERANGE;
+	if (errno != 0)
+		return -EINVAL;
+	if (!kvargs_at_end(endptr))
+		return -EINVAL;	/* trailing garbage */
+
+	if (val < min || val > max)
+		return -ERANGE;
+
+	*result = val;
+	return 0;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_to_int, 26.11)
+int
+rte_kvargs_to_int(const char *value, int64_t min, int64_t max, int64_t *result)
+{
+	const char *str = value;
+	unsigned long long mag;
+	char *endptr;
+	bool negative;
+	int64_t val;
+	int base;
+
+	if (str == NULL || result == NULL)
+		return -EINVAL;
+
+	negative = kvargs_get_sign(&str);
+	base = kvargs_get_base(&str);
+	if (base == 0)
+		return -EINVAL;	/* doubled 0x prefix */
+
+	/* Nothing may sit between the sign and the digits. */
+	if (!isxdigit((unsigned char)*str))
+		return -EINVAL;
+
+	/*
+	 * The sign is consumed above, so that the 0x prefix can be found
+	 * behind it, and the magnitude is parsed unsigned. Letting strtoll()
+	 * do the whole job instead would reject INT64_MIN, whose magnitude is
+	 * one past INT64_MAX.
+	 */
+	errno = 0;
+	mag = strtoull(str, &endptr, base);
+	if (endptr == str)
+		return -EINVAL;
+	if (errno == ERANGE)
+		return -ERANGE;
+	if (errno != 0)
+		return -EINVAL;
+	if (!kvargs_at_end(endptr))
+		return -EINVAL;
+
+	if (negative) {
+		if (mag > (unsigned long long)INT64_MAX + 1)
+			return -ERANGE;
+		/* Negate in unsigned space; -INT64_MIN would overflow. */
+		val = (int64_t)(-(uint64_t)mag);
+	} else {
+		if (mag > INT64_MAX)
+			return -ERANGE;
+		val = (int64_t)mag;
+	}
+
+	if (val < min || val > max)
+		return -ERANGE;
+
+	*result = val;
+	return 0;
+}
+
+/*
+ * The typed handlers below share this shape: convert with a range matching
+ * the target type, then store. The target is written only on success, so a
+ * caller-supplied default survives a bad argument.
+ */
+static int
+kvargs_store_uint(const char *key, const char *value, void *opaque,
+		  uint64_t max, uint64_t *val)
+{
+	int ret;
+
+	if (opaque == NULL)
+		return -EINVAL;
+
+	ret = rte_kvargs_to_uint(value, 0, max, val);
+	if (ret < 0)
+		KVARGS_LOG(ERR, "invalid value \"%s\" for key \"%s\", expected 0..%" PRIu64,
+			   value != NULL ? value : "", key != NULL ? key : "", max);
+
+	return ret;
+}
+
+static int
+kvargs_store_int(const char *key, const char *value, void *opaque,
+		 int64_t min, int64_t max, int64_t *val)
+{
+	int ret;
+
+	if (opaque == NULL)
+		return -EINVAL;
+
+	ret = rte_kvargs_to_int(value, min, max, val);
+	if (ret < 0)
+		KVARGS_LOG(ERR,
+			   "invalid value \"%s\" for key \"%s\", expected %" PRId64 "..%" PRId64,
+			   value != NULL ? value : "", key != NULL ? key : "",
+			   min, max);
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_u8, 26.11)
+int
+rte_kvargs_handle_u8(const char *key, const char *value, void *opaque)
+{
+	uint64_t val;
+	int ret;
+
+	ret = kvargs_store_uint(key, value, opaque, UINT8_MAX, &val);
+	if (ret == 0)
+		*(uint8_t *)opaque = (uint8_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_u16, 26.11)
+int
+rte_kvargs_handle_u16(const char *key, const char *value, void *opaque)
+{
+	uint64_t val;
+	int ret;
+
+	ret = kvargs_store_uint(key, value, opaque, UINT16_MAX, &val);
+	if (ret == 0)
+		*(uint16_t *)opaque = (uint16_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_u32, 26.11)
+int
+rte_kvargs_handle_u32(const char *key, const char *value, void *opaque)
+{
+	uint64_t val;
+	int ret;
+
+	ret = kvargs_store_uint(key, value, opaque, UINT32_MAX, &val);
+	if (ret == 0)
+		*(uint32_t *)opaque = (uint32_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_u64, 26.11)
+int
+rte_kvargs_handle_u64(const char *key, const char *value, void *opaque)
+{
+	uint64_t val;
+	int ret;
+
+	ret = kvargs_store_uint(key, value, opaque, UINT64_MAX, &val);
+	if (ret == 0)
+		*(uint64_t *)opaque = (uint64_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_uint, 26.11)
+int
+rte_kvargs_handle_uint(const char *key, const char *value, void *opaque)
+{
+	uint64_t val;
+	int ret;
+
+	ret = kvargs_store_uint(key, value, opaque, UINT_MAX, &val);
+	if (ret == 0)
+		*(unsigned int *)opaque = (unsigned int)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_size, 26.11)
+int
+rte_kvargs_handle_size(const char *key, const char *value, void *opaque)
+{
+	uint64_t val;
+	int ret;
+
+	ret = kvargs_store_uint(key, value, opaque, SIZE_MAX, &val);
+	if (ret == 0)
+		*(size_t *)opaque = (size_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_i8, 26.11)
+int
+rte_kvargs_handle_i8(const char *key, const char *value, void *opaque)
+{
+	int64_t val;
+	int ret;
+
+	ret = kvargs_store_int(key, value, opaque, INT8_MIN, INT8_MAX, &val);
+	if (ret == 0)
+		*(int8_t *)opaque = (int8_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_i16, 26.11)
+int
+rte_kvargs_handle_i16(const char *key, const char *value, void *opaque)
+{
+	int64_t val;
+	int ret;
+
+	ret = kvargs_store_int(key, value, opaque, INT16_MIN, INT16_MAX, &val);
+	if (ret == 0)
+		*(int16_t *)opaque = (int16_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_i32, 26.11)
+int
+rte_kvargs_handle_i32(const char *key, const char *value, void *opaque)
+{
+	int64_t val;
+	int ret;
+
+	ret = kvargs_store_int(key, value, opaque, INT32_MIN, INT32_MAX, &val);
+	if (ret == 0)
+		*(int32_t *)opaque = (int32_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_i64, 26.11)
+int
+rte_kvargs_handle_i64(const char *key, const char *value, void *opaque)
+{
+	int64_t val;
+	int ret;
+
+	ret = kvargs_store_int(key, value, opaque, INT64_MIN, INT64_MAX, &val);
+	if (ret == 0)
+		*(int64_t *)opaque = (int64_t)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_int, 26.11)
+int
+rte_kvargs_handle_int(const char *key, const char *value, void *opaque)
+{
+	int64_t val;
+	int ret;
+
+	ret = kvargs_store_int(key, value, opaque, INT_MIN, INT_MAX, &val);
+	if (ret == 0)
+		*(int *)opaque = (int)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_long, 26.11)
+int
+rte_kvargs_handle_long(const char *key, const char *value, void *opaque)
+{
+	int64_t val;
+	int ret;
+
+	ret = kvargs_store_int(key, value, opaque, LONG_MIN, LONG_MAX, &val);
+	if (ret == 0)
+		*(long *)opaque = (long)val;
+
+	return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_ulong, 26.11)
+int
+rte_kvargs_handle_ulong(const char *key, const char *value, void *opaque)
+{
+	uint64_t val;
+	int ret;
+
+	ret = kvargs_store_uint(key, value, opaque, ULONG_MAX, &val);
+	if (ret == 0)
+		*(unsigned long *)opaque = (unsigned long)val;
+
+	return ret;
+}
+
+static const char * const kvargs_true[] = { "1", "y", "yes", "on", "true" };
+static const char * const kvargs_false[] = { "0", "n", "no", "off", "false" };
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_bool, 26.11)
+int
+rte_kvargs_handle_bool(const char *key, const char *value, void *opaque)
+{
+	unsigned int i;
+
+	if (opaque == NULL)
+		return -EINVAL;
+
+	/* A bare key means true; only rte_kvargs_process_opt() allows it.
+	 * An empty value is a blank value, not a missing one, so it is
+	 * rejected below.
+	 */
+	if (value == NULL) {
+		*(bool *)opaque = true;
+		return 0;
+	}
+
+	for (i = 0; i < RTE_DIM(kvargs_true); i++) {
+		if (strcasecmp(value, kvargs_true[i]) == 0) {
+			*(bool *)opaque = true;
+			return 0;
+		}
+	}
+
+	for (i = 0; i < RTE_DIM(kvargs_false); i++) {
+		if (strcasecmp(value, kvargs_false[i]) == 0) {
+			*(bool *)opaque = false;
+			return 0;
+		}
+	}
+
+	KVARGS_LOG(ERR, "invalid value \"%s\" for key \"%s\", expected a boolean",
+		   value, key != NULL ? key : "");
+
+	return -EINVAL;
+}
diff --git a/lib/kvargs/rte_kvargs.h b/lib/kvargs/rte_kvargs.h
index 73fa1e621b..118cf3c79b 100644
--- a/lib/kvargs/rte_kvargs.h
+++ b/lib/kvargs/rte_kvargs.h
@@ -21,6 +21,10 @@
  * ethernet devices at initialization for arguments parsing.
  */
 
+#include <stdint.h>
+
+#include <rte_compat.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -230,6 +234,188 @@ int rte_kvargs_process_opt(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Handlers to convert a key/value pair into a numeric type.
+ *
+ * The functions below all match the ``arg_handler_t`` prototype, so they can
+ * be passed directly to rte_kvargs_process():
+ *
+ * @code
+ *   uint16_t nb_desc = DEFAULT_NB_DESC;
+ *
+ *   ret = rte_kvargs_process(kvlist, "nb_desc",
+ *                            rte_kvargs_handle_u16, &nb_desc);
+ * @endcode
+ *
+ * The value string is accepted only if it represents the whole number, that
+ * is:
+ *
+ * - it is not NULL and not empty;
+ * - it is decimal, or hexadecimal with a ``0x`` or ``0X`` prefix;
+ * - it has no trailing characters other than white space;
+ * - it does not overflow the target type.
+ *
+ * A leading ``+`` or ``-`` sign is accepted. The unsigned handlers reject a
+ * negative value rather than wrapping it around, which is what strtoul()
+ * would otherwise do.
+ *
+ * Note that a leading zero does @b not select octal, so ``010`` is ten and
+ * not eight.
+ *
+ * @param key
+ *   The key, used for error reporting only. May be NULL.
+ * @param value
+ *   The value to convert.
+ * @param opaque
+ *   Pointer to the variable to store the result into. The pointed-to type
+ *   must match the handler: for example rte_kvargs_handle_u16() requires a
+ *   ``uint16_t *``. On error the variable is left unmodified.
+ *
+ * @return
+ *   - 0 on success.
+ *   - -EINVAL if the value is missing or malformed, or if @p opaque is NULL.
+ *   - -ERANGE if the value does not fit in the target type.
+ */
+__rte_experimental
+int rte_kvargs_handle_u8(const char *key, const char *value, void *opaque);
+
+/** Convert a value to uint16_t. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_u16(const char *key, const char *value, void *opaque);
+
+/** Convert a value to uint32_t. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_u32(const char *key, const char *value, void *opaque);
+
+/** Convert a value to uint64_t. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_u64(const char *key, const char *value, void *opaque);
+
+/** Convert a value to int8_t. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_i8(const char *key, const char *value, void *opaque);
+
+/** Convert a value to int16_t. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_i16(const char *key, const char *value, void *opaque);
+
+/** Convert a value to int32_t. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_i32(const char *key, const char *value, void *opaque);
+
+/** Convert a value to int64_t. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_i64(const char *key, const char *value, void *opaque);
+
+/** Convert a value to unsigned int. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_uint(const char *key, const char *value, void *opaque);
+
+/** Convert a value to int. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_int(const char *key, const char *value, void *opaque);
+
+/** Convert a value to long. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_long(const char *key, const char *value, void *opaque);
+
+/** Convert a value to unsigned long. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_ulong(const char *key, const char *value, void *opaque);
+
+/** Convert a value to size_t. See rte_kvargs_handle_u8(). */
+__rte_experimental
+int rte_kvargs_handle_size(const char *key, const char *value, void *opaque);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Convert a key/value pair to a boolean.
+ *
+ * Accepts, case insensitively, ``1``, ``y``, ``yes``, ``on`` and ``true``
+ * for true; ``0``, ``n``, ``no``, ``off`` and ``false`` for false.
+ *
+ * A key given without a value, as in ``key``, is treated as true. Use
+ * rte_kvargs_process_opt() rather than rte_kvargs_process() to support
+ * that form, since the latter rejects a missing value before the handler
+ * is called. An empty value, as in ``key=``, is rejected.
+ *
+ * @param key
+ *   The key, used for error reporting only. May be NULL.
+ * @param value
+ *   The value to convert. NULL means true.
+ * @param opaque
+ *   Pointer to a ``bool`` to store the result into. On error it is left
+ *   unmodified.
+ *
+ * @return
+ *   - 0 on success.
+ *   - -EINVAL if the value is malformed or if @p opaque is NULL.
+ */
+__rte_experimental
+int rte_kvargs_handle_bool(const char *key, const char *value, void *opaque);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Convert a string to an unsigned integer, checking it against a range.
+ *
+ * This is the underlying conversion used by the rte_kvargs_handle_*()
+ * unsigned handlers. It is meant for drivers which need a range narrower
+ * than the target type, or which parse a value obtained from
+ * rte_kvargs_get() rather than from a handler.
+ *
+ * @param value
+ *   The string to convert. Must be non-NULL and non-empty. See
+ *   rte_kvargs_handle_u8() for the accepted syntax.
+ * @param min
+ *   Smallest acceptable value, inclusive.
+ * @param max
+ *   Largest acceptable value, inclusive.
+ * @param result
+ *   Where to store the converted value. Left unmodified on error.
+ *
+ * @return
+ *   - 0 on success.
+ *   - -EINVAL if the value is missing or malformed, or if @p result is NULL.
+ *   - -ERANGE if the value is outside [@p min, @p max].
+ */
+__rte_experimental
+int rte_kvargs_to_uint(const char *value, uint64_t min, uint64_t max,
+	uint64_t *result);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Convert a string to a signed integer, checking it against a range.
+ *
+ * This is the signed counterpart of rte_kvargs_to_uint().
+ *
+ * @param value
+ *   The string to convert. Must be non-NULL and non-empty. See
+ *   rte_kvargs_handle_u8() for the accepted syntax.
+ * @param min
+ *   Smallest acceptable value, inclusive.
+ * @param max
+ *   Largest acceptable value, inclusive.
+ * @param result
+ *   Where to store the converted value. Left unmodified on error.
+ *
+ * @return
+ *   - 0 on success.
+ *   - -EINVAL if the value is missing or malformed, or if @p result is NULL.
+ *   - -ERANGE if the value is outside [@p min, @p max].
+ */
+__rte_experimental
+int rte_kvargs_to_int(const char *value, int64_t min, int64_t max,
+	int64_t *result);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.53.0


  parent reply	other threads:[~2026-09-30 22:43 UTC|newest]

Thread overview: 198+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-14  5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
2026-09-14  5:46 ` [PATCH 01/62] net/txgbe: fix FDIR devarg integer width Stephen Hemminger
2026-09-14  5:46 ` [PATCH 02/62] kvargs: add numeric conversion helpers Stephen Hemminger
2026-09-14  5:46 ` [PATCH 03/62] kvargs: add a socket ID handler Stephen Hemminger
2026-09-14  5:46 ` [PATCH 04/62] kvargs: add hexadecimal conversion helpers Stephen Hemminger
2026-09-14  5:46 ` [PATCH 05/62] eal: validate memory size arguments Stephen Hemminger
2026-09-14  5:46 ` [PATCH 06/62] net/null: use kvargs numeric helpers Stephen Hemminger
2026-09-14  5:46 ` [PATCH 07/62] net/vhost: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 08/62] vdpa/ifc: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 09/62] net/softnic: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 10/62] dma/skeleton: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 11/62] raw/skeleton: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 12/62] baseband/null: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 13/62] net/memif: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 14/62] net/af_packet: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 15/62] net/pcap: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 16/62] net/ring: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 17/62] net/af_xdp: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 18/62] net/ark: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 19/62] net/failsafe: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 20/62] net/virtio: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 21/62] net/bonding: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 22/62] net/ena: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 23/62] net/netvsc: " Stephen Hemminger
2026-09-14 12:43   ` [EXTERNAL] " Wei Hu
2026-09-14  5:46 ` [PATCH 24/62] net/ice: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 25/62] net/iavf: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 26/62] net/i40e: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 27/62] net/idpf: " Stephen Hemminger
2026-09-14  5:46 ` [PATCH 28/62] net/cpfl: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 29/62] net/ixgbe: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 30/62] net/txgbe: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 31/62] net/octeontx: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 32/62] net/octeon_ep: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 33/62] net/qede: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 34/62] net/nfb: " Stephen Hemminger
2026-09-14 14:44   ` Martin Spinler
2026-09-14  5:47 ` [PATCH 35/62] net/thunderx: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 36/62] net/i40e: propagate VF queue number parse errors Stephen Hemminger
2026-09-14  5:47 ` [PATCH 37/62] net/cnxk: use kvargs numeric helpers Stephen Hemminger
2026-09-14  5:47 ` [PATCH 38/62] net/xsc: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 39/62] net/hns3: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 40/62] net/enetc: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 41/62] event/dlb2: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 42/62] net/nfp: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 43/62] drivers/crypto: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 44/62] event/sw: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 45/62] net/bnxt: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 46/62] net/bnxt: propagate devargs parsing errors Stephen Hemminger
2026-09-14  5:47 ` [PATCH 47/62] net/mlx4: use kvargs numeric helpers Stephen Hemminger
2026-09-14  5:47 ` [PATCH 48/62] net/sfc: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 49/62] crypto/mvsam: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 50/62] ml/cnxk: use kvargs numeric helpers in cn10k Stephen Hemminger
2026-09-14  5:47 ` [PATCH 51/62] ml/cnxk: use kvargs numeric helpers in mvtvm Stephen Hemminger
2026-09-14  5:47 ` [PATCH 52/62] event/opdl: use kvargs numeric helpers Stephen Hemminger
2026-09-14  5:47 ` [PATCH 53/62] mempool/cnxk: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 54/62] event/octeontx: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 55/62] baseband/turbo_sw: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 56/62] baseband/la12xx: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 57/62] dma/hisi_acc: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 58/62] crypto/virtio: " Stephen Hemminger
2026-09-14  5:47 ` [PATCH 59/62] net/ice: use kvargs hex helper for debug mask Stephen Hemminger
2026-09-14  5:47 ` [PATCH 60/62] net/hns3: use kvargs hex helper for capability mask Stephen Hemminger
2026-09-14  5:47 ` [PATCH 61/62] net/cxgbe: use kvargs numeric helpers Stephen Hemminger
2026-09-14  5:47 ` [PATCH 62/62] doc: note kvargs devargs conversion in release notes Stephen Hemminger
2026-09-29 16:36 ` [PATCH v2 00/61] kvargs: add numeric conversion helpers Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 01/61] " Stephen Hemminger
2026-09-30  0:49     ` fengchengwen
2026-09-29 16:36   ` [PATCH v2 02/61] kvargs: add a socket ID handler Stephen Hemminger
2026-09-30  1:01     ` fengchengwen
2026-09-29 16:36   ` [PATCH v2 03/61] kvargs: add hexadecimal conversion helpers Stephen Hemminger
2026-09-30  1:07     ` fengchengwen
2026-09-29 16:36   ` [PATCH v2 04/61] eal: validate memory size arguments Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 05/61] net/null: use kvargs numeric helpers Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 06/61] net/vhost: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 07/61] vdpa/ifc: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 08/61] net/softnic: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 09/61] dma/skeleton: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 10/61] raw/skeleton: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 11/61] baseband/null: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 12/61] net/memif: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 13/61] net/af_packet: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 14/61] net/pcap: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 15/61] net/ring: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 16/61] net/af_xdp: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 17/61] net/ark: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 18/61] net/failsafe: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 19/61] net/virtio: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 20/61] net/bonding: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 21/61] net/ena: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 22/61] net/netvsc: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 23/61] net/ice: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 24/61] net/iavf: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 25/61] net/i40e: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 26/61] net/idpf: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 27/61] net/cpfl: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 28/61] net/ixgbe: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 29/61] net/txgbe: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 30/61] net/octeontx: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 31/61] net/octeon_ep: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 32/61] net/qede: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 33/61] net/nfb: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 34/61] net/thunderx: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 35/61] net/i40e: propagate VF queue number parse errors Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 36/61] net/cnxk: use kvargs numeric helpers Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 37/61] net/xsc: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 38/61] net/hns3: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 39/61] net/enetc: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 40/61] event/dlb2: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 41/61] net/nfp: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 42/61] drivers/crypto: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 43/61] event/sw: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 44/61] net/bnxt: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 45/61] net/bnxt: propagate devargs parsing errors Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 46/61] net/mlx4: use kvargs numeric helpers Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 47/61] net/sfc: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 48/61] crypto/mvsam: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 49/61] ml/cnxk: use kvargs numeric helpers in cn10k Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 50/61] ml/cnxk: use kvargs numeric helpers in mvtvm Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 51/61] event/opdl: use kvargs numeric helpers Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 52/61] mempool/cnxk: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 53/61] event/octeontx: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 54/61] baseband/turbo_sw: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 55/61] baseband/la12xx: " Stephen Hemminger
2026-09-29 16:36   ` [PATCH v2 56/61] dma/hisi_acc: " Stephen Hemminger
2026-09-29 16:37   ` [PATCH v2 57/61] crypto/virtio: " Stephen Hemminger
2026-09-29 16:37   ` [PATCH v2 58/61] net/ice: use kvargs hex helper for debug mask Stephen Hemminger
2026-09-29 16:37   ` [PATCH v2 59/61] net/hns3: use kvargs hex helper for capability mask Stephen Hemminger
2026-09-29 16:37   ` [PATCH v2 60/61] net/cxgbe: use kvargs numeric helpers Stephen Hemminger
2026-09-29 16:37   ` [PATCH v2 61/61] doc: note kvargs devargs conversion in release notes Stephen Hemminger
2026-09-30  1:14   ` [PATCH v2 00/61] kvargs: add numeric conversion helpers fengchengwen
2026-09-30 15:21     ` Stephen Hemminger
2026-09-30 22:40 ` [PATCH v3 00/65] " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 01/65] net/ring: make numa node signed Stephen Hemminger
2026-09-30 22:40   ` Stephen Hemminger [this message]
2026-09-30 22:40   ` [PATCH v3 03/65] kvargs: add a socket ID handler Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 04/65] kvargs: add hexadecimal conversion helpers Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 05/65] eal: validate memory size arguments Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 06/65] net/null: use kvargs numeric helpers Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 07/65] net/vhost: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 08/65] vdpa/ifc: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 09/65] net/softnic: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 10/65] dma/skeleton: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 11/65] raw/skeleton: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 12/65] baseband/null: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 13/65] net/memif: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 14/65] net/af_packet: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 15/65] net/pcap: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 16/65] net/ring: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 17/65] net/af_xdp: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 18/65] net/ark: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 19/65] net/failsafe: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 20/65] net/virtio: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 21/65] net/bonding: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 22/65] net/ena: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 23/65] net/netvsc: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 24/65] net/ice: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 25/65] net/iavf: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 26/65] net/i40e: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 27/65] net/idpf: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 28/65] net/cpfl: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 29/65] net/ixgbe: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 30/65] net/txgbe: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 31/65] net/octeontx: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 32/65] net/octeon_ep: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 33/65] net/qede: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 34/65] net/nfb: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 35/65] net/thunderx: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 36/65] net/i40e: propagate VF queue number parse errors Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 37/65] net/cnxk: use kvargs numeric helpers Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 38/65] net/xsc: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 39/65] net/hns3: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 40/65] net/enetc: " Stephen Hemminger
2026-09-30 22:40   ` [PATCH v3 41/65] event/dlb2: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 42/65] net/nfp: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 43/65] drivers/crypto: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 44/65] event/sw: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 45/65] net/bnxt: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 46/65] net/bnxt: propagate devargs parsing errors Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 47/65] net/mlx4: use kvargs numeric helpers Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 48/65] net/sfc: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 49/65] crypto/mvsam: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 50/65] ml/cnxk: use kvargs numeric helpers in cn10k Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 51/65] ml/cnxk: use kvargs numeric helpers in mvtvm Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 52/65] event/opdl: use kvargs numeric helpers Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 53/65] mempool/cnxk: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 54/65] event/octeontx: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 55/65] baseband/turbo_sw: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 56/65] baseband/la12xx: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 57/65] dma/hisi_acc: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 58/65] crypto/virtio: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 59/65] net/ice: use kvargs hex helper for debug mask Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 60/65] net/hns3: use kvargs hex helper for capability mask Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 61/65] net/cxgbe: use kvargs numeric helpers Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 62/65] kvargs: add range conversion handlers Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 63/65] event/sw: use kvargs range handlers Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 64/65] net/cnxk: " Stephen Hemminger
2026-09-30 22:41   ` [PATCH v3 65/65] doc: note kvargs devargs conversion in release notes Stephen Hemminger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260930224340.58580-3-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.