* [PATCH 00/62] kvargs: add numeric conversion helpers and use them
@ 2026-09-14 5:46 Stephen Hemminger
2026-09-14 5:46 ` [PATCH 01/62] net/txgbe: fix FDIR devarg integer width Stephen Hemminger
` (61 more replies)
0 siblings, 62 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
The txgbe driver fix (included) inspired a deeper look at kvargs parsing
across all of DPDK drivers. With AI assistance found lots of issues.
Almost every driver parses numeric device arguments with its own
code, and most get some part of it wrong: atoi() does not detect
invalid input, errno is checked without being cleared, the end
pointer is ignored, the value is truncated before it is range
checked, or base 0 turns a leading zero into octal.
This series adds range checked converters and ready made
rte_kvargs_process() handlers to librte_kvargs, then converts the
drivers to use them.
Library (patches 2 to 4)
------------------------
rte_kvargs_to_uint/to_int/to_hex convert with an explicit range
rte_kvargs_handle_u8/u16/u32/u64 store into a typed variable
rte_kvargs_handle_i8/i16/i32/i64
rte_kvargs_handle_uint/int/long/ulong/size
rte_kvargs_handle_bool 1/y/yes/on/true and negatives,
bare key means true
rte_kvargs_handle_socket_id -1 (SOCKET_ID_ANY) through
RTE_MAX_NUMA_NODES - 1
rte_kvargs_handle_hex32/hex64 bare hex mask, 0x optional
Values are decimal or 0x hexadecimal, no octal, no negative value for
an unsigned type, no trailing garbage.
The handlers log key, value, and expected range on failure.
Unit tests cover all of them.
The new api's are marked experimental for 26.11.
Drivers (patches 6 to 61)
-------------------------
Patch 1 is the txgbe FDIR width fix already in next-net, carried so
the txgbe conversion applies on main. Patch 5 fixes EAL -m/-n/-r
parsing, same class of bug, independent of the rest.
52 drivers converted. Local handlers that only did a range checked
store are deleted, 40 of them, which is why the driver patches remove
about a thousand more lines than they add. Handlers that map values
onto hardware constants or set flags are kept and call the
converters.
Converting forced the question of how wide each field is, and found
twelve handlers storing through a pointer of the wrong width, in
eleven drivers (octeontx, ice twice, vhost, vdpa/ifc, bbdev_null,
idpf, cpfl, ml/cnxk, mempool/cnxk, la12xx, turbo_sw) plus discarded
parse errors in i40e and bnxt. Each is fixed in the patch that
converts the driver.
Nine of those are filed as Bugzilla 2036 to 2044 and the patches
carry the IDs. The worst is octeontx, where "nr_port=1" writes four
bytes into a one byte struct on the stack; next is ice, where
"default-mac-disable" overruns into the protocol extraction array
that was memset a few lines earlier. The la12xx and turbo_sw
mismatches were found in the same audit but not filed separately.
These are probe time parsing bugs and the fixes are part of the
conversion, so they are not marked for stable. The one exception is
the bnxt error propagation fix, which is independent of the new API
and is marked. It is ordered after the bnxt conversion, so it needs
a manual backport.
Left alone: multi field and list syntax (cnxk pre_l2 and SDP
channels, queue ranges, enetc txq_prior), sysfs and getenv() parsing,
and drivers not touched in this round (mlx5 family, cnxk crypto/sec/
event, crypto/scheduler, pfe, vdev_netvsc, raw/cnxk_gpio, qat, sxe2,
bus/vmbus). rte_kvargs_process() return values are still discarded at
some call sites; making those fail probe is a per driver decision.
Behaviour changes
-----------------
- malformed, out of range and wrapped values now fail probe with a
message instead of being silently misread
- a leading zero is decimal, not octal
- boolean arguments accept on/off/yes/no/true/false and reject
anything else, including numbers other than 0 and 1
- socket IDs are checked at both ends (dlb2 accepted
RTE_MAX_NUMA_NODES, turbo_sw and bbdev_null accepted negatives)
- the four bare hex masks (ice hw_debug_mask, hns3 dev_caps_mask,
cxgbe filtermode/filtermask, ark Pkt_dir) keep their syntax
Stephen Hemminger (61):
kvargs: add numeric conversion helpers
kvargs: add a socket ID handler
kvargs: add hexadecimal conversion helpers
eal: validate memory size arguments
net/null: use kvargs numeric helpers
net/vhost: use kvargs numeric helpers
vdpa/ifc: use kvargs numeric helpers
net/softnic: use kvargs numeric helpers
dma/skeleton: use kvargs numeric helpers
raw/skeleton: use kvargs numeric helpers
baseband/null: use kvargs numeric helpers
net/memif: use kvargs numeric helpers
net/af_packet: use kvargs numeric helpers
net/pcap: use kvargs numeric helpers
net/ring: use kvargs numeric helpers
net/af_xdp: use kvargs numeric helpers
net/ark: use kvargs numeric helpers
net/failsafe: use kvargs numeric helpers
net/virtio: use kvargs numeric helpers
net/bonding: use kvargs numeric helpers
net/ena: use kvargs numeric helpers
net/netvsc: use kvargs numeric helpers
net/ice: use kvargs numeric helpers
net/iavf: use kvargs numeric helpers
net/i40e: use kvargs numeric helpers
net/idpf: use kvargs numeric helpers
net/cpfl: use kvargs numeric helpers
net/ixgbe: use kvargs numeric helpers
net/txgbe: use kvargs numeric helpers
net/octeontx: use kvargs numeric helpers
net/octeon_ep: use kvargs numeric helpers
net/qede: use kvargs numeric helpers
net/nfb: use kvargs numeric helpers
net/thunderx: use kvargs numeric helpers
net/i40e: propagate VF queue number parse errors
net/cnxk: use kvargs numeric helpers
net/xsc: use kvargs numeric helpers
net/hns3: use kvargs numeric helpers
net/enetc: use kvargs numeric helpers
event/dlb2: use kvargs numeric helpers
net/nfp: use kvargs numeric helpers
drivers/crypto: use kvargs numeric helpers
event/sw: use kvargs numeric helpers
net/bnxt: use kvargs numeric helpers
net/bnxt: propagate devargs parsing errors
net/mlx4: use kvargs numeric helpers
net/sfc: use kvargs numeric helpers
crypto/mvsam: use kvargs numeric helpers
ml/cnxk: use kvargs numeric helpers in cn10k
ml/cnxk: use kvargs numeric helpers in mvtvm
event/opdl: use kvargs numeric helpers
mempool/cnxk: use kvargs numeric helpers
event/octeontx: use kvargs numeric helpers
baseband/turbo_sw: use kvargs numeric helpers
baseband/la12xx: use kvargs numeric helpers
dma/hisi_acc: use kvargs numeric helpers
crypto/virtio: use kvargs numeric helpers
net/ice: use kvargs hex helper for debug mask
net/hns3: use kvargs hex helper for capability mask
net/cxgbe: use kvargs numeric helpers
doc: note kvargs devargs conversion in release notes
Zhang Tengfei (1):
net/txgbe: fix FDIR devarg integer width
.mailmap | 1 +
app/test/test_kvargs.c | 297 +++++++++
doc/guides/eventdevs/dlb2.rst | 4 +-
doc/guides/nics/null.rst | 2 +-
doc/guides/prog_guide/devargs.rst | 18 +
doc/guides/rel_notes/release_26_11.rst | 44 ++
drivers/baseband/la12xx/bbdev_la12xx.c | 60 +-
drivers/baseband/null/bbdev_null.c | 29 +-
.../baseband/turbo_sw/bbdev_turbo_software.c | 29 +-
drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 15 +-
drivers/crypto/dpaa_sec/dpaa_sec.c | 17 +-
drivers/crypto/mvsam/rte_mrvl_pmd.c | 22 +-
drivers/crypto/virtio/virtio_user_cryptodev.c | 21 +-
drivers/dma/hisi_acc/hisi_acc_dmadev.c | 5 +-
drivers/dma/skeleton/skeleton_dmadev.c | 23 +-
drivers/event/dlb2/dlb2.c | 127 +---
drivers/event/octeontx/ssovf_evdev.c | 25 +-
drivers/event/opdl/opdl_evdev.c | 49 +-
drivers/event/sw/sw_evdev.c | 56 +-
drivers/mempool/cnxk/cnxk_mempool.c | 37 +-
drivers/ml/cnxk/cn10k_ml_dev.c | 70 +--
drivers/ml/cnxk/cn10k_ml_dev.h | 8 +-
drivers/ml/cnxk/cn10k_ml_ops.c | 2 +-
drivers/ml/cnxk/mvtvm_ml_dev.c | 47 +-
drivers/ml/cnxk/mvtvm_ml_dev.h | 2 +-
drivers/net/af_packet/rte_eth_af_packet.c | 72 +--
drivers/net/af_xdp/rte_eth_af_xdp.c | 68 ++-
drivers/net/ark/ark_ethdev.c | 4 +-
drivers/net/bnxt/bnxt_ethdev.c | 148 ++---
drivers/net/bonding/eth_bond_private.h | 8 -
drivers/net/bonding/rte_eth_bond_args.c | 71 +--
drivers/net/bonding/rte_eth_bond_pmd.c | 8 +-
drivers/net/cnxk/cnxk_ethdev_devargs.c | 277 +++------
drivers/net/cxgbe/cxgbe_main.c | 38 +-
drivers/net/ena/ena_ethdev.c | 45 +-
drivers/net/enetc/enetc4_vf.c | 22 +-
drivers/net/failsafe/failsafe_args.c | 20 +-
drivers/net/hns3/hns3_common.c | 23 +-
drivers/net/hns3/hns3_common.h | 3 -
drivers/net/intel/cpfl/cpfl_ethdev.c | 26 +-
drivers/net/intel/i40e/i40e_ethdev.c | 57 +-
drivers/net/intel/iavf/iavf.h | 8 +-
drivers/net/intel/iavf/iavf_ethdev.c | 61 +-
drivers/net/intel/ice/ice_ethdev.c | 123 +---
drivers/net/intel/ice/ice_ethdev.h | 10 +-
drivers/net/intel/idpf/idpf_ethdev.c | 26 +-
drivers/net/intel/ixgbe/ixgbe_ethdev.c | 40 +-
drivers/net/intel/ixgbe/ixgbe_ethdev.h | 4 +-
drivers/net/memif/rte_eth_memif.c | 73 ++-
drivers/net/mlx4/mlx4.c | 33 +-
drivers/net/netvsc/hn_ethdev.c | 6 +-
drivers/net/nfb/nfb_ethdev.c | 13 +-
drivers/net/nfp/nfp_ethdev.c | 36 +-
drivers/net/null/rte_eth_null.c | 78 +--
drivers/net/octeon_ep/otx_ep_ethdev.c | 16 +-
drivers/net/octeontx/octeontx_ethdev.c | 18 +-
drivers/net/pcap/pcap_ethdev.c | 51 +-
drivers/net/qede/qede_ethdev.c | 55 +-
drivers/net/ring/rte_eth_ring.c | 21 +-
drivers/net/sfc/sfc.c | 2 +-
drivers/net/sfc/sfc_kvargs.c | 19 -
drivers/net/sfc/sfc_kvargs.h | 2 -
drivers/net/sfc/sfc_port.c | 2 +-
drivers/net/softnic/rte_eth_softnic.c | 30 +-
.../net/softnic/rte_eth_softnic_internals.h | 3 +-
drivers/net/thunderx/nicvf_ethdev.c | 13 +-
drivers/net/txgbe/txgbe_ethdev.c | 95 ++-
drivers/net/vhost/rte_eth_vhost.c | 69 +--
drivers/net/virtio/virtio_ethdev.c | 36 +-
drivers/net/virtio/virtio_user_ethdev.c | 59 +-
drivers/net/xsc/xsc_dev.c | 50 +-
drivers/raw/skeleton/skeleton_rawdev.c | 20 +-
drivers/vdpa/ifc/ifcvf_vdpa.c | 29 +-
lib/eal/common/eal_common_options.c | 27 +-
lib/kvargs/rte_kvargs.c | 563 ++++++++++++++++++
lib/kvargs/rte_kvargs.h | 257 ++++++++
76 files changed, 2009 insertions(+), 1839 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 65+ messages in thread
* [PATCH 01/62] net/txgbe: fix FDIR devarg integer width
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 02/62] kvargs: add numeric conversion helpers Stephen Hemminger
` (60 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Zhang Tengfei, stable, Thomas Monjalon, Jiawen Wu, Zaiyu Wang
From: Zhang Tengfei <zhtfdev@gmail.com>
txgbe_handle_devarg() stores a uint16_t through extra_args, but
pballoc and drop_queue were u8. Setting pkt-filter-size overwrote
the adjacent drop_queue default.
Fixes: 7e18be9beef2 ("net/txgbe: add device arguments for FDIR")
Cc: stable@dpdk.org
Signed-off-by: Zhang Tengfei <zhtfdev@gmail.com>
---
.mailmap | 1 +
drivers/net/txgbe/txgbe_ethdev.c | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/.mailmap b/.mailmap
index fcb3d1bb3f..1b52f2caef 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1968,6 +1968,7 @@ Zerun Fu <zerun.fu@corigine.com>
Zhangfei Gao <zhangfei.gao@linaro.org>
Zhangkun <zhangk.zhangkun@huawei.com>
Zhanibek Bakin <zhanibek.bakin@gmail.com>
+Zhang Tengfei <zhtfdev@gmail.com>
Zhaochen Zhan <zhaochen.zhan@intel.com>
Zhaoyan Chen <zhaoyan.chen@intel.com>
Zhe Tao <zhe.tao@intel.com>
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 4d2746371b..814840b3f5 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -533,8 +533,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
u16 ffe_pre = 8;
u16 ffe_post = 44;
/* FDIR args */
- u8 pballoc = 0;
- u8 drop_queue = 127;
+ u16 pballoc = 0;
+ u16 drop_queue = 127;
/* New devargs for amberlite config */
u16 tx_headwb = 1;
u16 tx_headwb_size = 16;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 02/62] kvargs: add numeric conversion helpers
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 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 03/62] kvargs: add a socket ID handler Stephen Hemminger
` (59 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
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 | 440 +++++++++++++++++++++++++
lib/kvargs/rte_kvargs.h | 186 +++++++++++
5 files changed, 885 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 87c7e81bde..c175fe089b 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -55,6 +55,26 @@ New Features
Also, make sure to start the actual text at the margin.
=======================================================
+* **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..c3bd199f3e 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,430 @@ 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
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 03/62] kvargs: add a socket ID handler
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 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 04/62] kvargs: add hexadecimal conversion helpers Stephen Hemminger
` (58 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
Device arguments naming a NUMA socket are common, and every driver that
takes one open codes the same range check against RTE_MAX_NUMA_NODES.
They do not agree on what the range is: dlb2 accepts RTE_MAX_NUMA_NODES
itself, and turbo_sw and bbdev_null check only the upper bound, so a
negative socket id is taken as valid.
Add a handler for these:
rte_kvargs_handle_socket_id
It stores through an int and accepts -1, which is SOCKET_ID_ANY, through
RTE_MAX_NUMA_NODES - 1.
The bound is the compile time maximum rather than the sockets present on
the running system, which is what the open coded checks used. Validating
against rte_socket_count() would also make kvargs depend on EAL, which
depends on kvargs in turn.
SOCKET_ID_ANY is spelled as a literal -1 rather than included from
rte_memory.h for the same reason. The value is part of the ABI.
No handler is added for lcore ids. There is no caller for one: the
drivers that take a core argument either parse a list, as crypto/scheduler
does with its coremask, or dispatch many keys through one shared handler,
as mlx5 does with service_core. One can be added when a user appears.
Nor is one added for queue ids or queue counts. Those look similar but
are not: some drivers count from one and others from zero, and the useful
bound is nearly always a hardware limit well below
RTE_MAX_QUEUES_PER_PORT, which rte_kvargs_to_uint() already covers.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/test/test_kvargs.c | 31 ++++++++++++++++++++++++++
doc/guides/rel_notes/release_26_11.rst | 2 ++
lib/kvargs/rte_kvargs.c | 18 +++++++++++++++
lib/kvargs/rte_kvargs.h | 27 ++++++++++++++++++++++
4 files changed, 78 insertions(+)
diff --git a/app/test/test_kvargs.c b/app/test/test_kvargs.c
index b74dfd6acb..f05c7918e9 100644
--- a/app/test/test_kvargs.c
+++ b/app/test/test_kvargs.c
@@ -515,6 +515,36 @@ test_handle_bool(void)
return TEST_SUCCESS;
}
+static int
+test_handle_socket_id(void)
+{
+ char buf[32];
+
+ /* SOCKET_ID_ANY is a valid socket id, anything below it is not. */
+ CHECK_GOOD(rte_kvargs_handle_socket_id, int, "-1", -1);
+ CHECK_GOOD(rte_kvargs_handle_socket_id, int, "0", 0);
+ CHECK_BAD(rte_kvargs_handle_socket_id, int, "-2");
+ CHECK_BAD(rte_kvargs_handle_socket_id, int, "");
+ CHECK_BAD(rte_kvargs_handle_socket_id, int, "1x");
+
+ /* The last valid value, and the first one past it. */
+ {
+ int socket = 0x5a;
+
+ snprintf(buf, sizeof(buf), "%d", RTE_MAX_NUMA_NODES - 1);
+ TEST_ASSERT_SUCCESS(handle_one(rte_kvargs_handle_socket_id, buf,
+ &socket), "socket id %s rejected", buf);
+ TEST_ASSERT_EQUAL(socket, RTE_MAX_NUMA_NODES - 1, "wrong socket id");
+
+ snprintf(buf, sizeof(buf), "%d", RTE_MAX_NUMA_NODES);
+ TEST_ASSERT_FAIL(handle_one(rte_kvargs_handle_socket_id, buf,
+ &socket), "socket id %s accepted", buf);
+ TEST_ASSERT_EQUAL(socket, RTE_MAX_NUMA_NODES - 1, "target clobbered");
+ }
+
+ return TEST_SUCCESS;
+}
+
static int
test_kvargs_to_range(void)
{
@@ -574,6 +604,7 @@ static struct unit_test_suite kvargs_test_suite = {
TEST_CASE(test_handle_unsigned),
TEST_CASE(test_handle_signed),
TEST_CASE(test_handle_bool),
+ TEST_CASE(test_handle_socket_id),
TEST_CASE(test_kvargs_to_range),
TEST_CASES_END() /**< NULL terminate unit test array */
}
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index c175fe089b..dbf7923b66 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -68,6 +68,8 @@ New Features
* ``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_socket_id``, which accepts ``SOCKET_ID_ANY``
+ through ``RTE_MAX_NUMA_NODES`` - 1
* ``rte_kvargs_handle_bool``, accepting ``1``, ``y``, ``yes``, ``on``,
``true`` and their negative counterparts. A bare ``key`` means true;
an empty ``key=`` is rejected.
diff --git a/lib/kvargs/rte_kvargs.c b/lib/kvargs/rte_kvargs.c
index c3bd199f3e..3f45ea519b 100644
--- a/lib/kvargs/rte_kvargs.c
+++ b/lib/kvargs/rte_kvargs.c
@@ -749,3 +749,21 @@ rte_kvargs_handle_bool(const char *key, const char *value, void *opaque)
return -EINVAL;
}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_socket_id, 26.11)
+int
+rte_kvargs_handle_socket_id(const char *key, const char *value, void *opaque)
+{
+ int64_t val;
+ int ret;
+
+ /* SOCKET_ID_ANY, which is -1, is a valid socket id. It is spelled
+ * out here rather than included from EAL, which kvargs sits below.
+ */
+ ret = kvargs_store_int(key, value, opaque, -1,
+ RTE_MAX_NUMA_NODES - 1, &val);
+ if (ret == 0)
+ *(int *)opaque = (int)val;
+
+ return ret;
+}
diff --git a/lib/kvargs/rte_kvargs.h b/lib/kvargs/rte_kvargs.h
index 118cf3c79b..acc15607bc 100644
--- a/lib/kvargs/rte_kvargs.h
+++ b/lib/kvargs/rte_kvargs.h
@@ -359,6 +359,33 @@ int rte_kvargs_handle_size(const char *key, const char *value, void *opaque);
__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 key/value pair to a NUMA socket id.
+ *
+ * Accepts -1, which is SOCKET_ID_ANY, through RTE_MAX_NUMA_NODES - 1.
+ * The bound is the compile time maximum rather than the set of sockets
+ * present on the running system, matching what drivers checked before
+ * this helper existed.
+ *
+ * @param key
+ * The key, used for error reporting only. May be NULL.
+ * @param value
+ * The value to convert.
+ * @param opaque
+ * Pointer to an ``int`` 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.
+ * - -ERANGE if the value is not a valid socket id.
+ */
+__rte_experimental
+int rte_kvargs_handle_socket_id(const char *key, const char *value, void *opaque);
+
/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 04/62] kvargs: add hexadecimal conversion helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (2 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 03/62] kvargs: add a socket ID handler Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 05/62] eal: validate memory size arguments Stephen Hemminger
` (57 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
Several device arguments are documented as a bare hexadecimal mask, with
no 0x prefix, such as the ice hw_debug_mask, the cxgbe filtermode
and filtermask, the hns3 dev_caps_mask and the ark Pkt_dir. Each
open codes strtoull() with base 16, and each gets the validation
wrong in a familiar way. ice checks errno but not the end pointer,
cxgbe checks errno without clearing it first, and hns3 checks
nothing at all, so dev_caps_mask=junk is silently taken as zero.
The existing helpers cannot be used for these. They read base 16 only
when the value carries an explicit 0x prefix, so a documented bare mask
containing a letter, such as "ff", would be rejected outright, while one
which happens to be all digits, such as "10", would be reread as decimal
and change from sixteen to ten.
The second case is the dangerous one: it silently changes the meaning of
a working command line instead of rejecting it, which is the one kind of
breakage the rest of this series is careful to avoid.
Add rte_kvargs_handle_hex32() and rte_kvargs_handle_hex64(), which are
the same as rte_kvargs_handle_u32() and rte_kvargs_handle_u64() except
that the value is always read as hexadecimal, whether or not it carries
a 0x prefix. Expose the underlying rte_kvargs_to_hex() for a mask
narrower than the target type.
A sign is rejected, as it is for the unsigned handlers, so a mask cannot
be given as -1.
Only the 32 and 64 bit widths are added, since those are the only ones
any caller needs; the family can be extended on demand.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/test/test_kvargs.c | 45 +++++++++
doc/guides/rel_notes/release_26_11.rst | 8 +-
lib/kvargs/rte_kvargs.c | 131 ++++++++++++++++++++++---
lib/kvargs/rte_kvargs.h | 44 +++++++++
4 files changed, 213 insertions(+), 15 deletions(-)
diff --git a/app/test/test_kvargs.c b/app/test/test_kvargs.c
index f05c7918e9..6e84ebf35c 100644
--- a/app/test/test_kvargs.c
+++ b/app/test/test_kvargs.c
@@ -475,6 +475,50 @@ test_handle_signed(void)
return TEST_SUCCESS;
}
+static int
+test_handle_hex(void)
+{
+ uint64_t u = 0x5a;
+
+ /* The 0x prefix is optional, and a bare value is still hexadecimal. */
+ CHECK_GOOD(rte_kvargs_handle_hex32, uint32_t, "0xff", 0xff);
+ CHECK_GOOD(rte_kvargs_handle_hex32, uint32_t, "0XFF", 0xff);
+ CHECK_GOOD(rte_kvargs_handle_hex32, uint32_t, "ff", 0xff);
+ CHECK_GOOD(rte_kvargs_handle_hex32, uint32_t, "FF", 0xff);
+ /* "10" is sixteen here, not ten. */
+ CHECK_GOOD(rte_kvargs_handle_hex32, uint32_t, "10", 0x10);
+ CHECK_GOOD(rte_kvargs_handle_hex32, uint32_t, "0", 0);
+ CHECK_GOOD(rte_kvargs_handle_hex32, uint32_t, "00110F10", 0x00110f10);
+ CHECK_GOOD(rte_kvargs_handle_hex32, uint32_t, "ffffffff", 0xffffffff);
+ CHECK_BAD(rte_kvargs_handle_hex32, uint32_t, "100000000");
+ CHECK_BAD(rte_kvargs_handle_hex32, uint32_t, "");
+ CHECK_BAD(rte_kvargs_handle_hex32, uint32_t, "-1");
+ CHECK_BAD(rte_kvargs_handle_hex32, uint32_t, "0x");
+ CHECK_BAD(rte_kvargs_handle_hex32, uint32_t, "0x0x10");
+ CHECK_BAD(rte_kvargs_handle_hex32, uint32_t, "1g");
+ CHECK_BAD(rte_kvargs_handle_hex32, uint32_t, "0x1p");
+
+ CHECK_GOOD(rte_kvargs_handle_hex64, uint64_t, "0xF", 0xf);
+ CHECK_GOOD(rte_kvargs_handle_hex64, uint64_t, "F", 0xf);
+ CHECK_GOOD(rte_kvargs_handle_hex64, uint64_t, "ffffffffffffffff",
+ UINT64_MAX);
+ CHECK_BAD(rte_kvargs_handle_hex64, uint64_t, "10000000000000000");
+ CHECK_BAD(rte_kvargs_handle_hex64, uint64_t, "-1");
+
+ /* The underlying conversion, with a mask narrower than the type. */
+ TEST_ASSERT_SUCCESS(rte_kvargs_to_hex("fff", 0xfff, &u), "fff in 0..fff");
+ TEST_ASSERT_EQUAL(u, 0xfffU, "wrong value");
+ TEST_ASSERT_EQUAL(rte_kvargs_to_hex("1000", 0xfff, &u), -ERANGE,
+ "1000 should be out of 0..fff");
+ TEST_ASSERT_EQUAL(u, 0xfffU, "target clobbered on range error");
+ TEST_ASSERT_EQUAL(rte_kvargs_to_hex(NULL, 0xfff, &u), -EINVAL,
+ "NULL should be rejected");
+ TEST_ASSERT_EQUAL(rte_kvargs_to_hex("f", 0xfff, NULL), -EINVAL,
+ "a NULL result should be rejected");
+
+ return TEST_SUCCESS;
+}
+
static int
test_handle_bool(void)
{
@@ -603,6 +647,7 @@ static struct unit_test_suite kvargs_test_suite = {
TEST_CASE(test_invalid_kvargs),
TEST_CASE(test_handle_unsigned),
TEST_CASE(test_handle_signed),
+ TEST_CASE(test_handle_hex),
TEST_CASE(test_handle_bool),
TEST_CASE(test_handle_socket_id),
TEST_CASE(test_kvargs_to_range),
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index dbf7923b66..a663d69655 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -73,9 +73,13 @@ New Features
* ``rte_kvargs_handle_bool``, accepting ``1``, ``y``, ``yes``, ``on``,
``true`` and their negative counterparts. A bare ``key`` means true;
an empty ``key=`` is rejected.
+ * ``rte_kvargs_handle_hex32`` and ``rte_kvargs_handle_hex64``, for the
+ arguments documented as a bare hexadecimal mask, where the value is
+ always read as hexadecimal whether or not it carries a ``0x`` prefix
- 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.
+ Added ``rte_kvargs_to_uint``, ``rte_kvargs_to_int`` and
+ ``rte_kvargs_to_hex`` 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 3f45ea519b..2fa2b77178 100644
--- a/lib/kvargs/rte_kvargs.c
+++ b/lib/kvargs/rte_kvargs.c
@@ -323,6 +323,35 @@ rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
return kvlist;
}
+/*
+ * Skip over a "0x" prefix if there is one.
+ *
+ * Returns true if a prefix was consumed, and advances *str past it. Only one
+ * prefix is ever consumed: a second one is left in place so that the caller
+ * rejects it, since strtoull() would otherwise strip it itself and read
+ * "0x0x10" as sixteen rather than as the garbage it is.
+ */
+static bool
+kvargs_skip_hex_prefix(const char **str)
+{
+ const char *s = *str;
+
+ if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') &&
+ isxdigit((unsigned char)s[2])) {
+ *str = s + 2;
+ return true;
+ }
+
+ return false;
+}
+
+/* Tell whether a "0x" prefix is present, without consuming it. */
+static bool
+kvargs_has_hex_prefix(const char *str)
+{
+ return str[0] == '0' && (str[1] == 'x' || str[1] == 'X');
+}
+
/*
* Determine the base of a numeric value and skip over its prefix.
*
@@ -331,24 +360,15 @@ rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
* 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.
+ * Returns 0 if what follows the prefix is a second one, which is not a number.
*/
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;
- }
+ if (!kvargs_skip_hex_prefix(str))
+ return 10;
- return 10;
+ return kvargs_has_hex_prefix(*str) ? 0 : 16;
}
/* Skip trailing white space, and tell whether anything else is left. */
@@ -487,6 +507,46 @@ rte_kvargs_to_int(const char *value, int64_t min, int64_t max, int64_t *result)
return 0;
}
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_to_hex, 26.11)
+int
+rte_kvargs_to_hex(const char *value, uint64_t max, uint64_t *result)
+{
+ const char *str = value;
+ unsigned long long val;
+ char *endptr;
+
+ if (str == NULL || result == NULL)
+ return -EINVAL;
+
+ /* A mask has no sign; "-1" must not wrap around to UINT64_MAX. */
+ if (kvargs_get_sign(&str))
+ return -EINVAL;
+
+ /* The 0x prefix is optional here, but still accepted. */
+ if (kvargs_skip_hex_prefix(&str) && kvargs_has_hex_prefix(str))
+ return -EINVAL; /* doubled 0x prefix */
+
+ if (!isxdigit((unsigned char)*str))
+ return -EINVAL;
+
+ errno = 0;
+ val = strtoull(str, &endptr, 16);
+ if (endptr == str)
+ return -EINVAL;
+ if (errno == ERANGE)
+ return -ERANGE;
+ if (errno != 0)
+ return -EINVAL;
+ if (!kvargs_at_end(endptr))
+ return -EINVAL; /* trailing garbage */
+
+ if (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
@@ -709,6 +769,51 @@ rte_kvargs_handle_ulong(const char *key, const char *value, void *opaque)
return ret;
}
+static int
+kvargs_store_hex(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_hex(value, max, val);
+ if (ret < 0)
+ KVARGS_LOG(ERR, "invalid value \"%s\" for key \"%s\", expected 0..%" PRIx64 " in hex",
+ value != NULL ? value : "", key != NULL ? key : "", max);
+
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_hex32, 26.11)
+int
+rte_kvargs_handle_hex32(const char *key, const char *value, void *opaque)
+{
+ uint64_t val;
+ int ret;
+
+ ret = kvargs_store_hex(key, value, opaque, UINT32_MAX, &val);
+ if (ret == 0)
+ *(uint32_t *)opaque = (uint32_t)val;
+
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_kvargs_handle_hex64, 26.11)
+int
+rte_kvargs_handle_hex64(const char *key, const char *value, void *opaque)
+{
+ uint64_t val;
+ int ret;
+
+ ret = kvargs_store_hex(key, value, opaque, UINT64_MAX, &val);
+ if (ret == 0)
+ *(uint64_t *)opaque = 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" };
diff --git a/lib/kvargs/rte_kvargs.h b/lib/kvargs/rte_kvargs.h
index acc15607bc..fe18841709 100644
--- a/lib/kvargs/rte_kvargs.h
+++ b/lib/kvargs/rte_kvargs.h
@@ -330,6 +330,24 @@ int rte_kvargs_handle_ulong(const char *key, const char *value, void *opaque);
__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 bit mask to uint32_t.
+ *
+ * As rte_kvargs_handle_u32(), except that the value is always read as
+ * hexadecimal, with or without a ``0x`` prefix, so ``10`` is sixteen. This
+ * is for arguments documented as a bare hexadecimal mask; use
+ * rte_kvargs_handle_u32() for a count or a size.
+ */
+__rte_experimental
+int rte_kvargs_handle_hex32(const char *key, const char *value, void *opaque);
+
+/** Convert a hexadecimal value to uint64_t. See rte_kvargs_handle_hex32(). */
+__rte_experimental
+int rte_kvargs_handle_hex64(const char *key, const char *value, void *opaque);
+
/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
@@ -443,6 +461,32 @@ __rte_experimental
int rte_kvargs_to_int(const char *value, int64_t min, int64_t max,
int64_t *result);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Convert a hexadecimal string to an unsigned integer, checking it against
+ * a maximum.
+ *
+ * This is the conversion underlying rte_kvargs_handle_hex32(), and is the
+ * hexadecimal counterpart of rte_kvargs_to_uint(). The minimum is always
+ * zero, since a negative value is rejected rather than wrapped around.
+ *
+ * @param value
+ * The string to convert. Must be non-NULL and non-empty.
+ * @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 greater than @p max.
+ */
+__rte_experimental
+int rte_kvargs_to_hex(const char *value, uint64_t max, uint64_t *result);
+
#ifdef __cplusplus
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 05/62] eal: validate memory size arguments
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (3 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 04/62] kvargs: add hexadecimal conversion helpers Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 06/62] net/null: use kvargs numeric helpers Stephen Hemminger
` (56 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
The -m, -n and -r options are converted with atoi(), which does not
detect any error: it returns zero for a string that is not a number at
all, and its behaviour on overflow is undefined.
So "-m foo" is silently taken as zero rather than rejected, and
"-m 99999999999999999999" is undefined. The -n and -r cases are partly
covered by their existing checks for zero, but only because a garbage
value happens to convert to zero; "-n 4x" is accepted as four.
The -m value is also scaled by 1024 * 1024 with no check, so a large
enough value wraps around and asks for a small amount of memory.
Use rte_kvargs_to_uint() for the three options, which converts the
whole string and checks it against a range. EAL already depends on
kvargs, so no new dependency is introduced. Note that this now bounds
-m so that the scaled value cannot overflow size_t, which on a 32-bit
build limits it to just under 4G; previously such a value was accepted
and wrapped.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
lib/eal/common/eal_common_options.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 42cdef632f..519307bdc3 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -9,6 +9,7 @@
#include <ctype.h>
#include <limits.h>
#include <errno.h>
+#include <stdint.h>
#include <getopt.h>
#include <sys/queue.h>
#ifndef RTE_EXEC_ENV_WINDOWS
@@ -29,6 +30,7 @@
#include <rte_tailq.h>
#include <rte_version.h>
#include <rte_devargs.h>
+#include <rte_kvargs.h>
#include <rte_memcpy.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <rte_telemetry.h>
@@ -2210,23 +2212,34 @@ eal_parse_args(void)
/* memory options */
if (args.memory_size != NULL) {
- int_cfg->memory = atoi(args.memory_size);
- int_cfg->memory *= 1024ULL;
- int_cfg->memory *= 1024ULL;
+ uint64_t mem;
+
+ /* value is in megabytes, and must not overflow when scaled */
+ if (rte_kvargs_to_uint(args.memory_size, 0,
+ SIZE_MAX / (1024 * 1024), &mem) < 0) {
+ EAL_LOG(ERR, "invalid memory size parameter");
+ return -1;
+ }
+ int_cfg->memory = (size_t)mem * 1024 * 1024;
}
if (args.memory_channels != NULL) {
- int_cfg->force_nchannel = atoi(args.memory_channels);
- if (int_cfg->force_nchannel == 0) {
+ uint64_t channels;
+
+ if (rte_kvargs_to_uint(args.memory_channels, 1, UINT_MAX,
+ &channels) < 0) {
EAL_LOG(ERR, "invalid memory channel parameter");
return -1;
}
+ int_cfg->force_nchannel = channels;
}
if (args.memory_ranks != NULL) {
- int_cfg->force_nrank = atoi(args.memory_ranks);
- if (int_cfg->force_nrank == 0 || int_cfg->force_nrank > 16) {
+ uint64_t ranks;
+
+ if (rte_kvargs_to_uint(args.memory_ranks, 1, 16, &ranks) < 0) {
EAL_LOG(ERR, "invalid memory rank parameter");
return -1;
}
+ int_cfg->force_nrank = ranks;
}
if (args.no_huge) {
int_cfg->no_hugetlbfs = 1;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 06/62] net/null: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (4 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 05/62] eal: validate memory size arguments Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 07/62] net/vhost: " Stephen Hemminger
` (55 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Tetsuya Mukawa
The three device argument handlers each convert with strtoul() and
check neither errno nor the end pointer, so "size=foo" is silently
taken as zero and "size=99999999999999999999" as ULONG_MAX truncated
to unsigned int. The checks for UINT_MAX that follow only catch the
truncated overflow case on a 32 bit build.
A zero packet size was accepted, and the value is later cast to the
16 bit mbuf data length, so anything above 65535 was silently
truncated. Convert with an explicit 1..UINT16_MAX range instead.
The copy and no-rx arguments are booleans, so store them as bool and
use rte_kvargs_handle_bool. This also means they now accept the word
forms such as "copy=on", not only 0 and 1.
While here, set an error code when copy and no-rx are both given.
The error was logged but the zero return from the last successful
rte_kvargs_process() was returned, so probe reported success without
ever creating the device.
The booleans use rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
doc/guides/nics/null.rst | 2 +-
drivers/net/null/rte_eth_null.c | 78 ++++++++++-----------------------
2 files changed, 24 insertions(+), 56 deletions(-)
diff --git a/doc/guides/nics/null.rst b/doc/guides/nics/null.rst
index c0e3199102..fd8d685d83 100644
--- a/doc/guides/nics/null.rst
+++ b/doc/guides/nics/null.rst
@@ -30,7 +30,7 @@ Runtime Configuration
- ``size`` [optional, default=64 bytes]
- Custom packet length value to use.r
+ Custom packet length value to use, from 1 to 65535.
If ``copy`` is enabled, this is the length of copy operation.
.. code-block:: console
diff --git a/drivers/net/null/rte_eth_null.c b/drivers/net/null/rte_eth_null.c
index 7fba3a661b..60f6f7d799 100644
--- a/drivers/net/null/rte_eth_null.c
+++ b/drivers/net/null/rte_eth_null.c
@@ -3,7 +3,8 @@
* All rights reserved.
*/
-#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <rte_mbuf.h>
#include <ethdev_driver.h>
@@ -19,8 +20,8 @@
#define ETH_NULL_PACKET_NO_RX_ARG "no-rx"
static unsigned int default_packet_size = 64;
-static unsigned int default_packet_copy;
-static unsigned int default_no_rx;
+static bool default_packet_copy;
+static bool default_no_rx;
static const char *valid_arguments[] = {
ETH_NULL_PACKET_SIZE_ARG,
@@ -45,15 +46,15 @@ struct null_queue {
};
struct pmd_options {
- unsigned int packet_copy;
+ bool packet_copy;
unsigned int packet_size;
- unsigned int no_rx;
+ bool no_rx;
};
struct pmd_internals {
unsigned int packet_size;
- unsigned int packet_copy;
- unsigned int no_rx;
+ bool packet_copy;
+ bool no_rx;
uint16_t port_id;
struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
@@ -606,55 +607,22 @@ eth_dev_null_create(struct rte_vdev_device *dev, struct pmd_options *args)
return 0;
}
-static inline int
-get_packet_size_arg(const char *key __rte_unused,
- const char *value, void *extra_args)
-{
- const char *a = value;
- unsigned int *packet_size = extra_args;
-
- if ((value == NULL) || (extra_args == NULL))
- return -EINVAL;
-
- *packet_size = (unsigned int)strtoul(a, NULL, 0);
- if (*packet_size == UINT_MAX)
- return -1;
-
- return 0;
-}
-
-static inline int
-get_packet_copy_arg(const char *key __rte_unused,
- const char *value, void *extra_args)
-{
- const char *a = value;
- unsigned int *packet_copy = extra_args;
-
- if ((value == NULL) || (extra_args == NULL))
- return -EINVAL;
-
- *packet_copy = (unsigned int)strtoul(a, NULL, 0);
- if (*packet_copy == UINT_MAX)
- return -1;
-
- return 0;
-}
-
+/* Packet size is stored in a 16 bit mbuf data length, and must not be zero. */
static int
-get_packet_no_rx_arg(const char *key __rte_unused,
+get_packet_size_arg(const char *key __rte_unused,
const char *value, void *extra_args)
{
- const char *a = value;
- unsigned int no_rx;
+ uint64_t packet_size;
+ int ret;
- if (value == NULL || extra_args == NULL)
+ if (extra_args == NULL)
return -EINVAL;
- no_rx = (unsigned int)strtoul(a, NULL, 0);
- if (no_rx != 0 && no_rx != 1)
- return -1;
+ ret = rte_kvargs_to_uint(value, 1, UINT16_MAX, &packet_size);
+ if (ret < 0)
+ return ret;
- *(unsigned int *)extra_args = no_rx;
+ *(unsigned int *)extra_args = packet_size;
return 0;
}
@@ -714,16 +682,15 @@ rte_pmd_null_probe(struct rte_vdev_device *dev)
if (ret < 0)
goto free_kvlist;
-
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
ETH_NULL_PACKET_COPY_ARG,
- &get_packet_copy_arg, &args.packet_copy);
+ rte_kvargs_handle_bool, &args.packet_copy);
if (ret < 0)
goto free_kvlist;
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
ETH_NULL_PACKET_NO_RX_ARG,
- &get_packet_no_rx_arg, &args.no_rx);
+ rte_kvargs_handle_bool, &args.no_rx);
if (ret < 0)
goto free_kvlist;
@@ -732,11 +699,12 @@ rte_pmd_null_probe(struct rte_vdev_device *dev)
"Both %s and %s arguments at the same time not supported",
ETH_NULL_PACKET_COPY_ARG,
ETH_NULL_PACKET_NO_RX_ARG);
+ ret = -EINVAL;
goto free_kvlist;
}
}
- PMD_LOG(INFO, "Configure pmd_null: packet size is %d, "
+ PMD_LOG(INFO, "Configure pmd_null: packet size is %u, "
"packet copy is %s", args.packet_size,
args.packet_copy ? "enabled" : "disabled");
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 07/62] net/vhost: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (5 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 06/62] net/null: use kvargs numeric helpers Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 08/62] vdpa/ifc: " Stephen Hemminger
` (54 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Maxime Coquelin, Chenbo Xia, Yuanhan Liu
open_int() converts with strtoul() and checks errno without resetting
it first, so an unrelated earlier failure makes a valid value fail,
and an overflow which does not happen to produce USHRT_MAX is accepted.
The end pointer is not checked at all, so "queues=foo" is silently
taken as zero.
More seriously, open_int() stores through a uint16_t pointer, but seven
of its eight callers pass the address of an int. Only two bytes of a
four byte object are written; this happens to work on little endian
because the callers initialize the variable to zero first, but it is
wrong on big endian.
The queues argument is the only real number, and it keeps a handler of
its own so that the range is checked where it is parsed. The caller
tested "queues > RTE_MAX_QUEUES_PER_PORT" after the fact but left ret
at zero, so an out of range value skipped the rest of the parsing and
still returned success from probe. Bounding it in the handler to
1..RTE_MAX_QUEUES_PER_PORT makes it fail properly, and also rejects
"queues=0", which was accepted before and left the device with no
queues.
The rest are booleans, so store them as bool and use
rte_kvargs_handle_bool, which also gives them the word forms such as
"client=on". They are processed with rte_kvargs_process_opt(), so a
bare key with no value enables the option.
Bugzilla ID: 2039
Fixes: 39cac2adcad0 ("net/vhost: add client option")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/vhost/rte_eth_vhost.c | 69 ++++++++++++++++---------------
1 file changed, 35 insertions(+), 34 deletions(-)
diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
index 05940f2461..a3acdcabb4 100644
--- a/drivers/net/vhost/rte_eth_vhost.c
+++ b/drivers/net/vhost/rte_eth_vhost.c
@@ -1585,17 +1585,18 @@ open_iface(const char *key __rte_unused, const char *value, void *extra_args)
return 0;
}
-static inline int
-open_int(const char *key __rte_unused, const char *value, void *extra_args)
+static int
+open_queues(const char *key, const char *value, void *extra_args)
{
- uint16_t *n = extra_args;
+ uint64_t queues;
- if (value == NULL || extra_args == NULL)
+ if (rte_kvargs_to_uint(value, 1, RTE_MAX_QUEUES_PER_PORT, &queues) < 0) {
+ VHOST_LOG_LINE(ERR, "invalid %s, must be 1..%u", key,
+ RTE_MAX_QUEUES_PER_PORT);
return -EINVAL;
+ }
- *n = (uint16_t)strtoul(value, NULL, 0);
- if (*n == USHRT_MAX && errno == ERANGE)
- return -1;
+ *(uint16_t *)extra_args = queues;
return 0;
}
@@ -1609,13 +1610,13 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev)
uint16_t queues;
uint64_t flags = RTE_VHOST_USER_NET_STATS_ENABLE;
uint64_t disable_flags = 0;
- int client_mode = 0;
- int iommu_support = 0;
- int postcopy_support = 0;
- int tso = 0;
- int linear_buf = 0;
- int ext_buf = 0;
- int legacy_ol_flags = 0;
+ bool client_mode = false;
+ bool iommu_support = false;
+ bool postcopy_support = false;
+ bool tso = false;
+ bool linear_buf = false;
+ bool ext_buf = false;
+ bool legacy_ol_flags = false;
struct rte_eth_dev *eth_dev;
const char *name = rte_vdev_device_name(dev);
@@ -1653,16 +1654,16 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev)
if (rte_kvargs_count(kvlist, ETH_VHOST_QUEUES_ARG) == 1) {
ret = rte_kvargs_process(kvlist, ETH_VHOST_QUEUES_ARG,
- &open_int, &queues);
- if (ret < 0 || queues > RTE_MAX_QUEUES_PER_PORT)
+ &open_queues, &queues);
+ if (ret < 0)
goto out_free;
} else
queues = 1;
if (rte_kvargs_count(kvlist, ETH_VHOST_CLIENT_ARG) == 1) {
- ret = rte_kvargs_process(kvlist, ETH_VHOST_CLIENT_ARG,
- &open_int, &client_mode);
+ ret = rte_kvargs_process_opt(kvlist, ETH_VHOST_CLIENT_ARG,
+ rte_kvargs_handle_bool, &client_mode);
if (ret < 0)
goto out_free;
@@ -1671,8 +1672,8 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev)
}
if (rte_kvargs_count(kvlist, ETH_VHOST_IOMMU_SUPPORT) == 1) {
- ret = rte_kvargs_process(kvlist, ETH_VHOST_IOMMU_SUPPORT,
- &open_int, &iommu_support);
+ ret = rte_kvargs_process_opt(kvlist, ETH_VHOST_IOMMU_SUPPORT,
+ rte_kvargs_handle_bool, &iommu_support);
if (ret < 0)
goto out_free;
@@ -1681,8 +1682,8 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev)
}
if (rte_kvargs_count(kvlist, ETH_VHOST_POSTCOPY_SUPPORT) == 1) {
- ret = rte_kvargs_process(kvlist, ETH_VHOST_POSTCOPY_SUPPORT,
- &open_int, &postcopy_support);
+ ret = rte_kvargs_process_opt(kvlist, ETH_VHOST_POSTCOPY_SUPPORT,
+ rte_kvargs_handle_bool, &postcopy_support);
if (ret < 0)
goto out_free;
@@ -1691,49 +1692,49 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev)
}
if (rte_kvargs_count(kvlist, ETH_VHOST_VIRTIO_NET_F_HOST_TSO) == 1) {
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
ETH_VHOST_VIRTIO_NET_F_HOST_TSO,
- &open_int, &tso);
+ rte_kvargs_handle_bool, &tso);
if (ret < 0)
goto out_free;
}
- if (tso == 0) {
+ if (!tso) {
disable_flags |= (1ULL << VIRTIO_NET_F_HOST_TSO4);
disable_flags |= (1ULL << VIRTIO_NET_F_HOST_TSO6);
}
if (rte_kvargs_count(kvlist, ETH_VHOST_LINEAR_BUF) == 1) {
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
ETH_VHOST_LINEAR_BUF,
- &open_int, &linear_buf);
+ rte_kvargs_handle_bool, &linear_buf);
if (ret < 0)
goto out_free;
- if (linear_buf == 1)
+ if (linear_buf)
flags |= RTE_VHOST_USER_LINEARBUF_SUPPORT;
}
if (rte_kvargs_count(kvlist, ETH_VHOST_EXT_BUF) == 1) {
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
ETH_VHOST_EXT_BUF,
- &open_int, &ext_buf);
+ rte_kvargs_handle_bool, &ext_buf);
if (ret < 0)
goto out_free;
- if (ext_buf == 1)
+ if (ext_buf)
flags |= RTE_VHOST_USER_EXTBUF_SUPPORT;
}
if (rte_kvargs_count(kvlist, ETH_VHOST_LEGACY_OL_FLAGS) == 1) {
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
ETH_VHOST_LEGACY_OL_FLAGS,
- &open_int, &legacy_ol_flags);
+ rte_kvargs_handle_bool, &legacy_ol_flags);
if (ret < 0)
goto out_free;
}
- if (legacy_ol_flags == 0)
+ if (!legacy_ol_flags)
flags |= RTE_VHOST_USER_NET_COMPLIANT_OL_FLAGS;
if (dev->device.numa_node == SOCKET_ID_ANY)
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 08/62] vdpa/ifc: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (6 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 07/62] net/vhost: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 09/62] net/softnic: " Stephen Hemminger
` (53 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Maxime Coquelin, Xiao Wang
open_int() stores through a uint16_t pointer but both callers pass the
address of an int, so only two bytes of a four byte object are written.
It also checks errno without resetting it first, and never checks the
end pointer, so "vdpa=foo" is silently taken as zero.
Both arguments are used as booleans, so store them as bool and use
rte_kvargs_handle_bool.
The booleans use rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Bugzilla ID: 2040
Fixes: 40ef35f4a504 ("net/ifc: detect if VDPA mode is specified")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/vdpa/ifc/ifcvf_vdpa.c | 29 +++++++----------------------
1 file changed, 7 insertions(+), 22 deletions(-)
diff --git a/drivers/vdpa/ifc/ifcvf_vdpa.c b/drivers/vdpa/ifc/ifcvf_vdpa.c
index f319d455ba..1381f7cc9a 100644
--- a/drivers/vdpa/ifc/ifcvf_vdpa.c
+++ b/drivers/vdpa/ifc/ifcvf_vdpa.c
@@ -1480,21 +1480,6 @@ static struct rte_vdpa_dev_ops ifcvf_net_ops = {
.get_dev_type = ifcvf_get_device_type,
};
-static inline int
-open_int(const char *key __rte_unused, const char *value, void *extra_args)
-{
- uint16_t *n = extra_args;
-
- if (value == NULL || extra_args == NULL)
- return -EINVAL;
-
- *n = (uint16_t)strtoul(value, NULL, 0);
- if (*n == USHRT_MAX && errno == ERANGE)
- return -1;
-
- return 0;
-}
-
static int16_t
ifcvf_pci_get_device_type(struct rte_pci_device *pci_dev)
{
@@ -1635,8 +1620,8 @@ ifcvf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
uint64_t features;
struct ifcvf_internal *internal = NULL;
struct internal_list *list = NULL;
- int vdpa_mode = 0;
- int sw_fallback_lm = 0;
+ bool vdpa_mode = false;
+ bool sw_fallback_lm = false;
struct rte_kvargs *kvlist = NULL;
int ret = 0;
int16_t device_id;
@@ -1662,9 +1647,9 @@ ifcvf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
return 1;
}
- ret = rte_kvargs_process(kvlist, IFCVF_VDPA_MODE, &open_int,
- &vdpa_mode);
- if (ret < 0 || vdpa_mode == 0) {
+ ret = rte_kvargs_process_opt(kvlist, IFCVF_VDPA_MODE,
+ rte_kvargs_handle_bool, &vdpa_mode);
+ if (ret < 0 || !vdpa_mode) {
rte_kvargs_free(kvlist);
return 1;
}
@@ -1756,8 +1741,8 @@ ifcvf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
list->internal = internal;
if (rte_kvargs_count(kvlist, IFCVF_SW_FALLBACK_LM)) {
- ret = rte_kvargs_process(kvlist, IFCVF_SW_FALLBACK_LM,
- &open_int, &sw_fallback_lm);
+ ret = rte_kvargs_process_opt(kvlist, IFCVF_SW_FALLBACK_LM,
+ rte_kvargs_handle_bool, &sw_fallback_lm);
if (ret < 0)
goto error;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 09/62] net/softnic: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (7 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 08/62] vdpa/ifc: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 10/62] dma/skeleton: " Stephen Hemminger
` (52 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Cristian Dumitrescu
get_uint32() and get_uint16() check neither errno nor the end pointer,
so a malformed value is silently taken as zero and an out of range one
is truncated into the target.
The service cores argument is only ever tested for truth, so make it a
bool. It was declared int but written through a uint32_t pointer.
The boolean uses rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/softnic/rte_eth_softnic.c | 30 +++----------------
.../net/softnic/rte_eth_softnic_internals.h | 3 +-
2 files changed, 6 insertions(+), 27 deletions(-)
diff --git a/drivers/net/softnic/rte_eth_softnic.c b/drivers/net/softnic/rte_eth_softnic.c
index 868e194509..81688d1dcf 100644
--- a/drivers/net/softnic/rte_eth_softnic.c
+++ b/drivers/net/softnic/rte_eth_softnic.c
@@ -344,28 +344,6 @@ get_string(const char *key __rte_unused, const char *value, void *extra_args)
return 0;
}
-static int
-get_uint32(const char *key __rte_unused, const char *value, void *extra_args)
-{
- if (!value || !extra_args)
- return -EINVAL;
-
- *(uint32_t *)extra_args = strtoull(value, NULL, 0);
-
- return 0;
-}
-
-static int
-get_uint16(const char *key __rte_unused, const char *value, void *extra_args)
-{
- if (!value || !extra_args)
- return -EINVAL;
-
- *(uint16_t *)extra_args = strtoull(value, NULL, 0);
-
- return 0;
-}
-
static int
pmd_parse_args(struct pmd_params *p, const char *params)
{
@@ -412,7 +390,7 @@ pmd_parse_args(struct pmd_params *p, const char *params)
/* Connection listening port (optional) */
if (rte_kvargs_count(kvlist, PMD_PARAM_CONN_PORT) == 1) {
ret = rte_kvargs_process(kvlist, PMD_PARAM_CONN_PORT,
- &get_uint16, &p->conn_port);
+ rte_kvargs_handle_u16, &p->conn_port);
if (ret < 0)
goto out_free;
}
@@ -420,15 +398,15 @@ pmd_parse_args(struct pmd_params *p, const char *params)
/* CPU ID (optional) */
if (rte_kvargs_count(kvlist, PMD_PARAM_CPU_ID) == 1) {
ret = rte_kvargs_process(kvlist, PMD_PARAM_CPU_ID,
- &get_uint32, &p->cpu_id);
+ rte_kvargs_handle_u32, &p->cpu_id);
if (ret < 0)
goto out_free;
}
/* Service cores (optional) */
if (rte_kvargs_count(kvlist, PMD_PARAM_SC) == 1) {
- ret = rte_kvargs_process(kvlist, PMD_PARAM_SC,
- &get_uint32, &p->sc);
+ ret = rte_kvargs_process_opt(kvlist, PMD_PARAM_SC,
+ rte_kvargs_handle_bool, &p->sc);
if (ret < 0)
goto out_free;
}
diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index d3975dad10..a1f309afb1 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -5,6 +5,7 @@
#ifndef __INCLUDE_RTE_ETH_SOFTNIC_INTERNALS_H__
#define __INCLUDE_RTE_ETH_SOFTNIC_INTERNALS_H__
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/queue.h>
@@ -34,7 +35,7 @@ struct pmd_params {
char firmware[SOFTNIC_PATH_MAX];
uint16_t conn_port;
uint32_t cpu_id;
- int sc; /**< Service cores. */
+ bool sc; /**< Service cores. */
};
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 10/62] dma/skeleton: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (8 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 09/62] net/softnic: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 11/62] raw/skeleton: " Stephen Hemminger
` (51 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Chengwen Feng, Kevin Laatz, Bruce Richardson
The lcore argument is converted with atoi(), which validates nothing:
a malformed value such as "abc" becomes zero, and the range check that
follows only catches a value which happens to land outside it.
Use rte_kvargs_to_int() with the lcore range, and log the key and the
range when it does not fit.
The parsing function returns void and probe does not fail on a bad
argument, which is left alone here: an unusable lcore still falls back
to the default. Only the "Parse lcore_id" message is now skipped when
the conversion failed, since it reported a value which had not been
parsed at all.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/dma/skeleton/skeleton_dmadev.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/skeleton/skeleton_dmadev.c b/drivers/dma/skeleton/skeleton_dmadev.c
index e287802eb9..44158d5a7f 100644
--- a/drivers/dma/skeleton/skeleton_dmadev.c
+++ b/drivers/dma/skeleton/skeleton_dmadev.c
@@ -638,19 +638,24 @@ skeldma_destroy(const char *name)
}
static int
-skeldma_parse_lcore(const char *key __rte_unused,
+skeldma_parse_lcore(const char *key,
const char *value,
void *opaque)
{
- int lcore_id;
+ int64_t lcore_id;
+ int ret;
- if (value == NULL || opaque == NULL)
+ if (opaque == NULL)
return -EINVAL;
- lcore_id = atoi(value);
- if (lcore_id >= 0 && lcore_id < RTE_MAX_LCORE)
- *(int *)opaque = lcore_id;
+ ret = rte_kvargs_to_int(value, 0, RTE_MAX_LCORE - 1, &lcore_id);
+ if (ret < 0) {
+ SKELDMA_LOG(ERR, "Invalid %s, must be 0..%u", key,
+ RTE_MAX_LCORE - 1);
+ return ret;
+ }
+ *(int *)opaque = lcore_id;
return 0;
}
@@ -673,9 +678,9 @@ skeldma_parse_vdev_args(struct rte_vdev_device *vdev, int *lcore_id)
if (!kvlist)
return;
- (void)rte_kvargs_process(kvlist, SKELDMA_ARG_LCORE,
- skeldma_parse_lcore, lcore_id);
- SKELDMA_LOG(INFO, "Parse lcore_id = %d", *lcore_id);
+ if (rte_kvargs_process(kvlist, SKELDMA_ARG_LCORE,
+ skeldma_parse_lcore, lcore_id) == 0)
+ SKELDMA_LOG(INFO, "Parse lcore_id = %d", *lcore_id);
rte_kvargs_free(kvlist);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 11/62] raw/skeleton: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (9 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 10/62] dma/skeleton: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 12/62] baseband/null: " Stephen Hemminger
` (50 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Sachin Saxena, Hemant Agrawal
The selftest argument is converted with atoi(), so a malformed value is
silently taken as zero. Make it a bool and use rte_kvargs_handle_bool,
which rejects anything which is not a recognized boolean and removes
the need for the separate range check on the result.
The boolean uses rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/raw/skeleton/skeleton_rawdev.c | 20 ++++----------------
1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/drivers/raw/skeleton/skeleton_rawdev.c b/drivers/raw/skeleton/skeleton_rawdev.c
index 6e99d35536..4e20952e47 100644
--- a/drivers/raw/skeleton/skeleton_rawdev.c
+++ b/drivers/raw/skeleton/skeleton_rawdev.c
@@ -658,22 +658,10 @@ skeleton_rawdev_destroy(const char *name)
return 0;
}
-static int
-skeldev_get_selftest(const char *key __rte_unused,
- const char *value,
- void *opaque)
-{
- int *flag = opaque;
- if (value == NULL || opaque == NULL)
- return -EINVAL;
- *flag = atoi(value);
- return 0;
-}
-
static int
skeldev_parse_vdev_args(struct rte_vdev_device *vdev)
{
- int selftest = 0;
+ bool selftest = false;
const char *name;
const char *params;
@@ -693,10 +681,10 @@ skeldev_parse_vdev_args(struct rte_vdev_device *vdev)
"Ignoring unsupported params supplied '%s'",
name);
} else {
- int ret = rte_kvargs_process(kvlist,
+ int ret = rte_kvargs_process_opt(kvlist,
SKELETON_SELFTEST_ARG,
- skeldev_get_selftest, &selftest);
- if (ret != 0 || (selftest < 0 || selftest > 1)) {
+ rte_kvargs_handle_bool, &selftest);
+ if (ret != 0) {
SKELETON_PMD_ERR("%s: Error in parsing args",
name);
rte_kvargs_free(kvlist);
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 12/62] baseband/null: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (10 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 11/62] raw/skeleton: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 13/62] net/memif: " Stephen Hemminger
` (49 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Nicolas Chautru, Ferruh Yigit, Amr Mokhtar
parse_u16_arg() does not check the end pointer, so "max_nb_queues=foo"
is silently taken as zero.
It was used for socket_id as well, which is an int rather than a
uint16_t, so parsing it wrote only two of the four bytes. Use
rte_kvargs_handle_socket_id() for that argument.
As in turbo_sw, the open coded range check only tested the upper bound,
so a negative socket id was accepted. The helper checks both ends, so
the check is removed.
Bugzilla ID: 2041
Fixes: 7dc2b1589440 ("bb/null: add null base band device driver")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/baseband/null/bbdev_null.c | 29 ++---------------------------
1 file changed, 2 insertions(+), 27 deletions(-)
diff --git a/drivers/baseband/null/bbdev_null.c b/drivers/baseband/null/bbdev_null.c
index cfa1790126..fc23a84f32 100644
--- a/drivers/baseband/null/bbdev_null.c
+++ b/drivers/baseband/null/bbdev_null.c
@@ -202,25 +202,6 @@ dequeue_enc_ops(struct rte_bbdev_queue_data *q_data,
return nb_dequeued;
}
-/* Parse 16bit integer from string argument */
-static inline int
-parse_u16_arg(const char *key, const char *value, void *extra_args)
-{
- uint16_t *u16 = extra_args;
- unsigned int long result;
-
- if ((value == NULL) || (extra_args == NULL))
- return -EINVAL;
- errno = 0;
- result = strtoul(value, NULL, 0);
- if ((result >= (1 << 16)) || (errno != 0)) {
- rte_bbdev_log(ERR, "Invalid value %lu for %s", result, key);
- return -ERANGE;
- }
- *u16 = (uint16_t)result;
- return 0;
-}
-
/* Parse parameters used to create device */
static int
parse_bbdev_null_params(struct bbdev_null_params *params,
@@ -237,20 +218,14 @@ parse_bbdev_null_params(struct bbdev_null_params *params,
return -EFAULT;
ret = rte_kvargs_process(kvlist, bbdev_null_valid_params[0],
- &parse_u16_arg, ¶ms->queues_num);
+ rte_kvargs_handle_u16, ¶ms->queues_num);
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, bbdev_null_valid_params[1],
- &parse_u16_arg, ¶ms->socket_id);
+ rte_kvargs_handle_socket_id, ¶ms->socket_id);
if (ret < 0)
goto exit;
-
- if (params->socket_id >= RTE_MAX_NUMA_NODES) {
- rte_bbdev_log(ERR, "Invalid socket, must be < %u",
- RTE_MAX_NUMA_NODES);
- goto exit;
- }
}
exit:
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 13/62] net/memif: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (11 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 12/62] baseband/null: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 14/62] net/af_packet: " Stephen Hemminger
` (48 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Jakub Grajciar
memif_set_id() dereferences the value without checking it for NULL, so
"net_memif,id" with no value crashes. It then ignores the result of the
conversion entirely, with a comment noting that zero is a valid id, so
"id=foo" silently selects interface zero.
memif_set_bs() and memif_set_rs() check neither errno nor the end
pointer, so a malformed value is taken as zero and rejected with a
misleading message, while an overflowing one wraps into range.
memif_set_owner() is nearly correct but does not reset errno before
strtoul(), and rejects UINT32_MAX which is a valid uid.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/memif/rte_eth_memif.c | 73 ++++++++++++++-----------------
1 file changed, 34 insertions(+), 39 deletions(-)
diff --git a/drivers/net/memif/rte_eth_memif.c b/drivers/net/memif/rte_eth_memif.c
index 5d153c3a5a..807ff20e1b 100644
--- a/drivers/net/memif/rte_eth_memif.c
+++ b/drivers/net/memif/rte_eth_memif.c
@@ -1807,45 +1807,42 @@ memif_set_zc(const char *key __rte_unused, const char *value, void *extra_args)
return 0;
}
-static int
-memif_set_id(const char *key __rte_unused, const char *value, void *extra_args)
-{
- memif_interface_id_t *id = (memif_interface_id_t *)extra_args;
-
- /* even if parsing fails, 0 is a valid id */
- *id = strtoul(value, NULL, 10);
- return 0;
-}
-
static int
memif_set_bs(const char *key __rte_unused, const char *value, void *extra_args)
{
- unsigned long tmp;
- uint16_t *pkt_buffer_size = (uint16_t *)extra_args;
+ uint64_t tmp;
+ int ret;
- tmp = strtoul(value, NULL, 10);
- if (tmp == 0 || tmp > 0xFFFF) {
- MIF_LOG(ERR, "Invalid buffer size: %s.", value);
+ if (extra_args == NULL)
return -EINVAL;
+
+ ret = rte_kvargs_to_uint(value, 1, UINT16_MAX, &tmp);
+ if (ret < 0) {
+ MIF_LOG(ERR, "Invalid buffer size: %s.", value);
+ return ret;
}
- *pkt_buffer_size = tmp;
+
+ *(uint16_t *)extra_args = tmp;
return 0;
}
static int
memif_set_rs(const char *key __rte_unused, const char *value, void *extra_args)
{
- unsigned long tmp;
- memif_log2_ring_size_t *log2_ring_size =
- (memif_log2_ring_size_t *)extra_args;
+ uint64_t tmp;
+ int ret;
- tmp = strtoul(value, NULL, 10);
- if (tmp == 0 || tmp > ETH_MEMIF_MAX_LOG2_RING_SIZE) {
+ if (extra_args == NULL)
+ return -EINVAL;
+
+ ret = rte_kvargs_to_uint(value, 1, ETH_MEMIF_MAX_LOG2_RING_SIZE, &tmp);
+ if (ret < 0) {
MIF_LOG(ERR, "Invalid ring size: %s (max %u).",
value, ETH_MEMIF_MAX_LOG2_RING_SIZE);
- return -EINVAL;
+ return ret;
}
- *log2_ring_size = tmp;
+
+ *(memif_log2_ring_size_t *)extra_args = tmp;
return 0;
}
@@ -1917,21 +1914,19 @@ memif_set_owner(const char *key, const char *value, void *extra_args)
RTE_ASSERT(sizeof(uid_t) == sizeof(uint32_t));
RTE_ASSERT(sizeof(gid_t) == sizeof(uint32_t));
- unsigned long val;
- char *end = NULL;
- uint32_t *id = (uint32_t *)extra_args;
+ uint64_t val;
+ int ret;
- val = strtoul(value, &end, 10);
- if (*value == '\0' || *end != '\0') {
- MIF_LOG(ERR, "Failed to parse %s: %s.", key, value);
+ if (extra_args == NULL)
return -EINVAL;
- }
- if (val >= UINT32_MAX) {
- MIF_LOG(ERR, "Invalid %s: %s.", key, value);
- return -ERANGE;
+
+ ret = rte_kvargs_to_uint(value, 0, UINT32_MAX, &val);
+ if (ret < 0) {
+ MIF_LOG(ERR, "Failed to parse %s: %s.", key, value);
+ return ret;
}
- *id = val;
+ *(uint32_t *)extra_args = val;
return 0;
}
@@ -2032,15 +2027,15 @@ rte_pmd_memif_probe(struct rte_vdev_device *vdev)
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, ETH_MEMIF_ID_ARG,
- &memif_set_id, &id);
+ rte_kvargs_handle_u32, &id);
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, ETH_MEMIF_PKT_BUFFER_SIZE_ARG,
- &memif_set_bs, &pkt_buffer_size);
+ memif_set_bs, &pkt_buffer_size);
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, ETH_MEMIF_RING_SIZE_ARG,
- &memif_set_rs, &log2_ring_size);
+ memif_set_rs, &log2_ring_size);
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, ETH_MEMIF_SOCKET_ARG,
@@ -2053,11 +2048,11 @@ rte_pmd_memif_probe(struct rte_vdev_device *vdev)
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, ETH_MEMIF_OWNER_UID_ARG,
- &memif_set_owner, &owner_uid);
+ memif_set_owner, &owner_uid);
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, ETH_MEMIF_OWNER_GID_ARG,
- &memif_set_owner, &owner_gid);
+ memif_set_owner, &owner_gid);
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, ETH_MEMIF_MAC_ARG,
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 14/62] net/af_packet: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (12 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 13/62] net/memif: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 15/62] net/pcap: " Stephen Hemminger
` (47 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
The open coded parse_uint() is correct, but the same checks are now
available from kvargs. Use them, and express the lower bound as part of
the range rather than as a separate test after each call.
qdisc_bypass is a boolean, so parse it with rte_kvargs_handle_bool()
into a bool. A bare "qdisc_bypass" with no value now enables it, which
the manual pair loop here supports without any further change.
Note that the qdisc_bypass parameter of rte_pmd_init_internals() stays
an unsigned int: its address is passed to setsockopt(), which expects a
four byte int.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/af_packet/rte_eth_af_packet.c | 72 +++++------------------
1 file changed, 16 insertions(+), 56 deletions(-)
diff --git a/drivers/net/af_packet/rte_eth_af_packet.c b/drivers/net/af_packet/rte_eth_af_packet.c
index b0ff22ea55..8de4705744 100644
--- a/drivers/net/af_packet/rte_eth_af_packet.c
+++ b/drivers/net/af_packet/rte_eth_af_packet.c
@@ -15,7 +15,6 @@
#include <rte_kvargs.h>
#include <bus_vdev_driver.h>
-#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <linux/if_ether.h>
@@ -1143,36 +1142,17 @@ rte_pmd_init_internals(struct rte_vdev_device *dev,
/* Parse an unsigned integer device argument. */
static int
parse_uint(const char *key, const char *value,
- unsigned int *out, unsigned long limit)
+ unsigned int *out, unsigned long min, unsigned long max)
{
- unsigned long val;
- char *endptr;
+ uint64_t val;
- if (value == NULL) {
- PMD_LOG(ERR, "no value for argument \"%s\"", key);
- return -1;
- }
-
- /* Skip leading whitespace so a leading sign can be detected. */
- while (isspace((unsigned char)*value))
- value++;
-
- /* strtoul() silently accepts and negates a leading '-'. */
- if (*value == '\0' || *value == '-') {
- PMD_LOG(ERR, "invalid value \"%s\" for argument \"%s\"",
- value, key);
- return -1;
- }
-
- errno = 0;
- val = strtoul(value, &endptr, 10);
- if (errno != 0 || *endptr != '\0' || val > limit) {
+ if (rte_kvargs_to_uint(value, min, max, &val) < 0) {
PMD_LOG(ERR, "invalid value \"%s\" for argument \"%s\"",
- value, key);
+ value == NULL ? "" : value, key);
return -1;
}
- *out = (unsigned int)val;
+ *out = val;
return 0;
}
@@ -1191,7 +1171,7 @@ rte_eth_from_packet(struct rte_vdev_device *dev,
unsigned int framesize = DFLT_FRAME_SIZE;
unsigned int framecount = DFLT_FRAME_COUNT;
unsigned int qpairs = 1;
- unsigned int qdisc_bypass = 1;
+ bool qdisc_bypass = true;
const char *fanout_mode = NULL;
/* do some parameter checking */
@@ -1206,52 +1186,32 @@ rte_eth_from_packet(struct rte_vdev_device *dev,
for (k_idx = 0; k_idx < kvlist->count; k_idx++) {
pair = &kvlist->pairs[k_idx];
if (strstr(pair->key, ETH_AF_PACKET_NUM_Q_ARG) != NULL) {
- if (parse_uint(pair->key, pair->value,
- &qpairs, RTE_MAX_QUEUES_PER_PORT) < 0)
+ if (parse_uint(pair->key, pair->value, &qpairs,
+ 1, RTE_MAX_QUEUES_PER_PORT) < 0)
return -1;
- if (qpairs < 1) {
- PMD_LOG(ERR,
- "%s: invalid qpairs value",
- name);
- return -1;
- }
continue;
}
if (strstr(pair->key, ETH_AF_PACKET_BLOCKSIZE_ARG) != NULL) {
- if (parse_uint(pair->key, pair->value, &blocksize, UINT_MAX) < 0)
+ if (parse_uint(pair->key, pair->value, &blocksize,
+ 1, UINT_MAX) < 0)
return -1;
- if (!blocksize) {
- PMD_LOG(ERR,
- "%s: invalid blocksize value",
- name);
- return -1;
- }
continue;
}
if (strstr(pair->key, ETH_AF_PACKET_FRAMESIZE_ARG) != NULL) {
- if (parse_uint(pair->key, pair->value, &framesize, UINT_MAX) < 0)
+ if (parse_uint(pair->key, pair->value, &framesize,
+ 1, UINT_MAX) < 0)
return -1;
- if (!framesize) {
- PMD_LOG(ERR,
- "%s: invalid framesize value",
- name);
- return -1;
- }
continue;
}
if (strstr(pair->key, ETH_AF_PACKET_FRAMECOUNT_ARG) != NULL) {
- if (parse_uint(pair->key, pair->value, &framecount, UINT_MAX) < 0)
+ if (parse_uint(pair->key, pair->value, &framecount,
+ 1, UINT_MAX) < 0)
return -1;
- if (!framecount) {
- PMD_LOG(ERR,
- "%s: invalid framecount value",
- name);
- return -1;
- }
continue;
}
if (strstr(pair->key, ETH_AF_PACKET_QDISC_BYPASS_ARG) != NULL) {
- if (parse_uint(pair->key, pair->value, &qdisc_bypass, 1) < 0)
+ if (rte_kvargs_handle_bool(pair->key, pair->value,
+ &qdisc_bypass) < 0)
return -1;
continue;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 15/62] net/pcap: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (13 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 14/62] net/af_packet: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 16/62] net/ring: " Stephen Hemminger
` (46 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
The open coded conversion is correct, but the same checks are now
available from kvargs.
process_bool_flag() duplicated what rte_kvargs_handle_bool() does, so
drop it and use the helper for phy_mac, infinite_rx and eof. The
process_opt() form newly enables the bare "infinite_rx" spelling: the
value == NULL branch of process_bool_flag() was dead, since
rte_kvargs_process() rejects a missing value before the handler runs.
The usual words such as "on" and "true" are now accepted as well,
while an empty "infinite_rx=" is rejected rather than taken as true.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/pcap/pcap_ethdev.c | 51 ++++++++--------------------------
1 file changed, 12 insertions(+), 39 deletions(-)
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 08d3ab9e91..b262498f7d 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -1586,46 +1586,19 @@ open_tx_iface(const char *key, const char *value, void *extra_args)
return open_iface(key, value, extra_args);
}
-static int
-process_bool_flag(const char *key, const char *value, void *extra_args)
-{
- bool *flag = extra_args;
-
- if (value == NULL || *value == '\0') {
- *flag = true; /* default with no additional argument */
- } else if (strcmp(value, "0") == 0) {
- *flag = false;
- } else if (strcmp(value, "1") == 0) {
- *flag = true;
- } else {
- PMD_LOG(ERR, "Invalid '%s' value '%s'", key, value);
- return -1;
- }
- return 0;
-}
-
static int
process_snapshot_len(const char *key, const char *value, void *extra_args)
{
- uint32_t *snaplen = extra_args;
- unsigned long val;
- char *endptr;
-
- if (value == NULL || *value == '\0') {
- PMD_LOG(ERR, "Argument '%s' requires a value", key);
- return -1;
- }
+ uint64_t val;
- errno = 0;
- val = strtoul(value, &endptr, 10);
- if (errno != 0 || *endptr != '\0' ||
- val < RTE_ETHER_HDR_LEN ||
- val > ETH_PCAP_MAXIMUM_SNAPLEN) {
- PMD_LOG(ERR, "Invalid '%s' value '%s'", key, value);
+ if (rte_kvargs_to_uint(value, RTE_ETHER_HDR_LEN,
+ ETH_PCAP_MAXIMUM_SNAPLEN, &val) < 0) {
+ PMD_LOG(ERR, "Invalid '%s' value '%s'", key,
+ value == NULL ? "" : value);
return -1;
}
- *snaplen = (uint32_t)val;
+ *(uint32_t *)extra_args = val;
return 0;
}
@@ -1934,8 +1907,8 @@ pmd_pcap_probe(struct rte_vdev_device *dev)
dumpers.queue[0] = pcaps.queue[0];
- ret = rte_kvargs_process(kvlist, ETH_PCAP_PHY_MAC_ARG,
- &process_bool_flag, &pcaps.phy_mac);
+ ret = rte_kvargs_process_opt(kvlist, ETH_PCAP_PHY_MAC_ARG,
+ rte_kvargs_handle_bool, &pcaps.phy_mac);
if (ret < 0)
goto free_kvlist;
@@ -1973,9 +1946,9 @@ pmd_pcap_probe(struct rte_vdev_device *dev)
ETH_PCAP_INFINITE_RX_ARG);
if (infinite_rx_arg_cnt == 1) {
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
ETH_PCAP_INFINITE_RX_ARG,
- &process_bool_flag,
+ rte_kvargs_handle_bool,
&devargs_all.infinite_rx);
if (ret < 0)
goto free_kvlist;
@@ -1993,8 +1966,8 @@ pmd_pcap_probe(struct rte_vdev_device *dev)
* Check whether to signal EOF via link status change.
*/
if (rte_kvargs_count(kvlist, ETH_PCAP_EOF_ARG) == 1) {
- ret = rte_kvargs_process(kvlist, ETH_PCAP_EOF_ARG,
- &process_bool_flag,
+ ret = rte_kvargs_process_opt(kvlist, ETH_PCAP_EOF_ARG,
+ rte_kvargs_handle_bool,
&devargs_all.eof);
if (ret < 0)
goto free_kvlist;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 16/62] net/ring: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (14 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 15/62] net/pcap: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 17/62] net/af_xdp: " Stephen Hemminger
` (45 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson
The node number is stored in an unsigned int but converted with
strtol(), so a negative value such as "node:-1:CREATE" was accepted and
wrapped around.
The value is also passed to strdup() without being checked for NULL, so
a key given with no value crashes. Check it first, and report an
allocation failure as such instead of reusing the empty parameter
message.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/ring/rte_eth_ring.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ring/rte_eth_ring.c b/drivers/net/ring/rte_eth_ring.c
index b639544eab..3a1040305d 100644
--- a/drivers/net/ring/rte_eth_ring.c
+++ b/drivers/net/ring/rte_eth_ring.c
@@ -2,6 +2,7 @@
* Copyright(c) 2010-2015 Intel Corporation
*/
+#include <limits.h>
#include <stdlib.h>
#include <eal_export.h>
@@ -583,21 +584,25 @@ static int parse_kvlist(const char *key __rte_unused,
const char *value, void *data)
{
struct node_action_list *info = data;
+ uint64_t node_val;
int ret;
- char *name;
+ char *name = NULL;
char *action;
char *node;
- char *end;
-
- name = strdup(value);
ret = -EINVAL;
- if (!name) {
+ if (value == NULL) {
PMD_LOG(WARNING, "command line parameter is empty for ring pmd!");
goto out;
}
+ name = strdup(value);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
node = strchr(name, ':');
if (!node) {
PMD_LOG(WARNING, "could not parse node value from %s",
@@ -629,14 +634,12 @@ static int parse_kvlist(const char *key __rte_unused,
else
goto out;
- errno = 0;
- info->list[info->count].node = strtol(node, &end, 10);
-
- if ((errno != 0) || (*end != '\0')) {
+ if (rte_kvargs_to_uint(node, 0, UINT_MAX, &node_val) < 0) {
PMD_LOG(WARNING,
"node value %s is unparseable as a number", node);
goto out;
}
+ info->list[info->count].node = node_val;
strlcpy(info->list[info->count].name, name,
sizeof(info->list[info->count].name));
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 17/62] net/af_xdp: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (15 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 16/62] net/ring: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 18/62] net/ark: " Stephen Hemminger
` (44 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Ciara Loftus, Maryam Tahhan
parse_integer_arg() and parse_budget_arg() do not check the end pointer
or errno, so "start_queue=foo" is silently taken as zero, and they store
the unvalidated result before testing it, so a rejected argument still
overwrites the caller's default.
The shared_umem, force_copy, use_cni and use_pinned_map arguments are
booleans, and are already stored as bool in the internals, so parse them
as bool rather than as int.
The booleans use rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/af_xdp/rte_eth_af_xdp.c | 68 +++++++++++++++++------------
1 file changed, 39 insertions(+), 29 deletions(-)
diff --git a/drivers/net/af_xdp/rte_eth_af_xdp.c b/drivers/net/af_xdp/rte_eth_af_xdp.c
index 2cdb533276..30739d07bc 100644
--- a/drivers/net/af_xdp/rte_eth_af_xdp.c
+++ b/drivers/net/af_xdp/rte_eth_af_xdp.c
@@ -3,6 +3,8 @@
*/
#include <unistd.h>
#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
@@ -2002,16 +2004,20 @@ static int
parse_budget_arg(const char *key __rte_unused,
const char *value, void *extra_args)
{
- int *i = (int *)extra_args;
- char *end;
+ int64_t val;
+ int ret;
- *i = strtol(value, &end, 10);
- if (*i < 0 || *i > UINT16_MAX) {
- AF_XDP_LOG_LINE(ERR, "Invalid busy_budget %i, must be >= 0 and <= %u",
- *i, UINT16_MAX);
+ if (extra_args == NULL)
return -EINVAL;
+
+ ret = rte_kvargs_to_int(value, 0, UINT16_MAX, &val);
+ if (ret < 0) {
+ AF_XDP_LOG_LINE(ERR, "Invalid busy_budget %s, must be >= 0 and <= %u",
+ value == NULL ? "" : value, UINT16_MAX);
+ return ret;
}
+ *(int *)extra_args = val;
return 0;
}
@@ -2020,15 +2026,19 @@ static int
parse_integer_arg(const char *key __rte_unused,
const char *value, void *extra_args)
{
- int *i = (int *)extra_args;
- char *end;
+ int64_t val;
+ int ret;
- *i = strtol(value, &end, 10);
- if (*i < 0) {
- AF_XDP_LOG_LINE(ERR, "Argument has to be positive.");
+ if (extra_args == NULL)
return -EINVAL;
+
+ ret = rte_kvargs_to_int(value, 0, INT_MAX, &val);
+ if (ret < 0) {
+ AF_XDP_LOG_LINE(ERR, "Argument has to be positive.");
+ return ret;
}
+ *(int *)extra_args = val;
return 0;
}
@@ -2144,9 +2154,9 @@ xdp_get_channels_info(const char *if_name, int *max_queues,
static int
parse_parameters(struct rte_kvargs *kvlist, char *if_name, int *start_queue,
- int *queue_cnt, int *shared_umem, char *prog_path,
- int *busy_budget, int *force_copy, int *use_cni,
- int *use_pinned_map, char *dp_path, uint32_t *xdp_mode)
+ int *queue_cnt, bool *shared_umem, char *prog_path,
+ int *busy_budget, bool *force_copy, bool *use_cni,
+ bool *use_pinned_map, char *dp_path, uint32_t *xdp_mode)
{
int ret;
@@ -2167,8 +2177,8 @@ parse_parameters(struct rte_kvargs *kvlist, char *if_name, int *start_queue,
goto free_kvlist;
}
- ret = rte_kvargs_process(kvlist, ETH_AF_XDP_SHARED_UMEM_ARG,
- &parse_integer_arg, shared_umem);
+ ret = rte_kvargs_process_opt(kvlist, ETH_AF_XDP_SHARED_UMEM_ARG,
+ rte_kvargs_handle_bool, shared_umem);
if (ret < 0)
goto free_kvlist;
@@ -2182,18 +2192,18 @@ parse_parameters(struct rte_kvargs *kvlist, char *if_name, int *start_queue,
if (ret < 0)
goto free_kvlist;
- ret = rte_kvargs_process(kvlist, ETH_AF_XDP_FORCE_COPY_ARG,
- &parse_integer_arg, force_copy);
+ ret = rte_kvargs_process_opt(kvlist, ETH_AF_XDP_FORCE_COPY_ARG,
+ rte_kvargs_handle_bool, force_copy);
if (ret < 0)
goto free_kvlist;
- ret = rte_kvargs_process(kvlist, ETH_AF_XDP_USE_CNI_ARG,
- &parse_integer_arg, use_cni);
+ ret = rte_kvargs_process_opt(kvlist, ETH_AF_XDP_USE_CNI_ARG,
+ rte_kvargs_handle_bool, use_cni);
if (ret < 0)
goto free_kvlist;
- ret = rte_kvargs_process(kvlist, ETH_AF_XDP_USE_PINNED_MAP_ARG,
- &parse_integer_arg, use_pinned_map);
+ ret = rte_kvargs_process_opt(kvlist, ETH_AF_XDP_USE_PINNED_MAP_ARG,
+ rte_kvargs_handle_bool, use_pinned_map);
if (ret < 0)
goto free_kvlist;
@@ -2246,9 +2256,9 @@ get_iface_info(const char *if_name,
static struct rte_eth_dev *
init_internals(struct rte_vdev_device *dev, const char *if_name,
- int start_queue_idx, int queue_cnt, int shared_umem,
- const char *prog_path, int busy_budget, int force_copy,
- int use_cni, int use_pinned_map, const char *dp_path, uint32_t xdp_mode)
+ int start_queue_idx, int queue_cnt, bool shared_umem,
+ const char *prog_path, int busy_budget, bool force_copy,
+ bool use_cni, bool use_pinned_map, const char *dp_path, uint32_t xdp_mode)
{
const char *name = rte_vdev_device_name(dev);
const unsigned int numa_node = dev->device.numa_node;
@@ -2466,12 +2476,12 @@ rte_pmd_af_xdp_probe(struct rte_vdev_device *dev)
char if_name[IFNAMSIZ] = {'\0'};
int xsk_start_queue_idx = ETH_AF_XDP_DFLT_START_QUEUE_IDX;
int xsk_queue_cnt = ETH_AF_XDP_DFLT_QUEUE_COUNT;
- int shared_umem = 0;
+ bool shared_umem = false;
char prog_path[PATH_MAX] = {'\0'};
int busy_budget = -1, ret;
- int force_copy = 0;
- int use_cni = 0;
- int use_pinned_map = 0;
+ bool force_copy = false;
+ bool use_cni = false;
+ bool use_pinned_map = false;
uint32_t xdp_mode = 0;
char dp_path[PATH_MAX] = {'\0'};
struct rte_eth_dev *eth_dev = NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 18/62] net/ark: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (16 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 17/62] net/af_xdp: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 19/62] net/failsafe: " Stephen Hemminger
` (43 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Shepard Siegel, Ed Czeck, John Miller
The packet director argument is stored in a uint32_t but converted with
strtol() with no validation, so a malformed value is silently taken as
zero and a negative one wraps around. It is also converted through a
signed long, so on a 32-bit build a value above INT32_MAX saturates at
LONG_MAX rather than being stored.
It is documented as "Pkt_dir=0x00110F10" and read as base 16, so use
rte_kvargs_handle_hex32(), which keeps hexadecimal with or without the
0x prefix and validates the whole string. Both the documented form and a
bare "00110F10" are unchanged.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/ark/ark_ethdev.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ark/ark_ethdev.c b/drivers/net/ark/ark_ethdev.c
index 9272e271e6..8810b02849 100644
--- a/drivers/net/ark/ark_ethdev.c
+++ b/drivers/net/ark/ark_ethdev.c
@@ -896,7 +896,9 @@ process_pktdir_arg(const char *key, const char *value,
struct ark_adapter *ark =
(struct ark_adapter *)extra_args;
- ark->pkt_dir_v = strtol(value, NULL, 16);
+ if (rte_kvargs_handle_hex32(key, value, &ark->pkt_dir_v) < 0)
+ return -EINVAL;
+
ARK_PMD_LOG(DEBUG, "pkt_dir_v = 0x%x\n", ark->pkt_dir_v);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 19/62] net/failsafe: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (17 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 18/62] net/ark: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 20/62] net/virtio: " Stephen Hemminger
` (42 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Gaetan Rivet
fs_get_u64_arg() returns -errno on failure, but errno is not reset
before strtoull(), so an unrelated earlier failure is reported. It also
accepts a value with trailing garbage, and base 0 means a leading zero
selects octal.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/failsafe/failsafe_args.c | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)
diff --git a/drivers/net/failsafe/failsafe_args.c b/drivers/net/failsafe/failsafe_args.c
index 1b8f1d3050..f256a9f6a0 100644
--- a/drivers/net/failsafe/failsafe_args.c
+++ b/drivers/net/failsafe/failsafe_args.c
@@ -345,24 +345,6 @@ fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
return 0;
}
-static int
-fs_get_u64_arg(const char *key __rte_unused,
- const char *value, void *out)
-{
- uint64_t *u64 = out;
- char *endptr = NULL;
-
- if ((value == NULL) || (out == NULL))
- return -EINVAL;
- errno = 0;
- *u64 = strtoull(value, &endptr, 0);
- if (errno != 0)
- return -errno;
- if (endptr == value)
- return -1;
- return 0;
-}
-
static int
fs_get_mac_addr_arg(const char *key __rte_unused,
const char *value, void *out)
@@ -416,7 +398,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
if (arg_count == 1) {
ret = rte_kvargs_process(kvlist,
PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
- &fs_get_u64_arg, &failsafe_hotplug_poll);
+ rte_kvargs_handle_u64, &failsafe_hotplug_poll);
if (ret < 0)
goto free_kvlist;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 20/62] net/virtio: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (18 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 19/62] net/failsafe: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 21/62] net/bonding: " Stephen Hemminger
` (41 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Maxime Coquelin, Chenbo Xia
get_integer_arg() checks only errno, so "queues=foo" was silently taken
as zero, and since the store is skipped on failure but zero is returned,
the argument was accepted while leaving the default in place. It also
uses base 0, so a leading zero selects octal.
link_speed_handler() checks neither errno nor the end pointer before
validating the result against the speed capabilities.
The boolean arguments become bool and use rte_kvargs_handle_bool():
server, cq, packed_vq, vectorized, mrg_rxbuf and in_order for
virtio_user, and vectorized for virtio. They are passed by value into
virtio_user_dev_init(), whose parameters stay int.
vectorized_check_handler() treated anything other than "1" as false, so
"vectorized=y" silently disabled it and a typo did the same. It is now
a boolean like the rest: the usual spellings work, a bare key enables
the option, and anything else is rejected instead of being read as
false.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/virtio/virtio_ethdev.c | 36 ++++++---------
drivers/net/virtio/virtio_user_ethdev.c | 59 +++++++++----------------
2 files changed, 34 insertions(+), 61 deletions(-)
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 9fd746b80f..83ea6745ce 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -47,7 +47,7 @@ static int virtio_dev_allmulticast_disable(struct rte_eth_dev *dev);
static uint32_t virtio_dev_speed_capa_get(uint32_t speed);
static int virtio_dev_devargs_parse(struct rte_devargs *devargs,
uint32_t *speed,
- int *vectorized);
+ bool *vectorized);
static int virtio_dev_info_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info);
static int virtio_dev_link_update(struct rte_eth_dev *dev,
@@ -2039,7 +2039,7 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
{
struct virtio_hw *hw = eth_dev->data->dev_private;
uint32_t speed = RTE_ETH_SPEED_NUM_UNKNOWN;
- int vectorized = 0;
+ bool vectorized = false;
int ret;
if (sizeof(struct virtio_net_hdr_hash_report) > RTE_PKTMBUF_HEADROOM) {
@@ -2138,20 +2138,6 @@ virtio_dev_speed_capa_get(uint32_t speed)
}
}
-static int vectorized_check_handler(__rte_unused const char *key,
- const char *value, void *ret_val)
-{
- if (value == NULL || ret_val == NULL)
- return -EINVAL;
-
- if (strcmp(value, "1") == 0)
- *(int *)ret_val = 1;
- else
- *(int *)ret_val = 0;
-
- return 0;
-}
-
#define VIRTIO_ARG_SPEED "speed"
#define VIRTIO_ARG_VECTORIZED "vectorized"
@@ -2159,21 +2145,25 @@ static int
link_speed_handler(const char *key __rte_unused,
const char *value, void *ret_val)
{
- uint32_t val;
- if (!value || !ret_val)
+ uint64_t val;
+
+ if (ret_val == NULL)
+ return -EINVAL;
+
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &val) < 0)
return -EINVAL;
- val = strtoul(value, NULL, 0);
+
/* validate input */
if (virtio_dev_speed_capa_get(val) == 0)
return -EINVAL;
- *(uint32_t *)ret_val = val;
+ *(uint32_t *)ret_val = val;
return 0;
}
static int
-virtio_dev_devargs_parse(struct rte_devargs *devargs, uint32_t *speed, int *vectorized)
+virtio_dev_devargs_parse(struct rte_devargs *devargs, uint32_t *speed, bool *vectorized)
{
struct rte_kvargs *kvlist;
int ret = 0;
@@ -2200,9 +2190,9 @@ virtio_dev_devargs_parse(struct rte_devargs *devargs, uint32_t *speed, int *vect
if (vectorized &&
rte_kvargs_count(kvlist, VIRTIO_ARG_VECTORIZED) == 1) {
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
VIRTIO_ARG_VECTORIZED,
- vectorized_check_handler, vectorized);
+ rte_kvargs_handle_bool, vectorized);
if (ret < 0) {
PMD_INIT_LOG(ERR, "Failed to parse %s",
VIRTIO_ARG_VECTORIZED);
diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c
index 747dddeb2e..4925924211 100644
--- a/drivers/net/virtio/virtio_user_ethdev.c
+++ b/drivers/net/virtio/virtio_user_ethdev.c
@@ -387,23 +387,6 @@ get_string_arg(const char *key __rte_unused,
return 0;
}
-static int
-get_integer_arg(const char *key __rte_unused,
- const char *value, void *extra_args)
-{
- uint64_t integer = 0;
- if (!value || !extra_args)
- return -EINVAL;
- errno = 0;
- integer = strtoull(value, NULL, 0);
- /* extra_args keeps default value, it should be replaced
- * only in case of successful parsing of the 'value' arg
- */
- if (errno == 0)
- *(uint64_t *)extra_args = integer;
- return -errno;
-}
-
static uint32_t
vdpa_dynamic_major_num(void)
{
@@ -508,13 +491,13 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
struct virtio_user_dev *dev;
enum virtio_user_backend_type backend_type = VIRTIO_USER_BACKEND_UNKNOWN;
uint64_t queues = VIRTIO_USER_DEF_Q_NUM;
- uint64_t cq = VIRTIO_USER_DEF_CQ_EN;
+ bool cq = VIRTIO_USER_DEF_CQ_EN;
uint64_t queue_size = VIRTIO_USER_DEF_Q_SZ;
- uint64_t server_mode = VIRTIO_USER_DEF_SERVER_MODE;
- uint64_t mrg_rxbuf = 1;
- uint64_t in_order = 1;
- uint64_t packed_vq = 0;
- uint64_t vectorized = 0;
+ bool server_mode = VIRTIO_USER_DEF_SERVER_MODE;
+ bool mrg_rxbuf = true;
+ bool in_order = true;
+ bool packed_vq = false;
+ bool vectorized = false;
char *path = NULL;
char *ifname = NULL;
char *mac_addr = NULL;
@@ -602,7 +585,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_QUEUE_SIZE) == 1) {
if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_QUEUE_SIZE,
- &get_integer_arg, &queue_size) < 0) {
+ rte_kvargs_handle_u64, &queue_size) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_QUEUE_SIZE);
goto end;
@@ -611,7 +594,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_QUEUES_NUM) == 1) {
if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_QUEUES_NUM,
- &get_integer_arg, &queues) < 0) {
+ rte_kvargs_handle_u64, &queues) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_QUEUES_NUM);
goto end;
@@ -619,8 +602,8 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
}
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_SERVER_MODE) == 1) {
- if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_SERVER_MODE,
- &get_integer_arg, &server_mode) < 0) {
+ if (rte_kvargs_process_opt(kvlist, VIRTIO_USER_ARG_SERVER_MODE,
+ rte_kvargs_handle_bool, &server_mode) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_SERVER_MODE);
goto end;
@@ -628,8 +611,8 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
}
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_CQ_NUM) == 1) {
- if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_CQ_NUM,
- &get_integer_arg, &cq) < 0) {
+ if (rte_kvargs_process_opt(kvlist, VIRTIO_USER_ARG_CQ_NUM,
+ rte_kvargs_handle_bool, &cq) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_CQ_NUM);
goto end;
@@ -637,8 +620,8 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
}
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_PACKED_VQ) == 1) {
- if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_PACKED_VQ,
- &get_integer_arg, &packed_vq) < 0) {
+ if (rte_kvargs_process_opt(kvlist, VIRTIO_USER_ARG_PACKED_VQ,
+ rte_kvargs_handle_bool, &packed_vq) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_PACKED_VQ);
goto end;
@@ -646,8 +629,8 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
}
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_VECTORIZED) == 1) {
- if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_VECTORIZED,
- &get_integer_arg, &vectorized) < 0) {
+ if (rte_kvargs_process_opt(kvlist, VIRTIO_USER_ARG_VECTORIZED,
+ rte_kvargs_handle_bool, &vectorized) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_VECTORIZED);
goto end;
@@ -655,8 +638,8 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
}
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_MRG_RXBUF) == 1) {
- if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_MRG_RXBUF,
- &get_integer_arg, &mrg_rxbuf) < 0) {
+ if (rte_kvargs_process_opt(kvlist, VIRTIO_USER_ARG_MRG_RXBUF,
+ rte_kvargs_handle_bool, &mrg_rxbuf) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_MRG_RXBUF);
goto end;
@@ -664,8 +647,8 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
}
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_IN_ORDER) == 1) {
- if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_IN_ORDER,
- &get_integer_arg, &in_order) < 0) {
+ if (rte_kvargs_process_opt(kvlist, VIRTIO_USER_ARG_IN_ORDER,
+ rte_kvargs_handle_bool, &in_order) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_IN_ORDER);
goto end;
@@ -816,7 +799,7 @@ RTE_PMD_REGISTER_ALIAS(net_virtio_user, virtio_user);
RTE_PMD_REGISTER_PARAM_STRING(net_virtio_user,
"path=<path> "
"mac=<mac addr> "
- "cq=<int> "
+ "cq=<0|1> "
"queue_size=<int> "
"queues=<int> "
"iface=<string> "
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 21/62] net/bonding: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (19 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 20/62] net/virtio: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 22/62] net/ena: " Stephen Hemminger
` (40 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Chas Williams, Min Hu (Connor)
The mode, socket id and time_ms parsers all assign the strtol() result
before checking the end pointer and errno, and the mode parser truncates
into a uint8_t so "mode=257" aliases onto mode 1.
parse_port_id() has the same unchecked pattern, and did not bound the
result before using it, relying on rte_eth_dev_is_valid_port() to catch
out of range values.
The socket id parser cast to int8_t when testing for SOCKET_ID_ANY, so
any value whose low byte is 0xff, such as 255 or -257, was accepted as
SOCKET_ID_ANY.
Drop the stray errno reset in the agg mode parser, which only does
string comparisons.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/bonding/eth_bond_private.h | 8 ---
drivers/net/bonding/rte_eth_bond_args.c | 71 ++++---------------------
drivers/net/bonding/rte_eth_bond_pmd.c | 8 +--
3 files changed, 14 insertions(+), 73 deletions(-)
diff --git a/drivers/net/bonding/eth_bond_private.h b/drivers/net/bonding/eth_bond_private.h
index 378bbba4e6..9a2fb7167e 100644
--- a/drivers/net/bonding/eth_bond_private.h
+++ b/drivers/net/bonding/eth_bond_private.h
@@ -298,10 +298,6 @@ int
bond_ethdev_parse_member_agg_mode_kvarg(const char *key __rte_unused,
const char *value, void *extra_args);
-int
-bond_ethdev_parse_socket_id_kvarg(const char *key,
- const char *value, void *extra_args);
-
int
bond_ethdev_parse_primary_member_port_id_kvarg(const char *key,
const char *value, void *extra_args);
@@ -314,10 +310,6 @@ int
bond_ethdev_parse_bond_mac_addr_kvarg(const char *key,
const char *value, void *extra_args);
-int
-bond_ethdev_parse_time_ms_kvarg(const char *key,
- const char *value, void *extra_args);
-
void
bond_tlb_disable(struct bond_dev_private *internals);
diff --git a/drivers/net/bonding/rte_eth_bond_args.c b/drivers/net/bonding/rte_eth_bond_args.c
index 823ed80f07..25602b3b47 100644
--- a/drivers/net/bonding/rte_eth_bond_args.c
+++ b/drivers/net/bonding/rte_eth_bond_args.c
@@ -91,13 +91,13 @@ parse_port_id(const char *port_str)
/* try parsing as device name, virtual devices */
port_id = find_port_id_by_dev_name(port_str);
if (port_id < 0) {
- char *end;
- errno = 0;
+ uint64_t val;
/* try parsing as port id */
- port_id = strtol(port_str, &end, 10);
- if (*end != 0 || errno != 0)
+ if (rte_kvargs_to_uint(port_str, 0, RTE_MAX_ETHPORTS - 1, &val) < 0)
return -1;
+
+ port_id = val;
}
}
@@ -136,19 +136,17 @@ int
bond_ethdev_parse_member_mode_kvarg(const char *key __rte_unused,
const char *value, void *extra_args)
{
- uint8_t *mode;
- char *endptr;
+ uint8_t *mode = extra_args;
+ uint64_t val;
- if (value == NULL || extra_args == NULL)
+ if (extra_args == NULL)
return -1;
- mode = extra_args;
-
- errno = 0;
- *mode = strtol(value, &endptr, 10);
- if (*endptr != 0 || errno != 0)
+ if (rte_kvargs_to_uint(value, 0, UINT8_MAX, &val) < 0)
return -1;
+ *mode = val;
+
/* validate mode value */
switch (*mode) {
case BONDING_MODE_ROUND_ROBIN:
@@ -176,7 +174,6 @@ bond_ethdev_parse_member_agg_mode_kvarg(const char *key __rte_unused,
agg_mode = extra_args;
- errno = 0;
if (strncmp(value, "stable", 6) == 0)
*agg_mode = AGG_STABLE;
@@ -197,35 +194,6 @@ bond_ethdev_parse_member_agg_mode_kvarg(const char *key __rte_unused,
}
}
-int
-bond_ethdev_parse_socket_id_kvarg(const char *key __rte_unused,
- const char *value, void *extra_args)
-{
- long socket_id;
- char *endptr;
-
- if (value == NULL || extra_args == NULL)
- return -1;
-
- errno = 0;
- socket_id = strtol(value, &endptr, 10);
- if (*endptr != 0 || errno != 0)
- return -1;
-
- /* SOCKET_ID_ANY also consider a valid socket id */
- if ((int8_t)socket_id == SOCKET_ID_ANY) {
- *(int *)extra_args = SOCKET_ID_ANY;
- return 0;
- }
-
- /* validate socket id value */
- if (socket_id >= 0 && socket_id < RTE_MAX_NUMA_NODES) {
- *(int *)extra_args = (int)socket_id;
- return 0;
- }
- return -1;
-}
-
int
bond_ethdev_parse_primary_member_port_id_kvarg(const char *key __rte_unused,
const char *value, void *extra_args)
@@ -278,22 +246,3 @@ bond_ethdev_parse_bond_mac_addr_kvarg(const char *key __rte_unused,
return rte_ether_unformat_addr(value, extra_args);
}
-int
-bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
- const char *value, void *extra_args)
-{
- uint32_t time_ms;
- char *endptr;
-
- if (value == NULL || extra_args == NULL)
- return -1;
-
- errno = 0;
- time_ms = (uint32_t)strtol(value, &endptr, 10);
- if (*endptr != 0 || errno != 0)
- return -1;
-
- *(uint32_t *)extra_args = time_ms;
-
- return 0;
-}
diff --git a/drivers/net/bonding/rte_eth_bond_pmd.c b/drivers/net/bonding/rte_eth_bond_pmd.c
index 6a4f997b5a..766dfd9459 100644
--- a/drivers/net/bonding/rte_eth_bond_pmd.c
+++ b/drivers/net/bonding/rte_eth_bond_pmd.c
@@ -3869,7 +3869,7 @@ bond_probe(struct rte_vdev_device *dev)
arg_count = rte_kvargs_count(kvlist, PMD_BOND_SOCKET_ID_KVARG);
if (arg_count == 1) {
if (rte_kvargs_process(kvlist, PMD_BOND_SOCKET_ID_KVARG,
- &bond_ethdev_parse_socket_id_kvarg, &socket_id)
+ rte_kvargs_handle_socket_id, &socket_id)
!= 0) {
RTE_BOND_LOG(ERR, "Invalid socket Id specified for "
"bonding device %s", name);
@@ -4207,7 +4207,7 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
if (rte_kvargs_process(kvlist,
PMD_BOND_LSC_POLL_PERIOD_KVARG,
- &bond_ethdev_parse_time_ms_kvarg,
+ rte_kvargs_handle_u32,
&lsc_poll_interval_ms) < 0) {
RTE_BOND_LOG(INFO,
"Invalid lsc polling interval value specified for bonding"
@@ -4236,7 +4236,7 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
if (rte_kvargs_process(kvlist,
PMD_BOND_LINK_UP_PROP_DELAY_KVARG,
- &bond_ethdev_parse_time_ms_kvarg,
+ rte_kvargs_handle_u32,
&link_up_delay_ms) < 0) {
RTE_BOND_LOG(INFO,
"Invalid link up propagation delay value specified for"
@@ -4266,7 +4266,7 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
if (rte_kvargs_process(kvlist,
PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG,
- &bond_ethdev_parse_time_ms_kvarg,
+ rte_kvargs_handle_u32,
&link_down_delay_ms) < 0) {
RTE_BOND_LOG(INFO,
"Invalid link down propagation delay value specified for"
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 22/62] net/ena: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (20 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 21/62] net/bonding: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 23/62] net/netvsc: " Stephen Hemminger
` (39 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Shai Brandes, Evgeny Schemeilin,
Amit Bernstein, Wajeeh Atrash
ena_process_uint_devarg() only checks that strtoull() consumed at least
one character, so trailing garbage such as "8junk" is accepted, and a
negative value is silently wrapped to a huge unsigned value.
ena_process_llq_policy_devarg() ignores the end pointer entirely, so any
unparsable value becomes zero and disables the LLQ policy rather than
being rejected.
ena_process_bool_devarg() only served enable_frag_bypass, and did
nothing beyond accepting "0" or "1" and storing into a bool, so drop it
and point rte_kvargs_handle_bool() at the field. A bare
"enable_frag_bypass" now enables it, along with the usual spellings.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/ena/ena_ethdev.c | 45 +++++-------------------------------
1 file changed, 6 insertions(+), 39 deletions(-)
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ad2ac6dbbf..c91f4f4b73 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -48,8 +48,6 @@
#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
-#define DECIMAL_BASE 10
-
#define MAX_WIDE_LLQ_DEPTH_UNSUPPORTED 0
#define ENA_TS_OFFSET_UNSET -1
@@ -321,9 +319,6 @@ static int ena_xstats_get_by_id(struct rte_eth_dev *dev,
static int ena_process_llq_policy_devarg(const char *key,
const char *value,
void *opaque);
-static int ena_process_bool_devarg(const char *key,
- const char *value,
- void *opaque);
static int ena_parse_devargs(struct ena_adapter *adapter,
struct rte_devargs *devargs);
static void ena_copy_customer_metrics(struct ena_adapter *adapter,
@@ -3841,11 +3836,9 @@ static int ena_process_uint_devarg(const char *key,
void *opaque)
{
struct ena_adapter *adapter = opaque;
- char *str_end;
uint64_t uint64_value;
- uint64_value = strtoull(value, &str_end, DECIMAL_BASE);
- if (value == str_end) {
+ if (rte_kvargs_to_uint(value, 0, UINT64_MAX, &uint64_value) < 0) {
PMD_INIT_LOG_LINE(ERR,
"Invalid value for key '%s'. Only uint values are accepted.",
key);
@@ -3890,17 +3883,15 @@ static int ena_process_uint_devarg(const char *key,
static int ena_process_llq_policy_devarg(const char *key, const char *value, void *opaque)
{
struct ena_adapter *adapter = opaque;
- uint32_t policy;
+ uint64_t policy;
- policy = strtoul(value, NULL, DECIMAL_BASE);
- if (policy < ENA_LLQ_POLICY_LAST) {
- adapter->llq_header_policy = policy;
- } else {
+ if (rte_kvargs_to_uint(value, 0, ENA_LLQ_POLICY_LAST - 1, &policy) < 0) {
PMD_INIT_LOG_LINE(ERR,
"Invalid value: '%s' for key '%s'. valid [0-3]",
value, key);
return -EINVAL;
}
+ adapter->llq_header_policy = policy;
PMD_INIT_LOG_LINE(INFO,
"LLQ policy is %u [0 - disabled, 1 - device recommended, 2 - normal, 3 - large]",
adapter->llq_header_policy);
@@ -3908,30 +3899,6 @@ static int ena_process_llq_policy_devarg(const char *key, const char *value, voi
return 0;
}
-static int ena_process_bool_devarg(const char *key, const char *value, void *opaque)
-{
- struct ena_adapter *adapter = opaque;
- bool bool_value;
-
- /* Parse the value. */
- if (strcmp(value, "1") == 0) {
- bool_value = true;
- } else if (strcmp(value, "0") == 0) {
- bool_value = false;
- } else {
- PMD_INIT_LOG_LINE(ERR,
- "Invalid value: '%s' for key '%s'. Accepted: '0' or '1'",
- value, key);
- return -EINVAL;
- }
-
- /* Now, assign it to the proper adapter field. */
- if (strcmp(key, ENA_DEVARG_ENABLE_FRAG_BYPASS) == 0)
- adapter->enable_frag_bypass = bool_value;
-
- return 0;
-}
-
static int ena_parse_devargs(struct ena_adapter *adapter, struct rte_devargs *devargs)
{
static const char * const allowed_args[] = {
@@ -3965,8 +3932,8 @@ static int ena_parse_devargs(struct ena_adapter *adapter, struct rte_devargs *de
ena_process_uint_devarg, adapter);
if (rc != 0)
goto exit;
- rc = rte_kvargs_process(kvlist, ENA_DEVARG_ENABLE_FRAG_BYPASS,
- ena_process_bool_devarg, adapter);
+ rc = rte_kvargs_process_opt(kvlist, ENA_DEVARG_ENABLE_FRAG_BYPASS,
+ rte_kvargs_handle_bool, &adapter->enable_frag_bypass);
if (rc != 0)
goto exit;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 23/62] net/netvsc: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (21 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 22/62] net/ena: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 12:43 ` [EXTERNAL] " Wei Hu
2026-09-14 5:46 ` [PATCH 24/62] net/ice: " Stephen Hemminger
` (38 subsequent siblings)
61 siblings, 1 reply; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Long Li, Wei Hu
hn_set_parameter() does not check errno, so an out of range value is
accepted as ULONG_MAX, and the result is stored into 32-bit fields
without any range check.
This also drops support for octal, which base 0 accepted; hexadecimal
still works.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/netvsc/hn_ethdev.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/netvsc/hn_ethdev.c b/drivers/net/netvsc/hn_ethdev.c
index 9a193e4a7a..d9f60ec279 100644
--- a/drivers/net/netvsc/hn_ethdev.c
+++ b/drivers/net/netvsc/hn_ethdev.c
@@ -202,11 +202,9 @@ eth_dev_vmbus_release(struct rte_eth_dev *eth_dev)
static int hn_set_parameter(const char *key, const char *value, void *opaque)
{
struct hn_data *hv = opaque;
- char *endp = NULL;
- unsigned long v;
+ uint64_t v;
- v = strtoul(value, &endp, 0);
- if (*value == '\0' || *endp != '\0') {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &v) < 0) {
PMD_DRV_LOG(ERR, "invalid parameter %s=%s", key, value);
return -EINVAL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 24/62] net/ice: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (22 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 23/62] net/netvsc: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 25/62] net/iavf: " Stephen Hemminger
` (37 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Bruce Richardson, Anatoly Burakov, Qi Zhang,
Ke Zhang, Kevin Liu
parse_u32() open codes the errno, end pointer and range checks that the
helper does.
parse_tx_sched_levels() assigns before validating and uses base 0, so a
leading zero silently selects octal.
handle_field_offs_arg() converts with atoi(), which reports no error,
and stores the result through a uint8_t pointer while the caller passes
&xtr_field_offs, which is an int. Only one byte of a four byte field
was written. Convert with rte_kvargs_to_int() and store through an int
pointer instead. The range starts at zero, which keeps the old isdigit()
rejection of a negative value: -1 is used internally to mean that no
extraction field is configured.
The debug_mask parser is converted separately, later in this series,
since it needs the hexadecimal handler rather than a decimal one.
parse_bool() stored an int through the pointer it was given, but three
of its five callers pass the address of a uint8_t field in struct
ice_devargs: default_mac_disable, ddp_load_sched and source_prune.
Each of those parsed four bytes over a one byte field and corrupted
whatever followed it. default_mac_disable is the worst of the three,
since it is immediately followed by proto_xtr[ICE_MAX_QUEUE_NUM], which
ice_parse_devargs() has just initialized when the argument is parsed.
All five arguments are booleans, so make the fields bool and use
rte_kvargs_handle_bool(), which removes the mismatch along with the
hand written parser. A bare key such as "safe-mode-support" now enables
the option, and the usual spellings are accepted.
Bugzilla ID: 2037
Bugzilla ID: 2038
Fixes: 66214b547c65 ("net/ice: add option to disable default MAC")
Fixes: df539aaf35cb ("net/ice: refactor flex descriptor protocol field extraction")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/intel/ice/ice_ethdev.c | 102 +++++++++--------------------
drivers/net/intel/ice/ice_ethdev.h | 10 +--
2 files changed, 36 insertions(+), 76 deletions(-)
diff --git a/drivers/net/intel/ice/ice_ethdev.c b/drivers/net/intel/ice/ice_ethdev.c
index 76b8ff0a72..af859f2174 100644
--- a/drivers/net/intel/ice/ice_ethdev.c
+++ b/drivers/net/intel/ice/ice_ethdev.c
@@ -8,6 +8,7 @@
#include <ctype.h>
#include <fcntl.h>
+#include <limits.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -15,6 +16,7 @@
#include <math.h>
#include <rte_tailq.h>
+#include <rte_kvargs.h>
#include <rte_os_shim.h>
#include "eal_firmware.h"
@@ -732,18 +734,20 @@ handle_proto_xtr_arg(__rte_unused const char *key, const char *value,
}
static int
-handle_field_offs_arg(__rte_unused const char *key, const char *value,
- void *offs_args)
+handle_field_offs_arg(const char *key, const char *value, void *offs_args)
{
- uint8_t *offset = offs_args;
+ int64_t offset;
- if (value == NULL || offs_args == NULL)
+ if (offs_args == NULL)
return -EINVAL;
- if (!isdigit(*value))
- return -1;
+ /* A negative offset is reserved: -1 means no field is configured. */
+ if (rte_kvargs_to_int(value, 0, INT_MAX, &offset) < 0) {
+ PMD_DRV_LOG(ERR, "Invalid %s, must be a positive offset", key);
+ return -EINVAL;
+ }
- *offset = atoi(value);
+ *(int *)offs_args = offset;
return 0;
}
@@ -1083,7 +1087,7 @@ ice_init_mac_address(struct rte_eth_dev *dev)
return -ENOMEM;
}
/* store it to dev data */
- if (ad->devargs.default_mac_disable != 1)
+ if (!ad->devargs.default_mac_disable)
rte_ether_addr_copy((struct rte_ether_addr *)hw->port_info[0].mac.perm_addr,
&dev->data->mac_addrs[0]);
return 0;
@@ -1113,7 +1117,7 @@ ice_add_mac_filter(struct ice_vsi *vsi, struct rte_ether_addr *mac_addr)
struct ice_adapter *ad = (struct ice_adapter *)hw->back;
int ret = 0;
- if (ad->devargs.default_mac_disable == 1 && rte_is_same_ether_addr(mac_addr,
+ if (ad->devargs.default_mac_disable && rte_is_same_ether_addr(mac_addr,
(struct rte_ether_addr *)hw->port_info[0].mac.perm_addr)) {
PMD_DRV_LOG(ERR, "This Default MAC filter is disabled.");
return 0;
@@ -1763,7 +1767,7 @@ ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type)
*/
vsi_ctx.info.sw_id = hw->port_info->sw_id;
/* Source Prune */
- if (ad->devargs.source_prune != 1) {
+ if (!ad->devargs.source_prune) {
/* Disable source prune to support VRRP
* when source-prune devarg is not set
*/
@@ -2136,25 +2140,6 @@ ice_base_queue_get(struct ice_pf *pf)
}
}
-static int
-parse_bool(const char *key, const char *value, void *args)
-{
- int *i = args;
-
- if (value == NULL || value[0] == '\0') {
- PMD_DRV_LOG(WARNING, "key:\"%s\", requires a value, which must be 0 or 1", key);
- return -1;
- }
- if (value[1] != '\0' || (value[0] != '0' && value[0] != '1')) {
- PMD_DRV_LOG(WARNING, "invalid value:\"%s\" for key:\"%s\", value must be 0 or 1",
- value, key);
- return -1;
- }
-
- *i = (value[0] == '1');
- return 0;
-}
-
static int
parse_u64(const char *key, const char *value, void *args)
{
@@ -2174,45 +2159,19 @@ parse_u64(const char *key, const char *value, void *args)
return 0;
}
-static int
-parse_u32(const char *key, const char *value, void *args)
-{
- uint32_t *num = args;
- unsigned long tmp;
- char *endptr;
-
- errno = 0;
- tmp = strtoul(value, &endptr, 0);
- if (errno != 0 || endptr == value || *endptr != '\0') {
- PMD_DRV_LOG(WARNING, "%s: \"%s\" is not a valid u32", key, value);
- return -1;
- }
- if (tmp > UINT32_MAX) {
- PMD_DRV_LOG(WARNING, "%s: value \"%s\" is out of range", key, value);
- return -1;
- }
-
- *num = (uint32_t)tmp;
-
- return 0;
-}
-
static int
parse_tx_sched_levels(const char *key, const char *value, void *args)
{
uint8_t *num = args;
- long tmp;
- char *endptr;
+ uint64_t tmp;
- errno = 0;
- tmp = strtol(value, &endptr, 0);
/* the value needs two stage validation, since the actual number of available
* levels is not known at this point. Initially just validate that it is in
* the correct range, between 3 and 8. Later validation will check that the
* available layers on a particular port is higher than the value specified here.
*/
- if (errno || *endptr != '\0' ||
- tmp < (ICE_VSI_LAYER_OFFSET - 1) || tmp >= ICE_TM_MAX_LAYERS) {
+ if (rte_kvargs_to_uint(value, ICE_VSI_LAYER_OFFSET - 1,
+ ICE_TM_MAX_LAYERS - 1, &tmp) < 0) {
PMD_DRV_LOG(WARNING, "%s: Invalid value \"%s\", should be in range [%d, %d]",
key, value, ICE_VSI_LAYER_OFFSET - 1, ICE_TM_MAX_LAYERS - 1);
return -1;
@@ -2453,13 +2412,13 @@ static int ice_parse_devargs(struct rte_eth_dev *dev)
if (ret)
goto bail;
- ret = rte_kvargs_process(kvlist, ICE_SAFE_MODE_SUPPORT_ARG,
- &parse_bool, &ad->devargs.safe_mode_support);
+ ret = rte_kvargs_process_opt(kvlist, ICE_SAFE_MODE_SUPPORT_ARG,
+ rte_kvargs_handle_bool, &ad->devargs.safe_mode_support);
if (ret)
goto bail;
- ret = rte_kvargs_process(kvlist, ICE_DEFAULT_MAC_DISABLE,
- &parse_bool, &ad->devargs.default_mac_disable);
+ ret = rte_kvargs_process_opt(kvlist, ICE_DEFAULT_MAC_DISABLE,
+ rte_kvargs_handle_bool, &ad->devargs.default_mac_disable);
if (ret)
goto bail;
@@ -2478,8 +2437,8 @@ static int ice_parse_devargs(struct rte_eth_dev *dev)
if (ret)
goto bail;
- ret = rte_kvargs_process(kvlist, ICE_RX_LOW_LATENCY_ARG,
- &parse_bool, &ad->devargs.rx_low_latency);
+ ret = rte_kvargs_process_opt(kvlist, ICE_RX_LOW_LATENCY_ARG,
+ rte_kvargs_handle_bool, &ad->devargs.rx_low_latency);
if (ret)
goto bail;
@@ -2488,8 +2447,8 @@ static int ice_parse_devargs(struct rte_eth_dev *dev)
if (ret)
goto bail;
- ret = rte_kvargs_process(kvlist, ICE_DDP_LOAD_SCHED_ARG,
- &parse_bool, &ad->devargs.ddp_load_sched);
+ ret = rte_kvargs_process_opt(kvlist, ICE_DDP_LOAD_SCHED_ARG,
+ rte_kvargs_handle_bool, &ad->devargs.ddp_load_sched);
if (ret)
goto bail;
@@ -2499,12 +2458,12 @@ static int ice_parse_devargs(struct rte_eth_dev *dev)
goto bail;
ret = rte_kvargs_process(kvlist, ICE_RL_BURST_SIZE_ARG,
- &parse_u32, &ad->devargs.rl_burst_size);
+ rte_kvargs_handle_u32, &ad->devargs.rl_burst_size);
if (ret)
goto bail;
- ret = rte_kvargs_process(kvlist, ICE_SOURCE_PRUNE_ARG,
- &parse_bool, &ad->devargs.source_prune);
+ ret = rte_kvargs_process_opt(kvlist, ICE_SOURCE_PRUNE_ARG,
+ rte_kvargs_handle_bool, &ad->devargs.source_prune);
if (ret)
goto bail;
@@ -2758,7 +2717,7 @@ ice_dev_init(struct rte_eth_dev *dev)
}
if (ret) {
- if (ad->devargs.safe_mode_support == 0) {
+ if (!ad->devargs.safe_mode_support) {
PMD_INIT_LOG(ERR, "Failed to load the DDP package,"
"Use safe-mode-support=1 to enter Safe Mode");
goto err_init_fw;
@@ -4211,7 +4170,8 @@ __vsi_queues_bind_intr(struct ice_vsi *vsi, uint16_t msix_vect,
{
struct ice_hw *hw = ICE_VSI_TO_HW(vsi);
uint32_t val, val_tx;
- int rx_low_latency, i;
+ bool rx_low_latency;
+ int i;
rx_low_latency = vsi->adapter->devargs.rx_low_latency;
for (i = 0; i < nb_queue; i++) {
diff --git a/drivers/net/intel/ice/ice_ethdev.h b/drivers/net/intel/ice/ice_ethdev.h
index 7ee3ea8a70..3ca820ccb6 100644
--- a/drivers/net/intel/ice/ice_ethdev.h
+++ b/drivers/net/intel/ice/ice_ethdev.h
@@ -622,16 +622,16 @@ struct ice_pf {
* Cache devargs parse result.
*/
struct ice_devargs {
- int rx_low_latency;
- int safe_mode_support;
+ bool rx_low_latency;
+ bool safe_mode_support;
uint8_t proto_xtr_dflt;
- uint8_t default_mac_disable;
+ bool default_mac_disable;
uint8_t proto_xtr[ICE_MAX_QUEUE_NUM];
uint8_t pin_idx;
uint8_t pps_out_ena;
- uint8_t ddp_load_sched;
+ bool ddp_load_sched;
uint8_t tm_exposed_levels;
- uint8_t source_prune;
+ bool source_prune;
uint32_t rl_burst_size;
int link_state_on_close;
int xtr_field_offs;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 25/62] net/iavf: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (23 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 24/62] net/ice: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 26/62] net/i40e: " Stephen Hemminger
` (36 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Vladimir Medvedkin
parse_u16() ignores the end pointer, so "8junk" is accepted, and assigns
a u64 into a u16 without a range check, so "65536" wraps to zero. Zero
is still rejected, as it is the unset marker for quanta_size.
parse_bool() checks neither errno nor the end pointer.
iavf_parse_watchdog_period() uses atoi(), which cannot report an error
at all, so a malformed value becomes zero and the negative check never
fires.
no-poll-on-link-down, auto_reset, auto_reconfig and enable_ptype_lldp
are booleans, so make the fields bool and use rte_kvargs_handle_bool().
That is every caller of the local parse_bool(), so it goes away too. A
bare key now enables the option, and the usual spellings are accepted.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/intel/iavf/iavf.h | 8 ++--
drivers/net/intel/iavf/iavf_ethdev.c | 61 +++++++++-------------------
2 files changed, 24 insertions(+), 45 deletions(-)
diff --git a/drivers/net/intel/iavf/iavf.h b/drivers/net/intel/iavf/iavf.h
index 293adaf6c9..6bfe07e1b0 100644
--- a/drivers/net/intel/iavf/iavf.h
+++ b/drivers/net/intel/iavf/iavf.h
@@ -322,11 +322,11 @@ struct iavf_devargs {
uint8_t proto_xtr[IAVF_MAX_QUEUE_NUM];
uint16_t quanta_size;
uint32_t watchdog_period;
- int auto_reset;
- int auto_reconfig;
- int no_poll_on_link_down;
+ bool auto_reset;
+ bool auto_reconfig;
+ bool no_poll_on_link_down;
uint64_t mbuf_check;
- int enable_ptype_lldp;
+ bool enable_ptype_lldp;
};
struct iavf_security_ctx;
diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c
index d601ec3b6a..273040d8a5 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -3,6 +3,7 @@
*/
#include <ctype.h>
+#include <limits.h>
#include <sys/queue.h>
#include <stdalign.h>
#include <stdio.h>
@@ -13,6 +14,7 @@
#include <stdarg.h>
#include <inttypes.h>
#include <rte_byteorder.h>
+#include <rte_kvargs.h>
#include <rte_common.h>
#include <rte_os_shim.h>
@@ -2352,11 +2354,10 @@ static int
parse_u16(__rte_unused const char *key, const char *value, void *args)
{
u16 *num = (u16 *)args;
- u16 tmp;
+ uint64_t tmp;
- errno = 0;
- tmp = strtoull(value, NULL, 10);
- if (errno || !tmp) {
+ /* zero is not accepted, it is the "unset" marker for this argument */
+ if (rte_kvargs_to_uint(value, 1, UINT16_MAX, &tmp) < 0) {
PMD_DRV_LOG(WARNING, "%s: \"%s\" is not a valid u16",
key, value);
return -1;
@@ -2367,35 +2368,13 @@ parse_u16(__rte_unused const char *key, const char *value, void *args)
return 0;
}
-static int
-parse_bool(const char *key, const char *value, void *args)
-{
- int *i = (int *)args;
- char *end;
- int num;
-
- num = strtoul(value, &end, 10);
-
- if (num != 0 && num != 1) {
- PMD_DRV_LOG(WARNING, "invalid value:\"%s\" for key:\"%s\", "
- "value must be 0 or 1",
- value, key);
- return -1;
- }
-
- *i = num;
- return 0;
-}
-
static int
iavf_parse_watchdog_period(__rte_unused const char *key, const char *value, void *args)
{
int *num = (int *)args;
- int tmp;
+ uint64_t tmp;
- errno = 0;
- tmp = atoi(value);
- if (tmp < 0) {
+ if (rte_kvargs_to_uint(value, 0, INT_MAX, &tmp) < 0) {
PMD_DRV_LOG(WARNING, "%s: \"%s\" is not greater than or equal to zero",
key, value);
return -1;
@@ -2466,9 +2445,9 @@ static int iavf_parse_devargs(struct rte_eth_dev *dev)
int ret;
int watchdog_period = -1;
- ad->devargs.auto_reset = 1;
- ad->devargs.no_poll_on_link_down = 1;
- ad->devargs.auto_reconfig = 1;
+ ad->devargs.auto_reset = true;
+ ad->devargs.no_poll_on_link_down = true;
+ ad->devargs.auto_reconfig = true;
if (!devargs)
return 0;
@@ -2502,8 +2481,8 @@ static int iavf_parse_devargs(struct rte_eth_dev *dev)
else
ad->devargs.watchdog_period = watchdog_period;
- ret = rte_kvargs_process(kvlist, IAVF_NO_POLL_ON_LINK_DOWN_ARG,
- &parse_bool, &ad->devargs.no_poll_on_link_down);
+ ret = rte_kvargs_process_opt(kvlist, IAVF_NO_POLL_ON_LINK_DOWN_ARG,
+ rte_kvargs_handle_bool, &ad->devargs.no_poll_on_link_down);
if (ret)
goto bail;
@@ -2520,24 +2499,24 @@ static int iavf_parse_devargs(struct rte_eth_dev *dev)
if (ret)
goto bail;
- ret = rte_kvargs_process(kvlist, IAVF_ENABLE_AUTO_RESET_ARG,
- &parse_bool, &ad->devargs.auto_reset);
+ ret = rte_kvargs_process_opt(kvlist, IAVF_ENABLE_AUTO_RESET_ARG,
+ rte_kvargs_handle_bool, &ad->devargs.auto_reset);
if (ret)
goto bail;
- if (ad->devargs.auto_reset != 0 && ad->devargs.no_poll_on_link_down == 0) {
+ if (ad->devargs.auto_reset && !ad->devargs.no_poll_on_link_down) {
PMD_INIT_LOG(WARNING,
"no-poll-on-link-down=0 is incompatible with auto_reset=1, ignoring");
- ad->devargs.no_poll_on_link_down = 1;
+ ad->devargs.no_poll_on_link_down = true;
}
- ret = rte_kvargs_process(kvlist, IAVF_ENABLE_AUTO_RECONFIG_ARG,
- &parse_bool, &ad->devargs.auto_reconfig);
+ ret = rte_kvargs_process_opt(kvlist, IAVF_ENABLE_AUTO_RECONFIG_ARG,
+ rte_kvargs_handle_bool, &ad->devargs.auto_reconfig);
if (ret)
goto bail;
- ret = rte_kvargs_process(kvlist, IAVF_ENABLE_PTYPE_LLDP_ARG,
- &parse_bool, &ad->devargs.enable_ptype_lldp);
+ ret = rte_kvargs_process_opt(kvlist, IAVF_ENABLE_PTYPE_LLDP_ARG,
+ rte_kvargs_handle_bool, &ad->devargs.enable_ptype_lldp);
if (ret)
goto bail;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 26/62] net/i40e: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (24 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 25/62] net/iavf: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 27/62] net/idpf: " Stephen Hemminger
` (35 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson
Replace the open coded errno and end pointer checks in the multi driver
and VF queue number handlers.
The VF queue number handler also used base 0, so a leading zero silently
selected octal. It is now parsed as a uint16_t, which is the width of
the field it feeds, so a value above 65535 is rejected outright rather
than warned about; anything in range still warns and returns success, so
that a later valid instance of the same argument takes effect.
support-multi-driver is a boolean and the field behind it is already a
bool, so drop i40e_parse_multi_drv_handler() and point
rte_kvargs_handle_bool() at the field.
Note that a value other than 0 or 1 used to log a warning and carry on
with the default. It now fails the probe, like every other malformed
devarg in this series.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/intel/i40e/i40e_ethdev.c | 45 ++++++----------------------
1 file changed, 9 insertions(+), 36 deletions(-)
diff --git a/drivers/net/intel/i40e/i40e_ethdev.c b/drivers/net/intel/i40e/i40e_ethdev.c
index b6b2d291ee..3b17281952 100644
--- a/drivers/net/intel/i40e/i40e_ethdev.c
+++ b/drivers/net/intel/i40e/i40e_ethdev.c
@@ -14,6 +14,7 @@
#include <assert.h>
#include <rte_common.h>
+#include <rte_kvargs.h>
#include <rte_eal.h>
#include <rte_string_fns.h>
#include <rte_pci.h>
@@ -1267,33 +1268,6 @@ i40e_init_queue_region_conf(struct rte_eth_dev *dev)
memset(info, 0, sizeof(struct i40e_queue_regions));
}
-static int
-i40e_parse_multi_drv_handler(__rte_unused const char *key,
- const char *value,
- void *opaque)
-{
- struct i40e_pf *pf;
- unsigned long support_multi_driver;
- char *end;
-
- pf = (struct i40e_pf *)opaque;
-
- errno = 0;
- support_multi_driver = strtoul(value, &end, 10);
- if (errno != 0 || end == value || *end != 0) {
- PMD_DRV_LOG(WARNING, "Wrong global configuration");
- return -(EINVAL);
- }
-
- if (support_multi_driver == 1 || support_multi_driver == 0)
- pf->support_multi_driver = (bool)support_multi_driver;
- else
- PMD_DRV_LOG(WARNING, "%s must be 1 or 0,",
- "enable global configuration by default."
- ETH_I40E_SUPPORT_MULTI_DRIVER);
- return 0;
-}
-
static int
i40e_support_multi_driver(struct rte_eth_dev *dev)
{
@@ -1322,8 +1296,9 @@ i40e_support_multi_driver(struct rte_eth_dev *dev)
"the first invalid or last valid one is used !",
ETH_I40E_SUPPORT_MULTI_DRIVER);
- if (rte_kvargs_process(kvlist, ETH_I40E_SUPPORT_MULTI_DRIVER,
- i40e_parse_multi_drv_handler, pf) < 0) {
+ if (rte_kvargs_process_opt(kvlist, ETH_I40E_SUPPORT_MULTI_DRIVER,
+ rte_kvargs_handle_bool,
+ &pf->support_multi_driver) < 0) {
rte_kvargs_free(kvlist);
return -EINVAL;
}
@@ -4831,15 +4806,12 @@ static int i40e_pf_parse_vf_queue_number_handler(const char *key,
void *opaque)
{
struct i40e_pf *pf;
- unsigned long num;
- char *end;
+ uint64_t num;
pf = (struct i40e_pf *)opaque;
RTE_SET_USED(key);
- errno = 0;
- num = strtoul(value, &end, 0);
- if (errno != 0 || end == value || *end != 0) {
+ if (rte_kvargs_to_uint(value, 0, UINT16_MAX, &num) < 0) {
PMD_DRV_LOG(WARNING, "Wrong VF queue number = %s, Now it is "
"kept the value = %hu", value, pf->vf_nb_qp_max);
return -(EINVAL);
@@ -4849,9 +4821,10 @@ static int i40e_pf_parse_vf_queue_number_handler(const char *key,
pf->vf_nb_qp_max = (uint16_t)num;
else
/* here return 0 to make next valid same argument work */
- PMD_DRV_LOG(WARNING, "Wrong VF queue number = %lu, it must be "
+ PMD_DRV_LOG(WARNING, "Wrong VF queue number = %hu, it must be "
"power of 2 and equal or less than 16 !, Now it is "
- "kept the value = %hu", num, pf->vf_nb_qp_max);
+ "kept the value = %hu", (uint16_t)num,
+ pf->vf_nb_qp_max);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 27/62] net/idpf: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (25 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 26/62] net/i40e: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:46 ` [PATCH 28/62] net/cpfl: " Stephen Hemminger
` (34 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Jingjing Wu, Praveen Shetty, Beilei Xing,
Wenjun Wu, Junfeng Guo, Xiao Wang, Xiaoyun Li
parse_bool() only tested errno for ERANGE and ignored the end pointer, so
"1junk" was accepted.
It also stored through an int pointer, but both device arguments are bool
fields, so parsing either wrote four bytes into a one byte object.
The handler did nothing beyond a range checked store of a boolean, so
drop it and pass rte_kvargs_handle_bool() directly, which stores a bool
and also accepts the usual spellings such as "on" and "true".
The booleans use rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Bugzilla ID: 2042
Fixes: 549343c25db8 ("net/idpf: support device initialization")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/intel/idpf/idpf_ethdev.c | 26 +++-----------------------
1 file changed, 3 insertions(+), 23 deletions(-)
diff --git a/drivers/net/intel/idpf/idpf_ethdev.c b/drivers/net/intel/idpf/idpf_ethdev.c
index c13505416a..6aad5c5008 100644
--- a/drivers/net/intel/idpf/idpf_ethdev.c
+++ b/drivers/net/intel/idpf/idpf_ethdev.c
@@ -3,6 +3,7 @@
*/
#include <rte_atomic.h>
+#include <rte_kvargs.h>
#include <rte_eal.h>
#include <rte_ether.h>
#include <rte_malloc.h>
@@ -1244,27 +1245,6 @@ parse_vport(const char *key, const char *value, void *args)
return 0;
}
-static int
-parse_bool(const char *key, const char *value, void *args)
-{
- int *i = args;
- char *end;
- int num;
-
- errno = 0;
-
- num = strtoul(value, &end, 10);
-
- if (errno == ERANGE || (num != 0 && num != 1)) {
- PMD_INIT_LOG(ERR, "invalid value:\"%s\" for key:\"%s\", value must be 0 or 1",
- value, key);
- return -EINVAL;
- }
-
- *i = num;
- return 0;
-}
-
static int
idpf_parse_devargs(struct rte_pci_device *pci_dev, struct idpf_adapter_ext *adapter,
struct idpf_devargs *idpf_args)
@@ -1307,12 +1287,12 @@ idpf_parse_devargs(struct rte_pci_device *pci_dev, struct idpf_adapter_ext *adap
if (ret != 0)
goto bail;
- ret = rte_kvargs_process(kvlist, IDPF_TX_SINGLE_Q, &parse_bool,
+ ret = rte_kvargs_process_opt(kvlist, IDPF_TX_SINGLE_Q, rte_kvargs_handle_bool,
&adapter->base.is_tx_singleq);
if (ret != 0)
goto bail;
- ret = rte_kvargs_process(kvlist, IDPF_RX_SINGLE_Q, &parse_bool,
+ ret = rte_kvargs_process_opt(kvlist, IDPF_RX_SINGLE_Q, rte_kvargs_handle_bool,
&adapter->base.is_rx_singleq);
if (ret != 0)
goto bail;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 28/62] net/cpfl: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (26 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 27/62] net/idpf: " Stephen Hemminger
@ 2026-09-14 5:46 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 29/62] net/ixgbe: " Stephen Hemminger
` (33 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:46 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Praveen Shetty, Mingxia Liu
parse_bool() only tested errno for ERANGE and ignored the end pointer, so
"1junk" was accepted.
It also stored through an int pointer, but both device arguments are bool
fields, so parsing either wrote four bytes into a one byte object.
The handler did nothing beyond a range checked store of a boolean, so
drop it and pass rte_kvargs_handle_bool() directly, which stores a bool
and also accepts the usual spellings such as "on" and "true".
The booleans use rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Bugzilla ID: 2042
Fixes: 2d823ecd671c ("net/cpfl: support device initialization")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/intel/cpfl/cpfl_ethdev.c | 26 +++-----------------------
1 file changed, 3 insertions(+), 23 deletions(-)
diff --git a/drivers/net/intel/cpfl/cpfl_ethdev.c b/drivers/net/intel/cpfl/cpfl_ethdev.c
index 4315adb68c..6e6401a9ce 100644
--- a/drivers/net/intel/cpfl/cpfl_ethdev.c
+++ b/drivers/net/intel/cpfl/cpfl_ethdev.c
@@ -3,6 +3,7 @@
*/
#include <rte_atomic.h>
+#include <rte_kvargs.h>
#include <rte_eal.h>
#include <rte_ether.h>
#include <rte_malloc.h>
@@ -1445,27 +1446,6 @@ parse_vport(const char *key, const char *value, void *args)
return 0;
}
-static int
-parse_bool(const char *key, const char *value, void *args)
-{
- int *i = args;
- char *end;
- int num;
-
- errno = 0;
-
- num = strtoul(value, &end, 10);
-
- if (errno == ERANGE || (num != 0 && num != 1)) {
- PMD_INIT_LOG(ERR, "invalid value:\"%s\" for key:\"%s\", value must be 0 or 1",
- value, key);
- return -EINVAL;
- }
-
- *i = num;
- return 0;
-}
-
static int
enlist(uint16_t *list, uint16_t *len_list, const uint16_t max_list, uint16_t val)
{
@@ -1643,12 +1623,12 @@ cpfl_parse_devargs(struct rte_pci_device *pci_dev, struct cpfl_adapter_ext *adap
if (ret != 0)
goto fail;
- ret = rte_kvargs_process(kvlist, CPFL_TX_SINGLE_Q, &parse_bool,
+ ret = rte_kvargs_process_opt(kvlist, CPFL_TX_SINGLE_Q, rte_kvargs_handle_bool,
&adapter->base.is_tx_singleq);
if (ret != 0)
goto fail;
- ret = rte_kvargs_process(kvlist, CPFL_RX_SINGLE_Q, &parse_bool,
+ ret = rte_kvargs_process_opt(kvlist, CPFL_RX_SINGLE_Q, rte_kvargs_handle_bool,
&adapter->base.is_rx_singleq);
if (ret != 0)
goto fail;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 29/62] net/ixgbe: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (27 preceding siblings ...)
2026-09-14 5:46 ` [PATCH 28/62] net/cpfl: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 30/62] net/txgbe: " Stephen Hemminger
` (32 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Anatoly Burakov, Vladimir Medvedkin
devarg_handle_int() truncates the strtoul() result into a uint16_t and
then infers overflow from the truncated value being USHRT_MAX, so a
value such as "65536" is silently accepted as zero. It also never
checked the end pointer, and read errno without clearing it first.
fiber_sdp3_no_tx_disable and pflink_fullchk are booleans, so make the
fields bool and parse them with rte_kvargs_handle_bool() straight into
the adapter, which also removes the temporary and the "== 1" dance. A
bare key now enables the option, and the usual spellings are accepted.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/intel/ixgbe/ixgbe_ethdev.c | 40 ++++++--------------------
drivers/net/intel/ixgbe/ixgbe_ethdev.h | 4 +--
2 files changed, 11 insertions(+), 33 deletions(-)
diff --git a/drivers/net/intel/ixgbe/ixgbe_ethdev.c b/drivers/net/intel/ixgbe/ixgbe_ethdev.c
index c5010f623c..e410c8d469 100644
--- a/drivers/net/intel/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/intel/ixgbe/ixgbe_ethdev.c
@@ -355,8 +355,6 @@ static int ixgbe_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
static int ixgbe_filter_restore(struct rte_eth_dev *dev);
static void ixgbe_l2_tunnel_conf(struct rte_eth_dev *dev);
static int ixgbe_wait_for_link_up(struct ixgbe_hw *hw);
-static int devarg_handle_int(__rte_unused const char *key, const char *value,
- void *extra_args);
/*
* Define VF Stats MACRO for Non "cleared on read" register
@@ -1059,7 +1057,6 @@ ixgbe_parse_devargs(struct ixgbe_adapter *adapter,
struct rte_devargs *devargs)
{
struct rte_kvargs *kvlist;
- uint16_t sdp3_no_tx_disable;
if (devargs == NULL)
return;
@@ -1068,11 +1065,10 @@ ixgbe_parse_devargs(struct ixgbe_adapter *adapter,
if (kvlist == NULL)
return;
- if (rte_kvargs_count(kvlist, IXGBE_DEVARG_FIBER_SDP3_NOT_TX_DISABLE) == 1 &&
- rte_kvargs_process(kvlist, IXGBE_DEVARG_FIBER_SDP3_NOT_TX_DISABLE,
- devarg_handle_int, &sdp3_no_tx_disable) == 0 &&
- sdp3_no_tx_disable == 1)
- adapter->sdp3_no_tx_disable = 1;
+ if (rte_kvargs_count(kvlist, IXGBE_DEVARG_FIBER_SDP3_NOT_TX_DISABLE) == 1)
+ (void)rte_kvargs_process_opt(kvlist, IXGBE_DEVARG_FIBER_SDP3_NOT_TX_DISABLE,
+ rte_kvargs_handle_bool,
+ &adapter->sdp3_no_tx_disable);
rte_kvargs_free(kvlist);
}
@@ -1555,28 +1551,11 @@ generate_random_mac_addr(struct rte_ether_addr *mac_addr)
memcpy(&mac_addr->addr_bytes[3], &random, 3);
}
-static int
-devarg_handle_int(__rte_unused const char *key, const char *value,
- void *extra_args)
-{
- uint16_t *n = extra_args;
-
- if (value == NULL || extra_args == NULL)
- return -EINVAL;
-
- *n = (uint16_t)strtoul(value, NULL, 0);
- if (*n == USHRT_MAX && errno == ERANGE)
- return -1;
-
- return 0;
-}
-
static void
ixgbevf_parse_devargs(struct ixgbe_adapter *adapter,
struct rte_devargs *devargs)
{
struct rte_kvargs *kvlist;
- uint16_t pflink_fullchk;
if (devargs == NULL)
return;
@@ -1585,11 +1564,10 @@ ixgbevf_parse_devargs(struct ixgbe_adapter *adapter,
if (kvlist == NULL)
return;
- if (rte_kvargs_count(kvlist, IXGBEVF_DEVARG_PFLINK_FULLCHK) == 1 &&
- rte_kvargs_process(kvlist, IXGBEVF_DEVARG_PFLINK_FULLCHK,
- devarg_handle_int, &pflink_fullchk) == 0 &&
- pflink_fullchk == 1)
- adapter->pflink_fullchk = 1;
+ if (rte_kvargs_count(kvlist, IXGBEVF_DEVARG_PFLINK_FULLCHK) == 1)
+ (void)rte_kvargs_process_opt(kvlist, IXGBEVF_DEVARG_PFLINK_FULLCHK,
+ rte_kvargs_handle_bool,
+ &adapter->pflink_fullchk);
rte_kvargs_free(kvlist);
}
@@ -4231,7 +4209,7 @@ ixgbevf_check_link(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
*speed = IXGBE_LINK_SPEED_UNKNOWN;
}
- if (wait_to_complete == 0 && adapter->pflink_fullchk == 0) {
+ if (wait_to_complete == 0 && !adapter->pflink_fullchk) {
if (*speed == IXGBE_LINK_SPEED_UNKNOWN)
mac->get_link_status = true;
else
diff --git a/drivers/net/intel/ixgbe/ixgbe_ethdev.h b/drivers/net/intel/ixgbe/ixgbe_ethdev.h
index 5d3243cb4d..75d9ef4cce 100644
--- a/drivers/net/intel/ixgbe/ixgbe_ethdev.h
+++ b/drivers/net/intel/ixgbe/ixgbe_ethdev.h
@@ -496,13 +496,13 @@ struct ixgbe_adapter {
uint8_t rss_reta_updated;
/* Used for limiting SDP3 TX_DISABLE checks */
- uint8_t sdp3_no_tx_disable;
+ bool sdp3_no_tx_disable;
uint16_t max_vfs;
/* Used for VF link sync with PF's physical and logical (by checking
* mailbox status) link status.
*/
- uint8_t pflink_fullchk;
+ bool pflink_fullchk;
uint8_t mac_ctrl_frame_fwd;
RTE_ATOMIC(bool) link_thread_running;
rte_thread_t link_thread_tid;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 30/62] net/txgbe: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (28 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 29/62] net/ixgbe: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 31/62] net/octeontx: " Stephen Hemminger
` (31 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Jiawen Wu, Zaiyu Wang
txgbe_handle_devarg() truncates the strtoul() result into a uint16_t and
then infers overflow from the truncated value being USHRT_MAX, so a
value such as "65536" is silently accepted as zero. It also never
checked the end pointer, and read errno without clearing it first.
All thirteen rte_kvargs_process() results were discarded, so a bad
value was ignored and the default used instead. Collect them and fail
the probe, which makes a malformed devarg visible rather than silently
changing the configuration the user asked for.
auto_neg, poll, present, sgmii, tx_headwb and rx_desc_merge are
booleans, so parse them with rte_kvargs_handle_bool() into a bool. The
struct txgbe_devargs fields stay u16, since they live in base code
shared with the vendor tree; a bool assigned into them still yields 0
or 1. A bare key now enables the option, and the usual spellings are
accepted.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/txgbe/txgbe_ethdev.c | 91 +++++++++++++++-----------------
1 file changed, 42 insertions(+), 49 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 814840b3f5..b99e1ad1bc 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -501,22 +501,6 @@ txgbe_swfw_lock_reset(struct txgbe_hw *hw)
}
static int
-txgbe_handle_devarg(__rte_unused const char *key, const char *value,
- void *extra_args)
-{
- uint16_t *n = extra_args;
-
- if (value == NULL || extra_args == NULL)
- return -EINVAL;
-
- *n = (uint16_t)strtoul(value, NULL, 10);
- if (*n == USHRT_MAX && errno == ERANGE)
- return -1;
-
- return 0;
-}
-
-static void
txgbe_parse_devargs(struct rte_eth_dev *dev)
{
struct rte_eth_fdir_conf *fdir_conf = TXGBE_DEV_FDIR_CONF(dev);
@@ -524,10 +508,10 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
struct rte_devargs *devargs = pci_dev->device.devargs;
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
struct rte_kvargs *kvlist;
- u16 auto_neg = 1;
- u16 poll = 0;
- u16 present = 0;
- u16 sgmii = 0;
+ bool auto_neg = true;
+ bool poll = false;
+ bool present = false;
+ bool sgmii = false;
u16 ffe_set = 0;
u16 ffe_main = 27;
u16 ffe_pre = 8;
@@ -536,9 +520,10 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
u16 pballoc = 0;
u16 drop_queue = 127;
/* New devargs for amberlite config */
- u16 tx_headwb = 1;
+ bool tx_headwb = true;
u16 tx_headwb_size = 16;
- u16 rx_desc_merge = 1;
+ bool rx_desc_merge = true;
+ int ret;
if (devargs == NULL)
goto null;
@@ -547,34 +532,37 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
if (kvlist == NULL)
goto null;
- rte_kvargs_process(kvlist, TXGBE_DEVARG_BP_AUTO,
- &txgbe_handle_devarg, &auto_neg);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_KR_POLL,
- &txgbe_handle_devarg, &poll);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_KR_PRESENT,
- &txgbe_handle_devarg, &present);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_KX_SGMII,
- &txgbe_handle_devarg, &sgmii);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_SET,
- &txgbe_handle_devarg, &ffe_set);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_MAIN,
- &txgbe_handle_devarg, &ffe_main);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_PRE,
- &txgbe_handle_devarg, &ffe_pre);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_POST,
- &txgbe_handle_devarg, &ffe_post);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_FDIR_PBALLOC,
- &txgbe_handle_devarg, &pballoc);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_FDIR_DROP_QUEUE,
- &txgbe_handle_devarg, &drop_queue);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_TX_HEAD_WB,
- &txgbe_handle_devarg, &tx_headwb);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_TX_HEAD_WB_SIZE,
- &txgbe_handle_devarg, &tx_headwb_size);
- rte_kvargs_process(kvlist, TXGBE_DEVARG_RX_DESC_MERGE,
- &txgbe_handle_devarg, &rx_desc_merge);
+ ret = rte_kvargs_process_opt(kvlist, TXGBE_DEVARG_BP_AUTO,
+ rte_kvargs_handle_bool, &auto_neg);
+ ret |= rte_kvargs_process_opt(kvlist, TXGBE_DEVARG_KR_POLL,
+ rte_kvargs_handle_bool, &poll);
+ ret |= rte_kvargs_process_opt(kvlist, TXGBE_DEVARG_KR_PRESENT,
+ rte_kvargs_handle_bool, &present);
+ ret |= rte_kvargs_process_opt(kvlist, TXGBE_DEVARG_KX_SGMII,
+ rte_kvargs_handle_bool, &sgmii);
+ ret |= rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_SET,
+ rte_kvargs_handle_u16, &ffe_set);
+ ret |= rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_MAIN,
+ rte_kvargs_handle_u16, &ffe_main);
+ ret |= rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_PRE,
+ rte_kvargs_handle_u16, &ffe_pre);
+ ret |= rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_POST,
+ rte_kvargs_handle_u16, &ffe_post);
+ ret |= rte_kvargs_process(kvlist, TXGBE_DEVARG_FDIR_PBALLOC,
+ rte_kvargs_handle_u16, &pballoc);
+ ret |= rte_kvargs_process(kvlist, TXGBE_DEVARG_FDIR_DROP_QUEUE,
+ rte_kvargs_handle_u16, &drop_queue);
+ ret |= rte_kvargs_process_opt(kvlist, TXGBE_DEVARG_TX_HEAD_WB,
+ rte_kvargs_handle_bool, &tx_headwb);
+ ret |= rte_kvargs_process(kvlist, TXGBE_DEVARG_TX_HEAD_WB_SIZE,
+ rte_kvargs_handle_u16, &tx_headwb_size);
+ ret |= rte_kvargs_process_opt(kvlist, TXGBE_DEVARG_RX_DESC_MERGE,
+ rte_kvargs_handle_bool, &rx_desc_merge);
rte_kvargs_free(kvlist);
+ if (ret != 0)
+ return -EINVAL;
+
null:
hw->devarg.auto_neg = auto_neg;
hw->devarg.poll = poll;
@@ -590,6 +578,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
fdir_conf->pballoc = pballoc;
fdir_conf->drop_queue = drop_queue;
+
+ return 0;
}
static void
@@ -690,7 +680,10 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
hw->isb_dma = TMZ_PADDR(mz);
hw->isb_mem = TMZ_VADDR(mz);
- txgbe_parse_devargs(eth_dev);
+ err = txgbe_parse_devargs(eth_dev);
+ if (err != 0)
+ return err;
+
/* Initialize the shared code (base driver) */
err = txgbe_init_shared_code(hw);
if (err != 0) {
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 31/62] net/octeontx: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (29 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 30/62] net/txgbe: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 32/62] net/octeon_ep: " Stephen Hemminger
` (30 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Harman Kalra, Santosh Shukla, Jerin Jacob
parse_integer_arg() uses atoi(), which cannot report an error, so a
malformed value such as "abc" becomes zero and the negative check never
fires.
It also stores through an int pointer, while the caller passes
¶ms->nr_port, which is a uint8_t and the only member of a
struct octeontx_vdev_init_params on the stack. Parsing nr_port
therefore wrote three bytes past the field.
Use rte_kvargs_handle_u8(), which both validates the value and matches
the width of the field.
Bugzilla ID: 2036
Fixes: f7be70e5130e ("net/octeontx: add net device probe and remove")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/octeontx/octeontx_ethdev.c | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/drivers/net/octeontx/octeontx_ethdev.c b/drivers/net/octeontx/octeontx_ethdev.c
index e4dca30d9d..d2ad9a7d04 100644
--- a/drivers/net/octeontx/octeontx_ethdev.c
+++ b/drivers/net/octeontx/octeontx_ethdev.c
@@ -65,22 +65,6 @@ RTE_LOG_REGISTER_SUFFIX(otx_net_logtype_mbox, mbox, NOTICE);
RTE_LOG_REGISTER_SUFFIX(otx_net_logtype_init, init, NOTICE);
RTE_LOG_REGISTER_SUFFIX(otx_net_logtype_driver, driver, NOTICE);
-/* Parse integer from integer argument */
-static int
-parse_integer_arg(const char *key __rte_unused,
- const char *value, void *extra_args)
-{
- int *i = (int *)extra_args;
-
- *i = atoi(value);
- if (*i < 0) {
- octeontx_log_err("argument has to be positive.");
- return -1;
- }
-
- return 0;
-}
-
static int
octeontx_parse_vdev_init_params(struct octeontx_vdev_init_params *params,
struct rte_vdev_device *dev)
@@ -106,7 +90,7 @@ octeontx_parse_vdev_init_params(struct octeontx_vdev_init_params *params,
ret = rte_kvargs_process(kvlist,
OCTEONTX_VDEV_NR_PORT_ARG,
- &parse_integer_arg,
+ rte_kvargs_handle_u8,
¶ms->nr_port);
if (ret < 0)
goto free_kvlist;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 32/62] net/octeon_ep: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (30 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 31/62] net/octeontx: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 33/62] net/qede: " Stephen Hemminger
` (29 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Vamsi Attunuru
parse_flag() uses atoi(), which cannot report an error, so a malformed
value is silently taken as zero. The result was only ever used as a
boolean, so use rte_kvargs_handle_bool() and drop the local handler.
This also accepts the usual spellings such as "on" and "true" in
addition to 0 and 1.
The boolean uses rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/octeon_ep/otx_ep_ethdev.c | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)
diff --git a/drivers/net/octeon_ep/otx_ep_ethdev.c b/drivers/net/octeon_ep/otx_ep_ethdev.c
index 876d2f9d7d..cec51dc706 100644
--- a/drivers/net/octeon_ep/otx_ep_ethdev.c
+++ b/drivers/net/octeon_ep/otx_ep_ethdev.c
@@ -29,21 +29,11 @@ static const struct rte_eth_desc_lim otx_ep_tx_desc_lim = {
.nb_align = OTX_EP_TXD_ALIGN,
};
-static int
-parse_flag(const char *key, const char *value, void *extra_args)
-{
- RTE_SET_USED(key);
-
- *(uint8_t *)extra_args = atoi(value);
-
- return 0;
-}
-
static int
otx_ethdev_parse_devargs(struct rte_devargs *devargs, struct otx_ep_device *otx_epvf)
{
struct rte_kvargs *kvlist;
- uint8_t ism_enable = 0;
+ bool ism_enable = false;
if (devargs == NULL)
goto null_devargs;
@@ -52,11 +42,11 @@ otx_ethdev_parse_devargs(struct rte_devargs *devargs, struct otx_ep_device *otx_
if (kvlist == NULL)
goto exit;
- rte_kvargs_process(kvlist, OTX_ISM_ENABLE, &parse_flag, &ism_enable);
+ rte_kvargs_process_opt(kvlist, OTX_ISM_ENABLE, rte_kvargs_handle_bool, &ism_enable);
rte_kvargs_free(kvlist);
null_devargs:
- otx_epvf->ism_ena = !!ism_enable;
+ otx_epvf->ism_ena = ism_enable;
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 33/62] net/qede: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (31 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 32/62] net/octeon_ep: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 34/62] net/nfb: " Stephen Hemminger
` (28 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Devendra Singh Rawat, Alok Prasad
qede_args_check() ignores the end pointer, so "1junk" is accepted, and
uses base 0, so a leading zero silently selects octal.
On failure it returned errno, a positive value, where the kvargs
handler contract expects a negative error code; return -EINVAL.
Both arguments are booleans, so drop qede_args_check() and use
rte_kvargs_handle_bool() on qdev->enable_tx_switching directly. The
handler needed the device only to reach that field and to apply the
VF argument on a VF alone, so the IS_VF() test moves to the caller and
the loop over valid_args[] becomes two explicit calls.
The old handler accepted any integer and reduced it with "!!", so
"vf_txswitch=2" meant true. It is now rejected, along with the other
values that are not booleans. A bare key enables tx-switching.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/qede/qede_ethdev.c | 55 ++++++++++------------------------
1 file changed, 16 insertions(+), 39 deletions(-)
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index 4efc2dd349..5bf70ca2b5 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -1203,39 +1203,14 @@ static const char * const valid_args[] = {
NULL,
};
-static int qede_args_check(const char *key, const char *val, void *opaque)
-{
- unsigned long tmp;
- int ret = 0;
- struct rte_eth_dev *eth_dev = opaque;
- struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
- struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
-
- errno = 0;
- tmp = strtoul(val, NULL, 0);
- if (errno) {
- DP_INFO(edev, "%s: \"%s\" is not a valid integer", key, val);
- return errno;
- }
-
- if ((strcmp(QEDE_NPAR_TX_SWITCHING, key) == 0) ||
- ((strcmp(QEDE_VF_TX_SWITCHING, key) == 0) && IS_VF(edev))) {
- qdev->enable_tx_switching = !!tmp;
- DP_INFO(edev, "Disabling %s tx-switching\n",
- strcmp(QEDE_NPAR_TX_SWITCHING, key) ?
- "VF" : "NPAR");
- }
-
- return ret;
-}
-
static int qede_args(struct rte_eth_dev *eth_dev)
{
struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
+ struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
+ struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
struct rte_kvargs *kvlist;
struct rte_devargs *devargs;
int ret;
- int i;
devargs = pci_dev->device.devargs;
if (!devargs)
@@ -1245,20 +1220,22 @@ static int qede_args(struct rte_eth_dev *eth_dev)
if (kvlist == NULL)
return -EINVAL;
- /* Process parameters. */
- for (i = 0; (valid_args[i] != NULL); ++i) {
- if (rte_kvargs_count(kvlist, valid_args[i])) {
- ret = rte_kvargs_process(kvlist, valid_args[i],
- qede_args_check, eth_dev);
- if (ret != ECORE_SUCCESS) {
- rte_kvargs_free(kvlist);
- return ret;
- }
- }
- }
+ /*
+ * Both arguments select the same thing. The VF one is only honoured
+ * on a VF, which is why the two are handled separately rather than
+ * in a loop over valid_args[].
+ */
+ ret = rte_kvargs_process_opt(kvlist, QEDE_NPAR_TX_SWITCHING,
+ rte_kvargs_handle_bool,
+ &qdev->enable_tx_switching);
+ if (ret == 0 && IS_VF(edev))
+ ret = rte_kvargs_process_opt(kvlist, QEDE_VF_TX_SWITCHING,
+ rte_kvargs_handle_bool,
+ &qdev->enable_tx_switching);
+
rte_kvargs_free(kvlist);
- return 0;
+ return ret;
}
static int qede_dev_configure(struct rte_eth_dev *eth_dev)
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 34/62] net/nfb: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (32 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 33/62] net/qede: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 14:44 ` Martin Spinler
2026-09-14 5:47 ` [PATCH 35/62] net/thunderx: " Stephen Hemminger
` (27 subsequent siblings)
61 siblings, 1 reply; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Martin Spinler
Replace the open coded isdigit(), errno and end pointer checks in
nfb_eth_dev_create_for_ifc_by_port() with a range checked conversion.
The "port >= LONG_MAX" test was redundant with the interface count
check that follows it, since ifc_cnt is far below LONG_MAX.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/nfb/nfb_ethdev.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
index ba7c849a4b..f2ad831c08 100644
--- a/drivers/net/nfb/nfb_ethdev.c
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -965,19 +965,14 @@ static int nfb_eth_dev_create_for_ifc_by_port(const char *key __rte_unused,
const char *value, void *opaque)
{
int ret = -EINVAL;
- char *end;
- unsigned long port;
+ uint64_t port;
struct nfb_ifc_create_params *ifc_params = opaque;
- if (value == NULL || strlen(value) == 0 || !isdigit(*value))
+ if (ifc_params->map_info.ifc_cnt == 0)
goto out;
- errno = 0;
- port = strtoul(value, &end, 10);
- if (errno != 0 || *end != '\0')
- goto out;
-
- if (port >= LONG_MAX || port >= (unsigned long)ifc_params->map_info.ifc_cnt)
+ if (rte_kvargs_to_uint(value, 0, ifc_params->map_info.ifc_cnt - 1,
+ &port) < 0)
goto out;
ifc_params->ifc_info = &ifc_params->map_info.ifc[port];
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 35/62] net/thunderx: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (33 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 34/62] net/nfb: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 36/62] net/i40e: propagate VF queue number parse errors Stephen Hemminger
` (26 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Jerin Jacob, Maciej Czekaj
nicvf_parse_devargs() uses atoi() on the skip_data_bytes value, which
cannot report an error, so a malformed value is silently taken as zero
and the argument is quietly ignored rather than rejected.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/thunderx/nicvf_ethdev.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/net/thunderx/nicvf_ethdev.c b/drivers/net/thunderx/nicvf_ethdev.c
index 6e34da7c3c..7061def01a 100644
--- a/drivers/net/thunderx/nicvf_ethdev.c
+++ b/drivers/net/thunderx/nicvf_ethdev.c
@@ -3,6 +3,7 @@
*/
#include <assert.h>
+#include <limits.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
@@ -2161,9 +2162,17 @@ nicvf_set_first_skip(struct rte_eth_dev *dev)
for (i = 0; i != kvlist->count; ++i) {
const struct rte_kvargs_pair *pair = &kvlist->pairs[i];
+ uint64_t val;
- if (!strcmp(pair->key, SKIP_DATA_BYTES))
- bytes_to_skip = atoi(pair->value);
+ if (strcmp(pair->key, SKIP_DATA_BYTES))
+ continue;
+
+ if (rte_kvargs_to_uint(pair->value, 0, INT_MAX, &val) < 0) {
+ PMD_INIT_LOG(ERR, "skip_data_bytes is not a valid number");
+ ret = -EINVAL;
+ goto exit;
+ }
+ bytes_to_skip = val;
}
/*128 bytes amounts to one cache line*/
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 36/62] net/i40e: propagate VF queue number parse errors
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (34 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 35/62] net/thunderx: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 37/62] net/cnxk: use kvargs numeric helpers Stephen Hemminger
` (25 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson
i40e_pf_config_vf_rxq_number() discarded the rte_kvargs_process() return
value and unconditionally returned success, and its own return value was
then discarded by i40e_pf_parameter_init(). A malformed or out of range
queue-num-per-vf value was therefore silently ignored, leaving the
default in place with no indication to the user.
Every other rte_kvargs_process() call site in this driver already checks
its return value. Do the same here, so that a bad value fails probe
rather than being masked.
rte_kvargs_process() stops at the first failing pair, which preserves
the "first invalid or last valid one is used" behaviour already
documented in the warning above the call.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/intel/i40e/i40e_ethdev.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/intel/i40e/i40e_ethdev.c b/drivers/net/intel/i40e/i40e_ethdev.c
index 3b17281952..a218e9f05e 100644
--- a/drivers/net/intel/i40e/i40e_ethdev.c
+++ b/drivers/net/intel/i40e/i40e_ethdev.c
@@ -4834,6 +4834,7 @@ static int i40e_pf_config_vf_rxq_number(struct rte_eth_dev *dev)
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
struct rte_kvargs *kvlist;
int kvargs_count;
+ int ret;
/* set default queue number per VF as 4 */
pf->vf_nb_qp_max = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF;
@@ -4856,12 +4857,12 @@ static int i40e_pf_config_vf_rxq_number(struct rte_eth_dev *dev)
"the first invalid or last valid one is used !",
ETH_I40E_QUEUE_NUM_PER_VF_ARG);
- rte_kvargs_process(kvlist, ETH_I40E_QUEUE_NUM_PER_VF_ARG,
- i40e_pf_parse_vf_queue_number_handler, pf);
+ ret = rte_kvargs_process(kvlist, ETH_I40E_QUEUE_NUM_PER_VF_ARG,
+ i40e_pf_parse_vf_queue_number_handler, pf);
rte_kvargs_free(kvlist);
- return 0;
+ return ret;
}
static int
@@ -4871,13 +4872,16 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)
struct i40e_hw *hw = I40E_PF_TO_HW(pf);
struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(dev, *pci_dev);
uint16_t qp_count = 0, vsi_count = 0;
+ int ret;
if (pci_dev->max_vfs && !hw->func_caps.sr_iov_1_1) {
PMD_INIT_LOG(ERR, "HW configuration doesn't support SRIOV");
return -EINVAL;
}
- i40e_pf_config_vf_rxq_number(dev);
+ ret = i40e_pf_config_vf_rxq_number(dev);
+ if (ret != 0)
+ return ret;
/* Add the parameter init for LFC */
pf->fc_conf.pause_time = I40E_DEFAULT_PAUSE_TIME;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 37/62] net/cnxk: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (35 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 36/62] net/i40e: propagate VF queue number parse errors Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 38/62] net/xsc: " Stephen Hemminger
` (24 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Nithin Dabilpuram, Kiran Kumar K,
Sunil Kumar Kori, Satha Rao, Harman Kalra
Most handlers in this file used atoi(), which cannot report an error, so
a malformed value was silently taken as zero. Several of them also
assigned a uint32_t into a uint16_t without a range check, so a value
such as "65536" wrapped to zero.
parse_ipsec_in_spi_range(), parse_ipsec_out_max_sa() and
parse_meta_bufsize() went further and deliberately swallowed the error,
setting the value to zero and returning success.
Seven of the handlers were left doing nothing beyond a plain range
checked store, so drop them and pass rte_kvargs_handle_u16() or
rte_kvargs_handle_u32() to rte_kvargs_process() directly. The rest keep
a local handler because they have a narrower range or non-numeric
syntax.
Since the handlers can now fail, propagate the rte_kvargs_process()
return value instead of discarding it, so that a bad argument fails
probe rather than being ignored.
The pre_l2 header and SDP channel mask parsers are left alone: each
packs several fields into one value separated by punctuation, as in
flow_pre_l2_info=0x2/0x7e/0x1, which no single arg_handler_t can parse.
The eleven boolean arguments become bool and use
rte_kvargs_handle_bool(): scalar_enable, tx_compl_ena, tag_as_xor,
lock_rx_ctx, no_inl_dev, custom_sa_act, rx_inj_ena,
custom_meta_aura_dis, custom_inb_sa, force_tail_drop and
disable_xqe_drop. Most of the fields behind them are already bool, so
the "!!" coercions on the way in are no longer needed. A bare key now
enables the option, and the usual spellings are accepted.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/cnxk/cnxk_ethdev_devargs.c | 277 ++++++++-----------------
1 file changed, 91 insertions(+), 186 deletions(-)
diff --git a/drivers/net/cnxk/cnxk_ethdev_devargs.c b/drivers/net/cnxk/cnxk_ethdev_devargs.c
index ea18090919..25ba203027 100644
--- a/drivers/net/cnxk/cnxk_ethdev_devargs.c
+++ b/drivers/net/cnxk/cnxk_ethdev_devargs.c
@@ -5,6 +5,8 @@
#include <inttypes.h>
#include <math.h>
+#include <rte_kvargs.h>
+
#include "cnxk_ethdev.h"
struct sdp_channel {
@@ -19,28 +21,14 @@ struct flow_pre_l2_size_info {
uint8_t pre_l2_size_shift_dir;
};
-static int
-parse_outb_nb_desc(const char *key, const char *value, void *extra_args)
-{
- RTE_SET_USED(key);
- uint32_t val;
-
- val = atoi(value);
-
- *(uint16_t *)extra_args = val;
-
- return 0;
-}
-
static int
parse_outb_nb_crypto_qs(const char *key, const char *value, void *extra_args)
{
- RTE_SET_USED(key);
- uint32_t val;
+ uint64_t val;
- val = atoi(value);
+ RTE_SET_USED(key);
- if (val < 1 || val > 64)
+ if (rte_kvargs_to_uint(value, 1, 64, &val) < 0)
return -EINVAL;
*(uint16_t *)extra_args = val;
@@ -48,51 +36,15 @@ parse_outb_nb_crypto_qs(const char *key, const char *value, void *extra_args)
return 0;
}
-static int
-parse_ipsec_in_spi_range(const char *key, const char *value, void *extra_args)
-{
- RTE_SET_USED(key);
- uint32_t val;
-
- errno = 0;
- val = strtoul(value, NULL, 0);
- if (errno)
- val = 0;
-
- *(uint32_t *)extra_args = val;
-
- return 0;
-}
-
static int
parse_rxc_step(const char *key, const char *value, void *extra_args)
{
- RTE_SET_USED(key);
- uint32_t val;
+ uint64_t val;
- errno = 0;
- val = strtoul(value, NULL, 0);
- if (errno)
- return -EINVAL;
-
- if (val > ROC_NIX_INL_REAS_STEP_MAX)
- return -EINVAL;
-
- *(uint32_t *)extra_args = val;
-
- return 0;
-}
-
-static int
-parse_ipsec_out_max_sa(const char *key, const char *value, void *extra_args)
-{
RTE_SET_USED(key);
- uint32_t val;
- errno = 0;
- val = strtoul(value, NULL, 0);
- if (errno)
- val = 0;
+ if (rte_kvargs_to_uint(value, 0, ROC_NIX_INL_REAS_STEP_MAX, &val) < 0)
+ return -EINVAL;
*(uint32_t *)extra_args = val;
@@ -102,12 +54,11 @@ parse_ipsec_out_max_sa(const char *key, const char *value, void *extra_args)
static int
parse_flow_max_priority(const char *key, const char *value, void *extra_args)
{
- RTE_SET_USED(key);
- uint16_t val;
+ uint64_t val;
- val = atoi(value);
+ RTE_SET_USED(key);
- if (val < 1 || val > ROC_NPC_MAX_MCAM_PRIORITY)
+ if (rte_kvargs_to_uint(value, 1, ROC_NPC_MAX_MCAM_PRIORITY, &val) < 0)
return -EINVAL;
*(uint16_t *)extra_args = val;
@@ -118,13 +69,12 @@ parse_flow_max_priority(const char *key, const char *value, void *extra_args)
static int
parse_flow_prealloc_size(const char *key, const char *value, void *extra_args)
{
- RTE_SET_USED(key);
- uint16_t val;
+ uint64_t val;
- val = atoi(value);
+ RTE_SET_USED(key);
/* Limit the prealloc size to 32 */
- if (val < 1 || val > 32)
+ if (rte_kvargs_to_uint(value, 1, 32, &val) < 0)
return -EINVAL;
*(uint16_t *)extra_args = val;
@@ -135,10 +85,12 @@ parse_flow_prealloc_size(const char *key, const char *value, void *extra_args)
static int
parse_reta_size(const char *key, const char *value, void *extra_args)
{
+ uint64_t val;
+
RTE_SET_USED(key);
- uint32_t val;
- val = atoi(value);
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &val) < 0)
+ return -EINVAL;
if (val <= RTE_ETH_RSS_RETA_SIZE_64)
val = ROC_NIX_RSS_RETA_SZ_64;
@@ -177,45 +129,6 @@ parse_pre_l2_hdr_info(const char *key, const char *value, void *extra_args)
return 0;
}
-static int
-parse_flag(const char *key, const char *value, void *extra_args)
-{
- RTE_SET_USED(key);
-
- *(uint16_t *)extra_args = atoi(value);
-
- return 0;
-}
-
-static int
-parse_sqb_count(const char *key, const char *value, void *extra_args)
-{
- RTE_SET_USED(key);
- uint32_t val;
-
- val = atoi(value);
-
- *(uint16_t *)extra_args = val;
-
- return 0;
-}
-
-static int
-parse_meta_bufsize(const char *key, const char *value, void *extra_args)
-{
- RTE_SET_USED(key);
- uint32_t val;
-
- errno = 0;
- val = strtoul(value, NULL, 0);
- if (errno)
- val = 0;
-
- *(uint32_t *)extra_args = val;
-
- return 0;
-}
-
static int
parse_switch_header_type(const char *key, const char *value, void *extra_args)
{
@@ -248,12 +161,11 @@ parse_switch_header_type(const char *key, const char *value, void *extra_args)
static int
parse_skip_size_info(const char *key, const char *value, void *extra_args)
{
+ uint64_t val;
+
RTE_SET_USED(key);
- uint32_t val;
- errno = 0;
- val = strtoul(value, NULL, 0);
- if (errno || val > 255)
+ if (rte_kvargs_to_uint(value, 0, 255, &val) < 0)
return -EINVAL;
*(uint16_t *)extra_args = val;
@@ -282,19 +194,6 @@ parse_sdp_channel_mask(const char *key, const char *value, void *extra_args)
return 0;
}
-static int
-parse_val_u16(const char *key, const char *value, void *extra_args)
-{
- RTE_SET_USED(key);
- uint16_t val;
-
- val = atoi(value);
-
- *(uint16_t *)extra_args = val;
-
- return 0;
-}
-
#define CNXK_RSS_RETA_SIZE "reta_size"
#define CNXK_SCL_ENABLE "scalar_enable"
#define CNXK_TX_COMPL_ENA "tx_compl_ena"
@@ -334,7 +233,7 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
uint32_t ipsec_in_max_spi = BIT(8) - 1;
uint16_t sqb_slack = ROC_NIX_SQB_SLACK;
uint32_t ipsec_out_max_sa = BIT(12);
- uint16_t custom_meta_aura_dis = 0;
+ bool custom_meta_aura_dis = false;
uint16_t flow_prealloc_size = 1;
uint16_t switch_header_type = 0;
uint16_t skip_size_info = 0;
@@ -343,19 +242,20 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
uint32_t ipsec_in_min_spi = 0;
uint16_t outb_nb_desc = 8200;
struct sdp_channel sdp_chan;
- uint16_t rss_tag_as_xor = 0;
- uint16_t force_tail_drop = 0;
- uint16_t scalar_enable = 0;
- uint16_t tx_compl_ena = 0;
- uint16_t custom_sa_act = 0;
- uint16_t custom_inb_sa = 0;
+ bool rss_tag_as_xor = false;
+ bool force_tail_drop = false;
+ bool scalar_enable = false;
+ bool tx_compl_ena = false;
+ bool custom_sa_act = false;
+ bool custom_inb_sa = false;
struct rte_kvargs *kvlist;
- uint16_t dis_xqe_drop = 0;
+ bool dis_xqe_drop = false;
uint32_t meta_buf_sz = 0;
- uint16_t lock_rx_ctx = 0;
- uint16_t rx_inj_ena = 0;
- uint16_t no_inl_dev = 0;
+ bool lock_rx_ctx = false;
+ bool rx_inj_ena = false;
+ bool no_inl_dev = false;
uint32_t rxc_step = 0;
+ int ret;
memset(&sdp_chan, 0, sizeof(sdp_chan));
memset(&pre_l2_info, 0, sizeof(struct flow_pre_l2_size_info));
@@ -367,60 +267,65 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
if (kvlist == NULL)
goto exit;
- rte_kvargs_process(kvlist, CNXK_RSS_RETA_SIZE, &parse_reta_size,
- &reta_sz);
- rte_kvargs_process(kvlist, CNXK_SCL_ENABLE, &parse_flag,
- &scalar_enable);
- rte_kvargs_process(kvlist, CNXK_TX_COMPL_ENA, &parse_flag,
- &tx_compl_ena);
- rte_kvargs_process(kvlist, CNXK_MAX_SQB_COUNT, &parse_sqb_count,
- &sqb_count);
- rte_kvargs_process(kvlist, CNXK_FLOW_PREALLOC_SIZE,
- &parse_flow_prealloc_size, &flow_prealloc_size);
- rte_kvargs_process(kvlist, CNXK_FLOW_MAX_PRIORITY,
- &parse_flow_max_priority, &flow_max_priority);
- rte_kvargs_process(kvlist, CNXK_SWITCH_HEADER_TYPE,
- &parse_switch_header_type, &switch_header_type);
- rte_kvargs_process(kvlist, CNXK_RSS_TAG_AS_XOR, &parse_flag,
- &rss_tag_as_xor);
- rte_kvargs_process(kvlist, CNXK_LOCK_RX_CTX, &parse_flag, &lock_rx_ctx);
- rte_kvargs_process(kvlist, CNXK_IPSEC_IN_MIN_SPI,
- &parse_ipsec_in_spi_range, &ipsec_in_min_spi);
- rte_kvargs_process(kvlist, CNXK_IPSEC_IN_MAX_SPI,
- &parse_ipsec_in_spi_range, &ipsec_in_max_spi);
- rte_kvargs_process(kvlist, CNXK_IPSEC_OUT_MAX_SA,
- &parse_ipsec_out_max_sa, &ipsec_out_max_sa);
- rte_kvargs_process(kvlist, CNXK_OUTB_NB_DESC, &parse_outb_nb_desc,
- &outb_nb_desc);
- rte_kvargs_process(kvlist, CNXK_OUTB_NB_CRYPTO_QS,
- &parse_outb_nb_crypto_qs, &outb_nb_crypto_qs);
- rte_kvargs_process(kvlist, CNXK_NO_INL_DEV, &parse_flag, &no_inl_dev);
- rte_kvargs_process(kvlist, CNXK_SDP_CHANNEL_MASK,
- &parse_sdp_channel_mask, &sdp_chan);
- rte_kvargs_process(kvlist, CNXK_FLOW_PRE_L2_INFO,
- &parse_pre_l2_hdr_info, &pre_l2_info);
- rte_kvargs_process(kvlist, CNXK_CUSTOM_SA_ACT, &parse_flag,
- &custom_sa_act);
- rte_kvargs_process(kvlist, CNXK_SQB_SLACK, &parse_sqb_count,
- &sqb_slack);
- rte_kvargs_process(kvlist, CNXK_NIX_META_BUF_SZ, &parse_meta_bufsize, &meta_buf_sz);
- rte_kvargs_process(kvlist, CNXK_FLOW_AGING_POLL_FREQ, &parse_val_u16,
- &aging_thread_poll_freq);
- rte_kvargs_process(kvlist, CNXK_NIX_RX_INJ_ENABLE, &parse_flag, &rx_inj_ena);
- rte_kvargs_process(kvlist, CNXK_CUSTOM_META_AURA_DIS, &parse_flag,
- &custom_meta_aura_dis);
- rte_kvargs_process(kvlist, CNXK_CUSTOM_INB_SA, &parse_flag, &custom_inb_sa);
- rte_kvargs_process(kvlist, CNXK_FORCE_TAIL_DROP, &parse_flag, &force_tail_drop);
- rte_kvargs_process(kvlist, CNXK_DIS_XQE_DROP, &parse_flag, &dis_xqe_drop);
- rte_kvargs_process(kvlist, CNXK_RXC_STEP, &parse_rxc_step, &rxc_step);
- rte_kvargs_process(kvlist, CNXK_SKIP_SIZE_INFO, &parse_skip_size_info,
- &skip_size_info);
+ ret = 0;
+ ret |= rte_kvargs_process(kvlist, CNXK_RSS_RETA_SIZE, &parse_reta_size,
+ &reta_sz);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_SCL_ENABLE, rte_kvargs_handle_bool,
+ &scalar_enable);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_TX_COMPL_ENA, rte_kvargs_handle_bool,
+ &tx_compl_ena);
+ ret |= rte_kvargs_process(kvlist, CNXK_MAX_SQB_COUNT, rte_kvargs_handle_u16,
+ &sqb_count);
+ ret |= rte_kvargs_process(kvlist, CNXK_FLOW_PREALLOC_SIZE,
+ &parse_flow_prealloc_size, &flow_prealloc_size);
+ ret |= rte_kvargs_process(kvlist, CNXK_FLOW_MAX_PRIORITY,
+ &parse_flow_max_priority, &flow_max_priority);
+ ret |= rte_kvargs_process(kvlist, CNXK_SWITCH_HEADER_TYPE,
+ &parse_switch_header_type, &switch_header_type);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_RSS_TAG_AS_XOR, rte_kvargs_handle_bool,
+ &rss_tag_as_xor);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_LOCK_RX_CTX, rte_kvargs_handle_bool, &lock_rx_ctx);
+ ret |= rte_kvargs_process(kvlist, CNXK_IPSEC_IN_MIN_SPI,
+ rte_kvargs_handle_u32, &ipsec_in_min_spi);
+ ret |= rte_kvargs_process(kvlist, CNXK_IPSEC_IN_MAX_SPI,
+ rte_kvargs_handle_u32, &ipsec_in_max_spi);
+ ret |= rte_kvargs_process(kvlist, CNXK_IPSEC_OUT_MAX_SA,
+ rte_kvargs_handle_u32, &ipsec_out_max_sa);
+ ret |= rte_kvargs_process(kvlist, CNXK_OUTB_NB_DESC, rte_kvargs_handle_u16,
+ &outb_nb_desc);
+ ret |= rte_kvargs_process(kvlist, CNXK_OUTB_NB_CRYPTO_QS,
+ &parse_outb_nb_crypto_qs, &outb_nb_crypto_qs);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_NO_INL_DEV, rte_kvargs_handle_bool, &no_inl_dev);
+ ret |= rte_kvargs_process(kvlist, CNXK_SDP_CHANNEL_MASK,
+ &parse_sdp_channel_mask, &sdp_chan);
+ ret |= rte_kvargs_process(kvlist, CNXK_FLOW_PRE_L2_INFO,
+ &parse_pre_l2_hdr_info, &pre_l2_info);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_CUSTOM_SA_ACT, rte_kvargs_handle_bool,
+ &custom_sa_act);
+ ret |= rte_kvargs_process(kvlist, CNXK_SQB_SLACK, rte_kvargs_handle_u16,
+ &sqb_slack);
+ ret |= rte_kvargs_process(kvlist, CNXK_NIX_META_BUF_SZ, rte_kvargs_handle_u32, &meta_buf_sz);
+ ret |= rte_kvargs_process(kvlist, CNXK_FLOW_AGING_POLL_FREQ, rte_kvargs_handle_u16,
+ &aging_thread_poll_freq);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_NIX_RX_INJ_ENABLE, rte_kvargs_handle_bool, &rx_inj_ena);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_CUSTOM_META_AURA_DIS, rte_kvargs_handle_bool,
+ &custom_meta_aura_dis);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_CUSTOM_INB_SA, rte_kvargs_handle_bool, &custom_inb_sa);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_FORCE_TAIL_DROP, rte_kvargs_handle_bool,
+ &force_tail_drop);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_DIS_XQE_DROP, rte_kvargs_handle_bool, &dis_xqe_drop);
+ ret |= rte_kvargs_process(kvlist, CNXK_RXC_STEP, &parse_rxc_step, &rxc_step);
+ ret |= rte_kvargs_process(kvlist, CNXK_SKIP_SIZE_INFO, &parse_skip_size_info,
+ &skip_size_info);
rte_kvargs_free(kvlist);
+ if (ret != 0)
+ goto exit;
+
null_devargs:
- dev->scalar_ena = !!scalar_enable;
- dev->tx_compl_ena = !!tx_compl_ena;
- dev->inb.no_inl_dev = !!no_inl_dev;
+ dev->scalar_ena = scalar_enable;
+ dev->tx_compl_ena = tx_compl_ena;
+ dev->inb.no_inl_dev = no_inl_dev;
dev->inb.min_spi = ipsec_in_min_spi;
dev->inb.max_spi = ipsec_in_max_spi;
dev->inb.custom_meta_aura_dis = custom_meta_aura_dis;
@@ -428,7 +333,7 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
dev->outb.nb_desc = outb_nb_desc;
dev->outb.nb_crypto_qs = outb_nb_crypto_qs;
dev->nix.ipsec_out_max_sa = ipsec_out_max_sa;
- dev->nix.rss_tag_as_xor = !!rss_tag_as_xor;
+ dev->nix.rss_tag_as_xor = rss_tag_as_xor;
dev->nix.max_sqb_count = sqb_count;
dev->nix.reta_sz = reta_sz;
dev->nix.lock_rx_ctx = lock_rx_ctx;
@@ -458,7 +363,7 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
if (roc_feature_nix_has_rx_inject())
dev->nix.rx_inj_ena = rx_inj_ena;
dev->nix.force_tail_drop = force_tail_drop;
- dev->nix.dis_xqe_drop = !!dis_xqe_drop;
+ dev->nix.dis_xqe_drop = dis_xqe_drop;
dev->nix.rxc_step = rxc_step;
return 0;
exit:
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 38/62] net/xsc: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (36 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 37/62] net/cnxk: use kvargs numeric helpers Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 39/62] net/hns3: " Stephen Hemminger
` (23 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Renyong Wan, Na Na, Rong Qian, Xiaoxiong Zhang,
Dongwei Xu
xsc_dev_args_parse() uses atoi() on each value, which cannot report an
error, so a malformed argument is silently taken as zero. For pph_mode
and nic_mode zero is a meaningful setting, so a typo quietly selects a
mode rather than being rejected.
Fold the three copies of the lookup into a helper that range checks the
value and leaves the default in place when it is rejected. The defaults
are now assigned up front so they also apply on error.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/xsc/xsc_dev.c | 50 +++++++++++++++++++++++++--------------
1 file changed, 32 insertions(+), 18 deletions(-)
diff --git a/drivers/net/xsc/xsc_dev.c b/drivers/net/xsc/xsc_dev.c
index 478f489516..78a0984295 100644
--- a/drivers/net/xsc/xsc_dev.c
+++ b/drivers/net/xsc/xsc_dev.c
@@ -199,34 +199,48 @@ xsc_dev_alloc_vfos_info(struct xsc_dev *xdev)
return 0;
}
+/* Parse one optional numeric devarg, leaving the default in place if unset. */
+static void
+xsc_dev_arg_get(struct rte_kvargs *kvlist, const char *key, uint64_t max,
+ int *result)
+{
+ const char *value;
+ uint64_t val;
+
+ value = rte_kvargs_get(kvlist, key);
+ if (value == NULL)
+ return;
+
+ if (rte_kvargs_to_uint(value, 0, max, &val) < 0) {
+ PMD_DRV_LOG(ERR, "Invalid %s \"%s\", using default %d",
+ key, value, *result);
+ return;
+ }
+
+ *result = val;
+}
+
static void
xsc_dev_args_parse(struct xsc_dev *xdev, struct rte_devargs *devargs)
{
struct rte_kvargs *kvlist;
struct xsc_devargs *xdevargs = &xdev->devargs;
- const char *tmp;
+
+ xdevargs->pph_mode = XSC_PPH_NONE;
+ xdevargs->nic_mode = XSC_NIC_MODE_LEGACY;
+ xdevargs->flow_mode = XSC_DEV_DEF_FLOW_MODE;
kvlist = rte_kvargs_parse(devargs->args, NULL);
if (kvlist == NULL)
return;
- tmp = rte_kvargs_get(kvlist, XSC_PPH_MODE_ARG);
- if (tmp != NULL)
- xdevargs->pph_mode = atoi(tmp);
- else
- xdevargs->pph_mode = XSC_PPH_NONE;
-
- tmp = rte_kvargs_get(kvlist, XSC_NIC_MODE_ARG);
- if (tmp != NULL)
- xdevargs->nic_mode = atoi(tmp);
- else
- xdevargs->nic_mode = XSC_NIC_MODE_LEGACY;
-
- tmp = rte_kvargs_get(kvlist, XSC_FLOW_MODE_ARG);
- if (tmp != NULL)
- xdevargs->flow_mode = atoi(tmp);
- else
- xdevargs->flow_mode = XSC_DEV_DEF_FLOW_MODE;
+ xsc_dev_arg_get(kvlist, XSC_PPH_MODE_ARG,
+ XSC_RX_PPH | XSC_TX_PPH | XSC_VFREP_PPH | XSC_UPLINK_PPH,
+ &xdevargs->pph_mode);
+ xsc_dev_arg_get(kvlist, XSC_NIC_MODE_ARG, XSC_NIC_MODE_SOC,
+ &xdevargs->nic_mode);
+ xsc_dev_arg_get(kvlist, XSC_FLOW_MODE_ARG, INT_MAX,
+ &xdevargs->flow_mode);
rte_kvargs_free(kvlist);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 39/62] net/hns3: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (37 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 38/62] net/xsc: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 40/62] net/enetc: " Stephen Hemminger
` (22 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Xingui Yang, Chengwen Feng
hns3_parse_mbx_time_limit() checks neither errno nor the end pointer, so
a malformed value such as "abc" is taken as zero and then silently
ignored by the range test that follows.
The range test is now part of the conversion, which keeps the existing
behaviour of leaving the default in place when the value is out of
range.
The device capability mask parser is converted separately, later in this
series, since it needs the hexadecimal handler rather than a decimal one.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/hns3/hns3_common.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 29b51856d9..c21740ba5e 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -231,14 +231,13 @@ hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
if (value == NULL || extra_args == NULL)
return 0;
- val = strtoul(value, NULL, HNS3_CONVERT_TO_DECIMAL);
-
/*
* 500ms is empirical value in process of mailbox communication. If
* the delay value is set to one lower than the empirical value, mailbox
* communication may fail.
*/
- if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
+ if (rte_kvargs_to_uint(value, HNS3_MBX_DEF_TIME_LIMIT_MS + 1,
+ UINT16_MAX, &val) == 0)
*(uint16_t *)extra_args = val;
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 40/62] net/enetc: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (38 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 39/62] net/hns3: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 41/62] event/dlb2: " Stephen Hemminger
` (21 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Gagandeep Singh, Sachin Saxena,
Vanshika Shukla
The VSI timeout and delay arguments are parsed with strtoul() without
checking the end pointer, so a value such as "10abc" is accepted. They
are also assigned into a uint32_t before being validated, so a value
above UINT32_MAX is truncated and only rejected if it happens to
truncate to zero.
Report the offending string rather than the truncated value, which was
not meaningful once the conversion had failed.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/enetc/enetc4_vf.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c
index ef5f1e6d66..18bbffc255 100644
--- a/drivers/net/enetc/enetc4_vf.c
+++ b/drivers/net/enetc/enetc4_vf.c
@@ -1359,28 +1359,30 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev)
/* parse optional VSI-PSI timeout devarg */
val = rte_kvargs_get(kvlist, ENETC4_VSI_TIMEOUT);
if (val) {
- errno = 0;
- hw->vsi_timeout = (uint32_t)strtoul(val, NULL, 0);
- if (errno != 0 || hw->vsi_timeout == 0) {
- ENETC_PMD_ERR("Invalid VSI Timeout value = %u",
- hw->vsi_timeout);
+ uint64_t num;
+
+ if (rte_kvargs_to_uint(val, 1, UINT32_MAX, &num) < 0) {
+ ENETC_PMD_ERR("Invalid VSI Timeout value = %s",
+ val);
rte_kvargs_free(kvlist);
return -1;
}
+ hw->vsi_timeout = num;
ENETC_PMD_NOTICE("VSI timeout set to %u", hw->vsi_timeout);
}
/* parse optional VSI-PSI delay devarg */
val = rte_kvargs_get(kvlist, ENETC4_VSI_DELAY);
if (val) {
- errno = 0;
- hw->vsi_delay = (uint32_t)strtoul(val, NULL, 0);
- if (errno != 0 || hw->vsi_delay == 0) {
- ENETC_PMD_ERR("Invalid VSI Delay value = %u",
- hw->vsi_delay);
+ uint64_t num;
+
+ if (rte_kvargs_to_uint(val, 1, UINT32_MAX, &num) < 0) {
+ ENETC_PMD_ERR("Invalid VSI Delay value = %s",
+ val);
rte_kvargs_free(kvlist);
return -1;
}
+ hw->vsi_delay = num;
ENETC_PMD_NOTICE("VSI delay set to %u us", hw->vsi_delay);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 41/62] event/dlb2: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (39 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 40/62] net/enetc: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 42/62] net/nfp: " Stephen Hemminger
` (20 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Tirthendu Sarkar
dlb2_string_to_int() returns -errno on failure, but errno is only
meaningful when strtol() actually failed; on a plain parse failure it
returns -0, that is success, with an uninitialised result. The end
pointer is also only checked after the errno test, so "abc" reaches the
range check with a value of zero.
All thirteen dlb2 devargs handlers go through this one function, so
converting it covers them all.
set_numa_node() is replaced by rte_kvargs_handle_socket_id(). It used
"> RTE_MAX_NUMA_NODES", which is off by one and accepted a socket id one
past the end of the range, so that value is now rejected. The helper
also rejects a negative socket id other than -1, which is SOCKET_ID_ANY.
The four boolean arguments use rte_kvargs_handle_bool() and their local
handlers go away: vector_opts_enable, default_ldb_port_allocation,
enable_cq_weight and use_default_hl.
Beware that this changes what the first three accept. They only ever
tested for a leading 'y' or 'Y', so "=1" meant false, and any typo
silently meant false as well. They now take the usual boolean
spellings, "=1" means true, and anything else is rejected. The
documented "=<y/Y>" form still works; the examples are updated to the
more usual "=<0|1>". use_default_hl already treated '0' and 'n' as
false and everything else as true, so only the rejection of garbage
is new there.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
doc/guides/eventdevs/dlb2.rst | 4 +-
drivers/event/dlb2/dlb2.c | 127 ++++------------------------------
2 files changed, 14 insertions(+), 117 deletions(-)
diff --git a/doc/guides/eventdevs/dlb2.rst b/doc/guides/eventdevs/dlb2.rst
index 06841ba312..0966746f4e 100644
--- a/doc/guides/eventdevs/dlb2.rst
+++ b/doc/guides/eventdevs/dlb2.rst
@@ -380,7 +380,7 @@ follows
.. code-block:: console
- --allow ea:00.0,vector_opts_enabled=<y/Y>
+ --allow ea:00.0,vector_opts_enabled=<0|1>
Maximum CQ Depth
~~~~~~~~~~~~~~~~
@@ -459,7 +459,7 @@ Example command to enable QE Weight feature:
.. code-block:: console
- --allow ea:00.0,enable_cq_weight=<y/Y>
+ --allow ea:00.0,enable_cq_weight=<0|1>
Credit Handling Scenario Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/drivers/event/dlb2/dlb2.c b/drivers/event/dlb2/dlb2.c
index 084875f1c8..b3eceab094 100644
--- a/drivers/event/dlb2/dlb2.c
+++ b/drivers/event/dlb2/dlb2.c
@@ -288,24 +288,15 @@ dlb2_hw_query_resources(struct dlb2_eventdev *dlb2)
return 0;
}
-#define DLB2_BASE_10 10
-
static int
dlb2_string_to_int(int *result, const char *str)
{
- long ret;
- char *endptr;
+ int64_t ret;
- if (str == NULL || result == NULL)
+ if (result == NULL)
return -EINVAL;
- errno = 0;
- ret = strtol(str, &endptr, DLB2_BASE_10);
- if (errno)
- return -errno;
-
- /* long int and int may be different width for some architectures */
- if (ret < INT_MIN || ret > INT_MAX || endptr == str)
+ if (rte_kvargs_to_int(str, INT_MIN, INT_MAX, &ret) < 0)
return -EINVAL;
*result = ret;
@@ -329,22 +320,6 @@ set_producer_coremask(const char *key __rte_unused,
return 0;
}
-static int
-set_numa_node(const char *key __rte_unused, const char *value, void *opaque)
-{
- int *socket_id = opaque;
- int ret;
-
- ret = dlb2_string_to_int(socket_id, value);
- if (ret < 0)
- return ret;
-
- if (*socket_id > RTE_MAX_NUMA_NODES)
- return -EINVAL;
- return 0;
-}
-
-
static int
set_max_cq_depth(const char *key __rte_unused,
const char *value,
@@ -667,84 +642,6 @@ set_default_depth_thresh(const char *key __rte_unused,
return 0;
}
-static int
-set_vector_opts_enab(const char *key __rte_unused,
- const char *value,
- void *opaque)
-{
- bool *dlb2_vector_opts_enabled = opaque;
-
- if (value == NULL || opaque == NULL) {
- DLB2_LOG_ERR("NULL pointer");
- return -EINVAL;
- }
-
- if ((*value == 'y') || (*value == 'Y'))
- *dlb2_vector_opts_enabled = true;
- else
- *dlb2_vector_opts_enabled = false;
-
- return 0;
-}
-
-static int
-set_default_ldb_port_allocation(const char *key __rte_unused,
- const char *value,
- void *opaque)
-{
- bool *default_ldb_port_allocation = opaque;
-
- if (value == NULL || opaque == NULL) {
- DLB2_LOG_ERR("NULL pointer");
- return -EINVAL;
- }
-
- if ((*value == 'y') || (*value == 'Y'))
- *default_ldb_port_allocation = true;
- else
- *default_ldb_port_allocation = false;
-
- return 0;
-}
-
-static int
-set_enable_cq_weight(const char *key __rte_unused,
- const char *value,
- void *opaque)
-{
- bool *enable_cq_weight = opaque;
-
- if (value == NULL || opaque == NULL) {
- DLB2_LOG_ERR("NULL pointer");
- return -EINVAL;
- }
-
- if ((*value == 'y') || (*value == 'Y'))
- *enable_cq_weight = true;
- else
- *enable_cq_weight = false;
-
- return 0;
-}
-
-static int set_hl_override(const char *key __rte_unused, const char *value,
- void *opaque)
-{
- bool *default_hl = opaque;
-
- if (value == NULL || opaque == NULL) {
- DLB2_LOG_ERR("NULL pointer");
- return -EINVAL;
- }
-
- if ((*value == 'n') || (*value == 'N') || (*value == '0'))
- *default_hl = false;
- else
- *default_hl = true;
-
- return 0;
-}
-
static int set_hl_entries(const char *key __rte_unused, const char *value,
void *opaque)
{
@@ -5223,7 +5120,7 @@ dlb2_parse_params(const char *params,
name);
} else {
int ret = rte_kvargs_process(kvlist, NUMA_NODE_ARG,
- set_numa_node,
+ rte_kvargs_handle_socket_id,
&dlb2_args->socket_id);
if (ret != 0) {
DLB2_LOG_ERR("%s: Error parsing numa node parameter",
@@ -5335,9 +5232,9 @@ dlb2_parse_params(const char *params,
return ret;
}
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
DLB2_VECTOR_OPTS_ENAB_ARG,
- set_vector_opts_enab,
+ rte_kvargs_handle_bool,
&dlb2_args->vector_opts_enabled);
if (ret != 0) {
DLB2_LOG_ERR("%s: Error parsing vector opts enabled",
@@ -5403,9 +5300,9 @@ dlb2_parse_params(const char *params,
return ret;
}
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
DLB2_DEFAULT_LDB_PORT_ALLOCATION_ARG,
- set_default_ldb_port_allocation,
+ rte_kvargs_handle_bool,
&dlb2_args->default_ldb_port_allocation);
if (ret != 0) {
DLB2_LOG_ERR("%s: Error parsing ldb default port allocation arg",
@@ -5414,9 +5311,9 @@ dlb2_parse_params(const char *params,
return ret;
}
- ret = rte_kvargs_process(kvlist,
+ ret = rte_kvargs_process_opt(kvlist,
DLB2_ENABLE_CQ_WEIGHT_ARG,
- set_enable_cq_weight,
+ rte_kvargs_handle_bool,
&dlb2_args->enable_cq_weight);
if (ret != 0) {
DLB2_LOG_ERR("%s: Error parsing enable_cq_weight arg",
@@ -5427,8 +5324,8 @@ dlb2_parse_params(const char *params,
if (version == DLB2_HW_V2 && dlb2_args->enable_cq_weight)
DLB2_LOG_INFO("Ignoring 'enable_cq_weight=y'. Only supported for 2.5 HW onwards");
- ret = rte_kvargs_process(kvlist, DLB2_USE_DEFAULT_HL,
- set_hl_override,
+ ret = rte_kvargs_process_opt(kvlist, DLB2_USE_DEFAULT_HL,
+ rte_kvargs_handle_bool,
&dlb2_args->use_default_hl);
if (ret != 0) {
DLB2_LOG_ERR("%s: Error parsing hl_override arg",
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 42/62] net/nfp: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (40 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 41/62] event/dlb2: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 43/62] drivers/crypto: " Stephen Hemminger
` (19 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Chaoyong He
nfp_devarg_handle_int() infers overflow from the result being ULONG_MAX
rather than checking errno, so the literal value 18446744073709551615 is
rejected while a genuine overflow of any other value is not detected.
Both users of it parse a boolean, so use rte_kvargs_handle_bool() and
drop the local handler along with the open coded 0/1 check. The
documented "=0" and "=1" forms still work, and the usual spellings such
as "on" and "true" are now accepted as well.
The boolean uses rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/nfp/nfp_ethdev.c | 36 ++----------------------------------
1 file changed, 2 insertions(+), 34 deletions(-)
diff --git a/drivers/net/nfp/nfp_ethdev.c b/drivers/net/nfp/nfp_ethdev.c
index d2da18013c..37005a3cea 100644
--- a/drivers/net/nfp/nfp_ethdev.c
+++ b/drivers/net/nfp/nfp_ethdev.c
@@ -48,28 +48,6 @@ struct nfp_net_init {
struct nfp_net_hw_priv *hw_priv;
};
-static int
-nfp_devarg_handle_int(const char *key,
- const char *value,
- void *extra_args)
-{
- char *end_ptr;
- uint64_t *num = extra_args;
-
- if (value == NULL)
- return -EPERM;
-
- *num = strtoul(value, &end_ptr, 10);
- if (*num == ULONG_MAX) {
- PMD_DRV_LOG(ERR, "%s: '%s' is not a valid param.", key, value);
- return -ERANGE;
- } else if (value == end_ptr) {
- return -EPERM;
- }
-
- return 0;
-}
-
static int
nfp_devarg_parse_bool_para(struct rte_kvargs *kvlist,
const char *key_match,
@@ -77,7 +55,6 @@ nfp_devarg_parse_bool_para(struct rte_kvargs *kvlist,
{
int ret;
uint32_t count;
- uint64_t value;
count = rte_kvargs_count(kvlist, key_match);
if (count == 0)
@@ -88,20 +65,11 @@ nfp_devarg_parse_bool_para(struct rte_kvargs *kvlist,
return -EINVAL;
}
- ret = rte_kvargs_process(kvlist, key_match, &nfp_devarg_handle_int, &value);
+ ret = rte_kvargs_process_opt(kvlist, key_match, rte_kvargs_handle_bool,
+ value_ret);
if (ret != 0)
return -EINVAL;
- if (value == 1) {
- *value_ret = true;
- } else if (value == 0) {
- *value_ret = false;
- } else {
- PMD_DRV_LOG(ERR, "The param does not work, the format is %s=0/1.",
- key_match);
- return -EINVAL;
- }
-
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 43/62] drivers/crypto: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (41 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 42/62] net/nfp: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 44/62] event/sw: " Stephen Hemminger
` (18 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Gagandeep Singh, Hemant Agrawal
The dump mode handlers use atoi(), which cannot report an error, so a
malformed value is silently taken as zero, which disables dumping
entirely rather than being rejected.
Out of range values keep being clamped to the full dump level, as
before.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 15 ++++++++++++---
drivers/crypto/dpaa_sec/dpaa_sec.c | 17 +++++++++++++----
2 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 3d980d096f..93e92af6a7 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -4342,13 +4342,22 @@ check_devargs_handler(const char *key, const char *value,
if (!strcmp(key, "drv_strict_order")) {
priv->en_loose_ordered = false;
} else if (!strcmp(key, "drv_dump_mode")) {
- dpaa2_sec_dp_dump = atoi(value);
- if (dpaa2_sec_dp_dump > DPAA2_SEC_DP_FULL_DUMP) {
+ uint64_t val;
+
+ if (rte_kvargs_to_uint(value, 0, UINT8_MAX, &val) < 0) {
+ DPAA2_SEC_WARN("WARN: invalid value \"%s\" for \"%s\"",
+ value, key);
+ return -EINVAL;
+ }
+
+ if (val > DPAA2_SEC_DP_FULL_DUMP) {
DPAA2_SEC_WARN("WARN: DPAA2_SEC_DP_DUMP_LEVEL is not "
"supported, changing to FULL error"
" prints");
- dpaa2_sec_dp_dump = DPAA2_SEC_DP_FULL_DUMP;
+ val = DPAA2_SEC_DP_FULL_DUMP;
}
+
+ dpaa2_sec_dp_dump = val;
} else
return -1;
diff --git a/drivers/crypto/dpaa_sec/dpaa_sec.c b/drivers/crypto/dpaa_sec/dpaa_sec.c
index c53ee70853..3feb752bcd 100644
--- a/drivers/crypto/dpaa_sec/dpaa_sec.c
+++ b/drivers/crypto/dpaa_sec/dpaa_sec.c
@@ -3625,16 +3625,25 @@ dpaa_sec_uninit(struct rte_cryptodev *dev)
}
static int
-check_devargs_handler(__rte_unused const char *key, const char *value,
+check_devargs_handler(const char *key, const char *value,
__rte_unused void *opaque)
{
- dpaa_sec_dp_dump = atoi(value);
- if (dpaa_sec_dp_dump > DPAA_SEC_DP_FULL_DUMP) {
+ uint64_t val;
+
+ if (rte_kvargs_to_uint(value, 0, UINT8_MAX, &val) < 0) {
+ DPAA_SEC_WARN("WARN: invalid value \"%s\" for \"%s\"",
+ value, key);
+ return -EINVAL;
+ }
+
+ if (val > DPAA_SEC_DP_FULL_DUMP) {
DPAA_SEC_WARN("WARN: DPAA_SEC_DP_DUMP_LEVEL is not "
"supported, changing to FULL error prints");
- dpaa_sec_dp_dump = DPAA_SEC_DP_FULL_DUMP;
+ val = DPAA_SEC_DP_FULL_DUMP;
}
+ dpaa_sec_dp_dump = val;
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 44/62] event/sw: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (42 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 43/62] drivers/crypto: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 45/62] net/bnxt: " Stephen Hemminger
` (17 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
All six handlers use atoi(), which cannot report an error, so a
malformed value is silently taken as zero. Since zero is within the
accepted range for every one of these arguments, a typo such as
"sched_quanta=abc" was accepted and quietly applied as zero.
The lower bound is now part of the conversion, so the separate negative
checks are no longer needed.
refill_once is a boolean, so drop set_refill_once() and use
rte_kvargs_handle_bool(). The registered parameter string said
"=<int>", which was never true, and now says "=<0|1>". A bare
"refill_once" enables it, and the usual spellings are accepted.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/event/sw/sw_evdev.c | 56 ++++++++++++++++---------------------
1 file changed, 24 insertions(+), 32 deletions(-)
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 3ad82e94ac..fa9fe3e4c2 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -872,23 +872,16 @@ sw_close(struct rte_eventdev *dev)
return 0;
}
-static int
-assign_numa_node(const char *key __rte_unused, const char *value, void *opaque)
-{
- int *socket_id = opaque;
- *socket_id = atoi(value);
- if (*socket_id >= RTE_MAX_NUMA_NODES)
- return -1;
- return 0;
-}
-
static int
set_sched_quanta(const char *key __rte_unused, const char *value, void *opaque)
{
int *quanta = opaque;
- *quanta = atoi(value);
- if (*quanta < 0 || *quanta >= 4096)
+ uint64_t val;
+
+ if (rte_kvargs_to_uint(value, 0, 4095, &val) < 0)
return -1;
+
+ *quanta = val;
return 0;
}
@@ -896,9 +889,12 @@ static int
set_credit_quanta(const char *key __rte_unused, const char *value, void *opaque)
{
int *credit = opaque;
- *credit = atoi(value);
- if (*credit < 0 || *credit >= 128)
+ uint64_t val;
+
+ if (rte_kvargs_to_uint(value, 0, 127, &val) < 0)
return -1;
+
+ *credit = val;
return 0;
}
@@ -906,9 +902,12 @@ static int
set_deq_burst_sz(const char *key __rte_unused, const char *value, void *opaque)
{
int *deq_burst_sz = opaque;
- *deq_burst_sz = atoi(value);
- if (*deq_burst_sz < 0 || *deq_burst_sz > SCHED_DEQUEUE_MAX_BURST_SIZE)
+ uint64_t val;
+
+ if (rte_kvargs_to_uint(value, 0, SCHED_DEQUEUE_MAX_BURST_SIZE, &val) < 0)
return -1;
+
+ *deq_burst_sz = val;
return 0;
}
@@ -916,19 +915,12 @@ static int
set_min_burst_sz(const char *key __rte_unused, const char *value, void *opaque)
{
int *min_burst_sz = opaque;
- *min_burst_sz = atoi(value);
- if (*min_burst_sz < 0 || *min_burst_sz > SCHED_DEQUEUE_MAX_BURST_SIZE)
- return -1;
- return 0;
-}
+ uint64_t val;
-static int
-set_refill_once(const char *key __rte_unused, const char *value, void *opaque)
-{
- int *refill_once_per_call = opaque;
- *refill_once_per_call = atoi(value);
- if (*refill_once_per_call < 0 || *refill_once_per_call > 1)
+ if (rte_kvargs_to_uint(value, 0, SCHED_DEQUEUE_MAX_BURST_SIZE, &val) < 0)
return -1;
+
+ *min_burst_sz = val;
return 0;
}
@@ -991,7 +983,7 @@ sw_probe(struct rte_vdev_device *vdev)
int credit_quanta = SW_DEFAULT_CREDIT_QUANTA;
int min_burst_size = 1;
int deq_burst_size = SCHED_DEQUEUE_DEFAULT_BURST_SIZE;
- int refill_once = 0;
+ bool refill_once = false;
name = rte_vdev_device_name(vdev);
params = rte_vdev_device_args(vdev);
@@ -1004,7 +996,7 @@ sw_probe(struct rte_vdev_device *vdev)
name);
} else {
int ret = rte_kvargs_process(kvlist, NUMA_NODE_ARG,
- assign_numa_node, &socket_id);
+ rte_kvargs_handle_socket_id, &socket_id);
if (ret != 0) {
SW_LOG_ERR(
"%s: Error parsing numa node parameter",
@@ -1053,8 +1045,8 @@ sw_probe(struct rte_vdev_device *vdev)
return ret;
}
- ret = rte_kvargs_process(kvlist, REFIL_ONCE_ARG,
- set_refill_once, &refill_once);
+ ret = rte_kvargs_process_opt(kvlist, REFIL_ONCE_ARG,
+ rte_kvargs_handle_bool, &refill_once);
if (ret != 0) {
SW_LOG_ERR(
"%s: Error parsing refill once per call switch",
@@ -1146,5 +1138,5 @@ RTE_PMD_REGISTER_VDEV(EVENTDEV_NAME_SW_PMD, evdev_sw_pmd_drv);
RTE_PMD_REGISTER_PARAM_STRING(event_sw, NUMA_NODE_ARG "=<int> "
SCHED_QUANTA_ARG "=<int>" CREDIT_QUANTA_ARG "=<int>"
MIN_BURST_SIZE_ARG "=<int>" DEQ_BURST_SIZE_ARG "=<int>"
- REFIL_ONCE_ARG "=<int>");
+ REFIL_ONCE_ARG "=<0|1>");
RTE_LOG_REGISTER_DEFAULT(eventdev_sw_log_level, NOTICE);
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 45/62] net/bnxt: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (43 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 44/62] event/sw: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 46/62] net/bnxt: propagate devargs parsing errors Stephen Hemminger
` (16 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Kishore Padmanabha, Ajit Khaparde
All fourteen handlers repeat the same open coded conversion, testing
errno for ERANGE without ever clearing it first. A stale ERANGE left by
earlier code therefore rejects a valid value, and the test only fires at
all when the result happens to be ULONG_MAX.
The per-argument range checks are left as they are, since they carry the
documented limits for each devarg.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/bnxt/bnxt_ethdev.c | 106 ++++++++++-----------------------
1 file changed, 32 insertions(+), 74 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 8e8ead8f61..4903f6fb10 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -5866,8 +5866,7 @@ bnxt_parse_devarg_flow_xstat(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt *bp = opaque_arg;
- unsigned long flow_xstat;
- char *end = NULL;
+ uint64_t flow_xstat;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -5875,9 +5874,7 @@ bnxt_parse_devarg_flow_xstat(__rte_unused const char *key,
return -EINVAL;
}
- flow_xstat = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (flow_xstat == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &flow_xstat) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to flow_xstat devarg.");
return -EINVAL;
@@ -5901,8 +5898,7 @@ bnxt_parse_devarg_max_num_kflows(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt *bp = opaque_arg;
- unsigned long max_num_kflows;
- char *end = NULL;
+ uint64_t max_num_kflows;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -5910,9 +5906,7 @@ bnxt_parse_devarg_max_num_kflows(__rte_unused const char *key,
return -EINVAL;
}
- max_num_kflows = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (max_num_kflows == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &max_num_kflows) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to max_num_kflows devarg.");
return -EINVAL;
@@ -5926,8 +5920,8 @@ bnxt_parse_devarg_max_num_kflows(__rte_unused const char *key,
bp->max_num_kflows = max_num_kflows;
if (bp->max_num_kflows)
- PMD_DRV_LOG_LINE(INFO, "max_num_kflows set as %ldK.",
- max_num_kflows);
+ PMD_DRV_LOG_LINE(INFO, "max_num_kflows set as %uK.",
+ (unsigned int)max_num_kflows);
return 0;
}
@@ -5937,8 +5931,7 @@ bnxt_parse_devarg_cqe_mode(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt *bp = opaque_arg;
- unsigned long cqe_mode;
- char *end = NULL;
+ uint64_t cqe_mode;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -5947,9 +5940,7 @@ bnxt_parse_devarg_cqe_mode(__rte_unused const char *key,
return -EINVAL;
}
- cqe_mode = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (cqe_mode == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &cqe_mode) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to cqe-mode "
"devargs.");
@@ -5974,8 +5965,7 @@ bnxt_parse_devarg_app_instance_id(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt *bp = opaque_arg;
- unsigned long app_instance_id;
- char *end = NULL;
+ uint64_t app_instance_id;
if (!opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -5983,9 +5973,7 @@ bnxt_parse_devarg_app_instance_id(__rte_unused const char *key,
return -EINVAL;
}
- app_instance_id = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (app_instance_id == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &app_instance_id) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to instance devargs");
return -EINVAL;
@@ -6008,8 +5996,7 @@ bnxt_parse_devarg_app_id(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt *bp = opaque_arg;
- unsigned long app_id;
- char *end = NULL;
+ uint64_t app_id;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6018,9 +6005,7 @@ bnxt_parse_devarg_app_id(__rte_unused const char *key,
return -EINVAL;
}
- app_id = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (app_id == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &app_id) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to app_id "
"devargs.");
@@ -6044,8 +6029,7 @@ bnxt_parse_devarg_ieee_1588(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt *bp = opaque_arg;
- unsigned long ieee_1588;
- char *end = NULL;
+ uint64_t ieee_1588;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6054,9 +6038,7 @@ bnxt_parse_devarg_ieee_1588(__rte_unused const char *key,
return -EINVAL;
}
- ieee_1588 = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (ieee_1588 == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &ieee_1588) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to ieee_1588 "
"devargs.");
@@ -6088,8 +6070,7 @@ bnxt_parse_devarg_rep_is_pf(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt_representor *vfr_bp = opaque_arg;
- unsigned long rep_is_pf;
- char *end = NULL;
+ uint64_t rep_is_pf;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6097,9 +6078,7 @@ bnxt_parse_devarg_rep_is_pf(__rte_unused const char *key,
return -EINVAL;
}
- rep_is_pf = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (rep_is_pf == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &rep_is_pf) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to rep_is_pf devargs.");
return -EINVAL;
@@ -6125,8 +6104,7 @@ bnxt_parse_devarg_rep_based_pf(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt_representor *vfr_bp = opaque_arg;
- unsigned long rep_based_pf;
- char *end = NULL;
+ uint64_t rep_based_pf;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6135,9 +6113,7 @@ bnxt_parse_devarg_rep_based_pf(__rte_unused const char *key,
return -EINVAL;
}
- rep_based_pf = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (rep_based_pf == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &rep_based_pf) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to rep_based_pf "
"devargs.");
@@ -6163,8 +6139,7 @@ bnxt_parse_devarg_rep_q_r2f(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt_representor *vfr_bp = opaque_arg;
- unsigned long rep_q_r2f;
- char *end = NULL;
+ uint64_t rep_q_r2f;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6173,9 +6148,7 @@ bnxt_parse_devarg_rep_q_r2f(__rte_unused const char *key,
return -EINVAL;
}
- rep_q_r2f = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (rep_q_r2f == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &rep_q_r2f) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to rep_q_r2f "
"devargs.");
@@ -6200,8 +6173,7 @@ bnxt_parse_devarg_rep_q_f2r(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt_representor *vfr_bp = opaque_arg;
- unsigned long rep_q_f2r;
- char *end = NULL;
+ uint64_t rep_q_f2r;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6210,9 +6182,7 @@ bnxt_parse_devarg_rep_q_f2r(__rte_unused const char *key,
return -EINVAL;
}
- rep_q_f2r = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (rep_q_f2r == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &rep_q_f2r) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to rep_q_f2r "
"devargs.");
@@ -6237,8 +6207,7 @@ bnxt_parse_devarg_rep_fc_r2f(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt_representor *vfr_bp = opaque_arg;
- unsigned long rep_fc_r2f;
- char *end = NULL;
+ uint64_t rep_fc_r2f;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6247,9 +6216,7 @@ bnxt_parse_devarg_rep_fc_r2f(__rte_unused const char *key,
return -EINVAL;
}
- rep_fc_r2f = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (rep_fc_r2f == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &rep_fc_r2f) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to rep_fc_r2f "
"devargs.");
@@ -6264,7 +6231,7 @@ bnxt_parse_devarg_rep_fc_r2f(__rte_unused const char *key,
vfr_bp->flags |= BNXT_REP_FC_R2F_VALID;
vfr_bp->rep_fc_r2f = rep_fc_r2f;
- PMD_DRV_LOG_LINE(INFO, "rep-fc-r2f = %lu", rep_fc_r2f);
+ PMD_DRV_LOG_LINE(INFO, "rep-fc-r2f = %u", (unsigned int)rep_fc_r2f);
return 0;
}
@@ -6274,8 +6241,7 @@ bnxt_parse_devarg_rep_fc_f2r(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt_representor *vfr_bp = opaque_arg;
- unsigned long rep_fc_f2r;
- char *end = NULL;
+ uint64_t rep_fc_f2r;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6284,9 +6250,7 @@ bnxt_parse_devarg_rep_fc_f2r(__rte_unused const char *key,
return -EINVAL;
}
- rep_fc_f2r = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (rep_fc_f2r == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &rep_fc_f2r) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid parameter passed to rep_fc_f2r "
"devargs.");
@@ -6301,7 +6265,7 @@ bnxt_parse_devarg_rep_fc_f2r(__rte_unused const char *key,
vfr_bp->flags |= BNXT_REP_FC_F2R_VALID;
vfr_bp->rep_fc_f2r = rep_fc_f2r;
- PMD_DRV_LOG_LINE(INFO, "rep-fc-f2r = %lu", rep_fc_f2r);
+ PMD_DRV_LOG_LINE(INFO, "rep-fc-f2r = %u", (unsigned int)rep_fc_f2r);
return 0;
}
@@ -6311,8 +6275,7 @@ bnxt_parse_devarg_representor_mode(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt *bp = opaque_arg;
- unsigned long rep;
- char *end = NULL;
+ uint64_t rep;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6320,9 +6283,7 @@ bnxt_parse_devarg_representor_mode(__rte_unused const char *key,
return -EINVAL;
}
- rep = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (rep == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &rep) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid param passed to rep mode in devargs");
return -EINVAL;
@@ -6340,8 +6301,7 @@ bnxt_parse_devarg_scalar_mode(__rte_unused const char *key,
const char *value, void *opaque_arg)
{
struct bnxt *bp = opaque_arg;
- unsigned long rep;
- char *end = NULL;
+ uint64_t rep;
if (!value || !opaque_arg) {
PMD_DRV_LOG_LINE(ERR,
@@ -6349,9 +6309,7 @@ bnxt_parse_devarg_scalar_mode(__rte_unused const char *key,
return -EINVAL;
}
- rep = strtoul(value, &end, 10);
- if (end == NULL || *end != '\0' ||
- (rep == ULONG_MAX && errno == ERANGE)) {
+ if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &rep) < 0) {
PMD_DRV_LOG_LINE(ERR,
"Invalid param passed to scalar mode in devargs");
return -EINVAL;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 46/62] net/bnxt: propagate devargs parsing errors
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (44 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 45/62] net/bnxt: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 47/62] net/mlx4: use kvargs numeric helpers Stephen Hemminger
` (15 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, stable, Kishore Padmanabha, Ajit Khaparde,
Lance Richardson
bnxt_parse_dev_args() placed the "err" label immediately after the last
"goto err", in the middle of the fall-through path, so the jump skipped
nothing. The seven handlers that follow it ran even when an earlier
argument had already failed to parse, and their return values were
discarded, so a bad value in any of them was ignored entirely.
Move the label to just before the kvargs list is freed and check every
handler, so that parsing stops at the first bad argument.
Fixes: 29ce7059e8e7 ("net/bnxt: check kvargs parsing")
Cc: stable@dpdk.org
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/bnxt/bnxt_ethdev.c | 42 ++++++++++++++++++++++------------
1 file changed, 27 insertions(+), 15 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 4903f6fb10..816d466354 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -6353,57 +6353,69 @@ bnxt_parse_dev_args(struct bnxt *bp, struct rte_devargs *devargs)
if (ret)
goto err;
-err:
/*
* Handler for "mpc" devarg.
* Invoked as for ex: "-a 000:00:0d.0,mpc=1"
*/
- rte_kvargs_process(kvlist, BNXT_DEVARG_MPC,
- bnxt_parse_devarg_mpc, bp);
+ ret = rte_kvargs_process(kvlist, BNXT_DEVARG_MPC,
+ bnxt_parse_devarg_mpc, bp);
+ if (ret)
+ goto err;
/*
* Handler for "app-id" devarg.
* Invoked as for ex: "-a 000:00:0d.0,app-id=1"
*/
- rte_kvargs_process(kvlist, BNXT_DEVARG_APP_ID,
- bnxt_parse_devarg_app_id, bp);
+ ret = rte_kvargs_process(kvlist, BNXT_DEVARG_APP_ID,
+ bnxt_parse_devarg_app_id, bp);
+ if (ret)
+ goto err;
/*
* Handler for "ieee-1588" devarg.
* Invoked as for ex: "-a 000:00:0d.0,ieee-1588=1"
*/
- rte_kvargs_process(kvlist, BNXT_DEVARG_IEEE_1588,
- bnxt_parse_devarg_ieee_1588, bp);
+ ret = rte_kvargs_process(kvlist, BNXT_DEVARG_IEEE_1588,
+ bnxt_parse_devarg_ieee_1588, bp);
+ if (ret)
+ goto err;
/*
* Handler for "cqe-mode" devarg.
* Invoked as for ex: "-a 000:00:0d.0,cqe-mode=1"
*/
- rte_kvargs_process(kvlist, BNXT_DEVARG_CQE_MODE,
- bnxt_parse_devarg_cqe_mode, bp);
+ ret = rte_kvargs_process(kvlist, BNXT_DEVARG_CQE_MODE,
+ bnxt_parse_devarg_cqe_mode, bp);
+ if (ret)
+ goto err;
/*
* Handler for "representor" devarg.
* Invoked as for ex: "-a 000:00:0d.0,representor=1"
*/
- rte_kvargs_process(kvlist, BNXT_DEVARG_REPRESENTOR,
- bnxt_parse_devarg_representor_mode, bp);
+ ret = rte_kvargs_process(kvlist, BNXT_DEVARG_REPRESENTOR,
+ bnxt_parse_devarg_representor_mode, bp);
+ if (ret)
+ goto err;
/*
* Handler for "scalar-mode" devarg.
* Invoked as for ex: "-a 000:00:0d.0,scalar-mode=1"
*/
- rte_kvargs_process(kvlist, BNXT_DEVARG_SCALAR_MODE,
- bnxt_parse_devarg_scalar_mode, bp);
+ ret = rte_kvargs_process(kvlist, BNXT_DEVARG_SCALAR_MODE,
+ bnxt_parse_devarg_scalar_mode, bp);
+ if (ret)
+ goto err;
/*
* Handler for "app-instance-id" devarg.
* Invoked as for ex: "-a 000:00:0d.0,app-instance-id=1"
* This argument is required for enabling truflow hot upgrade feature.
*/
- rte_kvargs_process(kvlist, BNXT_DEVARD_APP_INST_ID,
- bnxt_parse_devarg_app_instance_id, bp);
+ ret = rte_kvargs_process(kvlist, BNXT_DEVARD_APP_INST_ID,
+ bnxt_parse_devarg_app_instance_id, bp);
+err:
rte_kvargs_free(kvlist);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 47/62] net/mlx4: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (45 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 46/62] net/bnxt: propagate devargs parsing errors Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 48/62] net/sfc: " Stephen Hemminger
` (14 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Matan Azrad, Viacheslav Ovsiienko
mlx4_arg_parse() checks errno without clearing it first, so a stale
value left by earlier code rejects a valid argument, while a malformed
value such as "abc" sets no errno at all and is silently taken as zero.
The end pointer is never checked, so "1junk" is accepted.
Base 0 was used, so a leading zero silently selected octal.
The PCI_SLOT_NAME parser is left alone: it reads sysfs rather than a
device argument.
mr_ext_memseg_en is a boolean, so make the mlx4_conf field bool and
parse it with rte_kvargs_handle_bool(). mlx4_arg_parse() serves several
keys through a cast function pointer, so the boolean gets a call of its
own and the generic loop skips it. The one bit field it is later copied
into stays as it is.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/mlx4/mlx4.c | 33 +++++++++++++++++++++------------
1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 28f1116891..1e64230e35 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -70,7 +70,7 @@ struct mlx4_conf {
uint32_t present; /**< Bit-field for existing ports. */
uint32_t enabled; /**< Bit-field for user-enabled ports. */
} ports;
- int mr_ext_memseg_en;
+ bool mr_ext_memseg_en;
/** Whether memseg should be extended for MR creation. */
};
@@ -532,12 +532,10 @@ mlx4_ibv_device_to_pci_addr(const struct ibv_device *device,
static int
mlx4_arg_parse(const char *key, const char *val, struct mlx4_conf *conf)
{
- unsigned long tmp;
+ uint64_t tmp;
- errno = 0;
- tmp = strtoul(val, NULL, 0);
- if (errno) {
- rte_errno = errno;
+ if (rte_kvargs_to_uint(val, 0, UINT32_MAX, &tmp) < 0) {
+ rte_errno = EINVAL;
WARN("%s: \"%s\" is not a valid integer", key, val);
return -rte_errno;
}
@@ -545,18 +543,16 @@ mlx4_arg_parse(const char *key, const char *val, struct mlx4_conf *conf)
uint32_t ports = rte_log2_u32(conf->ports.present + 1);
if (tmp >= ports) {
- ERROR("port index %lu outside range [0,%" PRIu32 ")",
- tmp, ports);
+ ERROR("port index %u outside range [0,%u)",
+ (unsigned int)tmp, ports);
return -EINVAL;
}
if (!(conf->ports.present & (1 << tmp))) {
rte_errno = EINVAL;
- ERROR("invalid port index %lu", tmp);
+ ERROR("invalid port index %u", (unsigned int)tmp);
return -rte_errno;
}
conf->ports.enabled |= 1 << tmp;
- } else if (strcmp(MLX4_MR_EXT_MEMSEG_EN_KVARG, key) == 0) {
- conf->mr_ext_memseg_en = !!tmp;
} else {
rte_errno = EINVAL;
WARN("%s: unknown parameter", key);
@@ -590,8 +586,21 @@ mlx4_args(struct rte_devargs *devargs, struct mlx4_conf *conf)
ERROR("failed to parse kvargs");
return -rte_errno;
}
+ /*
+ * mr_ext_memseg_en is a boolean and has a handler of its own; the
+ * loop below covers the arguments which mlx4_arg_parse() handles.
+ */
+ ret = rte_kvargs_process_opt(kvlist, MLX4_MR_EXT_MEMSEG_EN_KVARG,
+ rte_kvargs_handle_bool,
+ &conf->mr_ext_memseg_en);
+ if (ret != 0)
+ goto free_kvlist;
+
/* Process parameters. */
for (i = 0; pmd_mlx4_init_params[i]; ++i) {
+ if (strcmp(pmd_mlx4_init_params[i],
+ MLX4_MR_EXT_MEMSEG_EN_KVARG) == 0)
+ continue;
arg_count = rte_kvargs_count(kvlist, pmd_mlx4_init_params[i]);
while (arg_count-- > 0) {
ret = rte_kvargs_process(kvlist,
@@ -783,7 +792,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
struct rte_eth_dev *prev_dev = NULL;
struct mlx4_conf conf = {
.ports.present = 0,
- .mr_ext_memseg_en = 1,
+ .mr_ext_memseg_en = true,
};
unsigned int vf;
int i;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 48/62] net/sfc: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (46 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 47/62] net/mlx4: use kvargs numeric helpers Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 49/62] crypto/mvsam: " Stephen Hemminger
` (13 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Andrew Rybchenko
sfc_kvarg_long_handler() only checked that strtol() consumed at least one
character, so trailing garbage such as "5abc" was accepted, and errno was
never checked, so an out of range value was silently taken as LONG_MAX or
LONG_MIN.
It did nothing beyond that conversion, so drop it and use the new
rte_kvargs_handle_long(). The callers keep their long variables and their
own range checks.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/sfc/sfc.c | 2 +-
drivers/net/sfc/sfc_kvargs.c | 19 -------------------
drivers/net/sfc/sfc_kvargs.h | 2 --
drivers/net/sfc/sfc_port.c | 2 +-
4 files changed, 2 insertions(+), 23 deletions(-)
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 39cd8d519a..3d460cc222 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -1213,7 +1213,7 @@ sfc_kvarg_rxd_wait_timeout_ns(struct sfc_adapter *sa)
value = SFC_RXD_WAIT_TIMEOUT_NS_DEF;
rc = sfc_kvargs_process(sa, SFC_KVARG_RXD_WAIT_TIMEOUT_NS,
- sfc_kvarg_long_handler, &value);
+ rte_kvargs_handle_long, &value);
if (rc != 0)
return rc;
diff --git a/drivers/net/sfc/sfc_kvargs.c b/drivers/net/sfc/sfc_kvargs.c
index eb36fa98ca..d67f822dd2 100644
--- a/drivers/net/sfc/sfc_kvargs.c
+++ b/drivers/net/sfc/sfc_kvargs.c
@@ -107,25 +107,6 @@ sfc_kvarg_bool_handler(__rte_unused const char *key,
return 0;
}
-int
-sfc_kvarg_long_handler(__rte_unused const char *key,
- const char *value_str, void *opaque)
-{
- long value;
- char *endptr;
-
- if (!opaque)
- return -EINVAL;
-
- value = strtol(value_str, &endptr, 0);
- if (endptr == value_str)
- return -EINVAL;
-
- *(long *)opaque = value;
-
- return 0;
-}
-
int
sfc_kvarg_string_handler(__rte_unused const char *key,
const char *value_str, void *opaque)
diff --git a/drivers/net/sfc/sfc_kvargs.h b/drivers/net/sfc/sfc_kvargs.h
index 4dcc61e973..99de772d2d 100644
--- a/drivers/net/sfc/sfc_kvargs.h
+++ b/drivers/net/sfc/sfc_kvargs.h
@@ -88,8 +88,6 @@ int sfc_kvargs_process_opt(struct sfc_adapter *sa, const char *key_match,
int sfc_kvarg_bool_handler(const char *key, const char *value_str,
void *opaque);
-int sfc_kvarg_long_handler(const char *key, const char *value_str,
- void *opaque);
int sfc_kvarg_string_handler(const char *key, const char *value_str,
void *opaque);
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index 33b53f7ac8..d0652b612b 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -488,7 +488,7 @@ sfc_port_attach(struct sfc_adapter *sa)
kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF;
rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS,
- sfc_kvarg_long_handler,
+ rte_kvargs_handle_long,
&kvarg_stats_update_period_ms);
if ((rc == 0) &&
((kvarg_stats_update_period_ms < 0) ||
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 49/62] crypto/mvsam: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (47 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 48/62] net/sfc: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 50/62] ml/cnxk: use kvargs numeric helpers in cn10k Stephen Hemminger
` (12 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Michael Shamis, Liron Himi
parse_integer_arg() uses atoi(), which cannot report an error, so a
malformed value such as "abc" becomes zero and the negative check never
fires.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/crypto/mvsam/rte_mrvl_pmd.c | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
diff --git a/drivers/crypto/mvsam/rte_mrvl_pmd.c b/drivers/crypto/mvsam/rte_mrvl_pmd.c
index a824719fb0..3fd39e20d8 100644
--- a/drivers/crypto/mvsam/rte_mrvl_pmd.c
+++ b/drivers/crypto/mvsam/rte_mrvl_pmd.c
@@ -1117,22 +1117,6 @@ cryptodev_mrvl_crypto_create(const char *name,
return ret;
}
-/** Parse integer from integer argument */
-static int
-parse_integer_arg(const char *key __rte_unused,
- const char *value, void *extra_args)
-{
- int *i = (int *) extra_args;
-
- *i = atoi(value);
- if (*i < 0) {
- MRVL_LOG(ERR, "Argument has to be positive!");
- return -EINVAL;
- }
-
- return 0;
-}
-
/** Parse name */
static int
parse_name_arg(const char *key __rte_unused,
@@ -1170,14 +1154,14 @@ mrvl_pmd_parse_input_args(struct mrvl_pmd_init_params *params,
/* Common VDEV parameters */
ret = rte_kvargs_process(kvlist,
RTE_CRYPTODEV_PMD_MAX_NB_QP_ARG,
- &parse_integer_arg,
+ rte_kvargs_handle_uint,
¶ms->common.max_nb_queue_pairs);
if (ret < 0)
goto free_kvlist;
ret = rte_kvargs_process(kvlist,
RTE_CRYPTODEV_PMD_SOCKET_ID_ARG,
- &parse_integer_arg,
+ rte_kvargs_handle_socket_id,
¶ms->common.socket_id);
if (ret < 0)
goto free_kvlist;
@@ -1191,7 +1175,7 @@ mrvl_pmd_parse_input_args(struct mrvl_pmd_init_params *params,
ret = rte_kvargs_process(kvlist,
MRVL_PMD_MAX_NB_SESS_ARG,
- &parse_integer_arg,
+ rte_kvargs_handle_u32,
¶ms->max_nb_sessions);
if (ret < 0)
goto free_kvlist;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 50/62] ml/cnxk: use kvargs numeric helpers in cn10k
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (48 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 49/62] crypto/mvsam: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 51/62] ml/cnxk: use kvargs numeric helpers in mvtvm Stephen Hemminger
` (11 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Srikanth Yalavarthi
parse_integer_arg() uses atoi(), which cannot report an error, so a
malformed value such as "abc" becomes zero and the negative check never
fires.
enable_dpe_warnings, report_dpe_warnings, cache_model_data and
hw_queue_lock are booleans, so make the fields bool and use
rte_kvargs_handle_bool(). The "< 0 || > 1" checks which followed each
of them are then dead and go away; the *_set flags stay, since they
still distinguish an unset argument from one set to false. A bare key
now enables the option, and the usual spellings are accepted.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/ml/cnxk/cn10k_ml_dev.c | 70 ++++++----------------------------
drivers/ml/cnxk/cn10k_ml_dev.h | 8 ++--
drivers/ml/cnxk/cn10k_ml_ops.c | 2 +-
3 files changed, 16 insertions(+), 64 deletions(-)
diff --git a/drivers/ml/cnxk/cn10k_ml_dev.c b/drivers/ml/cnxk/cn10k_ml_dev.c
index c35895dc14..60bfb41b0f 100644
--- a/drivers/ml/cnxk/cn10k_ml_dev.c
+++ b/drivers/ml/cnxk/cn10k_ml_dev.c
@@ -80,20 +80,6 @@ parse_string_arg(const char *key __rte_unused, const char *value, void *extra_ar
return 0;
}
-static int
-parse_integer_arg(const char *key __rte_unused, const char *value, void *extra_args)
-{
- int *i = (int *)extra_args;
-
- *i = atoi(value);
- if (*i < 0) {
- plt_err("Argument has to be positive.");
- return -EINVAL;
- }
-
- return 0;
-}
-
static int
cn10k_mldev_parse_devargs(struct rte_devargs *devargs, struct cn10k_ml_dev *cn10k_mldev)
{
@@ -131,8 +117,8 @@ cn10k_mldev_parse_devargs(struct rte_devargs *devargs, struct cn10k_ml_dev *cn10
}
if (rte_kvargs_count(kvlist, CN10K_ML_FW_ENABLE_DPE_WARNINGS) == 1) {
- ret = rte_kvargs_process(kvlist, CN10K_ML_FW_ENABLE_DPE_WARNINGS,
- &parse_integer_arg, &cn10k_mldev->fw.enable_dpe_warnings);
+ ret = rte_kvargs_process_opt(kvlist, CN10K_ML_FW_ENABLE_DPE_WARNINGS,
+ rte_kvargs_handle_bool, &cn10k_mldev->fw.enable_dpe_warnings);
if (ret < 0) {
plt_err("Error processing arguments, key = %s",
CN10K_ML_FW_ENABLE_DPE_WARNINGS);
@@ -143,8 +129,8 @@ cn10k_mldev_parse_devargs(struct rte_devargs *devargs, struct cn10k_ml_dev *cn10
}
if (rte_kvargs_count(kvlist, CN10K_ML_FW_REPORT_DPE_WARNINGS) == 1) {
- ret = rte_kvargs_process(kvlist, CN10K_ML_FW_REPORT_DPE_WARNINGS,
- &parse_integer_arg, &cn10k_mldev->fw.report_dpe_warnings);
+ ret = rte_kvargs_process_opt(kvlist, CN10K_ML_FW_REPORT_DPE_WARNINGS,
+ rte_kvargs_handle_bool, &cn10k_mldev->fw.report_dpe_warnings);
if (ret < 0) {
plt_err("Error processing arguments, key = %s",
CN10K_ML_FW_REPORT_DPE_WARNINGS);
@@ -155,7 +141,7 @@ cn10k_mldev_parse_devargs(struct rte_devargs *devargs, struct cn10k_ml_dev *cn10
}
if (rte_kvargs_count(kvlist, CN10K_ML_DEV_CACHE_MODEL_DATA) == 1) {
- ret = rte_kvargs_process(kvlist, CN10K_ML_DEV_CACHE_MODEL_DATA, &parse_integer_arg,
+ ret = rte_kvargs_process_opt(kvlist, CN10K_ML_DEV_CACHE_MODEL_DATA, rte_kvargs_handle_bool,
&cn10k_mldev->cache_model_data);
if (ret < 0) {
plt_err("Error processing arguments, key = %s",
@@ -178,7 +164,7 @@ cn10k_mldev_parse_devargs(struct rte_devargs *devargs, struct cn10k_ml_dev *cn10
}
if (rte_kvargs_count(kvlist, CN10K_ML_DEV_HW_QUEUE_LOCK) == 1) {
- ret = rte_kvargs_process(kvlist, CN10K_ML_DEV_HW_QUEUE_LOCK, &parse_integer_arg,
+ ret = rte_kvargs_process_opt(kvlist, CN10K_ML_DEV_HW_QUEUE_LOCK, rte_kvargs_handle_bool,
&cn10k_mldev->hw_queue_lock);
if (ret < 0) {
plt_err("Error processing arguments, key = %s",
@@ -190,7 +176,7 @@ cn10k_mldev_parse_devargs(struct rte_devargs *devargs, struct cn10k_ml_dev *cn10
}
if (rte_kvargs_count(kvlist, CN10K_ML_OCM_PAGE_SIZE) == 1) {
- ret = rte_kvargs_process(kvlist, CN10K_ML_OCM_PAGE_SIZE, &parse_integer_arg,
+ ret = rte_kvargs_process(kvlist, CN10K_ML_OCM_PAGE_SIZE, rte_kvargs_handle_int,
&cn10k_mldev->ocm_page_size);
if (ret < 0) {
plt_err("Error processing arguments, key = %s", CN10K_ML_OCM_PAGE_SIZE);
@@ -207,44 +193,18 @@ cn10k_mldev_parse_devargs(struct rte_devargs *devargs, struct cn10k_ml_dev *cn10
cn10k_mldev->fw.path = fw_path;
plt_info("ML: %s = %s", CN10K_ML_FW_PATH, cn10k_mldev->fw.path);
- if (!enable_dpe_warnings_set) {
+ if (!enable_dpe_warnings_set)
cn10k_mldev->fw.enable_dpe_warnings = CN10K_ML_FW_ENABLE_DPE_WARNINGS_DEFAULT;
- } else {
- if ((cn10k_mldev->fw.enable_dpe_warnings < 0) ||
- (cn10k_mldev->fw.enable_dpe_warnings > 1)) {
- plt_err("Invalid argument, %s = %d", CN10K_ML_FW_ENABLE_DPE_WARNINGS,
- cn10k_mldev->fw.enable_dpe_warnings);
- ret = -EINVAL;
- goto exit;
- }
- }
plt_info("ML: %s = %d", CN10K_ML_FW_ENABLE_DPE_WARNINGS,
cn10k_mldev->fw.enable_dpe_warnings);
- if (!report_dpe_warnings_set) {
+ if (!report_dpe_warnings_set)
cn10k_mldev->fw.report_dpe_warnings = CN10K_ML_FW_REPORT_DPE_WARNINGS_DEFAULT;
- } else {
- if ((cn10k_mldev->fw.report_dpe_warnings < 0) ||
- (cn10k_mldev->fw.report_dpe_warnings > 1)) {
- plt_err("Invalid argument, %s = %d", CN10K_ML_FW_REPORT_DPE_WARNINGS,
- cn10k_mldev->fw.report_dpe_warnings);
- ret = -EINVAL;
- goto exit;
- }
- }
plt_info("ML: %s = %d", CN10K_ML_FW_REPORT_DPE_WARNINGS,
cn10k_mldev->fw.report_dpe_warnings);
- if (!cache_model_data_set) {
+ if (!cache_model_data_set)
cn10k_mldev->cache_model_data = CN10K_ML_DEV_CACHE_MODEL_DATA_DEFAULT;
- } else {
- if ((cn10k_mldev->cache_model_data < 0) || (cn10k_mldev->cache_model_data > 1)) {
- plt_err("Invalid argument, %s = %d", CN10K_ML_DEV_CACHE_MODEL_DATA,
- cn10k_mldev->cache_model_data);
- ret = -EINVAL;
- goto exit;
- }
- }
plt_info("ML: %s = %d", CN10K_ML_DEV_CACHE_MODEL_DATA, cn10k_mldev->cache_model_data);
if (!ocm_alloc_mode_set) {
@@ -261,16 +221,8 @@ cn10k_mldev_parse_devargs(struct rte_devargs *devargs, struct cn10k_ml_dev *cn10
}
plt_info("ML: %s = %s", CN10K_ML_OCM_ALLOC_MODE, cn10k_mldev->ocm.alloc_mode);
- if (!hw_queue_lock_set) {
+ if (!hw_queue_lock_set)
cn10k_mldev->hw_queue_lock = CN10K_ML_DEV_HW_QUEUE_LOCK_DEFAULT;
- } else {
- if ((cn10k_mldev->hw_queue_lock < 0) || (cn10k_mldev->hw_queue_lock > 1)) {
- plt_err("Invalid argument, %s = %d", CN10K_ML_DEV_HW_QUEUE_LOCK,
- cn10k_mldev->hw_queue_lock);
- ret = -EINVAL;
- goto exit;
- }
- }
plt_info("ML: %s = %d", CN10K_ML_DEV_HW_QUEUE_LOCK, cn10k_mldev->hw_queue_lock);
if (!ocm_page_size_set) {
diff --git a/drivers/ml/cnxk/cn10k_ml_dev.h b/drivers/ml/cnxk/cn10k_ml_dev.h
index dadb3b571b..4ca8dc63f4 100644
--- a/drivers/ml/cnxk/cn10k_ml_dev.h
+++ b/drivers/ml/cnxk/cn10k_ml_dev.h
@@ -108,10 +108,10 @@ struct cn10k_ml_fw {
const char *path;
/* Enable DPE warnings */
- int enable_dpe_warnings;
+ bool enable_dpe_warnings;
/* Report DPE warnings */
- int report_dpe_warnings;
+ bool report_dpe_warnings;
/* Data buffer */
uint8_t *data;
@@ -132,10 +132,10 @@ struct cn10k_ml_dev {
struct cn10k_ml_ocm ocm;
/* Enable / disable model data caching */
- int cache_model_data;
+ bool cache_model_data;
/* Use spinlock version of ROC enqueue */
- int hw_queue_lock;
+ bool hw_queue_lock;
/* OCM page size */
int ocm_page_size;
diff --git a/drivers/ml/cnxk/cn10k_ml_ops.c b/drivers/ml/cnxk/cn10k_ml_ops.c
index 597806b787..732f9b62ae 100644
--- a/drivers/ml/cnxk/cn10k_ml_ops.c
+++ b/drivers/ml/cnxk/cn10k_ml_ops.c
@@ -377,7 +377,7 @@ cn10k_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_c
rte_spinlock_init(&ocm->lock);
/* Set JCMDQ enqueue function */
- if (cn10k_mldev->hw_queue_lock == 1)
+ if (cn10k_mldev->hw_queue_lock)
cn10k_mldev->ml_jcmdq_enqueue = roc_ml_jcmdq_enqueue_sl;
else
cn10k_mldev->ml_jcmdq_enqueue = roc_ml_jcmdq_enqueue_lf;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 51/62] ml/cnxk: use kvargs numeric helpers in mvtvm
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (49 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 50/62] ml/cnxk: use kvargs numeric helpers in cn10k Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 52/62] event/opdl: use kvargs numeric helpers Stephen Hemminger
` (10 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Srikanth Yalavarthi
parse_integer_arg() used atoi(), which cannot report an error, so a
malformed value became zero and the negative check never fired.
parse_uint_arg() open coded the errno and end pointer checks.
parse_uint_arg() also stored through a uint32_t pointer, but max_nb_qpairs
is a uint16_t followed by an int in the same struct, so parsing that
argument wrote past the field.
Neither handler did anything beyond a range checked store, so drop them
and pass rte_kvargs_handle_u16() directly for max_qps.
cache_model_data is a boolean, so make the field bool and use
rte_kvargs_handle_bool(), which makes the "< 0 || > 1" check that
followed it dead code. cache_model_data_set stays, since it still
tells an unset argument from one set to false. A bare key now enables
the option, and the usual spellings are accepted.
Bugzilla ID: 2043
Fixes: 48c6081ab4b3 ("ml/cnxk: enable creation of MVTVM virtual device")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/ml/cnxk/mvtvm_ml_dev.c | 47 ++++------------------------------
drivers/ml/cnxk/mvtvm_ml_dev.h | 2 +-
2 files changed, 6 insertions(+), 43 deletions(-)
diff --git a/drivers/ml/cnxk/mvtvm_ml_dev.c b/drivers/ml/cnxk/mvtvm_ml_dev.c
index 74959a12fc..cbaf17698e 100644
--- a/drivers/ml/cnxk/mvtvm_ml_dev.c
+++ b/drivers/ml/cnxk/mvtvm_ml_dev.c
@@ -20,36 +20,6 @@
static const char *const valid_args[] = {MVTVM_ML_DEV_MAX_QPS, MVTVM_ML_DEV_CACHE_MODEL_DATA, NULL};
-static int
-parse_integer_arg(const char *key __rte_unused, const char *value, void *extra_args)
-{
- int *i = (int *)extra_args;
-
- *i = atoi(value);
- if (*i < 0) {
- plt_err("Argument has to be positive.");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int
-parse_uint_arg(const char *key __rte_unused, const char *value, void *extra_args)
-{
- int i;
- char *end;
- errno = 0;
-
- i = strtol(value, &end, 10);
- if (*end != 0 || errno != 0 || i < 0)
- return -EINVAL;
-
- *((uint32_t *)extra_args) = i;
-
- return 0;
-}
-
static int
mvtvm_mldev_parse_devargs(const char *args, struct mvtvm_ml_dev *mvtvm_mldev)
{
@@ -68,7 +38,7 @@ mvtvm_mldev_parse_devargs(const char *args, struct mvtvm_ml_dev *mvtvm_mldev)
}
if (rte_kvargs_count(kvlist, MVTVM_ML_DEV_MAX_QPS) == 1) {
- ret = rte_kvargs_process(kvlist, MVTVM_ML_DEV_MAX_QPS, &parse_uint_arg,
+ ret = rte_kvargs_process(kvlist, MVTVM_ML_DEV_MAX_QPS, rte_kvargs_handle_u16,
&mvtvm_mldev->max_nb_qpairs);
if (ret < 0) {
plt_err("Error processing arguments, key = %s", MVTVM_ML_DEV_MAX_QPS);
@@ -79,8 +49,9 @@ mvtvm_mldev_parse_devargs(const char *args, struct mvtvm_ml_dev *mvtvm_mldev)
}
if (rte_kvargs_count(kvlist, MVTVM_ML_DEV_CACHE_MODEL_DATA) == 1) {
- ret = rte_kvargs_process(kvlist, MVTVM_ML_DEV_CACHE_MODEL_DATA, &parse_integer_arg,
- &mvtvm_mldev->cache_model_data);
+ ret = rte_kvargs_process_opt(kvlist, MVTVM_ML_DEV_CACHE_MODEL_DATA,
+ rte_kvargs_handle_bool,
+ &mvtvm_mldev->cache_model_data);
if (ret < 0) {
plt_err("Error processing arguments, key = %s",
MVTVM_ML_DEV_CACHE_MODEL_DATA);
@@ -95,16 +66,8 @@ mvtvm_mldev_parse_devargs(const char *args, struct mvtvm_ml_dev *mvtvm_mldev)
mvtvm_mldev->max_nb_qpairs = MVTVM_ML_DEV_MAX_QPS_DEFAULT;
plt_ml_dbg("ML: %s = %u", MVTVM_ML_DEV_MAX_QPS, mvtvm_mldev->max_nb_qpairs);
- if (!cache_model_data_set) {
+ if (!cache_model_data_set)
mvtvm_mldev->cache_model_data = CN10K_ML_DEV_CACHE_MODEL_DATA_DEFAULT;
- } else {
- if ((mvtvm_mldev->cache_model_data < 0) || (mvtvm_mldev->cache_model_data > 1)) {
- plt_err("Invalid argument, %s = %d", MVTVM_ML_DEV_CACHE_MODEL_DATA,
- mvtvm_mldev->cache_model_data);
- ret = -EINVAL;
- goto exit;
- }
- }
plt_ml_dbg("ML: %s = %d", MVTVM_ML_DEV_CACHE_MODEL_DATA, mvtvm_mldev->cache_model_data);
exit:
diff --git a/drivers/ml/cnxk/mvtvm_ml_dev.h b/drivers/ml/cnxk/mvtvm_ml_dev.h
index 05e30f094c..f8b34ecd3a 100644
--- a/drivers/ml/cnxk/mvtvm_ml_dev.h
+++ b/drivers/ml/cnxk/mvtvm_ml_dev.h
@@ -31,7 +31,7 @@ struct mvtvm_ml_dev {
uint16_t max_nb_qpairs;
/* Enable / disable model data caching */
- int cache_model_data;
+ bool cache_model_data;
};
#endif /* _MVTVM_ML_DEV_H_ */
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 52/62] event/opdl: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (50 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 51/62] ml/cnxk: use kvargs numeric helpers in mvtvm Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 53/62] mempool/cnxk: " Stephen Hemminger
` (9 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Liang Ma, Peter Mccarthy
All three handlers use atoi(), which cannot report an error, so a
malformed value is silently taken as zero. Zero is within the accepted
range for each of these arguments, so a typo was accepted and quietly
applied rather than rejected.
The booleans use rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/event/opdl/opdl_evdev.c | 49 ++++++---------------------------
1 file changed, 9 insertions(+), 40 deletions(-)
diff --git a/drivers/event/opdl/opdl_evdev.c b/drivers/event/opdl/opdl_evdev.c
index ffa65ef930..4650d3eca8 100644
--- a/drivers/event/opdl/opdl_evdev.c
+++ b/drivers/event/opdl/opdl_evdev.c
@@ -3,6 +3,7 @@
*/
#include <inttypes.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -580,38 +581,6 @@ opdl_close(struct rte_eventdev *dev)
return 0;
}
-static int
-assign_numa_node(const char *key __rte_unused, const char *value, void *opaque)
-{
- int *socket_id = opaque;
- *socket_id = atoi(value);
- if (*socket_id >= RTE_MAX_NUMA_NODES)
- return -1;
- return 0;
-}
-
-static int
-set_do_validation(const char *key __rte_unused, const char *value, void *opaque)
-{
- int *do_val = opaque;
- *do_val = atoi(value);
- if (*do_val != 0)
- *do_val = 1;
-
- return 0;
-}
-static int
-set_do_test(const char *key __rte_unused, const char *value, void *opaque)
-{
- int *do_test = opaque;
-
- *do_test = atoi(value);
-
- if (*do_test != 0)
- *do_test = 1;
- return 0;
-}
-
static int
opdl_probe(struct rte_vdev_device *vdev)
{
@@ -650,8 +619,8 @@ opdl_probe(struct rte_vdev_device *vdev)
struct rte_eventdev *dev;
struct opdl_evdev *opdl;
int socket_id = rte_socket_id();
- int do_validation = 0;
- int do_test = 0;
+ bool do_validation = false;
+ bool do_test = false;
int str_len;
int test_result = 0;
@@ -666,7 +635,7 @@ opdl_probe(struct rte_vdev_device *vdev)
name);
} else {
int ret = rte_kvargs_process(kvlist, NUMA_NODE_ARG,
- assign_numa_node, &socket_id);
+ rte_kvargs_handle_socket_id, &socket_id);
if (ret != 0) {
PMD_DRV_LOG(ERR,
"%s: Error parsing numa node parameter",
@@ -676,8 +645,8 @@ opdl_probe(struct rte_vdev_device *vdev)
return ret;
}
- ret = rte_kvargs_process(kvlist, DO_VALIDATION_ARG,
- set_do_validation, &do_validation);
+ ret = rte_kvargs_process_opt(kvlist, DO_VALIDATION_ARG,
+ rte_kvargs_handle_bool, &do_validation);
if (ret != 0) {
PMD_DRV_LOG(ERR,
"%s: Error parsing do validation parameter",
@@ -686,8 +655,8 @@ opdl_probe(struct rte_vdev_device *vdev)
return ret;
}
- ret = rte_kvargs_process(kvlist, DO_TEST_ARG,
- set_do_test, &do_test);
+ ret = rte_kvargs_process_opt(kvlist, DO_TEST_ARG,
+ rte_kvargs_handle_bool, &do_test);
if (ret != 0) {
PMD_DRV_LOG(ERR,
"%s: Error parsing do test parameter",
@@ -734,7 +703,7 @@ opdl_probe(struct rte_vdev_device *vdev)
str_len = strlen(name);
memcpy(opdl->service_name, name, str_len);
- if (do_test == 1)
+ if (do_test)
test_result = opdl_selftest();
done:
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 53/62] mempool/cnxk: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (51 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 52/62] event/opdl: use kvargs numeric helpers Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 54/62] event/octeontx: " Stephen Hemminger
` (8 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Ashwin Sekhar T K, Pavan Nikhilesh,
Nawal Kishor
Both handlers use atoi(), which cannot report an error, so a malformed
value is silently taken as zero. For max_pools that then gets clamped up
to the minimum, and for halo_ena zero is a valid setting, so neither was
rejected.
Since the handlers can now fail, propagate the rte_kvargs_process()
return value instead of discarding it.
halo_ena is a boolean, so drop its handler and use
rte_kvargs_handle_bool() on a bool. That also removes the store through
a uint8_t pointer into what the caller declared as a wider variable,
which only worked because the local was zeroed first and the host is
little endian. A bare "halo_ena" now enables it, and the usual
spellings are accepted.
Bugzilla ID: 2044
Fixes: 45abbfc836b1 ("mempool/cnxk: support HALO in mempool")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/mempool/cnxk/cnxk_mempool.c | 37 +++++++++++++----------------
1 file changed, 16 insertions(+), 21 deletions(-)
diff --git a/drivers/mempool/cnxk/cnxk_mempool.c b/drivers/mempool/cnxk/cnxk_mempool.c
index 6939fccff4..e5f1b9491b 100644
--- a/drivers/mempool/cnxk/cnxk_mempool.c
+++ b/drivers/mempool/cnxk/cnxk_mempool.c
@@ -2,6 +2,7 @@
* Copyright(C) 2021 Marvell.
*/
+#include <limits.h>
#include <rte_atomic.h>
#include <bus_pci_driver.h>
#include <rte_common.h>
@@ -34,10 +35,14 @@ npa_aura_size_to_u32(uint8_t val)
static int
parse_max_pools_handler(const char *key, const char *value, void *extra_args)
{
+ uint64_t val;
+
RTE_SET_USED(key);
- uint32_t val;
- val = rte_align32pow2(atoi(value));
+ if (rte_kvargs_to_uint(value, 0, INT_MAX, &val) < 0)
+ return -EINVAL;
+
+ val = rte_align32pow2(val);
if (val < npa_aura_size_to_u32(NPA_AURA_SZ_128))
val = 128;
if (val > npa_aura_size_to_u32(NPA_AURA_SZ_1M))
@@ -47,27 +52,14 @@ parse_max_pools_handler(const char *key, const char *value, void *extra_args)
return 0;
}
-static int
-parse_halo_ena_handler(const char *key, const char *value, void *extra_args)
-{
- RTE_SET_USED(key);
- uint8_t val;
-
- val = atoi(value);
- if (val != 0 && val != 1)
- return -EINVAL;
-
- *(uint8_t *)extra_args = val;
- return 0;
-}
-
static int
cnxk_mempool_plt_parse_devargs(struct rte_pci_device *pci_dev)
{
uint32_t max_pools = npa_aura_size_to_u32(NPA_AURA_SZ_128);
struct rte_devargs *devargs = pci_dev->device.devargs;
struct rte_kvargs *kvlist;
- uint32_t halo_ena = 0;
+ bool halo_ena = false;
+ int ret;
if (devargs == NULL)
goto null_devargs;
@@ -75,12 +67,15 @@ cnxk_mempool_plt_parse_devargs(struct rte_pci_device *pci_dev)
if (kvlist == NULL)
goto exit;
- rte_kvargs_process(kvlist, CNXK_NPA_MAX_POOLS_PARAM,
- &parse_max_pools_handler, &max_pools);
- rte_kvargs_process(kvlist, CNXK_NPA_HALO_ENA_PARAM,
- &parse_halo_ena_handler, &halo_ena);
+ ret = rte_kvargs_process(kvlist, CNXK_NPA_MAX_POOLS_PARAM,
+ &parse_max_pools_handler, &max_pools);
+ ret |= rte_kvargs_process_opt(kvlist, CNXK_NPA_HALO_ENA_PARAM,
+ rte_kvargs_handle_bool, &halo_ena);
rte_kvargs_free(kvlist);
+ if (ret != 0)
+ goto exit;
+
null_devargs:
roc_idev_npa_maxpools_set(max_pools);
roc_idev_npa_halo_ena_set(halo_ena);
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 54/62] event/octeontx: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (52 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 53/62] mempool/cnxk: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 55/62] baseband/turbo_sw: " Stephen Hemminger
` (7 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Jerin Jacob
ssovf_parsekv() open coded the errno, end pointer and range checks, and
the value it parsed was only ever used as a boolean.
Use rte_kvargs_handle_bool() and make the flag a bool to match. The
documented "=1" form still works, and the usual spellings such as "on"
and "true" are now accepted as well.
The boolean uses rte_kvargs_process_opt(), so that a bare key with no
value enables the option.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/event/octeontx/ssovf_evdev.c | 25 ++++---------------------
1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/drivers/event/octeontx/ssovf_evdev.c b/drivers/event/octeontx/ssovf_evdev.c
index 957fcab04e..4a56d91bf2 100644
--- a/drivers/event/octeontx/ssovf_evdev.c
+++ b/drivers/event/octeontx/ssovf_evdev.c
@@ -3,6 +3,7 @@
*/
#include <inttypes.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <rte_common.h>
@@ -23,7 +24,7 @@
#include "timvf_evdev.h"
#include "otx_cryptodev_hw_access.h"
-static uint8_t timvf_enable_stats;
+static bool timvf_enable_stats;
RTE_LOG_REGISTER_DEFAULT(otx_logtype_ssovf, NOTICE);
@@ -716,24 +717,6 @@ ssovf_close(struct rte_eventdev *dev)
return 0;
}
-static int
-ssovf_parsekv(const char *key, const char *value, void *opaque)
-{
- uint8_t *flag = opaque;
- uint64_t v;
- char *end;
-
- errno = 0;
- v = strtoul(value, &end, 0);
- if ((errno != 0) || (value == end) || *end != '\0' || v > 1) {
- ssovf_log_err("invalid %s value %s", key, value);
- return -EINVAL;
- }
-
- *flag = !!v;
- return 0;
-}
-
static int
ssovf_timvf_caps_get(const struct rte_eventdev *dev, uint64_t flags,
uint32_t *caps, const struct event_timer_adapter_ops **ops)
@@ -879,8 +862,8 @@ ssovf_vdev_probe(struct rte_vdev_device *vdev)
"Ignoring unsupported params supplied '%s'",
name);
} else {
- ret = rte_kvargs_process(kvlist, TIMVF_ENABLE_STATS_ARG,
- ssovf_parsekv,
+ ret = rte_kvargs_process_opt(kvlist, TIMVF_ENABLE_STATS_ARG,
+ rte_kvargs_handle_bool,
&timvf_enable_stats);
if (ret != 0) {
ssovf_log_err("%s: Error in timvf stats", name);
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 55/62] baseband/turbo_sw: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (53 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 54/62] event/octeontx: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 56/62] baseband/la12xx: " Stephen Hemminger
` (6 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Nicolas Chautru
parse_u16_arg() never checked the end pointer, so a value such as "8junk"
was accepted, and it used base 0, so a leading zero silently selected
octal.
It was also used for both device arguments, but only queues_num is a
uint16_t; socket_id is an int, so parsing it wrote two bytes into a four
byte object and left the rest uninitialised.
The handler did nothing beyond a range checked store, so drop it and pass
rte_kvargs_handle_u16() and rte_kvargs_handle_socket_id() directly, each
matching the width of the field it fills.
The open coded range check only tested the upper bound, so a negative
socket id such as -5 was accepted and used. The helper checks both ends,
accepting -1, which is SOCKET_ID_ANY, through RTE_MAX_NUMA_NODES - 1, so
the check is now redundant and is removed.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
.../baseband/turbo_sw/bbdev_turbo_software.c | 29 ++-----------------
1 file changed, 2 insertions(+), 27 deletions(-)
diff --git a/drivers/baseband/turbo_sw/bbdev_turbo_software.c b/drivers/baseband/turbo_sw/bbdev_turbo_software.c
index 2cab495294..d6801d9123 100644
--- a/drivers/baseband/turbo_sw/bbdev_turbo_software.c
+++ b/drivers/baseband/turbo_sw/bbdev_turbo_software.c
@@ -1835,25 +1835,6 @@ dequeue_enc_ops(struct rte_bbdev_queue_data *q_data,
return nb_dequeued;
}
-/* Parse 16bit integer from string argument */
-static inline int
-parse_u16_arg(const char *key, const char *value, void *extra_args)
-{
- uint16_t *u16 = extra_args;
- unsigned int long result;
-
- if ((value == NULL) || (extra_args == NULL))
- return -EINVAL;
- errno = 0;
- result = strtoul(value, NULL, 0);
- if ((result >= (1 << 16)) || (errno != 0)) {
- rte_bbdev_log(ERR, "Invalid value %lu for %s", result, key);
- return -ERANGE;
- }
- *u16 = (uint16_t)result;
- return 0;
-}
-
/* Parse parameters used to create device */
static int
parse_turbo_sw_params(struct turbo_sw_params *params, const char *input_args)
@@ -1869,20 +1850,14 @@ parse_turbo_sw_params(struct turbo_sw_params *params, const char *input_args)
return -EFAULT;
ret = rte_kvargs_process(kvlist, turbo_sw_valid_params[0],
- &parse_u16_arg, ¶ms->queues_num);
+ rte_kvargs_handle_u16, ¶ms->queues_num);
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist, turbo_sw_valid_params[1],
- &parse_u16_arg, ¶ms->socket_id);
+ rte_kvargs_handle_socket_id, ¶ms->socket_id);
if (ret < 0)
goto exit;
-
- if (params->socket_id >= RTE_MAX_NUMA_NODES) {
- rte_bbdev_log(ERR, "Invalid socket, must be < %u",
- RTE_MAX_NUMA_NODES);
- goto exit;
- }
}
exit:
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 56/62] baseband/la12xx: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (54 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 55/62] baseband/turbo_sw: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 57/62] dma/hisi_acc: " Stephen Hemminger
` (5 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Gagandeep Singh, Hemant Agrawal, Nipun Gupta,
Nicolas Chautru, Akhil Goyal
parse_u16_arg() stored through a uint16_t pointer and parse_integer_arg()
through a uint32_t pointer, but both device arguments are 8 bit fields:
queues_num is a uint8_t and modem_id an int8_t, and they are adjacent in
struct bbdev_la12xx_params. Parsing either argument therefore wrote past
the field and corrupted its neighbour.
parse_u16_arg() did nothing beyond a range checked store, so drop it and
pass rte_kvargs_handle_u8() directly, which also gives queues_num the
width it actually has.
The modem id keeps a handler of its own. parse_integer_arg() rejected
both ends of the range, and a plain rte_kvargs_handle_i8() would accept
anything down to -128 while the caller only checks the upper bound, so
"modem=-5" would be stored and only fail later in open_ipc_dev(). The
new handler bounds it to -1..LA12XX_MAX_MODEM-1, keeping -1 which
la12xx_bbdev_create() uses to mean "derive the modem id from the device
id", and replaces the caller's upper bound check.
The handler now rejects an out of range modem id, where the old check
did a "goto exit" with ret still zero. The probe also checks the result
of parse_bbdev_la12xx_params(), which it used to discard, so a bad modem
id or queue count now fails the probe instead of only being logged.
Fixes: ee36ba0f3042 ("baseband/la12xx: add devargs option for max queues")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/baseband/la12xx/bbdev_la12xx.c | 60 +++++++++-----------------
1 file changed, 20 insertions(+), 40 deletions(-)
diff --git a/drivers/baseband/la12xx/bbdev_la12xx.c b/drivers/baseband/la12xx/bbdev_la12xx.c
index 1116dacc4b..b9199189e7 100644
--- a/drivers/baseband/la12xx/bbdev_la12xx.c
+++ b/drivers/baseband/la12xx/bbdev_la12xx.c
@@ -912,44 +912,25 @@ setup_la12xx_dev(struct rte_bbdev *dev)
return ret;
}
-static inline int
-parse_u16_arg(const char *key, const char *value, void *extra_args)
-{
- uint16_t *u16 = extra_args;
-
- uint64_t result;
- if ((value == NULL) || (extra_args == NULL))
- return -EINVAL;
- errno = 0;
- result = strtoul(value, NULL, 0);
- if ((result >= (1 << 16)) || (errno != 0)) {
- rte_bbdev_log(ERR, "Invalid value %" PRIu64 " for %s",
- result, key);
- return -ERANGE;
- }
- *u16 = (uint16_t)result;
- return 0;
-}
-
-/* Parse integer from integer argument */
+/*
+ * Parse the modem id.
+ *
+ * A dedicated handler is needed because -1 is meaningful here: it leaves the
+ * modem id unset, and la12xx_bbdev_create() then derives it from the device
+ * id. rte_kvargs_handle_i8() alone would also accept anything down to -128.
+ */
static int
-parse_integer_arg(const char *key __rte_unused,
- const char *value, void *extra_args)
+parse_modem_id(const char *key, const char *value, void *extra_args)
{
- int i;
- char *end;
-
- errno = 0;
+ int64_t modem_id;
- i = strtol(value, &end, 10);
- if (*end != 0 || errno != 0 || i < 0 || i > LA12XX_MAX_MODEM) {
- rte_bbdev_log(ERR, "Supported Port IDS are 0 to %d",
- LA12XX_MAX_MODEM - 1);
+ if (rte_kvargs_to_int(value, -1, LA12XX_MAX_MODEM - 1, &modem_id) < 0) {
+ rte_bbdev_log(ERR, "Invalid %s, must be -1..%u", key,
+ LA12XX_MAX_MODEM - 1);
return -EINVAL;
}
- *((uint32_t *)extra_args) = i;
-
+ *(int8_t *)extra_args = modem_id;
return 0;
}
@@ -970,20 +951,16 @@ parse_bbdev_la12xx_params(struct bbdev_la12xx_params *params,
return -EFAULT;
ret = rte_kvargs_process(kvlist, bbdev_la12xx_valid_params[0],
- &parse_u16_arg, ¶ms->queues_num);
+ rte_kvargs_handle_u8, ¶ms->queues_num);
if (ret < 0)
goto exit;
ret = rte_kvargs_process(kvlist,
bbdev_la12xx_valid_params[1],
- &parse_integer_arg,
+ parse_modem_id,
¶ms->modem_id);
-
- if (params->modem_id >= LA12XX_MAX_MODEM) {
- rte_bbdev_log(ERR, "Invalid modem id, must be < %u",
- LA12XX_MAX_MODEM);
+ if (ret < 0)
goto exit;
- }
}
exit:
@@ -1062,6 +1039,7 @@ la12xx_bbdev_probe(struct rte_vdev_device *vdev)
};
const char *name;
const char *input_args;
+ int ret;
PMD_INIT_FUNC_TRACE();
@@ -1073,7 +1051,9 @@ la12xx_bbdev_probe(struct rte_vdev_device *vdev)
return -EINVAL;
input_args = rte_vdev_device_args(vdev);
- parse_bbdev_la12xx_params(&init_params, input_args);
+ ret = parse_bbdev_la12xx_params(&init_params, input_args);
+ if (ret < 0)
+ return ret;
return la12xx_bbdev_create(vdev, &init_params);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 57/62] dma/hisi_acc: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (55 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 56/62] baseband/la12xx: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 58/62] crypto/virtio: " Stephen Hemminger
` (4 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Chengwen Feng
hacc_dma_parse_queues() open codes the errno and end pointer checks the
helper performs. A queue count of zero is rejected by making one the
minimum of the accepted range, as before.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/dma/hisi_acc/hisi_acc_dmadev.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/dma/hisi_acc/hisi_acc_dmadev.c b/drivers/dma/hisi_acc/hisi_acc_dmadev.c
index 196aaadc05..7db93852a3 100644
--- a/drivers/dma/hisi_acc/hisi_acc_dmadev.c
+++ b/drivers/dma/hisi_acc/hisi_acc_dmadev.c
@@ -660,13 +660,10 @@ hacc_dma_parse_queues(const char *key, const char *value, void *extra_args)
{
struct hacc_dma_config *config = extra_args;
uint64_t val;
- char *end;
RTE_SET_USED(key);
- errno = 0;
- val = strtoull(value, &end, 0);
- if (errno == ERANGE || value == end || *end != '\0' || val == 0) {
+ if (rte_kvargs_to_uint(value, 1, UINT64_MAX, &val) < 0) {
HACC_DMA_LOG(ERR, "%s invalid queues! set to default one queue!",
config->dev->name);
config->queues = HACC_DMA_DEFAULT_QUEUES;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 58/62] crypto/virtio: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (56 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 57/62] dma/hisi_acc: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 59/62] net/ice: use kvargs hex helper for debug mask Stephen Hemminger
` (3 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Jay Zhou
get_integer_arg() never checks the end pointer and returns -errno, so a
malformed value such as "abc" leaves errno untouched, converts to zero
and is reported as success. It also used base 0, so a leading zero
silently selected octal.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/crypto/virtio/virtio_user_cryptodev.c | 21 ++-----------------
1 file changed, 2 insertions(+), 19 deletions(-)
diff --git a/drivers/crypto/virtio/virtio_user_cryptodev.c b/drivers/crypto/virtio/virtio_user_cryptodev.c
index 4daa188e1d..9844debeaf 100644
--- a/drivers/crypto/virtio/virtio_user_cryptodev.c
+++ b/drivers/crypto/virtio/virtio_user_cryptodev.c
@@ -345,23 +345,6 @@ get_string_arg(const char *key __rte_unused,
return 0;
}
-static int
-get_integer_arg(const char *key __rte_unused,
- const char *value, void *extra_args)
-{
- uint64_t integer = 0;
- if (!value || !extra_args)
- return -EINVAL;
- errno = 0;
- integer = strtoull(value, NULL, 0);
- /* extra_args keeps default value, it should be replaced
- * only in case of successful parsing of the 'value' arg
- */
- if (errno == 0)
- *(uint64_t *)extra_args = integer;
- return -errno;
-}
-
static struct rte_cryptodev *
virtio_user_cryptodev_alloc(struct rte_vdev_device *vdev)
{
@@ -432,7 +415,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_QUEUES_NUM) == 1) {
if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_QUEUES_NUM,
- &get_integer_arg, &queues) < 0) {
+ rte_kvargs_handle_u64, &queues) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_QUEUES_NUM);
goto end;
@@ -441,7 +424,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_QUEUE_SIZE) == 1) {
if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_QUEUE_SIZE,
- &get_integer_arg, &queue_size) < 0) {
+ rte_kvargs_handle_u64, &queue_size) < 0) {
PMD_INIT_LOG(ERR, "error to parse %s",
VIRTIO_USER_ARG_QUEUE_SIZE);
goto end;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 59/62] net/ice: use kvargs hex helper for debug mask
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (57 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 58/62] crypto/virtio: " Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 60/62] net/hns3: use kvargs hex helper for capability mask Stephen Hemminger
` (2 subsequent siblings)
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Anatoly Burakov
parse_u64() checks errno but not the end pointer, so "hw_debug_mask=junk"
is silently accepted as zero, and a trailing-garbage value such as
"0x80zz" is taken as 0x80.
The value is documented as a hexadecimal mask, so use
rte_kvargs_handle_hex64(), which reads it as hexadecimal with or without
a 0x prefix and validates the whole string. The documented form
"hw_debug_mask=0x80" is unchanged, and so is a bare "80".
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/intel/ice/ice_ethdev.c | 21 +--------------------
1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/net/intel/ice/ice_ethdev.c b/drivers/net/intel/ice/ice_ethdev.c
index af859f2174..77112bd499 100644
--- a/drivers/net/intel/ice/ice_ethdev.c
+++ b/drivers/net/intel/ice/ice_ethdev.c
@@ -2140,25 +2140,6 @@ ice_base_queue_get(struct ice_pf *pf)
}
}
-static int
-parse_u64(const char *key, const char *value, void *args)
-{
- u64 *num = (u64 *)args;
- u64 tmp;
-
- errno = 0;
- tmp = strtoull(value, NULL, 16);
- if (errno) {
- PMD_DRV_LOG(WARNING, "%s: \"%s\" is not a valid u64",
- key, value);
- return -1;
- }
-
- *num = tmp;
-
- return 0;
-}
-
static int
parse_tx_sched_levels(const char *key, const char *value, void *args)
{
@@ -2423,7 +2404,7 @@ static int ice_parse_devargs(struct rte_eth_dev *dev)
goto bail;
ret = rte_kvargs_process(kvlist, ICE_HW_DEBUG_MASK_ARG,
- &parse_u64, &ad->hw.debug_mask);
+ rte_kvargs_handle_hex64, &ad->hw.debug_mask);
if (ret)
goto bail;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 60/62] net/hns3: use kvargs hex helper for capability mask
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (58 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 59/62] net/ice: use kvargs hex helper for debug mask Stephen Hemminger
@ 2026-09-14 5:47 ` 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
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Xingui Yang, Chengwen Feng
hns3_parse_dev_caps_mask() does no validation whatsoever: strtoull() is
called with neither errno cleared nor the end pointer checked, so
"dev_caps_mask=junk" is silently taken as zero and "dev_caps_mask=-1"
wraps around to enable every capability.
The value is documented as a hexadecimal mask, so use
rte_kvargs_handle_hex64(), which reads it as hexadecimal with or without
a 0x prefix. The documented form "dev_caps_mask=0xF" is unchanged, and
so is a bare "F".
Note that hns3_parse_devargs() discards the rte_kvargs_process() return
value for every argument it parses, so a malformed mask is now reported
but still leaves the default of zero in place rather than failing probe.
Propagating those errors is a behaviour change per argument and is left
for a separate patch.
HNS3_CONVERT_TO_HEXADECIMAL loses its last user here, and
HNS3_CONVERT_TO_DECIMAL lost its own earlier in this series, so remove
both.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/hns3/hns3_common.c | 18 +-----------------
drivers/net/hns3/hns3_common.h | 3 ---
2 files changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index c21740ba5e..35cc3fca40 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -205,22 +205,6 @@ hns3_get_io_hint_func_name(uint32_t hint)
}
}
-static int
-hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
-{
- uint64_t val;
-
- RTE_SET_USED(key);
-
- if (value == NULL || extra_args == NULL)
- return 0;
-
- val = strtoull(value, NULL, HNS3_CONVERT_TO_HEXADECIMAL);
- *(uint64_t *)extra_args = val;
-
- return 0;
-}
-
static int
hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
{
@@ -341,7 +325,7 @@ hns3_parse_devargs(struct rte_eth_dev *dev)
(void)rte_kvargs_process(kvlist, HNS3_DEVARG_TX_FUNC_HINT,
&hns3_parse_io_hint_func, &tx_func_hint);
(void)rte_kvargs_process(kvlist, HNS3_DEVARG_DEV_CAPS_MASK,
- &hns3_parse_dev_caps_mask, &dev_caps_mask);
+ rte_kvargs_handle_hex64, &dev_caps_mask);
(void)rte_kvargs_process(kvlist, HNS3_DEVARG_MBX_TIME_LIMIT_MS,
&hns3_parse_mbx_time_limit, &mbx_time_limit_ms);
if (!hns->is_vf) {
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
index 7b3f96b01a..967cde9e39 100644
--- a/drivers/net/hns3/hns3_common.h
+++ b/drivers/net/hns3/hns3_common.h
@@ -9,9 +9,6 @@
#include "hns3_ethdev.h"
-#define HNS3_CONVERT_TO_DECIMAL 10
-#define HNS3_CONVERT_TO_HEXADECIMAL 16
-
enum {
HNS3_IO_FUNC_HINT_NONE = 0,
HNS3_IO_FUNC_HINT_VEC,
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 61/62] net/cxgbe: use kvargs numeric helpers
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (59 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 60/62] net/hns3: use kvargs hex helper for capability mask Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
2026-09-14 5:47 ` [PATCH 62/62] doc: note kvargs devargs conversion in release notes Stephen Hemminger
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Potnuri Bharat Teja
check_devargs_handler() is a single handler shared by all five device
arguments, which dispatches on the key to decide how to parse the value.
The dispatch is done with strncmp(key, NAME, strlen(key)), which compares
only as many bytes as the key given by the user is long, so a short key
matches a longer name by prefix. That is harmless today because
rte_kvargs_process() has already selected the pairs by exact key, but it
means the handler cannot tell which argument it was called for except by
accident.
The filtermode and filtermask branch checks errno without clearing it
first, so a stale ERANGE from unrelated earlier code rejects a valid
mask. The boolean branch tests only for "1" and silently ignores
anything else, so "keep_ovlan=yes" leaves the default in place without
complaint.
Pass the handler to cxgbe_get_devargs() instead of having one handler
work out what it was called for: rte_kvargs_handle_hex32() for the two
masks, which are documented as hexadecimal, and rte_kvargs_handle_bool()
for the three flags.
The masks are still read as hexadecimal with or without a 0x prefix, so
"filtermode=44" is unchanged. The flags now also accept "y", "yes",
"on" and "true" as well as "1", and a value which is not a boolean at
all is rejected rather than ignored.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/net/cxgbe/cxgbe_main.c | 38 ++++++----------------------------
1 file changed, 6 insertions(+), 32 deletions(-)
diff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c
index 2ed21f2d66..e0eefae6c1 100644
--- a/drivers/net/cxgbe/cxgbe_main.c
+++ b/drivers/net/cxgbe/cxgbe_main.c
@@ -744,36 +744,8 @@ void cxgbe_print_port_info(struct adapter *adap)
}
}
-static int check_devargs_handler(const char *key, const char *value, void *p)
-{
- if (!strncmp(key, CXGBE_DEVARG_CMN_KEEP_OVLAN, strlen(key)) ||
- !strncmp(key, CXGBE_DEVARG_CMN_TX_MODE_LATENCY, strlen(key)) ||
- !strncmp(key, CXGBE_DEVARG_VF_FORCE_LINK_UP, strlen(key))) {
- if (!strncmp(value, "1", 1)) {
- bool *dst_val = (bool *)p;
-
- *dst_val = true;
- }
- }
-
- if (!strncmp(key, CXGBE_DEVARG_PF_FILTER_MODE, strlen(key)) ||
- !strncmp(key, CXGBE_DEVARG_PF_FILTER_MASK, strlen(key))) {
- u32 *dst_val = (u32 *)p;
- char *endptr = NULL;
- u32 arg_val;
-
- arg_val = strtoul(value, &endptr, 16);
- if (errno || endptr == value)
- return -EINVAL;
-
- *dst_val = arg_val;
- }
-
- return 0;
-}
-
static int cxgbe_get_devargs(struct rte_devargs *devargs, const char *key,
- void *p)
+ arg_handler_t handler, void *p)
{
struct rte_kvargs *kvlist;
int ret = 0;
@@ -788,7 +760,7 @@ static int cxgbe_get_devargs(struct rte_devargs *devargs, const char *key,
if (!rte_kvargs_count(kvlist, key))
goto out;
- ret = rte_kvargs_process(kvlist, key, check_devargs_handler, p);
+ ret = rte_kvargs_process(kvlist, key, handler, p);
out:
rte_kvargs_free(kvlist);
@@ -807,7 +779,8 @@ static void cxgbe_get_devargs_int(struct adapter *adap, bool *dst,
if (!pdev)
return;
- ret = cxgbe_get_devargs(pdev->device.devargs, key, &devarg_value);
+ ret = cxgbe_get_devargs(pdev->device.devargs, key,
+ rte_kvargs_handle_bool, &devarg_value);
if (ret)
return;
@@ -825,7 +798,8 @@ static void cxgbe_get_devargs_u32(struct adapter *adap, u32 *dst,
if (!pdev)
return;
- ret = cxgbe_get_devargs(pdev->device.devargs, key, &devarg_value);
+ ret = cxgbe_get_devargs(pdev->device.devargs, key,
+ rte_kvargs_handle_hex32, &devarg_value);
if (ret)
return;
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 62/62] doc: note kvargs devargs conversion in release notes
2026-09-14 5:46 [PATCH 00/62] kvargs: add numeric conversion helpers and use them Stephen Hemminger
` (60 preceding siblings ...)
2026-09-14 5:47 ` [PATCH 61/62] net/cxgbe: use kvargs numeric helpers Stephen Hemminger
@ 2026-09-14 5:47 ` Stephen Hemminger
61 siblings, 0 replies; 65+ messages in thread
From: Stephen Hemminger @ 2026-09-14 5:47 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
Record that the drivers were converted to the new kvargs helpers, and
what a user should expect to change: a device argument which is
malformed or out of range is now reported and rejected, where before it
was commonly truncated, wrapped around, or taken as zero.
This is kept as a separate patch at the end of the series rather than
folded into the last driver, so that the note does not depend on any one
driver patch surviving review.
The individual drivers are not listed. At 52 entries the list was too
long to be useful, and it meant a third of the driver patches touched
the release notes only to append a bullet.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
doc/guides/rel_notes/release_26_11.rst | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index a663d69655..0399b96dde 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -81,6 +81,24 @@ New Features
``rte_kvargs_to_hex`` for the cases where a driver needs a narrower range
than the target type allows.
+ 52 drivers were converted to use these helpers. A device argument which
+ is malformed or out of range is now reported and rejected, where before
+ it was commonly truncated, wrapped around, or taken as zero.
+
+ The device arguments which are booleans were converted along with them.
+ Those now take any of the spellings above rather than only ``0`` and
+ ``1``, and ``key`` on its own means true. A value which is not a
+ boolean is rejected, where several drivers previously read it as false.
+ That includes an empty ``key=``, which ``net/pcap`` used to take as
+ true for ``infinite_rx``.
+
+ Two of these change what an existing argument means. ``event/dlb2``
+ only looked for a leading ``y`` in ``vector_opts_enable``,
+ ``default_ldb_port_allocation`` and ``enable_cq_weight``, so ``=1``
+ used to mean false and now means true. ``net/virtio`` compared
+ ``vectorized`` against ``"1"``, so ``vectorized=y`` used to mean false
+ and now means true.
+
Removed Items
-------------
--
2.53.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* RE: [EXTERNAL] [PATCH 23/62] net/netvsc: use kvargs numeric helpers
2026-09-14 5:46 ` [PATCH 23/62] net/netvsc: " Stephen Hemminger
@ 2026-09-14 12:43 ` Wei Hu
0 siblings, 0 replies; 65+ messages in thread
From: Wei Hu @ 2026-09-14 12:43 UTC (permalink / raw)
To: Stephen Hemminger, dev@dpdk.org; +Cc: Long Li
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Monday, September 14, 2026 1:47 PM
> To: dev@dpdk.org
> Cc: Stephen Hemminger <stephen@networkplumber.org>; Long Li
> <longli@microsoft.com>; Wei Hu <weh@microsoft.com>
> Subject: [EXTERNAL] [PATCH 23/62] net/netvsc: use kvargs numeric helpers
>
> hn_set_parameter() does not check errno, so an out of range value is accepted
> as ULONG_MAX, and the result is stored into 32-bit fields without any range
> check.
>
> This also drops support for octal, which base 0 accepted; hexadecimal still
> works.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Wei Hu <weh@microsoft.com>
> ---
> drivers/net/netvsc/hn_ethdev.c | 6 ++----
> 1 file changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/netvsc/hn_ethdev.c b/drivers/net/netvsc/hn_ethdev.c
> index 9a193e4a7a..d9f60ec279 100644
> --- a/drivers/net/netvsc/hn_ethdev.c
> +++ b/drivers/net/netvsc/hn_ethdev.c
> @@ -202,11 +202,9 @@ eth_dev_vmbus_release(struct rte_eth_dev
> *eth_dev) static int hn_set_parameter(const char *key, const char *value,
> void *opaque) {
> struct hn_data *hv = opaque;
> - char *endp = NULL;
> - unsigned long v;
> + uint64_t v;
>
> - v = strtoul(value, &endp, 0);
> - if (*value == '\0' || *endp != '\0') {
> + if (rte_kvargs_to_uint(value, 0, UINT32_MAX, &v) < 0) {
> PMD_DRV_LOG(ERR, "invalid parameter %s=%s", key, value);
> return -EINVAL;
> }
> --
> 2.53.0
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 34/62] net/nfb: use kvargs numeric helpers
2026-09-14 5:47 ` [PATCH 34/62] net/nfb: " Stephen Hemminger
@ 2026-09-14 14:44 ` Martin Spinler
0 siblings, 0 replies; 65+ messages in thread
From: Martin Spinler @ 2026-09-14 14:44 UTC (permalink / raw)
To: Stephen Hemminger, dev
On Sun, 2026-09-13 at 22:47 -0700, Stephen Hemminger wrote:
> Replace the open coded isdigit(), errno and end pointer checks in
> nfb_eth_dev_create_for_ifc_by_port() with a range checked conversion.
>
> The "port >= LONG_MAX" test was redundant with the interface count
> check that follows it, since ifc_cnt is far below LONG_MAX.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Martin Spinler <spinler@cesnet.cz>
^ permalink raw reply [flat|nested] 65+ messages in thread
end of thread, other threads:[~2026-09-14 14:44 UTC | newest]
Thread overview: 65+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).