* [RFC PATCH 0/7] rework EAL argument parsing in DPDK
@ 2025-05-20 16:40 Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 1/7] eal: add long options for each short option Bruce Richardson
` (20 more replies)
0 siblings, 21 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-05-20 16:40 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
This RFC is just an initial prototype of one approach we may want to
take to help improve management of EAL cmdline arguments.
Although not complete (no account taken yet for BSD or Windows),
it's hopefully complete enough to give an idea of what I think would
improve the handling.
BACKGROUND:
- The first problem that led to this work was that of providing a
way for users to easily provide a set of CPU cores to DPDK where the
CPU ids are >= RTE_MAX_LCORE
- There are a number of solutions which were discussed for this, most
of which involved automatically remapping CPU ids to lcore ids
starting at zero.
- However, in discussion with David M. at the last DPDK Summit in
Prague, he pointed out the main difficulty with all these approaches
in that they don't work with multi-process, since we can't reuse lcore
id numbers in secondary process.
- This in turn lead to a realisation that when processing cmdline
arguments in DPDK, we always do so with very little context. So, for
example, when processing the "-l" flag, we have no idea whether there
will be later a --proc-type=secondary flag. We have all sorts of
post-arg-processing checks in place to try and catch these scenarios.
This patchset therefore tries to simplify the handling of argument
processing, by explicitly doing an initial pass to collate all arguments
into a structure. Thereafter, the actual arg parsing is done in a fixed
order, meaning that e.g. when processing the --main-lcore flag, we have
already processed the service core flags. We also can far quicker and
easier check for conflicting options, since they can all be checked for
NULL/non-NULL in the arg structure immediately after the struct has been
populated.
To do the initial argument gathering, this RFC uses the existing argparse
library in DPDK. With some minor tweaking, this meets our needs for EAL
argument parsing and allows us to not need to do direct getopt argument
processing inside EAL at all.
Bruce Richardson (7):
eal: add long options for each short option
argparse: add support for string and boolean args
argparse: make argparse EAL-args compatible
eal: define the EAL parameters in argparse format
eal: gather EAL args before processing
eal: combine parameter validation checks
eal: simplify handling of conflicting cmdline options
app/test/test_argparse.c | 46 +-
lib/argparse/rte_argparse.c | 46 +-
lib/argparse/rte_argparse.h | 9 +-
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 1435 ++++++++++++++++-----------
lib/eal/common/eal_options.h | 99 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/linux/eal.c | 378 +------
lib/eal/meson.build | 2 +-
9 files changed, 966 insertions(+), 1063 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH 1/7] eal: add long options for each short option
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
@ 2025-05-20 16:40 ` Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 2/7] argparse: add support for string and boolean args Bruce Richardson
` (19 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-05-20 16:40 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
To simplify future rework of the EAL arg handling, add a long-option
equivalent for each short option that doesn't already have one.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 9 +++++++++
lib/eal/common/eal_options.h | 16 ++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index ed514ec1d1..a22dc69681 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -66,7 +66,9 @@ eal_short_options[] =
const struct option
eal_long_options[] = {
{OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
+ {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
{OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
+ {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
{OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
{OPT_HELP, 0, NULL, OPT_HELP_NUM },
{OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
@@ -76,6 +78,11 @@ eal_long_options[] = {
{OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
{OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
{OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
+ {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
+ {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
+ {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
+ {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
+ {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
{OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
{OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
{OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
@@ -106,6 +113,8 @@ eal_long_options[] = {
{OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
{OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
{OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
+ {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
+
{0, 0, NULL, 0 }
};
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 7b84b7d778..e493821db1 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -17,8 +17,24 @@ enum {
OPT_DEV_ALLOW_NUM = 'a',
#define OPT_DEV_BLOCK "block"
OPT_DEV_BLOCK_NUM = 'b',
+#define OPT_COREMASK "coremask"
+ OPT_COREMASK_NUM = 'c',
+#define OPT_DRIVER_PATH "driver-path"
+ OPT_DRIVER_PATH_NUM = 'd',
#define OPT_LCORES "lcores"
OPT_LCORES_NUM = 'l',
+#define OPT_MEMORY_SIZE "memory-size"
+ OPT_MEMORY_SIZE_NUM = 'm',
+#define OPT_MEMORY_CHANNELS "memory-channels"
+ OPT_MEMORY_CHANNELS_NUM = 'n',
+#define OPT_MEMORY_RANKS "memory-ranks"
+ OPT_MEMORY_RANKS_NUM = 'r',
+#define OPT_SERVICE_COREMASK "service-coremask"
+ OPT_SERVICE_COREMASK_NUM = 's',
+#define OPT_SERVICE_CORELIST "service-corelist"
+ OPT_SERVICE_CORELIST_NUM = 'S',
+#define OPT_VERSION "version"
+ OPT_VERSION_NUM = 'v',
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH 2/7] argparse: add support for string and boolean args
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 1/7] eal: add long options for each short option Bruce Richardson
@ 2025-05-20 16:40 ` Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 3/7] argparse: make argparse EAL-args compatible Bruce Richardson
` (18 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-05-20 16:40 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
Sometimes we don't want to parse the string at all, when doing arg
parsing, and just save it off for later. Add support for that.
Also, rather than assuming boolean values have to be the same size as
uint8 (or some other size), add an explicitly type for that - which also
allows checking for true/false and 0/1 values explicitly.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
Note: when adding support for strings, I was uncertain as to whether the library
should copy the string, or just store the pointer to the original value. This
patch takes the former approach and makes a copy, but I'd appreciate feedback
on people's thoughts as to whether this is the best approach.
---
lib/argparse/rte_argparse.c | 34 ++++++++++++++++++++++++++++++++++
lib/argparse/rte_argparse.h | 6 +++++-
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index 18290e0c38..1cc06b550b 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -508,6 +508,38 @@ parse_arg_u64(struct rte_argparse_arg *arg, const char *value)
return 0;
}
+static int
+parse_arg_str(struct rte_argparse_arg *arg, const char *value)
+{
+ if (value == NULL) {
+ *(char **)arg->val_saver = arg->val_set;
+ return 0;
+ }
+ *(char **)arg->val_saver = strdup(value);
+
+ return 0;
+}
+
+static int
+parse_arg_bool(struct rte_argparse_arg *arg, const char *value)
+{
+ if (value == NULL) {
+ *(bool *)arg->val_saver = (arg->val_set != NULL);
+ return 0;
+ }
+
+ if (strcmp(value, "true") == 0 || strcmp(value, "1") == 0)
+ *(bool *)arg->val_saver = true;
+ else if (strcmp(value, "false") == 0 || strcmp(value, "0") == 0)
+ *(bool *)arg->val_saver = false;
+ else {
+ ARGPARSE_LOG(ERR, "argument %s expect a boolean value!", arg->name_long);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int
parse_arg_autosave(struct rte_argparse_arg *arg, const char *value)
{
@@ -521,6 +553,8 @@ parse_arg_autosave(struct rte_argparse_arg *arg, const char *value)
{ parse_arg_u16 },
{ parse_arg_u32 },
{ parse_arg_u64 },
+ { parse_arg_str},
+ { parse_arg_bool },
};
uint32_t index = arg_attr_val_type(arg);
int ret = -EINVAL;
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index d0cfaa1e4c..332184302e 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -60,8 +60,12 @@ extern "C" {
#define RTE_ARGPARSE_ARG_VALUE_U32 RTE_SHIFT_VAL64(4, 2)
/** The argument's value is uint64 type. */
#define RTE_ARGPARSE_ARG_VALUE_U64 RTE_SHIFT_VAL64(5, 2)
+/** The argument's value is string type. */
+#define RTE_ARGPARSE_ARG_VALUE_STR RTE_SHIFT_VAL64(6, 2)
+/** The argument's value is boolean flag type. */
+#define RTE_ARGPARSE_ARG_VALUE_BOOL RTE_SHIFT_VAL64(7, 2)
/** Max value type. */
-#define RTE_ARGPARSE_ARG_VALUE_MAX RTE_SHIFT_VAL64(6, 2)
+#define RTE_ARGPARSE_ARG_VALUE_MAX RTE_SHIFT_VAL64(8, 2)
/**
* Flag for that argument support occur multiple times.
* This flag can be set only when the argument is optional.
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH 3/7] argparse: make argparse EAL-args compatible
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 1/7] eal: add long options for each short option Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 2/7] argparse: add support for string and boolean args Bruce Richardson
@ 2025-05-20 16:40 ` Bruce Richardson
2025-05-22 10:44 ` Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 4/7] eal: define the EAL parameters in argparse format Bruce Richardson
` (17 subsequent siblings)
20 siblings, 1 reply; 67+ messages in thread
From: Bruce Richardson @ 2025-05-20 16:40 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
The argparse library was missing two key features which made it
unsuitable for use by EAL or any program wanting similar behaviour.
1. It didn't stop parsing arguments when it hit a "--" character
2. It never returned the number of arguments parsed
Fix both these issues - the latter is a change to the ABI, since we now
return >= 0 rather than == 0 on success. However, the ABI is still
experimental so we can make exactly these sorts of tweaks to it.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
app/test/test_argparse.c | 46 ++++++++++++++++++-------------------
lib/argparse/rte_argparse.c | 12 +++++++---
lib/argparse/rte_argparse.h | 3 ++-
3 files changed, 34 insertions(+), 27 deletions(-)
diff --git a/app/test/test_argparse.c b/app/test/test_argparse.c
index fcea620501..77bace5a39 100644
--- a/app/test/test_argparse.c
+++ b/app/test/test_argparse.c
@@ -360,14 +360,14 @@ test_argparse_opt_autosave_parse_int_of_no_val(void)
argv[0] = test_strdup(obj->prog_name);
argv[1] = test_strdup("--test-long");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
obj->args[0].flags = flags;
val_saver = 0;
argv[1] = test_strdup("-t");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
return 0;
@@ -393,14 +393,14 @@ test_argparse_opt_autosave_parse_int_of_required_val(void)
argv[1] = test_strdup("--test-long");
argv[2] = test_strdup("100");
ret = rte_argparse_parse(obj, 3, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
obj->args[0].flags = flags;
val_saver = 0;
argv[1] = test_strdup("-t");
ret = rte_argparse_parse(obj, 3, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
/* test invalid value. */
@@ -434,13 +434,13 @@ test_argparse_opt_autosave_parse_int_of_optional_val(void)
argv[0] = test_strdup(obj->prog_name);
argv[1] = test_strdup("--test-long");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
obj->args[0].flags = flags;
val_saver = 0;
argv[1] = test_strdup("-t");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
/* test with value. */
@@ -448,13 +448,13 @@ test_argparse_opt_autosave_parse_int_of_optional_val(void)
val_saver = 0;
argv[1] = test_strdup("--test-long=200");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 200, "Argparse parse expect success!");
obj->args[0].flags = flags;
val_saver = 0;
argv[1] = test_strdup("-t=200");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 200, "Argparse parse expect success!");
/* test with option value, but with wrong value. */
@@ -503,14 +503,14 @@ test_argparse_opt_callback_parse_int_of_no_val(void)
argv[0] = test_strdup(obj->prog_name);
argv[1] = test_strdup("--test-long");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE;
val_saver = 0;
argv[1] = test_strdup("-t");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
return 0;
@@ -555,14 +555,14 @@ test_argparse_opt_callback_parse_int_of_required_val(void)
argv[1] = test_strdup("--test-long");
argv[2] = test_strdup("100");
ret = rte_argparse_parse(obj, 3, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
val_saver = 0;
argv[1] = test_strdup("-t");
ret = rte_argparse_parse(obj, 3, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
/* test no more parameters. */
@@ -618,14 +618,14 @@ test_argparse_opt_callback_parse_int_of_optional_val(void)
argv[0] = test_strdup(obj->prog_name);
argv[1] = test_strdup("--test-long");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 10, "Argparse parse expect success!");
obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
val_saver = 0;
argv[1] = test_strdup("-t");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 10, "Argparse parse expect success!");
/* test with value. */
@@ -633,13 +633,13 @@ test_argparse_opt_callback_parse_int_of_optional_val(void)
val_saver = 0;
argv[1] = test_strdup("--test-long=100");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
val_saver = 0;
argv[1] = test_strdup("-t=100");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
/* test callback return failed. */
@@ -671,7 +671,7 @@ test_argparse_pos_autosave_parse_int(void)
argv[0] = test_strdup(obj->prog_name);
argv[1] = test_strdup("100");
ret = rte_argparse_parse(obj, 2, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
/* test positional autosave parse failed. */
@@ -738,7 +738,7 @@ test_argparse_pos_callback_parse_int(void)
argv[1] = test_strdup("100");
argv[2] = test_strdup("200");
ret = rte_argparse_parse(obj, 3, argv);
- TEST_ASSERT(ret == 0, "Argparse parse expect success!");
+ TEST_ASSERT(ret >= 0, "Argparse parse expect success!");
TEST_ASSERT(val_saver[1] == 100, "Argparse parse expect success!");
TEST_ASSERT(val_saver[2] == 200, "Argparse parse expect success!");
@@ -774,7 +774,7 @@ test_argparse_parse_type(void)
ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_INT, &val_int);
TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_INT, &val_int);
- TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
+ TEST_ASSERT(ret >= 0, "Argparse parse type expect failed!");
TEST_ASSERT(val_int == 123, "Argparse parse type expect failed!");
/* test for u8 parsing */
@@ -786,7 +786,7 @@ test_argparse_parse_type(void)
TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
val_u8 = 0;
ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
- TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
+ TEST_ASSERT(ret >= 0, "Argparse parse type expect failed!");
TEST_ASSERT(val_u8 == 123, "Argparse parse type expect failed!");
/* test for u16 parsing */
@@ -798,7 +798,7 @@ test_argparse_parse_type(void)
TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
val_u16 = 0;
ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
- TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
+ TEST_ASSERT(ret >= 0, "Argparse parse type expect failed!");
TEST_ASSERT(val_u16 == 123, "Argparse parse type expect failed!");
/* test for u32 parsing */
@@ -810,7 +810,7 @@ test_argparse_parse_type(void)
TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
val_u32 = 0;
ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
- TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
+ TEST_ASSERT(ret >= 0, "Argparse parse type expect failed!");
TEST_ASSERT(val_u32 == 123, "Argparse parse type expect failed!");
/* test for u64 parsing */
@@ -820,7 +820,7 @@ test_argparse_parse_type(void)
TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
val_u64 = 0;
ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64);
- TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
+ TEST_ASSERT(ret >= 0, "Argparse parse type expect failed!");
TEST_ASSERT(val_u64 == 123, "Argparse parse type expect failed!");
return 0;
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index 1cc06b550b..d8f964dc3c 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -605,6 +605,12 @@ parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help)
for (i = 1; i < argc; i++) {
curr_argv = argv[i];
+
+ if (strcmp(argv[i], "--") == 0) {
+ i++;
+ break;
+ }
+
if (curr_argv[0] != '-') {
/* process positional parameters. */
position_index++;
@@ -668,7 +674,7 @@ parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help)
arg->flags |= ARG_ATTR_FLAG_PARSED_MASK;
}
- return 0;
+ return i;
}
static uint32_t
@@ -784,7 +790,7 @@ rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv)
goto error;
ret = parse_args(obj, argc, argv, &show_help);
- if (ret != 0)
+ if (ret < 0)
goto error;
if (show_help) {
@@ -792,7 +798,7 @@ rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv)
exit(0);
}
- return 0;
+ return ret;
error:
if (obj->exit_on_error)
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index 332184302e..8cdb3195cb 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -183,7 +183,8 @@ struct rte_argparse {
* Array of parameters points.
*
* @return
- * 0 on success. Otherwise negative value is returned.
+ * number of arguments parsed (>= 0) on success.
+ * Otherwise negative error code is returned.
*/
__rte_experimental
int rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv);
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH 4/7] eal: define the EAL parameters in argparse format
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (2 preceding siblings ...)
2025-05-20 16:40 ` [RFC PATCH 3/7] argparse: make argparse EAL-args compatible Bruce Richardson
@ 2025-05-20 16:40 ` Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 5/7] eal: gather EAL args before processing Bruce Richardson
` (16 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-05-20 16:40 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
This table should allow us to parse all the eal args into a single
structure for later parsing in a fixed-order field basis. For those
elements that take multiple values, define a TAILQ and a callback to
process those elements.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
Note: Within the structure to store the elements, each field has the
same name as the cmdline parameter it corresponds to - just with "-"
replaced by "_". This allows us to later write generic code using
macros to check structure fields and auto-generate the error messages.
---
lib/eal/common/eal_common_options.c | 418 ++++++++++++++++++++++++++++
lib/eal/meson.build | 2 +-
2 files changed, 419 insertions(+), 1 deletion(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index a22dc69681..f0cccc1759 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -28,11 +28,13 @@
#include <rte_version.h>
#include <rte_devargs.h>
#include <rte_memcpy.h>
+#include <sys/queue.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <rte_telemetry.h>
#endif
#include <rte_vect.h>
+#include <rte_argparse.h>
#include <eal_export.h>
#include "eal_internal_cfg.h"
#include "eal_options.h"
@@ -47,6 +49,422 @@
#define LCORE_OPT_LST 1
#define LCORE_OPT_MSK 2
+struct arg_list_elem {
+ TAILQ_ENTRY(arg_list_elem) next;
+ char *arg;
+};
+TAILQ_HEAD(arg_list, arg_list_elem);
+
+struct eal_init_args {
+ /* define a struct member for each EAL option, member name is the same as option name.
+ * Parameters that take an argument e.g. -l, are char *,
+ * parameters that take no options e.g. --no-huge, are bool.
+ * parameters that can be given multiple times e.g. -a, are arg_lists,
+ * parameters that are optional e.g. --huge-unlink,
+ * are char * but are set to (void *)1 if the parameter is not given.
+ */
+ struct arg_list allow;
+ char *base_virtaddr;
+ struct arg_list block;
+ char *coremask;
+ bool create_uio_dev;
+ struct arg_list driver_path;
+ char *file_prefix;
+ char *force_max_simd_bitwidth;
+ char *huge_dir;
+ char *huge_unlink; /* parameter optional */
+ char *huge_worker_stack; /* parameter optional */
+ bool in_memory;
+ char *iova_mode;
+ char *lcores;
+ bool legacy_mem;
+ char *log_color; /* parameter optional */
+ char *log_level;
+ char *log_timestamp; /* parameter optional */
+ char *main_lcore;
+ bool match_allocations;
+ char *mbuf_pool_ops_name;
+ char *memory_channels;
+ char *memory_ranks;
+ char *memory_size;
+ bool no_hpet;
+ bool no_huge;
+ bool no_pci;
+ bool no_shconf;
+ bool no_telemetry;
+ char *proc_type;
+ char *service_coremask;
+ char *service_corelist;
+ bool single_file_segments;
+ char *socket_mem;
+ char *socket_limit;
+ char *syslog; /* parameter optional */
+ bool telemetry;
+ char *trace;
+ char *trace_bufsz;
+ char *trace_dir;
+ char *trace_mode;
+ struct arg_list vdev;
+ bool version;
+ char *vfio_intr;
+ char *vfio_vf_token;
+ bool vmware_tsc_map;
+};
+struct eal_init_args args;
+
+/* an rte_argparse callback to append the argument to an arg_list
+ * in args. The index is the offset into the struct of the list.
+ */
+static int
+arg_list_callback(uint32_t index, const char *arg, void *init_args)
+{
+ struct arg_list *list = RTE_PTR_ADD(init_args, index);
+ struct arg_list_elem *elem;
+
+ elem = malloc(sizeof(*elem));
+ if (elem == NULL)
+ return -1;
+
+ elem->arg = strdup(arg);
+ if (elem->arg == NULL) {
+ free(elem);
+ return -1;
+ }
+
+ TAILQ_INSERT_TAIL(list, elem, next);
+ return 0;
+}
+
+#define LIST_FLAGS (RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_SUPPORT_MULTI)
+#define STR_FLAGS (RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_STR)
+#define OPT_STR_FLAGS (RTE_ARGPARSE_ARG_OPTIONAL_VALUE | RTE_ARGPARSE_ARG_VALUE_STR)
+#define BOOL_FLAGS (RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_BOOL)
+
+struct rte_argparse eal_argparse = {
+ .prog_name = "",
+ .usage = "<DPDK EAL options>",
+ .exit_on_error = true,
+ .callback = arg_list_callback,
+ .opaque = &args,
+ .args = {
+ /* list of EAL arguments as struct rte_argparse_arg.
+ * For arguments which have an arg_list type, they use callback (no val_saver),
+ * and have the SUPPORT_MULTI flag set (as well as REQUIRED_VALUE flag).
+ * For arguments which have a string type, they use val_saver (no callback),
+ * and normally REQUIRED_VALUE.
+ * For flags which have optional arguments, they use both val_saver and val_set,
+ * but still have a string type.
+ * For boolean arguments, they use val_saver and val_set, with NO_VALUE flag.
+ */
+ {
+ .name_long = "--allow",
+ .name_short = "-a",
+ .help = "Add device to allow-list",
+ .val_set = (void *)offsetof(struct eal_init_args, allow),
+ .flags = LIST_FLAGS
+ },
+ {
+ .name_long = "--base-virtaddr",
+ .help = "Base virtual address to reserve memory",
+ .val_saver = &args.base_virtaddr,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--block",
+ .name_short = "-b",
+ .help = "Add device to block-list",
+ .val_set = (void *)offsetof(struct eal_init_args, block),
+ .flags = LIST_FLAGS
+ },
+ {
+ .name_long = "--coremask",
+ .name_short = "-c",
+ .help = "Hexadecimal bitmask of cores to use",
+ .val_saver = &args.coremask,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--create-uio-dev",
+ .help = "Create /dev/uioX devices",
+ .val_saver = &args.create_uio_dev,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--driver-path",
+ .name_short = "-d",
+ .help = "Path to external driver shared object",
+ .val_set = (void *)offsetof(struct eal_init_args, driver_path),
+ .flags = LIST_FLAGS
+ },
+ {
+ .name_long = "--file-prefix",
+ .help = "Base filename of hugetlbfs files",
+ .val_saver = &args.file_prefix,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--force-max-simd-bitwidth",
+ .help = "Set max SIMD bitwidth to use in vector code paths",
+ .val_saver = &args.force_max_simd_bitwidth,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--huge-dir",
+ .help = "Directory for hugepage files",
+ .val_saver = &args.huge_dir,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--huge-unlink",
+ .help = "Unlink hugetlbfs files on exit (existing|always|never)",
+ .val_saver = &args.huge_unlink,
+ .val_set = (void *)1,
+ .flags = OPT_STR_FLAGS
+ },
+ {
+ .name_long = "--huge-worker-stack",
+ .help = "Allocate worker thread stacks from hugepage memory, with optional size (kB)",
+ .val_saver = &args.huge_worker_stack,
+ .val_set = (void *) 1,
+ .flags = OPT_STR_FLAGS
+ },
+ {
+ .name_long = "--in-memory",
+ .help = "DPDK should not create shared mmap files in filesystem",
+ .val_saver = &args.in_memory,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--iova-mode",
+ .help = "IOVA mapping mode, physical (pa)/virtual (va)",
+ .val_saver = &args.iova_mode,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--lcores",
+ .name_short = "-l",
+ .help = "List of CPU cores to use",
+ .val_saver = &args.lcores,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--legacy-mem",
+ .help = "Enable legacy memory behavior",
+ .val_saver = &args.legacy_mem,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--log-color",
+ .help = "Enable/disable color in log output",
+ .val_saver = &args.log_color,
+ .val_set = (void *)1,
+ .flags = OPT_STR_FLAGS
+ },
+ {
+ .name_long = "--log-level",
+ .help = "Log level for all loggers",
+ .val_saver = &args.log_level,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--log-timestamp",
+ .help = "Enable/disable timestamp in log output",
+ .val_saver = &args.log_timestamp,
+ .val_set = (void *)1,
+ .flags = OPT_STR_FLAGS
+ },
+ {
+ .name_long = "--main-lcore",
+ .help = "Select which core to use for the main thread",
+ .val_saver = &args.main_lcore,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--match-allocations",
+ .help = "Free hugepages exactly as allocated",
+ .val_saver = &args.match_allocations,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--mbuf-pool-ops-name",
+ .help = "User defined mbuf default pool ops name",
+ .val_saver = &args.mbuf_pool_ops_name,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--memory-channels",
+ .name_short = "-n",
+ .help = "Number of memory channels per socket",
+ .val_saver = &args.memory_channels,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--memory-ranks",
+ .name_short = "-r",
+ .help = "Number of memory ranks",
+ .val_saver = &args.memory_ranks,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--memory-size",
+ .name_short = "-m",
+ .help = "Total size of memory to allocate initially",
+ .val_saver = &args.memory_size,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--no-hpet",
+ .help = "Disable HPET timer",
+ .val_saver = &args.no_hpet,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--no-huge",
+ .help = "Disable hugetlbfs support",
+ .val_saver = &args.no_huge,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--no-pci",
+ .help = "Disable all PCI devices",
+ .val_saver = &args.no_pci,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--no-shconf",
+ .help = "Disable shared config file generation",
+ .val_saver = &args.no_shconf,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--no-telemetry",
+ .help = "Disable telemetry",
+ .val_saver = &args.no_telemetry,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--proc-type",
+ .help = "Type of process (primary/secondary)",
+ .val_saver = &args.proc_type,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--service-corelist",
+ .name_short = "-S",
+ .help = "List of cores to use for service threads",
+ .val_saver = &args.service_corelist,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--service-coremask",
+ .name_short = "-s",
+ .help = "Hexadecimal bitmask of cores to use for service threads",
+ .val_saver = &args.service_coremask,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--single-file-segments",
+ .help = "Store all pages within single files (per-page-size, per-node)",
+ .val_saver = &args.single_file_segments,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--socket-mem",
+ .help = "List of memory sizes to be allocated per socket on init",
+ .val_saver = &args.socket_mem,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--socket-limit",
+ .help = "Memory limits per socket",
+ .val_saver = &args.socket_limit,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--syslog",
+ .help = "Log to syslog (and optionally set facility)",
+ .val_saver = &args.syslog,
+ .val_set = (void *)1,
+ .flags = OPT_STR_FLAGS
+ },
+ {
+ .name_long = "--telemetry",
+ .help = "Enable telemetry",
+ .val_saver = &args.telemetry,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--trace",
+ .help = "Enable trace based on regular expression trace name",
+ .val_saver = &args.trace,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--trace-bufsz",
+ .help = "Trace buffer size",
+ .val_saver = &args.trace_bufsz,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--trace-dir",
+ .help = "Trace directory",
+ .val_saver = &args.trace_dir,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--trace-mode",
+ .help = "Trace mode",
+ .val_saver = &args.trace_mode,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--vdev",
+ .help = "Virtual device to add to the system",
+ .val_set = (void *)offsetof(struct eal_init_args, vdev),
+ .flags = LIST_FLAGS
+ },
+ {
+ .name_long = "--vfio-intr",
+ .help = "VFIO interrupt mode (legacy|msi|msix)",
+ .val_saver = &args.vfio_intr,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--vfio-vf-token",
+ .help = "VF token (UUID) shared between SR-IOV PF and VFs",
+ .val_saver = &args.vfio_vf_token,
+ .flags = STR_FLAGS
+ },
+ {
+ .name_long = "--vmware-tsc-map",
+ .help = "Use VMware TSC mapping instead of native RDTSC",
+ .val_saver = &args.vmware_tsc_map,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ {
+ .name_long = "--version",
+ .name_short = "-v",
+ .help = "Show version",
+ .val_saver = &args.version,
+ .val_set = (void *)1,
+ .flags = BOOL_FLAGS
+ },
+ ARGPARSE_ARG_END(),
+ }
+};
+
const char
eal_short_options[] =
"a:" /* allow */
diff --git a/lib/eal/meson.build b/lib/eal/meson.build
index e1d6c4cf17..f9fcee24ee 100644
--- a/lib/eal/meson.build
+++ b/lib/eal/meson.build
@@ -14,7 +14,7 @@ subdir(exec_env)
subdir(arch_subdir)
-deps += ['log', 'kvargs']
+deps += ['argparse', 'kvargs']
if not is_windows
deps += ['telemetry']
endif
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH 5/7] eal: gather EAL args before processing
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (3 preceding siblings ...)
2025-05-20 16:40 ` [RFC PATCH 4/7] eal: define the EAL parameters in argparse format Bruce Richardson
@ 2025-05-20 16:40 ` Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 6/7] eal: combine parameter validation checks Bruce Richardson
` (15 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-05-20 16:40 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Anatoly Burakov
DPDK traditionally has iterated through all args and processed them as
they appear in the commandline. The arg processing logic can be
simplified if instead we initially gather all arguments into a structure
which is then processed with the arguments dealt with in a fixed/known
order.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 839 +++++++++++++---------------
lib/eal/common/eal_options.h | 10 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/linux/eal.c | 373 +------------
4 files changed, 419 insertions(+), 814 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index f0cccc1759..bb158a4983 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -46,8 +46,7 @@
#endif
#define BITS_PER_HEX 4
-#define LCORE_OPT_LST 1
-#define LCORE_OPT_MSK 2
+#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
struct arg_list_elem {
TAILQ_ENTRY(arg_list_elem) next;
@@ -465,77 +464,30 @@ struct rte_argparse eal_argparse = {
}
};
-const char
-eal_short_options[] =
- "a:" /* allow */
- "b:" /* block */
- "c:" /* coremask */
- "s:" /* service coremask */
- "d:" /* driver */
- "h" /* help */
- "l:" /* corelist */
- "S:" /* service corelist */
- "m:" /* memory size */
- "n:" /* memory channels */
- "r:" /* memory ranks */
- "v" /* version */
- ;
-
-const struct option
-eal_long_options[] = {
- {OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
- {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
- {OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
- {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
- {OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
- {OPT_HELP, 0, NULL, OPT_HELP_NUM },
- {OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
- {OPT_HUGE_UNLINK, 2, NULL, OPT_HUGE_UNLINK_NUM },
- {OPT_IOVA_MODE, 1, NULL, OPT_IOVA_MODE_NUM },
- {OPT_LCORES, 1, NULL, OPT_LCORES_NUM },
- {OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
- {OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
- {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
- {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
- {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
- {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
- {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
- {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
- {OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
- {OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
- {OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
- {OPT_TRACE_MODE, 1, NULL, OPT_TRACE_MODE_NUM },
- {OPT_MAIN_LCORE, 1, NULL, OPT_MAIN_LCORE_NUM },
- {OPT_MBUF_POOL_OPS_NAME, 1, NULL, OPT_MBUF_POOL_OPS_NAME_NUM},
- {OPT_NO_HPET, 0, NULL, OPT_NO_HPET_NUM },
- {OPT_NO_HUGE, 0, NULL, OPT_NO_HUGE_NUM },
- {OPT_NO_PCI, 0, NULL, OPT_NO_PCI_NUM },
- {OPT_NO_SHCONF, 0, NULL, OPT_NO_SHCONF_NUM },
- {OPT_IN_MEMORY, 0, NULL, OPT_IN_MEMORY_NUM },
- {OPT_DEV_BLOCK, 1, NULL, OPT_DEV_BLOCK_NUM },
- {OPT_DEV_ALLOW, 1, NULL, OPT_DEV_ALLOW_NUM },
- {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM },
- {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM },
- {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM },
-#ifndef RTE_EXEC_ENV_WINDOWS
- {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM },
-#endif
- {OPT_VDEV, 1, NULL, OPT_VDEV_NUM },
- {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
- {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM },
- {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
- {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM },
- {OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM},
- {OPT_MATCH_ALLOCATIONS, 0, NULL, OPT_MATCH_ALLOCATIONS_NUM},
- {OPT_TELEMETRY, 0, NULL, OPT_TELEMETRY_NUM },
- {OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
- {OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
- {OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
- {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
-
-
- {0, 0, NULL, 0 }
-};
+/* function to call into argparse library to parse the passed argc/argv parameters
+ * to the eal_init_args structure.
+ */
+int
+eal_collate_args(int argc, char **argv)
+{
+ if (argc < 1 || argv == NULL)
+ return -EINVAL;
+
+ /* initialize the list of arguments */
+ memset(&args, 0, sizeof(args));
+ TAILQ_INIT(&args.allow);
+ TAILQ_INIT(&args.block);
+ TAILQ_INIT(&args.vdev);
+
+ /* parse the arguments */
+ eal_argparse.prog_name = argv[0];
+ int retval = rte_argparse_parse(&eal_argparse, argc, argv);
+ if (retval < 0)
+ return retval;
+
+ argv[retval - 1] = argv[0];
+ return retval - 1;
+}
TAILQ_HEAD(shared_driver_list, shared_driver);
@@ -577,7 +529,6 @@ static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
static int main_lcore_parsed;
-static int mem_parsed;
static int core_parsed;
/* Allow the application to print its usage message too if set */
@@ -1115,17 +1066,6 @@ eal_parse_service_coremask(const char *coremask)
return 0;
}
-static int
-eal_service_cores_parsed(void)
-{
- int idx;
- for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- if (lcore_config[idx].core_role == ROLE_SERVICE)
- return 1;
- }
- return 0;
-}
-
static int
update_lcore_config(int *cores)
{
@@ -1952,361 +1892,467 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return -1;
}
-bool
-eal_option_is_log(int opt)
+/* Parse all arguments looking for log related ones */
+int
+eal_parse_log_options(void)
{
- switch (opt) {
- case OPT_LOG_COLOR_NUM:
- case OPT_LOG_LEVEL_NUM:
- case OPT_LOG_TIMESTAMP_NUM:
- case OPT_SYSLOG_NUM:
- return true;
- default:
- return false;
+ if (args.log_level != NULL) {
+ if (eal_parse_log_level(args.log_level) < 0) {
+ EAL_LOG(ERR, "invalid log-level parameter");
+ return -1;
+ }
+ }
+ if (args.log_color != NULL) {
+ /* if value is 1, no argument specified, so pass NULL */
+ if (args.log_color == (void *)1)
+ args.log_color = NULL;
+ if (eal_log_color(args.log_color) < 0) {
+ EAL_LOG(ERR, "invalid log-color parameter");
+ return -1;
+ }
+ }
+ if (args.log_timestamp != NULL) {
+ /* similarly log_timestamp may be 1 */
+ if (args.log_timestamp == (void *)1)
+ args.log_timestamp = NULL;
+ if (eal_log_timestamp(args.log_timestamp) < 0) {
+ EAL_LOG(ERR, "invalid log-timestamp parameter");
+ return -1;
+ }
+ }
+ if (args.syslog != NULL) {
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "syslog is not supported on Windows, ignoring parameter");
+#else
+ /* also syslog parameter may be 1 */
+ if (args.syslog == (void *)1)
+ args.syslog = NULL;
+ if (eal_log_syslog(args.syslog) < 0) {
+ EAL_LOG(ERR, "invalid syslog parameter");
+ return -1;
+ }
+#endif
}
+ return 0;
}
-/* Parse all arguments looking for log related ones */
-int
-eal_parse_log_options(int argc, char * const argv[])
+static int
+eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
{
- struct internal_config *internal_conf = eal_get_internal_configuration();
- int option_index, opt;
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_opterr = opterr;
- char *old_optarg = optarg;
-#ifdef RTE_EXEC_ENV_FREEBSD
- const int old_optreset = optreset;
- optreset = 1;
-#endif
+ char *arg[RTE_MAX_NUMA_NODES];
+ char *end;
+ int arg_num, i, len;
- optind = 1;
- opterr = 0;
+ len = strnlen(strval, SOCKET_MEM_STRLEN);
+ if (len == SOCKET_MEM_STRLEN) {
+ EAL_LOG(ERR, "--socket-mem is too long");
+ return -1;
+ }
- while ((opt = getopt_long(argc, argv, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
+ /* all other error cases will be caught later */
+ if (!isdigit(strval[len-1]))
+ return -1;
- if (!eal_option_is_log(opt))
- continue;
+ /* split the optarg into separate socket values */
+ arg_num = rte_strsplit(strval, len,
+ arg, RTE_MAX_NUMA_NODES, ',');
- if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+ /* if split failed, or 0 arguments */
+ if (arg_num <= 0)
+ return -1;
+
+ /* parse each defined socket option */
+ errno = 0;
+ for (i = 0; i < arg_num; i++) {
+ uint64_t val;
+ end = NULL;
+ val = strtoull(arg[i], &end, 10);
+
+ /* check for invalid input */
+ if ((errno != 0) ||
+ (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
+ val <<= 20;
+ socket_arg[i] = val;
}
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
- opterr = old_opterr;
-#ifdef RTE_EXEC_ENV_FREEBSD
- optreset = old_optreset;
-#endif
return 0;
}
+static int
+eal_parse_vfio_intr(const char *mode)
+{
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+ static struct {
+ const char *name;
+ enum rte_intr_mode value;
+ } map[] = {
+ { "legacy", RTE_INTR_MODE_LEGACY },
+ { "msi", RTE_INTR_MODE_MSI },
+ { "msix", RTE_INTR_MODE_MSIX },
+ };
+
+ for (size_t i = 0; i < RTE_DIM(map); i++) {
+ if (!strcmp(mode, map[i].name)) {
+ internal_conf->vfio_intr_mode = map[i].value;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+eal_parse_vfio_vf_token(const char *vf_token)
+{
+ struct internal_config *cfg = eal_get_internal_configuration();
+ rte_uuid_t uuid;
+
+ if (!rte_uuid_parse(vf_token, uuid)) {
+ rte_uuid_copy(cfg->vfio_vf_token, uuid);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+eal_parse_huge_worker_stack(const char *arg)
+{
+ struct internal_config *cfg = eal_get_internal_configuration();
+
+ if (arg == NULL || arg[0] == '\0') {
+ pthread_attr_t attr;
+ int ret;
+
+ if (pthread_attr_init(&attr) != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
+ pthread_attr_destroy(&attr);
+ if (ret != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ } else {
+ unsigned long stack_size;
+ char *end;
+
+ errno = 0;
+ stack_size = strtoul(arg, &end, 10);
+ if (errno || end == NULL || stack_size == 0 ||
+ stack_size >= (size_t)-1 / 1024)
+ return -1;
+
+ cfg->huge_worker_stack_size = stack_size * 1024;
+ }
+
+ EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
+ cfg->huge_worker_stack_size / 1024);
+ return 0;
+}
+
+/* Parse the arguments given in the command line of the application */
int
-eal_parse_common_option(int opt, const char *optarg,
- struct internal_config *conf)
+eal_parse_args(void)
{
- static int b_used;
- static int a_used;
-
- switch (opt) {
- case 'b':
- if (a_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, optarg) < 0)
+ struct internal_config *conf = eal_get_internal_configuration();
+ struct arg_list_elem *arg;
+
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+ /* both -l and -c cannot be used at the same time */
+ if (args.coremask != NULL && args.lcores != NULL) {
+ EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
+ return -1;
+ }
+ /* both -s and -S cannot be used at the same time */
+ if (args.service_coremask != NULL && args.service_corelist != NULL) {
+ EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
+ return -1;
+ }
+ /* can't have both telemetry and no-telemetry */
+ if (args.no_telemetry && args.telemetry) {
+ EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
+ return -1;
+ }
+ /* can't have both -m and --socket-mem */
+ if (args.memory_size != NULL && args.socket_mem != NULL) {
+ EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ return -1;
+ }
+
+ /* parse options */
+ /* print version before anything else */
+ if (args.version) {
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
+ }
+
+ /* parse the process type */
+ if (args.proc_type != NULL) {
+ conf->process_type = eal_parse_proc_type(args.proc_type);
+ if (conf->process_type == RTE_PROC_INVALID) {
+ EAL_LOG(ERR, "invalid process type: %s", args.proc_type);
return -1;
- b_used = 1;
- break;
+ }
+ }
- case 'a':
- if (b_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, optarg) < 0)
+ /* device -a/-b/-vdev options*/
+ TAILQ_FOREACH(arg, &args.allow, next)
+ if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, arg->arg) < 0)
return -1;
- a_used = 1;
- break;
- /* coremask */
- case 'c': {
+ TAILQ_FOREACH(arg, &args.block, next)
+ if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, arg->arg) < 0)
+ return -1;
+ TAILQ_FOREACH(arg, &args.vdev, next)
+ if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, arg->arg) < 0)
+ return -1;
+ /* driver loading options */
+ TAILQ_FOREACH(arg, &args.driver_path, next)
+ if (eal_plugin_add(arg->arg) < 0)
+ return -1;
+
+ /* parse the coremask /core-list */
+ if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -c is before -s or -S");
- if (rte_eal_parse_coremask(optarg, lcore_indexes) < 0) {
+ if (rte_eal_parse_coremask(args.coremask, lcore_indexes) < 0) {
EAL_LOG(ERR, "invalid coremask syntax");
return -1;
}
if (update_lcore_config(lcore_indexes) < 0) {
char *available = available_cores();
- EAL_LOG(ERR,
- "invalid coremask, please check specified cores are part of %s",
- available);
+ EAL_LOG(ERR, "invalid coremask '%s', please check specified cores are part of %s",
+ args.coremask, available);
free(available);
return -1;
}
-
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_MSK)
- EAL_LOG(ERR, "Option '-c' passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option -c is ignored, because option -l/--lcores used");
+ core_parsed = 1;
+ } else if (args.lcores != NULL) {
+ if (eal_parse_lcores(args.lcores) < 0) {
+ EAL_LOG(ERR, "invalid lcore list: '%s'", args.lcores);
return -1;
}
-
- core_parsed = LCORE_OPT_MSK;
- break;
+ core_parsed = 1;
}
- /* corelist */
- case 'l': {
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -l is before -s or -S");
-
- if (eal_parse_lcores(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for -l/--" OPT_LCORES);
- return -1;
- }
-
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_LST)
- EAL_LOG(ERR, "Core list option passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option '-l/--lcores' is ignored, because coremask option used");
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0) {
+ EAL_LOG(ERR, "invalid main-lcore parameter");
return -1;
}
-
- core_parsed = LCORE_OPT_LST;
- break;
}
- /* service coremask */
- case 's':
- if (eal_parse_service_coremask(optarg) < 0) {
- EAL_LOG(ERR, "invalid service coremask");
+
+ /* service core options */
+ if (args.service_coremask != NULL) {
+ if (eal_parse_service_coremask(args.service_coremask) < 0) {
+ EAL_LOG(ERR, "invalid service coremask: '%s'",
+ args.service_coremask);
return -1;
}
- break;
- /* service corelist */
- case 'S':
- if (eal_parse_service_corelist(optarg) < 0) {
- EAL_LOG(ERR, "invalid service core list");
+ } else if (args.service_corelist != NULL) {
+ if (eal_parse_service_corelist(args.service_corelist) < 0) {
+ EAL_LOG(ERR, "invalid service core list: '%s'",
+ args.service_corelist);
return -1;
}
- break;
- /* size of memory */
- case 'm':
- conf->memory = atoi(optarg);
+ }
+
+ /* memory options */
+ if (args.memory_size != NULL) {
+ conf->memory = atoi(args.memory_size);
conf->memory *= 1024ULL;
conf->memory *= 1024ULL;
- mem_parsed = 1;
- break;
- /* force number of channels */
- case 'n':
- conf->force_nchannel = atoi(optarg);
+ }
+ if (args.memory_channels != NULL) {
+ conf->force_nchannel = atoi(args.memory_channels);
if (conf->force_nchannel == 0) {
- EAL_LOG(ERR, "invalid channel number");
+ EAL_LOG(ERR, "invalid memory channel parameter");
return -1;
}
- break;
- /* force number of ranks */
- case 'r':
- conf->force_nrank = atoi(optarg);
- if (conf->force_nrank == 0 ||
- conf->force_nrank > 16) {
- EAL_LOG(ERR, "invalid rank number");
+ }
+ if (args.memory_ranks != NULL) {
+ conf->force_nrank = atoi(args.memory_ranks);
+ if (conf->force_nrank == 0 || conf->force_nrank > 16) {
+ EAL_LOG(ERR, "invalid memory rank parameter");
return -1;
}
- break;
- /* force loading of external driver */
- case 'd':
- if (eal_plugin_add(optarg) == -1)
- return -1;
- break;
- case 'v':
- /* since message is explicitly requested by user, we
- * write message at highest log level so it can always
- * be seen
- * even if info or warning messages are disabled */
- EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- break;
-
- /* long options */
- case OPT_HUGE_UNLINK_NUM:
- if (eal_parse_huge_unlink(optarg, &conf->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid --"OPT_HUGE_UNLINK" option");
+ }
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &conf->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
return -1;
}
- break;
-
- case OPT_NO_HUGE_NUM:
+ }
+ if (args.no_huge) {
conf->no_hugetlbfs = 1;
/* no-huge is legacy mem */
conf->legacy_mem = 1;
- break;
-
- case OPT_NO_PCI_NUM:
- conf->no_pci = 1;
- break;
-
- case OPT_NO_HPET_NUM:
- conf->no_hpet = 1;
- break;
-
- case OPT_VMWARE_TSC_MAP_NUM:
- conf->vmware_tsc_map = 1;
- break;
-
- case OPT_NO_SHCONF_NUM:
- conf->no_shconf = 1;
- break;
-
- case OPT_IN_MEMORY_NUM:
+ }
+ if (args.in_memory) {
conf->in_memory = 1;
/* in-memory is a superset of noshconf and huge-unlink */
conf->no_shconf = 1;
conf->hugepage_file.unlink_before_mapping = true;
- break;
-
- case OPT_PROC_TYPE_NUM:
- conf->process_type = eal_parse_proc_type(optarg);
- break;
-
- case OPT_MAIN_LCORE_NUM:
- if (eal_parse_main_lcore(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_MAIN_LCORE);
+ }
+ if (args.legacy_mem)
+ conf->legacy_mem = 1;
+ if (args.single_file_segments)
+ conf->single_file_segments = 1;
+ if (args.huge_dir != NULL) {
+ free(conf->hugepage_dir); /* free old hugepage dir */
+ conf->hugepage_dir = args.huge_dir;
+ }
+ if (args.file_prefix != NULL) {
+ free(conf->hugefile_prefix); /* free old file prefix */
+ conf->hugefile_prefix = args.file_prefix;
+ }
+ if (args.socket_mem != NULL) {
+ if (eal_parse_socket_arg(args.socket_mem, conf->socket_mem) < 0) {
+ EAL_LOG(ERR, "invalid socket-mem parameter: '%s'", args.socket_mem);
return -1;
}
- break;
-
- case OPT_VDEV_NUM:
- if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
- optarg) < 0) {
+ conf->force_sockets = 1;
+ }
+ if (args.socket_limit != NULL) {
+ if (eal_parse_socket_arg(args.socket_limit, conf->socket_limit) < 0) {
+ EAL_LOG(ERR, "invalid socket limit parameter: '%s'", args.socket_limit);
return -1;
}
- break;
+ conf->force_socket_limits = 1;
+ }
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_SYSLOG_NUM:
- if (eal_log_syslog(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_SYSLOG);
+ /* tracing settings, not supported on windows */
+#ifdef RTE_EXEC_ENV_WINDOWS
+ if (args.trace != NULL ||
+ args.trace_dir != NULL ||
+ args.trace_bufsz != NULL ||
+ args.trace_mode != NULL)
+ EAL_LOG(WARNING, "Tracing is not supported on Windows, ignoring tracing parameters");
+#else
+ if (args.trace != NULL) {
+ if (eal_trace_args_save(args.trace) < 0) {
+ EAL_LOG(ERR, "invalid trace parameter, '%s'", args.trace);
return -1;
}
- break;
-#endif
-
- case OPT_LOG_LEVEL_NUM:
- if (eal_parse_log_level(optarg) < 0) {
- EAL_LOG(ERR,
- "invalid parameters for --"
- OPT_LOG_LEVEL);
+ }
+ if (args.trace_dir != NULL) {
+ if (eal_trace_dir_args_save(args.trace_dir) < 0) {
+ EAL_LOG(ERR, "invalid trace directory, '%s'", args.trace_dir);
return -1;
}
- break;
-
- case OPT_LOG_TIMESTAMP_NUM:
- if (eal_log_timestamp(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_TIMESTAMP);
+ }
+ if (args.trace_bufsz != NULL) {
+ if (eal_trace_bufsz_args_save(args.trace_bufsz) < 0) {
+ EAL_LOG(ERR, "invalid trace buffer size, '%s'", args.trace_bufsz);
return -1;
}
- break;
-
- case OPT_LOG_COLOR_NUM:
- if (eal_log_color(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_COLOR);
+ }
+ if (args.trace_mode != NULL) {
+ if (eal_trace_mode_args_save(args.trace_mode) < 0) {
+ EAL_LOG(ERR, "invalid trace mode, '%s'", args.trace_mode);
return -1;
}
- break;
+ }
+#endif
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_TRACE_NUM: {
- if (eal_trace_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE);
+ /* simple flag settings
+ * Only set these to 1, as we don't want to set them to 0 in case
+ * other options above have already set them.
+ */
+ if (args.no_pci)
+ conf->no_pci = 1;
+ if (args.no_hpet)
+ conf->no_hpet = 1;
+ if (args.vmware_tsc_map)
+ conf->vmware_tsc_map = 1;
+ if (args.no_shconf)
+ conf->no_shconf = 1;
+ if (args.no_telemetry)
+ conf->no_telemetry = 1;
+ if (args.match_allocations)
+ conf->match_allocations = 1;
+ if (args.create_uio_dev)
+ conf->create_uio_dev = 1;
+
+
+ /* other misc settings */
+ if (args.iova_mode != NULL) {
+ if (eal_parse_iova_mode(args.iova_mode) < 0) {
+ EAL_LOG(ERR, "invalid iova mode parameter '%s'", args.iova_mode);
return -1;
}
- break;
- }
-
- case OPT_TRACE_DIR_NUM: {
- if (eal_trace_dir_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_DIR);
+ };
+ if (args.base_virtaddr != NULL) {
+ if (eal_parse_base_virtaddr(args.base_virtaddr) < 0) {
+ EAL_LOG(ERR, "invalid base virtaddr '%s'", args.base_virtaddr);
return -1;
}
- break;
}
-
- case OPT_TRACE_BUF_SIZE_NUM: {
- if (eal_trace_bufsz_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_BUF_SIZE);
+ if (args.force_max_simd_bitwidth != NULL) {
+ if (eal_parse_simd_bitwidth(args.force_max_simd_bitwidth) < 0) {
+ EAL_LOG(ERR, "invalid SIMD bitwidth parameter '%s'",
+ args.force_max_simd_bitwidth);
return -1;
}
- break;
}
-
- case OPT_TRACE_MODE_NUM: {
- if (eal_trace_mode_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_MODE);
+ if (args.vfio_intr != NULL) {
+ if (eal_parse_vfio_intr(args.vfio_intr) < 0) {
+ EAL_LOG(ERR, "invalid vfio interrupt parameter: '%s'", args.vfio_intr);
return -1;
}
- break;
}
-#endif /* !RTE_EXEC_ENV_WINDOWS */
-
- case OPT_LEGACY_MEM_NUM:
- conf->legacy_mem = 1;
- break;
- case OPT_SINGLE_FILE_SEGMENTS_NUM:
- conf->single_file_segments = 1;
- break;
- case OPT_IOVA_MODE_NUM:
- if (eal_parse_iova_mode(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_IOVA_MODE);
+ if (args.vfio_vf_token != NULL) {
+ if (eal_parse_vfio_vf_token(args.vfio_vf_token) < 0) {
+ EAL_LOG(ERR, "invalid vfio vf token parameter: '%s'", args.vfio_vf_token);
return -1;
}
- break;
- case OPT_BASE_VIRTADDR_NUM:
- if (eal_parse_base_virtaddr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_BASE_VIRTADDR);
+ }
+
+ if (args.huge_worker_stack != NULL) {
+ if (args.huge_worker_stack == (void *)1)
+ args.huge_worker_stack = NULL;
+ if (eal_parse_huge_worker_stack(args.huge_worker_stack) < 0) {
+ EAL_LOG(ERR, "invalid huge worker stack parameter");
return -1;
}
- break;
- case OPT_TELEMETRY_NUM:
- break;
- case OPT_NO_TELEMETRY_NUM:
- conf->no_telemetry = 1;
- break;
- case OPT_FORCE_MAX_SIMD_BITWIDTH_NUM:
- if (eal_parse_simd_bitwidth(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_FORCE_MAX_SIMD_BITWIDTH);
+ }
+ if (args.mbuf_pool_ops_name != NULL) {
+ free(conf->user_mbuf_pool_ops_name); /* free old ops name */
+ conf->user_mbuf_pool_ops_name = args.mbuf_pool_ops_name;
+ }
+
+ /* create runtime data directory. In no_shconf mode, skip any errors */
+ if (eal_create_runtime_dir() < 0) {
+ if (conf->no_shconf == 0) {
+ EAL_LOG(ERR, "Cannot create runtime directory");
return -1;
}
- break;
+ EAL_LOG(WARNING, "No DPDK runtime directory created");
+ }
- /* don't know what to do, leave this to caller */
- default:
- return 1;
+ if (eal_adjust_config(conf) != 0) {
+ EAL_LOG(ERR, "Invalid configuration");
+ return -1;
+ }
+ if (eal_check_common_options(conf) != 0) {
+ EAL_LOG(ERR, "Checking common options failed");
+ return -1;
}
return 0;
-
-ba_conflict:
- EAL_LOG(ERR,
- "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
}
static void
@@ -2434,11 +2480,6 @@ eal_check_common_options(struct internal_config *internal_cfg)
"option");
return -1;
}
- if (mem_parsed && internal_cfg->force_sockets == 1) {
- EAL_LOG(ERR, "Options -m and --"OPT_SOCKET_MEM" cannot "
- "be specified at the same time");
- return -1;
- }
if (internal_cfg->no_hugetlbfs && internal_cfg->force_sockets == 1) {
EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
"be specified together with --"OPT_NO_HUGE);
@@ -2526,97 +2567,3 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth)
internal_conf->max_simd_bitwidth.bitwidth = bitwidth;
return 0;
}
-
-void
-eal_common_usage(void)
-{
- printf("[options]\n\n"
- "EAL common options:\n"
- " -c COREMASK Hexadecimal bitmask of cores to run on\n"
- " -l, --"OPT_LCORES" CORELIST\n"
- " List of cores to run on\n"
- " The basic argument format is <c1>[-c2][,c3[-c4],...]\n"
- " where c1, c2, etc are core indexes between 0 and %d\n"
- " Can also be used to map lcore set to physical cpu set\n"
- " The argument format is\n"
- " '<lcores[@cpus]>[<,lcores[@cpus]>...]'\n"
- " lcores and cpus list are grouped by '(' and ')'\n"
- " Within the group, '-' is used for range separator,\n"
- " ',' is used for single number separator.\n"
- " '( )' can be omitted for single element group,\n"
- " '@' can be omitted if cpus and lcores have the same value\n"
- " -s SERVICE COREMASK Hexadecimal bitmask of cores to be used as service cores\n"
- " --"OPT_MAIN_LCORE" ID Core ID that is used as main\n"
- " --"OPT_MBUF_POOL_OPS_NAME" Pool ops name for mbuf to use\n"
- " -n CHANNELS Number of memory channels\n"
- " -m MB Memory to allocate (see also --"OPT_SOCKET_MEM")\n"
- " -r RANKS Force number of memory ranks (don't detect)\n"
- " -b, --block Add a device to the blocked list.\n"
- " Prevent EAL from using this device. The argument\n"
- " format for PCI devices is <domain:bus:devid.func>.\n"
- " -a, --allow Add a device to the allow list.\n"
- " Only use the specified devices. The argument format\n"
- " for PCI devices is <[domain:]bus:devid.func>.\n"
- " This option can be present several times.\n"
- " [NOTE: " OPT_DEV_ALLOW " cannot be used with "OPT_DEV_BLOCK" option]\n"
- " --"OPT_VDEV" Add a virtual device.\n"
- " The argument format is <driver><id>[,key=val,...]\n"
- " (ex: --vdev=net_pcap0,iface=eth2).\n"
- " --"OPT_IOVA_MODE" Set IOVA mode. 'pa' for IOVA_PA\n"
- " 'va' for IOVA_VA\n"
- " -d LIB.so|DIR Add a driver or driver directory\n"
- " (can be used multiple times)\n"
- " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n"
- " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_SYSLOG"[=<facility>] Enable use of syslog (and optionally set facility)\n"
-#endif
- " --"OPT_LOG_LEVEL"=<level> Set global log level\n"
- " --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
- " Set specific log level\n"
- " --"OPT_LOG_LEVEL"=help Show log types and levels\n"
- " --"OPT_LOG_TIMESTAMP"[=<format>] Timestamp log output\n"
- " --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_TRACE"=<regex-match>\n"
- " Enable trace based on regular expression trace name.\n"
- " By default, the trace is disabled.\n"
- " User must specify this option to enable trace.\n"
- " --"OPT_TRACE_DIR"=<directory path>\n"
- " Specify trace directory for trace output.\n"
- " By default, trace output will created at\n"
- " $HOME directory and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_BUF_SIZE"=<int>\n"
- " Specify maximum size of allocated memory\n"
- " for trace output for each thread. Valid\n"
- " unit can be either 'B|K|M' for 'Bytes',\n"
- " 'KBytes' and 'MBytes' respectively.\n"
- " Default is 1MB and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_MODE"=<o[verwrite] | d[iscard]>\n"
- " Specify the mode of update of trace\n"
- " output file. Either update on a file can\n"
- " be wrapped or discarded when file size\n"
- " reaches its maximum limit.\n"
- " Default mode is 'overwrite' and parameter\n"
- " must be specified once only.\n"
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- " -v Display version information on startup\n"
- " -h, --"OPT_HELP" This help\n"
- " --"OPT_IN_MEMORY" Operate entirely in memory. This will\n"
- " disable secondary process support\n"
- " --"OPT_BASE_VIRTADDR" Base virtual address\n"
- " --"OPT_TELEMETRY" Enable telemetry support (on by default)\n"
- " --"OPT_NO_TELEMETRY" Disable telemetry support\n"
- " --"OPT_FORCE_MAX_SIMD_BITWIDTH" Force the max SIMD bitwidth\n"
- "\nEAL options for DEBUG use only:\n"
- " --"OPT_HUGE_UNLINK"[=existing|always|never]\n"
- " When to unlink files in hugetlbfs\n"
- " ('existing' by default, no value means 'always')\n"
- " --"OPT_NO_HUGE" Use malloc instead of hugetlbfs\n"
- " --"OPT_NO_PCI" Disable PCI\n"
- " --"OPT_NO_HPET" Disable HPET\n"
- " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n"
- "\n", RTE_MAX_LCORE);
-}
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index e493821db1..41f95c4a1d 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -113,18 +113,12 @@ enum {
OPT_LONG_MAX_NUM
};
-extern const char eal_short_options[];
-extern const struct option eal_long_options[];
-
-bool eal_option_is_log(int opt);
-int eal_parse_log_options(int argc, char * const argv[]);
-int eal_parse_common_option(int opt, const char *argv,
- struct internal_config *conf);
+int eal_parse_log_options(void);
+int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
int eal_check_common_options(struct internal_config *internal_cfg);
-void eal_common_usage(void);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index 04ba8ddb86..fd95a82682 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -72,6 +72,17 @@ struct rte_config {
*/
struct rte_config *rte_eal_get_configuration(void);
+/**
+ * Put the argument list into a structure.
+ *
+ * This allows the arguments to then be processed out-of-order.
+ *
+ * @return
+ * - 0 on success
+ * - Negative on error
+ */
+int eal_collate_args(int argc, char **argv);
+
/**
* Initialize the memzone subsystem (private to eal).
*
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 20f777b8b0..2a68a02bfd 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -58,9 +58,6 @@
#include "log_internal.h"
#define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
-
-#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
-
#define KERNEL_IOMMU_GROUPS_PATH "/sys/kernel/iommu_groups"
/* define fd variable here, because file needs to be kept open for the
@@ -437,356 +434,6 @@ eal_hugedirs_unlock(void)
}
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- printf("EAL Linux options:\n"
- " --"OPT_SOCKET_MEM" Memory to allocate on sockets (comma separated values)\n"
- " --"OPT_SOCKET_LIMIT" Limit memory allocation on sockets (comma separated values)\n"
- " --"OPT_HUGE_DIR" Directory where hugetlbfs is mounted\n"
- " --"OPT_FILE_PREFIX" Prefix for hugepage filenames\n"
- " --"OPT_CREATE_UIO_DEV" Create /dev/uioX (usually done by hotplug)\n"
- " --"OPT_VFIO_INTR" Interrupt mode for VFIO (legacy|msi|msix)\n"
- " --"OPT_VFIO_VF_TOKEN" VF token (UUID) shared between SR-IOV PF and VFs\n"
- " --"OPT_LEGACY_MEM" Legacy memory mode (no dynamic allocation, contiguous segments)\n"
- " --"OPT_SINGLE_FILE_SEGMENTS" Put all hugepage memory in single files\n"
- " --"OPT_MATCH_ALLOCATIONS" Free hugepages exactly as allocated\n"
- " --"OPT_HUGE_WORKER_STACK"[=size]\n"
- " Allocate worker thread stacks from hugepage memory.\n"
- " Size is in units of kbytes and defaults to system\n"
- " thread stack size if not specified.\n"
- "\n");
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-static int
-eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
-{
- char * arg[RTE_MAX_NUMA_NODES];
- char *end;
- int arg_num, i, len;
-
- len = strnlen(strval, SOCKET_MEM_STRLEN);
- if (len == SOCKET_MEM_STRLEN) {
- EAL_LOG(ERR, "--socket-mem is too long");
- return -1;
- }
-
- /* all other error cases will be caught later */
- if (!isdigit(strval[len-1]))
- return -1;
-
- /* split the optarg into separate socket values */
- arg_num = rte_strsplit(strval, len,
- arg, RTE_MAX_NUMA_NODES, ',');
-
- /* if split failed, or 0 arguments */
- if (arg_num <= 0)
- return -1;
-
- /* parse each defined socket option */
- errno = 0;
- for (i = 0; i < arg_num; i++) {
- uint64_t val;
- end = NULL;
- val = strtoull(arg[i], &end, 10);
-
- /* check for invalid input */
- if ((errno != 0) ||
- (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
- return -1;
- val <<= 20;
- socket_arg[i] = val;
- }
-
- return 0;
-}
-
-static int
-eal_parse_vfio_intr(const char *mode)
-{
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
- unsigned i;
- static struct {
- const char *name;
- enum rte_intr_mode value;
- } map[] = {
- { "legacy", RTE_INTR_MODE_LEGACY },
- { "msi", RTE_INTR_MODE_MSI },
- { "msix", RTE_INTR_MODE_MSIX },
- };
-
- for (i = 0; i < RTE_DIM(map); i++) {
- if (!strcmp(mode, map[i].name)) {
- internal_conf->vfio_intr_mode = map[i].value;
- return 0;
- }
- }
- return -1;
-}
-
-static int
-eal_parse_vfio_vf_token(const char *vf_token)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
- rte_uuid_t uuid;
-
- if (!rte_uuid_parse(vf_token, uuid)) {
- rte_uuid_copy(cfg->vfio_vf_token, uuid);
- return 0;
- }
-
- return -1;
-}
-
-static int
-eal_parse_huge_worker_stack(const char *arg)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
-
- if (arg == NULL || arg[0] == '\0') {
- pthread_attr_t attr;
- int ret;
-
- if (pthread_attr_init(&attr) != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
- pthread_attr_destroy(&attr);
- if (ret != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- } else {
- unsigned long stack_size;
- char *end;
-
- errno = 0;
- stack_size = strtoul(arg, &end, 10);
- if (errno || end == NULL || stack_size == 0 ||
- stack_size >= (size_t)-1 / 1024)
- return -1;
-
- cfg->huge_worker_stack_size = stack_size * 1024;
- }
-
- EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
- cfg->huge_worker_stack_size / 1024);
- return 0;
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
-
- case OPT_HUGE_DIR_NUM:
- {
- char *hdir = strdup(optarg);
- if (hdir == NULL)
- EAL_LOG(ERR, "Could not store hugepage directory");
- else {
- /* free old hugepage dir */
- free(internal_conf->hugepage_dir);
- internal_conf->hugepage_dir = hdir;
- }
- break;
- }
- case OPT_FILE_PREFIX_NUM:
- {
- char *prefix = strdup(optarg);
- if (prefix == NULL)
- EAL_LOG(ERR, "Could not store file prefix");
- else {
- /* free old prefix */
- free(internal_conf->hugefile_prefix);
- internal_conf->hugefile_prefix = prefix;
- }
- break;
- }
- case OPT_SOCKET_MEM_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->socket_mem) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_SOCKET_MEM);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_sockets = 1;
- break;
-
- case OPT_SOCKET_LIMIT_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->socket_limit) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_SOCKET_LIMIT);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_socket_limits = 1;
- break;
-
- case OPT_VFIO_INTR_NUM:
- if (eal_parse_vfio_intr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_INTR);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_VFIO_VF_TOKEN_NUM:
- if (eal_parse_vfio_vf_token(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_VF_TOKEN);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_CREATE_UIO_DEV_NUM:
- internal_conf->create_uio_dev = 1;
- break;
-
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_MATCH_ALLOCATIONS_NUM:
- internal_conf->match_allocations = 1;
- break;
-
- case OPT_HUGE_WORKER_STACK_NUM:
- if (eal_parse_huge_worker_stack(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_HUGE_WORKER_STACK);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Linux", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Linux",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Linux", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -931,8 +578,18 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -963,18 +620,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH 6/7] eal: combine parameter validation checks
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (4 preceding siblings ...)
2025-05-20 16:40 ` [RFC PATCH 5/7] eal: gather EAL args before processing Bruce Richardson
@ 2025-05-20 16:40 ` Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 7/7] eal: simplify handling of conflicting cmdline options Bruce Richardson
` (14 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-05-20 16:40 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Anatoly Burakov, Tyler Retzlaff
Remove the separate function to check combinations of cmdline
parameters. Instead, just do those checks when parsing the parameters
since we have all info about what parameters are provided at that point.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 332 ++++++++++++----------------
lib/eal/common/eal_options.h | 105 ---------
lib/eal/linux/eal.c | 5 +-
4 files changed, 140 insertions(+), 305 deletions(-)
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index a2f64408f4..b4ba9a9d8b 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -252,8 +252,7 @@ eal_memseg_list_alloc(struct rte_memseg_list *msl, int reserve_flags)
* including common code, so don't duplicate the message.
*/
if (rte_errno == EADDRNOTAVAIL)
- EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - "
- "please use '--" OPT_BASE_VIRTADDR "' option",
+ EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - please use '--base-virtaddr' option",
(unsigned long long)mem_sz, msl->base_va);
#endif
return -1;
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index bb158a4983..50a2b139db 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -528,7 +528,6 @@ struct device_option {
static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
-static int main_lcore_parsed;
static int core_parsed;
/* Allow the application to print its usage message too if set */
@@ -1021,15 +1020,6 @@ eal_parse_service_coremask(const char *coremask)
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE;
j++, idx++) {
if ((1 << j) & val) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (main_lcore_parsed &&
- cfg->main_lcore == lcore) {
- EAL_LOG(ERR,
- "lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (eal_cpu_detected(idx) == 0) {
EAL_LOG(ERR,
@@ -1252,15 +1242,6 @@ eal_parse_service_corelist(const char *corelist)
min = idx;
for (idx = min; idx <= max; idx++) {
if (cfg->lcore_role[idx] != ROLE_SERVICE) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (cfg->main_lcore == lcore &&
- main_lcore_parsed) {
- EAL_LOG(ERR,
- "Error: lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (cfg->lcore_role[idx] == ROLE_RTE)
taken_lcore_count++;
@@ -1300,12 +1281,15 @@ eal_parse_main_lcore(const char *arg)
return -1;
if (cfg->main_lcore >= RTE_MAX_LCORE)
return -1;
- main_lcore_parsed = 1;
/* ensure main core is not used as service core */
if (lcore_config[cfg->main_lcore].core_role == ROLE_SERVICE) {
- EAL_LOG(ERR,
- "Error: Main lcore is used as a service core");
+ EAL_LOG(ERR, "Error: Main lcore is used as a service core");
+ return -1;
+ }
+ /* check that we have the core recorded in the core list */
+ if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
+ EAL_LOG(ERR, "Error: Main lcore is not enabled for DPDK");
return -1;
}
@@ -1600,11 +1584,11 @@ eal_log_usage(void)
rte_log_list_types(stdout, "\t");
printf("\n");
printf("Syntax using globbing pattern: ");
- printf("--"OPT_LOG_LEVEL" pattern:level\n");
+ printf("--log-level pattern:level\n");
printf("Syntax using regular expression: ");
- printf("--"OPT_LOG_LEVEL" regexp,level\n");
+ printf("--log-level regexp,level\n");
printf("Syntax for the global level: ");
- printf("--"OPT_LOG_LEVEL" level\n");
+ printf("--log-level level\n");
printf("Logs are emitted if allowed by both global and specific levels.\n");
printf("\n");
printf("Log level can be a number or the first letters of its name:\n");
@@ -1884,7 +1868,7 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return 0;
}
if (strcmp(arg, HUGE_UNLINK_NEVER) == 0) {
- EAL_LOG(WARNING, "Using --"OPT_HUGE_UNLINK"="
+ EAL_LOG(WARNING, "Using --huge-unlink="
HUGE_UNLINK_NEVER" may create data leaks.");
out->unlink_existing = false;
return 0;
@@ -2057,7 +2041,8 @@ eal_parse_huge_worker_stack(const char *arg)
int
eal_parse_args(void)
{
- struct internal_config *conf = eal_get_internal_configuration();
+ struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
/* check for conflicting options */
@@ -2086,21 +2071,64 @@ eal_parse_args(void)
EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
return -1;
}
+ /* can't use both no-huge and socket-mem */
+ if (args.no_huge && args.socket_mem) {
+ EAL_LOG(ERR, "Options --no-huge and --socket-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-worker-stack */
+ if (args.huge_worker_stack != NULL && args.no_huge) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
+ return -1;
+ }
+ /* can't use socket-limit and legacy-mem */
+ if (args.socket_limit != NULL && args.legacy_mem) {
+ EAL_LOG(ERR, "Options --socket-limit and --legacy-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and in-memory */
+ if (args.legacy_mem && args.in_memory) {
+ EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and match-allocations */
+ if (args.legacy_mem && args.match_allocations) {
+ EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and match-allocations */
+ if (args.no_huge && args.match_allocations) {
+ EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-unlink */
+ if (args.no_huge && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use single-file-segments and huge-unlink */
+ if (args.single_file_segments && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use in-memory and huge-unlink */
+ if (args.in_memory && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
+ return -1;
+ }
- /* parse options */
/* print version before anything else */
- if (args.version) {
- /* since message is explicitly requested by user, we write message
- * at highest log level so it can always be seen even if info or
- * warning messages are disabled
- */
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ if (args.version)
EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- }
/* parse the process type */
if (args.proc_type != NULL) {
- conf->process_type = eal_parse_proc_type(args.proc_type);
- if (conf->process_type == RTE_PROC_INVALID) {
+ int_cfg->process_type = eal_parse_proc_type(args.proc_type);
+ if (int_cfg->process_type == RTE_PROC_INVALID) {
EAL_LOG(ERR, "invalid process type: %s", args.proc_type);
return -1;
}
@@ -2121,7 +2149,7 @@ eal_parse_args(void)
if (eal_plugin_add(arg->arg) < 0)
return -1;
- /* parse the coremask /core-list */
+ /* parse the core list arguments */
if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
@@ -2145,13 +2173,6 @@ eal_parse_args(void)
}
core_parsed = 1;
}
- if (args.main_lcore != NULL) {
- if (eal_parse_main_lcore(args.main_lcore) < 0) {
- EAL_LOG(ERR, "invalid main-lcore parameter");
- return -1;
- }
- }
-
/* service core options */
if (args.service_coremask != NULL) {
if (eal_parse_service_coremask(args.service_coremask) < 0) {
@@ -2166,71 +2187,97 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0)
+ return -1;
+ } else {
+ /* default main lcore is the first one */
+ rte_cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
+ if (rte_cfg->main_lcore >= RTE_MAX_LCORE) {
+ EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
+ return -1;
+ }
+ }
/* memory options */
if (args.memory_size != NULL) {
- conf->memory = atoi(args.memory_size);
- conf->memory *= 1024ULL;
- conf->memory *= 1024ULL;
+ int_cfg->memory = atoi(args.memory_size);
+ int_cfg->memory *= 1024ULL;
+ int_cfg->memory *= 1024ULL;
}
if (args.memory_channels != NULL) {
- conf->force_nchannel = atoi(args.memory_channels);
- if (conf->force_nchannel == 0) {
+ int_cfg->force_nchannel = atoi(args.memory_channels);
+ if (int_cfg->force_nchannel == 0) {
EAL_LOG(ERR, "invalid memory channel parameter");
return -1;
}
}
if (args.memory_ranks != NULL) {
- conf->force_nrank = atoi(args.memory_ranks);
- if (conf->force_nrank == 0 || conf->force_nrank > 16) {
+ int_cfg->force_nrank = atoi(args.memory_ranks);
+ if (int_cfg->force_nrank == 0 || int_cfg->force_nrank > 16) {
EAL_LOG(ERR, "invalid memory rank parameter");
return -1;
}
}
- if (args.huge_unlink != NULL) {
- if (args.huge_unlink == (void *)1)
- args.huge_unlink = NULL;
- if (eal_parse_huge_unlink(args.huge_unlink, &conf->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid huge-unlink parameter");
- return -1;
- }
- }
if (args.no_huge) {
- conf->no_hugetlbfs = 1;
+ int_cfg->no_hugetlbfs = 1;
/* no-huge is legacy mem */
- conf->legacy_mem = 1;
+ int_cfg->legacy_mem = 1;
}
if (args.in_memory) {
- conf->in_memory = 1;
+ int_cfg->in_memory = 1;
/* in-memory is a superset of noshconf and huge-unlink */
- conf->no_shconf = 1;
- conf->hugepage_file.unlink_before_mapping = true;
+ int_cfg->no_shconf = 1;
+ int_cfg->hugepage_file.unlink_before_mapping = true;
+ }
+ if (args.legacy_mem) {
+ int_cfg->legacy_mem = 1;
+ if (args.memory_size == NULL && args.socket_mem == NULL)
+ EAL_LOG(NOTICE, "Static memory layout is selected, amount of reserved memory can be adjusted with -m or --socket-mem");
}
- if (args.legacy_mem)
- conf->legacy_mem = 1;
if (args.single_file_segments)
- conf->single_file_segments = 1;
+ int_cfg->single_file_segments = 1;
if (args.huge_dir != NULL) {
- free(conf->hugepage_dir); /* free old hugepage dir */
- conf->hugepage_dir = args.huge_dir;
+ if (strlen(args.huge_dir) < 1) {
+ EAL_LOG(ERR, "Invalid hugepage dir parameter");
+ return -1;
+ }
+ free(int_cfg->hugepage_dir); /* free old hugepage dir */
+ int_cfg->hugepage_dir = args.huge_dir;
}
if (args.file_prefix != NULL) {
- free(conf->hugefile_prefix); /* free old file prefix */
- conf->hugefile_prefix = args.file_prefix;
+ if (strlen(args.file_prefix) < 1) {
+ EAL_LOG(ERR, "Invalid file prefix parameter");
+ return -1;
+ }
+ if (strchr(args.file_prefix, '%') != NULL) {
+ EAL_LOG(ERR, "Invalid char, '%%', in file_prefix parameter");
+ return -1;
+ }
+ free(int_cfg->hugefile_prefix); /* free old file prefix */
+ int_cfg->hugefile_prefix = args.file_prefix;
+ }
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
+ return -1;
+ }
}
if (args.socket_mem != NULL) {
- if (eal_parse_socket_arg(args.socket_mem, conf->socket_mem) < 0) {
+ if (eal_parse_socket_arg(args.socket_mem, int_cfg->socket_mem) < 0) {
EAL_LOG(ERR, "invalid socket-mem parameter: '%s'", args.socket_mem);
return -1;
}
- conf->force_sockets = 1;
+ int_cfg->force_sockets = 1;
}
if (args.socket_limit != NULL) {
- if (eal_parse_socket_arg(args.socket_limit, conf->socket_limit) < 0) {
+ if (eal_parse_socket_arg(args.socket_limit, int_cfg->socket_limit) < 0) {
EAL_LOG(ERR, "invalid socket limit parameter: '%s'", args.socket_limit);
return -1;
}
- conf->force_socket_limits = 1;
+ int_cfg->force_socket_limits = 1;
}
/* tracing settings, not supported on windows */
@@ -2272,19 +2319,19 @@ eal_parse_args(void)
* other options above have already set them.
*/
if (args.no_pci)
- conf->no_pci = 1;
+ int_cfg->no_pci = 1;
if (args.no_hpet)
- conf->no_hpet = 1;
+ int_cfg->no_hpet = 1;
if (args.vmware_tsc_map)
- conf->vmware_tsc_map = 1;
+ int_cfg->vmware_tsc_map = 1;
if (args.no_shconf)
- conf->no_shconf = 1;
+ int_cfg->no_shconf = 1;
if (args.no_telemetry)
- conf->no_telemetry = 1;
+ int_cfg->no_telemetry = 1;
if (args.match_allocations)
- conf->match_allocations = 1;
+ int_cfg->match_allocations = 1;
if (args.create_uio_dev)
- conf->create_uio_dev = 1;
+ int_cfg->create_uio_dev = 1;
/* other misc settings */
@@ -2329,29 +2376,28 @@ eal_parse_args(void)
}
}
if (args.mbuf_pool_ops_name != NULL) {
- free(conf->user_mbuf_pool_ops_name); /* free old ops name */
- conf->user_mbuf_pool_ops_name = args.mbuf_pool_ops_name;
+ free(int_cfg->user_mbuf_pool_ops_name); /* free old ops name */
+ int_cfg->user_mbuf_pool_ops_name = args.mbuf_pool_ops_name;
+ if (strlen(int_cfg->user_mbuf_pool_ops_name) < 1) {
+ EAL_LOG(ERR, "Invalid mbuf pool ops name parameter");
+ return -1;
+ }
}
/* create runtime data directory. In no_shconf mode, skip any errors */
if (eal_create_runtime_dir() < 0) {
- if (conf->no_shconf == 0) {
+ if (int_cfg->no_shconf == 0) {
EAL_LOG(ERR, "Cannot create runtime directory");
return -1;
}
EAL_LOG(WARNING, "No DPDK runtime directory created");
}
- if (eal_adjust_config(conf) != 0) {
+ if (eal_adjust_config(int_cfg) != 0) {
EAL_LOG(ERR, "Invalid configuration");
return -1;
}
- if (eal_check_common_options(conf) != 0) {
- EAL_LOG(ERR, "Checking common options failed");
- return -1;
- }
-
return 0;
}
@@ -2426,14 +2472,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
if (internal_conf->process_type == RTE_PROC_AUTO)
internal_conf->process_type = eal_proc_type_detect();
- /* default main lcore is the first one */
- if (!main_lcore_parsed) {
- cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
- if (cfg->main_lcore >= RTE_MAX_LCORE)
- return -1;
- lcore_config[cfg->main_lcore].core_role = ROLE_RTE;
- }
-
compute_ctrl_threads_cpuset(internal_cfg);
/* if no memory amounts were requested, this will result in 0 and
@@ -2444,102 +2482,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
return 0;
}
-int
-eal_check_common_options(struct internal_config *internal_cfg)
-{
- struct rte_config *cfg = rte_eal_get_configuration();
- const struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
- EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
- return -1;
- }
-
- if (internal_cfg->process_type == RTE_PROC_INVALID) {
- EAL_LOG(ERR, "Invalid process type specified");
- return -1;
- }
- if (internal_cfg->hugefile_prefix != NULL &&
- strlen(internal_cfg->hugefile_prefix) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_FILE_PREFIX " option");
- return -1;
- }
- if (internal_cfg->hugepage_dir != NULL &&
- strlen(internal_cfg->hugepage_dir) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_HUGE_DIR" option");
- return -1;
- }
- if (internal_cfg->user_mbuf_pool_ops_name != NULL &&
- strlen(internal_cfg->user_mbuf_pool_ops_name) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_MBUF_POOL_OPS_NAME" option");
- return -1;
- }
- if (strchr(eal_get_hugefile_prefix(), '%') != NULL) {
- EAL_LOG(ERR, "Invalid char, '%%', in --"OPT_FILE_PREFIX" "
- "option");
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->force_sockets == 1) {
- EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_UNLINK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->huge_worker_stack_size != 0) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_WORKER_STACK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_conf->force_socket_limits && internal_conf->legacy_mem) {
- EAL_LOG(ERR, "Option --"OPT_SOCKET_LIMIT
- " is only supported in non-legacy memory mode");
- }
- if (internal_cfg->single_file_segments &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
- "not compatible with --"OPT_HUGE_UNLINK);
- return -1;
- }
- if (!internal_cfg->hugepage_file.unlink_existing &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_IN_MEMORY" is not compatible "
- "with --"OPT_HUGE_UNLINK"="HUGE_UNLINK_NEVER);
- return -1;
- }
- if (internal_cfg->legacy_mem &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_IN_MEMORY);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_NO_HUGE" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->memory == 0) {
- EAL_LOG(NOTICE, "Static memory layout is selected, "
- "amount of reserved memory can be adjusted with "
- "-m or --"OPT_SOCKET_MEM);
- }
-
- return 0;
-}
-
RTE_EXPORT_SYMBOL(rte_vect_get_max_simd_bitwidth)
uint16_t
rte_vect_get_max_simd_bitwidth(void)
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 41f95c4a1d..e7431bb797 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -9,116 +9,11 @@
struct rte_tel_data;
-enum {
- /* long options mapped to a short option */
-#define OPT_HELP "help"
- OPT_HELP_NUM = 'h',
-#define OPT_DEV_ALLOW "allow"
- OPT_DEV_ALLOW_NUM = 'a',
-#define OPT_DEV_BLOCK "block"
- OPT_DEV_BLOCK_NUM = 'b',
-#define OPT_COREMASK "coremask"
- OPT_COREMASK_NUM = 'c',
-#define OPT_DRIVER_PATH "driver-path"
- OPT_DRIVER_PATH_NUM = 'd',
-#define OPT_LCORES "lcores"
- OPT_LCORES_NUM = 'l',
-#define OPT_MEMORY_SIZE "memory-size"
- OPT_MEMORY_SIZE_NUM = 'm',
-#define OPT_MEMORY_CHANNELS "memory-channels"
- OPT_MEMORY_CHANNELS_NUM = 'n',
-#define OPT_MEMORY_RANKS "memory-ranks"
- OPT_MEMORY_RANKS_NUM = 'r',
-#define OPT_SERVICE_COREMASK "service-coremask"
- OPT_SERVICE_COREMASK_NUM = 's',
-#define OPT_SERVICE_CORELIST "service-corelist"
- OPT_SERVICE_CORELIST_NUM = 'S',
-#define OPT_VERSION "version"
- OPT_VERSION_NUM = 'v',
-
- /* first long only option value must be >= 256, so that we won't
- * conflict with short options */
- OPT_LONG_MIN_NUM = 256,
-#define OPT_BASE_VIRTADDR "base-virtaddr"
- OPT_BASE_VIRTADDR_NUM,
-#define OPT_CREATE_UIO_DEV "create-uio-dev"
- OPT_CREATE_UIO_DEV_NUM,
-#define OPT_FILE_PREFIX "file-prefix"
- OPT_FILE_PREFIX_NUM,
-#define OPT_HUGE_DIR "huge-dir"
- OPT_HUGE_DIR_NUM,
-#define OPT_HUGE_UNLINK "huge-unlink"
- OPT_HUGE_UNLINK_NUM,
-#define OPT_LOG_COLOR "log-color"
- OPT_LOG_COLOR_NUM,
-#define OPT_LOG_LEVEL "log-level"
- OPT_LOG_LEVEL_NUM,
-#define OPT_LOG_TIMESTAMP "log-timestamp"
- OPT_LOG_TIMESTAMP_NUM,
-#define OPT_TRACE "trace"
- OPT_TRACE_NUM,
-#define OPT_TRACE_DIR "trace-dir"
- OPT_TRACE_DIR_NUM,
-#define OPT_TRACE_BUF_SIZE "trace-bufsz"
- OPT_TRACE_BUF_SIZE_NUM,
-#define OPT_TRACE_MODE "trace-mode"
- OPT_TRACE_MODE_NUM,
-#define OPT_MAIN_LCORE "main-lcore"
- OPT_MAIN_LCORE_NUM,
-#define OPT_MBUF_POOL_OPS_NAME "mbuf-pool-ops-name"
- OPT_MBUF_POOL_OPS_NAME_NUM,
-#define OPT_PROC_TYPE "proc-type"
- OPT_PROC_TYPE_NUM,
-#define OPT_NO_HPET "no-hpet"
- OPT_NO_HPET_NUM,
-#define OPT_NO_HUGE "no-huge"
- OPT_NO_HUGE_NUM,
-#define OPT_NO_PCI "no-pci"
- OPT_NO_PCI_NUM,
-#define OPT_NO_SHCONF "no-shconf"
- OPT_NO_SHCONF_NUM,
-#define OPT_IN_MEMORY "in-memory"
- OPT_IN_MEMORY_NUM,
-#define OPT_SOCKET_MEM "socket-mem"
- OPT_SOCKET_MEM_NUM,
-#define OPT_SOCKET_LIMIT "socket-limit"
- OPT_SOCKET_LIMIT_NUM,
-#define OPT_SYSLOG "syslog"
- OPT_SYSLOG_NUM,
-#define OPT_VDEV "vdev"
- OPT_VDEV_NUM,
-#define OPT_VFIO_INTR "vfio-intr"
- OPT_VFIO_INTR_NUM,
-#define OPT_VFIO_VF_TOKEN "vfio-vf-token"
- OPT_VFIO_VF_TOKEN_NUM,
-#define OPT_VMWARE_TSC_MAP "vmware-tsc-map"
- OPT_VMWARE_TSC_MAP_NUM,
-#define OPT_LEGACY_MEM "legacy-mem"
- OPT_LEGACY_MEM_NUM,
-#define OPT_SINGLE_FILE_SEGMENTS "single-file-segments"
- OPT_SINGLE_FILE_SEGMENTS_NUM,
-#define OPT_IOVA_MODE "iova-mode"
- OPT_IOVA_MODE_NUM,
-#define OPT_MATCH_ALLOCATIONS "match-allocations"
- OPT_MATCH_ALLOCATIONS_NUM,
-#define OPT_TELEMETRY "telemetry"
- OPT_TELEMETRY_NUM,
-#define OPT_NO_TELEMETRY "no-telemetry"
- OPT_NO_TELEMETRY_NUM,
-#define OPT_FORCE_MAX_SIMD_BITWIDTH "force-max-simd-bitwidth"
- OPT_FORCE_MAX_SIMD_BITWIDTH_NUM,
-#define OPT_HUGE_WORKER_STACK "huge-worker-stack"
- OPT_HUGE_WORKER_STACK_NUM,
-
- OPT_LONG_MAX_NUM
-};
-
int eal_parse_log_options(void);
int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
-int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 2a68a02bfd..9c9ae88570 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -328,9 +328,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
/* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option", rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH 7/7] eal: simplify handling of conflicting cmdline options
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (5 preceding siblings ...)
2025-05-20 16:40 ` [RFC PATCH 6/7] eal: combine parameter validation checks Bruce Richardson
@ 2025-05-20 16:40 ` Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
` (13 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-05-20 16:40 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
Use a utility function and macro to simplify the code for checking for
conflicting cmdline options. The checking can also be done at the
initial argument collating stage, shortening the argument
processing function which is very much on the long side.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 119 +++++++++++-----------------
1 file changed, 47 insertions(+), 72 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 50a2b139db..e7314a201d 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -464,6 +464,29 @@ struct rte_argparse eal_argparse = {
}
};
+static inline bool
+conflicting_options(uintptr_t opt1, uintptr_t opt2, const char *opt1_name, const char *opt2_name)
+{
+ char name1[64]; /* should be the max length of any argument */
+ char name2[64];
+
+ strlcpy(name1, opt1_name, sizeof(name1));
+ strlcpy(name2, opt2_name, sizeof(name2));
+ for (int i = 0; name1[i] != '\0'; i++)
+ if (name1[i] == '_')
+ name1[i] = '-';
+ for (int i = 0; name2[i] != '\0'; i++)
+ if (name2[i] == '_')
+ name2[i] = '-';
+ if (opt1 && opt2) {
+ EAL_LOG(ERR, "Options '%s' and '%s' can't be used at the same time", name1, name2);
+ return true;
+ }
+ return false; /* no conflicts */
+}
+#define CONFLICTING_OPTIONS(args, opt1, opt2) \
+ conflicting_options((uintptr_t)(args.opt1), (uintptr_t)(args.opt2), #opt1, #opt2)
+
/* function to call into argparse library to parse the passed argc/argv parameters
* to the eal_init_args structure.
*/
@@ -485,6 +508,30 @@ eal_collate_args(int argc, char **argv)
if (retval < 0)
return retval;
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+
+ /* for non-list args, we can just check for zero/null values using macro */
+ if (CONFLICTING_OPTIONS(args, coremask, lcores) ||
+ CONFLICTING_OPTIONS(args, service_coremask, service_corelist) ||
+ CONFLICTING_OPTIONS(args, no_telemetry, telemetry) ||
+ CONFLICTING_OPTIONS(args, memory_size, socket_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, socket_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_worker_stack) ||
+ CONFLICTING_OPTIONS(args, socket_limit, legacy_mem) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, in_memory) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, single_file_segments, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, no_huge, single_file_segments) ||
+ CONFLICTING_OPTIONS(args, in_memory, huge_unlink))
+ return -1;
+
argv[retval - 1] = argv[0];
return retval - 1;
}
@@ -2045,78 +2092,6 @@ eal_parse_args(void)
struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
- /* check for conflicting options */
- /* both -a and -b cannot be used together (one list must be empty at least) */
- if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
- EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
- }
- /* both -l and -c cannot be used at the same time */
- if (args.coremask != NULL && args.lcores != NULL) {
- EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
- return -1;
- }
- /* both -s and -S cannot be used at the same time */
- if (args.service_coremask != NULL && args.service_corelist != NULL) {
- EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
- return -1;
- }
- /* can't have both telemetry and no-telemetry */
- if (args.no_telemetry && args.telemetry) {
- EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
- return -1;
- }
- /* can't have both -m and --socket-mem */
- if (args.memory_size != NULL && args.socket_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
- return -1;
- }
- /* can't use both no-huge and socket-mem */
- if (args.no_huge && args.socket_mem) {
- EAL_LOG(ERR, "Options --no-huge and --socket-mem can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-worker-stack */
- if (args.huge_worker_stack != NULL && args.no_huge) {
- EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
- return -1;
- }
- /* can't use socket-limit and legacy-mem */
- if (args.socket_limit != NULL && args.legacy_mem) {
- EAL_LOG(ERR, "Options --socket-limit and --legacy-mem can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and in-memory */
- if (args.legacy_mem && args.in_memory) {
- EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and match-allocations */
- if (args.legacy_mem && args.match_allocations) {
- EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and match-allocations */
- if (args.no_huge && args.match_allocations) {
- EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-unlink */
- if (args.no_huge && args.huge_unlink) {
- EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use single-file-segments and huge-unlink */
- if (args.single_file_segments && args.huge_unlink) {
- EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use in-memory and huge-unlink */
- if (args.in_memory && args.huge_unlink) {
- EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
- return -1;
- }
-
/* print version before anything else */
/* since message is explicitly requested by user, we write message
* at highest log level so it can always be seen even if info or
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [RFC PATCH 3/7] argparse: make argparse EAL-args compatible
2025-05-20 16:40 ` [RFC PATCH 3/7] argparse: make argparse EAL-args compatible Bruce Richardson
@ 2025-05-22 10:44 ` Bruce Richardson
0 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-05-22 10:44 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Chengwen Feng
On Tue, May 20, 2025 at 05:40:20PM +0100, Bruce Richardson wrote:
> The argparse library was missing two key features which made it
> unsuitable for use by EAL or any program wanting similar behaviour.
>
> 1. It didn't stop parsing arguments when it hit a "--" character
> 2. It never returned the number of arguments parsed
>
> Fix both these issues - the latter is a change to the ABI, since we now
> return >= 0 rather than == 0 on success. However, the ABI is still
> experimental so we can make exactly these sorts of tweaks to it.
>
> Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> ---
Thinking about it further, for EAL we can actually do without these changes
to the argparse library*. However, this is also functionality that may be
useful in other cases, so looking for feedback on whether to continue with
this patch, or drop it?
Question:
* should argparse library stop processing args at "--"?
* should argparse library return number of args parsed, or zero on success?
/Bruce
*The reason we don't need these is because we clone the argv data on
eal_init so we can return it via telemetry library. This splits the args
into eal and non-eal args, so we can use just the "eal" arg array to pass to
arg-parse, if we don't include this patch.
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (6 preceding siblings ...)
2025-05-20 16:40 ` [RFC PATCH 7/7] eal: simplify handling of conflicting cmdline options Bruce Richardson
@ 2025-07-08 17:20 ` Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 1/5] eal: add long options for each short option Bruce Richardson
` (7 more replies)
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
` (12 subsequent siblings)
20 siblings, 8 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-08 17:20 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
This RFC is a second, more complete, prototype of one approach we may
want to take to help improve management of EAL cmdline arguments.
BACKGROUND:
- The first problem that led to this work was that of providing a
way for users to easily provide a set of CPU cores to DPDK where the
CPU ids are >= RTE_MAX_LCORE
- There are a number of solutions which were discussed for this, most
of which involved automatically remapping CPU ids to lcore ids
starting at zero.
- However, in discussion with David M. at the last DPDK Summit in
Prague, he pointed out the main difficulty with all these approaches
in that they don't work with multi-process, since we can't reuse lcore
id numbers in secondary process.
- This in turn lead to a realisation that when processing cmdline
arguments in DPDK, we always do so with very little context. So, for
example, when processing the "-l" flag, we have no idea whether there
will be later a --proc-type=secondary flag. We have all sorts of
post-arg-processing checks in place to try and catch these scenarios.
This patchset therefore tries to simplify the handling of argument
processing, by explicitly doing an initial pass to collate all arguments
into a structure. Thereafter, the actual arg parsing is done in a fixed
order, meaning that e.g. when processing the --main-lcore flag, we have
already processed the service core flags. We also can far quicker and
easier check for conflicting options, since they can all be checked for
NULL/non-NULL in the arg structure immediately after the struct has been
populated.
To do the initial argument gathering, this RFC uses the existing argparse
library in DPDK. With recent changes, this now meets our needs for EAL
argument parsing and allows us to not need to do direct getopt argument
processing inside EAL at all.
An additional benefit of this work, is that the argument parsing for EAL
is much more centralised into common options. This reduces code a bit.
However, what is missing here is proper handling for unsupported options
across BSD and Windows. We can either take two approaches:
1. just ifdef them out so they don't appear in the argparse list on
unsupported platforms, giving errors when used.
2. keep them in the list of arguments, and ignore them (with warning) when
used on unsupported platforms.
The advantage of #1 is that it is simple and correct, but the advantage
of #2 is that is makes it easier to move scripts and commandline args
between platforms - but at the cost of the arg list shown by help to be
less accurate.
Bruce Richardson (5):
eal: add long options for each short option
eal: define the EAL parameters in argparse format
eal: gather EAL args before processing
eal: combine parameter validation checks
eal: simplify handling of conflicting cmdline options
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 1236 ++++++++++++++-------------
lib/eal/common/eal_options.h | 101 +--
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 164 +---
lib/eal/linux/eal.c | 384 +--------
lib/eal/linux/eal_memory.c | 2 +-
lib/eal/meson.build | 2 +-
lib/eal/windows/eal.c | 113 +--
lib/meson.build | 1 +
10 files changed, 726 insertions(+), 1291 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH v2 1/5] eal: add long options for each short option
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
@ 2025-07-08 17:20 ` Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 2/5] eal: define the EAL parameters in argparse format Bruce Richardson
` (6 subsequent siblings)
7 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-08 17:20 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
To simplify future rework of the EAL arg handling, add a long-option
equivalent for each short option that doesn't already have one.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 9 +++++++++
lib/eal/common/eal_options.h | 16 ++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index f0a9ddeeb7..cafae9d9d7 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -66,7 +66,9 @@ eal_short_options[] =
const struct option
eal_long_options[] = {
{OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
+ {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
{OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
+ {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
{OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
{OPT_HELP, 0, NULL, OPT_HELP_NUM },
{OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
@@ -76,6 +78,11 @@ eal_long_options[] = {
{OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
{OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
{OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
+ {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
+ {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
+ {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
+ {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
+ {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
{OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
{OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
{OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
@@ -109,6 +116,8 @@ eal_long_options[] = {
{OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
{OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
{OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
+ {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
+
{0, 0, NULL, 0 }
};
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 7a56aa3810..6ef45559f0 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -17,8 +17,24 @@ enum {
OPT_DEV_ALLOW_NUM = 'a',
#define OPT_DEV_BLOCK "block"
OPT_DEV_BLOCK_NUM = 'b',
+#define OPT_COREMASK "coremask"
+ OPT_COREMASK_NUM = 'c',
+#define OPT_DRIVER_PATH "driver-path"
+ OPT_DRIVER_PATH_NUM = 'd',
#define OPT_LCORES "lcores"
OPT_LCORES_NUM = 'l',
+#define OPT_MEMORY_SIZE "memory-size"
+ OPT_MEMORY_SIZE_NUM = 'm',
+#define OPT_MEMORY_CHANNELS "memory-channels"
+ OPT_MEMORY_CHANNELS_NUM = 'n',
+#define OPT_MEMORY_RANKS "memory-ranks"
+ OPT_MEMORY_RANKS_NUM = 'r',
+#define OPT_SERVICE_COREMASK "service-coremask"
+ OPT_SERVICE_COREMASK_NUM = 's',
+#define OPT_SERVICE_CORELIST "service-corelist"
+ OPT_SERVICE_CORELIST_NUM = 'S',
+#define OPT_VERSION "version"
+ OPT_VERSION_NUM = 'v',
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH v2 2/5] eal: define the EAL parameters in argparse format
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 1/5] eal: add long options for each short option Bruce Richardson
@ 2025-07-08 17:20 ` Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 3/5] eal: gather EAL args before processing Bruce Richardson
` (5 subsequent siblings)
7 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-08 17:20 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
This table should allow us to parse all the eal args into a single
structure for later parsing in a fixed-order field basis. For those
elements that take multiple values, define a TAILQ and a callback to
process those elements.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 192 ++++++++++++++++++++++++++++
lib/eal/meson.build | 2 +-
lib/meson.build | 1 +
3 files changed, 194 insertions(+), 1 deletion(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index cafae9d9d7..7558206f93 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -28,11 +28,13 @@
#include <rte_version.h>
#include <rte_devargs.h>
#include <rte_memcpy.h>
+#include <sys/queue.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <rte_telemetry.h>
#endif
#include <rte_vect.h>
+#include <rte_argparse.h>
#include <eal_export.h>
#include "eal_internal_cfg.h"
#include "eal_options.h"
@@ -47,6 +49,196 @@
#define LCORE_OPT_LST 1
#define LCORE_OPT_MSK 2
+struct arg_list_elem {
+ TAILQ_ENTRY(arg_list_elem) next;
+ char *arg;
+};
+TAILQ_HEAD(arg_list, arg_list_elem);
+
+struct eal_init_args {
+ /* define a struct member for each EAL option, member name is the same as option name.
+ * Parameters that take an argument e.g. -l, are char *,
+ * parameters that take no options e.g. --no-huge, are bool.
+ * parameters that can be given multiple times e.g. -a, are arg_lists,
+ * parameters that are optional e.g. --huge-unlink,
+ * are char * but are set to (void *)1 if the parameter is not given.
+ */
+ struct arg_list allow;
+ char *base_virtaddr;
+ struct arg_list block;
+ char *coremask;
+ bool create_uio_dev;
+ struct arg_list driver_path;
+ char *file_prefix;
+ char *force_max_simd_bitwidth;
+ char *huge_dir;
+ char *huge_unlink; /* parameter optional */
+ char *huge_worker_stack; /* parameter optional */
+ bool in_memory;
+ char *iova_mode;
+ char *lcores;
+ bool legacy_mem;
+ char *log_color; /* parameter optional */
+ char *log_level;
+ char *log_timestamp; /* parameter optional */
+ char *main_lcore;
+ bool match_allocations;
+ char *mbuf_pool_ops_name;
+ char *memory_channels;
+ char *memory_ranks;
+ char *memory_size;
+ bool no_hpet;
+ bool no_huge;
+ bool no_pci;
+ bool no_shconf;
+ bool no_telemetry;
+ char *proc_type;
+ char *service_coremask;
+ char *service_corelist;
+ bool single_file_segments;
+ char *socket_mem;
+ char *socket_limit;
+ char *syslog; /* parameter optional */
+ bool telemetry;
+ char *trace;
+ char *trace_bufsz;
+ char *trace_dir;
+ char *trace_mode;
+ struct arg_list vdev;
+ bool version;
+ char *vfio_intr;
+ char *vfio_vf_token;
+ bool vmware_tsc_map;
+};
+struct eal_init_args args;
+
+/* an rte_argparse callback to append the argument to an arg_list
+ * in args. The index is the offset into the struct of the list.
+ */
+static int
+arg_list_callback(uint32_t index, const char *arg, void *init_args)
+{
+ struct arg_list *list = RTE_PTR_ADD(init_args, index);
+ struct arg_list_elem *elem;
+
+ elem = malloc(sizeof(*elem));
+ if (elem == NULL)
+ return -1;
+
+ elem->arg = strdup(arg);
+ if (elem->arg == NULL) {
+ free(elem);
+ return -1;
+ }
+
+ TAILQ_INSERT_TAIL(list, elem, next);
+ return 0;
+}
+
+/* For arguments which have an arg_list type, they use callback (no val_saver),
+ * require a value, and have the SUPPORT_MULTI flag.
+ */
+#define LIST_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_set = (void *)offsetof(struct eal_init_args, fieldname), \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .flags = RTE_ARGPARSE_FLAG_SUPPORT_MULTI, \
+}
+/* For arguments which have a string type, they use val_saver (no callback),
+ * and normally REQUIRED_VALUE.
+ */
+#define STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+}
+/* For flags which have optional arguments, they use both val_saver and val_set,
+ * but still have a string type.
+ */
+#define OPT_STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_OPTIONAL, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+}
+/* For boolean arguments, they use val_saver and val_set, with NO_VALUE flag.
+ */
+#define BOOL_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_NONE, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_BOOL, \
+}
+
+struct rte_argparse eal_argparse = {
+ .prog_name = "",
+ .usage = "<DPDK EAL options>",
+ .exit_on_error = true,
+ .callback = arg_list_callback,
+ .opaque = &args,
+ .args = {
+ /* list of EAL arguments as struct rte_argparse_arg. */
+ LIST_ARG("--allow", "-a", "Add device to allow-list", allow),
+ STR_ARG("--base-virtaddr", NULL, "Base virtual address to reserve memory", base_virtaddr),
+ LIST_ARG("--block", "-b", "Add device to block-list", block),
+ STR_ARG("--coremask", "-c", "Hexadecimal bitmask of cores to use", coremask),
+ BOOL_ARG("--create-uio-dev", NULL, "Create /dev/uioX devices", create_uio_dev),
+ LIST_ARG("--driver-path", "-d", "Path to external driver shared object", driver_path),
+ STR_ARG("--file-prefix", NULL, "Base filename of hugetlbfs files", file_prefix),
+ STR_ARG("--force-max-simd-bitwidth", NULL, "Set max SIMD bitwidth to use in vector code paths", force_max_simd_bitwidth),
+ STR_ARG("--huge-dir", NULL, "Directory for hugepage files", huge_dir),
+ OPT_STR_ARG("--huge-unlink", NULL, "Unlink hugetlbfs files on exit (existing|always|never)", huge_unlink),
+ OPT_STR_ARG("--huge-worker-stack", NULL, "Allocate worker thread stacks from hugepage memory, with optional size (kB)", huge_worker_stack),
+ BOOL_ARG("--in-memory", NULL, "DPDK should not create shared mmap files in filesystem", in_memory),
+ STR_ARG("--iova-mode", NULL, "IOVA mapping mode, physical (pa)/virtual (va)", iova_mode),
+ STR_ARG("--lcores", "-l", "List of CPU cores to use", lcores),
+ BOOL_ARG("--legacy-mem", NULL, "Enable legacy memory behavior", legacy_mem),
+ OPT_STR_ARG("--log-color", NULL, "Enable/disable color in log output", log_color),
+ STR_ARG("--log-level", NULL, "Log level for all loggers", log_level),
+ OPT_STR_ARG("--log-timestamp", NULL, "Enable/disable timestamp in log output", log_timestamp),
+ STR_ARG("--main-lcore", NULL, "Select which core to use for the main thread", main_lcore),
+ BOOL_ARG("--match-allocations", NULL, "Free hugepages exactly as allocated", match_allocations),
+ STR_ARG("--mbuf-pool-ops-name", NULL, "User defined mbuf default pool ops name", mbuf_pool_ops_name),
+ STR_ARG("--memory-channels", "-n", "Number of memory channels per socket", memory_channels),
+ STR_ARG("--memory-ranks", "-r", "Number of memory ranks", memory_ranks),
+ STR_ARG("--memory-size", "-m", "Total size of memory to allocate initially", memory_size),
+ BOOL_ARG("--no-hpet", NULL, "Disable HPET timer", no_hpet),
+ BOOL_ARG("--no-huge", NULL, "Disable hugetlbfs support", no_huge),
+ BOOL_ARG("--no-pci", NULL, "Disable all PCI devices", no_pci),
+ BOOL_ARG("--no-shconf", NULL, "Disable shared config file generation", no_shconf),
+ BOOL_ARG("--no-telemetry", NULL, "Disable telemetry", no_telemetry),
+ STR_ARG("--proc-type", NULL, "Type of process (primary/secondary)", proc_type),
+ STR_ARG("--service-corelist", "-S", "List of cores to use for service threads", service_corelist),
+ STR_ARG("--service-coremask", "-s", "Hexadecimal bitmask of cores to use for service threads", service_coremask),
+ BOOL_ARG("--single-file-segments", NULL, "Store all pages within single files (per-page-size, per-node)", single_file_segments),
+ STR_ARG("--socket-mem", NULL, "List of memory sizes to be allocated per socket on init", socket_mem),
+ STR_ARG("--socket-limit", NULL, "Memory limits per socket", socket_limit),
+ OPT_STR_ARG("--syslog", NULL, "Log to syslog (and optionally set facility)", syslog),
+ BOOL_ARG("--telemetry", NULL, "Enable telemetry", telemetry),
+ STR_ARG("--trace", NULL, "Enable trace based on regular expression trace name", trace),
+ STR_ARG("--trace-bufsz", NULL, "Trace buffer size", trace_bufsz),
+ STR_ARG("--trace-dir", NULL, "Trace directory", trace_dir),
+ STR_ARG("--trace-mode", NULL, "Trace mode", trace_mode),
+ LIST_ARG("--vdev", NULL, "Virtual device to add to the system", vdev),
+ STR_ARG("--vfio-intr", NULL, "VFIO interrupt mode (legacy|msi|msix)", vfio_intr),
+ STR_ARG("--vfio-vf-token", NULL, "VF token (UUID) shared between SR-IOV PF and VFs", vfio_vf_token),
+ BOOL_ARG("--vmware-tsc-map", NULL, "Use VMware TSC mapping instead of native RDTSC", vmware_tsc_map),
+ BOOL_ARG("--version", "-v", "Show version", version),
+ ARGPARSE_ARG_END(),
+ }
+};
+
const char
eal_short_options[] =
"a:" /* allow */
diff --git a/lib/eal/meson.build b/lib/eal/meson.build
index e1d6c4cf17..f9fcee24ee 100644
--- a/lib/eal/meson.build
+++ b/lib/eal/meson.build
@@ -14,7 +14,7 @@ subdir(exec_env)
subdir(arch_subdir)
-deps += ['log', 'kvargs']
+deps += ['argparse', 'kvargs']
if not is_windows
deps += ['telemetry']
endif
diff --git a/lib/meson.build b/lib/meson.build
index 0d56b2083b..dec90059e1 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -71,6 +71,7 @@ libraries = [
]
always_enable = [
+ 'argparse',
'cmdline',
'eal',
'ethdev',
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH v2 3/5] eal: gather EAL args before processing
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 1/5] eal: add long options for each short option Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 2/5] eal: define the EAL parameters in argparse format Bruce Richardson
@ 2025-07-08 17:20 ` Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 4/5] eal: combine parameter validation checks Bruce Richardson
` (4 subsequent siblings)
7 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-08 17:20 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
DPDK traditionally has iterated through all args and processed them as
they appear in the commandline. The arg processing logic can be
simplified if instead we initially gather all arguments into a structure
which is then processed with the arguments dealt with in a fixed/known
order.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 877 ++++++++++++++--------------
lib/eal/common/eal_options.h | 10 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 164 +-----
lib/eal/linux/eal.c | 379 +-----------
lib/eal/windows/eal.c | 113 +---
6 files changed, 482 insertions(+), 1072 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 7558206f93..2a1a7c744f 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -46,8 +46,7 @@
#endif
#define BITS_PER_HEX 4
-#define LCORE_OPT_LST 1
-#define LCORE_OPT_MSK 2
+#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
struct arg_list_elem {
TAILQ_ENTRY(arg_list_elem) next;
@@ -239,80 +238,31 @@ struct rte_argparse eal_argparse = {
}
};
-const char
-eal_short_options[] =
- "a:" /* allow */
- "b:" /* block */
- "c:" /* coremask */
- "s:" /* service coremask */
- "d:" /* driver */
- "h" /* help */
- "l:" /* corelist */
- "S:" /* service corelist */
- "m:" /* memory size */
- "n:" /* memory channels */
- "r:" /* memory ranks */
- "v" /* version */
- ;
-
-const struct option
-eal_long_options[] = {
- {OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
- {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
- {OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
- {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
- {OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
- {OPT_HELP, 0, NULL, OPT_HELP_NUM },
- {OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
- {OPT_HUGE_UNLINK, 2, NULL, OPT_HUGE_UNLINK_NUM },
- {OPT_IOVA_MODE, 1, NULL, OPT_IOVA_MODE_NUM },
- {OPT_LCORES, 1, NULL, OPT_LCORES_NUM },
- {OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
- {OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
- {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
- {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
- {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
- {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
- {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
- {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
- {OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
- {OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
- {OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
- {OPT_TRACE_MODE, 1, NULL, OPT_TRACE_MODE_NUM },
- {OPT_MAIN_LCORE, 1, NULL, OPT_MAIN_LCORE_NUM },
- {OPT_MBUF_POOL_OPS_NAME, 1, NULL, OPT_MBUF_POOL_OPS_NAME_NUM},
- {OPT_NO_HPET, 0, NULL, OPT_NO_HPET_NUM },
- {OPT_NO_HUGE, 0, NULL, OPT_NO_HUGE_NUM },
- {OPT_NO_PCI, 0, NULL, OPT_NO_PCI_NUM },
- {OPT_NO_SHCONF, 0, NULL, OPT_NO_SHCONF_NUM },
- {OPT_IN_MEMORY, 0, NULL, OPT_IN_MEMORY_NUM },
- {OPT_DEV_BLOCK, 1, NULL, OPT_DEV_BLOCK_NUM },
- {OPT_DEV_ALLOW, 1, NULL, OPT_DEV_ALLOW_NUM },
- {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM },
- /* socket-mem/socket-limit are kept for backwards compatibility */
- {OPT_SOCKET_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_SOCKET_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
- {OPT_NUMA_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_NUMA_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
-#ifndef RTE_EXEC_ENV_WINDOWS
- {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM },
-#endif
- {OPT_VDEV, 1, NULL, OPT_VDEV_NUM },
- {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
- {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM },
- {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
- {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM },
- {OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM},
- {OPT_MATCH_ALLOCATIONS, 0, NULL, OPT_MATCH_ALLOCATIONS_NUM},
- {OPT_TELEMETRY, 0, NULL, OPT_TELEMETRY_NUM },
- {OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
- {OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
- {OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
- {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
-
-
- {0, 0, NULL, 0 }
-};
+/* function to call into argparse library to parse the passed argc/argv parameters
+ * to the eal_init_args structure.
+ */
+int
+eal_collate_args(int argc, char **argv)
+{
+ if (argc < 1 || argv == NULL)
+ return -EINVAL;
+
+ /* initialize the list of arguments */
+ memset(&args, 0, sizeof(args));
+ TAILQ_INIT(&args.allow);
+ TAILQ_INIT(&args.block);
+ TAILQ_INIT(&args.driver_path);
+ TAILQ_INIT(&args.vdev);
+
+ /* parse the arguments */
+ eal_argparse.prog_name = argv[0];
+ int retval = rte_argparse_parse(&eal_argparse, argc, argv);
+ if (retval < 0)
+ return retval;
+
+ argv[retval - 1] = argv[0];
+ return retval - 1;
+}
TAILQ_HEAD(shared_driver_list, shared_driver);
@@ -354,7 +304,6 @@ static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
static int main_lcore_parsed;
-static int mem_parsed;
static int core_parsed;
/* Allow the application to print its usage message too if set */
@@ -381,7 +330,12 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
return old_func;
}
-#ifndef RTE_EXEC_ENV_WINDOWS
+#ifdef RTE_EXEC_ENV_WINDOWS
+
+int
+eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+
+#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
static char **eal_app_args;
@@ -469,7 +423,7 @@ eal_save_args(int argc, char **argv)
eal_args = NULL;
return -1;
}
-#endif
+#endif /* !RTE_EXEC_ENV_WINDOWS */
static int
eal_option_device_add(enum rte_devtype type, const char *optarg)
@@ -892,17 +846,6 @@ eal_parse_service_coremask(const char *coremask)
return 0;
}
-static int
-eal_service_cores_parsed(void)
-{
- int idx;
- for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- if (lcore_config[idx].core_role == ROLE_SERVICE)
- return 1;
- }
- return 0;
-}
-
static int
update_lcore_config(int *cores)
{
@@ -1729,361 +1672,486 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return -1;
}
-bool
-eal_option_is_log(int opt)
+/* Parse all arguments looking for log related ones */
+int
+eal_parse_log_options(void)
{
- switch (opt) {
- case OPT_LOG_COLOR_NUM:
- case OPT_LOG_LEVEL_NUM:
- case OPT_LOG_TIMESTAMP_NUM:
- case OPT_SYSLOG_NUM:
- return true;
- default:
- return false;
+ if (args.log_level != NULL) {
+ if (eal_parse_log_level(args.log_level) < 0) {
+ EAL_LOG(ERR, "invalid log-level parameter");
+ return -1;
+ }
+ }
+ if (args.log_color != NULL) {
+ /* if value is 1, no argument specified, so pass NULL */
+ if (args.log_color == (void *)1)
+ args.log_color = NULL;
+ if (eal_log_color(args.log_color) < 0) {
+ EAL_LOG(ERR, "invalid log-color parameter");
+ return -1;
+ }
+ }
+ if (args.log_timestamp != NULL) {
+ /* similarly log_timestamp may be 1 */
+ if (args.log_timestamp == (void *)1)
+ args.log_timestamp = NULL;
+ if (eal_log_timestamp(args.log_timestamp) < 0) {
+ EAL_LOG(ERR, "invalid log-timestamp parameter");
+ return -1;
+ }
+ }
+ if (args.syslog != NULL) {
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "syslog is not supported on Windows, ignoring parameter");
+#else
+ /* also syslog parameter may be 1 */
+ if (args.syslog == (void *)1)
+ args.syslog = NULL;
+ if (eal_log_syslog(args.syslog) < 0) {
+ EAL_LOG(ERR, "invalid syslog parameter");
+ return -1;
+ }
+#endif
}
+ return 0;
}
-/* Parse all arguments looking for log related ones */
-int
-eal_parse_log_options(int argc, char * const argv[])
+static int
+eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
{
- struct internal_config *internal_conf = eal_get_internal_configuration();
- int option_index, opt;
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_opterr = opterr;
- char *old_optarg = optarg;
-#ifdef RTE_EXEC_ENV_FREEBSD
- const int old_optreset = optreset;
- optreset = 1;
-#endif
+ char *arg[RTE_MAX_NUMA_NODES];
+ char *end;
+ int arg_num, i, len;
- optind = 1;
- opterr = 0;
+ len = strnlen(strval, SOCKET_MEM_STRLEN);
+ if (len == SOCKET_MEM_STRLEN) {
+ EAL_LOG(ERR, "--socket-mem is too long");
+ return -1;
+ }
- while ((opt = getopt_long(argc, argv, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
+ /* all other error cases will be caught later */
+ if (!isdigit(strval[len-1]))
+ return -1;
- if (!eal_option_is_log(opt))
- continue;
+ /* split the optarg into separate socket values */
+ arg_num = rte_strsplit(strval, len,
+ arg, RTE_MAX_NUMA_NODES, ',');
- if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+ /* if split failed, or 0 arguments */
+ if (arg_num <= 0)
+ return -1;
+
+ /* parse each defined socket option */
+ errno = 0;
+ for (i = 0; i < arg_num; i++) {
+ uint64_t val;
+ end = NULL;
+ val = strtoull(arg[i], &end, 10);
+
+ /* check for invalid input */
+ if ((errno != 0) ||
+ (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
+ val <<= 20;
+ socket_arg[i] = val;
}
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
- opterr = old_opterr;
-#ifdef RTE_EXEC_ENV_FREEBSD
- optreset = old_optreset;
+ return 0;
+}
+
+static int
+eal_parse_vfio_intr(const char *mode)
+{
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+ static struct {
+ const char *name;
+ enum rte_intr_mode value;
+ } map[] = {
+ { "legacy", RTE_INTR_MODE_LEGACY },
+ { "msi", RTE_INTR_MODE_MSI },
+ { "msix", RTE_INTR_MODE_MSIX },
+ };
+
+ for (size_t i = 0; i < RTE_DIM(map); i++) {
+ if (!strcmp(mode, map[i].name)) {
+ internal_conf->vfio_intr_mode = map[i].value;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+eal_parse_vfio_vf_token(const char *vf_token)
+{
+ struct internal_config *cfg = eal_get_internal_configuration();
+ rte_uuid_t uuid;
+
+ if (!rte_uuid_parse(vf_token, uuid)) {
+ rte_uuid_copy(cfg->vfio_vf_token, uuid);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+eal_parse_huge_worker_stack(const char *arg)
+{
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "Cannot set worker stack size on Windows, parameter ignored");
+ RTE_SET_USED(arg);
+#else
+ struct internal_config *cfg = eal_get_internal_configuration();
+
+ if (arg == NULL || arg[0] == '\0') {
+ pthread_attr_t attr;
+ int ret;
+
+ if (pthread_attr_init(&attr) != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
+ pthread_attr_destroy(&attr);
+ if (ret != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ } else {
+ unsigned long stack_size;
+ char *end;
+
+ errno = 0;
+ stack_size = strtoul(arg, &end, 10);
+ if (errno || end == NULL || stack_size == 0 ||
+ stack_size >= (size_t)-1 / 1024)
+ return -1;
+
+ cfg->huge_worker_stack_size = stack_size * 1024;
+ }
+
+ EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
+ cfg->huge_worker_stack_size / 1024);
#endif
return 0;
}
+/* Parse the arguments given in the command line of the application */
int
-eal_parse_common_option(int opt, const char *optarg,
- struct internal_config *conf)
+eal_parse_args(void)
{
- static int b_used;
- static int a_used;
-
- switch (opt) {
- case 'b':
- if (a_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, optarg) < 0)
+ struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct arg_list_elem *arg;
+
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+ /* both -l and -c cannot be used at the same time */
+ if (args.coremask != NULL && args.lcores != NULL) {
+ EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
+ return -1;
+ }
+ /* both -s and -S cannot be used at the same time */
+ if (args.service_coremask != NULL && args.service_corelist != NULL) {
+ EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
+ return -1;
+ }
+ /* can't have both telemetry and no-telemetry */
+ if (args.no_telemetry && args.telemetry) {
+ EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
+ return -1;
+ }
+ /* can't have both -m and --socket-mem */
+ if (args.memory_size != NULL && args.socket_mem != NULL) {
+ EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ return -1;
+ }
+
+ /* parse options */
+ /* print version before anything else */
+ if (args.version) {
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
+ }
+
+ /* parse the process type */
+ if (args.proc_type != NULL) {
+ int_cfg->process_type = eal_parse_proc_type(args.proc_type);
+ if (int_cfg->process_type == RTE_PROC_INVALID) {
+ EAL_LOG(ERR, "invalid process type: %s", args.proc_type);
return -1;
- b_used = 1;
- break;
+ }
+ }
- case 'a':
- if (b_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, optarg) < 0)
+ /* device -a/-b/-vdev options*/
+ TAILQ_FOREACH(arg, &args.allow, next)
+ if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, arg->arg) < 0)
return -1;
- a_used = 1;
- break;
- /* coremask */
- case 'c': {
+ TAILQ_FOREACH(arg, &args.block, next)
+ if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, arg->arg) < 0)
+ return -1;
+ TAILQ_FOREACH(arg, &args.vdev, next)
+ if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, arg->arg) < 0)
+ return -1;
+ /* driver loading options */
+ TAILQ_FOREACH(arg, &args.driver_path, next)
+ if (eal_plugin_add(arg->arg) < 0)
+ return -1;
+
+ /* parse the coremask /core-list */
+ if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -c is before -s or -S");
- if (rte_eal_parse_coremask(optarg, lcore_indexes) < 0) {
+ if (rte_eal_parse_coremask(args.coremask, lcore_indexes) < 0) {
EAL_LOG(ERR, "invalid coremask syntax");
return -1;
}
if (update_lcore_config(lcore_indexes) < 0) {
char *available = available_cores();
- EAL_LOG(ERR,
- "invalid coremask, please check specified cores are part of %s",
- available);
+ EAL_LOG(ERR, "invalid coremask '%s', please check specified cores are part of %s",
+ args.coremask, available);
free(available);
return -1;
}
-
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_MSK)
- EAL_LOG(ERR, "Option '-c' passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option -c is ignored, because option -l/--lcores used");
+ core_parsed = 1;
+ } else if (args.lcores != NULL) {
+ if (eal_parse_lcores(args.lcores) < 0) {
+ EAL_LOG(ERR, "invalid lcore list: '%s'", args.lcores);
return -1;
}
-
- core_parsed = LCORE_OPT_MSK;
- break;
+ core_parsed = 1;
}
- /* corelist */
- case 'l': {
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -l is before -s or -S");
-
- if (eal_parse_lcores(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for -l/--" OPT_LCORES);
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0) {
+ EAL_LOG(ERR, "invalid main-lcore parameter");
return -1;
}
+ }
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_LST)
- EAL_LOG(ERR, "Core list option passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option '-l/--lcores' is ignored, because coremask option used");
+ /* service core options */
+ if (args.service_coremask != NULL) {
+ if (eal_parse_service_coremask(args.service_coremask) < 0) {
+ EAL_LOG(ERR, "invalid service coremask: '%s'",
+ args.service_coremask);
return -1;
}
+ } else if (args.service_corelist != NULL) {
+ if (eal_parse_service_corelist(args.service_corelist) < 0) {
+ EAL_LOG(ERR, "invalid service core list: '%s'",
+ args.service_corelist);
+ return -1;
+ }
+ }
- core_parsed = LCORE_OPT_LST;
- break;
+ /* memory options */
+ if (args.memory_size != NULL) {
+ int_cfg->memory = atoi(args.memory_size);
+ int_cfg->memory *= 1024ULL;
+ int_cfg->memory *= 1024ULL;
}
- /* service coremask */
- case 's':
- if (eal_parse_service_coremask(optarg) < 0) {
- EAL_LOG(ERR, "invalid service coremask");
+ if (args.memory_channels != NULL) {
+ int_cfg->force_nchannel = atoi(args.memory_channels);
+ if (int_cfg->force_nchannel == 0) {
+ EAL_LOG(ERR, "invalid memory channel parameter");
return -1;
}
- break;
- /* service corelist */
- case 'S':
- if (eal_parse_service_corelist(optarg) < 0) {
- EAL_LOG(ERR, "invalid service core list");
+ }
+ if (args.memory_ranks != NULL) {
+ int_cfg->force_nrank = atoi(args.memory_ranks);
+ if (int_cfg->force_nrank == 0 || int_cfg->force_nrank > 16) {
+ EAL_LOG(ERR, "invalid memory rank parameter");
return -1;
}
- break;
- /* size of memory */
- case 'm':
- conf->memory = atoi(optarg);
- conf->memory *= 1024ULL;
- conf->memory *= 1024ULL;
- mem_parsed = 1;
- break;
- /* force number of channels */
- case 'n':
- conf->force_nchannel = atoi(optarg);
- if (conf->force_nchannel == 0) {
- EAL_LOG(ERR, "invalid channel number");
+ }
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
return -1;
}
- break;
- /* force number of ranks */
- case 'r':
- conf->force_nrank = atoi(optarg);
- if (conf->force_nrank == 0 ||
- conf->force_nrank > 16) {
- EAL_LOG(ERR, "invalid rank number");
+ }
+ if (args.no_huge) {
+ int_cfg->no_hugetlbfs = 1;
+ /* no-huge is legacy mem */
+ int_cfg->legacy_mem = 1;
+ }
+ if (args.in_memory) {
+ int_cfg->in_memory = 1;
+ /* in-memory is a superset of noshconf and huge-unlink */
+ int_cfg->no_shconf = 1;
+ int_cfg->hugepage_file.unlink_before_mapping = true;
+ }
+ if (args.legacy_mem)
+ int_cfg->legacy_mem = 1;
+ if (args.single_file_segments)
+ int_cfg->single_file_segments = 1;
+ if (args.huge_dir != NULL) {
+ free(int_cfg->hugepage_dir); /* free old hugepage dir */
+ int_cfg->hugepage_dir = strdup(args.huge_dir);
+ if (int_cfg->hugepage_dir == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for hugepage dir parameter");
return -1;
}
- break;
- /* force loading of external driver */
- case 'd':
- if (eal_plugin_add(optarg) == -1)
+ }
+ if (args.file_prefix != NULL) {
+ free(int_cfg->hugefile_prefix); /* free old file prefix */
+ int_cfg->hugefile_prefix = strdup(args.file_prefix);
+ if (int_cfg->hugefile_prefix == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for file prefix parameter");
return -1;
- break;
- case 'v':
- /* since message is explicitly requested by user, we
- * write message at highest log level so it can always
- * be seen
- * even if info or warning messages are disabled */
- EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- break;
-
- /* long options */
- case OPT_HUGE_UNLINK_NUM:
- if (eal_parse_huge_unlink(optarg, &conf->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid --"OPT_HUGE_UNLINK" option");
+ }
+ }
+ if (args.socket_mem != NULL) {
+ if (eal_parse_socket_arg(args.socket_mem, int_cfg->numa_mem) < 0) {
+ EAL_LOG(ERR, "invalid socket-mem parameter: '%s'", args.socket_mem);
return -1;
}
- break;
-
- case OPT_NO_HUGE_NUM:
- conf->no_hugetlbfs = 1;
- /* no-huge is legacy mem */
- conf->legacy_mem = 1;
- break;
-
- case OPT_NO_PCI_NUM:
- conf->no_pci = 1;
- break;
-
- case OPT_NO_HPET_NUM:
- conf->no_hpet = 1;
- break;
-
- case OPT_VMWARE_TSC_MAP_NUM:
- conf->vmware_tsc_map = 1;
- break;
-
- case OPT_NO_SHCONF_NUM:
- conf->no_shconf = 1;
- break;
-
- case OPT_IN_MEMORY_NUM:
- conf->in_memory = 1;
- /* in-memory is a superset of noshconf and huge-unlink */
- conf->no_shconf = 1;
- conf->hugepage_file.unlink_before_mapping = true;
- break;
-
- case OPT_PROC_TYPE_NUM:
- conf->process_type = eal_parse_proc_type(optarg);
- break;
-
- case OPT_MAIN_LCORE_NUM:
- if (eal_parse_main_lcore(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_MAIN_LCORE);
+ int_cfg->force_numa = 1;
+ }
+ if (args.socket_limit != NULL) {
+ if (eal_parse_socket_arg(args.socket_limit, int_cfg->numa_limit) < 0) {
+ EAL_LOG(ERR, "invalid socket limit parameter: '%s'", args.socket_limit);
return -1;
}
- break;
+ int_cfg->force_numa_limits = 1;
+ }
- case OPT_VDEV_NUM:
- if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
- optarg) < 0) {
+ /* tracing settings, not supported on windows */
+#ifdef RTE_EXEC_ENV_WINDOWS
+ if (args.trace != NULL ||
+ args.trace_dir != NULL ||
+ args.trace_bufsz != NULL ||
+ args.trace_mode != NULL)
+ EAL_LOG(WARNING, "Tracing is not supported on Windows, ignoring tracing parameters");
+#else
+ if (args.trace != NULL) {
+ if (eal_trace_args_save(args.trace) < 0) {
+ EAL_LOG(ERR, "invalid trace parameter, '%s'", args.trace);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_SYSLOG_NUM:
- if (eal_log_syslog(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_SYSLOG);
+ }
+ if (args.trace_dir != NULL) {
+ if (eal_trace_dir_args_save(args.trace_dir) < 0) {
+ EAL_LOG(ERR, "invalid trace directory, '%s'", args.trace_dir);
return -1;
}
- break;
-#endif
-
- case OPT_LOG_LEVEL_NUM:
- if (eal_parse_log_level(optarg) < 0) {
- EAL_LOG(ERR,
- "invalid parameters for --"
- OPT_LOG_LEVEL);
+ }
+ if (args.trace_bufsz != NULL) {
+ if (eal_trace_bufsz_args_save(args.trace_bufsz) < 0) {
+ EAL_LOG(ERR, "invalid trace buffer size, '%s'", args.trace_bufsz);
return -1;
}
- break;
-
- case OPT_LOG_TIMESTAMP_NUM:
- if (eal_log_timestamp(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_TIMESTAMP);
+ }
+ if (args.trace_mode != NULL) {
+ if (eal_trace_mode_args_save(args.trace_mode) < 0) {
+ EAL_LOG(ERR, "invalid trace mode, '%s'", args.trace_mode);
return -1;
}
- break;
+ }
+#endif
- case OPT_LOG_COLOR_NUM:
- if (eal_log_color(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_COLOR);
+ /* simple flag settings
+ * Only set these to 1, as we don't want to set them to 0 in case
+ * other options above have already set them.
+ */
+ if (args.no_pci)
+ int_cfg->no_pci = 1;
+ if (args.no_hpet)
+ int_cfg->no_hpet = 1;
+ if (args.vmware_tsc_map)
+ int_cfg->vmware_tsc_map = 1;
+ if (args.no_shconf)
+ int_cfg->no_shconf = 1;
+ if (args.no_telemetry)
+ int_cfg->no_telemetry = 1;
+ if (args.match_allocations)
+ int_cfg->match_allocations = 1;
+ if (args.create_uio_dev)
+ int_cfg->create_uio_dev = 1;
+
+
+ /* other misc settings */
+ if (args.iova_mode != NULL) {
+ if (eal_parse_iova_mode(args.iova_mode) < 0) {
+ EAL_LOG(ERR, "invalid iova mode parameter '%s'", args.iova_mode);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_TRACE_NUM: {
- if (eal_trace_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE);
+ };
+ if (args.base_virtaddr != NULL) {
+ if (eal_parse_base_virtaddr(args.base_virtaddr) < 0) {
+ EAL_LOG(ERR, "invalid base virtaddr '%s'", args.base_virtaddr);
return -1;
}
- break;
}
-
- case OPT_TRACE_DIR_NUM: {
- if (eal_trace_dir_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_DIR);
+ if (args.force_max_simd_bitwidth != NULL) {
+ if (eal_parse_simd_bitwidth(args.force_max_simd_bitwidth) < 0) {
+ EAL_LOG(ERR, "invalid SIMD bitwidth parameter '%s'",
+ args.force_max_simd_bitwidth);
return -1;
}
- break;
}
-
- case OPT_TRACE_BUF_SIZE_NUM: {
- if (eal_trace_bufsz_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_BUF_SIZE);
+ if (args.vfio_intr != NULL) {
+ if (eal_parse_vfio_intr(args.vfio_intr) < 0) {
+ EAL_LOG(ERR, "invalid vfio interrupt parameter: '%s'", args.vfio_intr);
return -1;
}
- break;
}
-
- case OPT_TRACE_MODE_NUM: {
- if (eal_trace_mode_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_MODE);
+ if (args.vfio_vf_token != NULL) {
+ if (eal_parse_vfio_vf_token(args.vfio_vf_token) < 0) {
+ EAL_LOG(ERR, "invalid vfio vf token parameter: '%s'", args.vfio_vf_token);
return -1;
}
- break;
}
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- case OPT_LEGACY_MEM_NUM:
- conf->legacy_mem = 1;
- break;
- case OPT_SINGLE_FILE_SEGMENTS_NUM:
- conf->single_file_segments = 1;
- break;
- case OPT_IOVA_MODE_NUM:
- if (eal_parse_iova_mode(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_IOVA_MODE);
+ if (args.huge_worker_stack != NULL) {
+ if (args.huge_worker_stack == (void *)1)
+ args.huge_worker_stack = NULL;
+ if (eal_parse_huge_worker_stack(args.huge_worker_stack) < 0) {
+ EAL_LOG(ERR, "invalid huge worker stack parameter");
return -1;
}
- break;
- case OPT_BASE_VIRTADDR_NUM:
- if (eal_parse_base_virtaddr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_BASE_VIRTADDR);
+ }
+ if (args.mbuf_pool_ops_name != NULL) {
+ free(int_cfg->user_mbuf_pool_ops_name); /* free old ops name */
+ int_cfg->user_mbuf_pool_ops_name = strdup(args.mbuf_pool_ops_name);
+ if (int_cfg->user_mbuf_pool_ops_name == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
- break;
- case OPT_TELEMETRY_NUM:
- break;
- case OPT_NO_TELEMETRY_NUM:
- conf->no_telemetry = 1;
- break;
- case OPT_FORCE_MAX_SIMD_BITWIDTH_NUM:
- if (eal_parse_simd_bitwidth(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_FORCE_MAX_SIMD_BITWIDTH);
+ }
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+ /* create runtime data directory. In no_shconf mode, skip any errors */
+ if (eal_create_runtime_dir() < 0) {
+ if (int_cfg->no_shconf == 0) {
+ EAL_LOG(ERR, "Cannot create runtime directory");
return -1;
}
- break;
+ EAL_LOG(WARNING, "No DPDK runtime directory created");
+ }
+#endif
- /* don't know what to do, leave this to caller */
- default:
- return 1;
+ if (eal_adjust_config(int_cfg) != 0) {
+ EAL_LOG(ERR, "Invalid configuration");
+ return -1;
+ }
+ if (eal_check_common_options(int_cfg) != 0) {
+ EAL_LOG(ERR, "Checking common options failed");
+ return -1;
}
return 0;
-
-ba_conflict:
- EAL_LOG(ERR,
- "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
}
static void
@@ -2216,13 +2284,8 @@ eal_check_common_options(struct internal_config *internal_cfg)
"option");
return -1;
}
- if (mem_parsed && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Options -m and --"OPT_NUMA_MEM" cannot "
- "be specified at the same time");
- return -1;
- }
if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_MEM" cannot "
+ EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
"be specified together with --"OPT_NO_HUGE);
return -1;
}
@@ -2308,97 +2371,3 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth)
internal_conf->max_simd_bitwidth.bitwidth = bitwidth;
return 0;
}
-
-void
-eal_common_usage(void)
-{
- printf("[options]\n\n"
- "EAL common options:\n"
- " -c COREMASK Hexadecimal bitmask of cores to run on\n"
- " -l, --"OPT_LCORES" CORELIST\n"
- " List of cores to run on\n"
- " The basic argument format is <c1>[-c2][,c3[-c4],...]\n"
- " where c1, c2, etc are core indexes between 0 and %d\n"
- " Can also be used to map lcore set to physical CPU set\n"
- " The argument format is\n"
- " '<lcores[@cpus]>[<,lcores[@cpus]>...]'\n"
- " lcores and cpus list are grouped by '(' and ')'\n"
- " Within the group, '-' is used for range separator,\n"
- " ',' is used for single number separator.\n"
- " '( )' can be omitted for single element group,\n"
- " '@' can be omitted if cpus and lcores have the same value\n"
- " -s SERVICE COREMASK Hexadecimal bitmask of cores to be used as service cores\n"
- " --"OPT_MAIN_LCORE" ID Core ID that is used as main\n"
- " --"OPT_MBUF_POOL_OPS_NAME" Pool ops name for mbuf to use\n"
- " -n CHANNELS Number of memory channels\n"
- " -m MB Memory to allocate (see also --"OPT_NUMA_MEM")\n"
- " -r RANKS Force number of memory ranks (don't detect)\n"
- " -b, --block Add a device to the blocked list.\n"
- " Prevent EAL from using this device. The argument\n"
- " format for PCI devices is <domain:bus:devid.func>.\n"
- " -a, --allow Add a device to the allow list.\n"
- " Only use the specified devices. The argument format\n"
- " for PCI devices is <[domain:]bus:devid.func>.\n"
- " This option can be present several times.\n"
- " [NOTE: " OPT_DEV_ALLOW " cannot be used with "OPT_DEV_BLOCK" option]\n"
- " --"OPT_VDEV" Add a virtual device.\n"
- " The argument format is <driver><id>[,key=val,...]\n"
- " (ex: --vdev=net_pcap0,iface=eth2).\n"
- " --"OPT_IOVA_MODE" Set IOVA mode. 'pa' for IOVA_PA\n"
- " 'va' for IOVA_VA\n"
- " -d LIB.so|DIR Add a driver or driver directory\n"
- " (can be used multiple times)\n"
- " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n"
- " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_SYSLOG"[=<facility>] Enable use of syslog (and optionally set facility)\n"
-#endif
- " --"OPT_LOG_LEVEL"=<level> Set global log level\n"
- " --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
- " Set specific log level\n"
- " --"OPT_LOG_LEVEL"=help Show log types and levels\n"
- " --"OPT_LOG_TIMESTAMP"[=<format>] Timestamp log output\n"
- " --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_TRACE"=<regex-match>\n"
- " Enable trace based on regular expression trace name.\n"
- " By default, the trace is disabled.\n"
- " User must specify this option to enable trace.\n"
- " --"OPT_TRACE_DIR"=<directory path>\n"
- " Specify trace directory for trace output.\n"
- " By default, trace output will created at\n"
- " $HOME directory and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_BUF_SIZE"=<int>\n"
- " Specify maximum size of allocated memory\n"
- " for trace output for each thread. Valid\n"
- " unit can be either 'B|K|M' for 'Bytes',\n"
- " 'KBytes' and 'MBytes' respectively.\n"
- " Default is 1MB and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_MODE"=<o[verwrite] | d[iscard]>\n"
- " Specify the mode of update of trace\n"
- " output file. Either update on a file can\n"
- " be wrapped or discarded when file size\n"
- " reaches its maximum limit.\n"
- " Default mode is 'overwrite' and parameter\n"
- " must be specified once only.\n"
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- " -v Display version information on startup\n"
- " -h, --"OPT_HELP" This help\n"
- " --"OPT_IN_MEMORY" Operate entirely in memory. This will\n"
- " disable secondary process support\n"
- " --"OPT_BASE_VIRTADDR" Base virtual address\n"
- " --"OPT_TELEMETRY" Enable telemetry support (on by default)\n"
- " --"OPT_NO_TELEMETRY" Disable telemetry support\n"
- " --"OPT_FORCE_MAX_SIMD_BITWIDTH" Force the max SIMD bitwidth\n"
- "\nEAL options for DEBUG use only:\n"
- " --"OPT_HUGE_UNLINK"[=existing|always|never]\n"
- " When to unlink files in hugetlbfs\n"
- " ('existing' by default, no value means 'always')\n"
- " --"OPT_NO_HUGE" Use malloc instead of hugetlbfs\n"
- " --"OPT_NO_PCI" Disable PCI\n"
- " --"OPT_NO_HPET" Disable HPET\n"
- " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n"
- "\n", RTE_MAX_LCORE);
-}
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 6ef45559f0..c4d2cc84dc 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -115,18 +115,12 @@ enum {
OPT_LONG_MAX_NUM
};
-extern const char eal_short_options[];
-extern const struct option eal_long_options[];
-
-bool eal_option_is_log(int opt);
-int eal_parse_log_options(int argc, char * const argv[]);
-int eal_parse_common_option(int opt, const char *argv,
- struct internal_config *conf);
+int eal_parse_log_options(void);
+int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
int eal_check_common_options(struct internal_config *internal_cfg);
-void eal_common_usage(void);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index 5846917cc5..ab8b37b956 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -72,6 +72,17 @@ struct rte_config {
*/
struct rte_config *rte_eal_get_configuration(void);
+/**
+ * Put the argument list into a structure.
+ *
+ * This allows the arguments to then be processed out-of-order.
+ *
+ * @return
+ * - 0 on success
+ * - Negative on error
+ */
+int eal_collate_args(int argc, char **argv);
+
/**
* Initialize the memzone subsystem (private to eal).
*
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index c1ab8d86d2..ee8bf92bff 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -160,7 +160,7 @@ rte_eal_config_create(void)
cfg_len_aligned, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, mem_cfg_fd, 0);
if (mapped_mem_cfg_addr == MAP_FAILED) {
- EAL_LOG(ERR, "Cannot remap memory for rte_config");
+ EAL_LOG(ERR, "Cannot remap memory for rte_config: %s", strerror(errno));
munmap(rte_mem_cfg_addr, cfg_len);
close(mem_cfg_fd);
mem_cfg_fd = -1;
@@ -245,11 +245,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
- /* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option",
- rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
@@ -332,21 +329,6 @@ rte_config_init(void)
return 0;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
static inline size_t
eal_get_hugepage_mem_size(void)
{
@@ -367,123 +349,6 @@ eal_get_hugepage_mem_size(void)
return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX;
}
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_optreset = optreset;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
- optreset = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on FreeBSD", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on FreeBSD",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on FreeBSD", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optreset = old_optreset;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -553,8 +418,18 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* Save and collate args at the top */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("invalid command-line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -585,18 +460,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
@@ -605,8 +476,7 @@ rte_eal_init(int argc, char **argv)
/* FreeBSD always uses legacy memory model */
internal_conf->legacy_mem = true;
if (internal_conf->in_memory) {
- EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '%s'",
- OPT_IN_MEMORY);
+ EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '--in-memory'");
internal_conf->in_memory = false;
}
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 52efb8626b..f59cb43b0e 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -59,9 +59,6 @@
#include "log_internal.h"
#define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
-
-#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
-
#define KERNEL_IOMMU_GROUPS_PATH "/sys/kernel/iommu_groups"
/* define fd variable here, because file needs to be kept open for the
@@ -438,362 +435,6 @@ eal_hugedirs_unlock(void)
}
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- printf("EAL Linux options:\n"
- " --"OPT_NUMA_MEM" Memory to allocate on NUMA nodes (comma separated values)\n"
- " --"OPT_NUMA_LIMIT" Limit memory allocation on NUMA nodes (comma separated values)\n"
- " --"OPT_HUGE_DIR" Directory where hugetlbfs is mounted\n"
- " --"OPT_FILE_PREFIX" Prefix for hugepage filenames\n"
- " --"OPT_CREATE_UIO_DEV" Create /dev/uioX (usually done by hotplug)\n"
- " --"OPT_VFIO_INTR" Interrupt mode for VFIO (legacy|msi|msix)\n"
- " --"OPT_VFIO_VF_TOKEN" VF token (UUID) shared between SR-IOV PF and VFs\n"
- " --"OPT_LEGACY_MEM" Legacy memory mode (no dynamic allocation, contiguous segments)\n"
- " --"OPT_SINGLE_FILE_SEGMENTS" Put all hugepage memory in single files\n"
- " --"OPT_MATCH_ALLOCATIONS" Free hugepages exactly as allocated\n"
- " --"OPT_HUGE_WORKER_STACK"[=size]\n"
- " Allocate worker thread stacks from hugepage memory.\n"
- " Size is in units of kbytes and defaults to system\n"
- " thread stack size if not specified.\n"
- "\n");
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-static int
-eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
-{
- char * arg[RTE_MAX_NUMA_NODES];
- char *end;
- int arg_num, i, len;
-
- len = strnlen(strval, SOCKET_MEM_STRLEN);
- if (len == SOCKET_MEM_STRLEN) {
- EAL_LOG(ERR, "--socket-mem is too long");
- return -1;
- }
-
- /* all other error cases will be caught later */
- if (!isdigit(strval[len-1]))
- return -1;
-
- /* split the optarg into separate socket values */
- arg_num = rte_strsplit(strval, len,
- arg, RTE_MAX_NUMA_NODES, ',');
-
- /* if split failed, or 0 arguments */
- if (arg_num <= 0)
- return -1;
-
- /* parse each defined socket option */
- errno = 0;
- for (i = 0; i < arg_num; i++) {
- uint64_t val;
- end = NULL;
- val = strtoull(arg[i], &end, 10);
-
- /* check for invalid input */
- if ((errno != 0) ||
- (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
- return -1;
- val <<= 20;
- socket_arg[i] = val;
- }
-
- return 0;
-}
-
-static int
-eal_parse_vfio_intr(const char *mode)
-{
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
- unsigned i;
- static struct {
- const char *name;
- enum rte_intr_mode value;
- } map[] = {
- { "legacy", RTE_INTR_MODE_LEGACY },
- { "msi", RTE_INTR_MODE_MSI },
- { "msix", RTE_INTR_MODE_MSIX },
- };
-
- for (i = 0; i < RTE_DIM(map); i++) {
- if (!strcmp(mode, map[i].name)) {
- internal_conf->vfio_intr_mode = map[i].value;
- return 0;
- }
- }
- return -1;
-}
-
-static int
-eal_parse_vfio_vf_token(const char *vf_token)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
- rte_uuid_t uuid;
-
- if (!rte_uuid_parse(vf_token, uuid)) {
- rte_uuid_copy(cfg->vfio_vf_token, uuid);
- return 0;
- }
-
- return -1;
-}
-
-static int
-eal_parse_huge_worker_stack(const char *arg)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
-
- if (arg == NULL || arg[0] == '\0') {
- pthread_attr_t attr;
- int ret;
-
- if (pthread_attr_init(&attr) != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
- pthread_attr_destroy(&attr);
- if (ret != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- } else {
- unsigned long stack_size;
- char *end;
-
- errno = 0;
- stack_size = strtoul(arg, &end, 10);
- if (errno || end == NULL || stack_size == 0 ||
- stack_size >= (size_t)-1 / 1024)
- return -1;
-
- cfg->huge_worker_stack_size = stack_size * 1024;
- }
-
- EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
- cfg->huge_worker_stack_size / 1024);
- return 0;
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
-
- case OPT_HUGE_DIR_NUM:
- {
- char *hdir = strdup(optarg);
- if (hdir == NULL)
- EAL_LOG(ERR, "Could not store hugepage directory");
- else {
- /* free old hugepage dir */
- free(internal_conf->hugepage_dir);
- internal_conf->hugepage_dir = hdir;
- }
- break;
- }
- case OPT_FILE_PREFIX_NUM:
- {
- char *prefix = strdup(optarg);
- if (prefix == NULL)
- EAL_LOG(ERR, "Could not store file prefix");
- else {
- /* free old prefix */
- free(internal_conf->hugefile_prefix);
- internal_conf->hugefile_prefix = prefix;
- }
- break;
- }
- case OPT_NUMA_MEM_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_mem) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_MEM
- " (aka --"
- OPT_SOCKET_MEM
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa = 1;
- break;
-
- case OPT_NUMA_LIMIT_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_limit) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_LIMIT
- " (aka --"
- OPT_SOCKET_LIMIT
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa_limits = 1;
- break;
-
- case OPT_VFIO_INTR_NUM:
- if (eal_parse_vfio_intr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_INTR);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_VFIO_VF_TOKEN_NUM:
- if (eal_parse_vfio_vf_token(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_VF_TOKEN);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_CREATE_UIO_DEV_NUM:
- internal_conf->create_uio_dev = 1;
- break;
-
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_MATCH_ALLOCATIONS_NUM:
- internal_conf->match_allocations = 1;
- break;
-
- case OPT_HUGE_WORKER_STACK_NUM:
- if (eal_parse_huge_worker_stack(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_HUGE_WORKER_STACK);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Linux", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Linux",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Linux", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -938,8 +579,18 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -970,18 +621,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 4f0a164d9b..14547d5ac9 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -82,99 +82,6 @@ rte_mp_disable(void)
return true;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too
- * if hook is set
- */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- int ret;
-
- /* getopt is not happy, stop right now */
- if (opt == '?') {
- eal_usage(prgname);
- return -1;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- return -1;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Windows", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Windows",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Windows", opt);
- }
- eal_usage(prgname);
- return -1;
- }
- }
-
- if (eal_adjust_config(internal_conf) != 0)
- return -1;
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- return -1;
- }
-
- if (optind >= 0)
- argv[optind - 1] = prgname;
- ret = optind - 1;
- optind = 0; /* reset getopt lib */
- return ret;
-}
-
static int
sync_func(void *arg __rte_unused)
{
@@ -260,8 +167,18 @@ rte_eal_init(int argc, char **argv)
char cpuset[RTE_CPU_AFFINITY_STR_LEN];
char thread_name[RTE_THREAD_NAME_SIZE];
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -288,9 +205,11 @@ rte_eal_init(int argc, char **argv)
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0)
- exit(1);
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
if (eal_option_device_parse()) {
rte_errno = ENODEV;
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH v2 4/5] eal: combine parameter validation checks
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
` (2 preceding siblings ...)
2025-07-08 17:20 ` [RFC PATCH v2 3/5] eal: gather EAL args before processing Bruce Richardson
@ 2025-07-08 17:20 ` Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 5/5] eal: simplify handling of conflicting cmdline options Bruce Richardson
` (3 subsequent siblings)
7 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-08 17:20 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
Remove the separate function to check combinations of cmdline
parameters. Instead, just do those checks when parsing the parameters
since we have all info about what parameters are provided at that point.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 260 +++++++++++-----------------
lib/eal/common/eal_options.h | 107 ------------
lib/eal/linux/eal.c | 5 +-
lib/eal/linux/eal_memory.c | 2 +-
5 files changed, 105 insertions(+), 272 deletions(-)
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 38ccc734e8..c62edf5e55 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -258,8 +258,7 @@ eal_memseg_list_alloc(struct rte_memseg_list *msl, int reserve_flags)
* including common code, so don't duplicate the message.
*/
if (rte_errno == EADDRNOTAVAIL)
- EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - "
- "please use '--" OPT_BASE_VIRTADDR "' option",
+ EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - please use '--base-virtaddr' option",
(unsigned long long)mem_sz, msl->base_va);
#endif
return -1;
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 2a1a7c744f..87ab5a4f13 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -303,7 +303,6 @@ struct device_option {
static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
-static int main_lcore_parsed;
static int core_parsed;
/* Allow the application to print its usage message too if set */
@@ -801,15 +800,6 @@ eal_parse_service_coremask(const char *coremask)
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE;
j++, idx++) {
if ((1 << j) & val) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (main_lcore_parsed &&
- cfg->main_lcore == lcore) {
- EAL_LOG(ERR,
- "lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (eal_cpu_detected(idx) == 0) {
EAL_LOG(ERR,
@@ -1032,15 +1022,6 @@ eal_parse_service_corelist(const char *corelist)
min = idx;
for (idx = min; idx <= max; idx++) {
if (cfg->lcore_role[idx] != ROLE_SERVICE) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (cfg->main_lcore == lcore &&
- main_lcore_parsed) {
- EAL_LOG(ERR,
- "Error: lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (cfg->lcore_role[idx] == ROLE_RTE)
taken_lcore_count++;
@@ -1080,12 +1061,15 @@ eal_parse_main_lcore(const char *arg)
return -1;
if (cfg->main_lcore >= RTE_MAX_LCORE)
return -1;
- main_lcore_parsed = 1;
/* ensure main core is not used as service core */
if (lcore_config[cfg->main_lcore].core_role == ROLE_SERVICE) {
- EAL_LOG(ERR,
- "Error: Main lcore is used as a service core");
+ EAL_LOG(ERR, "Error: Main lcore is used as a service core");
+ return -1;
+ }
+ /* check that we have the core recorded in the core list */
+ if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
+ EAL_LOG(ERR, "Error: Main lcore is not enabled for DPDK");
return -1;
}
@@ -1380,11 +1364,11 @@ eal_log_usage(void)
rte_log_list_types(stdout, "\t");
printf("\n");
printf("Syntax using globbing pattern: ");
- printf("--"OPT_LOG_LEVEL" pattern:level\n");
+ printf("--log-level pattern:level\n");
printf("Syntax using regular expression: ");
- printf("--"OPT_LOG_LEVEL" regexp,level\n");
+ printf("--log-level regexp,level\n");
printf("Syntax for the global level: ");
- printf("--"OPT_LOG_LEVEL" level\n");
+ printf("--log-level level\n");
printf("Logs are emitted if allowed by both global and specific levels.\n");
printf("\n");
printf("Log level can be a number or the first letters of its name:\n");
@@ -1664,7 +1648,7 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return 0;
}
if (strcmp(arg, HUGE_UNLINK_NEVER) == 0) {
- EAL_LOG(WARNING, "Using --"OPT_HUGE_UNLINK"="
+ EAL_LOG(WARNING, "Using --huge-unlink="
HUGE_UNLINK_NEVER" may create data leaks.");
out->unlink_existing = false;
return 0;
@@ -1843,6 +1827,7 @@ int
eal_parse_args(void)
{
struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
/* check for conflicting options */
@@ -1871,16 +1856,59 @@ eal_parse_args(void)
EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
return -1;
}
+ /* can't use both no-huge and socket-mem */
+ if (args.no_huge && args.socket_mem) {
+ EAL_LOG(ERR, "Options --no-huge and --socket-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-worker-stack */
+ if (args.huge_worker_stack != NULL && args.no_huge) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
+ return -1;
+ }
+ /* can't use socket-limit and legacy-mem */
+ if (args.socket_limit != NULL && args.legacy_mem) {
+ EAL_LOG(ERR, "Options --socket-limit and --legacy-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and in-memory */
+ if (args.legacy_mem && args.in_memory) {
+ EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and match-allocations */
+ if (args.legacy_mem && args.match_allocations) {
+ EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and match-allocations */
+ if (args.no_huge && args.match_allocations) {
+ EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-unlink */
+ if (args.no_huge && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use single-file-segments and huge-unlink */
+ if (args.single_file_segments && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use in-memory and huge-unlink */
+ if (args.in_memory && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
+ return -1;
+ }
- /* parse options */
/* print version before anything else */
- if (args.version) {
- /* since message is explicitly requested by user, we write message
- * at highest log level so it can always be seen even if info or
- * warning messages are disabled
- */
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ if (args.version)
EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- }
/* parse the process type */
if (args.proc_type != NULL) {
@@ -1906,7 +1934,7 @@ eal_parse_args(void)
if (eal_plugin_add(arg->arg) < 0)
return -1;
- /* parse the coremask /core-list */
+ /* parse the core list arguments */
if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
@@ -1930,13 +1958,6 @@ eal_parse_args(void)
}
core_parsed = 1;
}
- if (args.main_lcore != NULL) {
- if (eal_parse_main_lcore(args.main_lcore) < 0) {
- EAL_LOG(ERR, "invalid main-lcore parameter");
- return -1;
- }
- }
-
/* service core options */
if (args.service_coremask != NULL) {
if (eal_parse_service_coremask(args.service_coremask) < 0) {
@@ -1951,6 +1972,17 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0)
+ return -1;
+ } else {
+ /* default main lcore is the first one */
+ rte_cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
+ if (rte_cfg->main_lcore >= RTE_MAX_LCORE) {
+ EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
+ return -1;
+ }
+ }
/* memory options */
if (args.memory_size != NULL) {
@@ -1972,14 +2004,6 @@ eal_parse_args(void)
return -1;
}
}
- if (args.huge_unlink != NULL) {
- if (args.huge_unlink == (void *)1)
- args.huge_unlink = NULL;
- if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid huge-unlink parameter");
- return -1;
- }
- }
if (args.no_huge) {
int_cfg->no_hugetlbfs = 1;
/* no-huge is legacy mem */
@@ -1991,11 +2015,18 @@ eal_parse_args(void)
int_cfg->no_shconf = 1;
int_cfg->hugepage_file.unlink_before_mapping = true;
}
- if (args.legacy_mem)
+ if (args.legacy_mem) {
int_cfg->legacy_mem = 1;
+ if (args.memory_size == NULL && args.socket_mem == NULL)
+ EAL_LOG(NOTICE, "Static memory layout is selected, amount of reserved memory can be adjusted with -m or --socket-mem");
+ }
if (args.single_file_segments)
int_cfg->single_file_segments = 1;
if (args.huge_dir != NULL) {
+ if (strlen(args.huge_dir) < 1) {
+ EAL_LOG(ERR, "Invalid hugepage dir parameter");
+ return -1;
+ }
free(int_cfg->hugepage_dir); /* free old hugepage dir */
int_cfg->hugepage_dir = strdup(args.huge_dir);
if (int_cfg->hugepage_dir == NULL) {
@@ -2004,6 +2035,14 @@ eal_parse_args(void)
}
}
if (args.file_prefix != NULL) {
+ if (strlen(args.file_prefix) < 1) {
+ EAL_LOG(ERR, "Invalid file prefix parameter");
+ return -1;
+ }
+ if (strchr(args.file_prefix, '%') != NULL) {
+ EAL_LOG(ERR, "Invalid char, '%%', in file_prefix parameter");
+ return -1;
+ }
free(int_cfg->hugefile_prefix); /* free old file prefix */
int_cfg->hugefile_prefix = strdup(args.file_prefix);
if (int_cfg->hugefile_prefix == NULL) {
@@ -2011,6 +2050,14 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
+ return -1;
+ }
+ }
if (args.socket_mem != NULL) {
if (eal_parse_socket_arg(args.socket_mem, int_cfg->numa_mem) < 0) {
EAL_LOG(ERR, "invalid socket-mem parameter: '%s'", args.socket_mem);
@@ -2128,6 +2175,10 @@ eal_parse_args(void)
EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
+ if (strlen(int_cfg->user_mbuf_pool_ops_name) < 1) {
+ EAL_LOG(ERR, "Invalid mbuf pool ops name parameter");
+ return -1;
+ }
}
#ifndef RTE_EXEC_ENV_WINDOWS
@@ -2146,11 +2197,6 @@ eal_parse_args(void)
return -1;
}
- if (eal_check_common_options(int_cfg) != 0) {
- EAL_LOG(ERR, "Checking common options failed");
- return -1;
- }
-
return 0;
}
@@ -2230,14 +2276,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
if (internal_conf->process_type == RTE_PROC_AUTO)
internal_conf->process_type = eal_proc_type_detect();
- /* default main lcore is the first one */
- if (!main_lcore_parsed) {
- cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
- if (cfg->main_lcore >= RTE_MAX_LCORE)
- return -1;
- lcore_config[cfg->main_lcore].core_role = ROLE_RTE;
- }
-
compute_ctrl_threads_cpuset(internal_cfg);
/* if no memory amounts were requested, this will result in 0 and
@@ -2248,102 +2286,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
return 0;
}
-int
-eal_check_common_options(struct internal_config *internal_cfg)
-{
- struct rte_config *cfg = rte_eal_get_configuration();
- const struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
- EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
- return -1;
- }
-
- if (internal_cfg->process_type == RTE_PROC_INVALID) {
- EAL_LOG(ERR, "Invalid process type specified");
- return -1;
- }
- if (internal_cfg->hugefile_prefix != NULL &&
- strlen(internal_cfg->hugefile_prefix) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_FILE_PREFIX " option");
- return -1;
- }
- if (internal_cfg->hugepage_dir != NULL &&
- strlen(internal_cfg->hugepage_dir) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_HUGE_DIR" option");
- return -1;
- }
- if (internal_cfg->user_mbuf_pool_ops_name != NULL &&
- strlen(internal_cfg->user_mbuf_pool_ops_name) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_MBUF_POOL_OPS_NAME" option");
- return -1;
- }
- if (strchr(eal_get_hugefile_prefix(), '%') != NULL) {
- EAL_LOG(ERR, "Invalid char, '%%', in --"OPT_FILE_PREFIX" "
- "option");
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_UNLINK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->huge_worker_stack_size != 0) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_WORKER_STACK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_conf->force_numa_limits && internal_conf->legacy_mem) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_LIMIT
- " is only supported in non-legacy memory mode");
- }
- if (internal_cfg->single_file_segments &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
- "not compatible with --"OPT_HUGE_UNLINK);
- return -1;
- }
- if (!internal_cfg->hugepage_file.unlink_existing &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_IN_MEMORY" is not compatible "
- "with --"OPT_HUGE_UNLINK"="HUGE_UNLINK_NEVER);
- return -1;
- }
- if (internal_cfg->legacy_mem &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_IN_MEMORY);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_NO_HUGE" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->memory == 0) {
- EAL_LOG(NOTICE, "Static memory layout is selected, "
- "amount of reserved memory can be adjusted with "
- "-m or --"OPT_NUMA_MEM);
- }
-
- return 0;
-}
-
RTE_EXPORT_SYMBOL(rte_vect_get_max_simd_bitwidth)
uint16_t
rte_vect_get_max_simd_bitwidth(void)
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index c4d2cc84dc..e7431bb797 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -9,118 +9,11 @@
struct rte_tel_data;
-enum {
- /* long options mapped to a short option */
-#define OPT_HELP "help"
- OPT_HELP_NUM = 'h',
-#define OPT_DEV_ALLOW "allow"
- OPT_DEV_ALLOW_NUM = 'a',
-#define OPT_DEV_BLOCK "block"
- OPT_DEV_BLOCK_NUM = 'b',
-#define OPT_COREMASK "coremask"
- OPT_COREMASK_NUM = 'c',
-#define OPT_DRIVER_PATH "driver-path"
- OPT_DRIVER_PATH_NUM = 'd',
-#define OPT_LCORES "lcores"
- OPT_LCORES_NUM = 'l',
-#define OPT_MEMORY_SIZE "memory-size"
- OPT_MEMORY_SIZE_NUM = 'm',
-#define OPT_MEMORY_CHANNELS "memory-channels"
- OPT_MEMORY_CHANNELS_NUM = 'n',
-#define OPT_MEMORY_RANKS "memory-ranks"
- OPT_MEMORY_RANKS_NUM = 'r',
-#define OPT_SERVICE_COREMASK "service-coremask"
- OPT_SERVICE_COREMASK_NUM = 's',
-#define OPT_SERVICE_CORELIST "service-corelist"
- OPT_SERVICE_CORELIST_NUM = 'S',
-#define OPT_VERSION "version"
- OPT_VERSION_NUM = 'v',
-
- /* first long only option value must be >= 256, so that we won't
- * conflict with short options */
- OPT_LONG_MIN_NUM = 256,
-#define OPT_BASE_VIRTADDR "base-virtaddr"
- OPT_BASE_VIRTADDR_NUM,
-#define OPT_CREATE_UIO_DEV "create-uio-dev"
- OPT_CREATE_UIO_DEV_NUM,
-#define OPT_FILE_PREFIX "file-prefix"
- OPT_FILE_PREFIX_NUM,
-#define OPT_HUGE_DIR "huge-dir"
- OPT_HUGE_DIR_NUM,
-#define OPT_HUGE_UNLINK "huge-unlink"
- OPT_HUGE_UNLINK_NUM,
-#define OPT_LOG_COLOR "log-color"
- OPT_LOG_COLOR_NUM,
-#define OPT_LOG_LEVEL "log-level"
- OPT_LOG_LEVEL_NUM,
-#define OPT_LOG_TIMESTAMP "log-timestamp"
- OPT_LOG_TIMESTAMP_NUM,
-#define OPT_TRACE "trace"
- OPT_TRACE_NUM,
-#define OPT_TRACE_DIR "trace-dir"
- OPT_TRACE_DIR_NUM,
-#define OPT_TRACE_BUF_SIZE "trace-bufsz"
- OPT_TRACE_BUF_SIZE_NUM,
-#define OPT_TRACE_MODE "trace-mode"
- OPT_TRACE_MODE_NUM,
-#define OPT_MAIN_LCORE "main-lcore"
- OPT_MAIN_LCORE_NUM,
-#define OPT_MBUF_POOL_OPS_NAME "mbuf-pool-ops-name"
- OPT_MBUF_POOL_OPS_NAME_NUM,
-#define OPT_PROC_TYPE "proc-type"
- OPT_PROC_TYPE_NUM,
-#define OPT_NO_HPET "no-hpet"
- OPT_NO_HPET_NUM,
-#define OPT_NO_HUGE "no-huge"
- OPT_NO_HUGE_NUM,
-#define OPT_NO_PCI "no-pci"
- OPT_NO_PCI_NUM,
-#define OPT_NO_SHCONF "no-shconf"
- OPT_NO_SHCONF_NUM,
-#define OPT_IN_MEMORY "in-memory"
- OPT_IN_MEMORY_NUM,
-#define OPT_SOCKET_MEM "socket-mem"
-#define OPT_NUMA_MEM "numa-mem"
- OPT_NUMA_MEM_NUM,
-#define OPT_SOCKET_LIMIT "socket-limit"
-#define OPT_NUMA_LIMIT "numa-limit"
- OPT_NUMA_LIMIT_NUM,
-#define OPT_SYSLOG "syslog"
- OPT_SYSLOG_NUM,
-#define OPT_VDEV "vdev"
- OPT_VDEV_NUM,
-#define OPT_VFIO_INTR "vfio-intr"
- OPT_VFIO_INTR_NUM,
-#define OPT_VFIO_VF_TOKEN "vfio-vf-token"
- OPT_VFIO_VF_TOKEN_NUM,
-#define OPT_VMWARE_TSC_MAP "vmware-tsc-map"
- OPT_VMWARE_TSC_MAP_NUM,
-#define OPT_LEGACY_MEM "legacy-mem"
- OPT_LEGACY_MEM_NUM,
-#define OPT_SINGLE_FILE_SEGMENTS "single-file-segments"
- OPT_SINGLE_FILE_SEGMENTS_NUM,
-#define OPT_IOVA_MODE "iova-mode"
- OPT_IOVA_MODE_NUM,
-#define OPT_MATCH_ALLOCATIONS "match-allocations"
- OPT_MATCH_ALLOCATIONS_NUM,
-#define OPT_TELEMETRY "telemetry"
- OPT_TELEMETRY_NUM,
-#define OPT_NO_TELEMETRY "no-telemetry"
- OPT_NO_TELEMETRY_NUM,
-#define OPT_FORCE_MAX_SIMD_BITWIDTH "force-max-simd-bitwidth"
- OPT_FORCE_MAX_SIMD_BITWIDTH_NUM,
-#define OPT_HUGE_WORKER_STACK "huge-worker-stack"
- OPT_HUGE_WORKER_STACK_NUM,
-
- OPT_LONG_MAX_NUM
-};
-
int eal_parse_log_options(void);
int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
-int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index f59cb43b0e..7b1d2794ec 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -329,9 +329,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
/* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option", rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index e433c1afee..a366083822 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -1967,7 +1967,7 @@ rte_eal_memseg_init(void)
if (!internal_conf->legacy_mem && rte_socket_count() > 1) {
EAL_LOG(WARNING, "DPDK is running on a NUMA system, but is compiled without NUMA support.");
EAL_LOG(WARNING, "This will have adverse consequences for performance and usability.");
- EAL_LOG(WARNING, "Please use --"OPT_LEGACY_MEM" option, or recompile with NUMA support.");
+ EAL_LOG(WARNING, "Please use --legacy-mem option, or recompile with NUMA support.");
}
#endif
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [RFC PATCH v2 5/5] eal: simplify handling of conflicting cmdline options
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
` (3 preceding siblings ...)
2025-07-08 17:20 ` [RFC PATCH v2 4/5] eal: combine parameter validation checks Bruce Richardson
@ 2025-07-08 17:20 ` Bruce Richardson
2025-07-08 18:41 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Stephen Hemminger
` (2 subsequent siblings)
7 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-08 17:20 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
Use a utility function and macro to simplify the code for checking for
conflicting cmdline options. The checking can also be done at the
initial argument collating stage, shortening the argument
processing function which is very much on the long side.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 119 +++++++++++-----------------
1 file changed, 47 insertions(+), 72 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 87ab5a4f13..8c9502c3a6 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -238,6 +238,29 @@ struct rte_argparse eal_argparse = {
}
};
+static inline bool
+conflicting_options(uintptr_t opt1, uintptr_t opt2, const char *opt1_name, const char *opt2_name)
+{
+ char name1[64]; /* should be the max length of any argument */
+ char name2[64];
+
+ strlcpy(name1, opt1_name, sizeof(name1));
+ strlcpy(name2, opt2_name, sizeof(name2));
+ for (int i = 0; name1[i] != '\0'; i++)
+ if (name1[i] == '_')
+ name1[i] = '-';
+ for (int i = 0; name2[i] != '\0'; i++)
+ if (name2[i] == '_')
+ name2[i] = '-';
+ if (opt1 && opt2) {
+ EAL_LOG(ERR, "Options '%s' and '%s' can't be used at the same time", name1, name2);
+ return true;
+ }
+ return false; /* no conflicts */
+}
+#define CONFLICTING_OPTIONS(args, opt1, opt2) \
+ conflicting_options((uintptr_t)(args.opt1), (uintptr_t)(args.opt2), #opt1, #opt2)
+
/* function to call into argparse library to parse the passed argc/argv parameters
* to the eal_init_args structure.
*/
@@ -260,6 +283,30 @@ eal_collate_args(int argc, char **argv)
if (retval < 0)
return retval;
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+
+ /* for non-list args, we can just check for zero/null values using macro */
+ if (CONFLICTING_OPTIONS(args, coremask, lcores) ||
+ CONFLICTING_OPTIONS(args, service_coremask, service_corelist) ||
+ CONFLICTING_OPTIONS(args, no_telemetry, telemetry) ||
+ CONFLICTING_OPTIONS(args, memory_size, socket_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, socket_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_worker_stack) ||
+ CONFLICTING_OPTIONS(args, socket_limit, legacy_mem) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, in_memory) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, single_file_segments, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, no_huge, single_file_segments) ||
+ CONFLICTING_OPTIONS(args, in_memory, huge_unlink))
+ return -1;
+
argv[retval - 1] = argv[0];
return retval - 1;
}
@@ -1830,78 +1877,6 @@ eal_parse_args(void)
struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
- /* check for conflicting options */
- /* both -a and -b cannot be used together (one list must be empty at least) */
- if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
- EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
- }
- /* both -l and -c cannot be used at the same time */
- if (args.coremask != NULL && args.lcores != NULL) {
- EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
- return -1;
- }
- /* both -s and -S cannot be used at the same time */
- if (args.service_coremask != NULL && args.service_corelist != NULL) {
- EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
- return -1;
- }
- /* can't have both telemetry and no-telemetry */
- if (args.no_telemetry && args.telemetry) {
- EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
- return -1;
- }
- /* can't have both -m and --socket-mem */
- if (args.memory_size != NULL && args.socket_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
- return -1;
- }
- /* can't use both no-huge and socket-mem */
- if (args.no_huge && args.socket_mem) {
- EAL_LOG(ERR, "Options --no-huge and --socket-mem can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-worker-stack */
- if (args.huge_worker_stack != NULL && args.no_huge) {
- EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
- return -1;
- }
- /* can't use socket-limit and legacy-mem */
- if (args.socket_limit != NULL && args.legacy_mem) {
- EAL_LOG(ERR, "Options --socket-limit and --legacy-mem can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and in-memory */
- if (args.legacy_mem && args.in_memory) {
- EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and match-allocations */
- if (args.legacy_mem && args.match_allocations) {
- EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and match-allocations */
- if (args.no_huge && args.match_allocations) {
- EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-unlink */
- if (args.no_huge && args.huge_unlink) {
- EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use single-file-segments and huge-unlink */
- if (args.single_file_segments && args.huge_unlink) {
- EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use in-memory and huge-unlink */
- if (args.in_memory && args.huge_unlink) {
- EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
- return -1;
- }
-
/* print version before anything else */
/* since message is explicitly requested by user, we write message
* at highest log level so it can always be seen even if info or
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
` (4 preceding siblings ...)
2025-07-08 17:20 ` [RFC PATCH v2 5/5] eal: simplify handling of conflicting cmdline options Bruce Richardson
@ 2025-07-08 18:41 ` Stephen Hemminger
2025-07-09 7:50 ` Bruce Richardson
2025-07-09 12:30 ` David Marchand
2025-07-17 10:41 ` David Marchand
7 siblings, 1 reply; 67+ messages in thread
From: Stephen Hemminger @ 2025-07-08 18:41 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev
On Tue, 8 Jul 2025 17:20:34 +0000
Bruce Richardson <bruce.richardson@intel.com> wrote:
> This RFC is a second, more complete, prototype of one approach we may
> want to take to help improve management of EAL cmdline arguments.
>
> BACKGROUND:
> - The first problem that led to this work was that of providing a
> way for users to easily provide a set of CPU cores to DPDK where the
> CPU ids are >= RTE_MAX_LCORE
> - There are a number of solutions which were discussed for this, most
> of which involved automatically remapping CPU ids to lcore ids
> starting at zero.
> - However, in discussion with David M. at the last DPDK Summit in
> Prague, he pointed out the main difficulty with all these approaches
> in that they don't work with multi-process, since we can't reuse lcore
> id numbers in secondary process.
> - This in turn lead to a realisation that when processing cmdline
> arguments in DPDK, we always do so with very little context. So, for
> example, when processing the "-l" flag, we have no idea whether there
> will be later a --proc-type=secondary flag. We have all sorts of
> post-arg-processing checks in place to try and catch these scenarios.
>
> This patchset therefore tries to simplify the handling of argument
> processing, by explicitly doing an initial pass to collate all arguments
> into a structure. Thereafter, the actual arg parsing is done in a fixed
> order, meaning that e.g. when processing the --main-lcore flag, we have
> already processed the service core flags. We also can far quicker and
> easier check for conflicting options, since they can all be checked for
> NULL/non-NULL in the arg structure immediately after the struct has been
> populated.
>
> To do the initial argument gathering, this RFC uses the existing argparse
> library in DPDK. With recent changes, this now meets our needs for EAL
> argument parsing and allows us to not need to do direct getopt argument
> processing inside EAL at all.
>
> An additional benefit of this work, is that the argument parsing for EAL
> is much more centralised into common options. This reduces code a bit.
> However, what is missing here is proper handling for unsupported options
> across BSD and Windows. We can either take two approaches:
> 1. just ifdef them out so they don't appear in the argparse list on
> unsupported platforms, giving errors when used.
> 2. keep them in the list of arguments, and ignore them (with warning) when
> used on unsupported platforms.
> The advantage of #1 is that it is simple and correct, but the advantage
> of #2 is that is makes it easier to move scripts and commandline args
> between platforms - but at the cost of the arg list shown by help to be
> less accurate.
>
> Bruce Richardson (5):
> eal: add long options for each short option
> eal: define the EAL parameters in argparse format
> eal: gather EAL args before processing
> eal: combine parameter validation checks
> eal: simplify handling of conflicting cmdline options
>
> lib/eal/common/eal_common_memory.c | 3 +-
> lib/eal/common/eal_common_options.c | 1236 ++++++++++++++-------------
> lib/eal/common/eal_options.h | 101 +--
> lib/eal/common/eal_private.h | 11 +
> lib/eal/freebsd/eal.c | 164 +---
> lib/eal/linux/eal.c | 384 +--------
> lib/eal/linux/eal_memory.c | 2 +-
> lib/eal/meson.build | 2 +-
> lib/eal/windows/eal.c | 113 +--
> lib/meson.build | 1 +
> 10 files changed, 726 insertions(+), 1291 deletions(-)
>
Could DPDK use a better 3rd party library for arparse like:
https://github.com/cofyc/argparse
that one is MIT license so free to reuse, etc.
The project does have a bad habit of reinventing existing more complete
existing libraries (for example RCU).
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK
2025-07-08 18:41 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Stephen Hemminger
@ 2025-07-09 7:50 ` Bruce Richardson
0 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-09 7:50 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev
On Tue, Jul 08, 2025 at 11:41:01AM -0700, Stephen Hemminger wrote:
> On Tue, 8 Jul 2025 17:20:34 +0000
> Bruce Richardson <bruce.richardson@intel.com> wrote:
>
> > This RFC is a second, more complete, prototype of one approach we may
> > want to take to help improve management of EAL cmdline arguments.
> >
> > BACKGROUND:
> > - The first problem that led to this work was that of providing a
> > way for users to easily provide a set of CPU cores to DPDK where the
> > CPU ids are >= RTE_MAX_LCORE
> > - There are a number of solutions which were discussed for this, most
> > of which involved automatically remapping CPU ids to lcore ids
> > starting at zero.
> > - However, in discussion with David M. at the last DPDK Summit in
> > Prague, he pointed out the main difficulty with all these approaches
> > in that they don't work with multi-process, since we can't reuse lcore
> > id numbers in secondary process.
> > - This in turn lead to a realisation that when processing cmdline
> > arguments in DPDK, we always do so with very little context. So, for
> > example, when processing the "-l" flag, we have no idea whether there
> > will be later a --proc-type=secondary flag. We have all sorts of
> > post-arg-processing checks in place to try and catch these scenarios.
> >
> > This patchset therefore tries to simplify the handling of argument
> > processing, by explicitly doing an initial pass to collate all arguments
> > into a structure. Thereafter, the actual arg parsing is done in a fixed
> > order, meaning that e.g. when processing the --main-lcore flag, we have
> > already processed the service core flags. We also can far quicker and
> > easier check for conflicting options, since they can all be checked for
> > NULL/non-NULL in the arg structure immediately after the struct has been
> > populated.
> >
> > To do the initial argument gathering, this RFC uses the existing argparse
> > library in DPDK. With recent changes, this now meets our needs for EAL
> > argument parsing and allows us to not need to do direct getopt argument
> > processing inside EAL at all.
> >
> > An additional benefit of this work, is that the argument parsing for EAL
> > is much more centralised into common options. This reduces code a bit.
> > However, what is missing here is proper handling for unsupported options
> > across BSD and Windows. We can either take two approaches:
> > 1. just ifdef them out so they don't appear in the argparse list on
> > unsupported platforms, giving errors when used.
> > 2. keep them in the list of arguments, and ignore them (with warning) when
> > used on unsupported platforms.
> > The advantage of #1 is that it is simple and correct, but the advantage
> > of #2 is that is makes it easier to move scripts and commandline args
> > between platforms - but at the cost of the arg list shown by help to be
> > less accurate.
> >
> > Bruce Richardson (5):
> > eal: add long options for each short option
> > eal: define the EAL parameters in argparse format
> > eal: gather EAL args before processing
> > eal: combine parameter validation checks
> > eal: simplify handling of conflicting cmdline options
> >
> > lib/eal/common/eal_common_memory.c | 3 +-
> > lib/eal/common/eal_common_options.c | 1236 ++++++++++++++-------------
> > lib/eal/common/eal_options.h | 101 +--
> > lib/eal/common/eal_private.h | 11 +
> > lib/eal/freebsd/eal.c | 164 +---
> > lib/eal/linux/eal.c | 384 +--------
> > lib/eal/linux/eal_memory.c | 2 +-
> > lib/eal/meson.build | 2 +-
> > lib/eal/windows/eal.c | 113 +--
> > lib/meson.build | 1 +
> > 10 files changed, 726 insertions(+), 1291 deletions(-)
> >
>
> Could DPDK use a better 3rd party library for arparse like:
> https://github.com/cofyc/argparse
> that one is MIT license so free to reuse, etc.
>
> The project does have a bad habit of reinventing existing more complete
> existing libraries (for example RCU).
It could, but that would be a separate effort. Since we have the argparse
library already in DPDK, I don't see the point in using a third-party one.
Now, if we want to take the decision to remove our argparse library and
recommend an alternative, that's fine, and I'm sure I'll be able to rework
this patchset to use it. For now, while we have our own argparse, I think
it makes sense to us it rather than have another dependency.
/Bruce
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
` (5 preceding siblings ...)
2025-07-08 18:41 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Stephen Hemminger
@ 2025-07-09 12:30 ` David Marchand
2025-07-09 12:54 ` Bruce Richardson
2025-07-17 10:41 ` David Marchand
7 siblings, 1 reply; 67+ messages in thread
From: David Marchand @ 2025-07-09 12:30 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev
Hi Bruce,
On Tue, Jul 8, 2025 at 7:21 PM Bruce Richardson
<bruce.richardson@intel.com> wrote:
>
> This RFC is a second, more complete, prototype of one approach we may
> want to take to help improve management of EAL cmdline arguments.
>
> BACKGROUND:
> - The first problem that led to this work was that of providing a
> way for users to easily provide a set of CPU cores to DPDK where the
> CPU ids are >= RTE_MAX_LCORE
> - There are a number of solutions which were discussed for this, most
> of which involved automatically remapping CPU ids to lcore ids
> starting at zero.
> - However, in discussion with David M. at the last DPDK Summit in
> Prague, he pointed out the main difficulty with all these approaches
> in that they don't work with multi-process, since we can't reuse lcore
> id numbers in secondary process.
> - This in turn lead to a realisation that when processing cmdline
> arguments in DPDK, we always do so with very little context. So, for
> example, when processing the "-l" flag, we have no idea whether there
> will be later a --proc-type=secondary flag. We have all sorts of
> post-arg-processing checks in place to try and catch these scenarios.
>
> This patchset therefore tries to simplify the handling of argument
> processing, by explicitly doing an initial pass to collate all arguments
> into a structure. Thereafter, the actual arg parsing is done in a fixed
> order, meaning that e.g. when processing the --main-lcore flag, we have
> already processed the service core flags. We also can far quicker and
> easier check for conflicting options, since they can all be checked for
> NULL/non-NULL in the arg structure immediately after the struct has been
> populated.
>
> To do the initial argument gathering, this RFC uses the existing argparse
> library in DPDK. With recent changes, this now meets our needs for EAL
> argument parsing and allows us to not need to do direct getopt argument
> processing inside EAL at all.
>
> An additional benefit of this work, is that the argument parsing for EAL
> is much more centralised into common options. This reduces code a bit.
> However, what is missing here is proper handling for unsupported options
> across BSD and Windows. We can either take two approaches:
> 1. just ifdef them out so they don't appear in the argparse list on
> unsupported platforms, giving errors when used.
> 2. keep them in the list of arguments, and ignore them (with warning) when
> used on unsupported platforms.
> The advantage of #1 is that it is simple and correct, but the advantage
> of #2 is that is makes it easier to move scripts and commandline args
> between platforms - but at the cost of the arg list shown by help to be
> less accurate.
>
> Bruce Richardson (5):
> eal: add long options for each short option
> eal: define the EAL parameters in argparse format
> eal: gather EAL args before processing
> eal: combine parameter validation checks
> eal: simplify handling of conflicting cmdline options
>
> lib/eal/common/eal_common_memory.c | 3 +-
> lib/eal/common/eal_common_options.c | 1236 ++++++++++++++-------------
> lib/eal/common/eal_options.h | 101 +--
> lib/eal/common/eal_private.h | 11 +
> lib/eal/freebsd/eal.c | 164 +---
> lib/eal/linux/eal.c | 384 +--------
> lib/eal/linux/eal_memory.c | 2 +-
> lib/eal/meson.build | 2 +-
> lib/eal/windows/eal.c | 113 +--
> lib/meson.build | 1 +
> 10 files changed, 726 insertions(+), 1291 deletions(-)
Thanks for working on this topic.
I will review it soon, after v25.07.
ASan complains about this series, as some memory gets leaked, could
you have a look?
--
David Marchand
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK
2025-07-09 12:30 ` David Marchand
@ 2025-07-09 12:54 ` Bruce Richardson
0 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-09 12:54 UTC (permalink / raw)
To: David Marchand; +Cc: dev
On Wed, Jul 09, 2025 at 02:30:42PM +0200, David Marchand wrote:
> Hi Bruce,
>
> On Tue, Jul 8, 2025 at 7:21 PM Bruce Richardson
> <bruce.richardson@intel.com> wrote:
> >
> > This RFC is a second, more complete, prototype of one approach we may
> > want to take to help improve management of EAL cmdline arguments.
> >
> > BACKGROUND:
> > - The first problem that led to this work was that of providing a
> > way for users to easily provide a set of CPU cores to DPDK where the
> > CPU ids are >= RTE_MAX_LCORE
> > - There are a number of solutions which were discussed for this, most
> > of which involved automatically remapping CPU ids to lcore ids
> > starting at zero.
> > - However, in discussion with David M. at the last DPDK Summit in
> > Prague, he pointed out the main difficulty with all these approaches
> > in that they don't work with multi-process, since we can't reuse lcore
> > id numbers in secondary process.
> > - This in turn lead to a realisation that when processing cmdline
> > arguments in DPDK, we always do so with very little context. So, for
> > example, when processing the "-l" flag, we have no idea whether there
> > will be later a --proc-type=secondary flag. We have all sorts of
> > post-arg-processing checks in place to try and catch these scenarios.
> >
> > This patchset therefore tries to simplify the handling of argument
> > processing, by explicitly doing an initial pass to collate all arguments
> > into a structure. Thereafter, the actual arg parsing is done in a fixed
> > order, meaning that e.g. when processing the --main-lcore flag, we have
> > already processed the service core flags. We also can far quicker and
> > easier check for conflicting options, since they can all be checked for
> > NULL/non-NULL in the arg structure immediately after the struct has been
> > populated.
> >
> > To do the initial argument gathering, this RFC uses the existing argparse
> > library in DPDK. With recent changes, this now meets our needs for EAL
> > argument parsing and allows us to not need to do direct getopt argument
> > processing inside EAL at all.
> >
> > An additional benefit of this work, is that the argument parsing for EAL
> > is much more centralised into common options. This reduces code a bit.
> > However, what is missing here is proper handling for unsupported options
> > across BSD and Windows. We can either take two approaches:
> > 1. just ifdef them out so they don't appear in the argparse list on
> > unsupported platforms, giving errors when used.
> > 2. keep them in the list of arguments, and ignore them (with warning) when
> > used on unsupported platforms.
> > The advantage of #1 is that it is simple and correct, but the advantage
> > of #2 is that is makes it easier to move scripts and commandline args
> > between platforms - but at the cost of the arg list shown by help to be
> > less accurate.
> >
> > Bruce Richardson (5):
> > eal: add long options for each short option
> > eal: define the EAL parameters in argparse format
> > eal: gather EAL args before processing
> > eal: combine parameter validation checks
> > eal: simplify handling of conflicting cmdline options
> >
> > lib/eal/common/eal_common_memory.c | 3 +-
> > lib/eal/common/eal_common_options.c | 1236 ++++++++++++++-------------
> > lib/eal/common/eal_options.h | 101 +--
> > lib/eal/common/eal_private.h | 11 +
> > lib/eal/freebsd/eal.c | 164 +---
> > lib/eal/linux/eal.c | 384 +--------
> > lib/eal/linux/eal_memory.c | 2 +-
> > lib/eal/meson.build | 2 +-
> > lib/eal/windows/eal.c | 113 +--
> > lib/meson.build | 1 +
> > 10 files changed, 726 insertions(+), 1291 deletions(-)
>
> Thanks for working on this topic.
> I will review it soon, after v25.07.
>
> ASan complains about this series, as some memory gets leaked, could
> you have a look?
>
Sure, I'll take a look before I do a non-RFC version.
However, I'll wait feedback on whether this is a direction we want to take
or not, before I do any more revisions of it.
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
` (6 preceding siblings ...)
2025-07-09 12:30 ` David Marchand
@ 2025-07-17 10:41 ` David Marchand
2025-07-17 10:54 ` Bruce Richardson
7 siblings, 1 reply; 67+ messages in thread
From: David Marchand @ 2025-07-17 10:41 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev, Thomas Monjalon
On Tue, Jul 8, 2025 at 7:21 PM Bruce Richardson
<bruce.richardson@intel.com> wrote:
>
> This RFC is a second, more complete, prototype of one approach we may
> want to take to help improve management of EAL cmdline arguments.
>
> BACKGROUND:
> - The first problem that led to this work was that of providing a
> way for users to easily provide a set of CPU cores to DPDK where the
> CPU ids are >= RTE_MAX_LCORE
> - There are a number of solutions which were discussed for this, most
> of which involved automatically remapping CPU ids to lcore ids
> starting at zero.
> - However, in discussion with David M. at the last DPDK Summit in
> Prague, he pointed out the main difficulty with all these approaches
> in that they don't work with multi-process, since we can't reuse lcore
> id numbers in secondary process.
> - This in turn lead to a realisation that when processing cmdline
> arguments in DPDK, we always do so with very little context. So, for
> example, when processing the "-l" flag, we have no idea whether there
> will be later a --proc-type=secondary flag. We have all sorts of
> post-arg-processing checks in place to try and catch these scenarios.
>
> This patchset therefore tries to simplify the handling of argument
> processing, by explicitly doing an initial pass to collate all arguments
> into a structure. Thereafter, the actual arg parsing is done in a fixed
> order, meaning that e.g. when processing the --main-lcore flag, we have
> already processed the service core flags. We also can far quicker and
> easier check for conflicting options, since they can all be checked for
> NULL/non-NULL in the arg structure immediately after the struct has been
> populated.
>
> To do the initial argument gathering, this RFC uses the existing argparse
> library in DPDK. With recent changes, this now meets our needs for EAL
> argument parsing and allows us to not need to do direct getopt argument
> processing inside EAL at all.
>
> An additional benefit of this work, is that the argument parsing for EAL
> is much more centralised into common options. This reduces code a bit.
> However, what is missing here is proper handling for unsupported options
> across BSD and Windows. We can either take two approaches:
> 1. just ifdef them out so they don't appear in the argparse list on
> unsupported platforms, giving errors when used.
> 2. keep them in the list of arguments, and ignore them (with warning) when
> used on unsupported platforms.
> The advantage of #1 is that it is simple and correct, but the advantage
> of #2 is that is makes it easier to move scripts and commandline args
> between platforms - but at the cost of the arg list shown by help to be
> less accurate.
#2 makes sense if we intend to implement those Linux options in other
OS, but I don't see this coming (I would rather remove options in
general).
So I prefer something like #1.
About patch 1, please update doc/guides/linux_gsg/eal_args.include.rst
(this file needs some fixes as well, like the --log* options are not
documented, this is a separate topic).
About patch 2 where the options are declared, --socket-* options got
renamed as --numa-* recently.
In this same patch, I see little differences in option descriptions.
Those tweaks are easier to read, but some details are lost and not
covered in doc/guides/linux_gsg/eal_args.include.rst (resp.
linux_eal_parameters.rst for Linux only options).
For example, our doc does not describe --log-level=help.
Patch 3 removed the rte_usage_hook_t stuff, this must be restored for
applications that rely on this.
I also see a difference in the cpu discovery logs that disappeared
after the series, I did not investigate why.
EAL: Detected CPU lcores: 16
EAL: Detected NUMA nodes: 1
The rest of the series looks like a good refactoring.
Thanks for the cleanup.
--
David Marchand
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK
2025-07-17 10:41 ` David Marchand
@ 2025-07-17 10:54 ` Bruce Richardson
0 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-17 10:54 UTC (permalink / raw)
To: David Marchand; +Cc: dev, Thomas Monjalon
On Thu, Jul 17, 2025 at 12:41:46PM +0200, David Marchand wrote:
> On Tue, Jul 8, 2025 at 7:21 PM Bruce Richardson
> <bruce.richardson@intel.com> wrote:
> >
> > This RFC is a second, more complete, prototype of one approach we may
> > want to take to help improve management of EAL cmdline arguments.
> >
> > BACKGROUND:
> > - The first problem that led to this work was that of providing a
> > way for users to easily provide a set of CPU cores to DPDK where the
> > CPU ids are >= RTE_MAX_LCORE
> > - There are a number of solutions which were discussed for this, most
> > of which involved automatically remapping CPU ids to lcore ids
> > starting at zero.
> > - However, in discussion with David M. at the last DPDK Summit in
> > Prague, he pointed out the main difficulty with all these approaches
> > in that they don't work with multi-process, since we can't reuse lcore
> > id numbers in secondary process.
> > - This in turn lead to a realisation that when processing cmdline
> > arguments in DPDK, we always do so with very little context. So, for
> > example, when processing the "-l" flag, we have no idea whether there
> > will be later a --proc-type=secondary flag. We have all sorts of
> > post-arg-processing checks in place to try and catch these scenarios.
> >
> > This patchset therefore tries to simplify the handling of argument
> > processing, by explicitly doing an initial pass to collate all arguments
> > into a structure. Thereafter, the actual arg parsing is done in a fixed
> > order, meaning that e.g. when processing the --main-lcore flag, we have
> > already processed the service core flags. We also can far quicker and
> > easier check for conflicting options, since they can all be checked for
> > NULL/non-NULL in the arg structure immediately after the struct has been
> > populated.
> >
> > To do the initial argument gathering, this RFC uses the existing argparse
> > library in DPDK. With recent changes, this now meets our needs for EAL
> > argument parsing and allows us to not need to do direct getopt argument
> > processing inside EAL at all.
> >
> > An additional benefit of this work, is that the argument parsing for EAL
> > is much more centralised into common options. This reduces code a bit.
> > However, what is missing here is proper handling for unsupported options
> > across BSD and Windows. We can either take two approaches:
> > 1. just ifdef them out so they don't appear in the argparse list on
> > unsupported platforms, giving errors when used.
> > 2. keep them in the list of arguments, and ignore them (with warning) when
> > used on unsupported platforms.
> > The advantage of #1 is that it is simple and correct, but the advantage
> > of #2 is that is makes it easier to move scripts and commandline args
> > between platforms - but at the cost of the arg list shown by help to be
> > less accurate.
>
> #2 makes sense if we intend to implement those Linux options in other
> OS, but I don't see this coming (I would rather remove options in
> general).
> So I prefer something like #1.
>
Agreed.
>
> About patch 1, please update doc/guides/linux_gsg/eal_args.include.rst
> (this file needs some fixes as well, like the --log* options are not
> documented, this is a separate topic).
>
Will take a look
> About patch 2 where the options are declared, --socket-* options got
> renamed as --numa-* recently.
>
Missed that. Hazard of just constantly rebasing an old series. Will add new
flags.
> In this same patch, I see little differences in option descriptions.
> Those tweaks are easier to read, but some details are lost and not
> covered in doc/guides/linux_gsg/eal_args.include.rst (resp.
> linux_eal_parameters.rst for Linux only options).
> For example, our doc does not describe --log-level=help.
>
I'll take a look.
> Patch 3 removed the rte_usage_hook_t stuff, this must be restored for
> applications that rely on this.
>
Yes, I was aware of this, but forgot to note it down. Sadly, I think it
will require changes to the argparse library itself, not just EAL work. The
"obvious" solution is to add user-callback support to argparse, but right
now I'm thinking a better solution is to have a flag to argparse which
makes argparse pass the "-h" option back to the user. We then can add a new
argparse function which returns the help string to the caller. That gives
flexibility to apps to create their own help functions with their own
behaviour, if that is what they want.
> I also see a difference in the cpu discovery logs that disappeared
> after the series, I did not investigate why.
> EAL: Detected CPU lcores: 16
> EAL: Detected NUMA nodes: 1
>
I probably used to know why - I just forget now :-)
I'll check this out, and make it compatible if possible.
>
> The rest of the series looks like a good refactoring.
> Thanks for the cleanup.
>
Thanks for the feedback.
Once this series is done, I hope it will make it easier to add in some EAL
arg capability to make it simple to run apps on cores > RTE_MAX_LCORE. I
sometimes run tests on a machine with 144 cores per numa node, and with the
NICs connected to node 1. Specifying the core list there is annoying...
/Bruce
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 0/9] rework EAL argument parsing
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (7 preceding siblings ...)
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 1/9] build: add define for the OS environment name Bruce Richardson
` (9 more replies)
2025-07-21 15:08 ` [PATCH v4 " Bruce Richardson
` (11 subsequent siblings)
20 siblings, 10 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
When processing cmdline arguments in DPDK, we always do so with very
little context. So, for example, when processing the "-l" flag, we have
no idea whether there will be later a --proc-type=secondary flag. We
have all sorts of post-arg-processing checks in place to try and catch
these scenarios.
To improve this situation, this patchset tries to simplify the handling
of argument processing, by explicitly doing an initial pass to collate
all arguments into a structure. Thereafter, the actual arg parsing is
done in a fixed order, meaning that e.g. when processing the
--main-lcore flag, we have already processed the service core flags. We
also can far quicker and easier check for conflicting options, since
they can all be checked for NULL/non-NULL in the arg structure
immediately after the struct has been populated.
To do the initial argument gathering, this RFC uses the existing
argparse library in DPDK. With recent changes, and two additional
patches at the start of this set, this library now meets our needs for
EAL argument parsing and allows us to not need to do direct getopt
argument processing inside EAL at all.
An additional benefit of this work, is that the argument parsing for EAL
is much more centralised into common options. This single list with
ifdefs makes it clear to the viewer what options are common across OS's,
vs what are unix-only or linux-only.
Bruce Richardson (9):
build: add define for the OS environment name
argparse: export function to print help text for object
argparse: allow user-override of help printing
eal: add long options for each short option
eal: define the EAL parameters in argparse format
eal: gather EAL args before processing
eal: ensure proper cleanup on EAL init failure
eal: combine parameter validation checks
eal: simplify handling of conflicting cmdline options
config/meson.build | 1 +
doc/guides/contributing/design.rst | 2 +-
doc/guides/linux_gsg/eal_args.include.rst | 20 +-
doc/guides/prog_guide/argparse_lib.rst | 16 +
lib/argparse/rte_argparse.c | 46 +-
lib/argparse/rte_argparse.h | 21 +-
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 1299 +++++++++++----------
lib/eal/common/eal_options.h | 102 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 245 +---
lib/eal/linux/eal.c | 470 +-------
lib/eal/linux/eal_memory.c | 2 +-
lib/eal/meson.build | 2 +-
lib/eal/windows/eal.c | 156 +--
lib/meson.build | 1 +
16 files changed, 954 insertions(+), 1443 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 1/9] build: add define for the OS environment name
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 2/9] argparse: export function to print help text for object Bruce Richardson
` (8 subsequent siblings)
9 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
Introduce a string define for the currently running OS, or execution
environment.
Originally, with old make build system, CONFIG_RTE_EXEC_ENV used to hold
this name string, but the variable seems to have been missed in the
meson build system, until commit cadb255e25d6 ("eal: add OS defines for
C conditional checks") which introduced the RTE_EXEC_ENV for a different
purpose. Now we can fix the docs with the new name reference.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
config/meson.build | 1 +
doc/guides/contributing/design.rst | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/config/meson.build b/config/meson.build
index f31fef216c..40f33816aa 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -20,6 +20,7 @@ foreach env, id:exec_envs
dpdk_conf.set10('RTE_EXEC_ENV_IS_' + env.to_upper(), (exec_env == env))
endforeach
dpdk_conf.set('RTE_EXEC_ENV', exec_envs[exec_env])
+dpdk_conf.set_quoted('RTE_EXEC_ENV_NAME', exec_env)
dpdk_conf.set('RTE_EXEC_ENV_' + exec_env.to_upper(), 1)
# MS linker requires special treatment.
diff --git a/doc/guides/contributing/design.rst b/doc/guides/contributing/design.rst
index b724177ba1..5517613424 100644
--- a/doc/guides/contributing/design.rst
+++ b/doc/guides/contributing/design.rst
@@ -50,7 +50,7 @@ Per Execution Environment Sources
The following macro options can be used:
-* ``RTE_EXEC_ENV`` is a string that contains the name of the executive environment.
+* ``RTE_EXEC_ENV_NAME`` is a string that contains the name of the executive environment.
* ``RTE_EXEC_ENV_FREEBSD``, ``RTE_EXEC_ENV_LINUX`` or ``RTE_EXEC_ENV_WINDOWS`` are defined only if we are building for this execution environment.
Mbuf features
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 2/9] argparse: export function to print help text for object
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 1/9] build: add define for the OS environment name Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 3/9] argparse: allow user-override of help printing Bruce Richardson
` (7 subsequent siblings)
9 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
Make the function to print out the help text for an argparse object a
public function, which takes as a new parameter the file stream on which
to print. This can be used in future to allow application to extend
their own help information.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/argparse/rte_argparse.c | 43 +++++++++++++++++++------------------
lib/argparse/rte_argparse.h | 14 ++++++++++++
2 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index 331f05f01d..d3b32c6357 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -716,23 +716,23 @@ calc_help_align(const struct rte_argparse *obj)
}
static void
-show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width)
+show_oneline_help(FILE *stream, const struct rte_argparse_arg *arg, uint32_t width)
{
uint32_t len = 0;
uint32_t i;
if (arg->name_short != NULL)
- len = printf(" %s,", arg->name_short);
- len += printf(" %s", arg->name_long);
+ len = fprintf(stream, " %s,", arg->name_short);
+ len += fprintf(stream, " %s", arg->name_long);
for (i = len; i < width; i++)
- printf(" ");
+ fprintf(stream, " ");
- printf("%s\n", arg->help);
+ fprintf(stream, "%s\n", arg->help);
}
static void
-show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
+show_args_pos_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
{
uint32_t position_count = calc_position_count(obj);
const struct rte_argparse_arg *arg;
@@ -741,19 +741,19 @@ show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
if (position_count == 0)
return;
- printf("\npositional arguments:\n");
+ fprintf(stream, "\npositional arguments:\n");
for (i = 0; /* NULL */; i++) {
arg = &obj->args[i];
if (arg->name_long == NULL)
break;
if (!is_arg_positional(arg))
continue;
- show_oneline_help(arg, align);
+ show_oneline_help(stream, arg, align);
}
}
static void
-show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
+show_args_opt_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
{
static const struct rte_argparse_arg help = {
.name_long = "--help",
@@ -763,34 +763,35 @@ show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
const struct rte_argparse_arg *arg;
uint32_t i;
- printf("\noptions:\n");
- show_oneline_help(&help, align);
+ fprintf(stream, "\noptions:\n");
+ show_oneline_help(stream, &help, align);
for (i = 0; /* NULL */; i++) {
arg = &obj->args[i];
if (arg->name_long == NULL)
break;
if (!is_arg_optional(arg))
continue;
- show_oneline_help(arg, align);
+ show_oneline_help(stream, arg, align);
}
}
-static void
-show_args_help(const struct rte_argparse *obj)
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_print_help, 25.07)
+void
+rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj)
{
uint32_t align = calc_help_align(obj);
- printf("usage: %s %s\n", obj->prog_name, obj->usage);
+ fprintf(stream, "usage: %s %s\n", obj->prog_name, obj->usage);
if (obj->descriptor != NULL)
- printf("\ndescriptor: %s\n", obj->descriptor);
+ fprintf(stream, "\ndescriptor: %s\n", obj->descriptor);
- show_args_pos_help(obj, align);
- show_args_opt_help(obj, align);
+ show_args_pos_help(stream, obj, align);
+ show_args_opt_help(stream, obj, align);
if (obj->epilog != NULL)
- printf("\n%s\n", obj->epilog);
+ fprintf(stream, "\n%s\n", obj->epilog);
else
- printf("\n");
+ fprintf(stream, "\n");
}
RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_parse, 24.03)
@@ -820,7 +821,7 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
goto error;
if (show_help) {
- show_args_help(obj);
+ rte_argparse_print_help(stdout, obj);
exit(0);
}
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index 52bef34363..baf278f6b9 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -189,6 +189,20 @@ struct rte_argparse {
__rte_experimental
int rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Output the help text information for the given argparse object.
+ *
+ * @param stream
+ * Output file handle, e.g. stdout, stderr, on which to print the help text.
+ * @param obj
+ * Parser object.
+ */
+__rte_experimental
+void rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj);
+
/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 3/9] argparse: allow user-override of help printing
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 1/9] build: add define for the OS environment name Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 2/9] argparse: export function to print help text for object Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-21 8:43 ` David Marchand
2025-07-18 14:33 ` [PATCH v3 4/9] eal: add long options for each short option Bruce Richardson
` (6 subsequent siblings)
9 siblings, 1 reply; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
When the arguments passed to argparse include -h/--help then usage
information is automatically printed. Provide the capability for the
user to supply their own help function for this.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
doc/guides/prog_guide/argparse_lib.rst | 16 ++++++++++++++++
lib/argparse/rte_argparse.c | 5 ++++-
lib/argparse/rte_argparse.h | 7 ++++++-
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/doc/guides/prog_guide/argparse_lib.rst b/doc/guides/prog_guide/argparse_lib.rst
index 9f11714890..b309260d20 100644
--- a/doc/guides/prog_guide/argparse_lib.rst
+++ b/doc/guides/prog_guide/argparse_lib.rst
@@ -24,6 +24,8 @@ Features and Capabilities
#. autosave: used for parsing known value types;
#. callback: will invoke user callback to parse.
+- Supports automatic help and usage information.
+
Usage Guide
-----------
@@ -193,3 +195,17 @@ Then the user input could contain multiple ``--xyz`` arguments.
The multiple times argument only support with optional argument
and must be parsed by callback way.
+
+Help and Usage Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The argparse library supports automatic generation of help and usage information.
+When the input arguments include ``-h`` or ``--help``,
+it will print the usage information to standard output.
+If the default help output is not what is wanted,
+the user can provide a custom help printing function by setting the ``print_help`` field in the ``rte_argparse`` object.
+(If this field is set to NULL, the default help printing function will be used.)
+
+If the custom help printing function wants to use the text produced by the default help function,
+it can call the function ``rte_argparse_print_help()`` to get the help text printed to an output stream,
+for example: stdout or stderr.
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index d3b32c6357..e7b9bf573d 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -821,7 +821,10 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
goto error;
if (show_help) {
- rte_argparse_print_help(stdout, obj);
+ if (obj->print_help != NULL)
+ obj->print_help(obj);
+ else
+ rte_argparse_print_help(stdout, obj);
exit(0);
}
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index baf278f6b9..63b49ba220 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -160,8 +160,13 @@ struct rte_argparse {
rte_arg_parser_t callback;
/** Opaque which used to invoke callback. */
void *opaque;
+ /**
+ * Function pointer for printing usage when -h is passed.
+ * If this is NULL, default printing function will be used.
+ */
+ void (*print_help)(const struct rte_argparse *obj);
/** Reserved field used for future extension. */
- void *reserved[16];
+ void *reserved[15];
/** Arguments configuration. Must ended with ARGPARSE_ARG_END(). */
struct rte_argparse_arg args[];
};
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 4/9] eal: add long options for each short option
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
` (2 preceding siblings ...)
2025-07-18 14:33 ` [PATCH v3 3/9] argparse: allow user-override of help printing Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
` (5 subsequent siblings)
9 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
To simplify future rework of the EAL arg handling, add a long-option
equivalent for each short option that doesn't already have one.
When updating the docs with the new long options, standardize the format
of options which have both short and long variants, and drop the
deprecated service-coremask option from the docs, rather than adding its
new long option.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
doc/guides/linux_gsg/eal_args.include.rst | 20 ++++++++------------
lib/eal/common/eal_common_options.c | 9 +++++++++
lib/eal/common/eal_options.h | 16 ++++++++++++++++
3 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/doc/guides/linux_gsg/eal_args.include.rst b/doc/guides/linux_gsg/eal_args.include.rst
index 9ced54af40..0b17879d42 100644
--- a/doc/guides/linux_gsg/eal_args.include.rst
+++ b/doc/guides/linux_gsg/eal_args.include.rst
@@ -4,7 +4,7 @@
Lcore-related options
~~~~~~~~~~~~~~~~~~~~~
-* ``-l/--lcores <core list>``
+* ``-l, --lcores <core list>``
List of cores to run on
@@ -71,11 +71,7 @@ Lcore-related options
Core ID that is used as main.
-* ``-s <service core mask>``
-
- Hexadecimal bitmask of cores to be used as service cores.
-
-* ``-S <service core list>``
+* ``-S, --service-corelist <service core list>``
List of cores to be used as service cores.
@@ -108,7 +104,7 @@ Device-related options
--vdev 'net_pcap0,rx_pcap=input.pcap,tx_pcap=output.pcap'
-* ``-d <path to shared object or directory>``
+* ``-d, --driver-path <path to shared object or directory>``
Load external drivers. An argument can be a single shared object file, or a
directory containing multiple driver shared objects. Multiple -d options are
@@ -134,15 +130,15 @@ Multiprocessing-related options
Memory-related options
~~~~~~~~~~~~~~~~~~~~~~
-* ``-n <number of channels>``
+* ``-n, --memory-channels <number of channels>``
Set the number of memory channels to use.
-* ``-r <number of ranks>``
+* ``-r, --memory-ranks <number of ranks>``
Set the number of memory ranks (auto-detected by default).
-* ``-m <megabytes>``
+* ``-m, --memory-size <megabytes>``
Amount of memory to preallocate at startup.
@@ -236,11 +232,11 @@ Debugging options
Other options
~~~~~~~~~~~~~
-* ``-h``, ``--help``
+* ``-h, --help``
Display help message listing all EAL parameters.
-* ``-v``
+* ``-v, --version``
Display the version information on startup.
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index f0a9ddeeb7..cafae9d9d7 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -66,7 +66,9 @@ eal_short_options[] =
const struct option
eal_long_options[] = {
{OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
+ {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
{OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
+ {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
{OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
{OPT_HELP, 0, NULL, OPT_HELP_NUM },
{OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
@@ -76,6 +78,11 @@ eal_long_options[] = {
{OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
{OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
{OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
+ {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
+ {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
+ {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
+ {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
+ {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
{OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
{OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
{OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
@@ -109,6 +116,8 @@ eal_long_options[] = {
{OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
{OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
{OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
+ {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
+
{0, 0, NULL, 0 }
};
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 7a56aa3810..6ef45559f0 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -17,8 +17,24 @@ enum {
OPT_DEV_ALLOW_NUM = 'a',
#define OPT_DEV_BLOCK "block"
OPT_DEV_BLOCK_NUM = 'b',
+#define OPT_COREMASK "coremask"
+ OPT_COREMASK_NUM = 'c',
+#define OPT_DRIVER_PATH "driver-path"
+ OPT_DRIVER_PATH_NUM = 'd',
#define OPT_LCORES "lcores"
OPT_LCORES_NUM = 'l',
+#define OPT_MEMORY_SIZE "memory-size"
+ OPT_MEMORY_SIZE_NUM = 'm',
+#define OPT_MEMORY_CHANNELS "memory-channels"
+ OPT_MEMORY_CHANNELS_NUM = 'n',
+#define OPT_MEMORY_RANKS "memory-ranks"
+ OPT_MEMORY_RANKS_NUM = 'r',
+#define OPT_SERVICE_COREMASK "service-coremask"
+ OPT_SERVICE_COREMASK_NUM = 's',
+#define OPT_SERVICE_CORELIST "service-corelist"
+ OPT_SERVICE_CORELIST_NUM = 'S',
+#define OPT_VERSION "version"
+ OPT_VERSION_NUM = 'v',
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 5/9] eal: define the EAL parameters in argparse format
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
` (3 preceding siblings ...)
2025-07-18 14:33 ` [PATCH v3 4/9] eal: add long options for each short option Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-21 8:41 ` David Marchand
2025-07-18 14:33 ` [PATCH v3 6/9] eal: gather EAL args before processing Bruce Richardson
` (4 subsequent siblings)
9 siblings, 1 reply; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
This table should allow us to parse all the eal args into a single
structure for later parsing in a fixed-order field basis. For those
elements that take multiple values, define a TAILQ and a callback to
process those elements.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 221 +++++++++++++++++++++++++++-
lib/eal/meson.build | 2 +-
lib/meson.build | 1 +
3 files changed, 220 insertions(+), 4 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index cafae9d9d7..9cbb6f31e7 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -28,11 +28,13 @@
#include <rte_version.h>
#include <rte_devargs.h>
#include <rte_memcpy.h>
+#include <sys/queue.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <rte_telemetry.h>
#endif
#include <rte_vect.h>
+#include <rte_argparse.h>
#include <eal_export.h>
#include "eal_internal_cfg.h"
#include "eal_options.h"
@@ -47,6 +49,222 @@
#define LCORE_OPT_LST 1
#define LCORE_OPT_MSK 2
+/* Allow the application to print its usage message too if set */
+static rte_usage_hook_t rte_application_usage_hook;
+
+struct arg_list_elem {
+ TAILQ_ENTRY(arg_list_elem) next;
+ char *arg;
+};
+TAILQ_HEAD(arg_list, arg_list_elem);
+
+struct eal_init_args {
+ /* define a struct member for each EAL option, member name is the same as option name.
+ * Parameters that take an argument e.g. -l, are char *,
+ * parameters that take no options e.g. --no-huge, are bool.
+ * parameters that can be given multiple times e.g. -a, are arg_lists,
+ * parameters that are optional e.g. --huge-unlink,
+ * are char * but are set to (void *)1 if the parameter is not given.
+ * NOTE: List is to be kept alphabetically by option name
+ */
+ struct arg_list allow;
+ char *base_virtaddr;
+ struct arg_list block;
+ char *coremask;
+ bool create_uio_dev;
+ struct arg_list driver_path;
+ char *file_prefix;
+ char *force_max_simd_bitwidth;
+ char *huge_dir;
+ char *huge_unlink; /* parameter optional */
+ char *huge_worker_stack; /* parameter optional */
+ bool in_memory;
+ char *iova_mode;
+ char *lcores;
+ bool legacy_mem;
+ char *log_color; /* parameter optional */
+ char *log_level;
+ char *log_timestamp; /* parameter optional */
+ char *main_lcore;
+ bool match_allocations;
+ char *mbuf_pool_ops_name;
+ char *memory_channels;
+ char *memory_ranks;
+ char *memory_size;
+ bool no_hpet;
+ bool no_huge;
+ bool no_pci;
+ bool no_shconf;
+ bool no_telemetry;
+ char *numa_mem;
+ char *numa_limit;
+ char *proc_type;
+ char *service_coremask;
+ char *service_corelist;
+ bool single_file_segments;
+ char *syslog; /* parameter optional */
+ bool telemetry;
+ char *trace;
+ char *trace_bufsz;
+ char *trace_dir;
+ char *trace_mode;
+ struct arg_list vdev;
+ bool version;
+ char *vfio_intr;
+ char *vfio_vf_token;
+ bool vmware_tsc_map;
+};
+struct eal_init_args args;
+
+/* an rte_argparse callback to append the argument to an arg_list
+ * in args. The index is the offset into the struct of the list.
+ */
+static int
+arg_list_callback(uint32_t index, const char *arg, void *init_args)
+{
+ struct arg_list *list = RTE_PTR_ADD(init_args, index);
+ struct arg_list_elem *elem;
+
+ elem = malloc(sizeof(*elem));
+ if (elem == NULL)
+ return -1;
+
+ elem->arg = strdup(arg);
+ if (elem->arg == NULL) {
+ free(elem);
+ return -1;
+ }
+
+ TAILQ_INSERT_TAIL(list, elem, next);
+ return 0;
+}
+
+static void
+eal_usage(const struct rte_argparse *obj)
+{
+ rte_argparse_print_help(stdout, obj);
+ if (rte_application_usage_hook != NULL)
+ rte_application_usage_hook(obj->prog_name);
+}
+
+/* For arguments which have an arg_list type, they use callback (no val_saver),
+ * require a value, and have the SUPPORT_MULTI flag.
+ */
+#define LIST_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_set = (void *)offsetof(struct eal_init_args, fieldname), \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .flags = RTE_ARGPARSE_FLAG_SUPPORT_MULTI, \
+}
+/* For arguments which have a string type, they use val_saver (no callback),
+ * and normally REQUIRED_VALUE.
+ */
+#define STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+}
+/* For flags which have optional arguments, they use both val_saver and val_set,
+ * but still have a string type.
+ */
+#define OPT_STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_OPTIONAL, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+}
+/* For boolean arguments, they use val_saver and val_set, with NO_VALUE flag.
+ */
+#define BOOL_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_NONE, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_BOOL, \
+}
+
+struct rte_argparse eal_argparse = {
+ .prog_name = "",
+ .usage = "<DPDK EAL options>",
+ .epilog = "For more information on EAL options, see the DPDK documentation at: \n"
+ "\thttps://doc.dpdk.org/guides/" RTE_EXEC_ENV_NAME "_gsg/",
+ .exit_on_error = true,
+ .callback = arg_list_callback,
+ .print_help = eal_usage,
+ .opaque = &args,
+ .args = {
+ /* list of EAL arguments as struct rte_argparse_arg. */
+ /* (Alphabetical) List of common options first */
+ LIST_ARG("--allow", "-a", "Add device to allow-list, causing DPDK to only use specified devices", allow),
+ STR_ARG("--base-virtaddr", NULL, "Base virtual address to reserve memory", base_virtaddr),
+ LIST_ARG("--block", "-b", "Add device to block-list, preventing DPDK from using the device", block),
+ STR_ARG("--coremask", "-c", "Hexadecimal bitmask of cores to use", coremask),
+ LIST_ARG("--driver-path", "-d", "Path to external driver shared object, or directory of drivers", driver_path),
+ STR_ARG("--force-max-simd-bitwidth", NULL, "Set max SIMD bitwidth to use in vector code paths", force_max_simd_bitwidth),
+ OPT_STR_ARG("--huge-unlink", NULL, "Unlink hugetlbfs files on exit (existing|always|never)", huge_unlink),
+ BOOL_ARG("--in-memory", NULL, "DPDK should not create shared mmap files in filesystem (disables secondary process support)", in_memory),
+ STR_ARG("--iova-mode", NULL, "IOVA mapping mode, physical (pa)/virtual (va)", iova_mode),
+ STR_ARG("--lcores", "-l", "List of CPU cores to use", lcores),
+ BOOL_ARG("--legacy-mem", NULL, "Enable legacy memory behavior", legacy_mem),
+ OPT_STR_ARG("--log-color", NULL, "Enable/disable color in log output", log_color),
+ STR_ARG("--log-level", NULL, "Log level for loggers; use log-level=help for list of log types and levels", log_level),
+ OPT_STR_ARG("--log-timestamp", NULL, "Enable/disable timestamp in log output", log_timestamp),
+ STR_ARG("--main-lcore", NULL, "Select which core to use for the main thread", main_lcore),
+ STR_ARG("--mbuf-pool-ops-name", NULL, "User defined mbuf default pool ops name", mbuf_pool_ops_name),
+ STR_ARG("--memory-channels", "-n", "Number of memory channels per socket", memory_channels),
+ STR_ARG("--memory-ranks", "-r", "Force number of memory ranks (don't detect)", memory_ranks),
+ STR_ARG("--memory-size", "-m", "Total size of memory to allocate initially", memory_size),
+ BOOL_ARG("--no-hpet", NULL, "Disable HPET timer", no_hpet),
+ BOOL_ARG("--no-huge", NULL, "Disable hugetlbfs support", no_huge),
+ BOOL_ARG("--no-pci", NULL, "Disable all PCI devices", no_pci),
+ BOOL_ARG("--no-shconf", NULL, "Disable shared config file generation", no_shconf),
+ BOOL_ARG("--no-telemetry", NULL, "Disable telemetry", no_telemetry),
+ STR_ARG("--proc-type", NULL, "Type of process (primary|secondary|auto)", proc_type),
+ STR_ARG("--service-corelist", "-S", "List of cores to use for service threads", service_corelist),
+ STR_ARG("--service-coremask", "-s", "Hexadecimal bitmask of cores to use for service threads", service_coremask),
+ BOOL_ARG("--single-file-segments", NULL, "Store all pages within single files (per-page-size, per-node)", single_file_segments),
+ BOOL_ARG("--telemetry", NULL, "Enable telemetry", telemetry),
+ LIST_ARG("--vdev", NULL, "Add a virtual device to the system; format=<driver><id>[,key=val,...]", vdev),
+ BOOL_ARG("--vmware-tsc-map", NULL, "Use VMware TSC mapping instead of native RDTSC", vmware_tsc_map),
+ BOOL_ARG("--version", "-v", "Show version", version),
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+ /* Linux and FreeBSD options*/
+ OPT_STR_ARG("--syslog", NULL, "Log to syslog (and optionally set facility)", syslog),
+ STR_ARG("--trace", NULL, "Enable trace based on regular expression trace name", trace),
+ STR_ARG("--trace-bufsz", NULL, "Trace buffer size", trace_bufsz),
+ STR_ARG("--trace-dir", NULL, "Trace directory", trace_dir),
+ STR_ARG("--trace-mode", NULL, "Trace mode", trace_mode),
+#endif
+
+#ifdef RTE_EXEC_ENV_LINUX
+ /* Linux-only options */
+ BOOL_ARG("--create-uio-dev", NULL, "Create /dev/uioX devices", create_uio_dev),
+ STR_ARG("--file-prefix", NULL, "Base filename of hugetlbfs files", file_prefix),
+ STR_ARG("--huge-dir", NULL, "Directory for hugepage files", huge_dir),
+ OPT_STR_ARG("--huge-worker-stack", NULL, "Allocate worker thread stacks from hugepage memory, with optional size (kB)", huge_worker_stack),
+ BOOL_ARG("--match-allocations", NULL, "Free hugepages exactly as allocated", match_allocations),
+ STR_ARG("--numa-mem", NULL, "Memory to allocate on NUMA nodes (comma separated values)", numa_mem),
+ STR_ARG("--numa-limit", NULL, "Limit memory allocation on NUMA nodes (comma separated values)", numa_limit),
+ STR_ARG("--socket-mem", NULL, "Alias for --numa-mem", numa_mem),
+ STR_ARG("--socket-limit", NULL, "Alias for --numa-limit", numa_limit),
+ STR_ARG("--vfio-intr", NULL, "VFIO interrupt mode (legacy|msi|msix)", vfio_intr),
+ STR_ARG("--vfio-vf-token", NULL, "VF token (UUID) shared between SR-IOV PF and VFs", vfio_vf_token),
+#endif
+ ARGPARSE_ARG_END(),
+ }
+};
+
const char
eal_short_options[] =
"a:" /* allow */
@@ -165,9 +383,6 @@ static int main_lcore_parsed;
static int mem_parsed;
static int core_parsed;
-/* Allow the application to print its usage message too if set */
-static rte_usage_hook_t rte_application_usage_hook;
-
/* Returns rte_usage_hook_t */
rte_usage_hook_t
eal_get_application_usage_hook(void)
diff --git a/lib/eal/meson.build b/lib/eal/meson.build
index e1d6c4cf17..f9fcee24ee 100644
--- a/lib/eal/meson.build
+++ b/lib/eal/meson.build
@@ -14,7 +14,7 @@ subdir(exec_env)
subdir(arch_subdir)
-deps += ['log', 'kvargs']
+deps += ['argparse', 'kvargs']
if not is_windows
deps += ['telemetry']
endif
diff --git a/lib/meson.build b/lib/meson.build
index 0d56b2083b..dec90059e1 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -71,6 +71,7 @@ libraries = [
]
always_enable = [
+ 'argparse',
'cmdline',
'eal',
'ethdev',
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 6/9] eal: gather EAL args before processing
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
` (4 preceding siblings ...)
2025-07-18 14:33 ` [PATCH v3 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
` (3 subsequent siblings)
9 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev
Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk,
Anatoly Burakov
DPDK traditionally has iterated through all args and processed them as
they appear in the commandline. The arg processing logic can be
simplified if instead we initially gather all arguments into a structure
which is then processed with the arguments dealt with in a fixed/known
order.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 877 ++++++++++++++--------------
lib/eal/common/eal_options.h | 10 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 164 +-----
lib/eal/linux/eal.c | 379 +-----------
lib/eal/windows/eal.c | 113 +---
6 files changed, 482 insertions(+), 1072 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 9cbb6f31e7..eecb8eba3a 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -46,8 +46,7 @@
#endif
#define BITS_PER_HEX 4
-#define LCORE_OPT_LST 1
-#define LCORE_OPT_MSK 2
+#define NUMA_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
/* Allow the application to print its usage message too if set */
static rte_usage_hook_t rte_application_usage_hook;
@@ -265,80 +264,31 @@ struct rte_argparse eal_argparse = {
}
};
-const char
-eal_short_options[] =
- "a:" /* allow */
- "b:" /* block */
- "c:" /* coremask */
- "s:" /* service coremask */
- "d:" /* driver */
- "h" /* help */
- "l:" /* corelist */
- "S:" /* service corelist */
- "m:" /* memory size */
- "n:" /* memory channels */
- "r:" /* memory ranks */
- "v" /* version */
- ;
-
-const struct option
-eal_long_options[] = {
- {OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
- {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
- {OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
- {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
- {OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
- {OPT_HELP, 0, NULL, OPT_HELP_NUM },
- {OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
- {OPT_HUGE_UNLINK, 2, NULL, OPT_HUGE_UNLINK_NUM },
- {OPT_IOVA_MODE, 1, NULL, OPT_IOVA_MODE_NUM },
- {OPT_LCORES, 1, NULL, OPT_LCORES_NUM },
- {OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
- {OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
- {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
- {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
- {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
- {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
- {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
- {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
- {OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
- {OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
- {OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
- {OPT_TRACE_MODE, 1, NULL, OPT_TRACE_MODE_NUM },
- {OPT_MAIN_LCORE, 1, NULL, OPT_MAIN_LCORE_NUM },
- {OPT_MBUF_POOL_OPS_NAME, 1, NULL, OPT_MBUF_POOL_OPS_NAME_NUM},
- {OPT_NO_HPET, 0, NULL, OPT_NO_HPET_NUM },
- {OPT_NO_HUGE, 0, NULL, OPT_NO_HUGE_NUM },
- {OPT_NO_PCI, 0, NULL, OPT_NO_PCI_NUM },
- {OPT_NO_SHCONF, 0, NULL, OPT_NO_SHCONF_NUM },
- {OPT_IN_MEMORY, 0, NULL, OPT_IN_MEMORY_NUM },
- {OPT_DEV_BLOCK, 1, NULL, OPT_DEV_BLOCK_NUM },
- {OPT_DEV_ALLOW, 1, NULL, OPT_DEV_ALLOW_NUM },
- {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM },
- /* socket-mem/socket-limit are kept for backwards compatibility */
- {OPT_SOCKET_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_SOCKET_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
- {OPT_NUMA_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_NUMA_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
-#ifndef RTE_EXEC_ENV_WINDOWS
- {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM },
-#endif
- {OPT_VDEV, 1, NULL, OPT_VDEV_NUM },
- {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
- {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM },
- {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
- {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM },
- {OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM},
- {OPT_MATCH_ALLOCATIONS, 0, NULL, OPT_MATCH_ALLOCATIONS_NUM},
- {OPT_TELEMETRY, 0, NULL, OPT_TELEMETRY_NUM },
- {OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
- {OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
- {OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
- {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
-
-
- {0, 0, NULL, 0 }
-};
+/* function to call into argparse library to parse the passed argc/argv parameters
+ * to the eal_init_args structure.
+ */
+int
+eal_collate_args(int argc, char **argv)
+{
+ if (argc < 1 || argv == NULL)
+ return -EINVAL;
+
+ /* initialize the list of arguments */
+ memset(&args, 0, sizeof(args));
+ TAILQ_INIT(&args.allow);
+ TAILQ_INIT(&args.block);
+ TAILQ_INIT(&args.driver_path);
+ TAILQ_INIT(&args.vdev);
+
+ /* parse the arguments */
+ eal_argparse.prog_name = argv[0];
+ int retval = rte_argparse_parse(&eal_argparse, argc, argv);
+ if (retval < 0)
+ return retval;
+
+ argv[retval - 1] = argv[0];
+ return retval - 1;
+}
TAILQ_HEAD(shared_driver_list, shared_driver);
@@ -380,7 +330,6 @@ static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
static int main_lcore_parsed;
-static int mem_parsed;
static int core_parsed;
/* Returns rte_usage_hook_t */
@@ -404,7 +353,12 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
return old_func;
}
-#ifndef RTE_EXEC_ENV_WINDOWS
+#ifdef RTE_EXEC_ENV_WINDOWS
+
+int
+eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+
+#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
static char **eal_app_args;
@@ -492,7 +446,7 @@ eal_save_args(int argc, char **argv)
eal_args = NULL;
return -1;
}
-#endif
+#endif /* !RTE_EXEC_ENV_WINDOWS */
static int
eal_option_device_add(enum rte_devtype type, const char *optarg)
@@ -915,17 +869,6 @@ eal_parse_service_coremask(const char *coremask)
return 0;
}
-static int
-eal_service_cores_parsed(void)
-{
- int idx;
- for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- if (lcore_config[idx].core_role == ROLE_SERVICE)
- return 1;
- }
- return 0;
-}
-
static int
update_lcore_config(int *cores)
{
@@ -1752,361 +1695,486 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return -1;
}
-bool
-eal_option_is_log(int opt)
+/* Parse all arguments looking for log related ones */
+int
+eal_parse_log_options(void)
{
- switch (opt) {
- case OPT_LOG_COLOR_NUM:
- case OPT_LOG_LEVEL_NUM:
- case OPT_LOG_TIMESTAMP_NUM:
- case OPT_SYSLOG_NUM:
- return true;
- default:
- return false;
+ if (args.log_level != NULL) {
+ if (eal_parse_log_level(args.log_level) < 0) {
+ EAL_LOG(ERR, "invalid log-level parameter");
+ return -1;
+ }
+ }
+ if (args.log_color != NULL) {
+ /* if value is 1, no argument specified, so pass NULL */
+ if (args.log_color == (void *)1)
+ args.log_color = NULL;
+ if (eal_log_color(args.log_color) < 0) {
+ EAL_LOG(ERR, "invalid log-color parameter");
+ return -1;
+ }
+ }
+ if (args.log_timestamp != NULL) {
+ /* similarly log_timestamp may be 1 */
+ if (args.log_timestamp == (void *)1)
+ args.log_timestamp = NULL;
+ if (eal_log_timestamp(args.log_timestamp) < 0) {
+ EAL_LOG(ERR, "invalid log-timestamp parameter");
+ return -1;
+ }
+ }
+ if (args.syslog != NULL) {
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "syslog is not supported on Windows, ignoring parameter");
+#else
+ /* also syslog parameter may be 1 */
+ if (args.syslog == (void *)1)
+ args.syslog = NULL;
+ if (eal_log_syslog(args.syslog) < 0) {
+ EAL_LOG(ERR, "invalid syslog parameter");
+ return -1;
+ }
+#endif
}
+ return 0;
}
-/* Parse all arguments looking for log related ones */
-int
-eal_parse_log_options(int argc, char * const argv[])
+static int
+eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
{
- struct internal_config *internal_conf = eal_get_internal_configuration();
- int option_index, opt;
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_opterr = opterr;
- char *old_optarg = optarg;
-#ifdef RTE_EXEC_ENV_FREEBSD
- const int old_optreset = optreset;
- optreset = 1;
-#endif
+ char *arg[RTE_MAX_NUMA_NODES];
+ char *end;
+ int arg_num, i, len;
- optind = 1;
- opterr = 0;
+ len = strnlen(strval, NUMA_MEM_STRLEN);
+ if (len == NUMA_MEM_STRLEN) {
+ EAL_LOG(ERR, "--numa-mem/--socket-mem parameter is too long");
+ return -1;
+ }
- while ((opt = getopt_long(argc, argv, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
+ /* all other error cases will be caught later */
+ if (!isdigit(strval[len-1]))
+ return -1;
- if (!eal_option_is_log(opt))
- continue;
+ /* split the optarg into separate socket values */
+ arg_num = rte_strsplit(strval, len,
+ arg, RTE_MAX_NUMA_NODES, ',');
- if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+ /* if split failed, or 0 arguments */
+ if (arg_num <= 0)
+ return -1;
+
+ /* parse each defined socket option */
+ errno = 0;
+ for (i = 0; i < arg_num; i++) {
+ uint64_t val;
+ end = NULL;
+ val = strtoull(arg[i], &end, 10);
+
+ /* check for invalid input */
+ if ((errno != 0) ||
+ (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
+ val <<= 20;
+ socket_arg[i] = val;
}
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
- opterr = old_opterr;
-#ifdef RTE_EXEC_ENV_FREEBSD
- optreset = old_optreset;
+ return 0;
+}
+
+static int
+eal_parse_vfio_intr(const char *mode)
+{
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+ static struct {
+ const char *name;
+ enum rte_intr_mode value;
+ } map[] = {
+ { "legacy", RTE_INTR_MODE_LEGACY },
+ { "msi", RTE_INTR_MODE_MSI },
+ { "msix", RTE_INTR_MODE_MSIX },
+ };
+
+ for (size_t i = 0; i < RTE_DIM(map); i++) {
+ if (!strcmp(mode, map[i].name)) {
+ internal_conf->vfio_intr_mode = map[i].value;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+eal_parse_vfio_vf_token(const char *vf_token)
+{
+ struct internal_config *cfg = eal_get_internal_configuration();
+ rte_uuid_t uuid;
+
+ if (!rte_uuid_parse(vf_token, uuid)) {
+ rte_uuid_copy(cfg->vfio_vf_token, uuid);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+eal_parse_huge_worker_stack(const char *arg)
+{
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "Cannot set worker stack size on Windows, parameter ignored");
+ RTE_SET_USED(arg);
+#else
+ struct internal_config *cfg = eal_get_internal_configuration();
+
+ if (arg == NULL || arg[0] == '\0') {
+ pthread_attr_t attr;
+ int ret;
+
+ if (pthread_attr_init(&attr) != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
+ pthread_attr_destroy(&attr);
+ if (ret != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ } else {
+ unsigned long stack_size;
+ char *end;
+
+ errno = 0;
+ stack_size = strtoul(arg, &end, 10);
+ if (errno || end == NULL || stack_size == 0 ||
+ stack_size >= (size_t)-1 / 1024)
+ return -1;
+
+ cfg->huge_worker_stack_size = stack_size * 1024;
+ }
+
+ EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
+ cfg->huge_worker_stack_size / 1024);
#endif
return 0;
}
+/* Parse the arguments given in the command line of the application */
int
-eal_parse_common_option(int opt, const char *optarg,
- struct internal_config *conf)
+eal_parse_args(void)
{
- static int b_used;
- static int a_used;
-
- switch (opt) {
- case 'b':
- if (a_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, optarg) < 0)
+ struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct arg_list_elem *arg;
+
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+ /* both -l and -c cannot be used at the same time */
+ if (args.coremask != NULL && args.lcores != NULL) {
+ EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
+ return -1;
+ }
+ /* both -s and -S cannot be used at the same time */
+ if (args.service_coremask != NULL && args.service_corelist != NULL) {
+ EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
+ return -1;
+ }
+ /* can't have both telemetry and no-telemetry */
+ if (args.no_telemetry && args.telemetry) {
+ EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
+ return -1;
+ }
+ /* can't have both -m and --socket-mem */
+ if (args.memory_size != NULL && args.numa_mem != NULL) {
+ EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ return -1;
+ }
+
+ /* parse options */
+ /* print version before anything else */
+ if (args.version) {
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
+ }
+
+ /* parse the process type */
+ if (args.proc_type != NULL) {
+ int_cfg->process_type = eal_parse_proc_type(args.proc_type);
+ if (int_cfg->process_type == RTE_PROC_INVALID) {
+ EAL_LOG(ERR, "invalid process type: %s", args.proc_type);
return -1;
- b_used = 1;
- break;
+ }
+ }
- case 'a':
- if (b_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, optarg) < 0)
+ /* device -a/-b/-vdev options*/
+ TAILQ_FOREACH(arg, &args.allow, next)
+ if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, arg->arg) < 0)
return -1;
- a_used = 1;
- break;
- /* coremask */
- case 'c': {
+ TAILQ_FOREACH(arg, &args.block, next)
+ if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, arg->arg) < 0)
+ return -1;
+ TAILQ_FOREACH(arg, &args.vdev, next)
+ if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, arg->arg) < 0)
+ return -1;
+ /* driver loading options */
+ TAILQ_FOREACH(arg, &args.driver_path, next)
+ if (eal_plugin_add(arg->arg) < 0)
+ return -1;
+
+ /* parse the coremask /core-list */
+ if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -c is before -s or -S");
- if (rte_eal_parse_coremask(optarg, lcore_indexes) < 0) {
+ if (rte_eal_parse_coremask(args.coremask, lcore_indexes) < 0) {
EAL_LOG(ERR, "invalid coremask syntax");
return -1;
}
if (update_lcore_config(lcore_indexes) < 0) {
char *available = available_cores();
- EAL_LOG(ERR,
- "invalid coremask, please check specified cores are part of %s",
- available);
+ EAL_LOG(ERR, "invalid coremask '%s', please check specified cores are part of %s",
+ args.coremask, available);
free(available);
return -1;
}
-
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_MSK)
- EAL_LOG(ERR, "Option '-c' passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option -c is ignored, because option -l/--lcores used");
+ core_parsed = 1;
+ } else if (args.lcores != NULL) {
+ if (eal_parse_lcores(args.lcores) < 0) {
+ EAL_LOG(ERR, "invalid lcore list: '%s'", args.lcores);
return -1;
}
-
- core_parsed = LCORE_OPT_MSK;
- break;
+ core_parsed = 1;
}
- /* corelist */
- case 'l': {
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -l is before -s or -S");
-
- if (eal_parse_lcores(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for -l/--" OPT_LCORES);
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0) {
+ EAL_LOG(ERR, "invalid main-lcore parameter");
return -1;
}
+ }
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_LST)
- EAL_LOG(ERR, "Core list option passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option '-l/--lcores' is ignored, because coremask option used");
+ /* service core options */
+ if (args.service_coremask != NULL) {
+ if (eal_parse_service_coremask(args.service_coremask) < 0) {
+ EAL_LOG(ERR, "invalid service coremask: '%s'",
+ args.service_coremask);
return -1;
}
+ } else if (args.service_corelist != NULL) {
+ if (eal_parse_service_corelist(args.service_corelist) < 0) {
+ EAL_LOG(ERR, "invalid service core list: '%s'",
+ args.service_corelist);
+ return -1;
+ }
+ }
- core_parsed = LCORE_OPT_LST;
- break;
+ /* memory options */
+ if (args.memory_size != NULL) {
+ int_cfg->memory = atoi(args.memory_size);
+ int_cfg->memory *= 1024ULL;
+ int_cfg->memory *= 1024ULL;
}
- /* service coremask */
- case 's':
- if (eal_parse_service_coremask(optarg) < 0) {
- EAL_LOG(ERR, "invalid service coremask");
+ if (args.memory_channels != NULL) {
+ int_cfg->force_nchannel = atoi(args.memory_channels);
+ if (int_cfg->force_nchannel == 0) {
+ EAL_LOG(ERR, "invalid memory channel parameter");
return -1;
}
- break;
- /* service corelist */
- case 'S':
- if (eal_parse_service_corelist(optarg) < 0) {
- EAL_LOG(ERR, "invalid service core list");
+ }
+ if (args.memory_ranks != NULL) {
+ int_cfg->force_nrank = atoi(args.memory_ranks);
+ if (int_cfg->force_nrank == 0 || int_cfg->force_nrank > 16) {
+ EAL_LOG(ERR, "invalid memory rank parameter");
return -1;
}
- break;
- /* size of memory */
- case 'm':
- conf->memory = atoi(optarg);
- conf->memory *= 1024ULL;
- conf->memory *= 1024ULL;
- mem_parsed = 1;
- break;
- /* force number of channels */
- case 'n':
- conf->force_nchannel = atoi(optarg);
- if (conf->force_nchannel == 0) {
- EAL_LOG(ERR, "invalid channel number");
+ }
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
return -1;
}
- break;
- /* force number of ranks */
- case 'r':
- conf->force_nrank = atoi(optarg);
- if (conf->force_nrank == 0 ||
- conf->force_nrank > 16) {
- EAL_LOG(ERR, "invalid rank number");
+ }
+ if (args.no_huge) {
+ int_cfg->no_hugetlbfs = 1;
+ /* no-huge is legacy mem */
+ int_cfg->legacy_mem = 1;
+ }
+ if (args.in_memory) {
+ int_cfg->in_memory = 1;
+ /* in-memory is a superset of noshconf and huge-unlink */
+ int_cfg->no_shconf = 1;
+ int_cfg->hugepage_file.unlink_before_mapping = true;
+ }
+ if (args.legacy_mem)
+ int_cfg->legacy_mem = 1;
+ if (args.single_file_segments)
+ int_cfg->single_file_segments = 1;
+ if (args.huge_dir != NULL) {
+ free(int_cfg->hugepage_dir); /* free old hugepage dir */
+ int_cfg->hugepage_dir = strdup(args.huge_dir);
+ if (int_cfg->hugepage_dir == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for hugepage dir parameter");
return -1;
}
- break;
- /* force loading of external driver */
- case 'd':
- if (eal_plugin_add(optarg) == -1)
+ }
+ if (args.file_prefix != NULL) {
+ free(int_cfg->hugefile_prefix); /* free old file prefix */
+ int_cfg->hugefile_prefix = strdup(args.file_prefix);
+ if (int_cfg->hugefile_prefix == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for file prefix parameter");
return -1;
- break;
- case 'v':
- /* since message is explicitly requested by user, we
- * write message at highest log level so it can always
- * be seen
- * even if info or warning messages are disabled */
- EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- break;
-
- /* long options */
- case OPT_HUGE_UNLINK_NUM:
- if (eal_parse_huge_unlink(optarg, &conf->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid --"OPT_HUGE_UNLINK" option");
+ }
+ }
+ if (args.numa_mem != NULL) {
+ if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
+ EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
return -1;
}
- break;
-
- case OPT_NO_HUGE_NUM:
- conf->no_hugetlbfs = 1;
- /* no-huge is legacy mem */
- conf->legacy_mem = 1;
- break;
-
- case OPT_NO_PCI_NUM:
- conf->no_pci = 1;
- break;
-
- case OPT_NO_HPET_NUM:
- conf->no_hpet = 1;
- break;
-
- case OPT_VMWARE_TSC_MAP_NUM:
- conf->vmware_tsc_map = 1;
- break;
-
- case OPT_NO_SHCONF_NUM:
- conf->no_shconf = 1;
- break;
-
- case OPT_IN_MEMORY_NUM:
- conf->in_memory = 1;
- /* in-memory is a superset of noshconf and huge-unlink */
- conf->no_shconf = 1;
- conf->hugepage_file.unlink_before_mapping = true;
- break;
-
- case OPT_PROC_TYPE_NUM:
- conf->process_type = eal_parse_proc_type(optarg);
- break;
-
- case OPT_MAIN_LCORE_NUM:
- if (eal_parse_main_lcore(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_MAIN_LCORE);
+ int_cfg->force_numa = 1;
+ }
+ if (args.numa_limit != NULL) {
+ if (eal_parse_socket_arg(args.numa_limit, int_cfg->numa_limit) < 0) {
+ EAL_LOG(ERR, "invalid numa-limit parameter: '%s'", args.numa_limit);
return -1;
}
- break;
+ int_cfg->force_numa_limits = 1;
+ }
- case OPT_VDEV_NUM:
- if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
- optarg) < 0) {
+ /* tracing settings, not supported on windows */
+#ifdef RTE_EXEC_ENV_WINDOWS
+ if (args.trace != NULL ||
+ args.trace_dir != NULL ||
+ args.trace_bufsz != NULL ||
+ args.trace_mode != NULL)
+ EAL_LOG(WARNING, "Tracing is not supported on Windows, ignoring tracing parameters");
+#else
+ if (args.trace != NULL) {
+ if (eal_trace_args_save(args.trace) < 0) {
+ EAL_LOG(ERR, "invalid trace parameter, '%s'", args.trace);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_SYSLOG_NUM:
- if (eal_log_syslog(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_SYSLOG);
+ }
+ if (args.trace_dir != NULL) {
+ if (eal_trace_dir_args_save(args.trace_dir) < 0) {
+ EAL_LOG(ERR, "invalid trace directory, '%s'", args.trace_dir);
return -1;
}
- break;
-#endif
-
- case OPT_LOG_LEVEL_NUM:
- if (eal_parse_log_level(optarg) < 0) {
- EAL_LOG(ERR,
- "invalid parameters for --"
- OPT_LOG_LEVEL);
+ }
+ if (args.trace_bufsz != NULL) {
+ if (eal_trace_bufsz_args_save(args.trace_bufsz) < 0) {
+ EAL_LOG(ERR, "invalid trace buffer size, '%s'", args.trace_bufsz);
return -1;
}
- break;
-
- case OPT_LOG_TIMESTAMP_NUM:
- if (eal_log_timestamp(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_TIMESTAMP);
+ }
+ if (args.trace_mode != NULL) {
+ if (eal_trace_mode_args_save(args.trace_mode) < 0) {
+ EAL_LOG(ERR, "invalid trace mode, '%s'", args.trace_mode);
return -1;
}
- break;
+ }
+#endif
- case OPT_LOG_COLOR_NUM:
- if (eal_log_color(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_COLOR);
+ /* simple flag settings
+ * Only set these to 1, as we don't want to set them to 0 in case
+ * other options above have already set them.
+ */
+ if (args.no_pci)
+ int_cfg->no_pci = 1;
+ if (args.no_hpet)
+ int_cfg->no_hpet = 1;
+ if (args.vmware_tsc_map)
+ int_cfg->vmware_tsc_map = 1;
+ if (args.no_shconf)
+ int_cfg->no_shconf = 1;
+ if (args.no_telemetry)
+ int_cfg->no_telemetry = 1;
+ if (args.match_allocations)
+ int_cfg->match_allocations = 1;
+ if (args.create_uio_dev)
+ int_cfg->create_uio_dev = 1;
+
+
+ /* other misc settings */
+ if (args.iova_mode != NULL) {
+ if (eal_parse_iova_mode(args.iova_mode) < 0) {
+ EAL_LOG(ERR, "invalid iova mode parameter '%s'", args.iova_mode);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_TRACE_NUM: {
- if (eal_trace_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE);
+ };
+ if (args.base_virtaddr != NULL) {
+ if (eal_parse_base_virtaddr(args.base_virtaddr) < 0) {
+ EAL_LOG(ERR, "invalid base virtaddr '%s'", args.base_virtaddr);
return -1;
}
- break;
}
-
- case OPT_TRACE_DIR_NUM: {
- if (eal_trace_dir_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_DIR);
+ if (args.force_max_simd_bitwidth != NULL) {
+ if (eal_parse_simd_bitwidth(args.force_max_simd_bitwidth) < 0) {
+ EAL_LOG(ERR, "invalid SIMD bitwidth parameter '%s'",
+ args.force_max_simd_bitwidth);
return -1;
}
- break;
}
-
- case OPT_TRACE_BUF_SIZE_NUM: {
- if (eal_trace_bufsz_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_BUF_SIZE);
+ if (args.vfio_intr != NULL) {
+ if (eal_parse_vfio_intr(args.vfio_intr) < 0) {
+ EAL_LOG(ERR, "invalid vfio interrupt parameter: '%s'", args.vfio_intr);
return -1;
}
- break;
}
-
- case OPT_TRACE_MODE_NUM: {
- if (eal_trace_mode_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_MODE);
+ if (args.vfio_vf_token != NULL) {
+ if (eal_parse_vfio_vf_token(args.vfio_vf_token) < 0) {
+ EAL_LOG(ERR, "invalid vfio vf token parameter: '%s'", args.vfio_vf_token);
return -1;
}
- break;
}
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- case OPT_LEGACY_MEM_NUM:
- conf->legacy_mem = 1;
- break;
- case OPT_SINGLE_FILE_SEGMENTS_NUM:
- conf->single_file_segments = 1;
- break;
- case OPT_IOVA_MODE_NUM:
- if (eal_parse_iova_mode(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_IOVA_MODE);
+ if (args.huge_worker_stack != NULL) {
+ if (args.huge_worker_stack == (void *)1)
+ args.huge_worker_stack = NULL;
+ if (eal_parse_huge_worker_stack(args.huge_worker_stack) < 0) {
+ EAL_LOG(ERR, "invalid huge worker stack parameter");
return -1;
}
- break;
- case OPT_BASE_VIRTADDR_NUM:
- if (eal_parse_base_virtaddr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_BASE_VIRTADDR);
+ }
+ if (args.mbuf_pool_ops_name != NULL) {
+ free(int_cfg->user_mbuf_pool_ops_name); /* free old ops name */
+ int_cfg->user_mbuf_pool_ops_name = strdup(args.mbuf_pool_ops_name);
+ if (int_cfg->user_mbuf_pool_ops_name == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
- break;
- case OPT_TELEMETRY_NUM:
- break;
- case OPT_NO_TELEMETRY_NUM:
- conf->no_telemetry = 1;
- break;
- case OPT_FORCE_MAX_SIMD_BITWIDTH_NUM:
- if (eal_parse_simd_bitwidth(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_FORCE_MAX_SIMD_BITWIDTH);
+ }
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+ /* create runtime data directory. In no_shconf mode, skip any errors */
+ if (eal_create_runtime_dir() < 0) {
+ if (int_cfg->no_shconf == 0) {
+ EAL_LOG(ERR, "Cannot create runtime directory");
return -1;
}
- break;
+ EAL_LOG(WARNING, "No DPDK runtime directory created");
+ }
+#endif
- /* don't know what to do, leave this to caller */
- default:
- return 1;
+ if (eal_adjust_config(int_cfg) != 0) {
+ EAL_LOG(ERR, "Invalid configuration");
+ return -1;
+ }
+ if (eal_check_common_options(int_cfg) != 0) {
+ EAL_LOG(ERR, "Checking common options failed");
+ return -1;
}
return 0;
-
-ba_conflict:
- EAL_LOG(ERR,
- "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
}
static void
@@ -2239,13 +2307,8 @@ eal_check_common_options(struct internal_config *internal_cfg)
"option");
return -1;
}
- if (mem_parsed && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Options -m and --"OPT_NUMA_MEM" cannot "
- "be specified at the same time");
- return -1;
- }
if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_MEM" cannot "
+ EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
"be specified together with --"OPT_NO_HUGE);
return -1;
}
@@ -2331,97 +2394,3 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth)
internal_conf->max_simd_bitwidth.bitwidth = bitwidth;
return 0;
}
-
-void
-eal_common_usage(void)
-{
- printf("[options]\n\n"
- "EAL common options:\n"
- " -c COREMASK Hexadecimal bitmask of cores to run on\n"
- " -l, --"OPT_LCORES" CORELIST\n"
- " List of cores to run on\n"
- " The basic argument format is <c1>[-c2][,c3[-c4],...]\n"
- " where c1, c2, etc are core indexes between 0 and %d\n"
- " Can also be used to map lcore set to physical CPU set\n"
- " The argument format is\n"
- " '<lcores[@cpus]>[<,lcores[@cpus]>...]'\n"
- " lcores and cpus list are grouped by '(' and ')'\n"
- " Within the group, '-' is used for range separator,\n"
- " ',' is used for single number separator.\n"
- " '( )' can be omitted for single element group,\n"
- " '@' can be omitted if cpus and lcores have the same value\n"
- " -s SERVICE COREMASK Hexadecimal bitmask of cores to be used as service cores\n"
- " --"OPT_MAIN_LCORE" ID Core ID that is used as main\n"
- " --"OPT_MBUF_POOL_OPS_NAME" Pool ops name for mbuf to use\n"
- " -n CHANNELS Number of memory channels\n"
- " -m MB Memory to allocate (see also --"OPT_NUMA_MEM")\n"
- " -r RANKS Force number of memory ranks (don't detect)\n"
- " -b, --block Add a device to the blocked list.\n"
- " Prevent EAL from using this device. The argument\n"
- " format for PCI devices is <domain:bus:devid.func>.\n"
- " -a, --allow Add a device to the allow list.\n"
- " Only use the specified devices. The argument format\n"
- " for PCI devices is <[domain:]bus:devid.func>.\n"
- " This option can be present several times.\n"
- " [NOTE: " OPT_DEV_ALLOW " cannot be used with "OPT_DEV_BLOCK" option]\n"
- " --"OPT_VDEV" Add a virtual device.\n"
- " The argument format is <driver><id>[,key=val,...]\n"
- " (ex: --vdev=net_pcap0,iface=eth2).\n"
- " --"OPT_IOVA_MODE" Set IOVA mode. 'pa' for IOVA_PA\n"
- " 'va' for IOVA_VA\n"
- " -d LIB.so|DIR Add a driver or driver directory\n"
- " (can be used multiple times)\n"
- " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n"
- " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_SYSLOG"[=<facility>] Enable use of syslog (and optionally set facility)\n"
-#endif
- " --"OPT_LOG_LEVEL"=<level> Set global log level\n"
- " --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
- " Set specific log level\n"
- " --"OPT_LOG_LEVEL"=help Show log types and levels\n"
- " --"OPT_LOG_TIMESTAMP"[=<format>] Timestamp log output\n"
- " --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_TRACE"=<regex-match>\n"
- " Enable trace based on regular expression trace name.\n"
- " By default, the trace is disabled.\n"
- " User must specify this option to enable trace.\n"
- " --"OPT_TRACE_DIR"=<directory path>\n"
- " Specify trace directory for trace output.\n"
- " By default, trace output will created at\n"
- " $HOME directory and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_BUF_SIZE"=<int>\n"
- " Specify maximum size of allocated memory\n"
- " for trace output for each thread. Valid\n"
- " unit can be either 'B|K|M' for 'Bytes',\n"
- " 'KBytes' and 'MBytes' respectively.\n"
- " Default is 1MB and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_MODE"=<o[verwrite] | d[iscard]>\n"
- " Specify the mode of update of trace\n"
- " output file. Either update on a file can\n"
- " be wrapped or discarded when file size\n"
- " reaches its maximum limit.\n"
- " Default mode is 'overwrite' and parameter\n"
- " must be specified once only.\n"
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- " -v Display version information on startup\n"
- " -h, --"OPT_HELP" This help\n"
- " --"OPT_IN_MEMORY" Operate entirely in memory. This will\n"
- " disable secondary process support\n"
- " --"OPT_BASE_VIRTADDR" Base virtual address\n"
- " --"OPT_TELEMETRY" Enable telemetry support (on by default)\n"
- " --"OPT_NO_TELEMETRY" Disable telemetry support\n"
- " --"OPT_FORCE_MAX_SIMD_BITWIDTH" Force the max SIMD bitwidth\n"
- "\nEAL options for DEBUG use only:\n"
- " --"OPT_HUGE_UNLINK"[=existing|always|never]\n"
- " When to unlink files in hugetlbfs\n"
- " ('existing' by default, no value means 'always')\n"
- " --"OPT_NO_HUGE" Use malloc instead of hugetlbfs\n"
- " --"OPT_NO_PCI" Disable PCI\n"
- " --"OPT_NO_HPET" Disable HPET\n"
- " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n"
- "\n", RTE_MAX_LCORE);
-}
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 6ef45559f0..c4d2cc84dc 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -115,18 +115,12 @@ enum {
OPT_LONG_MAX_NUM
};
-extern const char eal_short_options[];
-extern const struct option eal_long_options[];
-
-bool eal_option_is_log(int opt);
-int eal_parse_log_options(int argc, char * const argv[]);
-int eal_parse_common_option(int opt, const char *argv,
- struct internal_config *conf);
+int eal_parse_log_options(void);
+int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
int eal_check_common_options(struct internal_config *internal_cfg);
-void eal_common_usage(void);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index 5846917cc5..ab8b37b956 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -72,6 +72,17 @@ struct rte_config {
*/
struct rte_config *rte_eal_get_configuration(void);
+/**
+ * Put the argument list into a structure.
+ *
+ * This allows the arguments to then be processed out-of-order.
+ *
+ * @return
+ * - 0 on success
+ * - Negative on error
+ */
+int eal_collate_args(int argc, char **argv);
+
/**
* Initialize the memzone subsystem (private to eal).
*
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index c1ab8d86d2..ee8bf92bff 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -160,7 +160,7 @@ rte_eal_config_create(void)
cfg_len_aligned, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, mem_cfg_fd, 0);
if (mapped_mem_cfg_addr == MAP_FAILED) {
- EAL_LOG(ERR, "Cannot remap memory for rte_config");
+ EAL_LOG(ERR, "Cannot remap memory for rte_config: %s", strerror(errno));
munmap(rte_mem_cfg_addr, cfg_len);
close(mem_cfg_fd);
mem_cfg_fd = -1;
@@ -245,11 +245,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
- /* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option",
- rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
@@ -332,21 +329,6 @@ rte_config_init(void)
return 0;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
static inline size_t
eal_get_hugepage_mem_size(void)
{
@@ -367,123 +349,6 @@ eal_get_hugepage_mem_size(void)
return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX;
}
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_optreset = optreset;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
- optreset = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on FreeBSD", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on FreeBSD",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on FreeBSD", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optreset = old_optreset;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -553,8 +418,18 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* Save and collate args at the top */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("invalid command-line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -585,18 +460,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
@@ -605,8 +476,7 @@ rte_eal_init(int argc, char **argv)
/* FreeBSD always uses legacy memory model */
internal_conf->legacy_mem = true;
if (internal_conf->in_memory) {
- EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '%s'",
- OPT_IN_MEMORY);
+ EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '--in-memory'");
internal_conf->in_memory = false;
}
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 52efb8626b..f59cb43b0e 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -59,9 +59,6 @@
#include "log_internal.h"
#define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
-
-#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
-
#define KERNEL_IOMMU_GROUPS_PATH "/sys/kernel/iommu_groups"
/* define fd variable here, because file needs to be kept open for the
@@ -438,362 +435,6 @@ eal_hugedirs_unlock(void)
}
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- printf("EAL Linux options:\n"
- " --"OPT_NUMA_MEM" Memory to allocate on NUMA nodes (comma separated values)\n"
- " --"OPT_NUMA_LIMIT" Limit memory allocation on NUMA nodes (comma separated values)\n"
- " --"OPT_HUGE_DIR" Directory where hugetlbfs is mounted\n"
- " --"OPT_FILE_PREFIX" Prefix for hugepage filenames\n"
- " --"OPT_CREATE_UIO_DEV" Create /dev/uioX (usually done by hotplug)\n"
- " --"OPT_VFIO_INTR" Interrupt mode for VFIO (legacy|msi|msix)\n"
- " --"OPT_VFIO_VF_TOKEN" VF token (UUID) shared between SR-IOV PF and VFs\n"
- " --"OPT_LEGACY_MEM" Legacy memory mode (no dynamic allocation, contiguous segments)\n"
- " --"OPT_SINGLE_FILE_SEGMENTS" Put all hugepage memory in single files\n"
- " --"OPT_MATCH_ALLOCATIONS" Free hugepages exactly as allocated\n"
- " --"OPT_HUGE_WORKER_STACK"[=size]\n"
- " Allocate worker thread stacks from hugepage memory.\n"
- " Size is in units of kbytes and defaults to system\n"
- " thread stack size if not specified.\n"
- "\n");
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-static int
-eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
-{
- char * arg[RTE_MAX_NUMA_NODES];
- char *end;
- int arg_num, i, len;
-
- len = strnlen(strval, SOCKET_MEM_STRLEN);
- if (len == SOCKET_MEM_STRLEN) {
- EAL_LOG(ERR, "--socket-mem is too long");
- return -1;
- }
-
- /* all other error cases will be caught later */
- if (!isdigit(strval[len-1]))
- return -1;
-
- /* split the optarg into separate socket values */
- arg_num = rte_strsplit(strval, len,
- arg, RTE_MAX_NUMA_NODES, ',');
-
- /* if split failed, or 0 arguments */
- if (arg_num <= 0)
- return -1;
-
- /* parse each defined socket option */
- errno = 0;
- for (i = 0; i < arg_num; i++) {
- uint64_t val;
- end = NULL;
- val = strtoull(arg[i], &end, 10);
-
- /* check for invalid input */
- if ((errno != 0) ||
- (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
- return -1;
- val <<= 20;
- socket_arg[i] = val;
- }
-
- return 0;
-}
-
-static int
-eal_parse_vfio_intr(const char *mode)
-{
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
- unsigned i;
- static struct {
- const char *name;
- enum rte_intr_mode value;
- } map[] = {
- { "legacy", RTE_INTR_MODE_LEGACY },
- { "msi", RTE_INTR_MODE_MSI },
- { "msix", RTE_INTR_MODE_MSIX },
- };
-
- for (i = 0; i < RTE_DIM(map); i++) {
- if (!strcmp(mode, map[i].name)) {
- internal_conf->vfio_intr_mode = map[i].value;
- return 0;
- }
- }
- return -1;
-}
-
-static int
-eal_parse_vfio_vf_token(const char *vf_token)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
- rte_uuid_t uuid;
-
- if (!rte_uuid_parse(vf_token, uuid)) {
- rte_uuid_copy(cfg->vfio_vf_token, uuid);
- return 0;
- }
-
- return -1;
-}
-
-static int
-eal_parse_huge_worker_stack(const char *arg)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
-
- if (arg == NULL || arg[0] == '\0') {
- pthread_attr_t attr;
- int ret;
-
- if (pthread_attr_init(&attr) != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
- pthread_attr_destroy(&attr);
- if (ret != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- } else {
- unsigned long stack_size;
- char *end;
-
- errno = 0;
- stack_size = strtoul(arg, &end, 10);
- if (errno || end == NULL || stack_size == 0 ||
- stack_size >= (size_t)-1 / 1024)
- return -1;
-
- cfg->huge_worker_stack_size = stack_size * 1024;
- }
-
- EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
- cfg->huge_worker_stack_size / 1024);
- return 0;
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
-
- case OPT_HUGE_DIR_NUM:
- {
- char *hdir = strdup(optarg);
- if (hdir == NULL)
- EAL_LOG(ERR, "Could not store hugepage directory");
- else {
- /* free old hugepage dir */
- free(internal_conf->hugepage_dir);
- internal_conf->hugepage_dir = hdir;
- }
- break;
- }
- case OPT_FILE_PREFIX_NUM:
- {
- char *prefix = strdup(optarg);
- if (prefix == NULL)
- EAL_LOG(ERR, "Could not store file prefix");
- else {
- /* free old prefix */
- free(internal_conf->hugefile_prefix);
- internal_conf->hugefile_prefix = prefix;
- }
- break;
- }
- case OPT_NUMA_MEM_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_mem) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_MEM
- " (aka --"
- OPT_SOCKET_MEM
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa = 1;
- break;
-
- case OPT_NUMA_LIMIT_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_limit) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_LIMIT
- " (aka --"
- OPT_SOCKET_LIMIT
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa_limits = 1;
- break;
-
- case OPT_VFIO_INTR_NUM:
- if (eal_parse_vfio_intr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_INTR);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_VFIO_VF_TOKEN_NUM:
- if (eal_parse_vfio_vf_token(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_VF_TOKEN);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_CREATE_UIO_DEV_NUM:
- internal_conf->create_uio_dev = 1;
- break;
-
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_MATCH_ALLOCATIONS_NUM:
- internal_conf->match_allocations = 1;
- break;
-
- case OPT_HUGE_WORKER_STACK_NUM:
- if (eal_parse_huge_worker_stack(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_HUGE_WORKER_STACK);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Linux", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Linux",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Linux", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -938,8 +579,18 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -970,18 +621,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 4f0a164d9b..14547d5ac9 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -82,99 +82,6 @@ rte_mp_disable(void)
return true;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too
- * if hook is set
- */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- int ret;
-
- /* getopt is not happy, stop right now */
- if (opt == '?') {
- eal_usage(prgname);
- return -1;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- return -1;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Windows", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Windows",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Windows", opt);
- }
- eal_usage(prgname);
- return -1;
- }
- }
-
- if (eal_adjust_config(internal_conf) != 0)
- return -1;
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- return -1;
- }
-
- if (optind >= 0)
- argv[optind - 1] = prgname;
- ret = optind - 1;
- optind = 0; /* reset getopt lib */
- return ret;
-}
-
static int
sync_func(void *arg __rte_unused)
{
@@ -260,8 +167,18 @@ rte_eal_init(int argc, char **argv)
char cpuset[RTE_CPU_AFFINITY_STR_LEN];
char thread_name[RTE_THREAD_NAME_SIZE];
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -288,9 +205,11 @@ rte_eal_init(int argc, char **argv)
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0)
- exit(1);
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
if (eal_option_device_parse()) {
rte_errno = ENODEV;
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 7/9] eal: ensure proper cleanup on EAL init failure
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
` (5 preceding siblings ...)
2025-07-18 14:33 ` [PATCH v3 6/9] eal: gather EAL args before processing Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 8/9] eal: combine parameter validation checks Bruce Richardson
` (2 subsequent siblings)
9 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk
When rte_eal_init fails part way through, any saved EAL arguments need
to be freed, and the run_once flag needs to be set back to zero again.
The former task was never done on failure, and the latter was only done
on some occasions. Rework the error handling to always go to an err_out
label where cleanup is done.
To prevent memory leaks from the saved arguments when eal_init is called
twice, the check for multiple calls must be done first before the
argument saving and parsing is done.
This patch modifies all three eal.c files. Windows doesn't actually need
changes, since there are no args saved, and no run_once sentinel value,
but updating it keeps it consistent with FreeBSD and Linux versions.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
NOTE: this patch can probably be squashed in with the changes in the
previous one, but for easier review I've kept it separate for now.
---
lib/eal/common/eal_common_options.c | 37 ++++++++----
lib/eal/common/eal_options.h | 1 +
lib/eal/freebsd/eal.c | 83 +++++++++++++-------------
lib/eal/linux/eal.c | 90 ++++++++++++++---------------
lib/eal/windows/eal.c | 47 ++++++++-------
5 files changed, 137 insertions(+), 121 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index eecb8eba3a..646f47f886 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -357,6 +357,8 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
int
eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+void
+eal_clean_saved_args(void) { /* no-op */ }
#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
@@ -388,6 +390,28 @@ handle_eal_info_request(const char *cmd, const char *params __rte_unused,
return used;
}
+void
+eal_clean_saved_args(void)
+{
+ int i;
+
+ if (eal_args == NULL)
+ return;
+
+ if (eal_app_args != NULL) {
+ i = 0;
+ while (eal_app_args[i] != NULL)
+ free(eal_app_args[i++]);
+ free(eal_app_args);
+ eal_app_args = NULL;
+ }
+ i = 0;
+ while (eal_args[i] != NULL)
+ free(eal_args[i++]);
+ free(eal_args);
+ eal_args = NULL;
+}
+
int
eal_save_args(int argc, char **argv)
{
@@ -432,18 +456,7 @@ eal_save_args(int argc, char **argv)
return 0;
error:
- if (eal_app_args != NULL) {
- i = 0;
- while (eal_app_args[i] != NULL)
- free(eal_app_args[i++]);
- free(eal_app_args);
- eal_app_args = NULL;
- }
- i = 0;
- while (eal_args[i] != NULL)
- free(eal_args[i++]);
- free(eal_args);
- eal_args = NULL;
+ eal_clean_saved_args();
return -1;
}
#endif /* !RTE_EXEC_ENV_WINDOWS */
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index c4d2cc84dc..fd28111e73 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -124,6 +124,7 @@ int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
+void eal_clean_saved_args(void);
int handle_eal_info_request(const char *cmd, const char *params __rte_unused,
struct rte_tel_data *d);
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index ee8bf92bff..2882d218f6 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -418,6 +418,14 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* first check if we have been run before */
+ if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
+ rte_memory_order_relaxed, rte_memory_order_relaxed)) {
+ rte_eal_init_alert("already called initialization.");
+ rte_errno = EALREADY;
+ return -1;
+ }
+
/* Save and collate args at the top */
eal_save_args(argc, argv);
@@ -425,14 +433,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("invalid command-line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(getprogname());
@@ -441,21 +449,14 @@ rte_eal_init(int argc, char **argv)
if (!rte_cpu_is_supported()) {
rte_eal_init_alert("unsupported cpu type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
- }
-
- if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
- rte_memory_order_relaxed, rte_memory_order_relaxed)) {
- rte_eal_init_alert("already called initialization.");
- rte_errno = EALREADY;
- return -1;
+ goto err_out;
}
eal_reset_internal_config(internal_conf);
@@ -463,14 +464,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
/* FreeBSD always uses legacy memory model */
@@ -483,37 +483,34 @@ rte_eal_init(int argc, char **argv)
if (eal_plugins_init() < 0) {
rte_eal_init_alert("Cannot init plugins");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_trace_init() < 0) {
rte_eal_init_alert("Cannot init trace");
rte_errno = EFAULT;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (rte_config_init() < 0) {
rte_eal_init_alert("Cannot init config");
- return -1;
+ goto err_out;
}
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_alarm_init() < 0) {
rte_eal_init_alert("Cannot init alarm");
/* rte_eal_alarm_init sets rte_errno on failure. */
- return -1;
+ goto err_out;
}
/* Put mp channel init before bus scan so that we can init the vdev
@@ -523,15 +520,14 @@ rte_eal_init(int argc, char **argv)
rte_eal_init_alert("failed to init mp channel");
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
}
if (rte_bus_scan()) {
rte_eal_init_alert("Cannot scan the buses for devices");
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
/*
@@ -562,13 +558,13 @@ rte_eal_init(int argc, char **argv)
if (iova_mode == RTE_IOVA_PA && !has_phys_addr) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (iova_mode == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
rte_eal_get_configuration()->iova_mode = iova_mode;
@@ -583,8 +579,7 @@ rte_eal_init(int argc, char **argv)
if (ret < 0) {
rte_eal_init_alert("Cannot get hugepage information.");
rte_errno = EACCES;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
}
@@ -613,7 +608,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -622,14 +617,14 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
if (rte_eal_malloc_heap_init() < 0) {
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -637,19 +632,19 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init HPET or TSC timers");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -660,7 +655,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -713,14 +708,14 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/* Probe all the buses and devices/drivers on them */
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* initialize default service/lcore mappings and start running. Ignore
@@ -729,7 +724,7 @@ rte_eal_init(int argc, char **argv)
ret = rte_service_start_with_defaults();
if (ret < 0 && ret != -ENOTSUP) {
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/*
@@ -744,18 +739,22 @@ rte_eal_init(int argc, char **argv)
*/
if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
rte_eal_init_alert("Cannot clear runtime directory");
- return -1;
+ goto err_out;
}
if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
if (rte_telemetry_init(rte_eal_get_runtime_dir(),
rte_version(),
&internal_conf->ctrl_cpuset) != 0)
- return -1;
+ goto err_out;
}
eal_mcfg_complete();
return fctret;
+err_out:
+ rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
+ eal_clean_saved_args();
+ return -1;
}
RTE_EXPORT_SYMBOL(rte_eal_cleanup)
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index f59cb43b0e..210d461497 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -579,6 +579,14 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* first check if we have been run before */
+ if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
+ rte_memory_order_relaxed, rte_memory_order_relaxed)) {
+ rte_eal_init_alert("already called initialization.");
+ rte_errno = EALREADY;
+ return -1;
+ }
+
/* clone argv to report out later in telemetry */
eal_save_args(argc, argv);
@@ -586,14 +594,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(program_invocation_short_name);
@@ -602,21 +610,14 @@ rte_eal_init(int argc, char **argv)
if (!rte_cpu_is_supported()) {
rte_eal_init_alert("unsupported cpu type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
- }
-
- if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
- rte_memory_order_relaxed, rte_memory_order_relaxed)) {
- rte_eal_init_alert("already called initialization.");
- rte_errno = EALREADY;
- return -1;
+ goto err_out;
}
eal_reset_internal_config(internal_conf);
@@ -624,49 +625,46 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
- rte_eal_init_alert("Invalid command line arguments.");
+ rte_eal_init_alert("Error parsing command line arguments.");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_plugins_init() < 0) {
rte_eal_init_alert("Cannot init plugins");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_trace_init() < 0) {
rte_eal_init_alert("Cannot init trace");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (rte_config_init() < 0) {
rte_eal_init_alert("Cannot init config");
- return -1;
+ goto err_out;
}
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_alarm_init() < 0) {
rte_eal_init_alert("Cannot init alarm");
/* rte_eal_alarm_init sets rte_errno on failure. */
- return -1;
+ goto err_out;
}
/* Put mp channel init before bus scan so that we can init the vdev
@@ -676,15 +674,14 @@ rte_eal_init(int argc, char **argv)
rte_eal_init_alert("failed to init mp channel");
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
}
if (rte_bus_scan()) {
rte_eal_init_alert("Cannot scan the buses for devices");
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
phys_addrs = rte_eal_using_phys_addrs() != 0;
@@ -727,13 +724,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_iova_mode() == RTE_IOVA_PA && !phys_addrs) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (rte_eal_iova_mode() == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
EAL_LOG(INFO, "Selected IOVA mode '%s'",
@@ -747,8 +744,7 @@ rte_eal_init(int argc, char **argv)
if (ret < 0) {
rte_eal_init_alert("Cannot get hugepage information.");
rte_errno = EACCES;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
}
@@ -772,8 +768,7 @@ rte_eal_init(int argc, char **argv)
if (rte_vfio_enable("vfio")) {
rte_eal_init_alert("Cannot init VFIO");
rte_errno = EAGAIN;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
#endif
/* in secondary processes, memory init may allocate additional fbarrays
@@ -783,7 +778,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -792,7 +787,7 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
/* the directories are locked during eal_hugepage_info_init */
@@ -802,7 +797,7 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -810,25 +805,25 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
/* register multi-process action callbacks for hotplug after memory init */
if (eal_mp_dev_hotplug_init() < 0) {
rte_eal_init_alert("failed to register mp callback for hotplug");
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init HPET or TSC timers");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -839,7 +834,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -890,14 +885,14 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/* Probe all the buses and devices/drivers on them */
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* initialize default service/lcore mappings and start running. Ignore
@@ -906,7 +901,7 @@ rte_eal_init(int argc, char **argv)
ret = rte_service_start_with_defaults();
if (ret < 0 && ret != -ENOTSUP) {
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/*
@@ -921,18 +916,23 @@ rte_eal_init(int argc, char **argv)
*/
if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
rte_eal_init_alert("Cannot clear runtime directory");
- return -1;
+ goto err_out;
}
if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
if (rte_telemetry_init(rte_eal_get_runtime_dir(),
rte_version(),
&internal_conf->ctrl_cpuset) != 0)
- return -1;
+ goto err_out;
}
eal_mcfg_complete();
return fctret;
+
+err_out:
+ rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
+ eal_clean_saved_args();
+ return -1;
}
static int
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 14547d5ac9..cd9a72a0fc 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -174,14 +174,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(NULL);
@@ -189,31 +189,31 @@ rte_eal_init(int argc, char **argv)
if (eal_create_cpu_map() < 0) {
rte_eal_init_alert("Cannot discover CPU and NUMA.");
/* rte_errno is set */
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("Unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
/* Prevent creation of shared memory files. */
@@ -227,7 +227,7 @@ rte_eal_init(int argc, char **argv)
if (!internal_conf->no_hugetlbfs && (eal_hugepage_info_init() < 0)) {
rte_eal_init_alert("Cannot get hugepage information");
rte_errno = EACCES;
- return -1;
+ goto err_out;
}
if (internal_conf->memory == 0 && !internal_conf->force_numa) {
@@ -237,26 +237,26 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init TSC timer");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
bscan = rte_bus_scan();
if (bscan < 0) {
rte_eal_init_alert("Cannot scan the buses");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (eal_mem_win32api_init() < 0) {
rte_eal_init_alert("Cannot access Win32 memory management");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
has_phys_addr = true;
@@ -289,13 +289,13 @@ rte_eal_init(int argc, char **argv)
if (iova_mode == RTE_IOVA_PA && !has_phys_addr) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (iova_mode == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
EAL_LOG(DEBUG, "Selected IOVA mode '%s'",
@@ -305,7 +305,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -314,14 +314,14 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
if (rte_eal_malloc_heap_init() < 0) {
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -329,13 +329,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -344,7 +344,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -390,13 +390,13 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/*
@@ -409,6 +409,9 @@ rte_eal_init(int argc, char **argv)
eal_mcfg_complete();
return fctret;
+err_out:
+ eal_clean_saved_args();
+ return -1;
}
/* Don't use MinGW asprintf() to have identical code with all toolchains. */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 8/9] eal: combine parameter validation checks
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
` (6 preceding siblings ...)
2025-07-18 14:33 ` [PATCH v3 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
2025-07-18 14:41 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
9 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Anatoly Burakov, Tyler Retzlaff
Remove the separate function to check combinations of cmdline
parameters. Instead, just do those checks when parsing the parameters
since we have all info about what parameters are provided at that point.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 262 +++++++++++-----------------
lib/eal/common/eal_options.h | 107 ------------
lib/eal/linux/eal.c | 5 +-
lib/eal/linux/eal_memory.c | 2 +-
5 files changed, 106 insertions(+), 273 deletions(-)
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 38ccc734e8..c62edf5e55 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -258,8 +258,7 @@ eal_memseg_list_alloc(struct rte_memseg_list *msl, int reserve_flags)
* including common code, so don't duplicate the message.
*/
if (rte_errno == EADDRNOTAVAIL)
- EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - "
- "please use '--" OPT_BASE_VIRTADDR "' option",
+ EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - please use '--base-virtaddr' option",
(unsigned long long)mem_sz, msl->base_va);
#endif
return -1;
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 646f47f886..5daf56d1aa 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -329,7 +329,6 @@ struct device_option {
static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
-static int main_lcore_parsed;
static int core_parsed;
/* Returns rte_usage_hook_t */
@@ -837,15 +836,6 @@ eal_parse_service_coremask(const char *coremask)
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE;
j++, idx++) {
if ((1 << j) & val) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (main_lcore_parsed &&
- cfg->main_lcore == lcore) {
- EAL_LOG(ERR,
- "lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (eal_cpu_detected(idx) == 0) {
EAL_LOG(ERR,
@@ -1068,15 +1058,6 @@ eal_parse_service_corelist(const char *corelist)
min = idx;
for (idx = min; idx <= max; idx++) {
if (cfg->lcore_role[idx] != ROLE_SERVICE) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (cfg->main_lcore == lcore &&
- main_lcore_parsed) {
- EAL_LOG(ERR,
- "Error: lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (cfg->lcore_role[idx] == ROLE_RTE)
taken_lcore_count++;
@@ -1116,12 +1097,15 @@ eal_parse_main_lcore(const char *arg)
return -1;
if (cfg->main_lcore >= RTE_MAX_LCORE)
return -1;
- main_lcore_parsed = 1;
/* ensure main core is not used as service core */
if (lcore_config[cfg->main_lcore].core_role == ROLE_SERVICE) {
- EAL_LOG(ERR,
- "Error: Main lcore is used as a service core");
+ EAL_LOG(ERR, "Error: Main lcore is used as a service core");
+ return -1;
+ }
+ /* check that we have the core recorded in the core list */
+ if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
+ EAL_LOG(ERR, "Error: Main lcore is not enabled for DPDK");
return -1;
}
@@ -1416,11 +1400,11 @@ eal_log_usage(void)
rte_log_list_types(stdout, "\t");
printf("\n");
printf("Syntax using globbing pattern: ");
- printf("--"OPT_LOG_LEVEL" pattern:level\n");
+ printf("--log-level pattern:level\n");
printf("Syntax using regular expression: ");
- printf("--"OPT_LOG_LEVEL" regexp,level\n");
+ printf("--log-level regexp,level\n");
printf("Syntax for the global level: ");
- printf("--"OPT_LOG_LEVEL" level\n");
+ printf("--log-level level\n");
printf("Logs are emitted if allowed by both global and specific levels.\n");
printf("\n");
printf("Log level can be a number or the first letters of its name:\n");
@@ -1700,7 +1684,7 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return 0;
}
if (strcmp(arg, HUGE_UNLINK_NEVER) == 0) {
- EAL_LOG(WARNING, "Using --"OPT_HUGE_UNLINK"="
+ EAL_LOG(WARNING, "Using --huge-unlink="
HUGE_UNLINK_NEVER" may create data leaks.");
out->unlink_existing = false;
return 0;
@@ -1879,6 +1863,7 @@ int
eal_parse_args(void)
{
struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
/* check for conflicting options */
@@ -1904,19 +1889,62 @@ eal_parse_args(void)
}
/* can't have both -m and --socket-mem */
if (args.memory_size != NULL && args.numa_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ EAL_LOG(ERR, "Options -m and --numa-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use both no-huge and socket-mem */
+ if (args.no_huge && args.numa_mem) {
+ EAL_LOG(ERR, "Options --no-huge and --numa-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-worker-stack */
+ if (args.huge_worker_stack != NULL && args.no_huge) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
+ return -1;
+ }
+ /* can't use socket-limit and legacy-mem */
+ if (args.numa_limit != NULL && args.legacy_mem) {
+ EAL_LOG(ERR, "Options --numa-limit and --legacy-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and in-memory */
+ if (args.legacy_mem && args.in_memory) {
+ EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and match-allocations */
+ if (args.legacy_mem && args.match_allocations) {
+ EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and match-allocations */
+ if (args.no_huge && args.match_allocations) {
+ EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-unlink */
+ if (args.no_huge && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use single-file-segments and huge-unlink */
+ if (args.single_file_segments && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use in-memory and huge-unlink */
+ if (args.in_memory && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
return -1;
}
- /* parse options */
/* print version before anything else */
- if (args.version) {
- /* since message is explicitly requested by user, we write message
- * at highest log level so it can always be seen even if info or
- * warning messages are disabled
- */
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ if (args.version)
EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- }
/* parse the process type */
if (args.proc_type != NULL) {
@@ -1942,7 +1970,7 @@ eal_parse_args(void)
if (eal_plugin_add(arg->arg) < 0)
return -1;
- /* parse the coremask /core-list */
+ /* parse the core list arguments */
if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
@@ -1966,13 +1994,6 @@ eal_parse_args(void)
}
core_parsed = 1;
}
- if (args.main_lcore != NULL) {
- if (eal_parse_main_lcore(args.main_lcore) < 0) {
- EAL_LOG(ERR, "invalid main-lcore parameter");
- return -1;
- }
- }
-
/* service core options */
if (args.service_coremask != NULL) {
if (eal_parse_service_coremask(args.service_coremask) < 0) {
@@ -1987,6 +2008,17 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0)
+ return -1;
+ } else {
+ /* default main lcore is the first one */
+ rte_cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
+ if (rte_cfg->main_lcore >= RTE_MAX_LCORE) {
+ EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
+ return -1;
+ }
+ }
/* memory options */
if (args.memory_size != NULL) {
@@ -2008,14 +2040,6 @@ eal_parse_args(void)
return -1;
}
}
- if (args.huge_unlink != NULL) {
- if (args.huge_unlink == (void *)1)
- args.huge_unlink = NULL;
- if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid huge-unlink parameter");
- return -1;
- }
- }
if (args.no_huge) {
int_cfg->no_hugetlbfs = 1;
/* no-huge is legacy mem */
@@ -2027,11 +2051,18 @@ eal_parse_args(void)
int_cfg->no_shconf = 1;
int_cfg->hugepage_file.unlink_before_mapping = true;
}
- if (args.legacy_mem)
+ if (args.legacy_mem) {
int_cfg->legacy_mem = 1;
+ if (args.memory_size == NULL && args.numa_mem == NULL)
+ EAL_LOG(NOTICE, "Static memory layout is selected, amount of reserved memory can be adjusted with -m or --socket-mem");
+ }
if (args.single_file_segments)
int_cfg->single_file_segments = 1;
if (args.huge_dir != NULL) {
+ if (strlen(args.huge_dir) < 1) {
+ EAL_LOG(ERR, "Invalid hugepage dir parameter");
+ return -1;
+ }
free(int_cfg->hugepage_dir); /* free old hugepage dir */
int_cfg->hugepage_dir = strdup(args.huge_dir);
if (int_cfg->hugepage_dir == NULL) {
@@ -2040,6 +2071,14 @@ eal_parse_args(void)
}
}
if (args.file_prefix != NULL) {
+ if (strlen(args.file_prefix) < 1) {
+ EAL_LOG(ERR, "Invalid file prefix parameter");
+ return -1;
+ }
+ if (strchr(args.file_prefix, '%') != NULL) {
+ EAL_LOG(ERR, "Invalid char, '%%', in file_prefix parameter");
+ return -1;
+ }
free(int_cfg->hugefile_prefix); /* free old file prefix */
int_cfg->hugefile_prefix = strdup(args.file_prefix);
if (int_cfg->hugefile_prefix == NULL) {
@@ -2047,6 +2086,14 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
+ return -1;
+ }
+ }
if (args.numa_mem != NULL) {
if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
@@ -2164,6 +2211,10 @@ eal_parse_args(void)
EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
+ if (strlen(int_cfg->user_mbuf_pool_ops_name) < 1) {
+ EAL_LOG(ERR, "Invalid mbuf pool ops name parameter");
+ return -1;
+ }
}
#ifndef RTE_EXEC_ENV_WINDOWS
@@ -2182,11 +2233,6 @@ eal_parse_args(void)
return -1;
}
- if (eal_check_common_options(int_cfg) != 0) {
- EAL_LOG(ERR, "Checking common options failed");
- return -1;
- }
-
return 0;
}
@@ -2266,14 +2312,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
if (internal_conf->process_type == RTE_PROC_AUTO)
internal_conf->process_type = eal_proc_type_detect();
- /* default main lcore is the first one */
- if (!main_lcore_parsed) {
- cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
- if (cfg->main_lcore >= RTE_MAX_LCORE)
- return -1;
- lcore_config[cfg->main_lcore].core_role = ROLE_RTE;
- }
-
compute_ctrl_threads_cpuset(internal_cfg);
/* if no memory amounts were requested, this will result in 0 and
@@ -2284,102 +2322,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
return 0;
}
-int
-eal_check_common_options(struct internal_config *internal_cfg)
-{
- struct rte_config *cfg = rte_eal_get_configuration();
- const struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
- EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
- return -1;
- }
-
- if (internal_cfg->process_type == RTE_PROC_INVALID) {
- EAL_LOG(ERR, "Invalid process type specified");
- return -1;
- }
- if (internal_cfg->hugefile_prefix != NULL &&
- strlen(internal_cfg->hugefile_prefix) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_FILE_PREFIX " option");
- return -1;
- }
- if (internal_cfg->hugepage_dir != NULL &&
- strlen(internal_cfg->hugepage_dir) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_HUGE_DIR" option");
- return -1;
- }
- if (internal_cfg->user_mbuf_pool_ops_name != NULL &&
- strlen(internal_cfg->user_mbuf_pool_ops_name) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_MBUF_POOL_OPS_NAME" option");
- return -1;
- }
- if (strchr(eal_get_hugefile_prefix(), '%') != NULL) {
- EAL_LOG(ERR, "Invalid char, '%%', in --"OPT_FILE_PREFIX" "
- "option");
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_UNLINK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->huge_worker_stack_size != 0) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_WORKER_STACK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_conf->force_numa_limits && internal_conf->legacy_mem) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_LIMIT
- " is only supported in non-legacy memory mode");
- }
- if (internal_cfg->single_file_segments &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
- "not compatible with --"OPT_HUGE_UNLINK);
- return -1;
- }
- if (!internal_cfg->hugepage_file.unlink_existing &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_IN_MEMORY" is not compatible "
- "with --"OPT_HUGE_UNLINK"="HUGE_UNLINK_NEVER);
- return -1;
- }
- if (internal_cfg->legacy_mem &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_IN_MEMORY);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_NO_HUGE" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->memory == 0) {
- EAL_LOG(NOTICE, "Static memory layout is selected, "
- "amount of reserved memory can be adjusted with "
- "-m or --"OPT_NUMA_MEM);
- }
-
- return 0;
-}
-
RTE_EXPORT_SYMBOL(rte_vect_get_max_simd_bitwidth)
uint16_t
rte_vect_get_max_simd_bitwidth(void)
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index fd28111e73..4a8a0f1df7 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -9,118 +9,11 @@
struct rte_tel_data;
-enum {
- /* long options mapped to a short option */
-#define OPT_HELP "help"
- OPT_HELP_NUM = 'h',
-#define OPT_DEV_ALLOW "allow"
- OPT_DEV_ALLOW_NUM = 'a',
-#define OPT_DEV_BLOCK "block"
- OPT_DEV_BLOCK_NUM = 'b',
-#define OPT_COREMASK "coremask"
- OPT_COREMASK_NUM = 'c',
-#define OPT_DRIVER_PATH "driver-path"
- OPT_DRIVER_PATH_NUM = 'd',
-#define OPT_LCORES "lcores"
- OPT_LCORES_NUM = 'l',
-#define OPT_MEMORY_SIZE "memory-size"
- OPT_MEMORY_SIZE_NUM = 'm',
-#define OPT_MEMORY_CHANNELS "memory-channels"
- OPT_MEMORY_CHANNELS_NUM = 'n',
-#define OPT_MEMORY_RANKS "memory-ranks"
- OPT_MEMORY_RANKS_NUM = 'r',
-#define OPT_SERVICE_COREMASK "service-coremask"
- OPT_SERVICE_COREMASK_NUM = 's',
-#define OPT_SERVICE_CORELIST "service-corelist"
- OPT_SERVICE_CORELIST_NUM = 'S',
-#define OPT_VERSION "version"
- OPT_VERSION_NUM = 'v',
-
- /* first long only option value must be >= 256, so that we won't
- * conflict with short options */
- OPT_LONG_MIN_NUM = 256,
-#define OPT_BASE_VIRTADDR "base-virtaddr"
- OPT_BASE_VIRTADDR_NUM,
-#define OPT_CREATE_UIO_DEV "create-uio-dev"
- OPT_CREATE_UIO_DEV_NUM,
-#define OPT_FILE_PREFIX "file-prefix"
- OPT_FILE_PREFIX_NUM,
-#define OPT_HUGE_DIR "huge-dir"
- OPT_HUGE_DIR_NUM,
-#define OPT_HUGE_UNLINK "huge-unlink"
- OPT_HUGE_UNLINK_NUM,
-#define OPT_LOG_COLOR "log-color"
- OPT_LOG_COLOR_NUM,
-#define OPT_LOG_LEVEL "log-level"
- OPT_LOG_LEVEL_NUM,
-#define OPT_LOG_TIMESTAMP "log-timestamp"
- OPT_LOG_TIMESTAMP_NUM,
-#define OPT_TRACE "trace"
- OPT_TRACE_NUM,
-#define OPT_TRACE_DIR "trace-dir"
- OPT_TRACE_DIR_NUM,
-#define OPT_TRACE_BUF_SIZE "trace-bufsz"
- OPT_TRACE_BUF_SIZE_NUM,
-#define OPT_TRACE_MODE "trace-mode"
- OPT_TRACE_MODE_NUM,
-#define OPT_MAIN_LCORE "main-lcore"
- OPT_MAIN_LCORE_NUM,
-#define OPT_MBUF_POOL_OPS_NAME "mbuf-pool-ops-name"
- OPT_MBUF_POOL_OPS_NAME_NUM,
-#define OPT_PROC_TYPE "proc-type"
- OPT_PROC_TYPE_NUM,
-#define OPT_NO_HPET "no-hpet"
- OPT_NO_HPET_NUM,
-#define OPT_NO_HUGE "no-huge"
- OPT_NO_HUGE_NUM,
-#define OPT_NO_PCI "no-pci"
- OPT_NO_PCI_NUM,
-#define OPT_NO_SHCONF "no-shconf"
- OPT_NO_SHCONF_NUM,
-#define OPT_IN_MEMORY "in-memory"
- OPT_IN_MEMORY_NUM,
-#define OPT_SOCKET_MEM "socket-mem"
-#define OPT_NUMA_MEM "numa-mem"
- OPT_NUMA_MEM_NUM,
-#define OPT_SOCKET_LIMIT "socket-limit"
-#define OPT_NUMA_LIMIT "numa-limit"
- OPT_NUMA_LIMIT_NUM,
-#define OPT_SYSLOG "syslog"
- OPT_SYSLOG_NUM,
-#define OPT_VDEV "vdev"
- OPT_VDEV_NUM,
-#define OPT_VFIO_INTR "vfio-intr"
- OPT_VFIO_INTR_NUM,
-#define OPT_VFIO_VF_TOKEN "vfio-vf-token"
- OPT_VFIO_VF_TOKEN_NUM,
-#define OPT_VMWARE_TSC_MAP "vmware-tsc-map"
- OPT_VMWARE_TSC_MAP_NUM,
-#define OPT_LEGACY_MEM "legacy-mem"
- OPT_LEGACY_MEM_NUM,
-#define OPT_SINGLE_FILE_SEGMENTS "single-file-segments"
- OPT_SINGLE_FILE_SEGMENTS_NUM,
-#define OPT_IOVA_MODE "iova-mode"
- OPT_IOVA_MODE_NUM,
-#define OPT_MATCH_ALLOCATIONS "match-allocations"
- OPT_MATCH_ALLOCATIONS_NUM,
-#define OPT_TELEMETRY "telemetry"
- OPT_TELEMETRY_NUM,
-#define OPT_NO_TELEMETRY "no-telemetry"
- OPT_NO_TELEMETRY_NUM,
-#define OPT_FORCE_MAX_SIMD_BITWIDTH "force-max-simd-bitwidth"
- OPT_FORCE_MAX_SIMD_BITWIDTH_NUM,
-#define OPT_HUGE_WORKER_STACK "huge-worker-stack"
- OPT_HUGE_WORKER_STACK_NUM,
-
- OPT_LONG_MAX_NUM
-};
-
int eal_parse_log_options(void);
int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
-int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 210d461497..babd36bf37 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -329,9 +329,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
/* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option", rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index e433c1afee..a366083822 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -1967,7 +1967,7 @@ rte_eal_memseg_init(void)
if (!internal_conf->legacy_mem && rte_socket_count() > 1) {
EAL_LOG(WARNING, "DPDK is running on a NUMA system, but is compiled without NUMA support.");
EAL_LOG(WARNING, "This will have adverse consequences for performance and usability.");
- EAL_LOG(WARNING, "Please use --"OPT_LEGACY_MEM" option, or recompile with NUMA support.");
+ EAL_LOG(WARNING, "Please use --legacy-mem option, or recompile with NUMA support.");
}
#endif
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v3 9/9] eal: simplify handling of conflicting cmdline options
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
` (7 preceding siblings ...)
2025-07-18 14:33 ` [PATCH v3 8/9] eal: combine parameter validation checks Bruce Richardson
@ 2025-07-18 14:33 ` Bruce Richardson
2025-07-18 14:41 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
9 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:33 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
Use a utility function and macro to simplify the code for checking for
conflicting cmdline options. The checking can also be done at the
initial argument collating stage, shortening the argument
processing function which is very much on the long side.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 119 +++++++++++-----------------
1 file changed, 47 insertions(+), 72 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 5daf56d1aa..787f759196 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -264,6 +264,29 @@ struct rte_argparse eal_argparse = {
}
};
+static inline bool
+conflicting_options(uintptr_t opt1, uintptr_t opt2, const char *opt1_name, const char *opt2_name)
+{
+ char name1[64]; /* should be the max length of any argument */
+ char name2[64];
+
+ strlcpy(name1, opt1_name, sizeof(name1));
+ strlcpy(name2, opt2_name, sizeof(name2));
+ for (int i = 0; name1[i] != '\0'; i++)
+ if (name1[i] == '_')
+ name1[i] = '-';
+ for (int i = 0; name2[i] != '\0'; i++)
+ if (name2[i] == '_')
+ name2[i] = '-';
+ if (opt1 && opt2) {
+ EAL_LOG(ERR, "Options '%s' and '%s' can't be used at the same time", name1, name2);
+ return true;
+ }
+ return false; /* no conflicts */
+}
+#define CONFLICTING_OPTIONS(args, opt1, opt2) \
+ conflicting_options((uintptr_t)(args.opt1), (uintptr_t)(args.opt2), #opt1, #opt2)
+
/* function to call into argparse library to parse the passed argc/argv parameters
* to the eal_init_args structure.
*/
@@ -286,6 +309,30 @@ eal_collate_args(int argc, char **argv)
if (retval < 0)
return retval;
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+
+ /* for non-list args, we can just check for zero/null values using macro */
+ if (CONFLICTING_OPTIONS(args, coremask, lcores) ||
+ CONFLICTING_OPTIONS(args, service_coremask, service_corelist) ||
+ CONFLICTING_OPTIONS(args, no_telemetry, telemetry) ||
+ CONFLICTING_OPTIONS(args, memory_size, numa_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, numa_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_worker_stack) ||
+ CONFLICTING_OPTIONS(args, numa_limit, legacy_mem) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, in_memory) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, single_file_segments, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, no_huge, single_file_segments) ||
+ CONFLICTING_OPTIONS(args, in_memory, huge_unlink))
+ return -1;
+
argv[retval - 1] = argv[0];
return retval - 1;
}
@@ -1866,78 +1913,6 @@ eal_parse_args(void)
struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
- /* check for conflicting options */
- /* both -a and -b cannot be used together (one list must be empty at least) */
- if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
- EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
- }
- /* both -l and -c cannot be used at the same time */
- if (args.coremask != NULL && args.lcores != NULL) {
- EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
- return -1;
- }
- /* both -s and -S cannot be used at the same time */
- if (args.service_coremask != NULL && args.service_corelist != NULL) {
- EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
- return -1;
- }
- /* can't have both telemetry and no-telemetry */
- if (args.no_telemetry && args.telemetry) {
- EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
- return -1;
- }
- /* can't have both -m and --socket-mem */
- if (args.memory_size != NULL && args.numa_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --numa-mem can't be used at the same time");
- return -1;
- }
- /* can't use both no-huge and socket-mem */
- if (args.no_huge && args.numa_mem) {
- EAL_LOG(ERR, "Options --no-huge and --numa-mem can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-worker-stack */
- if (args.huge_worker_stack != NULL && args.no_huge) {
- EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
- return -1;
- }
- /* can't use socket-limit and legacy-mem */
- if (args.numa_limit != NULL && args.legacy_mem) {
- EAL_LOG(ERR, "Options --numa-limit and --legacy-mem can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and in-memory */
- if (args.legacy_mem && args.in_memory) {
- EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and match-allocations */
- if (args.legacy_mem && args.match_allocations) {
- EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and match-allocations */
- if (args.no_huge && args.match_allocations) {
- EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-unlink */
- if (args.no_huge && args.huge_unlink) {
- EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use single-file-segments and huge-unlink */
- if (args.single_file_segments && args.huge_unlink) {
- EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use in-memory and huge-unlink */
- if (args.in_memory && args.huge_unlink) {
- EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
- return -1;
- }
-
/* print version before anything else */
/* since message is explicitly requested by user, we write message
* at highest log level so it can always be seen even if info or
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v3 0/9] rework EAL argument parsing
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
` (8 preceding siblings ...)
2025-07-18 14:33 ` [PATCH v3 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
@ 2025-07-18 14:41 ` Bruce Richardson
9 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-18 14:41 UTC (permalink / raw)
To: dev; +Cc: david.marchand
On Fri, Jul 18, 2025 at 03:33:46PM +0100, Bruce Richardson wrote:
> When processing cmdline arguments in DPDK, we always do so with very
> little context. So, for example, when processing the "-l" flag, we have
> no idea whether there will be later a --proc-type=secondary flag. We
> have all sorts of post-arg-processing checks in place to try and catch
> these scenarios.
>
> To improve this situation, this patchset tries to simplify the handling
> of argument processing, by explicitly doing an initial pass to collate
> all arguments into a structure. Thereafter, the actual arg parsing is
> done in a fixed order, meaning that e.g. when processing the
> --main-lcore flag, we have already processed the service core flags. We
> also can far quicker and easier check for conflicting options, since
> they can all be checked for NULL/non-NULL in the arg structure
> immediately after the struct has been populated.
>
> To do the initial argument gathering, this RFC uses the existing
> argparse library in DPDK. With recent changes, and two additional
> patches at the start of this set, this library now meets our needs for
> EAL argument parsing and allows us to not need to do direct getopt
> argument processing inside EAL at all.
>
> An additional benefit of this work, is that the argument parsing for EAL
> is much more centralised into common options. This single list with
> ifdefs makes it clear to the viewer what options are common across OS's,
> vs what are unix-only or linux-only.
>
Apologies, forgot the diff from the RFC v2:
* Added 3 new initial patches, one for minor build-system addition, and two
for functionality in argparse to allow the user-callback help function to
be maintained as we move to argparse.
* Added doc updates in the first EAL patch adding the long options
* Fixed ASAN issues by adding a patch to properly clean up EAL init - both
memory allocations and fixing the run-once flag
* Put ifdefs around the linux-only or unix-only options in EAL patch 2
* Updated args to handle numa-mem and numa-limit as equivalent socket-mem
and socket-limit
>
> Bruce Richardson (9):
> build: add define for the OS environment name
> argparse: export function to print help text for object
> argparse: allow user-override of help printing
> eal: add long options for each short option
> eal: define the EAL parameters in argparse format
> eal: gather EAL args before processing
> eal: ensure proper cleanup on EAL init failure
> eal: combine parameter validation checks
> eal: simplify handling of conflicting cmdline options
>
> config/meson.build | 1 +
> doc/guides/contributing/design.rst | 2 +-
> doc/guides/linux_gsg/eal_args.include.rst | 20 +-
> doc/guides/prog_guide/argparse_lib.rst | 16 +
> lib/argparse/rte_argparse.c | 46 +-
> lib/argparse/rte_argparse.h | 21 +-
> lib/eal/common/eal_common_memory.c | 3 +-
> lib/eal/common/eal_common_options.c | 1299 +++++++++++----------
> lib/eal/common/eal_options.h | 102 +-
> lib/eal/common/eal_private.h | 11 +
> lib/eal/freebsd/eal.c | 245 +---
> lib/eal/linux/eal.c | 470 +-------
> lib/eal/linux/eal_memory.c | 2 +-
> lib/eal/meson.build | 2 +-
> lib/eal/windows/eal.c | 156 +--
> lib/meson.build | 1 +
> 16 files changed, 954 insertions(+), 1443 deletions(-)
>
> --
> 2.48.1
>
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v3 5/9] eal: define the EAL parameters in argparse format
2025-07-18 14:33 ` [PATCH v3 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
@ 2025-07-21 8:41 ` David Marchand
2025-07-21 9:05 ` Bruce Richardson
0 siblings, 1 reply; 67+ messages in thread
From: David Marchand @ 2025-07-21 8:41 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev, Tyler Retzlaff, Thomas Monjalon
On Fri, Jul 18, 2025 at 4:34 PM Bruce Richardson
<bruce.richardson@intel.com> wrote:
> +struct eal_init_args {
> + /* define a struct member for each EAL option, member name is the same as option name.
> + * Parameters that take an argument e.g. -l, are char *,
> + * parameters that take no options e.g. --no-huge, are bool.
> + * parameters that can be given multiple times e.g. -a, are arg_lists,
> + * parameters that are optional e.g. --huge-unlink,
> + * are char * but are set to (void *)1 if the parameter is not given.
> + * NOTE: List is to be kept alphabetically by option name
> + */
We will have to be careful to keep this struct below, in sync with the
options list.
Could we construct (at build time) this structure via the options list?
The rules above would be enforced at the same time.
(macros + #ifdef for Linux/FreeBSD may be an issue for MSVC though...)
> + struct arg_list allow;
> + char *base_virtaddr;
> + struct arg_list block;
> + char *coremask;
> + bool create_uio_dev;
> + struct arg_list driver_path;
> + char *file_prefix;
> + char *force_max_simd_bitwidth;
> + char *huge_dir;
> + char *huge_unlink; /* parameter optional */
> + char *huge_worker_stack; /* parameter optional */
> + bool in_memory;
> + char *iova_mode;
> + char *lcores;
> + bool legacy_mem;
> + char *log_color; /* parameter optional */
> + char *log_level;
> + char *log_timestamp; /* parameter optional */
> + char *main_lcore;
> + bool match_allocations;
> + char *mbuf_pool_ops_name;
> + char *memory_channels;
> + char *memory_ranks;
> + char *memory_size;
> + bool no_hpet;
> + bool no_huge;
> + bool no_pci;
> + bool no_shconf;
> + bool no_telemetry;
> + char *numa_mem;
> + char *numa_limit;
> + char *proc_type;
> + char *service_coremask;
> + char *service_corelist;
> + bool single_file_segments;
> + char *syslog; /* parameter optional */
> + bool telemetry;
> + char *trace;
> + char *trace_bufsz;
> + char *trace_dir;
> + char *trace_mode;
> + struct arg_list vdev;
> + bool version;
> + char *vfio_intr;
> + char *vfio_vf_token;
> + bool vmware_tsc_map;
> +};
> +struct eal_init_args args;
> +
[snip]
> +
> +struct rte_argparse eal_argparse = {
> + .prog_name = "",
> + .usage = "<DPDK EAL options>",
> + .epilog = "For more information on EAL options, see the DPDK documentation at: \n"
> + "\thttps://doc.dpdk.org/guides/" RTE_EXEC_ENV_NAME "_gsg/",
Options don't change that often, but I would prefer we point at the
right release doc, rather than origin/main.
diff --git a/config/meson.build b/config/meson.build
index 40f33816aa..c3c054bae9 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -70,6 +70,7 @@ abi_version = run_command(find_program('cat',
'more'), abi_version_file,
so_version = abi_version.split('.')[0]
# extract all version information into the build configuration
+dpdk_conf.set('RTE_VER_MAJOR', major_version)
dpdk_conf.set('RTE_VER_YEAR', pver.get(0).to_int())
dpdk_conf.set('RTE_VER_MONTH', pver.get(1).to_int())
if pver.get(2).contains('-rc')
diff --git a/lib/eal/common/eal_common_options.c
b/lib/eal/common/eal_common_options.c
index 787f759196..e11d76589f 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -196,7 +196,11 @@ struct rte_argparse eal_argparse = {
.prog_name = "",
.usage = "<DPDK EAL options>",
.epilog = "For more information on EAL options, see the DPDK
documentation at: \n"
+#ifdef RTE_VER_RELEASE == 99
+
"\thttps://doc.dpdk.org/guides-"RTE_STR(RTE_VER_MAJOR)"/"
RTE_EXEC_ENV_NAME "_gsg/",
+#else
"\thttps://doc.dpdk.org/guides/"
RTE_EXEC_ENV_NAME "_gsg/",
+#endif
.exit_on_error = true,
.callback = arg_list_callback,
.print_help = eal_usage,
--
David Marchand
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v3 3/9] argparse: allow user-override of help printing
2025-07-18 14:33 ` [PATCH v3 3/9] argparse: allow user-override of help printing Bruce Richardson
@ 2025-07-21 8:43 ` David Marchand
2025-07-21 9:00 ` Bruce Richardson
0 siblings, 1 reply; 67+ messages in thread
From: David Marchand @ 2025-07-21 8:43 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev, Chengwen Feng
On Fri, Jul 18, 2025 at 4:34 PM Bruce Richardson
<bruce.richardson@intel.com> wrote:
> diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
> index d3b32c6357..e7b9bf573d 100644
> --- a/lib/argparse/rte_argparse.c
> +++ b/lib/argparse/rte_argparse.c
> @@ -821,7 +821,10 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
> goto error;
>
> if (show_help) {
> - rte_argparse_print_help(stdout, obj);
> + if (obj->print_help != NULL)
> + obj->print_help(obj);
Should we pass a stream to the callback?
> + else
> + rte_argparse_print_help(stdout, obj);
> exit(0);
> }
>
--
David Marchand
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v3 3/9] argparse: allow user-override of help printing
2025-07-21 8:43 ` David Marchand
@ 2025-07-21 9:00 ` Bruce Richardson
0 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 9:00 UTC (permalink / raw)
To: David Marchand; +Cc: dev, Chengwen Feng
On Mon, Jul 21, 2025 at 10:43:05AM +0200, David Marchand wrote:
> On Fri, Jul 18, 2025 at 4:34 PM Bruce Richardson
> <bruce.richardson@intel.com> wrote:
> > diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
> > index d3b32c6357..e7b9bf573d 100644
> > --- a/lib/argparse/rte_argparse.c
> > +++ b/lib/argparse/rte_argparse.c
> > @@ -821,7 +821,10 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
> > goto error;
> >
> > if (show_help) {
> > - rte_argparse_print_help(stdout, obj);
> > + if (obj->print_help != NULL)
> > + obj->print_help(obj);
>
> Should we pass a stream to the callback?
>
I briefly thought about it, but I don't see the point. The callback can
print to stdout by default if it wants anyway, or stderr (or any other file
handle) if preferred by the user. Adding a filehandle would make the calls
consistent, but not any actual value.
/Bruce
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v3 5/9] eal: define the EAL parameters in argparse format
2025-07-21 8:41 ` David Marchand
@ 2025-07-21 9:05 ` Bruce Richardson
2025-07-21 12:53 ` Bruce Richardson
0 siblings, 1 reply; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 9:05 UTC (permalink / raw)
To: David Marchand; +Cc: dev, Tyler Retzlaff, Thomas Monjalon
On Mon, Jul 21, 2025 at 10:41:33AM +0200, David Marchand wrote:
> On Fri, Jul 18, 2025 at 4:34 PM Bruce Richardson
> <bruce.richardson@intel.com> wrote:
> > +struct eal_init_args {
> > + /* define a struct member for each EAL option, member name is the same as option name.
> > + * Parameters that take an argument e.g. -l, are char *,
> > + * parameters that take no options e.g. --no-huge, are bool.
> > + * parameters that can be given multiple times e.g. -a, are arg_lists,
> > + * parameters that are optional e.g. --huge-unlink,
> > + * are char * but are set to (void *)1 if the parameter is not given.
> > + * NOTE: List is to be kept alphabetically by option name
> > + */
>
> We will have to be careful to keep this struct below, in sync with the
> options list.
> Could we construct (at build time) this structure via the options list?
>
> The rules above would be enforced at the same time.
>
> (macros + #ifdef for Linux/FreeBSD may be an issue for MSVC though...)
>
I wonder how much an issue keeping them in sync would actually be? When
adding a new option to the options list, it takes a reference to the struct
field, meaning that we can't forget to add an entry here when adding the
option. If we add here but forget to add to the options list, then obvious
the option just doesn't get parsed so testing quickly would show up the
issue.
I suppose the main concern would be around renaming or deleting options -
though in the latter case having an extra stray element in the struct isn't
a big deal.
I might have a shot at auto-generating the struct, but I'm not convinced
the complexity will be worth the benefit.
/Bruce
> > + struct arg_list allow;
> > + char *base_virtaddr;
> > + struct arg_list block;
> > + char *coremask;
> > + bool create_uio_dev;
> > + struct arg_list driver_path;
> > + char *file_prefix;
> > + char *force_max_simd_bitwidth;
> > + char *huge_dir;
> > + char *huge_unlink; /* parameter optional */
> > + char *huge_worker_stack; /* parameter optional */
> > + bool in_memory;
> > + char *iova_mode;
> > + char *lcores;
> > + bool legacy_mem;
> > + char *log_color; /* parameter optional */
> > + char *log_level;
> > + char *log_timestamp; /* parameter optional */
> > + char *main_lcore;
> > + bool match_allocations;
> > + char *mbuf_pool_ops_name;
> > + char *memory_channels;
> > + char *memory_ranks;
> > + char *memory_size;
> > + bool no_hpet;
> > + bool no_huge;
> > + bool no_pci;
> > + bool no_shconf;
> > + bool no_telemetry;
> > + char *numa_mem;
> > + char *numa_limit;
> > + char *proc_type;
> > + char *service_coremask;
> > + char *service_corelist;
> > + bool single_file_segments;
> > + char *syslog; /* parameter optional */
> > + bool telemetry;
> > + char *trace;
> > + char *trace_bufsz;
> > + char *trace_dir;
> > + char *trace_mode;
> > + struct arg_list vdev;
> > + bool version;
> > + char *vfio_intr;
> > + char *vfio_vf_token;
> > + bool vmware_tsc_map;
> > +};
> > +struct eal_init_args args;
> > +
>
> [snip]
>
> > +
> > +struct rte_argparse eal_argparse = {
> > + .prog_name = "",
> > + .usage = "<DPDK EAL options>",
> > + .epilog = "For more information on EAL options, see the DPDK documentation at: \n"
> > + "\thttps://doc.dpdk.org/guides/" RTE_EXEC_ENV_NAME "_gsg/",
>
> Options don't change that often, but I would prefer we point at the
> right release doc, rather than origin/main.
>
> diff --git a/config/meson.build b/config/meson.build
> index 40f33816aa..c3c054bae9 100644
> --- a/config/meson.build
> +++ b/config/meson.build
> @@ -70,6 +70,7 @@ abi_version = run_command(find_program('cat',
> 'more'), abi_version_file,
> so_version = abi_version.split('.')[0]
>
> # extract all version information into the build configuration
> +dpdk_conf.set('RTE_VER_MAJOR', major_version)
> dpdk_conf.set('RTE_VER_YEAR', pver.get(0).to_int())
> dpdk_conf.set('RTE_VER_MONTH', pver.get(1).to_int())
> if pver.get(2).contains('-rc')
> diff --git a/lib/eal/common/eal_common_options.c
> b/lib/eal/common/eal_common_options.c
> index 787f759196..e11d76589f 100644
> --- a/lib/eal/common/eal_common_options.c
> +++ b/lib/eal/common/eal_common_options.c
> @@ -196,7 +196,11 @@ struct rte_argparse eal_argparse = {
> .prog_name = "",
> .usage = "<DPDK EAL options>",
> .epilog = "For more information on EAL options, see the DPDK
> documentation at: \n"
> +#ifdef RTE_VER_RELEASE == 99
> +
> "\thttps://doc.dpdk.org/guides-"RTE_STR(RTE_VER_MAJOR)"/"
> RTE_EXEC_ENV_NAME "_gsg/",
> +#else
> "\thttps://doc.dpdk.org/guides/"
> RTE_EXEC_ENV_NAME "_gsg/",
> +#endif
> .exit_on_error = true,
> .callback = arg_list_callback,
> .print_help = eal_usage,
>
>
> --
> David Marchand
>
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v3 5/9] eal: define the EAL parameters in argparse format
2025-07-21 9:05 ` Bruce Richardson
@ 2025-07-21 12:53 ` Bruce Richardson
0 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 12:53 UTC (permalink / raw)
To: David Marchand; +Cc: dev, Tyler Retzlaff, Thomas Monjalon
On Mon, Jul 21, 2025 at 10:05:23AM +0100, Bruce Richardson wrote:
> On Mon, Jul 21, 2025 at 10:41:33AM +0200, David Marchand wrote:
> > On Fri, Jul 18, 2025 at 4:34 PM Bruce Richardson
> > <bruce.richardson@intel.com> wrote:
> > > +struct eal_init_args {
> > > + /* define a struct member for each EAL option, member name is the same as option name.
> > > + * Parameters that take an argument e.g. -l, are char *,
> > > + * parameters that take no options e.g. --no-huge, are bool.
> > > + * parameters that can be given multiple times e.g. -a, are arg_lists,
> > > + * parameters that are optional e.g. --huge-unlink,
> > > + * are char * but are set to (void *)1 if the parameter is not given.
> > > + * NOTE: List is to be kept alphabetically by option name
> > > + */
> >
> > We will have to be careful to keep this struct below, in sync with the
> > options list.
> > Could we construct (at build time) this structure via the options list?
> >
> > The rules above would be enforced at the same time.
> >
> > (macros + #ifdef for Linux/FreeBSD may be an issue for MSVC though...)
> >
>
> I wonder how much an issue keeping them in sync would actually be? When
> adding a new option to the options list, it takes a reference to the struct
> field, meaning that we can't forget to add an entry here when adding the
> option. If we add here but forget to add to the options list, then obvious
> the option just doesn't get parsed so testing quickly would show up the
> issue.
>
> I suppose the main concern would be around renaming or deleting options -
> though in the latter case having an extra stray element in the struct isn't
> a big deal.
>
> I might have a shot at auto-generating the struct, but I'm not convinced
> the complexity will be worth the benefit.
>
Auto-generating the struct seems to work fairly ok. Will include in next
revision.
/Bruce
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 0/9] rework EAL argument parsing
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (8 preceding siblings ...)
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 1/9] build: add define for the OS environment name Bruce Richardson
` (10 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
When processing cmdline arguments in DPDK, we always do so with very
little context. So, for example, when processing the "-l" flag, we have
no idea whether there will be later a --proc-type=secondary flag. We
have all sorts of post-arg-processing checks in place to try and catch
these scenarios.
To improve this situation, this patchset tries to simplify the handling
of argument processing, by explicitly doing an initial pass to collate
all arguments into a structure. Thereafter, the actual arg parsing is
done in a fixed order, meaning that e.g. when processing the
--main-lcore flag, we have already processed the service core flags. We
also can far quicker and easier check for conflicting options, since
they can all be checked for NULL/non-NULL in the arg structure
immediately after the struct has been populated.
To do the initial argument gathering, this RFC uses the existing
argparse library in DPDK. With recent changes, and two additional
patches at the start of this set, this library now meets our needs for
EAL argument parsing and allows us to not need to do direct getopt
argument processing inside EAL at all.
An additional benefit of this work is that the argument parsing for EAL
is much more centralised into common options and the options list file.
This single list with ifdefs makes it clear to the viewer what options
are common across OS's, vs what are unix-only or linux-only.
V4:
* Updated patch 5 to auto-generate the arg struct definition from the same
list of defines used to construct the argument list.
V3:
* Added 3 new initial patches, one for minor build-system addition, and two
for functionality in argparse to allow the user-callback help function to
be maintained as we move to argparse.
* Added doc updates in the first EAL patch adding the long options
* Fixed ASAN issues by adding a patch to properly clean up EAL init - both
memory allocations and fixing the run-once flag
* Put ifdefs around the linux-only or unix-only options in EAL patch 2
* Updated args to handle numa-mem and numa-limit as equivalent socket-mem
and socket-limit
Bruce Richardson (9):
build: add define for the OS environment name
argparse: export function to print help text for object
argparse: allow user-override of help printing
eal: add long options for each short option
eal: define the EAL parameters in argparse format
eal: gather EAL args before processing
eal: ensure proper cleanup on EAL init failure
eal: combine parameter validation checks
eal: simplify handling of conflicting cmdline options
config/meson.build | 1 +
doc/guides/contributing/design.rst | 2 +-
doc/guides/linux_gsg/eal_args.include.rst | 20 +-
doc/guides/prog_guide/argparse_lib.rst | 16 +
lib/argparse/rte_argparse.c | 46 +-
lib/argparse/rte_argparse.h | 21 +-
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 1217 +++++++++++----------
lib/eal/common/eal_option_list.h | 90 ++
lib/eal/common/eal_options.h | 102 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 245 +----
lib/eal/linux/eal.c | 470 +-------
lib/eal/linux/eal_memory.c | 2 +-
lib/eal/meson.build | 2 +-
lib/eal/windows/eal.c | 156 +--
lib/meson.build | 1 +
17 files changed, 960 insertions(+), 1445 deletions(-)
create mode 100644 lib/eal/common/eal_option_list.h
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 1/9] build: add define for the OS environment name
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (9 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 " Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 2/9] argparse: export function to print help text for object Bruce Richardson
` (9 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
Introduce a string define for the currently running OS, or execution
environment.
Originally, with old make build system, CONFIG_RTE_EXEC_ENV used to hold
this name string, but the variable seems to have been missed in the
meson build system, until commit cadb255e25d6 ("eal: add OS defines for
C conditional checks") which introduced the RTE_EXEC_ENV for a different
purpose. Now we can fix the docs with the new name reference.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
config/meson.build | 1 +
doc/guides/contributing/design.rst | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/config/meson.build b/config/meson.build
index f31fef216c..40f33816aa 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -20,6 +20,7 @@ foreach env, id:exec_envs
dpdk_conf.set10('RTE_EXEC_ENV_IS_' + env.to_upper(), (exec_env == env))
endforeach
dpdk_conf.set('RTE_EXEC_ENV', exec_envs[exec_env])
+dpdk_conf.set_quoted('RTE_EXEC_ENV_NAME', exec_env)
dpdk_conf.set('RTE_EXEC_ENV_' + exec_env.to_upper(), 1)
# MS linker requires special treatment.
diff --git a/doc/guides/contributing/design.rst b/doc/guides/contributing/design.rst
index b724177ba1..5517613424 100644
--- a/doc/guides/contributing/design.rst
+++ b/doc/guides/contributing/design.rst
@@ -50,7 +50,7 @@ Per Execution Environment Sources
The following macro options can be used:
-* ``RTE_EXEC_ENV`` is a string that contains the name of the executive environment.
+* ``RTE_EXEC_ENV_NAME`` is a string that contains the name of the executive environment.
* ``RTE_EXEC_ENV_FREEBSD``, ``RTE_EXEC_ENV_LINUX`` or ``RTE_EXEC_ENV_WINDOWS`` are defined only if we are building for this execution environment.
Mbuf features
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 2/9] argparse: export function to print help text for object
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (10 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 1/9] build: add define for the OS environment name Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 3/9] argparse: allow user-override of help printing Bruce Richardson
` (8 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
Make the function to print out the help text for an argparse object a
public function, which takes as a new parameter the file stream on which
to print. This can be used in future to allow application to extend
their own help information.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/argparse/rte_argparse.c | 43 +++++++++++++++++++------------------
lib/argparse/rte_argparse.h | 14 ++++++++++++
2 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index 331f05f01d..d3b32c6357 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -716,23 +716,23 @@ calc_help_align(const struct rte_argparse *obj)
}
static void
-show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width)
+show_oneline_help(FILE *stream, const struct rte_argparse_arg *arg, uint32_t width)
{
uint32_t len = 0;
uint32_t i;
if (arg->name_short != NULL)
- len = printf(" %s,", arg->name_short);
- len += printf(" %s", arg->name_long);
+ len = fprintf(stream, " %s,", arg->name_short);
+ len += fprintf(stream, " %s", arg->name_long);
for (i = len; i < width; i++)
- printf(" ");
+ fprintf(stream, " ");
- printf("%s\n", arg->help);
+ fprintf(stream, "%s\n", arg->help);
}
static void
-show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
+show_args_pos_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
{
uint32_t position_count = calc_position_count(obj);
const struct rte_argparse_arg *arg;
@@ -741,19 +741,19 @@ show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
if (position_count == 0)
return;
- printf("\npositional arguments:\n");
+ fprintf(stream, "\npositional arguments:\n");
for (i = 0; /* NULL */; i++) {
arg = &obj->args[i];
if (arg->name_long == NULL)
break;
if (!is_arg_positional(arg))
continue;
- show_oneline_help(arg, align);
+ show_oneline_help(stream, arg, align);
}
}
static void
-show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
+show_args_opt_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
{
static const struct rte_argparse_arg help = {
.name_long = "--help",
@@ -763,34 +763,35 @@ show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
const struct rte_argparse_arg *arg;
uint32_t i;
- printf("\noptions:\n");
- show_oneline_help(&help, align);
+ fprintf(stream, "\noptions:\n");
+ show_oneline_help(stream, &help, align);
for (i = 0; /* NULL */; i++) {
arg = &obj->args[i];
if (arg->name_long == NULL)
break;
if (!is_arg_optional(arg))
continue;
- show_oneline_help(arg, align);
+ show_oneline_help(stream, arg, align);
}
}
-static void
-show_args_help(const struct rte_argparse *obj)
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_print_help, 25.07)
+void
+rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj)
{
uint32_t align = calc_help_align(obj);
- printf("usage: %s %s\n", obj->prog_name, obj->usage);
+ fprintf(stream, "usage: %s %s\n", obj->prog_name, obj->usage);
if (obj->descriptor != NULL)
- printf("\ndescriptor: %s\n", obj->descriptor);
+ fprintf(stream, "\ndescriptor: %s\n", obj->descriptor);
- show_args_pos_help(obj, align);
- show_args_opt_help(obj, align);
+ show_args_pos_help(stream, obj, align);
+ show_args_opt_help(stream, obj, align);
if (obj->epilog != NULL)
- printf("\n%s\n", obj->epilog);
+ fprintf(stream, "\n%s\n", obj->epilog);
else
- printf("\n");
+ fprintf(stream, "\n");
}
RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_parse, 24.03)
@@ -820,7 +821,7 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
goto error;
if (show_help) {
- show_args_help(obj);
+ rte_argparse_print_help(stdout, obj);
exit(0);
}
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index 52bef34363..baf278f6b9 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -189,6 +189,20 @@ struct rte_argparse {
__rte_experimental
int rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Output the help text information for the given argparse object.
+ *
+ * @param stream
+ * Output file handle, e.g. stdout, stderr, on which to print the help text.
+ * @param obj
+ * Parser object.
+ */
+__rte_experimental
+void rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj);
+
/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 3/9] argparse: allow user-override of help printing
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (11 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 2/9] argparse: export function to print help text for object Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 4/9] eal: add long options for each short option Bruce Richardson
` (7 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
When the arguments passed to argparse include -h/--help then usage
information is automatically printed. Provide the capability for the
user to supply their own help function for this.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
doc/guides/prog_guide/argparse_lib.rst | 16 ++++++++++++++++
lib/argparse/rte_argparse.c | 5 ++++-
lib/argparse/rte_argparse.h | 7 ++++++-
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/doc/guides/prog_guide/argparse_lib.rst b/doc/guides/prog_guide/argparse_lib.rst
index 9f11714890..b309260d20 100644
--- a/doc/guides/prog_guide/argparse_lib.rst
+++ b/doc/guides/prog_guide/argparse_lib.rst
@@ -24,6 +24,8 @@ Features and Capabilities
#. autosave: used for parsing known value types;
#. callback: will invoke user callback to parse.
+- Supports automatic help and usage information.
+
Usage Guide
-----------
@@ -193,3 +195,17 @@ Then the user input could contain multiple ``--xyz`` arguments.
The multiple times argument only support with optional argument
and must be parsed by callback way.
+
+Help and Usage Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The argparse library supports automatic generation of help and usage information.
+When the input arguments include ``-h`` or ``--help``,
+it will print the usage information to standard output.
+If the default help output is not what is wanted,
+the user can provide a custom help printing function by setting the ``print_help`` field in the ``rte_argparse`` object.
+(If this field is set to NULL, the default help printing function will be used.)
+
+If the custom help printing function wants to use the text produced by the default help function,
+it can call the function ``rte_argparse_print_help()`` to get the help text printed to an output stream,
+for example: stdout or stderr.
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index d3b32c6357..e7b9bf573d 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -821,7 +821,10 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
goto error;
if (show_help) {
- rte_argparse_print_help(stdout, obj);
+ if (obj->print_help != NULL)
+ obj->print_help(obj);
+ else
+ rte_argparse_print_help(stdout, obj);
exit(0);
}
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index baf278f6b9..63b49ba220 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -160,8 +160,13 @@ struct rte_argparse {
rte_arg_parser_t callback;
/** Opaque which used to invoke callback. */
void *opaque;
+ /**
+ * Function pointer for printing usage when -h is passed.
+ * If this is NULL, default printing function will be used.
+ */
+ void (*print_help)(const struct rte_argparse *obj);
/** Reserved field used for future extension. */
- void *reserved[16];
+ void *reserved[15];
/** Arguments configuration. Must ended with ARGPARSE_ARG_END(). */
struct rte_argparse_arg args[];
};
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 4/9] eal: add long options for each short option
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (12 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 3/9] argparse: allow user-override of help printing Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
` (6 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
To simplify future rework of the EAL arg handling, add a long-option
equivalent for each short option that doesn't already have one.
When updating the docs with the new long options, standardize the format
of options which have both short and long variants, and drop the
deprecated service-coremask option from the docs, rather than adding its
new long option.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
doc/guides/linux_gsg/eal_args.include.rst | 20 ++++++++------------
lib/eal/common/eal_common_options.c | 9 +++++++++
lib/eal/common/eal_options.h | 16 ++++++++++++++++
3 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/doc/guides/linux_gsg/eal_args.include.rst b/doc/guides/linux_gsg/eal_args.include.rst
index 9ced54af40..0b17879d42 100644
--- a/doc/guides/linux_gsg/eal_args.include.rst
+++ b/doc/guides/linux_gsg/eal_args.include.rst
@@ -4,7 +4,7 @@
Lcore-related options
~~~~~~~~~~~~~~~~~~~~~
-* ``-l/--lcores <core list>``
+* ``-l, --lcores <core list>``
List of cores to run on
@@ -71,11 +71,7 @@ Lcore-related options
Core ID that is used as main.
-* ``-s <service core mask>``
-
- Hexadecimal bitmask of cores to be used as service cores.
-
-* ``-S <service core list>``
+* ``-S, --service-corelist <service core list>``
List of cores to be used as service cores.
@@ -108,7 +104,7 @@ Device-related options
--vdev 'net_pcap0,rx_pcap=input.pcap,tx_pcap=output.pcap'
-* ``-d <path to shared object or directory>``
+* ``-d, --driver-path <path to shared object or directory>``
Load external drivers. An argument can be a single shared object file, or a
directory containing multiple driver shared objects. Multiple -d options are
@@ -134,15 +130,15 @@ Multiprocessing-related options
Memory-related options
~~~~~~~~~~~~~~~~~~~~~~
-* ``-n <number of channels>``
+* ``-n, --memory-channels <number of channels>``
Set the number of memory channels to use.
-* ``-r <number of ranks>``
+* ``-r, --memory-ranks <number of ranks>``
Set the number of memory ranks (auto-detected by default).
-* ``-m <megabytes>``
+* ``-m, --memory-size <megabytes>``
Amount of memory to preallocate at startup.
@@ -236,11 +232,11 @@ Debugging options
Other options
~~~~~~~~~~~~~
-* ``-h``, ``--help``
+* ``-h, --help``
Display help message listing all EAL parameters.
-* ``-v``
+* ``-v, --version``
Display the version information on startup.
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index f0a9ddeeb7..cafae9d9d7 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -66,7 +66,9 @@ eal_short_options[] =
const struct option
eal_long_options[] = {
{OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
+ {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
{OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
+ {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
{OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
{OPT_HELP, 0, NULL, OPT_HELP_NUM },
{OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
@@ -76,6 +78,11 @@ eal_long_options[] = {
{OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
{OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
{OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
+ {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
+ {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
+ {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
+ {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
+ {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
{OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
{OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
{OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
@@ -109,6 +116,8 @@ eal_long_options[] = {
{OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
{OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
{OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
+ {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
+
{0, 0, NULL, 0 }
};
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 7a56aa3810..6ef45559f0 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -17,8 +17,24 @@ enum {
OPT_DEV_ALLOW_NUM = 'a',
#define OPT_DEV_BLOCK "block"
OPT_DEV_BLOCK_NUM = 'b',
+#define OPT_COREMASK "coremask"
+ OPT_COREMASK_NUM = 'c',
+#define OPT_DRIVER_PATH "driver-path"
+ OPT_DRIVER_PATH_NUM = 'd',
#define OPT_LCORES "lcores"
OPT_LCORES_NUM = 'l',
+#define OPT_MEMORY_SIZE "memory-size"
+ OPT_MEMORY_SIZE_NUM = 'm',
+#define OPT_MEMORY_CHANNELS "memory-channels"
+ OPT_MEMORY_CHANNELS_NUM = 'n',
+#define OPT_MEMORY_RANKS "memory-ranks"
+ OPT_MEMORY_RANKS_NUM = 'r',
+#define OPT_SERVICE_COREMASK "service-coremask"
+ OPT_SERVICE_COREMASK_NUM = 's',
+#define OPT_SERVICE_CORELIST "service-corelist"
+ OPT_SERVICE_CORELIST_NUM = 'S',
+#define OPT_VERSION "version"
+ OPT_VERSION_NUM = 'v',
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 5/9] eal: define the EAL parameters in argparse format
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (13 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 4/9] eal: add long options for each short option Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 6/9] eal: gather EAL args before processing Bruce Richardson
` (5 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
Create eal_option_list.h, containing all the possible EAL parameters,
and basic info about them, such as type, whether they take a parameter
or not. Each entry is defined using a macro, which will be then
interpreted when the file is included.
First time this header in included in the eal_common_options.c file, the
macros are defined in such a way as to define field elements for an
"eal_init_args" structure, where each value is either a string type, if
it takes a parameter, or boolean type if it doesn't. For those elements
that take multiple values, i.e. are passed multiple times, we put them
in a TAILQ.
The second time of inclusion, the macros are defined so as to define the
arguments in an rte_argparse structure for EAL. For the basic string and
boolean types, we just store the values in the appropriate field in the
previous defined "eal_init_args" structure. For the list elements, we
use the argparse callback to process those elements, adding them to the
TAILQ as they are encountered.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 135 +++++++++++++++++++++++++++-
lib/eal/common/eal_option_list.h | 90 +++++++++++++++++++
lib/eal/meson.build | 2 +-
lib/meson.build | 1 +
4 files changed, 224 insertions(+), 4 deletions(-)
create mode 100644 lib/eal/common/eal_option_list.h
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index cafae9d9d7..197aa33590 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -28,11 +28,13 @@
#include <rte_version.h>
#include <rte_devargs.h>
#include <rte_memcpy.h>
+#include <sys/queue.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <rte_telemetry.h>
#endif
#include <rte_vect.h>
+#include <rte_argparse.h>
#include <eal_export.h>
#include "eal_internal_cfg.h"
#include "eal_options.h"
@@ -47,6 +49,136 @@
#define LCORE_OPT_LST 1
#define LCORE_OPT_MSK 2
+/* Allow the application to print its usage message too if set */
+static rte_usage_hook_t rte_application_usage_hook;
+
+struct arg_list_elem {
+ TAILQ_ENTRY(arg_list_elem) next;
+ char *arg;
+};
+TAILQ_HEAD(arg_list, arg_list_elem);
+
+struct eal_init_args {
+ /* define a struct member for each EAL option, member name is the same as option name.
+ * Parameters that take an argument e.g. -l, are char *,
+ * parameters that take no options e.g. --no-huge, are bool.
+ * parameters that can be given multiple times e.g. -a, are arg_lists,
+ * parameters that are optional e.g. --huge-unlink,
+ * are char * but are set to (void *)1 if the parameter is not given.
+ * for aliases, i.e. options under different names, no field needs to be output
+ */
+#define LIST_ARG(long, short, help_str, fieldname) struct arg_list fieldname;
+#define STR_ARG(long, short, help_str, fieldname) char *fieldname;
+#define OPT_STR_ARG(long, short, help_str, fieldname) char *fieldname;
+#define BOOL_ARG(long, short, help_str, fieldname) bool fieldname;
+#define STR_ALIAS(long, short, help_str, fieldname)
+
+#define INCLUDE_ALL_ARG 1 /* for struct definition, include even unsupported values */
+#include "eal_option_list.h"
+#undef INCLUDE_ALL_ARG
+};
+struct eal_init_args args;
+
+/* an rte_argparse callback to append the argument to an arg_list
+ * in args. The index is the offset into the struct of the list.
+ */
+static int
+arg_list_callback(uint32_t index, const char *arg, void *init_args)
+{
+ struct arg_list *list = RTE_PTR_ADD(init_args, index);
+ struct arg_list_elem *elem;
+
+ elem = malloc(sizeof(*elem));
+ if (elem == NULL)
+ return -1;
+
+ elem->arg = strdup(arg);
+ if (elem->arg == NULL) {
+ free(elem);
+ return -1;
+ }
+
+ TAILQ_INSERT_TAIL(list, elem, next);
+ return 0;
+}
+
+static void
+eal_usage(const struct rte_argparse *obj)
+{
+ rte_argparse_print_help(stdout, obj);
+ if (rte_application_usage_hook != NULL)
+ rte_application_usage_hook(obj->prog_name);
+}
+
+/* undef the *_ARG macros before redefining to generate the argparse arg list */
+#undef LIST_ARG
+#undef STR_ARG
+#undef OPT_STR_ARG
+#undef BOOL_ARG
+#undef STR_ALIAS
+
+/* For arguments which have an arg_list type, they use callback (no val_saver),
+ * require a value, and have the SUPPORT_MULTI flag.
+ */
+#define LIST_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_set = (void *)offsetof(struct eal_init_args, fieldname), \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .flags = RTE_ARGPARSE_FLAG_SUPPORT_MULTI, \
+},
+/* For arguments which have a string type, they use val_saver (no callback),
+ * and normally REQUIRED_VALUE.
+ */
+#define STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+},
+/* For flags which have optional arguments, they use both val_saver and val_set,
+ * but still have a string type.
+ */
+#define OPT_STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_OPTIONAL, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+},
+/* For boolean arguments, they use val_saver and val_set, with NO_VALUE flag.
+ */
+#define BOOL_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_NONE, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_BOOL, \
+},
+#define STR_ALIAS STR_ARG
+
+struct rte_argparse eal_argparse = {
+ .prog_name = "",
+ .usage = "<DPDK EAL options> -- <App options>",
+ .epilog = "For more information on EAL options, see the DPDK documentation at: \n"
+ "\thttps://doc.dpdk.org/guides/" RTE_EXEC_ENV_NAME "_gsg/",
+ .exit_on_error = true,
+ .callback = arg_list_callback,
+ .print_help = eal_usage,
+ .opaque = &args,
+ .args = {
+ #include "eal_option_list.h"
+ ARGPARSE_ARG_END(),
+ }
+};
+
const char
eal_short_options[] =
"a:" /* allow */
@@ -165,9 +297,6 @@ static int main_lcore_parsed;
static int mem_parsed;
static int core_parsed;
-/* Allow the application to print its usage message too if set */
-static rte_usage_hook_t rte_application_usage_hook;
-
/* Returns rte_usage_hook_t */
rte_usage_hook_t
eal_get_application_usage_hook(void)
diff --git a/lib/eal/common/eal_option_list.h b/lib/eal/common/eal_option_list.h
new file mode 100644
index 0000000000..dd148b7fed
--- /dev/null
+++ b/lib/eal/common/eal_option_list.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2025 Intel Corporation.
+ */
+
+/** This file contains a list of EAL commandline arguments.
+ *
+ * It's designed to be included multiple times in the codebase to
+ * generate both argument structure and the argument definitions
+ * for argparse.
+ */
+
+/* check that all ARG macros are defined */
+ #ifndef LIST_ARG
+#error "LIST_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef STR_ARG
+#error "STR_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef OPT_STR_ARG
+#error "OPT_STR_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef BOOL_ARG
+#error "BOOL_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef STR_ALIAS
+#error "STR_ALIAS macro must be defined before including " __FILE__
+#endif
+
+
+/*
+ * list of EAL arguments as struct rte_argparse_arg.
+ * Format of each entry: long name, short name, help string, struct member name.
+ */
+/* (Alphabetical) List of common options first */
+LIST_ARG("--allow", "-a", "Add device to allow-list, causing DPDK to only use specified devices", allow)
+STR_ARG("--base-virtaddr", NULL, "Base virtual address to reserve memory", base_virtaddr)
+LIST_ARG("--block", "-b", "Add device to block-list, preventing DPDK from using the device", block)
+STR_ARG("--coremask", "-c", "Hexadecimal bitmask of cores to use", coremask)
+LIST_ARG("--driver-path", "-d", "Path to external driver shared object, or directory of drivers", driver_path)
+STR_ARG("--force-max-simd-bitwidth", NULL, "Set max SIMD bitwidth to use in vector code paths", force_max_simd_bitwidth)
+OPT_STR_ARG("--huge-unlink", NULL, "Unlink hugetlbfs files on exit (existing|always|never)", huge_unlink)
+BOOL_ARG("--in-memory", NULL, "DPDK should not create shared mmap files in filesystem (disables secondary process support)", in_memory)
+STR_ARG("--iova-mode", NULL, "IOVA mapping mode, physical (pa)/virtual (va)", iova_mode)
+STR_ARG("--lcores", "-l", "List of CPU cores to use", lcores)
+BOOL_ARG("--legacy-mem", NULL, "Enable legacy memory behavior", legacy_mem)
+OPT_STR_ARG("--log-color", NULL, "Enable/disable color in log output", log_color)
+STR_ARG("--log-level", NULL, "Log level for loggers; use log-level=help for list of log types and levels", log_level)
+OPT_STR_ARG("--log-timestamp", NULL, "Enable/disable timestamp in log output", log_timestamp)
+STR_ARG("--main-lcore", NULL, "Select which core to use for the main thread", main_lcore)
+STR_ARG("--mbuf-pool-ops-name", NULL, "User defined mbuf default pool ops name", mbuf_pool_ops_name)
+STR_ARG("--memory-channels", "-n", "Number of memory channels per socket", memory_channels)
+STR_ARG("--memory-ranks", "-r", "Force number of memory ranks (don't detect)", memory_ranks)
+STR_ARG("--memory-size", "-m", "Total size of memory to allocate initially", memory_size)
+BOOL_ARG("--no-hpet", NULL, "Disable HPET timer", no_hpet)
+BOOL_ARG("--no-huge", NULL, "Disable hugetlbfs support", no_huge)
+BOOL_ARG("--no-pci", NULL, "Disable all PCI devices", no_pci)
+BOOL_ARG("--no-shconf", NULL, "Disable shared config file generation", no_shconf)
+BOOL_ARG("--no-telemetry", NULL, "Disable telemetry", no_telemetry)
+STR_ARG("--proc-type", NULL, "Type of process (primary|secondary|auto)", proc_type)
+STR_ARG("--service-corelist", "-S", "List of cores to use for service threads", service_corelist)
+STR_ARG("--service-coremask", "-s", "Hexadecimal bitmask of cores to use for service threads", service_coremask)
+BOOL_ARG("--single-file-segments", NULL, "Store all pages within single files (per-page-size, per-node)", single_file_segments)
+BOOL_ARG("--telemetry", NULL, "Enable telemetry", telemetry)
+LIST_ARG("--vdev", NULL, "Add a virtual device to the system; format=<driver><id>[,key=val,...]", vdev)
+BOOL_ARG("--vmware-tsc-map", NULL, "Use VMware TSC mapping instead of native RDTSC", vmware_tsc_map)
+BOOL_ARG("--version", "-v", "Show version", version)
+
+#if defined(INCLUDE_ALL_ARG) || !defined(RTE_EXEC_ENV_WINDOWS)
+/* Linux and FreeBSD options*/
+OPT_STR_ARG("--syslog", NULL, "Log to syslog (and optionally set facility)", syslog)
+STR_ARG("--trace", NULL, "Enable trace based on regular expression trace name", trace)
+STR_ARG("--trace-bufsz", NULL, "Trace buffer size", trace_bufsz)
+STR_ARG("--trace-dir", NULL, "Trace directory", trace_dir)
+STR_ARG("--trace-mode", NULL, "Trace mode", trace_mode)
+#endif
+
+#if defined(INCLUDE_ALL_ARG) || defined(RTE_EXEC_ENV_LINUX)
+/* Linux-only options */
+BOOL_ARG("--create-uio-dev", NULL, "Create /dev/uioX devices", create_uio_dev)
+STR_ARG("--file-prefix", NULL, "Base filename of hugetlbfs files", file_prefix)
+STR_ARG("--huge-dir", NULL, "Directory for hugepage files", huge_dir)
+OPT_STR_ARG("--huge-worker-stack", NULL, "Allocate worker thread stacks from hugepage memory, with optional size (kB)", huge_worker_stack)
+BOOL_ARG("--match-allocations", NULL, "Free hugepages exactly as allocated", match_allocations)
+STR_ARG("--numa-mem", NULL, "Memory to allocate on NUMA nodes (comma separated values)", numa_mem)
+STR_ARG("--numa-limit", NULL, "Limit memory allocation on NUMA nodes (comma separated values)", numa_limit)
+STR_ALIAS("--socket-mem", NULL, "Alias for --numa-mem", numa_mem)
+STR_ALIAS("--socket-limit", NULL, "Alias for --numa-limit", numa_limit)
+STR_ARG("--vfio-intr", NULL, "VFIO interrupt mode (legacy|msi|msix)", vfio_intr)
+STR_ARG("--vfio-vf-token", NULL, "VF token (UUID) shared between SR-IOV PF and VFs", vfio_vf_token)
+#endif
diff --git a/lib/eal/meson.build b/lib/eal/meson.build
index e1d6c4cf17..f9fcee24ee 100644
--- a/lib/eal/meson.build
+++ b/lib/eal/meson.build
@@ -14,7 +14,7 @@ subdir(exec_env)
subdir(arch_subdir)
-deps += ['log', 'kvargs']
+deps += ['argparse', 'kvargs']
if not is_windows
deps += ['telemetry']
endif
diff --git a/lib/meson.build b/lib/meson.build
index 0d56b2083b..dec90059e1 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -71,6 +71,7 @@ libraries = [
]
always_enable = [
+ 'argparse',
'cmdline',
'eal',
'ethdev',
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 6/9] eal: gather EAL args before processing
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (14 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
` (4 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev
Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk,
Anatoly Burakov
DPDK traditionally has iterated through all args and processed them as
they appear in the commandline. The arg processing logic can be
simplified if instead we initially gather all arguments into a structure
which is then processed with the arguments dealt with in a fixed/known
order.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 877 ++++++++++++++--------------
lib/eal/common/eal_options.h | 10 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 164 +-----
lib/eal/linux/eal.c | 379 +-----------
lib/eal/windows/eal.c | 113 +---
6 files changed, 482 insertions(+), 1072 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 197aa33590..aea2c813ed 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -46,8 +46,7 @@
#endif
#define BITS_PER_HEX 4
-#define LCORE_OPT_LST 1
-#define LCORE_OPT_MSK 2
+#define NUMA_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
/* Allow the application to print its usage message too if set */
static rte_usage_hook_t rte_application_usage_hook;
@@ -179,80 +178,31 @@ struct rte_argparse eal_argparse = {
}
};
-const char
-eal_short_options[] =
- "a:" /* allow */
- "b:" /* block */
- "c:" /* coremask */
- "s:" /* service coremask */
- "d:" /* driver */
- "h" /* help */
- "l:" /* corelist */
- "S:" /* service corelist */
- "m:" /* memory size */
- "n:" /* memory channels */
- "r:" /* memory ranks */
- "v" /* version */
- ;
-
-const struct option
-eal_long_options[] = {
- {OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
- {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
- {OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
- {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
- {OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
- {OPT_HELP, 0, NULL, OPT_HELP_NUM },
- {OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
- {OPT_HUGE_UNLINK, 2, NULL, OPT_HUGE_UNLINK_NUM },
- {OPT_IOVA_MODE, 1, NULL, OPT_IOVA_MODE_NUM },
- {OPT_LCORES, 1, NULL, OPT_LCORES_NUM },
- {OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
- {OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
- {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
- {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
- {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
- {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
- {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
- {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
- {OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
- {OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
- {OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
- {OPT_TRACE_MODE, 1, NULL, OPT_TRACE_MODE_NUM },
- {OPT_MAIN_LCORE, 1, NULL, OPT_MAIN_LCORE_NUM },
- {OPT_MBUF_POOL_OPS_NAME, 1, NULL, OPT_MBUF_POOL_OPS_NAME_NUM},
- {OPT_NO_HPET, 0, NULL, OPT_NO_HPET_NUM },
- {OPT_NO_HUGE, 0, NULL, OPT_NO_HUGE_NUM },
- {OPT_NO_PCI, 0, NULL, OPT_NO_PCI_NUM },
- {OPT_NO_SHCONF, 0, NULL, OPT_NO_SHCONF_NUM },
- {OPT_IN_MEMORY, 0, NULL, OPT_IN_MEMORY_NUM },
- {OPT_DEV_BLOCK, 1, NULL, OPT_DEV_BLOCK_NUM },
- {OPT_DEV_ALLOW, 1, NULL, OPT_DEV_ALLOW_NUM },
- {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM },
- /* socket-mem/socket-limit are kept for backwards compatibility */
- {OPT_SOCKET_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_SOCKET_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
- {OPT_NUMA_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_NUMA_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
-#ifndef RTE_EXEC_ENV_WINDOWS
- {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM },
-#endif
- {OPT_VDEV, 1, NULL, OPT_VDEV_NUM },
- {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
- {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM },
- {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
- {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM },
- {OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM},
- {OPT_MATCH_ALLOCATIONS, 0, NULL, OPT_MATCH_ALLOCATIONS_NUM},
- {OPT_TELEMETRY, 0, NULL, OPT_TELEMETRY_NUM },
- {OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
- {OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
- {OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
- {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
-
-
- {0, 0, NULL, 0 }
-};
+/* function to call into argparse library to parse the passed argc/argv parameters
+ * to the eal_init_args structure.
+ */
+int
+eal_collate_args(int argc, char **argv)
+{
+ if (argc < 1 || argv == NULL)
+ return -EINVAL;
+
+ /* initialize the list of arguments */
+ memset(&args, 0, sizeof(args));
+ TAILQ_INIT(&args.allow);
+ TAILQ_INIT(&args.block);
+ TAILQ_INIT(&args.driver_path);
+ TAILQ_INIT(&args.vdev);
+
+ /* parse the arguments */
+ eal_argparse.prog_name = argv[0];
+ int retval = rte_argparse_parse(&eal_argparse, argc, argv);
+ if (retval < 0)
+ return retval;
+
+ argv[retval - 1] = argv[0];
+ return retval - 1;
+}
TAILQ_HEAD(shared_driver_list, shared_driver);
@@ -294,7 +244,6 @@ static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
static int main_lcore_parsed;
-static int mem_parsed;
static int core_parsed;
/* Returns rte_usage_hook_t */
@@ -318,7 +267,12 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
return old_func;
}
-#ifndef RTE_EXEC_ENV_WINDOWS
+#ifdef RTE_EXEC_ENV_WINDOWS
+
+int
+eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+
+#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
static char **eal_app_args;
@@ -406,7 +360,7 @@ eal_save_args(int argc, char **argv)
eal_args = NULL;
return -1;
}
-#endif
+#endif /* !RTE_EXEC_ENV_WINDOWS */
static int
eal_option_device_add(enum rte_devtype type, const char *optarg)
@@ -829,17 +783,6 @@ eal_parse_service_coremask(const char *coremask)
return 0;
}
-static int
-eal_service_cores_parsed(void)
-{
- int idx;
- for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- if (lcore_config[idx].core_role == ROLE_SERVICE)
- return 1;
- }
- return 0;
-}
-
static int
update_lcore_config(int *cores)
{
@@ -1666,361 +1609,486 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return -1;
}
-bool
-eal_option_is_log(int opt)
+/* Parse all arguments looking for log related ones */
+int
+eal_parse_log_options(void)
{
- switch (opt) {
- case OPT_LOG_COLOR_NUM:
- case OPT_LOG_LEVEL_NUM:
- case OPT_LOG_TIMESTAMP_NUM:
- case OPT_SYSLOG_NUM:
- return true;
- default:
- return false;
+ if (args.log_level != NULL) {
+ if (eal_parse_log_level(args.log_level) < 0) {
+ EAL_LOG(ERR, "invalid log-level parameter");
+ return -1;
+ }
+ }
+ if (args.log_color != NULL) {
+ /* if value is 1, no argument specified, so pass NULL */
+ if (args.log_color == (void *)1)
+ args.log_color = NULL;
+ if (eal_log_color(args.log_color) < 0) {
+ EAL_LOG(ERR, "invalid log-color parameter");
+ return -1;
+ }
+ }
+ if (args.log_timestamp != NULL) {
+ /* similarly log_timestamp may be 1 */
+ if (args.log_timestamp == (void *)1)
+ args.log_timestamp = NULL;
+ if (eal_log_timestamp(args.log_timestamp) < 0) {
+ EAL_LOG(ERR, "invalid log-timestamp parameter");
+ return -1;
+ }
+ }
+ if (args.syslog != NULL) {
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "syslog is not supported on Windows, ignoring parameter");
+#else
+ /* also syslog parameter may be 1 */
+ if (args.syslog == (void *)1)
+ args.syslog = NULL;
+ if (eal_log_syslog(args.syslog) < 0) {
+ EAL_LOG(ERR, "invalid syslog parameter");
+ return -1;
+ }
+#endif
}
+ return 0;
}
-/* Parse all arguments looking for log related ones */
-int
-eal_parse_log_options(int argc, char * const argv[])
+static int
+eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
{
- struct internal_config *internal_conf = eal_get_internal_configuration();
- int option_index, opt;
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_opterr = opterr;
- char *old_optarg = optarg;
-#ifdef RTE_EXEC_ENV_FREEBSD
- const int old_optreset = optreset;
- optreset = 1;
-#endif
+ char *arg[RTE_MAX_NUMA_NODES];
+ char *end;
+ int arg_num, i, len;
- optind = 1;
- opterr = 0;
+ len = strnlen(strval, NUMA_MEM_STRLEN);
+ if (len == NUMA_MEM_STRLEN) {
+ EAL_LOG(ERR, "--numa-mem/--socket-mem parameter is too long");
+ return -1;
+ }
- while ((opt = getopt_long(argc, argv, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
+ /* all other error cases will be caught later */
+ if (!isdigit(strval[len-1]))
+ return -1;
- if (!eal_option_is_log(opt))
- continue;
+ /* split the optarg into separate socket values */
+ arg_num = rte_strsplit(strval, len,
+ arg, RTE_MAX_NUMA_NODES, ',');
- if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+ /* if split failed, or 0 arguments */
+ if (arg_num <= 0)
+ return -1;
+
+ /* parse each defined socket option */
+ errno = 0;
+ for (i = 0; i < arg_num; i++) {
+ uint64_t val;
+ end = NULL;
+ val = strtoull(arg[i], &end, 10);
+
+ /* check for invalid input */
+ if ((errno != 0) ||
+ (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
+ val <<= 20;
+ socket_arg[i] = val;
}
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
- opterr = old_opterr;
-#ifdef RTE_EXEC_ENV_FREEBSD
- optreset = old_optreset;
+ return 0;
+}
+
+static int
+eal_parse_vfio_intr(const char *mode)
+{
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+ static struct {
+ const char *name;
+ enum rte_intr_mode value;
+ } map[] = {
+ { "legacy", RTE_INTR_MODE_LEGACY },
+ { "msi", RTE_INTR_MODE_MSI },
+ { "msix", RTE_INTR_MODE_MSIX },
+ };
+
+ for (size_t i = 0; i < RTE_DIM(map); i++) {
+ if (!strcmp(mode, map[i].name)) {
+ internal_conf->vfio_intr_mode = map[i].value;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+eal_parse_vfio_vf_token(const char *vf_token)
+{
+ struct internal_config *cfg = eal_get_internal_configuration();
+ rte_uuid_t uuid;
+
+ if (!rte_uuid_parse(vf_token, uuid)) {
+ rte_uuid_copy(cfg->vfio_vf_token, uuid);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+eal_parse_huge_worker_stack(const char *arg)
+{
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "Cannot set worker stack size on Windows, parameter ignored");
+ RTE_SET_USED(arg);
+#else
+ struct internal_config *cfg = eal_get_internal_configuration();
+
+ if (arg == NULL || arg[0] == '\0') {
+ pthread_attr_t attr;
+ int ret;
+
+ if (pthread_attr_init(&attr) != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
+ pthread_attr_destroy(&attr);
+ if (ret != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ } else {
+ unsigned long stack_size;
+ char *end;
+
+ errno = 0;
+ stack_size = strtoul(arg, &end, 10);
+ if (errno || end == NULL || stack_size == 0 ||
+ stack_size >= (size_t)-1 / 1024)
+ return -1;
+
+ cfg->huge_worker_stack_size = stack_size * 1024;
+ }
+
+ EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
+ cfg->huge_worker_stack_size / 1024);
#endif
return 0;
}
+/* Parse the arguments given in the command line of the application */
int
-eal_parse_common_option(int opt, const char *optarg,
- struct internal_config *conf)
+eal_parse_args(void)
{
- static int b_used;
- static int a_used;
-
- switch (opt) {
- case 'b':
- if (a_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, optarg) < 0)
+ struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct arg_list_elem *arg;
+
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+ /* both -l and -c cannot be used at the same time */
+ if (args.coremask != NULL && args.lcores != NULL) {
+ EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
+ return -1;
+ }
+ /* both -s and -S cannot be used at the same time */
+ if (args.service_coremask != NULL && args.service_corelist != NULL) {
+ EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
+ return -1;
+ }
+ /* can't have both telemetry and no-telemetry */
+ if (args.no_telemetry && args.telemetry) {
+ EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
+ return -1;
+ }
+ /* can't have both -m and --socket-mem */
+ if (args.memory_size != NULL && args.numa_mem != NULL) {
+ EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ return -1;
+ }
+
+ /* parse options */
+ /* print version before anything else */
+ if (args.version) {
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
+ }
+
+ /* parse the process type */
+ if (args.proc_type != NULL) {
+ int_cfg->process_type = eal_parse_proc_type(args.proc_type);
+ if (int_cfg->process_type == RTE_PROC_INVALID) {
+ EAL_LOG(ERR, "invalid process type: %s", args.proc_type);
return -1;
- b_used = 1;
- break;
+ }
+ }
- case 'a':
- if (b_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, optarg) < 0)
+ /* device -a/-b/-vdev options*/
+ TAILQ_FOREACH(arg, &args.allow, next)
+ if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, arg->arg) < 0)
return -1;
- a_used = 1;
- break;
- /* coremask */
- case 'c': {
+ TAILQ_FOREACH(arg, &args.block, next)
+ if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, arg->arg) < 0)
+ return -1;
+ TAILQ_FOREACH(arg, &args.vdev, next)
+ if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, arg->arg) < 0)
+ return -1;
+ /* driver loading options */
+ TAILQ_FOREACH(arg, &args.driver_path, next)
+ if (eal_plugin_add(arg->arg) < 0)
+ return -1;
+
+ /* parse the coremask /core-list */
+ if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -c is before -s or -S");
- if (rte_eal_parse_coremask(optarg, lcore_indexes) < 0) {
+ if (rte_eal_parse_coremask(args.coremask, lcore_indexes) < 0) {
EAL_LOG(ERR, "invalid coremask syntax");
return -1;
}
if (update_lcore_config(lcore_indexes) < 0) {
char *available = available_cores();
- EAL_LOG(ERR,
- "invalid coremask, please check specified cores are part of %s",
- available);
+ EAL_LOG(ERR, "invalid coremask '%s', please check specified cores are part of %s",
+ args.coremask, available);
free(available);
return -1;
}
-
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_MSK)
- EAL_LOG(ERR, "Option '-c' passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option -c is ignored, because option -l/--lcores used");
+ core_parsed = 1;
+ } else if (args.lcores != NULL) {
+ if (eal_parse_lcores(args.lcores) < 0) {
+ EAL_LOG(ERR, "invalid lcore list: '%s'", args.lcores);
return -1;
}
-
- core_parsed = LCORE_OPT_MSK;
- break;
+ core_parsed = 1;
}
- /* corelist */
- case 'l': {
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -l is before -s or -S");
-
- if (eal_parse_lcores(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for -l/--" OPT_LCORES);
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0) {
+ EAL_LOG(ERR, "invalid main-lcore parameter");
return -1;
}
+ }
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_LST)
- EAL_LOG(ERR, "Core list option passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option '-l/--lcores' is ignored, because coremask option used");
+ /* service core options */
+ if (args.service_coremask != NULL) {
+ if (eal_parse_service_coremask(args.service_coremask) < 0) {
+ EAL_LOG(ERR, "invalid service coremask: '%s'",
+ args.service_coremask);
return -1;
}
+ } else if (args.service_corelist != NULL) {
+ if (eal_parse_service_corelist(args.service_corelist) < 0) {
+ EAL_LOG(ERR, "invalid service core list: '%s'",
+ args.service_corelist);
+ return -1;
+ }
+ }
- core_parsed = LCORE_OPT_LST;
- break;
+ /* memory options */
+ if (args.memory_size != NULL) {
+ int_cfg->memory = atoi(args.memory_size);
+ int_cfg->memory *= 1024ULL;
+ int_cfg->memory *= 1024ULL;
}
- /* service coremask */
- case 's':
- if (eal_parse_service_coremask(optarg) < 0) {
- EAL_LOG(ERR, "invalid service coremask");
+ if (args.memory_channels != NULL) {
+ int_cfg->force_nchannel = atoi(args.memory_channels);
+ if (int_cfg->force_nchannel == 0) {
+ EAL_LOG(ERR, "invalid memory channel parameter");
return -1;
}
- break;
- /* service corelist */
- case 'S':
- if (eal_parse_service_corelist(optarg) < 0) {
- EAL_LOG(ERR, "invalid service core list");
+ }
+ if (args.memory_ranks != NULL) {
+ int_cfg->force_nrank = atoi(args.memory_ranks);
+ if (int_cfg->force_nrank == 0 || int_cfg->force_nrank > 16) {
+ EAL_LOG(ERR, "invalid memory rank parameter");
return -1;
}
- break;
- /* size of memory */
- case 'm':
- conf->memory = atoi(optarg);
- conf->memory *= 1024ULL;
- conf->memory *= 1024ULL;
- mem_parsed = 1;
- break;
- /* force number of channels */
- case 'n':
- conf->force_nchannel = atoi(optarg);
- if (conf->force_nchannel == 0) {
- EAL_LOG(ERR, "invalid channel number");
+ }
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
return -1;
}
- break;
- /* force number of ranks */
- case 'r':
- conf->force_nrank = atoi(optarg);
- if (conf->force_nrank == 0 ||
- conf->force_nrank > 16) {
- EAL_LOG(ERR, "invalid rank number");
+ }
+ if (args.no_huge) {
+ int_cfg->no_hugetlbfs = 1;
+ /* no-huge is legacy mem */
+ int_cfg->legacy_mem = 1;
+ }
+ if (args.in_memory) {
+ int_cfg->in_memory = 1;
+ /* in-memory is a superset of noshconf and huge-unlink */
+ int_cfg->no_shconf = 1;
+ int_cfg->hugepage_file.unlink_before_mapping = true;
+ }
+ if (args.legacy_mem)
+ int_cfg->legacy_mem = 1;
+ if (args.single_file_segments)
+ int_cfg->single_file_segments = 1;
+ if (args.huge_dir != NULL) {
+ free(int_cfg->hugepage_dir); /* free old hugepage dir */
+ int_cfg->hugepage_dir = strdup(args.huge_dir);
+ if (int_cfg->hugepage_dir == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for hugepage dir parameter");
return -1;
}
- break;
- /* force loading of external driver */
- case 'd':
- if (eal_plugin_add(optarg) == -1)
+ }
+ if (args.file_prefix != NULL) {
+ free(int_cfg->hugefile_prefix); /* free old file prefix */
+ int_cfg->hugefile_prefix = strdup(args.file_prefix);
+ if (int_cfg->hugefile_prefix == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for file prefix parameter");
return -1;
- break;
- case 'v':
- /* since message is explicitly requested by user, we
- * write message at highest log level so it can always
- * be seen
- * even if info or warning messages are disabled */
- EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- break;
-
- /* long options */
- case OPT_HUGE_UNLINK_NUM:
- if (eal_parse_huge_unlink(optarg, &conf->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid --"OPT_HUGE_UNLINK" option");
+ }
+ }
+ if (args.numa_mem != NULL) {
+ if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
+ EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
return -1;
}
- break;
-
- case OPT_NO_HUGE_NUM:
- conf->no_hugetlbfs = 1;
- /* no-huge is legacy mem */
- conf->legacy_mem = 1;
- break;
-
- case OPT_NO_PCI_NUM:
- conf->no_pci = 1;
- break;
-
- case OPT_NO_HPET_NUM:
- conf->no_hpet = 1;
- break;
-
- case OPT_VMWARE_TSC_MAP_NUM:
- conf->vmware_tsc_map = 1;
- break;
-
- case OPT_NO_SHCONF_NUM:
- conf->no_shconf = 1;
- break;
-
- case OPT_IN_MEMORY_NUM:
- conf->in_memory = 1;
- /* in-memory is a superset of noshconf and huge-unlink */
- conf->no_shconf = 1;
- conf->hugepage_file.unlink_before_mapping = true;
- break;
-
- case OPT_PROC_TYPE_NUM:
- conf->process_type = eal_parse_proc_type(optarg);
- break;
-
- case OPT_MAIN_LCORE_NUM:
- if (eal_parse_main_lcore(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_MAIN_LCORE);
+ int_cfg->force_numa = 1;
+ }
+ if (args.numa_limit != NULL) {
+ if (eal_parse_socket_arg(args.numa_limit, int_cfg->numa_limit) < 0) {
+ EAL_LOG(ERR, "invalid numa-limit parameter: '%s'", args.numa_limit);
return -1;
}
- break;
+ int_cfg->force_numa_limits = 1;
+ }
- case OPT_VDEV_NUM:
- if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
- optarg) < 0) {
+ /* tracing settings, not supported on windows */
+#ifdef RTE_EXEC_ENV_WINDOWS
+ if (args.trace != NULL ||
+ args.trace_dir != NULL ||
+ args.trace_bufsz != NULL ||
+ args.trace_mode != NULL)
+ EAL_LOG(WARNING, "Tracing is not supported on Windows, ignoring tracing parameters");
+#else
+ if (args.trace != NULL) {
+ if (eal_trace_args_save(args.trace) < 0) {
+ EAL_LOG(ERR, "invalid trace parameter, '%s'", args.trace);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_SYSLOG_NUM:
- if (eal_log_syslog(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_SYSLOG);
+ }
+ if (args.trace_dir != NULL) {
+ if (eal_trace_dir_args_save(args.trace_dir) < 0) {
+ EAL_LOG(ERR, "invalid trace directory, '%s'", args.trace_dir);
return -1;
}
- break;
-#endif
-
- case OPT_LOG_LEVEL_NUM:
- if (eal_parse_log_level(optarg) < 0) {
- EAL_LOG(ERR,
- "invalid parameters for --"
- OPT_LOG_LEVEL);
+ }
+ if (args.trace_bufsz != NULL) {
+ if (eal_trace_bufsz_args_save(args.trace_bufsz) < 0) {
+ EAL_LOG(ERR, "invalid trace buffer size, '%s'", args.trace_bufsz);
return -1;
}
- break;
-
- case OPT_LOG_TIMESTAMP_NUM:
- if (eal_log_timestamp(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_TIMESTAMP);
+ }
+ if (args.trace_mode != NULL) {
+ if (eal_trace_mode_args_save(args.trace_mode) < 0) {
+ EAL_LOG(ERR, "invalid trace mode, '%s'", args.trace_mode);
return -1;
}
- break;
+ }
+#endif
- case OPT_LOG_COLOR_NUM:
- if (eal_log_color(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_COLOR);
+ /* simple flag settings
+ * Only set these to 1, as we don't want to set them to 0 in case
+ * other options above have already set them.
+ */
+ if (args.no_pci)
+ int_cfg->no_pci = 1;
+ if (args.no_hpet)
+ int_cfg->no_hpet = 1;
+ if (args.vmware_tsc_map)
+ int_cfg->vmware_tsc_map = 1;
+ if (args.no_shconf)
+ int_cfg->no_shconf = 1;
+ if (args.no_telemetry)
+ int_cfg->no_telemetry = 1;
+ if (args.match_allocations)
+ int_cfg->match_allocations = 1;
+ if (args.create_uio_dev)
+ int_cfg->create_uio_dev = 1;
+
+
+ /* other misc settings */
+ if (args.iova_mode != NULL) {
+ if (eal_parse_iova_mode(args.iova_mode) < 0) {
+ EAL_LOG(ERR, "invalid iova mode parameter '%s'", args.iova_mode);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_TRACE_NUM: {
- if (eal_trace_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE);
+ };
+ if (args.base_virtaddr != NULL) {
+ if (eal_parse_base_virtaddr(args.base_virtaddr) < 0) {
+ EAL_LOG(ERR, "invalid base virtaddr '%s'", args.base_virtaddr);
return -1;
}
- break;
}
-
- case OPT_TRACE_DIR_NUM: {
- if (eal_trace_dir_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_DIR);
+ if (args.force_max_simd_bitwidth != NULL) {
+ if (eal_parse_simd_bitwidth(args.force_max_simd_bitwidth) < 0) {
+ EAL_LOG(ERR, "invalid SIMD bitwidth parameter '%s'",
+ args.force_max_simd_bitwidth);
return -1;
}
- break;
}
-
- case OPT_TRACE_BUF_SIZE_NUM: {
- if (eal_trace_bufsz_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_BUF_SIZE);
+ if (args.vfio_intr != NULL) {
+ if (eal_parse_vfio_intr(args.vfio_intr) < 0) {
+ EAL_LOG(ERR, "invalid vfio interrupt parameter: '%s'", args.vfio_intr);
return -1;
}
- break;
}
-
- case OPT_TRACE_MODE_NUM: {
- if (eal_trace_mode_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_MODE);
+ if (args.vfio_vf_token != NULL) {
+ if (eal_parse_vfio_vf_token(args.vfio_vf_token) < 0) {
+ EAL_LOG(ERR, "invalid vfio vf token parameter: '%s'", args.vfio_vf_token);
return -1;
}
- break;
}
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- case OPT_LEGACY_MEM_NUM:
- conf->legacy_mem = 1;
- break;
- case OPT_SINGLE_FILE_SEGMENTS_NUM:
- conf->single_file_segments = 1;
- break;
- case OPT_IOVA_MODE_NUM:
- if (eal_parse_iova_mode(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_IOVA_MODE);
+ if (args.huge_worker_stack != NULL) {
+ if (args.huge_worker_stack == (void *)1)
+ args.huge_worker_stack = NULL;
+ if (eal_parse_huge_worker_stack(args.huge_worker_stack) < 0) {
+ EAL_LOG(ERR, "invalid huge worker stack parameter");
return -1;
}
- break;
- case OPT_BASE_VIRTADDR_NUM:
- if (eal_parse_base_virtaddr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_BASE_VIRTADDR);
+ }
+ if (args.mbuf_pool_ops_name != NULL) {
+ free(int_cfg->user_mbuf_pool_ops_name); /* free old ops name */
+ int_cfg->user_mbuf_pool_ops_name = strdup(args.mbuf_pool_ops_name);
+ if (int_cfg->user_mbuf_pool_ops_name == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
- break;
- case OPT_TELEMETRY_NUM:
- break;
- case OPT_NO_TELEMETRY_NUM:
- conf->no_telemetry = 1;
- break;
- case OPT_FORCE_MAX_SIMD_BITWIDTH_NUM:
- if (eal_parse_simd_bitwidth(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_FORCE_MAX_SIMD_BITWIDTH);
+ }
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+ /* create runtime data directory. In no_shconf mode, skip any errors */
+ if (eal_create_runtime_dir() < 0) {
+ if (int_cfg->no_shconf == 0) {
+ EAL_LOG(ERR, "Cannot create runtime directory");
return -1;
}
- break;
+ EAL_LOG(WARNING, "No DPDK runtime directory created");
+ }
+#endif
- /* don't know what to do, leave this to caller */
- default:
- return 1;
+ if (eal_adjust_config(int_cfg) != 0) {
+ EAL_LOG(ERR, "Invalid configuration");
+ return -1;
+ }
+ if (eal_check_common_options(int_cfg) != 0) {
+ EAL_LOG(ERR, "Checking common options failed");
+ return -1;
}
return 0;
-
-ba_conflict:
- EAL_LOG(ERR,
- "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
}
static void
@@ -2153,13 +2221,8 @@ eal_check_common_options(struct internal_config *internal_cfg)
"option");
return -1;
}
- if (mem_parsed && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Options -m and --"OPT_NUMA_MEM" cannot "
- "be specified at the same time");
- return -1;
- }
if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_MEM" cannot "
+ EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
"be specified together with --"OPT_NO_HUGE);
return -1;
}
@@ -2245,97 +2308,3 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth)
internal_conf->max_simd_bitwidth.bitwidth = bitwidth;
return 0;
}
-
-void
-eal_common_usage(void)
-{
- printf("[options]\n\n"
- "EAL common options:\n"
- " -c COREMASK Hexadecimal bitmask of cores to run on\n"
- " -l, --"OPT_LCORES" CORELIST\n"
- " List of cores to run on\n"
- " The basic argument format is <c1>[-c2][,c3[-c4],...]\n"
- " where c1, c2, etc are core indexes between 0 and %d\n"
- " Can also be used to map lcore set to physical CPU set\n"
- " The argument format is\n"
- " '<lcores[@cpus]>[<,lcores[@cpus]>...]'\n"
- " lcores and cpus list are grouped by '(' and ')'\n"
- " Within the group, '-' is used for range separator,\n"
- " ',' is used for single number separator.\n"
- " '( )' can be omitted for single element group,\n"
- " '@' can be omitted if cpus and lcores have the same value\n"
- " -s SERVICE COREMASK Hexadecimal bitmask of cores to be used as service cores\n"
- " --"OPT_MAIN_LCORE" ID Core ID that is used as main\n"
- " --"OPT_MBUF_POOL_OPS_NAME" Pool ops name for mbuf to use\n"
- " -n CHANNELS Number of memory channels\n"
- " -m MB Memory to allocate (see also --"OPT_NUMA_MEM")\n"
- " -r RANKS Force number of memory ranks (don't detect)\n"
- " -b, --block Add a device to the blocked list.\n"
- " Prevent EAL from using this device. The argument\n"
- " format for PCI devices is <domain:bus:devid.func>.\n"
- " -a, --allow Add a device to the allow list.\n"
- " Only use the specified devices. The argument format\n"
- " for PCI devices is <[domain:]bus:devid.func>.\n"
- " This option can be present several times.\n"
- " [NOTE: " OPT_DEV_ALLOW " cannot be used with "OPT_DEV_BLOCK" option]\n"
- " --"OPT_VDEV" Add a virtual device.\n"
- " The argument format is <driver><id>[,key=val,...]\n"
- " (ex: --vdev=net_pcap0,iface=eth2).\n"
- " --"OPT_IOVA_MODE" Set IOVA mode. 'pa' for IOVA_PA\n"
- " 'va' for IOVA_VA\n"
- " -d LIB.so|DIR Add a driver or driver directory\n"
- " (can be used multiple times)\n"
- " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n"
- " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_SYSLOG"[=<facility>] Enable use of syslog (and optionally set facility)\n"
-#endif
- " --"OPT_LOG_LEVEL"=<level> Set global log level\n"
- " --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
- " Set specific log level\n"
- " --"OPT_LOG_LEVEL"=help Show log types and levels\n"
- " --"OPT_LOG_TIMESTAMP"[=<format>] Timestamp log output\n"
- " --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_TRACE"=<regex-match>\n"
- " Enable trace based on regular expression trace name.\n"
- " By default, the trace is disabled.\n"
- " User must specify this option to enable trace.\n"
- " --"OPT_TRACE_DIR"=<directory path>\n"
- " Specify trace directory for trace output.\n"
- " By default, trace output will created at\n"
- " $HOME directory and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_BUF_SIZE"=<int>\n"
- " Specify maximum size of allocated memory\n"
- " for trace output for each thread. Valid\n"
- " unit can be either 'B|K|M' for 'Bytes',\n"
- " 'KBytes' and 'MBytes' respectively.\n"
- " Default is 1MB and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_MODE"=<o[verwrite] | d[iscard]>\n"
- " Specify the mode of update of trace\n"
- " output file. Either update on a file can\n"
- " be wrapped or discarded when file size\n"
- " reaches its maximum limit.\n"
- " Default mode is 'overwrite' and parameter\n"
- " must be specified once only.\n"
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- " -v Display version information on startup\n"
- " -h, --"OPT_HELP" This help\n"
- " --"OPT_IN_MEMORY" Operate entirely in memory. This will\n"
- " disable secondary process support\n"
- " --"OPT_BASE_VIRTADDR" Base virtual address\n"
- " --"OPT_TELEMETRY" Enable telemetry support (on by default)\n"
- " --"OPT_NO_TELEMETRY" Disable telemetry support\n"
- " --"OPT_FORCE_MAX_SIMD_BITWIDTH" Force the max SIMD bitwidth\n"
- "\nEAL options for DEBUG use only:\n"
- " --"OPT_HUGE_UNLINK"[=existing|always|never]\n"
- " When to unlink files in hugetlbfs\n"
- " ('existing' by default, no value means 'always')\n"
- " --"OPT_NO_HUGE" Use malloc instead of hugetlbfs\n"
- " --"OPT_NO_PCI" Disable PCI\n"
- " --"OPT_NO_HPET" Disable HPET\n"
- " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n"
- "\n", RTE_MAX_LCORE);
-}
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 6ef45559f0..c4d2cc84dc 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -115,18 +115,12 @@ enum {
OPT_LONG_MAX_NUM
};
-extern const char eal_short_options[];
-extern const struct option eal_long_options[];
-
-bool eal_option_is_log(int opt);
-int eal_parse_log_options(int argc, char * const argv[]);
-int eal_parse_common_option(int opt, const char *argv,
- struct internal_config *conf);
+int eal_parse_log_options(void);
+int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
int eal_check_common_options(struct internal_config *internal_cfg);
-void eal_common_usage(void);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index 5846917cc5..ab8b37b956 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -72,6 +72,17 @@ struct rte_config {
*/
struct rte_config *rte_eal_get_configuration(void);
+/**
+ * Put the argument list into a structure.
+ *
+ * This allows the arguments to then be processed out-of-order.
+ *
+ * @return
+ * - 0 on success
+ * - Negative on error
+ */
+int eal_collate_args(int argc, char **argv);
+
/**
* Initialize the memzone subsystem (private to eal).
*
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index c1ab8d86d2..ee8bf92bff 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -160,7 +160,7 @@ rte_eal_config_create(void)
cfg_len_aligned, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, mem_cfg_fd, 0);
if (mapped_mem_cfg_addr == MAP_FAILED) {
- EAL_LOG(ERR, "Cannot remap memory for rte_config");
+ EAL_LOG(ERR, "Cannot remap memory for rte_config: %s", strerror(errno));
munmap(rte_mem_cfg_addr, cfg_len);
close(mem_cfg_fd);
mem_cfg_fd = -1;
@@ -245,11 +245,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
- /* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option",
- rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
@@ -332,21 +329,6 @@ rte_config_init(void)
return 0;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
static inline size_t
eal_get_hugepage_mem_size(void)
{
@@ -367,123 +349,6 @@ eal_get_hugepage_mem_size(void)
return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX;
}
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_optreset = optreset;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
- optreset = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on FreeBSD", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on FreeBSD",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on FreeBSD", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optreset = old_optreset;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -553,8 +418,18 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* Save and collate args at the top */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("invalid command-line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -585,18 +460,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
@@ -605,8 +476,7 @@ rte_eal_init(int argc, char **argv)
/* FreeBSD always uses legacy memory model */
internal_conf->legacy_mem = true;
if (internal_conf->in_memory) {
- EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '%s'",
- OPT_IN_MEMORY);
+ EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '--in-memory'");
internal_conf->in_memory = false;
}
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 52efb8626b..f59cb43b0e 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -59,9 +59,6 @@
#include "log_internal.h"
#define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
-
-#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
-
#define KERNEL_IOMMU_GROUPS_PATH "/sys/kernel/iommu_groups"
/* define fd variable here, because file needs to be kept open for the
@@ -438,362 +435,6 @@ eal_hugedirs_unlock(void)
}
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- printf("EAL Linux options:\n"
- " --"OPT_NUMA_MEM" Memory to allocate on NUMA nodes (comma separated values)\n"
- " --"OPT_NUMA_LIMIT" Limit memory allocation on NUMA nodes (comma separated values)\n"
- " --"OPT_HUGE_DIR" Directory where hugetlbfs is mounted\n"
- " --"OPT_FILE_PREFIX" Prefix for hugepage filenames\n"
- " --"OPT_CREATE_UIO_DEV" Create /dev/uioX (usually done by hotplug)\n"
- " --"OPT_VFIO_INTR" Interrupt mode for VFIO (legacy|msi|msix)\n"
- " --"OPT_VFIO_VF_TOKEN" VF token (UUID) shared between SR-IOV PF and VFs\n"
- " --"OPT_LEGACY_MEM" Legacy memory mode (no dynamic allocation, contiguous segments)\n"
- " --"OPT_SINGLE_FILE_SEGMENTS" Put all hugepage memory in single files\n"
- " --"OPT_MATCH_ALLOCATIONS" Free hugepages exactly as allocated\n"
- " --"OPT_HUGE_WORKER_STACK"[=size]\n"
- " Allocate worker thread stacks from hugepage memory.\n"
- " Size is in units of kbytes and defaults to system\n"
- " thread stack size if not specified.\n"
- "\n");
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-static int
-eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
-{
- char * arg[RTE_MAX_NUMA_NODES];
- char *end;
- int arg_num, i, len;
-
- len = strnlen(strval, SOCKET_MEM_STRLEN);
- if (len == SOCKET_MEM_STRLEN) {
- EAL_LOG(ERR, "--socket-mem is too long");
- return -1;
- }
-
- /* all other error cases will be caught later */
- if (!isdigit(strval[len-1]))
- return -1;
-
- /* split the optarg into separate socket values */
- arg_num = rte_strsplit(strval, len,
- arg, RTE_MAX_NUMA_NODES, ',');
-
- /* if split failed, or 0 arguments */
- if (arg_num <= 0)
- return -1;
-
- /* parse each defined socket option */
- errno = 0;
- for (i = 0; i < arg_num; i++) {
- uint64_t val;
- end = NULL;
- val = strtoull(arg[i], &end, 10);
-
- /* check for invalid input */
- if ((errno != 0) ||
- (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
- return -1;
- val <<= 20;
- socket_arg[i] = val;
- }
-
- return 0;
-}
-
-static int
-eal_parse_vfio_intr(const char *mode)
-{
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
- unsigned i;
- static struct {
- const char *name;
- enum rte_intr_mode value;
- } map[] = {
- { "legacy", RTE_INTR_MODE_LEGACY },
- { "msi", RTE_INTR_MODE_MSI },
- { "msix", RTE_INTR_MODE_MSIX },
- };
-
- for (i = 0; i < RTE_DIM(map); i++) {
- if (!strcmp(mode, map[i].name)) {
- internal_conf->vfio_intr_mode = map[i].value;
- return 0;
- }
- }
- return -1;
-}
-
-static int
-eal_parse_vfio_vf_token(const char *vf_token)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
- rte_uuid_t uuid;
-
- if (!rte_uuid_parse(vf_token, uuid)) {
- rte_uuid_copy(cfg->vfio_vf_token, uuid);
- return 0;
- }
-
- return -1;
-}
-
-static int
-eal_parse_huge_worker_stack(const char *arg)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
-
- if (arg == NULL || arg[0] == '\0') {
- pthread_attr_t attr;
- int ret;
-
- if (pthread_attr_init(&attr) != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
- pthread_attr_destroy(&attr);
- if (ret != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- } else {
- unsigned long stack_size;
- char *end;
-
- errno = 0;
- stack_size = strtoul(arg, &end, 10);
- if (errno || end == NULL || stack_size == 0 ||
- stack_size >= (size_t)-1 / 1024)
- return -1;
-
- cfg->huge_worker_stack_size = stack_size * 1024;
- }
-
- EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
- cfg->huge_worker_stack_size / 1024);
- return 0;
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
-
- case OPT_HUGE_DIR_NUM:
- {
- char *hdir = strdup(optarg);
- if (hdir == NULL)
- EAL_LOG(ERR, "Could not store hugepage directory");
- else {
- /* free old hugepage dir */
- free(internal_conf->hugepage_dir);
- internal_conf->hugepage_dir = hdir;
- }
- break;
- }
- case OPT_FILE_PREFIX_NUM:
- {
- char *prefix = strdup(optarg);
- if (prefix == NULL)
- EAL_LOG(ERR, "Could not store file prefix");
- else {
- /* free old prefix */
- free(internal_conf->hugefile_prefix);
- internal_conf->hugefile_prefix = prefix;
- }
- break;
- }
- case OPT_NUMA_MEM_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_mem) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_MEM
- " (aka --"
- OPT_SOCKET_MEM
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa = 1;
- break;
-
- case OPT_NUMA_LIMIT_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_limit) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_LIMIT
- " (aka --"
- OPT_SOCKET_LIMIT
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa_limits = 1;
- break;
-
- case OPT_VFIO_INTR_NUM:
- if (eal_parse_vfio_intr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_INTR);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_VFIO_VF_TOKEN_NUM:
- if (eal_parse_vfio_vf_token(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_VF_TOKEN);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_CREATE_UIO_DEV_NUM:
- internal_conf->create_uio_dev = 1;
- break;
-
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_MATCH_ALLOCATIONS_NUM:
- internal_conf->match_allocations = 1;
- break;
-
- case OPT_HUGE_WORKER_STACK_NUM:
- if (eal_parse_huge_worker_stack(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_HUGE_WORKER_STACK);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Linux", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Linux",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Linux", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -938,8 +579,18 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -970,18 +621,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 4f0a164d9b..14547d5ac9 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -82,99 +82,6 @@ rte_mp_disable(void)
return true;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too
- * if hook is set
- */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- int ret;
-
- /* getopt is not happy, stop right now */
- if (opt == '?') {
- eal_usage(prgname);
- return -1;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- return -1;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Windows", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Windows",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Windows", opt);
- }
- eal_usage(prgname);
- return -1;
- }
- }
-
- if (eal_adjust_config(internal_conf) != 0)
- return -1;
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- return -1;
- }
-
- if (optind >= 0)
- argv[optind - 1] = prgname;
- ret = optind - 1;
- optind = 0; /* reset getopt lib */
- return ret;
-}
-
static int
sync_func(void *arg __rte_unused)
{
@@ -260,8 +167,18 @@ rte_eal_init(int argc, char **argv)
char cpuset[RTE_CPU_AFFINITY_STR_LEN];
char thread_name[RTE_THREAD_NAME_SIZE];
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -288,9 +205,11 @@ rte_eal_init(int argc, char **argv)
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0)
- exit(1);
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
if (eal_option_device_parse()) {
rte_errno = ENODEV;
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 7/9] eal: ensure proper cleanup on EAL init failure
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (15 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 6/9] eal: gather EAL args before processing Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 8/9] eal: combine parameter validation checks Bruce Richardson
` (3 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk
When rte_eal_init fails part way through, any saved EAL arguments need
to be freed, and the run_once flag needs to be set back to zero again.
The former task was never done on failure, and the latter was only done
on some occasions. Rework the error handling to always go to an err_out
label where cleanup is done.
To prevent memory leaks from the saved arguments when eal_init is called
twice, the check for multiple calls must be done first before the
argument saving and parsing is done.
This patch modifies all three eal.c files. Windows doesn't actually need
changes, since there are no args saved, and no run_once sentinel value,
but updating it keeps it consistent with FreeBSD and Linux versions.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
NOTE: this patch can probably be squashed in with the changes in the
previous one, but for easier review I've kept it separate for now.
---
lib/eal/common/eal_common_options.c | 37 ++++++++----
lib/eal/common/eal_options.h | 1 +
lib/eal/freebsd/eal.c | 83 +++++++++++++-------------
lib/eal/linux/eal.c | 90 ++++++++++++++---------------
lib/eal/windows/eal.c | 47 ++++++++-------
5 files changed, 137 insertions(+), 121 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index aea2c813ed..9c27d44a96 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -271,6 +271,8 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
int
eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+void
+eal_clean_saved_args(void) { /* no-op */ }
#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
@@ -302,6 +304,28 @@ handle_eal_info_request(const char *cmd, const char *params __rte_unused,
return used;
}
+void
+eal_clean_saved_args(void)
+{
+ int i;
+
+ if (eal_args == NULL)
+ return;
+
+ if (eal_app_args != NULL) {
+ i = 0;
+ while (eal_app_args[i] != NULL)
+ free(eal_app_args[i++]);
+ free(eal_app_args);
+ eal_app_args = NULL;
+ }
+ i = 0;
+ while (eal_args[i] != NULL)
+ free(eal_args[i++]);
+ free(eal_args);
+ eal_args = NULL;
+}
+
int
eal_save_args(int argc, char **argv)
{
@@ -346,18 +370,7 @@ eal_save_args(int argc, char **argv)
return 0;
error:
- if (eal_app_args != NULL) {
- i = 0;
- while (eal_app_args[i] != NULL)
- free(eal_app_args[i++]);
- free(eal_app_args);
- eal_app_args = NULL;
- }
- i = 0;
- while (eal_args[i] != NULL)
- free(eal_args[i++]);
- free(eal_args);
- eal_args = NULL;
+ eal_clean_saved_args();
return -1;
}
#endif /* !RTE_EXEC_ENV_WINDOWS */
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index c4d2cc84dc..fd28111e73 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -124,6 +124,7 @@ int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
+void eal_clean_saved_args(void);
int handle_eal_info_request(const char *cmd, const char *params __rte_unused,
struct rte_tel_data *d);
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index ee8bf92bff..2882d218f6 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -418,6 +418,14 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* first check if we have been run before */
+ if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
+ rte_memory_order_relaxed, rte_memory_order_relaxed)) {
+ rte_eal_init_alert("already called initialization.");
+ rte_errno = EALREADY;
+ return -1;
+ }
+
/* Save and collate args at the top */
eal_save_args(argc, argv);
@@ -425,14 +433,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("invalid command-line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(getprogname());
@@ -441,21 +449,14 @@ rte_eal_init(int argc, char **argv)
if (!rte_cpu_is_supported()) {
rte_eal_init_alert("unsupported cpu type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
- }
-
- if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
- rte_memory_order_relaxed, rte_memory_order_relaxed)) {
- rte_eal_init_alert("already called initialization.");
- rte_errno = EALREADY;
- return -1;
+ goto err_out;
}
eal_reset_internal_config(internal_conf);
@@ -463,14 +464,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
/* FreeBSD always uses legacy memory model */
@@ -483,37 +483,34 @@ rte_eal_init(int argc, char **argv)
if (eal_plugins_init() < 0) {
rte_eal_init_alert("Cannot init plugins");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_trace_init() < 0) {
rte_eal_init_alert("Cannot init trace");
rte_errno = EFAULT;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (rte_config_init() < 0) {
rte_eal_init_alert("Cannot init config");
- return -1;
+ goto err_out;
}
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_alarm_init() < 0) {
rte_eal_init_alert("Cannot init alarm");
/* rte_eal_alarm_init sets rte_errno on failure. */
- return -1;
+ goto err_out;
}
/* Put mp channel init before bus scan so that we can init the vdev
@@ -523,15 +520,14 @@ rte_eal_init(int argc, char **argv)
rte_eal_init_alert("failed to init mp channel");
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
}
if (rte_bus_scan()) {
rte_eal_init_alert("Cannot scan the buses for devices");
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
/*
@@ -562,13 +558,13 @@ rte_eal_init(int argc, char **argv)
if (iova_mode == RTE_IOVA_PA && !has_phys_addr) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (iova_mode == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
rte_eal_get_configuration()->iova_mode = iova_mode;
@@ -583,8 +579,7 @@ rte_eal_init(int argc, char **argv)
if (ret < 0) {
rte_eal_init_alert("Cannot get hugepage information.");
rte_errno = EACCES;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
}
@@ -613,7 +608,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -622,14 +617,14 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
if (rte_eal_malloc_heap_init() < 0) {
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -637,19 +632,19 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init HPET or TSC timers");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -660,7 +655,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -713,14 +708,14 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/* Probe all the buses and devices/drivers on them */
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* initialize default service/lcore mappings and start running. Ignore
@@ -729,7 +724,7 @@ rte_eal_init(int argc, char **argv)
ret = rte_service_start_with_defaults();
if (ret < 0 && ret != -ENOTSUP) {
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/*
@@ -744,18 +739,22 @@ rte_eal_init(int argc, char **argv)
*/
if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
rte_eal_init_alert("Cannot clear runtime directory");
- return -1;
+ goto err_out;
}
if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
if (rte_telemetry_init(rte_eal_get_runtime_dir(),
rte_version(),
&internal_conf->ctrl_cpuset) != 0)
- return -1;
+ goto err_out;
}
eal_mcfg_complete();
return fctret;
+err_out:
+ rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
+ eal_clean_saved_args();
+ return -1;
}
RTE_EXPORT_SYMBOL(rte_eal_cleanup)
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index f59cb43b0e..210d461497 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -579,6 +579,14 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* first check if we have been run before */
+ if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
+ rte_memory_order_relaxed, rte_memory_order_relaxed)) {
+ rte_eal_init_alert("already called initialization.");
+ rte_errno = EALREADY;
+ return -1;
+ }
+
/* clone argv to report out later in telemetry */
eal_save_args(argc, argv);
@@ -586,14 +594,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(program_invocation_short_name);
@@ -602,21 +610,14 @@ rte_eal_init(int argc, char **argv)
if (!rte_cpu_is_supported()) {
rte_eal_init_alert("unsupported cpu type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
- }
-
- if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
- rte_memory_order_relaxed, rte_memory_order_relaxed)) {
- rte_eal_init_alert("already called initialization.");
- rte_errno = EALREADY;
- return -1;
+ goto err_out;
}
eal_reset_internal_config(internal_conf);
@@ -624,49 +625,46 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
- rte_eal_init_alert("Invalid command line arguments.");
+ rte_eal_init_alert("Error parsing command line arguments.");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_plugins_init() < 0) {
rte_eal_init_alert("Cannot init plugins");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_trace_init() < 0) {
rte_eal_init_alert("Cannot init trace");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (rte_config_init() < 0) {
rte_eal_init_alert("Cannot init config");
- return -1;
+ goto err_out;
}
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_alarm_init() < 0) {
rte_eal_init_alert("Cannot init alarm");
/* rte_eal_alarm_init sets rte_errno on failure. */
- return -1;
+ goto err_out;
}
/* Put mp channel init before bus scan so that we can init the vdev
@@ -676,15 +674,14 @@ rte_eal_init(int argc, char **argv)
rte_eal_init_alert("failed to init mp channel");
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
}
if (rte_bus_scan()) {
rte_eal_init_alert("Cannot scan the buses for devices");
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
phys_addrs = rte_eal_using_phys_addrs() != 0;
@@ -727,13 +724,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_iova_mode() == RTE_IOVA_PA && !phys_addrs) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (rte_eal_iova_mode() == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
EAL_LOG(INFO, "Selected IOVA mode '%s'",
@@ -747,8 +744,7 @@ rte_eal_init(int argc, char **argv)
if (ret < 0) {
rte_eal_init_alert("Cannot get hugepage information.");
rte_errno = EACCES;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
}
@@ -772,8 +768,7 @@ rte_eal_init(int argc, char **argv)
if (rte_vfio_enable("vfio")) {
rte_eal_init_alert("Cannot init VFIO");
rte_errno = EAGAIN;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
#endif
/* in secondary processes, memory init may allocate additional fbarrays
@@ -783,7 +778,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -792,7 +787,7 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
/* the directories are locked during eal_hugepage_info_init */
@@ -802,7 +797,7 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -810,25 +805,25 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
/* register multi-process action callbacks for hotplug after memory init */
if (eal_mp_dev_hotplug_init() < 0) {
rte_eal_init_alert("failed to register mp callback for hotplug");
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init HPET or TSC timers");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -839,7 +834,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -890,14 +885,14 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/* Probe all the buses and devices/drivers on them */
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* initialize default service/lcore mappings and start running. Ignore
@@ -906,7 +901,7 @@ rte_eal_init(int argc, char **argv)
ret = rte_service_start_with_defaults();
if (ret < 0 && ret != -ENOTSUP) {
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/*
@@ -921,18 +916,23 @@ rte_eal_init(int argc, char **argv)
*/
if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
rte_eal_init_alert("Cannot clear runtime directory");
- return -1;
+ goto err_out;
}
if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
if (rte_telemetry_init(rte_eal_get_runtime_dir(),
rte_version(),
&internal_conf->ctrl_cpuset) != 0)
- return -1;
+ goto err_out;
}
eal_mcfg_complete();
return fctret;
+
+err_out:
+ rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
+ eal_clean_saved_args();
+ return -1;
}
static int
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 14547d5ac9..cd9a72a0fc 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -174,14 +174,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(NULL);
@@ -189,31 +189,31 @@ rte_eal_init(int argc, char **argv)
if (eal_create_cpu_map() < 0) {
rte_eal_init_alert("Cannot discover CPU and NUMA.");
/* rte_errno is set */
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("Unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
/* Prevent creation of shared memory files. */
@@ -227,7 +227,7 @@ rte_eal_init(int argc, char **argv)
if (!internal_conf->no_hugetlbfs && (eal_hugepage_info_init() < 0)) {
rte_eal_init_alert("Cannot get hugepage information");
rte_errno = EACCES;
- return -1;
+ goto err_out;
}
if (internal_conf->memory == 0 && !internal_conf->force_numa) {
@@ -237,26 +237,26 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init TSC timer");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
bscan = rte_bus_scan();
if (bscan < 0) {
rte_eal_init_alert("Cannot scan the buses");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (eal_mem_win32api_init() < 0) {
rte_eal_init_alert("Cannot access Win32 memory management");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
has_phys_addr = true;
@@ -289,13 +289,13 @@ rte_eal_init(int argc, char **argv)
if (iova_mode == RTE_IOVA_PA && !has_phys_addr) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (iova_mode == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
EAL_LOG(DEBUG, "Selected IOVA mode '%s'",
@@ -305,7 +305,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -314,14 +314,14 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
if (rte_eal_malloc_heap_init() < 0) {
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -329,13 +329,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -344,7 +344,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -390,13 +390,13 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/*
@@ -409,6 +409,9 @@ rte_eal_init(int argc, char **argv)
eal_mcfg_complete();
return fctret;
+err_out:
+ eal_clean_saved_args();
+ return -1;
}
/* Don't use MinGW asprintf() to have identical code with all toolchains. */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 8/9] eal: combine parameter validation checks
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (16 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
` (2 subsequent siblings)
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Anatoly Burakov, Tyler Retzlaff
Remove the separate function to check combinations of cmdline
parameters. Instead, just do those checks when parsing the parameters
since we have all info about what parameters are provided at that point.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 262 +++++++++++-----------------
lib/eal/common/eal_options.h | 107 ------------
lib/eal/linux/eal.c | 5 +-
lib/eal/linux/eal_memory.c | 2 +-
5 files changed, 106 insertions(+), 273 deletions(-)
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 38ccc734e8..c62edf5e55 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -258,8 +258,7 @@ eal_memseg_list_alloc(struct rte_memseg_list *msl, int reserve_flags)
* including common code, so don't duplicate the message.
*/
if (rte_errno == EADDRNOTAVAIL)
- EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - "
- "please use '--" OPT_BASE_VIRTADDR "' option",
+ EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - please use '--base-virtaddr' option",
(unsigned long long)mem_sz, msl->base_va);
#endif
return -1;
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 9c27d44a96..486e2ad854 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -243,7 +243,6 @@ struct device_option {
static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
-static int main_lcore_parsed;
static int core_parsed;
/* Returns rte_usage_hook_t */
@@ -751,15 +750,6 @@ eal_parse_service_coremask(const char *coremask)
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE;
j++, idx++) {
if ((1 << j) & val) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (main_lcore_parsed &&
- cfg->main_lcore == lcore) {
- EAL_LOG(ERR,
- "lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (eal_cpu_detected(idx) == 0) {
EAL_LOG(ERR,
@@ -982,15 +972,6 @@ eal_parse_service_corelist(const char *corelist)
min = idx;
for (idx = min; idx <= max; idx++) {
if (cfg->lcore_role[idx] != ROLE_SERVICE) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (cfg->main_lcore == lcore &&
- main_lcore_parsed) {
- EAL_LOG(ERR,
- "Error: lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (cfg->lcore_role[idx] == ROLE_RTE)
taken_lcore_count++;
@@ -1030,12 +1011,15 @@ eal_parse_main_lcore(const char *arg)
return -1;
if (cfg->main_lcore >= RTE_MAX_LCORE)
return -1;
- main_lcore_parsed = 1;
/* ensure main core is not used as service core */
if (lcore_config[cfg->main_lcore].core_role == ROLE_SERVICE) {
- EAL_LOG(ERR,
- "Error: Main lcore is used as a service core");
+ EAL_LOG(ERR, "Error: Main lcore is used as a service core");
+ return -1;
+ }
+ /* check that we have the core recorded in the core list */
+ if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
+ EAL_LOG(ERR, "Error: Main lcore is not enabled for DPDK");
return -1;
}
@@ -1330,11 +1314,11 @@ eal_log_usage(void)
rte_log_list_types(stdout, "\t");
printf("\n");
printf("Syntax using globbing pattern: ");
- printf("--"OPT_LOG_LEVEL" pattern:level\n");
+ printf("--log-level pattern:level\n");
printf("Syntax using regular expression: ");
- printf("--"OPT_LOG_LEVEL" regexp,level\n");
+ printf("--log-level regexp,level\n");
printf("Syntax for the global level: ");
- printf("--"OPT_LOG_LEVEL" level\n");
+ printf("--log-level level\n");
printf("Logs are emitted if allowed by both global and specific levels.\n");
printf("\n");
printf("Log level can be a number or the first letters of its name:\n");
@@ -1614,7 +1598,7 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return 0;
}
if (strcmp(arg, HUGE_UNLINK_NEVER) == 0) {
- EAL_LOG(WARNING, "Using --"OPT_HUGE_UNLINK"="
+ EAL_LOG(WARNING, "Using --huge-unlink="
HUGE_UNLINK_NEVER" may create data leaks.");
out->unlink_existing = false;
return 0;
@@ -1793,6 +1777,7 @@ int
eal_parse_args(void)
{
struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
/* check for conflicting options */
@@ -1818,19 +1803,62 @@ eal_parse_args(void)
}
/* can't have both -m and --socket-mem */
if (args.memory_size != NULL && args.numa_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ EAL_LOG(ERR, "Options -m and --numa-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use both no-huge and socket-mem */
+ if (args.no_huge && args.numa_mem) {
+ EAL_LOG(ERR, "Options --no-huge and --numa-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-worker-stack */
+ if (args.huge_worker_stack != NULL && args.no_huge) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
+ return -1;
+ }
+ /* can't use socket-limit and legacy-mem */
+ if (args.numa_limit != NULL && args.legacy_mem) {
+ EAL_LOG(ERR, "Options --numa-limit and --legacy-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and in-memory */
+ if (args.legacy_mem && args.in_memory) {
+ EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and match-allocations */
+ if (args.legacy_mem && args.match_allocations) {
+ EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and match-allocations */
+ if (args.no_huge && args.match_allocations) {
+ EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-unlink */
+ if (args.no_huge && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use single-file-segments and huge-unlink */
+ if (args.single_file_segments && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use in-memory and huge-unlink */
+ if (args.in_memory && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
return -1;
}
- /* parse options */
/* print version before anything else */
- if (args.version) {
- /* since message is explicitly requested by user, we write message
- * at highest log level so it can always be seen even if info or
- * warning messages are disabled
- */
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ if (args.version)
EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- }
/* parse the process type */
if (args.proc_type != NULL) {
@@ -1856,7 +1884,7 @@ eal_parse_args(void)
if (eal_plugin_add(arg->arg) < 0)
return -1;
- /* parse the coremask /core-list */
+ /* parse the core list arguments */
if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
@@ -1880,13 +1908,6 @@ eal_parse_args(void)
}
core_parsed = 1;
}
- if (args.main_lcore != NULL) {
- if (eal_parse_main_lcore(args.main_lcore) < 0) {
- EAL_LOG(ERR, "invalid main-lcore parameter");
- return -1;
- }
- }
-
/* service core options */
if (args.service_coremask != NULL) {
if (eal_parse_service_coremask(args.service_coremask) < 0) {
@@ -1901,6 +1922,17 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0)
+ return -1;
+ } else {
+ /* default main lcore is the first one */
+ rte_cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
+ if (rte_cfg->main_lcore >= RTE_MAX_LCORE) {
+ EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
+ return -1;
+ }
+ }
/* memory options */
if (args.memory_size != NULL) {
@@ -1922,14 +1954,6 @@ eal_parse_args(void)
return -1;
}
}
- if (args.huge_unlink != NULL) {
- if (args.huge_unlink == (void *)1)
- args.huge_unlink = NULL;
- if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid huge-unlink parameter");
- return -1;
- }
- }
if (args.no_huge) {
int_cfg->no_hugetlbfs = 1;
/* no-huge is legacy mem */
@@ -1941,11 +1965,18 @@ eal_parse_args(void)
int_cfg->no_shconf = 1;
int_cfg->hugepage_file.unlink_before_mapping = true;
}
- if (args.legacy_mem)
+ if (args.legacy_mem) {
int_cfg->legacy_mem = 1;
+ if (args.memory_size == NULL && args.numa_mem == NULL)
+ EAL_LOG(NOTICE, "Static memory layout is selected, amount of reserved memory can be adjusted with -m or --socket-mem");
+ }
if (args.single_file_segments)
int_cfg->single_file_segments = 1;
if (args.huge_dir != NULL) {
+ if (strlen(args.huge_dir) < 1) {
+ EAL_LOG(ERR, "Invalid hugepage dir parameter");
+ return -1;
+ }
free(int_cfg->hugepage_dir); /* free old hugepage dir */
int_cfg->hugepage_dir = strdup(args.huge_dir);
if (int_cfg->hugepage_dir == NULL) {
@@ -1954,6 +1985,14 @@ eal_parse_args(void)
}
}
if (args.file_prefix != NULL) {
+ if (strlen(args.file_prefix) < 1) {
+ EAL_LOG(ERR, "Invalid file prefix parameter");
+ return -1;
+ }
+ if (strchr(args.file_prefix, '%') != NULL) {
+ EAL_LOG(ERR, "Invalid char, '%%', in file_prefix parameter");
+ return -1;
+ }
free(int_cfg->hugefile_prefix); /* free old file prefix */
int_cfg->hugefile_prefix = strdup(args.file_prefix);
if (int_cfg->hugefile_prefix == NULL) {
@@ -1961,6 +2000,14 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
+ return -1;
+ }
+ }
if (args.numa_mem != NULL) {
if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
@@ -2078,6 +2125,10 @@ eal_parse_args(void)
EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
+ if (strlen(int_cfg->user_mbuf_pool_ops_name) < 1) {
+ EAL_LOG(ERR, "Invalid mbuf pool ops name parameter");
+ return -1;
+ }
}
#ifndef RTE_EXEC_ENV_WINDOWS
@@ -2096,11 +2147,6 @@ eal_parse_args(void)
return -1;
}
- if (eal_check_common_options(int_cfg) != 0) {
- EAL_LOG(ERR, "Checking common options failed");
- return -1;
- }
-
return 0;
}
@@ -2180,14 +2226,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
if (internal_conf->process_type == RTE_PROC_AUTO)
internal_conf->process_type = eal_proc_type_detect();
- /* default main lcore is the first one */
- if (!main_lcore_parsed) {
- cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
- if (cfg->main_lcore >= RTE_MAX_LCORE)
- return -1;
- lcore_config[cfg->main_lcore].core_role = ROLE_RTE;
- }
-
compute_ctrl_threads_cpuset(internal_cfg);
/* if no memory amounts were requested, this will result in 0 and
@@ -2198,102 +2236,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
return 0;
}
-int
-eal_check_common_options(struct internal_config *internal_cfg)
-{
- struct rte_config *cfg = rte_eal_get_configuration();
- const struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
- EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
- return -1;
- }
-
- if (internal_cfg->process_type == RTE_PROC_INVALID) {
- EAL_LOG(ERR, "Invalid process type specified");
- return -1;
- }
- if (internal_cfg->hugefile_prefix != NULL &&
- strlen(internal_cfg->hugefile_prefix) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_FILE_PREFIX " option");
- return -1;
- }
- if (internal_cfg->hugepage_dir != NULL &&
- strlen(internal_cfg->hugepage_dir) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_HUGE_DIR" option");
- return -1;
- }
- if (internal_cfg->user_mbuf_pool_ops_name != NULL &&
- strlen(internal_cfg->user_mbuf_pool_ops_name) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_MBUF_POOL_OPS_NAME" option");
- return -1;
- }
- if (strchr(eal_get_hugefile_prefix(), '%') != NULL) {
- EAL_LOG(ERR, "Invalid char, '%%', in --"OPT_FILE_PREFIX" "
- "option");
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_UNLINK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->huge_worker_stack_size != 0) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_WORKER_STACK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_conf->force_numa_limits && internal_conf->legacy_mem) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_LIMIT
- " is only supported in non-legacy memory mode");
- }
- if (internal_cfg->single_file_segments &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
- "not compatible with --"OPT_HUGE_UNLINK);
- return -1;
- }
- if (!internal_cfg->hugepage_file.unlink_existing &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_IN_MEMORY" is not compatible "
- "with --"OPT_HUGE_UNLINK"="HUGE_UNLINK_NEVER);
- return -1;
- }
- if (internal_cfg->legacy_mem &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_IN_MEMORY);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_NO_HUGE" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->memory == 0) {
- EAL_LOG(NOTICE, "Static memory layout is selected, "
- "amount of reserved memory can be adjusted with "
- "-m or --"OPT_NUMA_MEM);
- }
-
- return 0;
-}
-
RTE_EXPORT_SYMBOL(rte_vect_get_max_simd_bitwidth)
uint16_t
rte_vect_get_max_simd_bitwidth(void)
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index fd28111e73..4a8a0f1df7 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -9,118 +9,11 @@
struct rte_tel_data;
-enum {
- /* long options mapped to a short option */
-#define OPT_HELP "help"
- OPT_HELP_NUM = 'h',
-#define OPT_DEV_ALLOW "allow"
- OPT_DEV_ALLOW_NUM = 'a',
-#define OPT_DEV_BLOCK "block"
- OPT_DEV_BLOCK_NUM = 'b',
-#define OPT_COREMASK "coremask"
- OPT_COREMASK_NUM = 'c',
-#define OPT_DRIVER_PATH "driver-path"
- OPT_DRIVER_PATH_NUM = 'd',
-#define OPT_LCORES "lcores"
- OPT_LCORES_NUM = 'l',
-#define OPT_MEMORY_SIZE "memory-size"
- OPT_MEMORY_SIZE_NUM = 'm',
-#define OPT_MEMORY_CHANNELS "memory-channels"
- OPT_MEMORY_CHANNELS_NUM = 'n',
-#define OPT_MEMORY_RANKS "memory-ranks"
- OPT_MEMORY_RANKS_NUM = 'r',
-#define OPT_SERVICE_COREMASK "service-coremask"
- OPT_SERVICE_COREMASK_NUM = 's',
-#define OPT_SERVICE_CORELIST "service-corelist"
- OPT_SERVICE_CORELIST_NUM = 'S',
-#define OPT_VERSION "version"
- OPT_VERSION_NUM = 'v',
-
- /* first long only option value must be >= 256, so that we won't
- * conflict with short options */
- OPT_LONG_MIN_NUM = 256,
-#define OPT_BASE_VIRTADDR "base-virtaddr"
- OPT_BASE_VIRTADDR_NUM,
-#define OPT_CREATE_UIO_DEV "create-uio-dev"
- OPT_CREATE_UIO_DEV_NUM,
-#define OPT_FILE_PREFIX "file-prefix"
- OPT_FILE_PREFIX_NUM,
-#define OPT_HUGE_DIR "huge-dir"
- OPT_HUGE_DIR_NUM,
-#define OPT_HUGE_UNLINK "huge-unlink"
- OPT_HUGE_UNLINK_NUM,
-#define OPT_LOG_COLOR "log-color"
- OPT_LOG_COLOR_NUM,
-#define OPT_LOG_LEVEL "log-level"
- OPT_LOG_LEVEL_NUM,
-#define OPT_LOG_TIMESTAMP "log-timestamp"
- OPT_LOG_TIMESTAMP_NUM,
-#define OPT_TRACE "trace"
- OPT_TRACE_NUM,
-#define OPT_TRACE_DIR "trace-dir"
- OPT_TRACE_DIR_NUM,
-#define OPT_TRACE_BUF_SIZE "trace-bufsz"
- OPT_TRACE_BUF_SIZE_NUM,
-#define OPT_TRACE_MODE "trace-mode"
- OPT_TRACE_MODE_NUM,
-#define OPT_MAIN_LCORE "main-lcore"
- OPT_MAIN_LCORE_NUM,
-#define OPT_MBUF_POOL_OPS_NAME "mbuf-pool-ops-name"
- OPT_MBUF_POOL_OPS_NAME_NUM,
-#define OPT_PROC_TYPE "proc-type"
- OPT_PROC_TYPE_NUM,
-#define OPT_NO_HPET "no-hpet"
- OPT_NO_HPET_NUM,
-#define OPT_NO_HUGE "no-huge"
- OPT_NO_HUGE_NUM,
-#define OPT_NO_PCI "no-pci"
- OPT_NO_PCI_NUM,
-#define OPT_NO_SHCONF "no-shconf"
- OPT_NO_SHCONF_NUM,
-#define OPT_IN_MEMORY "in-memory"
- OPT_IN_MEMORY_NUM,
-#define OPT_SOCKET_MEM "socket-mem"
-#define OPT_NUMA_MEM "numa-mem"
- OPT_NUMA_MEM_NUM,
-#define OPT_SOCKET_LIMIT "socket-limit"
-#define OPT_NUMA_LIMIT "numa-limit"
- OPT_NUMA_LIMIT_NUM,
-#define OPT_SYSLOG "syslog"
- OPT_SYSLOG_NUM,
-#define OPT_VDEV "vdev"
- OPT_VDEV_NUM,
-#define OPT_VFIO_INTR "vfio-intr"
- OPT_VFIO_INTR_NUM,
-#define OPT_VFIO_VF_TOKEN "vfio-vf-token"
- OPT_VFIO_VF_TOKEN_NUM,
-#define OPT_VMWARE_TSC_MAP "vmware-tsc-map"
- OPT_VMWARE_TSC_MAP_NUM,
-#define OPT_LEGACY_MEM "legacy-mem"
- OPT_LEGACY_MEM_NUM,
-#define OPT_SINGLE_FILE_SEGMENTS "single-file-segments"
- OPT_SINGLE_FILE_SEGMENTS_NUM,
-#define OPT_IOVA_MODE "iova-mode"
- OPT_IOVA_MODE_NUM,
-#define OPT_MATCH_ALLOCATIONS "match-allocations"
- OPT_MATCH_ALLOCATIONS_NUM,
-#define OPT_TELEMETRY "telemetry"
- OPT_TELEMETRY_NUM,
-#define OPT_NO_TELEMETRY "no-telemetry"
- OPT_NO_TELEMETRY_NUM,
-#define OPT_FORCE_MAX_SIMD_BITWIDTH "force-max-simd-bitwidth"
- OPT_FORCE_MAX_SIMD_BITWIDTH_NUM,
-#define OPT_HUGE_WORKER_STACK "huge-worker-stack"
- OPT_HUGE_WORKER_STACK_NUM,
-
- OPT_LONG_MAX_NUM
-};
-
int eal_parse_log_options(void);
int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
-int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 210d461497..babd36bf37 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -329,9 +329,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
/* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option", rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index e433c1afee..a366083822 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -1967,7 +1967,7 @@ rte_eal_memseg_init(void)
if (!internal_conf->legacy_mem && rte_socket_count() > 1) {
EAL_LOG(WARNING, "DPDK is running on a NUMA system, but is compiled without NUMA support.");
EAL_LOG(WARNING, "This will have adverse consequences for performance and usability.");
- EAL_LOG(WARNING, "Please use --"OPT_LEGACY_MEM" option, or recompile with NUMA support.");
+ EAL_LOG(WARNING, "Please use --legacy-mem option, or recompile with NUMA support.");
}
#endif
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v4 9/9] eal: simplify handling of conflicting cmdline options
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (17 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 8/9] eal: combine parameter validation checks Bruce Richardson
@ 2025-07-21 15:08 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
20 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:08 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
Use a utility function and macro to simplify the code for checking for
conflicting cmdline options. The checking can also be done at the
initial argument collating stage, shortening the argument
processing function which is very much on the long side.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 119 +++++++++++-----------------
1 file changed, 47 insertions(+), 72 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 486e2ad854..c568e59ef3 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -178,6 +178,29 @@ struct rte_argparse eal_argparse = {
}
};
+static inline bool
+conflicting_options(uintptr_t opt1, uintptr_t opt2, const char *opt1_name, const char *opt2_name)
+{
+ char name1[64]; /* should be the max length of any argument */
+ char name2[64];
+
+ strlcpy(name1, opt1_name, sizeof(name1));
+ strlcpy(name2, opt2_name, sizeof(name2));
+ for (int i = 0; name1[i] != '\0'; i++)
+ if (name1[i] == '_')
+ name1[i] = '-';
+ for (int i = 0; name2[i] != '\0'; i++)
+ if (name2[i] == '_')
+ name2[i] = '-';
+ if (opt1 && opt2) {
+ EAL_LOG(ERR, "Options '%s' and '%s' can't be used at the same time", name1, name2);
+ return true;
+ }
+ return false; /* no conflicts */
+}
+#define CONFLICTING_OPTIONS(args, opt1, opt2) \
+ conflicting_options((uintptr_t)(args.opt1), (uintptr_t)(args.opt2), #opt1, #opt2)
+
/* function to call into argparse library to parse the passed argc/argv parameters
* to the eal_init_args structure.
*/
@@ -200,6 +223,30 @@ eal_collate_args(int argc, char **argv)
if (retval < 0)
return retval;
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+
+ /* for non-list args, we can just check for zero/null values using macro */
+ if (CONFLICTING_OPTIONS(args, coremask, lcores) ||
+ CONFLICTING_OPTIONS(args, service_coremask, service_corelist) ||
+ CONFLICTING_OPTIONS(args, no_telemetry, telemetry) ||
+ CONFLICTING_OPTIONS(args, memory_size, numa_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, numa_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_worker_stack) ||
+ CONFLICTING_OPTIONS(args, numa_limit, legacy_mem) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, in_memory) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, single_file_segments, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, no_huge, single_file_segments) ||
+ CONFLICTING_OPTIONS(args, in_memory, huge_unlink))
+ return -1;
+
argv[retval - 1] = argv[0];
return retval - 1;
}
@@ -1780,78 +1827,6 @@ eal_parse_args(void)
struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
- /* check for conflicting options */
- /* both -a and -b cannot be used together (one list must be empty at least) */
- if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
- EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
- }
- /* both -l and -c cannot be used at the same time */
- if (args.coremask != NULL && args.lcores != NULL) {
- EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
- return -1;
- }
- /* both -s and -S cannot be used at the same time */
- if (args.service_coremask != NULL && args.service_corelist != NULL) {
- EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
- return -1;
- }
- /* can't have both telemetry and no-telemetry */
- if (args.no_telemetry && args.telemetry) {
- EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
- return -1;
- }
- /* can't have both -m and --socket-mem */
- if (args.memory_size != NULL && args.numa_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --numa-mem can't be used at the same time");
- return -1;
- }
- /* can't use both no-huge and socket-mem */
- if (args.no_huge && args.numa_mem) {
- EAL_LOG(ERR, "Options --no-huge and --numa-mem can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-worker-stack */
- if (args.huge_worker_stack != NULL && args.no_huge) {
- EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
- return -1;
- }
- /* can't use socket-limit and legacy-mem */
- if (args.numa_limit != NULL && args.legacy_mem) {
- EAL_LOG(ERR, "Options --numa-limit and --legacy-mem can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and in-memory */
- if (args.legacy_mem && args.in_memory) {
- EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and match-allocations */
- if (args.legacy_mem && args.match_allocations) {
- EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and match-allocations */
- if (args.no_huge && args.match_allocations) {
- EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-unlink */
- if (args.no_huge && args.huge_unlink) {
- EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use single-file-segments and huge-unlink */
- if (args.single_file_segments && args.huge_unlink) {
- EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use in-memory and huge-unlink */
- if (args.in_memory && args.huge_unlink) {
- EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
- return -1;
- }
-
/* print version before anything else */
/* since message is explicitly requested by user, we write message
* at highest log level so it can always be seen even if info or
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 0/9] rework EAL argument parsing
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (18 preceding siblings ...)
2025-07-21 15:08 ` [PATCH v4 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 1/9] build: add define for the OS environment name Bruce Richardson
` (8 more replies)
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
20 siblings, 9 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
When processing cmdline arguments in DPDK, we always do so with very
little context. So, for example, when processing the "-l" flag, we have
no idea whether there will be later a --proc-type=secondary flag. We
have all sorts of post-arg-processing checks in place to try and catch
these scenarios.
To improve this situation, this patchset tries to simplify the handling
of argument processing, by explicitly doing an initial pass to collate
all arguments into a structure. Thereafter, the actual arg parsing is
done in a fixed order, meaning that e.g. when processing the
--main-lcore flag, we have already processed the service core flags. We
also can far quicker and easier check for conflicting options, since
they can all be checked for NULL/non-NULL in the arg structure
immediately after the struct has been populated.
To do the initial argument gathering, this RFC uses the existing
argparse library in DPDK. With recent changes, and two additional
patches at the start of this set, this library now meets our needs for
EAL argument parsing and allows us to not need to do direct getopt
argument processing inside EAL at all.
An additional benefit of this work is that the argument parsing for EAL
is much more centralised into common options and the options list file.
This single list with ifdefs makes it clear to the viewer what options
are common across OS's, vs what are unix-only or linux-only.
V5:
* Resubmit of V4, which didn't get sent correctly, or picked up correctly
in patchwork.
V4:
* Updated patch 5 to auto-generate the arg struct definition from the same
list of defines used to construct the argument list.
V3:
* Added 3 new initial patches, one for minor build-system addition, and two
for functionality in argparse to allow the user-callback help function to
be maintained as we move to argparse.
* Added doc updates in the first EAL patch adding the long options
* Fixed ASAN issues by adding a patch to properly clean up EAL init - both
memory allocations and fixing the run-once flag
* Put ifdefs around the linux-only or unix-only options in EAL patch 2
* Updated args to handle numa-mem and numa-limit as equivalent socket-mem
and socket-limit
Bruce Richardson (9):
build: add define for the OS environment name
argparse: export function to print help text for object
argparse: allow user-override of help printing
eal: add long options for each short option
eal: define the EAL parameters in argparse format
eal: gather EAL args before processing
eal: ensure proper cleanup on EAL init failure
eal: combine parameter validation checks
eal: simplify handling of conflicting cmdline options
config/meson.build | 1 +
doc/guides/contributing/design.rst | 2 +-
doc/guides/linux_gsg/eal_args.include.rst | 20 +-
doc/guides/prog_guide/argparse_lib.rst | 16 +
lib/argparse/rte_argparse.c | 46 +-
lib/argparse/rte_argparse.h | 21 +-
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 1217 +++++++++++----------
lib/eal/common/eal_option_list.h | 90 ++
lib/eal/common/eal_options.h | 102 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 245 +----
lib/eal/linux/eal.c | 470 +-------
lib/eal/linux/eal_memory.c | 2 +-
lib/eal/meson.build | 2 +-
lib/eal/windows/eal.c | 156 +--
lib/meson.build | 1 +
17 files changed, 960 insertions(+), 1445 deletions(-)
create mode 100644 lib/eal/common/eal_option_list.h
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 1/9] build: add define for the OS environment name
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 2/9] argparse: export function to print help text for object Bruce Richardson
` (7 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
Introduce a string define for the currently running OS, or execution
environment.
Originally, with old make build system, CONFIG_RTE_EXEC_ENV used to hold
this name string, but the variable seems to have been missed in the
meson build system, until commit cadb255e25d6 ("eal: add OS defines for
C conditional checks") which introduced the RTE_EXEC_ENV for a different
purpose. Now we can fix the docs with the new name reference.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
config/meson.build | 1 +
doc/guides/contributing/design.rst | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/config/meson.build b/config/meson.build
index f31fef216c..40f33816aa 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -20,6 +20,7 @@ foreach env, id:exec_envs
dpdk_conf.set10('RTE_EXEC_ENV_IS_' + env.to_upper(), (exec_env == env))
endforeach
dpdk_conf.set('RTE_EXEC_ENV', exec_envs[exec_env])
+dpdk_conf.set_quoted('RTE_EXEC_ENV_NAME', exec_env)
dpdk_conf.set('RTE_EXEC_ENV_' + exec_env.to_upper(), 1)
# MS linker requires special treatment.
diff --git a/doc/guides/contributing/design.rst b/doc/guides/contributing/design.rst
index b724177ba1..5517613424 100644
--- a/doc/guides/contributing/design.rst
+++ b/doc/guides/contributing/design.rst
@@ -50,7 +50,7 @@ Per Execution Environment Sources
The following macro options can be used:
-* ``RTE_EXEC_ENV`` is a string that contains the name of the executive environment.
+* ``RTE_EXEC_ENV_NAME`` is a string that contains the name of the executive environment.
* ``RTE_EXEC_ENV_FREEBSD``, ``RTE_EXEC_ENV_LINUX`` or ``RTE_EXEC_ENV_WINDOWS`` are defined only if we are building for this execution environment.
Mbuf features
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 2/9] argparse: export function to print help text for object
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 1/9] build: add define for the OS environment name Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 3/9] argparse: allow user-override of help printing Bruce Richardson
` (6 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
Make the function to print out the help text for an argparse object a
public function, which takes as a new parameter the file stream on which
to print. This can be used in future to allow application to extend
their own help information.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/argparse/rte_argparse.c | 43 +++++++++++++++++++------------------
lib/argparse/rte_argparse.h | 14 ++++++++++++
2 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index 331f05f01d..d3b32c6357 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -716,23 +716,23 @@ calc_help_align(const struct rte_argparse *obj)
}
static void
-show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width)
+show_oneline_help(FILE *stream, const struct rte_argparse_arg *arg, uint32_t width)
{
uint32_t len = 0;
uint32_t i;
if (arg->name_short != NULL)
- len = printf(" %s,", arg->name_short);
- len += printf(" %s", arg->name_long);
+ len = fprintf(stream, " %s,", arg->name_short);
+ len += fprintf(stream, " %s", arg->name_long);
for (i = len; i < width; i++)
- printf(" ");
+ fprintf(stream, " ");
- printf("%s\n", arg->help);
+ fprintf(stream, "%s\n", arg->help);
}
static void
-show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
+show_args_pos_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
{
uint32_t position_count = calc_position_count(obj);
const struct rte_argparse_arg *arg;
@@ -741,19 +741,19 @@ show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
if (position_count == 0)
return;
- printf("\npositional arguments:\n");
+ fprintf(stream, "\npositional arguments:\n");
for (i = 0; /* NULL */; i++) {
arg = &obj->args[i];
if (arg->name_long == NULL)
break;
if (!is_arg_positional(arg))
continue;
- show_oneline_help(arg, align);
+ show_oneline_help(stream, arg, align);
}
}
static void
-show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
+show_args_opt_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
{
static const struct rte_argparse_arg help = {
.name_long = "--help",
@@ -763,34 +763,35 @@ show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
const struct rte_argparse_arg *arg;
uint32_t i;
- printf("\noptions:\n");
- show_oneline_help(&help, align);
+ fprintf(stream, "\noptions:\n");
+ show_oneline_help(stream, &help, align);
for (i = 0; /* NULL */; i++) {
arg = &obj->args[i];
if (arg->name_long == NULL)
break;
if (!is_arg_optional(arg))
continue;
- show_oneline_help(arg, align);
+ show_oneline_help(stream, arg, align);
}
}
-static void
-show_args_help(const struct rte_argparse *obj)
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_print_help, 25.07)
+void
+rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj)
{
uint32_t align = calc_help_align(obj);
- printf("usage: %s %s\n", obj->prog_name, obj->usage);
+ fprintf(stream, "usage: %s %s\n", obj->prog_name, obj->usage);
if (obj->descriptor != NULL)
- printf("\ndescriptor: %s\n", obj->descriptor);
+ fprintf(stream, "\ndescriptor: %s\n", obj->descriptor);
- show_args_pos_help(obj, align);
- show_args_opt_help(obj, align);
+ show_args_pos_help(stream, obj, align);
+ show_args_opt_help(stream, obj, align);
if (obj->epilog != NULL)
- printf("\n%s\n", obj->epilog);
+ fprintf(stream, "\n%s\n", obj->epilog);
else
- printf("\n");
+ fprintf(stream, "\n");
}
RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_parse, 24.03)
@@ -820,7 +821,7 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
goto error;
if (show_help) {
- show_args_help(obj);
+ rte_argparse_print_help(stdout, obj);
exit(0);
}
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index 52bef34363..baf278f6b9 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -189,6 +189,20 @@ struct rte_argparse {
__rte_experimental
int rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Output the help text information for the given argparse object.
+ *
+ * @param stream
+ * Output file handle, e.g. stdout, stderr, on which to print the help text.
+ * @param obj
+ * Parser object.
+ */
+__rte_experimental
+void rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj);
+
/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 3/9] argparse: allow user-override of help printing
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 1/9] build: add define for the OS environment name Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 2/9] argparse: export function to print help text for object Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 4/9] eal: add long options for each short option Bruce Richardson
` (5 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
When the arguments passed to argparse include -h/--help then usage
information is automatically printed. Provide the capability for the
user to supply their own help function for this.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
doc/guides/prog_guide/argparse_lib.rst | 16 ++++++++++++++++
lib/argparse/rte_argparse.c | 5 ++++-
lib/argparse/rte_argparse.h | 7 ++++++-
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/doc/guides/prog_guide/argparse_lib.rst b/doc/guides/prog_guide/argparse_lib.rst
index 9f11714890..b309260d20 100644
--- a/doc/guides/prog_guide/argparse_lib.rst
+++ b/doc/guides/prog_guide/argparse_lib.rst
@@ -24,6 +24,8 @@ Features and Capabilities
#. autosave: used for parsing known value types;
#. callback: will invoke user callback to parse.
+- Supports automatic help and usage information.
+
Usage Guide
-----------
@@ -193,3 +195,17 @@ Then the user input could contain multiple ``--xyz`` arguments.
The multiple times argument only support with optional argument
and must be parsed by callback way.
+
+Help and Usage Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The argparse library supports automatic generation of help and usage information.
+When the input arguments include ``-h`` or ``--help``,
+it will print the usage information to standard output.
+If the default help output is not what is wanted,
+the user can provide a custom help printing function by setting the ``print_help`` field in the ``rte_argparse`` object.
+(If this field is set to NULL, the default help printing function will be used.)
+
+If the custom help printing function wants to use the text produced by the default help function,
+it can call the function ``rte_argparse_print_help()`` to get the help text printed to an output stream,
+for example: stdout or stderr.
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index d3b32c6357..e7b9bf573d 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -821,7 +821,10 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
goto error;
if (show_help) {
- rte_argparse_print_help(stdout, obj);
+ if (obj->print_help != NULL)
+ obj->print_help(obj);
+ else
+ rte_argparse_print_help(stdout, obj);
exit(0);
}
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index baf278f6b9..63b49ba220 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -160,8 +160,13 @@ struct rte_argparse {
rte_arg_parser_t callback;
/** Opaque which used to invoke callback. */
void *opaque;
+ /**
+ * Function pointer for printing usage when -h is passed.
+ * If this is NULL, default printing function will be used.
+ */
+ void (*print_help)(const struct rte_argparse *obj);
/** Reserved field used for future extension. */
- void *reserved[16];
+ void *reserved[15];
/** Arguments configuration. Must ended with ARGPARSE_ARG_END(). */
struct rte_argparse_arg args[];
};
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 4/9] eal: add long options for each short option
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
` (2 preceding siblings ...)
2025-07-21 15:16 ` [PATCH v5 3/9] argparse: allow user-override of help printing Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
` (4 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
To simplify future rework of the EAL arg handling, add a long-option
equivalent for each short option that doesn't already have one.
When updating the docs with the new long options, standardize the format
of options which have both short and long variants, and drop the
deprecated service-coremask option from the docs, rather than adding its
new long option.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
doc/guides/linux_gsg/eal_args.include.rst | 20 ++++++++------------
lib/eal/common/eal_common_options.c | 9 +++++++++
lib/eal/common/eal_options.h | 16 ++++++++++++++++
3 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/doc/guides/linux_gsg/eal_args.include.rst b/doc/guides/linux_gsg/eal_args.include.rst
index 9ced54af40..0b17879d42 100644
--- a/doc/guides/linux_gsg/eal_args.include.rst
+++ b/doc/guides/linux_gsg/eal_args.include.rst
@@ -4,7 +4,7 @@
Lcore-related options
~~~~~~~~~~~~~~~~~~~~~
-* ``-l/--lcores <core list>``
+* ``-l, --lcores <core list>``
List of cores to run on
@@ -71,11 +71,7 @@ Lcore-related options
Core ID that is used as main.
-* ``-s <service core mask>``
-
- Hexadecimal bitmask of cores to be used as service cores.
-
-* ``-S <service core list>``
+* ``-S, --service-corelist <service core list>``
List of cores to be used as service cores.
@@ -108,7 +104,7 @@ Device-related options
--vdev 'net_pcap0,rx_pcap=input.pcap,tx_pcap=output.pcap'
-* ``-d <path to shared object or directory>``
+* ``-d, --driver-path <path to shared object or directory>``
Load external drivers. An argument can be a single shared object file, or a
directory containing multiple driver shared objects. Multiple -d options are
@@ -134,15 +130,15 @@ Multiprocessing-related options
Memory-related options
~~~~~~~~~~~~~~~~~~~~~~
-* ``-n <number of channels>``
+* ``-n, --memory-channels <number of channels>``
Set the number of memory channels to use.
-* ``-r <number of ranks>``
+* ``-r, --memory-ranks <number of ranks>``
Set the number of memory ranks (auto-detected by default).
-* ``-m <megabytes>``
+* ``-m, --memory-size <megabytes>``
Amount of memory to preallocate at startup.
@@ -236,11 +232,11 @@ Debugging options
Other options
~~~~~~~~~~~~~
-* ``-h``, ``--help``
+* ``-h, --help``
Display help message listing all EAL parameters.
-* ``-v``
+* ``-v, --version``
Display the version information on startup.
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index f0a9ddeeb7..cafae9d9d7 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -66,7 +66,9 @@ eal_short_options[] =
const struct option
eal_long_options[] = {
{OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
+ {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
{OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
+ {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
{OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
{OPT_HELP, 0, NULL, OPT_HELP_NUM },
{OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
@@ -76,6 +78,11 @@ eal_long_options[] = {
{OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
{OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
{OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
+ {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
+ {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
+ {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
+ {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
+ {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
{OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
{OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
{OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
@@ -109,6 +116,8 @@ eal_long_options[] = {
{OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
{OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
{OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
+ {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
+
{0, 0, NULL, 0 }
};
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 7a56aa3810..6ef45559f0 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -17,8 +17,24 @@ enum {
OPT_DEV_ALLOW_NUM = 'a',
#define OPT_DEV_BLOCK "block"
OPT_DEV_BLOCK_NUM = 'b',
+#define OPT_COREMASK "coremask"
+ OPT_COREMASK_NUM = 'c',
+#define OPT_DRIVER_PATH "driver-path"
+ OPT_DRIVER_PATH_NUM = 'd',
#define OPT_LCORES "lcores"
OPT_LCORES_NUM = 'l',
+#define OPT_MEMORY_SIZE "memory-size"
+ OPT_MEMORY_SIZE_NUM = 'm',
+#define OPT_MEMORY_CHANNELS "memory-channels"
+ OPT_MEMORY_CHANNELS_NUM = 'n',
+#define OPT_MEMORY_RANKS "memory-ranks"
+ OPT_MEMORY_RANKS_NUM = 'r',
+#define OPT_SERVICE_COREMASK "service-coremask"
+ OPT_SERVICE_COREMASK_NUM = 's',
+#define OPT_SERVICE_CORELIST "service-corelist"
+ OPT_SERVICE_CORELIST_NUM = 'S',
+#define OPT_VERSION "version"
+ OPT_VERSION_NUM = 'v',
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 5/9] eal: define the EAL parameters in argparse format
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
` (3 preceding siblings ...)
2025-07-21 15:16 ` [PATCH v5 4/9] eal: add long options for each short option Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 6/9] eal: gather EAL args before processing Bruce Richardson
` (3 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
Create eal_option_list.h, containing all the possible EAL parameters,
and basic info about them, such as type, whether they take a parameter
or not. Each entry is defined using a macro, which will be then
interpreted when the file is included.
First time this header in included in the eal_common_options.c file, the
macros are defined in such a way as to define field elements for an
"eal_init_args" structure, where each value is either a string type, if
it takes a parameter, or boolean type if it doesn't. For those elements
that take multiple values, i.e. are passed multiple times, we put them
in a TAILQ.
The second time of inclusion, the macros are defined so as to define the
arguments in an rte_argparse structure for EAL. For the basic string and
boolean types, we just store the values in the appropriate field in the
previous defined "eal_init_args" structure. For the list elements, we
use the argparse callback to process those elements, adding them to the
TAILQ as they are encountered.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 135 +++++++++++++++++++++++++++-
lib/eal/common/eal_option_list.h | 90 +++++++++++++++++++
lib/eal/meson.build | 2 +-
lib/meson.build | 1 +
4 files changed, 224 insertions(+), 4 deletions(-)
create mode 100644 lib/eal/common/eal_option_list.h
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index cafae9d9d7..197aa33590 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -28,11 +28,13 @@
#include <rte_version.h>
#include <rte_devargs.h>
#include <rte_memcpy.h>
+#include <sys/queue.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <rte_telemetry.h>
#endif
#include <rte_vect.h>
+#include <rte_argparse.h>
#include <eal_export.h>
#include "eal_internal_cfg.h"
#include "eal_options.h"
@@ -47,6 +49,136 @@
#define LCORE_OPT_LST 1
#define LCORE_OPT_MSK 2
+/* Allow the application to print its usage message too if set */
+static rte_usage_hook_t rte_application_usage_hook;
+
+struct arg_list_elem {
+ TAILQ_ENTRY(arg_list_elem) next;
+ char *arg;
+};
+TAILQ_HEAD(arg_list, arg_list_elem);
+
+struct eal_init_args {
+ /* define a struct member for each EAL option, member name is the same as option name.
+ * Parameters that take an argument e.g. -l, are char *,
+ * parameters that take no options e.g. --no-huge, are bool.
+ * parameters that can be given multiple times e.g. -a, are arg_lists,
+ * parameters that are optional e.g. --huge-unlink,
+ * are char * but are set to (void *)1 if the parameter is not given.
+ * for aliases, i.e. options under different names, no field needs to be output
+ */
+#define LIST_ARG(long, short, help_str, fieldname) struct arg_list fieldname;
+#define STR_ARG(long, short, help_str, fieldname) char *fieldname;
+#define OPT_STR_ARG(long, short, help_str, fieldname) char *fieldname;
+#define BOOL_ARG(long, short, help_str, fieldname) bool fieldname;
+#define STR_ALIAS(long, short, help_str, fieldname)
+
+#define INCLUDE_ALL_ARG 1 /* for struct definition, include even unsupported values */
+#include "eal_option_list.h"
+#undef INCLUDE_ALL_ARG
+};
+struct eal_init_args args;
+
+/* an rte_argparse callback to append the argument to an arg_list
+ * in args. The index is the offset into the struct of the list.
+ */
+static int
+arg_list_callback(uint32_t index, const char *arg, void *init_args)
+{
+ struct arg_list *list = RTE_PTR_ADD(init_args, index);
+ struct arg_list_elem *elem;
+
+ elem = malloc(sizeof(*elem));
+ if (elem == NULL)
+ return -1;
+
+ elem->arg = strdup(arg);
+ if (elem->arg == NULL) {
+ free(elem);
+ return -1;
+ }
+
+ TAILQ_INSERT_TAIL(list, elem, next);
+ return 0;
+}
+
+static void
+eal_usage(const struct rte_argparse *obj)
+{
+ rte_argparse_print_help(stdout, obj);
+ if (rte_application_usage_hook != NULL)
+ rte_application_usage_hook(obj->prog_name);
+}
+
+/* undef the *_ARG macros before redefining to generate the argparse arg list */
+#undef LIST_ARG
+#undef STR_ARG
+#undef OPT_STR_ARG
+#undef BOOL_ARG
+#undef STR_ALIAS
+
+/* For arguments which have an arg_list type, they use callback (no val_saver),
+ * require a value, and have the SUPPORT_MULTI flag.
+ */
+#define LIST_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_set = (void *)offsetof(struct eal_init_args, fieldname), \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .flags = RTE_ARGPARSE_FLAG_SUPPORT_MULTI, \
+},
+/* For arguments which have a string type, they use val_saver (no callback),
+ * and normally REQUIRED_VALUE.
+ */
+#define STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+},
+/* For flags which have optional arguments, they use both val_saver and val_set,
+ * but still have a string type.
+ */
+#define OPT_STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_OPTIONAL, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+},
+/* For boolean arguments, they use val_saver and val_set, with NO_VALUE flag.
+ */
+#define BOOL_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_NONE, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_BOOL, \
+},
+#define STR_ALIAS STR_ARG
+
+struct rte_argparse eal_argparse = {
+ .prog_name = "",
+ .usage = "<DPDK EAL options> -- <App options>",
+ .epilog = "For more information on EAL options, see the DPDK documentation at: \n"
+ "\thttps://doc.dpdk.org/guides/" RTE_EXEC_ENV_NAME "_gsg/",
+ .exit_on_error = true,
+ .callback = arg_list_callback,
+ .print_help = eal_usage,
+ .opaque = &args,
+ .args = {
+ #include "eal_option_list.h"
+ ARGPARSE_ARG_END(),
+ }
+};
+
const char
eal_short_options[] =
"a:" /* allow */
@@ -165,9 +297,6 @@ static int main_lcore_parsed;
static int mem_parsed;
static int core_parsed;
-/* Allow the application to print its usage message too if set */
-static rte_usage_hook_t rte_application_usage_hook;
-
/* Returns rte_usage_hook_t */
rte_usage_hook_t
eal_get_application_usage_hook(void)
diff --git a/lib/eal/common/eal_option_list.h b/lib/eal/common/eal_option_list.h
new file mode 100644
index 0000000000..dd148b7fed
--- /dev/null
+++ b/lib/eal/common/eal_option_list.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2025 Intel Corporation.
+ */
+
+/** This file contains a list of EAL commandline arguments.
+ *
+ * It's designed to be included multiple times in the codebase to
+ * generate both argument structure and the argument definitions
+ * for argparse.
+ */
+
+/* check that all ARG macros are defined */
+ #ifndef LIST_ARG
+#error "LIST_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef STR_ARG
+#error "STR_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef OPT_STR_ARG
+#error "OPT_STR_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef BOOL_ARG
+#error "BOOL_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef STR_ALIAS
+#error "STR_ALIAS macro must be defined before including " __FILE__
+#endif
+
+
+/*
+ * list of EAL arguments as struct rte_argparse_arg.
+ * Format of each entry: long name, short name, help string, struct member name.
+ */
+/* (Alphabetical) List of common options first */
+LIST_ARG("--allow", "-a", "Add device to allow-list, causing DPDK to only use specified devices", allow)
+STR_ARG("--base-virtaddr", NULL, "Base virtual address to reserve memory", base_virtaddr)
+LIST_ARG("--block", "-b", "Add device to block-list, preventing DPDK from using the device", block)
+STR_ARG("--coremask", "-c", "Hexadecimal bitmask of cores to use", coremask)
+LIST_ARG("--driver-path", "-d", "Path to external driver shared object, or directory of drivers", driver_path)
+STR_ARG("--force-max-simd-bitwidth", NULL, "Set max SIMD bitwidth to use in vector code paths", force_max_simd_bitwidth)
+OPT_STR_ARG("--huge-unlink", NULL, "Unlink hugetlbfs files on exit (existing|always|never)", huge_unlink)
+BOOL_ARG("--in-memory", NULL, "DPDK should not create shared mmap files in filesystem (disables secondary process support)", in_memory)
+STR_ARG("--iova-mode", NULL, "IOVA mapping mode, physical (pa)/virtual (va)", iova_mode)
+STR_ARG("--lcores", "-l", "List of CPU cores to use", lcores)
+BOOL_ARG("--legacy-mem", NULL, "Enable legacy memory behavior", legacy_mem)
+OPT_STR_ARG("--log-color", NULL, "Enable/disable color in log output", log_color)
+STR_ARG("--log-level", NULL, "Log level for loggers; use log-level=help for list of log types and levels", log_level)
+OPT_STR_ARG("--log-timestamp", NULL, "Enable/disable timestamp in log output", log_timestamp)
+STR_ARG("--main-lcore", NULL, "Select which core to use for the main thread", main_lcore)
+STR_ARG("--mbuf-pool-ops-name", NULL, "User defined mbuf default pool ops name", mbuf_pool_ops_name)
+STR_ARG("--memory-channels", "-n", "Number of memory channels per socket", memory_channels)
+STR_ARG("--memory-ranks", "-r", "Force number of memory ranks (don't detect)", memory_ranks)
+STR_ARG("--memory-size", "-m", "Total size of memory to allocate initially", memory_size)
+BOOL_ARG("--no-hpet", NULL, "Disable HPET timer", no_hpet)
+BOOL_ARG("--no-huge", NULL, "Disable hugetlbfs support", no_huge)
+BOOL_ARG("--no-pci", NULL, "Disable all PCI devices", no_pci)
+BOOL_ARG("--no-shconf", NULL, "Disable shared config file generation", no_shconf)
+BOOL_ARG("--no-telemetry", NULL, "Disable telemetry", no_telemetry)
+STR_ARG("--proc-type", NULL, "Type of process (primary|secondary|auto)", proc_type)
+STR_ARG("--service-corelist", "-S", "List of cores to use for service threads", service_corelist)
+STR_ARG("--service-coremask", "-s", "Hexadecimal bitmask of cores to use for service threads", service_coremask)
+BOOL_ARG("--single-file-segments", NULL, "Store all pages within single files (per-page-size, per-node)", single_file_segments)
+BOOL_ARG("--telemetry", NULL, "Enable telemetry", telemetry)
+LIST_ARG("--vdev", NULL, "Add a virtual device to the system; format=<driver><id>[,key=val,...]", vdev)
+BOOL_ARG("--vmware-tsc-map", NULL, "Use VMware TSC mapping instead of native RDTSC", vmware_tsc_map)
+BOOL_ARG("--version", "-v", "Show version", version)
+
+#if defined(INCLUDE_ALL_ARG) || !defined(RTE_EXEC_ENV_WINDOWS)
+/* Linux and FreeBSD options*/
+OPT_STR_ARG("--syslog", NULL, "Log to syslog (and optionally set facility)", syslog)
+STR_ARG("--trace", NULL, "Enable trace based on regular expression trace name", trace)
+STR_ARG("--trace-bufsz", NULL, "Trace buffer size", trace_bufsz)
+STR_ARG("--trace-dir", NULL, "Trace directory", trace_dir)
+STR_ARG("--trace-mode", NULL, "Trace mode", trace_mode)
+#endif
+
+#if defined(INCLUDE_ALL_ARG) || defined(RTE_EXEC_ENV_LINUX)
+/* Linux-only options */
+BOOL_ARG("--create-uio-dev", NULL, "Create /dev/uioX devices", create_uio_dev)
+STR_ARG("--file-prefix", NULL, "Base filename of hugetlbfs files", file_prefix)
+STR_ARG("--huge-dir", NULL, "Directory for hugepage files", huge_dir)
+OPT_STR_ARG("--huge-worker-stack", NULL, "Allocate worker thread stacks from hugepage memory, with optional size (kB)", huge_worker_stack)
+BOOL_ARG("--match-allocations", NULL, "Free hugepages exactly as allocated", match_allocations)
+STR_ARG("--numa-mem", NULL, "Memory to allocate on NUMA nodes (comma separated values)", numa_mem)
+STR_ARG("--numa-limit", NULL, "Limit memory allocation on NUMA nodes (comma separated values)", numa_limit)
+STR_ALIAS("--socket-mem", NULL, "Alias for --numa-mem", numa_mem)
+STR_ALIAS("--socket-limit", NULL, "Alias for --numa-limit", numa_limit)
+STR_ARG("--vfio-intr", NULL, "VFIO interrupt mode (legacy|msi|msix)", vfio_intr)
+STR_ARG("--vfio-vf-token", NULL, "VF token (UUID) shared between SR-IOV PF and VFs", vfio_vf_token)
+#endif
diff --git a/lib/eal/meson.build b/lib/eal/meson.build
index e1d6c4cf17..f9fcee24ee 100644
--- a/lib/eal/meson.build
+++ b/lib/eal/meson.build
@@ -14,7 +14,7 @@ subdir(exec_env)
subdir(arch_subdir)
-deps += ['log', 'kvargs']
+deps += ['argparse', 'kvargs']
if not is_windows
deps += ['telemetry']
endif
diff --git a/lib/meson.build b/lib/meson.build
index 0d56b2083b..dec90059e1 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -71,6 +71,7 @@ libraries = [
]
always_enable = [
+ 'argparse',
'cmdline',
'eal',
'ethdev',
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 6/9] eal: gather EAL args before processing
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
` (4 preceding siblings ...)
2025-07-21 15:16 ` [PATCH v5 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
` (2 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev
Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk,
Anatoly Burakov
DPDK traditionally has iterated through all args and processed them as
they appear in the commandline. The arg processing logic can be
simplified if instead we initially gather all arguments into a structure
which is then processed with the arguments dealt with in a fixed/known
order.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 877 ++++++++++++++--------------
lib/eal/common/eal_options.h | 10 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 164 +-----
lib/eal/linux/eal.c | 379 +-----------
lib/eal/windows/eal.c | 113 +---
6 files changed, 482 insertions(+), 1072 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 197aa33590..aea2c813ed 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -46,8 +46,7 @@
#endif
#define BITS_PER_HEX 4
-#define LCORE_OPT_LST 1
-#define LCORE_OPT_MSK 2
+#define NUMA_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
/* Allow the application to print its usage message too if set */
static rte_usage_hook_t rte_application_usage_hook;
@@ -179,80 +178,31 @@ struct rte_argparse eal_argparse = {
}
};
-const char
-eal_short_options[] =
- "a:" /* allow */
- "b:" /* block */
- "c:" /* coremask */
- "s:" /* service coremask */
- "d:" /* driver */
- "h" /* help */
- "l:" /* corelist */
- "S:" /* service corelist */
- "m:" /* memory size */
- "n:" /* memory channels */
- "r:" /* memory ranks */
- "v" /* version */
- ;
-
-const struct option
-eal_long_options[] = {
- {OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
- {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
- {OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
- {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
- {OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
- {OPT_HELP, 0, NULL, OPT_HELP_NUM },
- {OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
- {OPT_HUGE_UNLINK, 2, NULL, OPT_HUGE_UNLINK_NUM },
- {OPT_IOVA_MODE, 1, NULL, OPT_IOVA_MODE_NUM },
- {OPT_LCORES, 1, NULL, OPT_LCORES_NUM },
- {OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
- {OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
- {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
- {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
- {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
- {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
- {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
- {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
- {OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
- {OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
- {OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
- {OPT_TRACE_MODE, 1, NULL, OPT_TRACE_MODE_NUM },
- {OPT_MAIN_LCORE, 1, NULL, OPT_MAIN_LCORE_NUM },
- {OPT_MBUF_POOL_OPS_NAME, 1, NULL, OPT_MBUF_POOL_OPS_NAME_NUM},
- {OPT_NO_HPET, 0, NULL, OPT_NO_HPET_NUM },
- {OPT_NO_HUGE, 0, NULL, OPT_NO_HUGE_NUM },
- {OPT_NO_PCI, 0, NULL, OPT_NO_PCI_NUM },
- {OPT_NO_SHCONF, 0, NULL, OPT_NO_SHCONF_NUM },
- {OPT_IN_MEMORY, 0, NULL, OPT_IN_MEMORY_NUM },
- {OPT_DEV_BLOCK, 1, NULL, OPT_DEV_BLOCK_NUM },
- {OPT_DEV_ALLOW, 1, NULL, OPT_DEV_ALLOW_NUM },
- {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM },
- /* socket-mem/socket-limit are kept for backwards compatibility */
- {OPT_SOCKET_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_SOCKET_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
- {OPT_NUMA_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_NUMA_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
-#ifndef RTE_EXEC_ENV_WINDOWS
- {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM },
-#endif
- {OPT_VDEV, 1, NULL, OPT_VDEV_NUM },
- {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
- {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM },
- {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
- {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM },
- {OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM},
- {OPT_MATCH_ALLOCATIONS, 0, NULL, OPT_MATCH_ALLOCATIONS_NUM},
- {OPT_TELEMETRY, 0, NULL, OPT_TELEMETRY_NUM },
- {OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
- {OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
- {OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
- {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
-
-
- {0, 0, NULL, 0 }
-};
+/* function to call into argparse library to parse the passed argc/argv parameters
+ * to the eal_init_args structure.
+ */
+int
+eal_collate_args(int argc, char **argv)
+{
+ if (argc < 1 || argv == NULL)
+ return -EINVAL;
+
+ /* initialize the list of arguments */
+ memset(&args, 0, sizeof(args));
+ TAILQ_INIT(&args.allow);
+ TAILQ_INIT(&args.block);
+ TAILQ_INIT(&args.driver_path);
+ TAILQ_INIT(&args.vdev);
+
+ /* parse the arguments */
+ eal_argparse.prog_name = argv[0];
+ int retval = rte_argparse_parse(&eal_argparse, argc, argv);
+ if (retval < 0)
+ return retval;
+
+ argv[retval - 1] = argv[0];
+ return retval - 1;
+}
TAILQ_HEAD(shared_driver_list, shared_driver);
@@ -294,7 +244,6 @@ static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
static int main_lcore_parsed;
-static int mem_parsed;
static int core_parsed;
/* Returns rte_usage_hook_t */
@@ -318,7 +267,12 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
return old_func;
}
-#ifndef RTE_EXEC_ENV_WINDOWS
+#ifdef RTE_EXEC_ENV_WINDOWS
+
+int
+eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+
+#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
static char **eal_app_args;
@@ -406,7 +360,7 @@ eal_save_args(int argc, char **argv)
eal_args = NULL;
return -1;
}
-#endif
+#endif /* !RTE_EXEC_ENV_WINDOWS */
static int
eal_option_device_add(enum rte_devtype type, const char *optarg)
@@ -829,17 +783,6 @@ eal_parse_service_coremask(const char *coremask)
return 0;
}
-static int
-eal_service_cores_parsed(void)
-{
- int idx;
- for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- if (lcore_config[idx].core_role == ROLE_SERVICE)
- return 1;
- }
- return 0;
-}
-
static int
update_lcore_config(int *cores)
{
@@ -1666,361 +1609,486 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return -1;
}
-bool
-eal_option_is_log(int opt)
+/* Parse all arguments looking for log related ones */
+int
+eal_parse_log_options(void)
{
- switch (opt) {
- case OPT_LOG_COLOR_NUM:
- case OPT_LOG_LEVEL_NUM:
- case OPT_LOG_TIMESTAMP_NUM:
- case OPT_SYSLOG_NUM:
- return true;
- default:
- return false;
+ if (args.log_level != NULL) {
+ if (eal_parse_log_level(args.log_level) < 0) {
+ EAL_LOG(ERR, "invalid log-level parameter");
+ return -1;
+ }
+ }
+ if (args.log_color != NULL) {
+ /* if value is 1, no argument specified, so pass NULL */
+ if (args.log_color == (void *)1)
+ args.log_color = NULL;
+ if (eal_log_color(args.log_color) < 0) {
+ EAL_LOG(ERR, "invalid log-color parameter");
+ return -1;
+ }
+ }
+ if (args.log_timestamp != NULL) {
+ /* similarly log_timestamp may be 1 */
+ if (args.log_timestamp == (void *)1)
+ args.log_timestamp = NULL;
+ if (eal_log_timestamp(args.log_timestamp) < 0) {
+ EAL_LOG(ERR, "invalid log-timestamp parameter");
+ return -1;
+ }
+ }
+ if (args.syslog != NULL) {
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "syslog is not supported on Windows, ignoring parameter");
+#else
+ /* also syslog parameter may be 1 */
+ if (args.syslog == (void *)1)
+ args.syslog = NULL;
+ if (eal_log_syslog(args.syslog) < 0) {
+ EAL_LOG(ERR, "invalid syslog parameter");
+ return -1;
+ }
+#endif
}
+ return 0;
}
-/* Parse all arguments looking for log related ones */
-int
-eal_parse_log_options(int argc, char * const argv[])
+static int
+eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
{
- struct internal_config *internal_conf = eal_get_internal_configuration();
- int option_index, opt;
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_opterr = opterr;
- char *old_optarg = optarg;
-#ifdef RTE_EXEC_ENV_FREEBSD
- const int old_optreset = optreset;
- optreset = 1;
-#endif
+ char *arg[RTE_MAX_NUMA_NODES];
+ char *end;
+ int arg_num, i, len;
- optind = 1;
- opterr = 0;
+ len = strnlen(strval, NUMA_MEM_STRLEN);
+ if (len == NUMA_MEM_STRLEN) {
+ EAL_LOG(ERR, "--numa-mem/--socket-mem parameter is too long");
+ return -1;
+ }
- while ((opt = getopt_long(argc, argv, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
+ /* all other error cases will be caught later */
+ if (!isdigit(strval[len-1]))
+ return -1;
- if (!eal_option_is_log(opt))
- continue;
+ /* split the optarg into separate socket values */
+ arg_num = rte_strsplit(strval, len,
+ arg, RTE_MAX_NUMA_NODES, ',');
- if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+ /* if split failed, or 0 arguments */
+ if (arg_num <= 0)
+ return -1;
+
+ /* parse each defined socket option */
+ errno = 0;
+ for (i = 0; i < arg_num; i++) {
+ uint64_t val;
+ end = NULL;
+ val = strtoull(arg[i], &end, 10);
+
+ /* check for invalid input */
+ if ((errno != 0) ||
+ (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
+ val <<= 20;
+ socket_arg[i] = val;
}
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
- opterr = old_opterr;
-#ifdef RTE_EXEC_ENV_FREEBSD
- optreset = old_optreset;
+ return 0;
+}
+
+static int
+eal_parse_vfio_intr(const char *mode)
+{
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+ static struct {
+ const char *name;
+ enum rte_intr_mode value;
+ } map[] = {
+ { "legacy", RTE_INTR_MODE_LEGACY },
+ { "msi", RTE_INTR_MODE_MSI },
+ { "msix", RTE_INTR_MODE_MSIX },
+ };
+
+ for (size_t i = 0; i < RTE_DIM(map); i++) {
+ if (!strcmp(mode, map[i].name)) {
+ internal_conf->vfio_intr_mode = map[i].value;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+eal_parse_vfio_vf_token(const char *vf_token)
+{
+ struct internal_config *cfg = eal_get_internal_configuration();
+ rte_uuid_t uuid;
+
+ if (!rte_uuid_parse(vf_token, uuid)) {
+ rte_uuid_copy(cfg->vfio_vf_token, uuid);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+eal_parse_huge_worker_stack(const char *arg)
+{
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "Cannot set worker stack size on Windows, parameter ignored");
+ RTE_SET_USED(arg);
+#else
+ struct internal_config *cfg = eal_get_internal_configuration();
+
+ if (arg == NULL || arg[0] == '\0') {
+ pthread_attr_t attr;
+ int ret;
+
+ if (pthread_attr_init(&attr) != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
+ pthread_attr_destroy(&attr);
+ if (ret != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ } else {
+ unsigned long stack_size;
+ char *end;
+
+ errno = 0;
+ stack_size = strtoul(arg, &end, 10);
+ if (errno || end == NULL || stack_size == 0 ||
+ stack_size >= (size_t)-1 / 1024)
+ return -1;
+
+ cfg->huge_worker_stack_size = stack_size * 1024;
+ }
+
+ EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
+ cfg->huge_worker_stack_size / 1024);
#endif
return 0;
}
+/* Parse the arguments given in the command line of the application */
int
-eal_parse_common_option(int opt, const char *optarg,
- struct internal_config *conf)
+eal_parse_args(void)
{
- static int b_used;
- static int a_used;
-
- switch (opt) {
- case 'b':
- if (a_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, optarg) < 0)
+ struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct arg_list_elem *arg;
+
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+ /* both -l and -c cannot be used at the same time */
+ if (args.coremask != NULL && args.lcores != NULL) {
+ EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
+ return -1;
+ }
+ /* both -s and -S cannot be used at the same time */
+ if (args.service_coremask != NULL && args.service_corelist != NULL) {
+ EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
+ return -1;
+ }
+ /* can't have both telemetry and no-telemetry */
+ if (args.no_telemetry && args.telemetry) {
+ EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
+ return -1;
+ }
+ /* can't have both -m and --socket-mem */
+ if (args.memory_size != NULL && args.numa_mem != NULL) {
+ EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ return -1;
+ }
+
+ /* parse options */
+ /* print version before anything else */
+ if (args.version) {
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
+ }
+
+ /* parse the process type */
+ if (args.proc_type != NULL) {
+ int_cfg->process_type = eal_parse_proc_type(args.proc_type);
+ if (int_cfg->process_type == RTE_PROC_INVALID) {
+ EAL_LOG(ERR, "invalid process type: %s", args.proc_type);
return -1;
- b_used = 1;
- break;
+ }
+ }
- case 'a':
- if (b_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, optarg) < 0)
+ /* device -a/-b/-vdev options*/
+ TAILQ_FOREACH(arg, &args.allow, next)
+ if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, arg->arg) < 0)
return -1;
- a_used = 1;
- break;
- /* coremask */
- case 'c': {
+ TAILQ_FOREACH(arg, &args.block, next)
+ if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, arg->arg) < 0)
+ return -1;
+ TAILQ_FOREACH(arg, &args.vdev, next)
+ if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, arg->arg) < 0)
+ return -1;
+ /* driver loading options */
+ TAILQ_FOREACH(arg, &args.driver_path, next)
+ if (eal_plugin_add(arg->arg) < 0)
+ return -1;
+
+ /* parse the coremask /core-list */
+ if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -c is before -s or -S");
- if (rte_eal_parse_coremask(optarg, lcore_indexes) < 0) {
+ if (rte_eal_parse_coremask(args.coremask, lcore_indexes) < 0) {
EAL_LOG(ERR, "invalid coremask syntax");
return -1;
}
if (update_lcore_config(lcore_indexes) < 0) {
char *available = available_cores();
- EAL_LOG(ERR,
- "invalid coremask, please check specified cores are part of %s",
- available);
+ EAL_LOG(ERR, "invalid coremask '%s', please check specified cores are part of %s",
+ args.coremask, available);
free(available);
return -1;
}
-
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_MSK)
- EAL_LOG(ERR, "Option '-c' passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option -c is ignored, because option -l/--lcores used");
+ core_parsed = 1;
+ } else if (args.lcores != NULL) {
+ if (eal_parse_lcores(args.lcores) < 0) {
+ EAL_LOG(ERR, "invalid lcore list: '%s'", args.lcores);
return -1;
}
-
- core_parsed = LCORE_OPT_MSK;
- break;
+ core_parsed = 1;
}
- /* corelist */
- case 'l': {
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -l is before -s or -S");
-
- if (eal_parse_lcores(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for -l/--" OPT_LCORES);
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0) {
+ EAL_LOG(ERR, "invalid main-lcore parameter");
return -1;
}
+ }
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_LST)
- EAL_LOG(ERR, "Core list option passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option '-l/--lcores' is ignored, because coremask option used");
+ /* service core options */
+ if (args.service_coremask != NULL) {
+ if (eal_parse_service_coremask(args.service_coremask) < 0) {
+ EAL_LOG(ERR, "invalid service coremask: '%s'",
+ args.service_coremask);
return -1;
}
+ } else if (args.service_corelist != NULL) {
+ if (eal_parse_service_corelist(args.service_corelist) < 0) {
+ EAL_LOG(ERR, "invalid service core list: '%s'",
+ args.service_corelist);
+ return -1;
+ }
+ }
- core_parsed = LCORE_OPT_LST;
- break;
+ /* memory options */
+ if (args.memory_size != NULL) {
+ int_cfg->memory = atoi(args.memory_size);
+ int_cfg->memory *= 1024ULL;
+ int_cfg->memory *= 1024ULL;
}
- /* service coremask */
- case 's':
- if (eal_parse_service_coremask(optarg) < 0) {
- EAL_LOG(ERR, "invalid service coremask");
+ if (args.memory_channels != NULL) {
+ int_cfg->force_nchannel = atoi(args.memory_channels);
+ if (int_cfg->force_nchannel == 0) {
+ EAL_LOG(ERR, "invalid memory channel parameter");
return -1;
}
- break;
- /* service corelist */
- case 'S':
- if (eal_parse_service_corelist(optarg) < 0) {
- EAL_LOG(ERR, "invalid service core list");
+ }
+ if (args.memory_ranks != NULL) {
+ int_cfg->force_nrank = atoi(args.memory_ranks);
+ if (int_cfg->force_nrank == 0 || int_cfg->force_nrank > 16) {
+ EAL_LOG(ERR, "invalid memory rank parameter");
return -1;
}
- break;
- /* size of memory */
- case 'm':
- conf->memory = atoi(optarg);
- conf->memory *= 1024ULL;
- conf->memory *= 1024ULL;
- mem_parsed = 1;
- break;
- /* force number of channels */
- case 'n':
- conf->force_nchannel = atoi(optarg);
- if (conf->force_nchannel == 0) {
- EAL_LOG(ERR, "invalid channel number");
+ }
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
return -1;
}
- break;
- /* force number of ranks */
- case 'r':
- conf->force_nrank = atoi(optarg);
- if (conf->force_nrank == 0 ||
- conf->force_nrank > 16) {
- EAL_LOG(ERR, "invalid rank number");
+ }
+ if (args.no_huge) {
+ int_cfg->no_hugetlbfs = 1;
+ /* no-huge is legacy mem */
+ int_cfg->legacy_mem = 1;
+ }
+ if (args.in_memory) {
+ int_cfg->in_memory = 1;
+ /* in-memory is a superset of noshconf and huge-unlink */
+ int_cfg->no_shconf = 1;
+ int_cfg->hugepage_file.unlink_before_mapping = true;
+ }
+ if (args.legacy_mem)
+ int_cfg->legacy_mem = 1;
+ if (args.single_file_segments)
+ int_cfg->single_file_segments = 1;
+ if (args.huge_dir != NULL) {
+ free(int_cfg->hugepage_dir); /* free old hugepage dir */
+ int_cfg->hugepage_dir = strdup(args.huge_dir);
+ if (int_cfg->hugepage_dir == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for hugepage dir parameter");
return -1;
}
- break;
- /* force loading of external driver */
- case 'd':
- if (eal_plugin_add(optarg) == -1)
+ }
+ if (args.file_prefix != NULL) {
+ free(int_cfg->hugefile_prefix); /* free old file prefix */
+ int_cfg->hugefile_prefix = strdup(args.file_prefix);
+ if (int_cfg->hugefile_prefix == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for file prefix parameter");
return -1;
- break;
- case 'v':
- /* since message is explicitly requested by user, we
- * write message at highest log level so it can always
- * be seen
- * even if info or warning messages are disabled */
- EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- break;
-
- /* long options */
- case OPT_HUGE_UNLINK_NUM:
- if (eal_parse_huge_unlink(optarg, &conf->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid --"OPT_HUGE_UNLINK" option");
+ }
+ }
+ if (args.numa_mem != NULL) {
+ if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
+ EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
return -1;
}
- break;
-
- case OPT_NO_HUGE_NUM:
- conf->no_hugetlbfs = 1;
- /* no-huge is legacy mem */
- conf->legacy_mem = 1;
- break;
-
- case OPT_NO_PCI_NUM:
- conf->no_pci = 1;
- break;
-
- case OPT_NO_HPET_NUM:
- conf->no_hpet = 1;
- break;
-
- case OPT_VMWARE_TSC_MAP_NUM:
- conf->vmware_tsc_map = 1;
- break;
-
- case OPT_NO_SHCONF_NUM:
- conf->no_shconf = 1;
- break;
-
- case OPT_IN_MEMORY_NUM:
- conf->in_memory = 1;
- /* in-memory is a superset of noshconf and huge-unlink */
- conf->no_shconf = 1;
- conf->hugepage_file.unlink_before_mapping = true;
- break;
-
- case OPT_PROC_TYPE_NUM:
- conf->process_type = eal_parse_proc_type(optarg);
- break;
-
- case OPT_MAIN_LCORE_NUM:
- if (eal_parse_main_lcore(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_MAIN_LCORE);
+ int_cfg->force_numa = 1;
+ }
+ if (args.numa_limit != NULL) {
+ if (eal_parse_socket_arg(args.numa_limit, int_cfg->numa_limit) < 0) {
+ EAL_LOG(ERR, "invalid numa-limit parameter: '%s'", args.numa_limit);
return -1;
}
- break;
+ int_cfg->force_numa_limits = 1;
+ }
- case OPT_VDEV_NUM:
- if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
- optarg) < 0) {
+ /* tracing settings, not supported on windows */
+#ifdef RTE_EXEC_ENV_WINDOWS
+ if (args.trace != NULL ||
+ args.trace_dir != NULL ||
+ args.trace_bufsz != NULL ||
+ args.trace_mode != NULL)
+ EAL_LOG(WARNING, "Tracing is not supported on Windows, ignoring tracing parameters");
+#else
+ if (args.trace != NULL) {
+ if (eal_trace_args_save(args.trace) < 0) {
+ EAL_LOG(ERR, "invalid trace parameter, '%s'", args.trace);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_SYSLOG_NUM:
- if (eal_log_syslog(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_SYSLOG);
+ }
+ if (args.trace_dir != NULL) {
+ if (eal_trace_dir_args_save(args.trace_dir) < 0) {
+ EAL_LOG(ERR, "invalid trace directory, '%s'", args.trace_dir);
return -1;
}
- break;
-#endif
-
- case OPT_LOG_LEVEL_NUM:
- if (eal_parse_log_level(optarg) < 0) {
- EAL_LOG(ERR,
- "invalid parameters for --"
- OPT_LOG_LEVEL);
+ }
+ if (args.trace_bufsz != NULL) {
+ if (eal_trace_bufsz_args_save(args.trace_bufsz) < 0) {
+ EAL_LOG(ERR, "invalid trace buffer size, '%s'", args.trace_bufsz);
return -1;
}
- break;
-
- case OPT_LOG_TIMESTAMP_NUM:
- if (eal_log_timestamp(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_TIMESTAMP);
+ }
+ if (args.trace_mode != NULL) {
+ if (eal_trace_mode_args_save(args.trace_mode) < 0) {
+ EAL_LOG(ERR, "invalid trace mode, '%s'", args.trace_mode);
return -1;
}
- break;
+ }
+#endif
- case OPT_LOG_COLOR_NUM:
- if (eal_log_color(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_COLOR);
+ /* simple flag settings
+ * Only set these to 1, as we don't want to set them to 0 in case
+ * other options above have already set them.
+ */
+ if (args.no_pci)
+ int_cfg->no_pci = 1;
+ if (args.no_hpet)
+ int_cfg->no_hpet = 1;
+ if (args.vmware_tsc_map)
+ int_cfg->vmware_tsc_map = 1;
+ if (args.no_shconf)
+ int_cfg->no_shconf = 1;
+ if (args.no_telemetry)
+ int_cfg->no_telemetry = 1;
+ if (args.match_allocations)
+ int_cfg->match_allocations = 1;
+ if (args.create_uio_dev)
+ int_cfg->create_uio_dev = 1;
+
+
+ /* other misc settings */
+ if (args.iova_mode != NULL) {
+ if (eal_parse_iova_mode(args.iova_mode) < 0) {
+ EAL_LOG(ERR, "invalid iova mode parameter '%s'", args.iova_mode);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_TRACE_NUM: {
- if (eal_trace_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE);
+ };
+ if (args.base_virtaddr != NULL) {
+ if (eal_parse_base_virtaddr(args.base_virtaddr) < 0) {
+ EAL_LOG(ERR, "invalid base virtaddr '%s'", args.base_virtaddr);
return -1;
}
- break;
}
-
- case OPT_TRACE_DIR_NUM: {
- if (eal_trace_dir_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_DIR);
+ if (args.force_max_simd_bitwidth != NULL) {
+ if (eal_parse_simd_bitwidth(args.force_max_simd_bitwidth) < 0) {
+ EAL_LOG(ERR, "invalid SIMD bitwidth parameter '%s'",
+ args.force_max_simd_bitwidth);
return -1;
}
- break;
}
-
- case OPT_TRACE_BUF_SIZE_NUM: {
- if (eal_trace_bufsz_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_BUF_SIZE);
+ if (args.vfio_intr != NULL) {
+ if (eal_parse_vfio_intr(args.vfio_intr) < 0) {
+ EAL_LOG(ERR, "invalid vfio interrupt parameter: '%s'", args.vfio_intr);
return -1;
}
- break;
}
-
- case OPT_TRACE_MODE_NUM: {
- if (eal_trace_mode_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_MODE);
+ if (args.vfio_vf_token != NULL) {
+ if (eal_parse_vfio_vf_token(args.vfio_vf_token) < 0) {
+ EAL_LOG(ERR, "invalid vfio vf token parameter: '%s'", args.vfio_vf_token);
return -1;
}
- break;
}
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- case OPT_LEGACY_MEM_NUM:
- conf->legacy_mem = 1;
- break;
- case OPT_SINGLE_FILE_SEGMENTS_NUM:
- conf->single_file_segments = 1;
- break;
- case OPT_IOVA_MODE_NUM:
- if (eal_parse_iova_mode(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_IOVA_MODE);
+ if (args.huge_worker_stack != NULL) {
+ if (args.huge_worker_stack == (void *)1)
+ args.huge_worker_stack = NULL;
+ if (eal_parse_huge_worker_stack(args.huge_worker_stack) < 0) {
+ EAL_LOG(ERR, "invalid huge worker stack parameter");
return -1;
}
- break;
- case OPT_BASE_VIRTADDR_NUM:
- if (eal_parse_base_virtaddr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_BASE_VIRTADDR);
+ }
+ if (args.mbuf_pool_ops_name != NULL) {
+ free(int_cfg->user_mbuf_pool_ops_name); /* free old ops name */
+ int_cfg->user_mbuf_pool_ops_name = strdup(args.mbuf_pool_ops_name);
+ if (int_cfg->user_mbuf_pool_ops_name == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
- break;
- case OPT_TELEMETRY_NUM:
- break;
- case OPT_NO_TELEMETRY_NUM:
- conf->no_telemetry = 1;
- break;
- case OPT_FORCE_MAX_SIMD_BITWIDTH_NUM:
- if (eal_parse_simd_bitwidth(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_FORCE_MAX_SIMD_BITWIDTH);
+ }
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+ /* create runtime data directory. In no_shconf mode, skip any errors */
+ if (eal_create_runtime_dir() < 0) {
+ if (int_cfg->no_shconf == 0) {
+ EAL_LOG(ERR, "Cannot create runtime directory");
return -1;
}
- break;
+ EAL_LOG(WARNING, "No DPDK runtime directory created");
+ }
+#endif
- /* don't know what to do, leave this to caller */
- default:
- return 1;
+ if (eal_adjust_config(int_cfg) != 0) {
+ EAL_LOG(ERR, "Invalid configuration");
+ return -1;
+ }
+ if (eal_check_common_options(int_cfg) != 0) {
+ EAL_LOG(ERR, "Checking common options failed");
+ return -1;
}
return 0;
-
-ba_conflict:
- EAL_LOG(ERR,
- "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
}
static void
@@ -2153,13 +2221,8 @@ eal_check_common_options(struct internal_config *internal_cfg)
"option");
return -1;
}
- if (mem_parsed && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Options -m and --"OPT_NUMA_MEM" cannot "
- "be specified at the same time");
- return -1;
- }
if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_MEM" cannot "
+ EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
"be specified together with --"OPT_NO_HUGE);
return -1;
}
@@ -2245,97 +2308,3 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth)
internal_conf->max_simd_bitwidth.bitwidth = bitwidth;
return 0;
}
-
-void
-eal_common_usage(void)
-{
- printf("[options]\n\n"
- "EAL common options:\n"
- " -c COREMASK Hexadecimal bitmask of cores to run on\n"
- " -l, --"OPT_LCORES" CORELIST\n"
- " List of cores to run on\n"
- " The basic argument format is <c1>[-c2][,c3[-c4],...]\n"
- " where c1, c2, etc are core indexes between 0 and %d\n"
- " Can also be used to map lcore set to physical CPU set\n"
- " The argument format is\n"
- " '<lcores[@cpus]>[<,lcores[@cpus]>...]'\n"
- " lcores and cpus list are grouped by '(' and ')'\n"
- " Within the group, '-' is used for range separator,\n"
- " ',' is used for single number separator.\n"
- " '( )' can be omitted for single element group,\n"
- " '@' can be omitted if cpus and lcores have the same value\n"
- " -s SERVICE COREMASK Hexadecimal bitmask of cores to be used as service cores\n"
- " --"OPT_MAIN_LCORE" ID Core ID that is used as main\n"
- " --"OPT_MBUF_POOL_OPS_NAME" Pool ops name for mbuf to use\n"
- " -n CHANNELS Number of memory channels\n"
- " -m MB Memory to allocate (see also --"OPT_NUMA_MEM")\n"
- " -r RANKS Force number of memory ranks (don't detect)\n"
- " -b, --block Add a device to the blocked list.\n"
- " Prevent EAL from using this device. The argument\n"
- " format for PCI devices is <domain:bus:devid.func>.\n"
- " -a, --allow Add a device to the allow list.\n"
- " Only use the specified devices. The argument format\n"
- " for PCI devices is <[domain:]bus:devid.func>.\n"
- " This option can be present several times.\n"
- " [NOTE: " OPT_DEV_ALLOW " cannot be used with "OPT_DEV_BLOCK" option]\n"
- " --"OPT_VDEV" Add a virtual device.\n"
- " The argument format is <driver><id>[,key=val,...]\n"
- " (ex: --vdev=net_pcap0,iface=eth2).\n"
- " --"OPT_IOVA_MODE" Set IOVA mode. 'pa' for IOVA_PA\n"
- " 'va' for IOVA_VA\n"
- " -d LIB.so|DIR Add a driver or driver directory\n"
- " (can be used multiple times)\n"
- " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n"
- " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_SYSLOG"[=<facility>] Enable use of syslog (and optionally set facility)\n"
-#endif
- " --"OPT_LOG_LEVEL"=<level> Set global log level\n"
- " --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
- " Set specific log level\n"
- " --"OPT_LOG_LEVEL"=help Show log types and levels\n"
- " --"OPT_LOG_TIMESTAMP"[=<format>] Timestamp log output\n"
- " --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_TRACE"=<regex-match>\n"
- " Enable trace based on regular expression trace name.\n"
- " By default, the trace is disabled.\n"
- " User must specify this option to enable trace.\n"
- " --"OPT_TRACE_DIR"=<directory path>\n"
- " Specify trace directory for trace output.\n"
- " By default, trace output will created at\n"
- " $HOME directory and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_BUF_SIZE"=<int>\n"
- " Specify maximum size of allocated memory\n"
- " for trace output for each thread. Valid\n"
- " unit can be either 'B|K|M' for 'Bytes',\n"
- " 'KBytes' and 'MBytes' respectively.\n"
- " Default is 1MB and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_MODE"=<o[verwrite] | d[iscard]>\n"
- " Specify the mode of update of trace\n"
- " output file. Either update on a file can\n"
- " be wrapped or discarded when file size\n"
- " reaches its maximum limit.\n"
- " Default mode is 'overwrite' and parameter\n"
- " must be specified once only.\n"
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- " -v Display version information on startup\n"
- " -h, --"OPT_HELP" This help\n"
- " --"OPT_IN_MEMORY" Operate entirely in memory. This will\n"
- " disable secondary process support\n"
- " --"OPT_BASE_VIRTADDR" Base virtual address\n"
- " --"OPT_TELEMETRY" Enable telemetry support (on by default)\n"
- " --"OPT_NO_TELEMETRY" Disable telemetry support\n"
- " --"OPT_FORCE_MAX_SIMD_BITWIDTH" Force the max SIMD bitwidth\n"
- "\nEAL options for DEBUG use only:\n"
- " --"OPT_HUGE_UNLINK"[=existing|always|never]\n"
- " When to unlink files in hugetlbfs\n"
- " ('existing' by default, no value means 'always')\n"
- " --"OPT_NO_HUGE" Use malloc instead of hugetlbfs\n"
- " --"OPT_NO_PCI" Disable PCI\n"
- " --"OPT_NO_HPET" Disable HPET\n"
- " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n"
- "\n", RTE_MAX_LCORE);
-}
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 6ef45559f0..c4d2cc84dc 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -115,18 +115,12 @@ enum {
OPT_LONG_MAX_NUM
};
-extern const char eal_short_options[];
-extern const struct option eal_long_options[];
-
-bool eal_option_is_log(int opt);
-int eal_parse_log_options(int argc, char * const argv[]);
-int eal_parse_common_option(int opt, const char *argv,
- struct internal_config *conf);
+int eal_parse_log_options(void);
+int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
int eal_check_common_options(struct internal_config *internal_cfg);
-void eal_common_usage(void);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index 5846917cc5..ab8b37b956 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -72,6 +72,17 @@ struct rte_config {
*/
struct rte_config *rte_eal_get_configuration(void);
+/**
+ * Put the argument list into a structure.
+ *
+ * This allows the arguments to then be processed out-of-order.
+ *
+ * @return
+ * - 0 on success
+ * - Negative on error
+ */
+int eal_collate_args(int argc, char **argv);
+
/**
* Initialize the memzone subsystem (private to eal).
*
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index c1ab8d86d2..ee8bf92bff 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -160,7 +160,7 @@ rte_eal_config_create(void)
cfg_len_aligned, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, mem_cfg_fd, 0);
if (mapped_mem_cfg_addr == MAP_FAILED) {
- EAL_LOG(ERR, "Cannot remap memory for rte_config");
+ EAL_LOG(ERR, "Cannot remap memory for rte_config: %s", strerror(errno));
munmap(rte_mem_cfg_addr, cfg_len);
close(mem_cfg_fd);
mem_cfg_fd = -1;
@@ -245,11 +245,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
- /* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option",
- rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
@@ -332,21 +329,6 @@ rte_config_init(void)
return 0;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
static inline size_t
eal_get_hugepage_mem_size(void)
{
@@ -367,123 +349,6 @@ eal_get_hugepage_mem_size(void)
return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX;
}
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_optreset = optreset;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
- optreset = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on FreeBSD", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on FreeBSD",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on FreeBSD", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optreset = old_optreset;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -553,8 +418,18 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* Save and collate args at the top */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("invalid command-line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -585,18 +460,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
@@ -605,8 +476,7 @@ rte_eal_init(int argc, char **argv)
/* FreeBSD always uses legacy memory model */
internal_conf->legacy_mem = true;
if (internal_conf->in_memory) {
- EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '%s'",
- OPT_IN_MEMORY);
+ EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '--in-memory'");
internal_conf->in_memory = false;
}
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 52efb8626b..f59cb43b0e 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -59,9 +59,6 @@
#include "log_internal.h"
#define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
-
-#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
-
#define KERNEL_IOMMU_GROUPS_PATH "/sys/kernel/iommu_groups"
/* define fd variable here, because file needs to be kept open for the
@@ -438,362 +435,6 @@ eal_hugedirs_unlock(void)
}
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- printf("EAL Linux options:\n"
- " --"OPT_NUMA_MEM" Memory to allocate on NUMA nodes (comma separated values)\n"
- " --"OPT_NUMA_LIMIT" Limit memory allocation on NUMA nodes (comma separated values)\n"
- " --"OPT_HUGE_DIR" Directory where hugetlbfs is mounted\n"
- " --"OPT_FILE_PREFIX" Prefix for hugepage filenames\n"
- " --"OPT_CREATE_UIO_DEV" Create /dev/uioX (usually done by hotplug)\n"
- " --"OPT_VFIO_INTR" Interrupt mode for VFIO (legacy|msi|msix)\n"
- " --"OPT_VFIO_VF_TOKEN" VF token (UUID) shared between SR-IOV PF and VFs\n"
- " --"OPT_LEGACY_MEM" Legacy memory mode (no dynamic allocation, contiguous segments)\n"
- " --"OPT_SINGLE_FILE_SEGMENTS" Put all hugepage memory in single files\n"
- " --"OPT_MATCH_ALLOCATIONS" Free hugepages exactly as allocated\n"
- " --"OPT_HUGE_WORKER_STACK"[=size]\n"
- " Allocate worker thread stacks from hugepage memory.\n"
- " Size is in units of kbytes and defaults to system\n"
- " thread stack size if not specified.\n"
- "\n");
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-static int
-eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
-{
- char * arg[RTE_MAX_NUMA_NODES];
- char *end;
- int arg_num, i, len;
-
- len = strnlen(strval, SOCKET_MEM_STRLEN);
- if (len == SOCKET_MEM_STRLEN) {
- EAL_LOG(ERR, "--socket-mem is too long");
- return -1;
- }
-
- /* all other error cases will be caught later */
- if (!isdigit(strval[len-1]))
- return -1;
-
- /* split the optarg into separate socket values */
- arg_num = rte_strsplit(strval, len,
- arg, RTE_MAX_NUMA_NODES, ',');
-
- /* if split failed, or 0 arguments */
- if (arg_num <= 0)
- return -1;
-
- /* parse each defined socket option */
- errno = 0;
- for (i = 0; i < arg_num; i++) {
- uint64_t val;
- end = NULL;
- val = strtoull(arg[i], &end, 10);
-
- /* check for invalid input */
- if ((errno != 0) ||
- (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
- return -1;
- val <<= 20;
- socket_arg[i] = val;
- }
-
- return 0;
-}
-
-static int
-eal_parse_vfio_intr(const char *mode)
-{
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
- unsigned i;
- static struct {
- const char *name;
- enum rte_intr_mode value;
- } map[] = {
- { "legacy", RTE_INTR_MODE_LEGACY },
- { "msi", RTE_INTR_MODE_MSI },
- { "msix", RTE_INTR_MODE_MSIX },
- };
-
- for (i = 0; i < RTE_DIM(map); i++) {
- if (!strcmp(mode, map[i].name)) {
- internal_conf->vfio_intr_mode = map[i].value;
- return 0;
- }
- }
- return -1;
-}
-
-static int
-eal_parse_vfio_vf_token(const char *vf_token)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
- rte_uuid_t uuid;
-
- if (!rte_uuid_parse(vf_token, uuid)) {
- rte_uuid_copy(cfg->vfio_vf_token, uuid);
- return 0;
- }
-
- return -1;
-}
-
-static int
-eal_parse_huge_worker_stack(const char *arg)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
-
- if (arg == NULL || arg[0] == '\0') {
- pthread_attr_t attr;
- int ret;
-
- if (pthread_attr_init(&attr) != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
- pthread_attr_destroy(&attr);
- if (ret != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- } else {
- unsigned long stack_size;
- char *end;
-
- errno = 0;
- stack_size = strtoul(arg, &end, 10);
- if (errno || end == NULL || stack_size == 0 ||
- stack_size >= (size_t)-1 / 1024)
- return -1;
-
- cfg->huge_worker_stack_size = stack_size * 1024;
- }
-
- EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
- cfg->huge_worker_stack_size / 1024);
- return 0;
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
-
- case OPT_HUGE_DIR_NUM:
- {
- char *hdir = strdup(optarg);
- if (hdir == NULL)
- EAL_LOG(ERR, "Could not store hugepage directory");
- else {
- /* free old hugepage dir */
- free(internal_conf->hugepage_dir);
- internal_conf->hugepage_dir = hdir;
- }
- break;
- }
- case OPT_FILE_PREFIX_NUM:
- {
- char *prefix = strdup(optarg);
- if (prefix == NULL)
- EAL_LOG(ERR, "Could not store file prefix");
- else {
- /* free old prefix */
- free(internal_conf->hugefile_prefix);
- internal_conf->hugefile_prefix = prefix;
- }
- break;
- }
- case OPT_NUMA_MEM_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_mem) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_MEM
- " (aka --"
- OPT_SOCKET_MEM
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa = 1;
- break;
-
- case OPT_NUMA_LIMIT_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_limit) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_LIMIT
- " (aka --"
- OPT_SOCKET_LIMIT
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa_limits = 1;
- break;
-
- case OPT_VFIO_INTR_NUM:
- if (eal_parse_vfio_intr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_INTR);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_VFIO_VF_TOKEN_NUM:
- if (eal_parse_vfio_vf_token(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_VF_TOKEN);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_CREATE_UIO_DEV_NUM:
- internal_conf->create_uio_dev = 1;
- break;
-
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_MATCH_ALLOCATIONS_NUM:
- internal_conf->match_allocations = 1;
- break;
-
- case OPT_HUGE_WORKER_STACK_NUM:
- if (eal_parse_huge_worker_stack(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_HUGE_WORKER_STACK);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Linux", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Linux",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Linux", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -938,8 +579,18 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -970,18 +621,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 4f0a164d9b..14547d5ac9 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -82,99 +82,6 @@ rte_mp_disable(void)
return true;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too
- * if hook is set
- */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- int ret;
-
- /* getopt is not happy, stop right now */
- if (opt == '?') {
- eal_usage(prgname);
- return -1;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- return -1;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Windows", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Windows",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Windows", opt);
- }
- eal_usage(prgname);
- return -1;
- }
- }
-
- if (eal_adjust_config(internal_conf) != 0)
- return -1;
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- return -1;
- }
-
- if (optind >= 0)
- argv[optind - 1] = prgname;
- ret = optind - 1;
- optind = 0; /* reset getopt lib */
- return ret;
-}
-
static int
sync_func(void *arg __rte_unused)
{
@@ -260,8 +167,18 @@ rte_eal_init(int argc, char **argv)
char cpuset[RTE_CPU_AFFINITY_STR_LEN];
char thread_name[RTE_THREAD_NAME_SIZE];
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -288,9 +205,11 @@ rte_eal_init(int argc, char **argv)
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0)
- exit(1);
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
if (eal_option_device_parse()) {
rte_errno = ENODEV;
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 7/9] eal: ensure proper cleanup on EAL init failure
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
` (5 preceding siblings ...)
2025-07-21 15:16 ` [PATCH v5 6/9] eal: gather EAL args before processing Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 8/9] eal: combine parameter validation checks Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk
When rte_eal_init fails part way through, any saved EAL arguments need
to be freed, and the run_once flag needs to be set back to zero again.
The former task was never done on failure, and the latter was only done
on some occasions. Rework the error handling to always go to an err_out
label where cleanup is done.
To prevent memory leaks from the saved arguments when eal_init is called
twice, the check for multiple calls must be done first before the
argument saving and parsing is done.
This patch modifies all three eal.c files. Windows doesn't actually need
changes, since there are no args saved, and no run_once sentinel value,
but updating it keeps it consistent with FreeBSD and Linux versions.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
NOTE: this patch can probably be squashed in with the changes in the
previous one, but for easier review I've kept it separate for now.
---
lib/eal/common/eal_common_options.c | 37 ++++++++----
lib/eal/common/eal_options.h | 1 +
lib/eal/freebsd/eal.c | 83 +++++++++++++-------------
lib/eal/linux/eal.c | 90 ++++++++++++++---------------
lib/eal/windows/eal.c | 47 ++++++++-------
5 files changed, 137 insertions(+), 121 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index aea2c813ed..9c27d44a96 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -271,6 +271,8 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
int
eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+void
+eal_clean_saved_args(void) { /* no-op */ }
#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
@@ -302,6 +304,28 @@ handle_eal_info_request(const char *cmd, const char *params __rte_unused,
return used;
}
+void
+eal_clean_saved_args(void)
+{
+ int i;
+
+ if (eal_args == NULL)
+ return;
+
+ if (eal_app_args != NULL) {
+ i = 0;
+ while (eal_app_args[i] != NULL)
+ free(eal_app_args[i++]);
+ free(eal_app_args);
+ eal_app_args = NULL;
+ }
+ i = 0;
+ while (eal_args[i] != NULL)
+ free(eal_args[i++]);
+ free(eal_args);
+ eal_args = NULL;
+}
+
int
eal_save_args(int argc, char **argv)
{
@@ -346,18 +370,7 @@ eal_save_args(int argc, char **argv)
return 0;
error:
- if (eal_app_args != NULL) {
- i = 0;
- while (eal_app_args[i] != NULL)
- free(eal_app_args[i++]);
- free(eal_app_args);
- eal_app_args = NULL;
- }
- i = 0;
- while (eal_args[i] != NULL)
- free(eal_args[i++]);
- free(eal_args);
- eal_args = NULL;
+ eal_clean_saved_args();
return -1;
}
#endif /* !RTE_EXEC_ENV_WINDOWS */
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index c4d2cc84dc..fd28111e73 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -124,6 +124,7 @@ int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
+void eal_clean_saved_args(void);
int handle_eal_info_request(const char *cmd, const char *params __rte_unused,
struct rte_tel_data *d);
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index ee8bf92bff..2882d218f6 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -418,6 +418,14 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* first check if we have been run before */
+ if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
+ rte_memory_order_relaxed, rte_memory_order_relaxed)) {
+ rte_eal_init_alert("already called initialization.");
+ rte_errno = EALREADY;
+ return -1;
+ }
+
/* Save and collate args at the top */
eal_save_args(argc, argv);
@@ -425,14 +433,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("invalid command-line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(getprogname());
@@ -441,21 +449,14 @@ rte_eal_init(int argc, char **argv)
if (!rte_cpu_is_supported()) {
rte_eal_init_alert("unsupported cpu type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
- }
-
- if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
- rte_memory_order_relaxed, rte_memory_order_relaxed)) {
- rte_eal_init_alert("already called initialization.");
- rte_errno = EALREADY;
- return -1;
+ goto err_out;
}
eal_reset_internal_config(internal_conf);
@@ -463,14 +464,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
/* FreeBSD always uses legacy memory model */
@@ -483,37 +483,34 @@ rte_eal_init(int argc, char **argv)
if (eal_plugins_init() < 0) {
rte_eal_init_alert("Cannot init plugins");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_trace_init() < 0) {
rte_eal_init_alert("Cannot init trace");
rte_errno = EFAULT;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (rte_config_init() < 0) {
rte_eal_init_alert("Cannot init config");
- return -1;
+ goto err_out;
}
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_alarm_init() < 0) {
rte_eal_init_alert("Cannot init alarm");
/* rte_eal_alarm_init sets rte_errno on failure. */
- return -1;
+ goto err_out;
}
/* Put mp channel init before bus scan so that we can init the vdev
@@ -523,15 +520,14 @@ rte_eal_init(int argc, char **argv)
rte_eal_init_alert("failed to init mp channel");
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
}
if (rte_bus_scan()) {
rte_eal_init_alert("Cannot scan the buses for devices");
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
/*
@@ -562,13 +558,13 @@ rte_eal_init(int argc, char **argv)
if (iova_mode == RTE_IOVA_PA && !has_phys_addr) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (iova_mode == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
rte_eal_get_configuration()->iova_mode = iova_mode;
@@ -583,8 +579,7 @@ rte_eal_init(int argc, char **argv)
if (ret < 0) {
rte_eal_init_alert("Cannot get hugepage information.");
rte_errno = EACCES;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
}
@@ -613,7 +608,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -622,14 +617,14 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
if (rte_eal_malloc_heap_init() < 0) {
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -637,19 +632,19 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init HPET or TSC timers");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -660,7 +655,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -713,14 +708,14 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/* Probe all the buses and devices/drivers on them */
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* initialize default service/lcore mappings and start running. Ignore
@@ -729,7 +724,7 @@ rte_eal_init(int argc, char **argv)
ret = rte_service_start_with_defaults();
if (ret < 0 && ret != -ENOTSUP) {
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/*
@@ -744,18 +739,22 @@ rte_eal_init(int argc, char **argv)
*/
if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
rte_eal_init_alert("Cannot clear runtime directory");
- return -1;
+ goto err_out;
}
if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
if (rte_telemetry_init(rte_eal_get_runtime_dir(),
rte_version(),
&internal_conf->ctrl_cpuset) != 0)
- return -1;
+ goto err_out;
}
eal_mcfg_complete();
return fctret;
+err_out:
+ rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
+ eal_clean_saved_args();
+ return -1;
}
RTE_EXPORT_SYMBOL(rte_eal_cleanup)
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index f59cb43b0e..210d461497 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -579,6 +579,14 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* first check if we have been run before */
+ if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
+ rte_memory_order_relaxed, rte_memory_order_relaxed)) {
+ rte_eal_init_alert("already called initialization.");
+ rte_errno = EALREADY;
+ return -1;
+ }
+
/* clone argv to report out later in telemetry */
eal_save_args(argc, argv);
@@ -586,14 +594,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(program_invocation_short_name);
@@ -602,21 +610,14 @@ rte_eal_init(int argc, char **argv)
if (!rte_cpu_is_supported()) {
rte_eal_init_alert("unsupported cpu type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
- }
-
- if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
- rte_memory_order_relaxed, rte_memory_order_relaxed)) {
- rte_eal_init_alert("already called initialization.");
- rte_errno = EALREADY;
- return -1;
+ goto err_out;
}
eal_reset_internal_config(internal_conf);
@@ -624,49 +625,46 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
- rte_eal_init_alert("Invalid command line arguments.");
+ rte_eal_init_alert("Error parsing command line arguments.");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_plugins_init() < 0) {
rte_eal_init_alert("Cannot init plugins");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_trace_init() < 0) {
rte_eal_init_alert("Cannot init trace");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (rte_config_init() < 0) {
rte_eal_init_alert("Cannot init config");
- return -1;
+ goto err_out;
}
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_alarm_init() < 0) {
rte_eal_init_alert("Cannot init alarm");
/* rte_eal_alarm_init sets rte_errno on failure. */
- return -1;
+ goto err_out;
}
/* Put mp channel init before bus scan so that we can init the vdev
@@ -676,15 +674,14 @@ rte_eal_init(int argc, char **argv)
rte_eal_init_alert("failed to init mp channel");
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
}
if (rte_bus_scan()) {
rte_eal_init_alert("Cannot scan the buses for devices");
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
phys_addrs = rte_eal_using_phys_addrs() != 0;
@@ -727,13 +724,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_iova_mode() == RTE_IOVA_PA && !phys_addrs) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (rte_eal_iova_mode() == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
EAL_LOG(INFO, "Selected IOVA mode '%s'",
@@ -747,8 +744,7 @@ rte_eal_init(int argc, char **argv)
if (ret < 0) {
rte_eal_init_alert("Cannot get hugepage information.");
rte_errno = EACCES;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
}
@@ -772,8 +768,7 @@ rte_eal_init(int argc, char **argv)
if (rte_vfio_enable("vfio")) {
rte_eal_init_alert("Cannot init VFIO");
rte_errno = EAGAIN;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
#endif
/* in secondary processes, memory init may allocate additional fbarrays
@@ -783,7 +778,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -792,7 +787,7 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
/* the directories are locked during eal_hugepage_info_init */
@@ -802,7 +797,7 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -810,25 +805,25 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
/* register multi-process action callbacks for hotplug after memory init */
if (eal_mp_dev_hotplug_init() < 0) {
rte_eal_init_alert("failed to register mp callback for hotplug");
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init HPET or TSC timers");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -839,7 +834,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -890,14 +885,14 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/* Probe all the buses and devices/drivers on them */
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* initialize default service/lcore mappings and start running. Ignore
@@ -906,7 +901,7 @@ rte_eal_init(int argc, char **argv)
ret = rte_service_start_with_defaults();
if (ret < 0 && ret != -ENOTSUP) {
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/*
@@ -921,18 +916,23 @@ rte_eal_init(int argc, char **argv)
*/
if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
rte_eal_init_alert("Cannot clear runtime directory");
- return -1;
+ goto err_out;
}
if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
if (rte_telemetry_init(rte_eal_get_runtime_dir(),
rte_version(),
&internal_conf->ctrl_cpuset) != 0)
- return -1;
+ goto err_out;
}
eal_mcfg_complete();
return fctret;
+
+err_out:
+ rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
+ eal_clean_saved_args();
+ return -1;
}
static int
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 14547d5ac9..cd9a72a0fc 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -174,14 +174,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(NULL);
@@ -189,31 +189,31 @@ rte_eal_init(int argc, char **argv)
if (eal_create_cpu_map() < 0) {
rte_eal_init_alert("Cannot discover CPU and NUMA.");
/* rte_errno is set */
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("Unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
/* Prevent creation of shared memory files. */
@@ -227,7 +227,7 @@ rte_eal_init(int argc, char **argv)
if (!internal_conf->no_hugetlbfs && (eal_hugepage_info_init() < 0)) {
rte_eal_init_alert("Cannot get hugepage information");
rte_errno = EACCES;
- return -1;
+ goto err_out;
}
if (internal_conf->memory == 0 && !internal_conf->force_numa) {
@@ -237,26 +237,26 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init TSC timer");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
bscan = rte_bus_scan();
if (bscan < 0) {
rte_eal_init_alert("Cannot scan the buses");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (eal_mem_win32api_init() < 0) {
rte_eal_init_alert("Cannot access Win32 memory management");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
has_phys_addr = true;
@@ -289,13 +289,13 @@ rte_eal_init(int argc, char **argv)
if (iova_mode == RTE_IOVA_PA && !has_phys_addr) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (iova_mode == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
EAL_LOG(DEBUG, "Selected IOVA mode '%s'",
@@ -305,7 +305,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -314,14 +314,14 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
if (rte_eal_malloc_heap_init() < 0) {
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -329,13 +329,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -344,7 +344,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -390,13 +390,13 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/*
@@ -409,6 +409,9 @@ rte_eal_init(int argc, char **argv)
eal_mcfg_complete();
return fctret;
+err_out:
+ eal_clean_saved_args();
+ return -1;
}
/* Don't use MinGW asprintf() to have identical code with all toolchains. */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 8/9] eal: combine parameter validation checks
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
` (6 preceding siblings ...)
2025-07-21 15:16 ` [PATCH v5 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Anatoly Burakov, Tyler Retzlaff
Remove the separate function to check combinations of cmdline
parameters. Instead, just do those checks when parsing the parameters
since we have all info about what parameters are provided at that point.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 262 +++++++++++-----------------
lib/eal/common/eal_options.h | 107 ------------
lib/eal/linux/eal.c | 5 +-
lib/eal/linux/eal_memory.c | 2 +-
5 files changed, 106 insertions(+), 273 deletions(-)
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 38ccc734e8..c62edf5e55 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -258,8 +258,7 @@ eal_memseg_list_alloc(struct rte_memseg_list *msl, int reserve_flags)
* including common code, so don't duplicate the message.
*/
if (rte_errno == EADDRNOTAVAIL)
- EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - "
- "please use '--" OPT_BASE_VIRTADDR "' option",
+ EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - please use '--base-virtaddr' option",
(unsigned long long)mem_sz, msl->base_va);
#endif
return -1;
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 9c27d44a96..486e2ad854 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -243,7 +243,6 @@ struct device_option {
static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
-static int main_lcore_parsed;
static int core_parsed;
/* Returns rte_usage_hook_t */
@@ -751,15 +750,6 @@ eal_parse_service_coremask(const char *coremask)
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE;
j++, idx++) {
if ((1 << j) & val) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (main_lcore_parsed &&
- cfg->main_lcore == lcore) {
- EAL_LOG(ERR,
- "lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (eal_cpu_detected(idx) == 0) {
EAL_LOG(ERR,
@@ -982,15 +972,6 @@ eal_parse_service_corelist(const char *corelist)
min = idx;
for (idx = min; idx <= max; idx++) {
if (cfg->lcore_role[idx] != ROLE_SERVICE) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (cfg->main_lcore == lcore &&
- main_lcore_parsed) {
- EAL_LOG(ERR,
- "Error: lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (cfg->lcore_role[idx] == ROLE_RTE)
taken_lcore_count++;
@@ -1030,12 +1011,15 @@ eal_parse_main_lcore(const char *arg)
return -1;
if (cfg->main_lcore >= RTE_MAX_LCORE)
return -1;
- main_lcore_parsed = 1;
/* ensure main core is not used as service core */
if (lcore_config[cfg->main_lcore].core_role == ROLE_SERVICE) {
- EAL_LOG(ERR,
- "Error: Main lcore is used as a service core");
+ EAL_LOG(ERR, "Error: Main lcore is used as a service core");
+ return -1;
+ }
+ /* check that we have the core recorded in the core list */
+ if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
+ EAL_LOG(ERR, "Error: Main lcore is not enabled for DPDK");
return -1;
}
@@ -1330,11 +1314,11 @@ eal_log_usage(void)
rte_log_list_types(stdout, "\t");
printf("\n");
printf("Syntax using globbing pattern: ");
- printf("--"OPT_LOG_LEVEL" pattern:level\n");
+ printf("--log-level pattern:level\n");
printf("Syntax using regular expression: ");
- printf("--"OPT_LOG_LEVEL" regexp,level\n");
+ printf("--log-level regexp,level\n");
printf("Syntax for the global level: ");
- printf("--"OPT_LOG_LEVEL" level\n");
+ printf("--log-level level\n");
printf("Logs are emitted if allowed by both global and specific levels.\n");
printf("\n");
printf("Log level can be a number or the first letters of its name:\n");
@@ -1614,7 +1598,7 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return 0;
}
if (strcmp(arg, HUGE_UNLINK_NEVER) == 0) {
- EAL_LOG(WARNING, "Using --"OPT_HUGE_UNLINK"="
+ EAL_LOG(WARNING, "Using --huge-unlink="
HUGE_UNLINK_NEVER" may create data leaks.");
out->unlink_existing = false;
return 0;
@@ -1793,6 +1777,7 @@ int
eal_parse_args(void)
{
struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
/* check for conflicting options */
@@ -1818,19 +1803,62 @@ eal_parse_args(void)
}
/* can't have both -m and --socket-mem */
if (args.memory_size != NULL && args.numa_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ EAL_LOG(ERR, "Options -m and --numa-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use both no-huge and socket-mem */
+ if (args.no_huge && args.numa_mem) {
+ EAL_LOG(ERR, "Options --no-huge and --numa-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-worker-stack */
+ if (args.huge_worker_stack != NULL && args.no_huge) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
+ return -1;
+ }
+ /* can't use socket-limit and legacy-mem */
+ if (args.numa_limit != NULL && args.legacy_mem) {
+ EAL_LOG(ERR, "Options --numa-limit and --legacy-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and in-memory */
+ if (args.legacy_mem && args.in_memory) {
+ EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and match-allocations */
+ if (args.legacy_mem && args.match_allocations) {
+ EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and match-allocations */
+ if (args.no_huge && args.match_allocations) {
+ EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-unlink */
+ if (args.no_huge && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use single-file-segments and huge-unlink */
+ if (args.single_file_segments && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use in-memory and huge-unlink */
+ if (args.in_memory && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
return -1;
}
- /* parse options */
/* print version before anything else */
- if (args.version) {
- /* since message is explicitly requested by user, we write message
- * at highest log level so it can always be seen even if info or
- * warning messages are disabled
- */
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ if (args.version)
EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- }
/* parse the process type */
if (args.proc_type != NULL) {
@@ -1856,7 +1884,7 @@ eal_parse_args(void)
if (eal_plugin_add(arg->arg) < 0)
return -1;
- /* parse the coremask /core-list */
+ /* parse the core list arguments */
if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
@@ -1880,13 +1908,6 @@ eal_parse_args(void)
}
core_parsed = 1;
}
- if (args.main_lcore != NULL) {
- if (eal_parse_main_lcore(args.main_lcore) < 0) {
- EAL_LOG(ERR, "invalid main-lcore parameter");
- return -1;
- }
- }
-
/* service core options */
if (args.service_coremask != NULL) {
if (eal_parse_service_coremask(args.service_coremask) < 0) {
@@ -1901,6 +1922,17 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0)
+ return -1;
+ } else {
+ /* default main lcore is the first one */
+ rte_cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
+ if (rte_cfg->main_lcore >= RTE_MAX_LCORE) {
+ EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
+ return -1;
+ }
+ }
/* memory options */
if (args.memory_size != NULL) {
@@ -1922,14 +1954,6 @@ eal_parse_args(void)
return -1;
}
}
- if (args.huge_unlink != NULL) {
- if (args.huge_unlink == (void *)1)
- args.huge_unlink = NULL;
- if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid huge-unlink parameter");
- return -1;
- }
- }
if (args.no_huge) {
int_cfg->no_hugetlbfs = 1;
/* no-huge is legacy mem */
@@ -1941,11 +1965,18 @@ eal_parse_args(void)
int_cfg->no_shconf = 1;
int_cfg->hugepage_file.unlink_before_mapping = true;
}
- if (args.legacy_mem)
+ if (args.legacy_mem) {
int_cfg->legacy_mem = 1;
+ if (args.memory_size == NULL && args.numa_mem == NULL)
+ EAL_LOG(NOTICE, "Static memory layout is selected, amount of reserved memory can be adjusted with -m or --socket-mem");
+ }
if (args.single_file_segments)
int_cfg->single_file_segments = 1;
if (args.huge_dir != NULL) {
+ if (strlen(args.huge_dir) < 1) {
+ EAL_LOG(ERR, "Invalid hugepage dir parameter");
+ return -1;
+ }
free(int_cfg->hugepage_dir); /* free old hugepage dir */
int_cfg->hugepage_dir = strdup(args.huge_dir);
if (int_cfg->hugepage_dir == NULL) {
@@ -1954,6 +1985,14 @@ eal_parse_args(void)
}
}
if (args.file_prefix != NULL) {
+ if (strlen(args.file_prefix) < 1) {
+ EAL_LOG(ERR, "Invalid file prefix parameter");
+ return -1;
+ }
+ if (strchr(args.file_prefix, '%') != NULL) {
+ EAL_LOG(ERR, "Invalid char, '%%', in file_prefix parameter");
+ return -1;
+ }
free(int_cfg->hugefile_prefix); /* free old file prefix */
int_cfg->hugefile_prefix = strdup(args.file_prefix);
if (int_cfg->hugefile_prefix == NULL) {
@@ -1961,6 +2000,14 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
+ return -1;
+ }
+ }
if (args.numa_mem != NULL) {
if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
@@ -2078,6 +2125,10 @@ eal_parse_args(void)
EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
+ if (strlen(int_cfg->user_mbuf_pool_ops_name) < 1) {
+ EAL_LOG(ERR, "Invalid mbuf pool ops name parameter");
+ return -1;
+ }
}
#ifndef RTE_EXEC_ENV_WINDOWS
@@ -2096,11 +2147,6 @@ eal_parse_args(void)
return -1;
}
- if (eal_check_common_options(int_cfg) != 0) {
- EAL_LOG(ERR, "Checking common options failed");
- return -1;
- }
-
return 0;
}
@@ -2180,14 +2226,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
if (internal_conf->process_type == RTE_PROC_AUTO)
internal_conf->process_type = eal_proc_type_detect();
- /* default main lcore is the first one */
- if (!main_lcore_parsed) {
- cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
- if (cfg->main_lcore >= RTE_MAX_LCORE)
- return -1;
- lcore_config[cfg->main_lcore].core_role = ROLE_RTE;
- }
-
compute_ctrl_threads_cpuset(internal_cfg);
/* if no memory amounts were requested, this will result in 0 and
@@ -2198,102 +2236,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
return 0;
}
-int
-eal_check_common_options(struct internal_config *internal_cfg)
-{
- struct rte_config *cfg = rte_eal_get_configuration();
- const struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
- EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
- return -1;
- }
-
- if (internal_cfg->process_type == RTE_PROC_INVALID) {
- EAL_LOG(ERR, "Invalid process type specified");
- return -1;
- }
- if (internal_cfg->hugefile_prefix != NULL &&
- strlen(internal_cfg->hugefile_prefix) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_FILE_PREFIX " option");
- return -1;
- }
- if (internal_cfg->hugepage_dir != NULL &&
- strlen(internal_cfg->hugepage_dir) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_HUGE_DIR" option");
- return -1;
- }
- if (internal_cfg->user_mbuf_pool_ops_name != NULL &&
- strlen(internal_cfg->user_mbuf_pool_ops_name) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_MBUF_POOL_OPS_NAME" option");
- return -1;
- }
- if (strchr(eal_get_hugefile_prefix(), '%') != NULL) {
- EAL_LOG(ERR, "Invalid char, '%%', in --"OPT_FILE_PREFIX" "
- "option");
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_UNLINK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->huge_worker_stack_size != 0) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_WORKER_STACK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_conf->force_numa_limits && internal_conf->legacy_mem) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_LIMIT
- " is only supported in non-legacy memory mode");
- }
- if (internal_cfg->single_file_segments &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
- "not compatible with --"OPT_HUGE_UNLINK);
- return -1;
- }
- if (!internal_cfg->hugepage_file.unlink_existing &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_IN_MEMORY" is not compatible "
- "with --"OPT_HUGE_UNLINK"="HUGE_UNLINK_NEVER);
- return -1;
- }
- if (internal_cfg->legacy_mem &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_IN_MEMORY);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_NO_HUGE" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->memory == 0) {
- EAL_LOG(NOTICE, "Static memory layout is selected, "
- "amount of reserved memory can be adjusted with "
- "-m or --"OPT_NUMA_MEM);
- }
-
- return 0;
-}
-
RTE_EXPORT_SYMBOL(rte_vect_get_max_simd_bitwidth)
uint16_t
rte_vect_get_max_simd_bitwidth(void)
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index fd28111e73..4a8a0f1df7 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -9,118 +9,11 @@
struct rte_tel_data;
-enum {
- /* long options mapped to a short option */
-#define OPT_HELP "help"
- OPT_HELP_NUM = 'h',
-#define OPT_DEV_ALLOW "allow"
- OPT_DEV_ALLOW_NUM = 'a',
-#define OPT_DEV_BLOCK "block"
- OPT_DEV_BLOCK_NUM = 'b',
-#define OPT_COREMASK "coremask"
- OPT_COREMASK_NUM = 'c',
-#define OPT_DRIVER_PATH "driver-path"
- OPT_DRIVER_PATH_NUM = 'd',
-#define OPT_LCORES "lcores"
- OPT_LCORES_NUM = 'l',
-#define OPT_MEMORY_SIZE "memory-size"
- OPT_MEMORY_SIZE_NUM = 'm',
-#define OPT_MEMORY_CHANNELS "memory-channels"
- OPT_MEMORY_CHANNELS_NUM = 'n',
-#define OPT_MEMORY_RANKS "memory-ranks"
- OPT_MEMORY_RANKS_NUM = 'r',
-#define OPT_SERVICE_COREMASK "service-coremask"
- OPT_SERVICE_COREMASK_NUM = 's',
-#define OPT_SERVICE_CORELIST "service-corelist"
- OPT_SERVICE_CORELIST_NUM = 'S',
-#define OPT_VERSION "version"
- OPT_VERSION_NUM = 'v',
-
- /* first long only option value must be >= 256, so that we won't
- * conflict with short options */
- OPT_LONG_MIN_NUM = 256,
-#define OPT_BASE_VIRTADDR "base-virtaddr"
- OPT_BASE_VIRTADDR_NUM,
-#define OPT_CREATE_UIO_DEV "create-uio-dev"
- OPT_CREATE_UIO_DEV_NUM,
-#define OPT_FILE_PREFIX "file-prefix"
- OPT_FILE_PREFIX_NUM,
-#define OPT_HUGE_DIR "huge-dir"
- OPT_HUGE_DIR_NUM,
-#define OPT_HUGE_UNLINK "huge-unlink"
- OPT_HUGE_UNLINK_NUM,
-#define OPT_LOG_COLOR "log-color"
- OPT_LOG_COLOR_NUM,
-#define OPT_LOG_LEVEL "log-level"
- OPT_LOG_LEVEL_NUM,
-#define OPT_LOG_TIMESTAMP "log-timestamp"
- OPT_LOG_TIMESTAMP_NUM,
-#define OPT_TRACE "trace"
- OPT_TRACE_NUM,
-#define OPT_TRACE_DIR "trace-dir"
- OPT_TRACE_DIR_NUM,
-#define OPT_TRACE_BUF_SIZE "trace-bufsz"
- OPT_TRACE_BUF_SIZE_NUM,
-#define OPT_TRACE_MODE "trace-mode"
- OPT_TRACE_MODE_NUM,
-#define OPT_MAIN_LCORE "main-lcore"
- OPT_MAIN_LCORE_NUM,
-#define OPT_MBUF_POOL_OPS_NAME "mbuf-pool-ops-name"
- OPT_MBUF_POOL_OPS_NAME_NUM,
-#define OPT_PROC_TYPE "proc-type"
- OPT_PROC_TYPE_NUM,
-#define OPT_NO_HPET "no-hpet"
- OPT_NO_HPET_NUM,
-#define OPT_NO_HUGE "no-huge"
- OPT_NO_HUGE_NUM,
-#define OPT_NO_PCI "no-pci"
- OPT_NO_PCI_NUM,
-#define OPT_NO_SHCONF "no-shconf"
- OPT_NO_SHCONF_NUM,
-#define OPT_IN_MEMORY "in-memory"
- OPT_IN_MEMORY_NUM,
-#define OPT_SOCKET_MEM "socket-mem"
-#define OPT_NUMA_MEM "numa-mem"
- OPT_NUMA_MEM_NUM,
-#define OPT_SOCKET_LIMIT "socket-limit"
-#define OPT_NUMA_LIMIT "numa-limit"
- OPT_NUMA_LIMIT_NUM,
-#define OPT_SYSLOG "syslog"
- OPT_SYSLOG_NUM,
-#define OPT_VDEV "vdev"
- OPT_VDEV_NUM,
-#define OPT_VFIO_INTR "vfio-intr"
- OPT_VFIO_INTR_NUM,
-#define OPT_VFIO_VF_TOKEN "vfio-vf-token"
- OPT_VFIO_VF_TOKEN_NUM,
-#define OPT_VMWARE_TSC_MAP "vmware-tsc-map"
- OPT_VMWARE_TSC_MAP_NUM,
-#define OPT_LEGACY_MEM "legacy-mem"
- OPT_LEGACY_MEM_NUM,
-#define OPT_SINGLE_FILE_SEGMENTS "single-file-segments"
- OPT_SINGLE_FILE_SEGMENTS_NUM,
-#define OPT_IOVA_MODE "iova-mode"
- OPT_IOVA_MODE_NUM,
-#define OPT_MATCH_ALLOCATIONS "match-allocations"
- OPT_MATCH_ALLOCATIONS_NUM,
-#define OPT_TELEMETRY "telemetry"
- OPT_TELEMETRY_NUM,
-#define OPT_NO_TELEMETRY "no-telemetry"
- OPT_NO_TELEMETRY_NUM,
-#define OPT_FORCE_MAX_SIMD_BITWIDTH "force-max-simd-bitwidth"
- OPT_FORCE_MAX_SIMD_BITWIDTH_NUM,
-#define OPT_HUGE_WORKER_STACK "huge-worker-stack"
- OPT_HUGE_WORKER_STACK_NUM,
-
- OPT_LONG_MAX_NUM
-};
-
int eal_parse_log_options(void);
int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
-int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 210d461497..babd36bf37 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -329,9 +329,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
/* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option", rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index e433c1afee..a366083822 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -1967,7 +1967,7 @@ rte_eal_memseg_init(void)
if (!internal_conf->legacy_mem && rte_socket_count() > 1) {
EAL_LOG(WARNING, "DPDK is running on a NUMA system, but is compiled without NUMA support.");
EAL_LOG(WARNING, "This will have adverse consequences for performance and usability.");
- EAL_LOG(WARNING, "Please use --"OPT_LEGACY_MEM" option, or recompile with NUMA support.");
+ EAL_LOG(WARNING, "Please use --legacy-mem option, or recompile with NUMA support.");
}
#endif
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 9/9] eal: simplify handling of conflicting cmdline options
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
` (7 preceding siblings ...)
2025-07-21 15:16 ` [PATCH v5 8/9] eal: combine parameter validation checks Bruce Richardson
@ 2025-07-21 15:16 ` Bruce Richardson
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-21 15:16 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
Use a utility function and macro to simplify the code for checking for
conflicting cmdline options. The checking can also be done at the
initial argument collating stage, shortening the argument
processing function which is very much on the long side.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 119 +++++++++++-----------------
1 file changed, 47 insertions(+), 72 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 486e2ad854..c568e59ef3 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -178,6 +178,29 @@ struct rte_argparse eal_argparse = {
}
};
+static inline bool
+conflicting_options(uintptr_t opt1, uintptr_t opt2, const char *opt1_name, const char *opt2_name)
+{
+ char name1[64]; /* should be the max length of any argument */
+ char name2[64];
+
+ strlcpy(name1, opt1_name, sizeof(name1));
+ strlcpy(name2, opt2_name, sizeof(name2));
+ for (int i = 0; name1[i] != '\0'; i++)
+ if (name1[i] == '_')
+ name1[i] = '-';
+ for (int i = 0; name2[i] != '\0'; i++)
+ if (name2[i] == '_')
+ name2[i] = '-';
+ if (opt1 && opt2) {
+ EAL_LOG(ERR, "Options '%s' and '%s' can't be used at the same time", name1, name2);
+ return true;
+ }
+ return false; /* no conflicts */
+}
+#define CONFLICTING_OPTIONS(args, opt1, opt2) \
+ conflicting_options((uintptr_t)(args.opt1), (uintptr_t)(args.opt2), #opt1, #opt2)
+
/* function to call into argparse library to parse the passed argc/argv parameters
* to the eal_init_args structure.
*/
@@ -200,6 +223,30 @@ eal_collate_args(int argc, char **argv)
if (retval < 0)
return retval;
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+
+ /* for non-list args, we can just check for zero/null values using macro */
+ if (CONFLICTING_OPTIONS(args, coremask, lcores) ||
+ CONFLICTING_OPTIONS(args, service_coremask, service_corelist) ||
+ CONFLICTING_OPTIONS(args, no_telemetry, telemetry) ||
+ CONFLICTING_OPTIONS(args, memory_size, numa_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, numa_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_worker_stack) ||
+ CONFLICTING_OPTIONS(args, numa_limit, legacy_mem) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, in_memory) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, single_file_segments, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, no_huge, single_file_segments) ||
+ CONFLICTING_OPTIONS(args, in_memory, huge_unlink))
+ return -1;
+
argv[retval - 1] = argv[0];
return retval - 1;
}
@@ -1780,78 +1827,6 @@ eal_parse_args(void)
struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
- /* check for conflicting options */
- /* both -a and -b cannot be used together (one list must be empty at least) */
- if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
- EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
- }
- /* both -l and -c cannot be used at the same time */
- if (args.coremask != NULL && args.lcores != NULL) {
- EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
- return -1;
- }
- /* both -s and -S cannot be used at the same time */
- if (args.service_coremask != NULL && args.service_corelist != NULL) {
- EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
- return -1;
- }
- /* can't have both telemetry and no-telemetry */
- if (args.no_telemetry && args.telemetry) {
- EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
- return -1;
- }
- /* can't have both -m and --socket-mem */
- if (args.memory_size != NULL && args.numa_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --numa-mem can't be used at the same time");
- return -1;
- }
- /* can't use both no-huge and socket-mem */
- if (args.no_huge && args.numa_mem) {
- EAL_LOG(ERR, "Options --no-huge and --numa-mem can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-worker-stack */
- if (args.huge_worker_stack != NULL && args.no_huge) {
- EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
- return -1;
- }
- /* can't use socket-limit and legacy-mem */
- if (args.numa_limit != NULL && args.legacy_mem) {
- EAL_LOG(ERR, "Options --numa-limit and --legacy-mem can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and in-memory */
- if (args.legacy_mem && args.in_memory) {
- EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and match-allocations */
- if (args.legacy_mem && args.match_allocations) {
- EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and match-allocations */
- if (args.no_huge && args.match_allocations) {
- EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-unlink */
- if (args.no_huge && args.huge_unlink) {
- EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use single-file-segments and huge-unlink */
- if (args.single_file_segments && args.huge_unlink) {
- EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use in-memory and huge-unlink */
- if (args.in_memory && args.huge_unlink) {
- EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
- return -1;
- }
-
/* print version before anything else */
/* since message is explicitly requested by user, we write message
* at highest log level so it can always be seen even if info or
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 0/9] rework EAL argument parsing
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
` (19 preceding siblings ...)
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 1/9] build: add define for the OS environment name Bruce Richardson
` (8 more replies)
20 siblings, 9 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
When processing cmdline arguments in DPDK, we always do so with very
little context. So, for example, when processing the "-l" flag, we have
no idea whether there will be later a --proc-type=secondary flag. We
have all sorts of post-arg-processing checks in place to try and catch
these scenarios.
To improve this situation, this patchset tries to simplify the handling
of argument processing, by explicitly doing an initial pass to collate
all arguments into a structure. Thereafter, the actual arg parsing is
done in a fixed order, meaning that e.g. when processing the
--main-lcore flag, we have already processed the service core flags. We
also can far quicker and easier check for conflicting options, since
they can all be checked for NULL/non-NULL in the arg structure
immediately after the struct has been populated.
To do the initial argument gathering, this RFC uses the existing
argparse library in DPDK. With recent changes, and two additional
patches at the start of this set, this library now meets our needs for
EAL argument parsing and allows us to not need to do direct getopt
argument processing inside EAL at all.
An additional benefit of this work is that the argument parsing for EAL
is much more centralised into common options and the options list file.
This single list with ifdefs makes it clear to the viewer what options
are common across OS's, vs what are unix-only or linux-only.
V6:
* Rebase to apply cleanly on latest main
V5:
* Resubmit of V4, which didn't get sent correctly, or picked up correctly
in patchwork.
V4:
* Updated patch 5 to auto-generate the arg struct definition from the same
list of defines used to construct the argument list.
V3:
* Added 3 new initial patches, one for minor build-system addition, and two
for functionality in argparse to allow the user-callback help function to
be maintained as we move to argparse.
* Added doc updates in the first EAL patch adding the long options
* Fixed ASAN issues by adding a patch to properly clean up EAL init - both
memory allocations and fixing the run-once flag
* Put ifdefs around the linux-only or unix-only options in EAL patch 2
* Updated args to handle numa-mem and numa-limit as equivalent socket-mem
and socket-limit
Bruce Richardson (9):
build: add define for the OS environment name
argparse: export function to print help text for object
argparse: allow user-override of help printing
eal: add long options for each short option
eal: define the EAL parameters in argparse format
eal: gather EAL args before processing
eal: ensure proper cleanup on EAL init failure
eal: combine parameter validation checks
eal: simplify handling of conflicting cmdline options
config/meson.build | 1 +
doc/guides/contributing/design.rst | 2 +-
doc/guides/linux_gsg/eal_args.include.rst | 20 +-
doc/guides/prog_guide/argparse_lib.rst | 16 +
lib/argparse/rte_argparse.c | 46 +-
lib/argparse/rte_argparse.h | 21 +-
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 1218 +++++++++++----------
lib/eal/common/eal_option_list.h | 90 ++
lib/eal/common/eal_options.h | 102 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 245 +----
lib/eal/linux/eal.c | 470 +-------
lib/eal/linux/eal_memory.c | 2 +-
lib/eal/meson.build | 2 +-
lib/eal/windows/eal.c | 156 +--
lib/meson.build | 1 +
17 files changed, 960 insertions(+), 1446 deletions(-)
create mode 100644 lib/eal/common/eal_option_list.h
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 1/9] build: add define for the OS environment name
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 2/9] argparse: export function to print help text for object Bruce Richardson
` (7 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson
Introduce a string define for the currently running OS, or execution
environment.
Originally, with old make build system, CONFIG_RTE_EXEC_ENV used to hold
this name string, but the variable seems to have been missed in the
meson build system, until commit cadb255e25d6 ("eal: add OS defines for
C conditional checks") which introduced the RTE_EXEC_ENV for a different
purpose. Now we can fix the docs with the new name reference.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
config/meson.build | 1 +
doc/guides/contributing/design.rst | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/config/meson.build b/config/meson.build
index f31fef216c..40f33816aa 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -20,6 +20,7 @@ foreach env, id:exec_envs
dpdk_conf.set10('RTE_EXEC_ENV_IS_' + env.to_upper(), (exec_env == env))
endforeach
dpdk_conf.set('RTE_EXEC_ENV', exec_envs[exec_env])
+dpdk_conf.set_quoted('RTE_EXEC_ENV_NAME', exec_env)
dpdk_conf.set('RTE_EXEC_ENV_' + exec_env.to_upper(), 1)
# MS linker requires special treatment.
diff --git a/doc/guides/contributing/design.rst b/doc/guides/contributing/design.rst
index b724177ba1..5517613424 100644
--- a/doc/guides/contributing/design.rst
+++ b/doc/guides/contributing/design.rst
@@ -50,7 +50,7 @@ Per Execution Environment Sources
The following macro options can be used:
-* ``RTE_EXEC_ENV`` is a string that contains the name of the executive environment.
+* ``RTE_EXEC_ENV_NAME`` is a string that contains the name of the executive environment.
* ``RTE_EXEC_ENV_FREEBSD``, ``RTE_EXEC_ENV_LINUX`` or ``RTE_EXEC_ENV_WINDOWS`` are defined only if we are building for this execution environment.
Mbuf features
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 2/9] argparse: export function to print help text for object
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 1/9] build: add define for the OS environment name Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 3/9] argparse: allow user-override of help printing Bruce Richardson
` (6 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
Make the function to print out the help text for an argparse object a
public function, which takes as a new parameter the file stream on which
to print. This can be used in future to allow application to extend
their own help information.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/argparse/rte_argparse.c | 43 +++++++++++++++++++------------------
lib/argparse/rte_argparse.h | 14 ++++++++++++
2 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index 331f05f01d..d3b32c6357 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -716,23 +716,23 @@ calc_help_align(const struct rte_argparse *obj)
}
static void
-show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width)
+show_oneline_help(FILE *stream, const struct rte_argparse_arg *arg, uint32_t width)
{
uint32_t len = 0;
uint32_t i;
if (arg->name_short != NULL)
- len = printf(" %s,", arg->name_short);
- len += printf(" %s", arg->name_long);
+ len = fprintf(stream, " %s,", arg->name_short);
+ len += fprintf(stream, " %s", arg->name_long);
for (i = len; i < width; i++)
- printf(" ");
+ fprintf(stream, " ");
- printf("%s\n", arg->help);
+ fprintf(stream, "%s\n", arg->help);
}
static void
-show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
+show_args_pos_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
{
uint32_t position_count = calc_position_count(obj);
const struct rte_argparse_arg *arg;
@@ -741,19 +741,19 @@ show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
if (position_count == 0)
return;
- printf("\npositional arguments:\n");
+ fprintf(stream, "\npositional arguments:\n");
for (i = 0; /* NULL */; i++) {
arg = &obj->args[i];
if (arg->name_long == NULL)
break;
if (!is_arg_positional(arg))
continue;
- show_oneline_help(arg, align);
+ show_oneline_help(stream, arg, align);
}
}
static void
-show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
+show_args_opt_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
{
static const struct rte_argparse_arg help = {
.name_long = "--help",
@@ -763,34 +763,35 @@ show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
const struct rte_argparse_arg *arg;
uint32_t i;
- printf("\noptions:\n");
- show_oneline_help(&help, align);
+ fprintf(stream, "\noptions:\n");
+ show_oneline_help(stream, &help, align);
for (i = 0; /* NULL */; i++) {
arg = &obj->args[i];
if (arg->name_long == NULL)
break;
if (!is_arg_optional(arg))
continue;
- show_oneline_help(arg, align);
+ show_oneline_help(stream, arg, align);
}
}
-static void
-show_args_help(const struct rte_argparse *obj)
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_print_help, 25.07)
+void
+rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj)
{
uint32_t align = calc_help_align(obj);
- printf("usage: %s %s\n", obj->prog_name, obj->usage);
+ fprintf(stream, "usage: %s %s\n", obj->prog_name, obj->usage);
if (obj->descriptor != NULL)
- printf("\ndescriptor: %s\n", obj->descriptor);
+ fprintf(stream, "\ndescriptor: %s\n", obj->descriptor);
- show_args_pos_help(obj, align);
- show_args_opt_help(obj, align);
+ show_args_pos_help(stream, obj, align);
+ show_args_opt_help(stream, obj, align);
if (obj->epilog != NULL)
- printf("\n%s\n", obj->epilog);
+ fprintf(stream, "\n%s\n", obj->epilog);
else
- printf("\n");
+ fprintf(stream, "\n");
}
RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_parse, 24.03)
@@ -820,7 +821,7 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
goto error;
if (show_help) {
- show_args_help(obj);
+ rte_argparse_print_help(stdout, obj);
exit(0);
}
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index 52bef34363..baf278f6b9 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -189,6 +189,20 @@ struct rte_argparse {
__rte_experimental
int rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Output the help text information for the given argparse object.
+ *
+ * @param stream
+ * Output file handle, e.g. stdout, stderr, on which to print the help text.
+ * @param obj
+ * Parser object.
+ */
+__rte_experimental
+void rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj);
+
/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 3/9] argparse: allow user-override of help printing
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 1/9] build: add define for the OS environment name Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 2/9] argparse: export function to print help text for object Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 4/9] eal: add long options for each short option Bruce Richardson
` (5 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Chengwen Feng
When the arguments passed to argparse include -h/--help then usage
information is automatically printed. Provide the capability for the
user to supply their own help function for this.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
doc/guides/prog_guide/argparse_lib.rst | 16 ++++++++++++++++
lib/argparse/rte_argparse.c | 5 ++++-
lib/argparse/rte_argparse.h | 7 ++++++-
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/doc/guides/prog_guide/argparse_lib.rst b/doc/guides/prog_guide/argparse_lib.rst
index 9f11714890..b309260d20 100644
--- a/doc/guides/prog_guide/argparse_lib.rst
+++ b/doc/guides/prog_guide/argparse_lib.rst
@@ -24,6 +24,8 @@ Features and Capabilities
#. autosave: used for parsing known value types;
#. callback: will invoke user callback to parse.
+- Supports automatic help and usage information.
+
Usage Guide
-----------
@@ -193,3 +195,17 @@ Then the user input could contain multiple ``--xyz`` arguments.
The multiple times argument only support with optional argument
and must be parsed by callback way.
+
+Help and Usage Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The argparse library supports automatic generation of help and usage information.
+When the input arguments include ``-h`` or ``--help``,
+it will print the usage information to standard output.
+If the default help output is not what is wanted,
+the user can provide a custom help printing function by setting the ``print_help`` field in the ``rte_argparse`` object.
+(If this field is set to NULL, the default help printing function will be used.)
+
+If the custom help printing function wants to use the text produced by the default help function,
+it can call the function ``rte_argparse_print_help()`` to get the help text printed to an output stream,
+for example: stdout or stderr.
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index d3b32c6357..e7b9bf573d 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -821,7 +821,10 @@ rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
goto error;
if (show_help) {
- rte_argparse_print_help(stdout, obj);
+ if (obj->print_help != NULL)
+ obj->print_help(obj);
+ else
+ rte_argparse_print_help(stdout, obj);
exit(0);
}
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
index baf278f6b9..63b49ba220 100644
--- a/lib/argparse/rte_argparse.h
+++ b/lib/argparse/rte_argparse.h
@@ -160,8 +160,13 @@ struct rte_argparse {
rte_arg_parser_t callback;
/** Opaque which used to invoke callback. */
void *opaque;
+ /**
+ * Function pointer for printing usage when -h is passed.
+ * If this is NULL, default printing function will be used.
+ */
+ void (*print_help)(const struct rte_argparse *obj);
/** Reserved field used for future extension. */
- void *reserved[16];
+ void *reserved[15];
/** Arguments configuration. Must ended with ARGPARSE_ARG_END(). */
struct rte_argparse_arg args[];
};
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 4/9] eal: add long options for each short option
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
` (2 preceding siblings ...)
2025-07-22 14:03 ` [PATCH v6 3/9] argparse: allow user-override of help printing Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
` (4 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
To simplify future rework of the EAL arg handling, add a long-option
equivalent for each short option that doesn't already have one.
When updating the docs with the new long options, standardize the format
of options which have both short and long variants, and drop the
deprecated service-coremask option from the docs, rather than adding its
new long option.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
doc/guides/linux_gsg/eal_args.include.rst | 20 ++++++++------------
lib/eal/common/eal_common_options.c | 9 +++++++++
lib/eal/common/eal_options.h | 16 ++++++++++++++++
3 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/doc/guides/linux_gsg/eal_args.include.rst b/doc/guides/linux_gsg/eal_args.include.rst
index 9ced54af40..0b17879d42 100644
--- a/doc/guides/linux_gsg/eal_args.include.rst
+++ b/doc/guides/linux_gsg/eal_args.include.rst
@@ -4,7 +4,7 @@
Lcore-related options
~~~~~~~~~~~~~~~~~~~~~
-* ``-l/--lcores <core list>``
+* ``-l, --lcores <core list>``
List of cores to run on
@@ -71,11 +71,7 @@ Lcore-related options
Core ID that is used as main.
-* ``-s <service core mask>``
-
- Hexadecimal bitmask of cores to be used as service cores.
-
-* ``-S <service core list>``
+* ``-S, --service-corelist <service core list>``
List of cores to be used as service cores.
@@ -108,7 +104,7 @@ Device-related options
--vdev 'net_pcap0,rx_pcap=input.pcap,tx_pcap=output.pcap'
-* ``-d <path to shared object or directory>``
+* ``-d, --driver-path <path to shared object or directory>``
Load external drivers. An argument can be a single shared object file, or a
directory containing multiple driver shared objects. Multiple -d options are
@@ -134,15 +130,15 @@ Multiprocessing-related options
Memory-related options
~~~~~~~~~~~~~~~~~~~~~~
-* ``-n <number of channels>``
+* ``-n, --memory-channels <number of channels>``
Set the number of memory channels to use.
-* ``-r <number of ranks>``
+* ``-r, --memory-ranks <number of ranks>``
Set the number of memory ranks (auto-detected by default).
-* ``-m <megabytes>``
+* ``-m, --memory-size <megabytes>``
Amount of memory to preallocate at startup.
@@ -236,11 +232,11 @@ Debugging options
Other options
~~~~~~~~~~~~~
-* ``-h``, ``--help``
+* ``-h, --help``
Display help message listing all EAL parameters.
-* ``-v``
+* ``-v, --version``
Display the version information on startup.
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 3169dd069f..226acea467 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -66,7 +66,9 @@ eal_short_options[] =
const struct option
eal_long_options[] = {
{OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
+ {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
{OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
+ {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
{OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
{OPT_HELP, 0, NULL, OPT_HELP_NUM },
{OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
@@ -76,6 +78,11 @@ eal_long_options[] = {
{OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
{OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
{OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
+ {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
+ {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
+ {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
+ {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
+ {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
{OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
{OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
{OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
@@ -109,6 +116,8 @@ eal_long_options[] = {
{OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
{OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
{OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
+ {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
+
{0, 0, NULL, 0 }
};
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 7a56aa3810..6ef45559f0 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -17,8 +17,24 @@ enum {
OPT_DEV_ALLOW_NUM = 'a',
#define OPT_DEV_BLOCK "block"
OPT_DEV_BLOCK_NUM = 'b',
+#define OPT_COREMASK "coremask"
+ OPT_COREMASK_NUM = 'c',
+#define OPT_DRIVER_PATH "driver-path"
+ OPT_DRIVER_PATH_NUM = 'd',
#define OPT_LCORES "lcores"
OPT_LCORES_NUM = 'l',
+#define OPT_MEMORY_SIZE "memory-size"
+ OPT_MEMORY_SIZE_NUM = 'm',
+#define OPT_MEMORY_CHANNELS "memory-channels"
+ OPT_MEMORY_CHANNELS_NUM = 'n',
+#define OPT_MEMORY_RANKS "memory-ranks"
+ OPT_MEMORY_RANKS_NUM = 'r',
+#define OPT_SERVICE_COREMASK "service-coremask"
+ OPT_SERVICE_COREMASK_NUM = 's',
+#define OPT_SERVICE_CORELIST "service-corelist"
+ OPT_SERVICE_CORELIST_NUM = 'S',
+#define OPT_VERSION "version"
+ OPT_VERSION_NUM = 'v',
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 5/9] eal: define the EAL parameters in argparse format
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
` (3 preceding siblings ...)
2025-07-22 14:03 ` [PATCH v6 4/9] eal: add long options for each short option Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 6/9] eal: gather EAL args before processing Bruce Richardson
` (3 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
Create eal_option_list.h, containing all the possible EAL parameters,
and basic info about them, such as type, whether they take a parameter
or not. Each entry is defined using a macro, which will be then
interpreted when the file is included.
First time this header in included in the eal_common_options.c file, the
macros are defined in such a way as to define field elements for an
"eal_init_args" structure, where each value is either a string type, if
it takes a parameter, or boolean type if it doesn't. For those elements
that take multiple values, i.e. are passed multiple times, we put them
in a TAILQ.
The second time of inclusion, the macros are defined so as to define the
arguments in an rte_argparse structure for EAL. For the basic string and
boolean types, we just store the values in the appropriate field in the
previous defined "eal_init_args" structure. For the list elements, we
use the argparse callback to process those elements, adding them to the
TAILQ as they are encountered.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 135 +++++++++++++++++++++++++++-
lib/eal/common/eal_option_list.h | 90 +++++++++++++++++++
lib/eal/meson.build | 2 +-
lib/meson.build | 1 +
4 files changed, 224 insertions(+), 4 deletions(-)
create mode 100644 lib/eal/common/eal_option_list.h
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 226acea467..ebb9f7063d 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -28,11 +28,13 @@
#include <rte_version.h>
#include <rte_devargs.h>
#include <rte_memcpy.h>
+#include <sys/queue.h>
#ifndef RTE_EXEC_ENV_WINDOWS
#include <rte_telemetry.h>
#endif
#include <rte_vect.h>
+#include <rte_argparse.h>
#include <eal_export.h>
#include "eal_internal_cfg.h"
#include "eal_options.h"
@@ -47,6 +49,136 @@
#define LCORE_OPT_LST 1
#define LCORE_OPT_MSK 2
+/* Allow the application to print its usage message too if set */
+static rte_usage_hook_t rte_application_usage_hook;
+
+struct arg_list_elem {
+ TAILQ_ENTRY(arg_list_elem) next;
+ char *arg;
+};
+TAILQ_HEAD(arg_list, arg_list_elem);
+
+struct eal_init_args {
+ /* define a struct member for each EAL option, member name is the same as option name.
+ * Parameters that take an argument e.g. -l, are char *,
+ * parameters that take no options e.g. --no-huge, are bool.
+ * parameters that can be given multiple times e.g. -a, are arg_lists,
+ * parameters that are optional e.g. --huge-unlink,
+ * are char * but are set to (void *)1 if the parameter is not given.
+ * for aliases, i.e. options under different names, no field needs to be output
+ */
+#define LIST_ARG(long, short, help_str, fieldname) struct arg_list fieldname;
+#define STR_ARG(long, short, help_str, fieldname) char *fieldname;
+#define OPT_STR_ARG(long, short, help_str, fieldname) char *fieldname;
+#define BOOL_ARG(long, short, help_str, fieldname) bool fieldname;
+#define STR_ALIAS(long, short, help_str, fieldname)
+
+#define INCLUDE_ALL_ARG 1 /* for struct definition, include even unsupported values */
+#include "eal_option_list.h"
+#undef INCLUDE_ALL_ARG
+};
+struct eal_init_args args;
+
+/* an rte_argparse callback to append the argument to an arg_list
+ * in args. The index is the offset into the struct of the list.
+ */
+static int
+arg_list_callback(uint32_t index, const char *arg, void *init_args)
+{
+ struct arg_list *list = RTE_PTR_ADD(init_args, index);
+ struct arg_list_elem *elem;
+
+ elem = malloc(sizeof(*elem));
+ if (elem == NULL)
+ return -1;
+
+ elem->arg = strdup(arg);
+ if (elem->arg == NULL) {
+ free(elem);
+ return -1;
+ }
+
+ TAILQ_INSERT_TAIL(list, elem, next);
+ return 0;
+}
+
+static void
+eal_usage(const struct rte_argparse *obj)
+{
+ rte_argparse_print_help(stdout, obj);
+ if (rte_application_usage_hook != NULL)
+ rte_application_usage_hook(obj->prog_name);
+}
+
+/* undef the *_ARG macros before redefining to generate the argparse arg list */
+#undef LIST_ARG
+#undef STR_ARG
+#undef OPT_STR_ARG
+#undef BOOL_ARG
+#undef STR_ALIAS
+
+/* For arguments which have an arg_list type, they use callback (no val_saver),
+ * require a value, and have the SUPPORT_MULTI flag.
+ */
+#define LIST_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_set = (void *)offsetof(struct eal_init_args, fieldname), \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .flags = RTE_ARGPARSE_FLAG_SUPPORT_MULTI, \
+},
+/* For arguments which have a string type, they use val_saver (no callback),
+ * and normally REQUIRED_VALUE.
+ */
+#define STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+},
+/* For flags which have optional arguments, they use both val_saver and val_set,
+ * but still have a string type.
+ */
+#define OPT_STR_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_OPTIONAL, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
+},
+/* For boolean arguments, they use val_saver and val_set, with NO_VALUE flag.
+ */
+#define BOOL_ARG(long, short, help_str, fieldname) { \
+ .name_long = long, \
+ .name_short = short, \
+ .help = help_str, \
+ .val_saver = &args.fieldname, \
+ .val_set = (void *)1, \
+ .value_required = RTE_ARGPARSE_VALUE_NONE, \
+ .value_type = RTE_ARGPARSE_VALUE_TYPE_BOOL, \
+},
+#define STR_ALIAS STR_ARG
+
+struct rte_argparse eal_argparse = {
+ .prog_name = "",
+ .usage = "<DPDK EAL options> -- <App options>",
+ .epilog = "For more information on EAL options, see the DPDK documentation at: \n"
+ "\thttps://doc.dpdk.org/guides/" RTE_EXEC_ENV_NAME "_gsg/",
+ .exit_on_error = true,
+ .callback = arg_list_callback,
+ .print_help = eal_usage,
+ .opaque = &args,
+ .args = {
+ #include "eal_option_list.h"
+ ARGPARSE_ARG_END(),
+ }
+};
+
const char
eal_short_options[] =
"a:" /* allow */
@@ -165,9 +297,6 @@ static int main_lcore_parsed;
static int mem_parsed;
static int core_parsed;
-/* Allow the application to print its usage message too if set */
-static rte_usage_hook_t rte_application_usage_hook;
-
/* Returns rte_usage_hook_t */
rte_usage_hook_t
eal_get_application_usage_hook(void)
diff --git a/lib/eal/common/eal_option_list.h b/lib/eal/common/eal_option_list.h
new file mode 100644
index 0000000000..dd148b7fed
--- /dev/null
+++ b/lib/eal/common/eal_option_list.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2025 Intel Corporation.
+ */
+
+/** This file contains a list of EAL commandline arguments.
+ *
+ * It's designed to be included multiple times in the codebase to
+ * generate both argument structure and the argument definitions
+ * for argparse.
+ */
+
+/* check that all ARG macros are defined */
+ #ifndef LIST_ARG
+#error "LIST_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef STR_ARG
+#error "STR_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef OPT_STR_ARG
+#error "OPT_STR_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef BOOL_ARG
+#error "BOOL_ARG macro must be defined before including " __FILE__
+#endif
+#ifndef STR_ALIAS
+#error "STR_ALIAS macro must be defined before including " __FILE__
+#endif
+
+
+/*
+ * list of EAL arguments as struct rte_argparse_arg.
+ * Format of each entry: long name, short name, help string, struct member name.
+ */
+/* (Alphabetical) List of common options first */
+LIST_ARG("--allow", "-a", "Add device to allow-list, causing DPDK to only use specified devices", allow)
+STR_ARG("--base-virtaddr", NULL, "Base virtual address to reserve memory", base_virtaddr)
+LIST_ARG("--block", "-b", "Add device to block-list, preventing DPDK from using the device", block)
+STR_ARG("--coremask", "-c", "Hexadecimal bitmask of cores to use", coremask)
+LIST_ARG("--driver-path", "-d", "Path to external driver shared object, or directory of drivers", driver_path)
+STR_ARG("--force-max-simd-bitwidth", NULL, "Set max SIMD bitwidth to use in vector code paths", force_max_simd_bitwidth)
+OPT_STR_ARG("--huge-unlink", NULL, "Unlink hugetlbfs files on exit (existing|always|never)", huge_unlink)
+BOOL_ARG("--in-memory", NULL, "DPDK should not create shared mmap files in filesystem (disables secondary process support)", in_memory)
+STR_ARG("--iova-mode", NULL, "IOVA mapping mode, physical (pa)/virtual (va)", iova_mode)
+STR_ARG("--lcores", "-l", "List of CPU cores to use", lcores)
+BOOL_ARG("--legacy-mem", NULL, "Enable legacy memory behavior", legacy_mem)
+OPT_STR_ARG("--log-color", NULL, "Enable/disable color in log output", log_color)
+STR_ARG("--log-level", NULL, "Log level for loggers; use log-level=help for list of log types and levels", log_level)
+OPT_STR_ARG("--log-timestamp", NULL, "Enable/disable timestamp in log output", log_timestamp)
+STR_ARG("--main-lcore", NULL, "Select which core to use for the main thread", main_lcore)
+STR_ARG("--mbuf-pool-ops-name", NULL, "User defined mbuf default pool ops name", mbuf_pool_ops_name)
+STR_ARG("--memory-channels", "-n", "Number of memory channels per socket", memory_channels)
+STR_ARG("--memory-ranks", "-r", "Force number of memory ranks (don't detect)", memory_ranks)
+STR_ARG("--memory-size", "-m", "Total size of memory to allocate initially", memory_size)
+BOOL_ARG("--no-hpet", NULL, "Disable HPET timer", no_hpet)
+BOOL_ARG("--no-huge", NULL, "Disable hugetlbfs support", no_huge)
+BOOL_ARG("--no-pci", NULL, "Disable all PCI devices", no_pci)
+BOOL_ARG("--no-shconf", NULL, "Disable shared config file generation", no_shconf)
+BOOL_ARG("--no-telemetry", NULL, "Disable telemetry", no_telemetry)
+STR_ARG("--proc-type", NULL, "Type of process (primary|secondary|auto)", proc_type)
+STR_ARG("--service-corelist", "-S", "List of cores to use for service threads", service_corelist)
+STR_ARG("--service-coremask", "-s", "Hexadecimal bitmask of cores to use for service threads", service_coremask)
+BOOL_ARG("--single-file-segments", NULL, "Store all pages within single files (per-page-size, per-node)", single_file_segments)
+BOOL_ARG("--telemetry", NULL, "Enable telemetry", telemetry)
+LIST_ARG("--vdev", NULL, "Add a virtual device to the system; format=<driver><id>[,key=val,...]", vdev)
+BOOL_ARG("--vmware-tsc-map", NULL, "Use VMware TSC mapping instead of native RDTSC", vmware_tsc_map)
+BOOL_ARG("--version", "-v", "Show version", version)
+
+#if defined(INCLUDE_ALL_ARG) || !defined(RTE_EXEC_ENV_WINDOWS)
+/* Linux and FreeBSD options*/
+OPT_STR_ARG("--syslog", NULL, "Log to syslog (and optionally set facility)", syslog)
+STR_ARG("--trace", NULL, "Enable trace based on regular expression trace name", trace)
+STR_ARG("--trace-bufsz", NULL, "Trace buffer size", trace_bufsz)
+STR_ARG("--trace-dir", NULL, "Trace directory", trace_dir)
+STR_ARG("--trace-mode", NULL, "Trace mode", trace_mode)
+#endif
+
+#if defined(INCLUDE_ALL_ARG) || defined(RTE_EXEC_ENV_LINUX)
+/* Linux-only options */
+BOOL_ARG("--create-uio-dev", NULL, "Create /dev/uioX devices", create_uio_dev)
+STR_ARG("--file-prefix", NULL, "Base filename of hugetlbfs files", file_prefix)
+STR_ARG("--huge-dir", NULL, "Directory for hugepage files", huge_dir)
+OPT_STR_ARG("--huge-worker-stack", NULL, "Allocate worker thread stacks from hugepage memory, with optional size (kB)", huge_worker_stack)
+BOOL_ARG("--match-allocations", NULL, "Free hugepages exactly as allocated", match_allocations)
+STR_ARG("--numa-mem", NULL, "Memory to allocate on NUMA nodes (comma separated values)", numa_mem)
+STR_ARG("--numa-limit", NULL, "Limit memory allocation on NUMA nodes (comma separated values)", numa_limit)
+STR_ALIAS("--socket-mem", NULL, "Alias for --numa-mem", numa_mem)
+STR_ALIAS("--socket-limit", NULL, "Alias for --numa-limit", numa_limit)
+STR_ARG("--vfio-intr", NULL, "VFIO interrupt mode (legacy|msi|msix)", vfio_intr)
+STR_ARG("--vfio-vf-token", NULL, "VF token (UUID) shared between SR-IOV PF and VFs", vfio_vf_token)
+#endif
diff --git a/lib/eal/meson.build b/lib/eal/meson.build
index e1d6c4cf17..f9fcee24ee 100644
--- a/lib/eal/meson.build
+++ b/lib/eal/meson.build
@@ -14,7 +14,7 @@ subdir(exec_env)
subdir(arch_subdir)
-deps += ['log', 'kvargs']
+deps += ['argparse', 'kvargs']
if not is_windows
deps += ['telemetry']
endif
diff --git a/lib/meson.build b/lib/meson.build
index 0d56b2083b..dec90059e1 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -71,6 +71,7 @@ libraries = [
]
always_enable = [
+ 'argparse',
'cmdline',
'eal',
'ethdev',
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 6/9] eal: gather EAL args before processing
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
` (4 preceding siblings ...)
2025-07-22 14:03 ` [PATCH v6 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
` (2 subsequent siblings)
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev
Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk,
Anatoly Burakov
DPDK traditionally has iterated through all args and processed them as
they appear in the commandline. The arg processing logic can be
simplified if instead we initially gather all arguments into a structure
which is then processed with the arguments dealt with in a fixed/known
order.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 878 ++++++++++++++--------------
lib/eal/common/eal_options.h | 10 +-
lib/eal/common/eal_private.h | 11 +
lib/eal/freebsd/eal.c | 164 +-----
lib/eal/linux/eal.c | 379 +-----------
lib/eal/windows/eal.c | 113 +---
6 files changed, 482 insertions(+), 1073 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index ebb9f7063d..aea2c813ed 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -46,8 +46,7 @@
#endif
#define BITS_PER_HEX 4
-#define LCORE_OPT_LST 1
-#define LCORE_OPT_MSK 2
+#define NUMA_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
/* Allow the application to print its usage message too if set */
static rte_usage_hook_t rte_application_usage_hook;
@@ -179,80 +178,31 @@ struct rte_argparse eal_argparse = {
}
};
-const char
-eal_short_options[] =
- "a:" /* allow */
- "b:" /* block */
- "c:" /* coremask */
- "s:" /* service coremask */
- "d:" /* driver */
- "h" /* help */
- "l:" /* corelist */
- "S:" /* service corelist */
- "m:" /* memory size */
- "n:" /* memory channels */
- "r:" /* memory ranks */
- "v" /* version */
- ;
-
-const struct option
-eal_long_options[] = {
- {OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM },
- {OPT_COREMASK, 1, NULL, OPT_COREMASK_NUM },
- {OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM },
- {OPT_DRIVER_PATH, 1, NULL, OPT_DRIVER_PATH_NUM },
- {OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM },
- {OPT_HELP, 0, NULL, OPT_HELP_NUM },
- {OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM },
- {OPT_HUGE_UNLINK, 2, NULL, OPT_HUGE_UNLINK_NUM },
- {OPT_IOVA_MODE, 1, NULL, OPT_IOVA_MODE_NUM },
- {OPT_LCORES, 1, NULL, OPT_LCORES_NUM },
- {OPT_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_NUM },
- {OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
- {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM },
- {OPT_MEMORY_CHANNELS, 1, NULL, OPT_MEMORY_CHANNELS_NUM },
- {OPT_MEMORY_RANKS, 1, NULL, OPT_MEMORY_RANKS_NUM },
- {OPT_MEMORY_SIZE, 1, NULL, OPT_MEMORY_SIZE_NUM },
- {OPT_SERVICE_CORELIST, 1, NULL, OPT_SERVICE_CORELIST_NUM },
- {OPT_SERVICE_COREMASK, 1, NULL, OPT_SERVICE_COREMASK_NUM },
- {OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
- {OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
- {OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
- {OPT_TRACE_MODE, 1, NULL, OPT_TRACE_MODE_NUM },
- {OPT_MAIN_LCORE, 1, NULL, OPT_MAIN_LCORE_NUM },
- {OPT_MBUF_POOL_OPS_NAME, 1, NULL, OPT_MBUF_POOL_OPS_NAME_NUM},
- {OPT_NO_HPET, 0, NULL, OPT_NO_HPET_NUM },
- {OPT_NO_HUGE, 0, NULL, OPT_NO_HUGE_NUM },
- {OPT_NO_PCI, 0, NULL, OPT_NO_PCI_NUM },
- {OPT_NO_SHCONF, 0, NULL, OPT_NO_SHCONF_NUM },
- {OPT_IN_MEMORY, 0, NULL, OPT_IN_MEMORY_NUM },
- {OPT_DEV_BLOCK, 1, NULL, OPT_DEV_BLOCK_NUM },
- {OPT_DEV_ALLOW, 1, NULL, OPT_DEV_ALLOW_NUM },
- {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM },
- /* socket-mem/socket-limit are kept for backwards compatibility */
- {OPT_SOCKET_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_SOCKET_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
- {OPT_NUMA_MEM, 1, NULL, OPT_NUMA_MEM_NUM },
- {OPT_NUMA_LIMIT, 1, NULL, OPT_NUMA_LIMIT_NUM },
-#ifndef RTE_EXEC_ENV_WINDOWS
- {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM },
-#endif
- {OPT_VDEV, 1, NULL, OPT_VDEV_NUM },
- {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
- {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM },
- {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
- {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM },
- {OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM},
- {OPT_MATCH_ALLOCATIONS, 0, NULL, OPT_MATCH_ALLOCATIONS_NUM},
- {OPT_TELEMETRY, 0, NULL, OPT_TELEMETRY_NUM },
- {OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
- {OPT_FORCE_MAX_SIMD_BITWIDTH, 1, NULL, OPT_FORCE_MAX_SIMD_BITWIDTH_NUM},
- {OPT_HUGE_WORKER_STACK, 2, NULL, OPT_HUGE_WORKER_STACK_NUM },
- {OPT_VERSION, 0, NULL, OPT_VERSION_NUM },
-
-
- {0, 0, NULL, 0 }
-};
+/* function to call into argparse library to parse the passed argc/argv parameters
+ * to the eal_init_args structure.
+ */
+int
+eal_collate_args(int argc, char **argv)
+{
+ if (argc < 1 || argv == NULL)
+ return -EINVAL;
+
+ /* initialize the list of arguments */
+ memset(&args, 0, sizeof(args));
+ TAILQ_INIT(&args.allow);
+ TAILQ_INIT(&args.block);
+ TAILQ_INIT(&args.driver_path);
+ TAILQ_INIT(&args.vdev);
+
+ /* parse the arguments */
+ eal_argparse.prog_name = argv[0];
+ int retval = rte_argparse_parse(&eal_argparse, argc, argv);
+ if (retval < 0)
+ return retval;
+
+ argv[retval - 1] = argv[0];
+ return retval - 1;
+}
TAILQ_HEAD(shared_driver_list, shared_driver);
@@ -294,7 +244,6 @@ static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
static int main_lcore_parsed;
-static int mem_parsed;
static int core_parsed;
/* Returns rte_usage_hook_t */
@@ -318,7 +267,12 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
return old_func;
}
-#ifndef RTE_EXEC_ENV_WINDOWS
+#ifdef RTE_EXEC_ENV_WINDOWS
+
+int
+eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+
+#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
static char **eal_app_args;
@@ -406,7 +360,7 @@ eal_save_args(int argc, char **argv)
eal_args = NULL;
return -1;
}
-#endif
+#endif /* !RTE_EXEC_ENV_WINDOWS */
static int
eal_option_device_add(enum rte_devtype type, const char *optarg)
@@ -829,17 +783,6 @@ eal_parse_service_coremask(const char *coremask)
return 0;
}
-static int
-eal_service_cores_parsed(void)
-{
- int idx;
- for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- if (lcore_config[idx].core_role == ROLE_SERVICE)
- return 1;
- }
- return 0;
-}
-
static int
update_lcore_config(int *cores)
{
@@ -1666,361 +1609,486 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return -1;
}
-bool
-eal_option_is_log(int opt)
+/* Parse all arguments looking for log related ones */
+int
+eal_parse_log_options(void)
{
- switch (opt) {
- case OPT_LOG_COLOR_NUM:
- case OPT_LOG_LEVEL_NUM:
- case OPT_LOG_TIMESTAMP_NUM:
- case OPT_SYSLOG_NUM:
- return true;
- default:
- return false;
+ if (args.log_level != NULL) {
+ if (eal_parse_log_level(args.log_level) < 0) {
+ EAL_LOG(ERR, "invalid log-level parameter");
+ return -1;
+ }
+ }
+ if (args.log_color != NULL) {
+ /* if value is 1, no argument specified, so pass NULL */
+ if (args.log_color == (void *)1)
+ args.log_color = NULL;
+ if (eal_log_color(args.log_color) < 0) {
+ EAL_LOG(ERR, "invalid log-color parameter");
+ return -1;
+ }
+ }
+ if (args.log_timestamp != NULL) {
+ /* similarly log_timestamp may be 1 */
+ if (args.log_timestamp == (void *)1)
+ args.log_timestamp = NULL;
+ if (eal_log_timestamp(args.log_timestamp) < 0) {
+ EAL_LOG(ERR, "invalid log-timestamp parameter");
+ return -1;
+ }
+ }
+ if (args.syslog != NULL) {
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "syslog is not supported on Windows, ignoring parameter");
+#else
+ /* also syslog parameter may be 1 */
+ if (args.syslog == (void *)1)
+ args.syslog = NULL;
+ if (eal_log_syslog(args.syslog) < 0) {
+ EAL_LOG(ERR, "invalid syslog parameter");
+ return -1;
+ }
+#endif
}
+ return 0;
}
-/* Parse all arguments looking for log related ones */
-int
-eal_parse_log_options(int argc, char * const argv[])
+static int
+eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
{
- struct internal_config *internal_conf = eal_get_internal_configuration();
- int option_index, opt;
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_opterr = opterr;
- char *old_optarg = optarg;
-#ifdef RTE_EXEC_ENV_FREEBSD
- const int old_optreset = optreset;
- optreset = 1;
-#endif
+ char *arg[RTE_MAX_NUMA_NODES];
+ char *end;
+ int arg_num, i, len;
- optind = 1;
- opterr = 0;
+ len = strnlen(strval, NUMA_MEM_STRLEN);
+ if (len == NUMA_MEM_STRLEN) {
+ EAL_LOG(ERR, "--numa-mem/--socket-mem parameter is too long");
+ return -1;
+ }
- while ((opt = getopt_long(argc, argv, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
+ /* all other error cases will be caught later */
+ if (!isdigit(strval[len-1]))
+ return -1;
- if (!eal_option_is_log(opt))
- continue;
+ /* split the optarg into separate socket values */
+ arg_num = rte_strsplit(strval, len,
+ arg, RTE_MAX_NUMA_NODES, ',');
- if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+ /* if split failed, or 0 arguments */
+ if (arg_num <= 0)
+ return -1;
+
+ /* parse each defined socket option */
+ errno = 0;
+ for (i = 0; i < arg_num; i++) {
+ uint64_t val;
+ end = NULL;
+ val = strtoull(arg[i], &end, 10);
+
+ /* check for invalid input */
+ if ((errno != 0) ||
+ (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
+ val <<= 20;
+ socket_arg[i] = val;
}
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
- opterr = old_opterr;
-#ifdef RTE_EXEC_ENV_FREEBSD
- optreset = old_optreset;
+ return 0;
+}
+
+static int
+eal_parse_vfio_intr(const char *mode)
+{
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+ static struct {
+ const char *name;
+ enum rte_intr_mode value;
+ } map[] = {
+ { "legacy", RTE_INTR_MODE_LEGACY },
+ { "msi", RTE_INTR_MODE_MSI },
+ { "msix", RTE_INTR_MODE_MSIX },
+ };
+
+ for (size_t i = 0; i < RTE_DIM(map); i++) {
+ if (!strcmp(mode, map[i].name)) {
+ internal_conf->vfio_intr_mode = map[i].value;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+eal_parse_vfio_vf_token(const char *vf_token)
+{
+ struct internal_config *cfg = eal_get_internal_configuration();
+ rte_uuid_t uuid;
+
+ if (!rte_uuid_parse(vf_token, uuid)) {
+ rte_uuid_copy(cfg->vfio_vf_token, uuid);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+eal_parse_huge_worker_stack(const char *arg)
+{
+#ifdef RTE_EXEC_ENV_WINDOWS
+ EAL_LOG(WARNING, "Cannot set worker stack size on Windows, parameter ignored");
+ RTE_SET_USED(arg);
+#else
+ struct internal_config *cfg = eal_get_internal_configuration();
+
+ if (arg == NULL || arg[0] == '\0') {
+ pthread_attr_t attr;
+ int ret;
+
+ if (pthread_attr_init(&attr) != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
+ pthread_attr_destroy(&attr);
+ if (ret != 0) {
+ EAL_LOG(ERR, "Could not retrieve default stack size");
+ return -1;
+ }
+ } else {
+ unsigned long stack_size;
+ char *end;
+
+ errno = 0;
+ stack_size = strtoul(arg, &end, 10);
+ if (errno || end == NULL || stack_size == 0 ||
+ stack_size >= (size_t)-1 / 1024)
+ return -1;
+
+ cfg->huge_worker_stack_size = stack_size * 1024;
+ }
+
+ EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
+ cfg->huge_worker_stack_size / 1024);
#endif
return 0;
}
+/* Parse the arguments given in the command line of the application */
int
-eal_parse_common_option(int opt, const char *optarg,
- struct internal_config *conf)
+eal_parse_args(void)
{
- static int b_used;
- static int a_used;
-
- switch (opt) {
- case 'b':
- if (a_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, optarg) < 0)
+ struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct arg_list_elem *arg;
+
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+ /* both -l and -c cannot be used at the same time */
+ if (args.coremask != NULL && args.lcores != NULL) {
+ EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
+ return -1;
+ }
+ /* both -s and -S cannot be used at the same time */
+ if (args.service_coremask != NULL && args.service_corelist != NULL) {
+ EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
+ return -1;
+ }
+ /* can't have both telemetry and no-telemetry */
+ if (args.no_telemetry && args.telemetry) {
+ EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
+ return -1;
+ }
+ /* can't have both -m and --socket-mem */
+ if (args.memory_size != NULL && args.numa_mem != NULL) {
+ EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ return -1;
+ }
+
+ /* parse options */
+ /* print version before anything else */
+ if (args.version) {
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
+ }
+
+ /* parse the process type */
+ if (args.proc_type != NULL) {
+ int_cfg->process_type = eal_parse_proc_type(args.proc_type);
+ if (int_cfg->process_type == RTE_PROC_INVALID) {
+ EAL_LOG(ERR, "invalid process type: %s", args.proc_type);
return -1;
- b_used = 1;
- break;
+ }
+ }
- case 'a':
- if (b_used)
- goto ba_conflict;
- if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, optarg) < 0)
+ /* device -a/-b/-vdev options*/
+ TAILQ_FOREACH(arg, &args.allow, next)
+ if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, arg->arg) < 0)
return -1;
- a_used = 1;
- break;
- /* coremask */
- case 'c': {
+ TAILQ_FOREACH(arg, &args.block, next)
+ if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, arg->arg) < 0)
+ return -1;
+ TAILQ_FOREACH(arg, &args.vdev, next)
+ if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, arg->arg) < 0)
+ return -1;
+ /* driver loading options */
+ TAILQ_FOREACH(arg, &args.driver_path, next)
+ if (eal_plugin_add(arg->arg) < 0)
+ return -1;
+
+ /* parse the coremask /core-list */
+ if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -c is before -s or -S");
- if (rte_eal_parse_coremask(optarg, lcore_indexes) < 0) {
+ if (rte_eal_parse_coremask(args.coremask, lcore_indexes) < 0) {
EAL_LOG(ERR, "invalid coremask syntax");
return -1;
}
if (update_lcore_config(lcore_indexes) < 0) {
char *available = available_cores();
- EAL_LOG(ERR,
- "invalid coremask, please check specified cores are part of %s",
- available);
+ EAL_LOG(ERR, "invalid coremask '%s', please check specified cores are part of %s",
+ args.coremask, available);
free(available);
return -1;
}
-
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_MSK)
- EAL_LOG(ERR, "Option '-c' passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option -c is ignored, because option -l/--lcores used");
+ core_parsed = 1;
+ } else if (args.lcores != NULL) {
+ if (eal_parse_lcores(args.lcores) < 0) {
+ EAL_LOG(ERR, "invalid lcore list: '%s'", args.lcores);
return -1;
}
-
- core_parsed = LCORE_OPT_MSK;
- break;
+ core_parsed = 1;
}
- /* corelist */
- case 'l': {
- if (eal_service_cores_parsed())
- EAL_LOG(WARNING,
- "Service cores parsed before dataplane cores. Please ensure -l is before -s or -S");
-
- if (eal_parse_lcores(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for -l/--" OPT_LCORES);
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0) {
+ EAL_LOG(ERR, "invalid main-lcore parameter");
return -1;
}
+ }
- if (core_parsed) {
- if (core_parsed == LCORE_OPT_LST)
- EAL_LOG(ERR, "Core list option passed multiple times to EAL");
- else
- EAL_LOG(ERR, "Option '-l/--lcores' is ignored, because coremask option used");
+ /* service core options */
+ if (args.service_coremask != NULL) {
+ if (eal_parse_service_coremask(args.service_coremask) < 0) {
+ EAL_LOG(ERR, "invalid service coremask: '%s'",
+ args.service_coremask);
return -1;
}
+ } else if (args.service_corelist != NULL) {
+ if (eal_parse_service_corelist(args.service_corelist) < 0) {
+ EAL_LOG(ERR, "invalid service core list: '%s'",
+ args.service_corelist);
+ return -1;
+ }
+ }
- core_parsed = LCORE_OPT_LST;
- break;
+ /* memory options */
+ if (args.memory_size != NULL) {
+ int_cfg->memory = atoi(args.memory_size);
+ int_cfg->memory *= 1024ULL;
+ int_cfg->memory *= 1024ULL;
}
- /* service coremask */
- case 's':
- if (eal_parse_service_coremask(optarg) < 0) {
- EAL_LOG(ERR, "invalid service coremask");
+ if (args.memory_channels != NULL) {
+ int_cfg->force_nchannel = atoi(args.memory_channels);
+ if (int_cfg->force_nchannel == 0) {
+ EAL_LOG(ERR, "invalid memory channel parameter");
return -1;
}
- break;
- /* service corelist */
- case 'S':
- if (eal_parse_service_corelist(optarg) < 0) {
- EAL_LOG(ERR, "invalid service core list");
+ }
+ if (args.memory_ranks != NULL) {
+ int_cfg->force_nrank = atoi(args.memory_ranks);
+ if (int_cfg->force_nrank == 0 || int_cfg->force_nrank > 16) {
+ EAL_LOG(ERR, "invalid memory rank parameter");
return -1;
}
- break;
- /* size of memory */
- case 'm':
- conf->memory = atoi(optarg);
- conf->memory *= 1024ULL;
- conf->memory *= 1024ULL;
- mem_parsed = 1;
- break;
- /* force number of channels */
- case 'n':
- conf->force_nchannel = atoi(optarg);
- if (conf->force_nchannel == 0) {
- EAL_LOG(ERR, "invalid channel number");
+ }
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
return -1;
}
- break;
- /* force number of ranks */
- case 'r':
- conf->force_nrank = atoi(optarg);
- if (conf->force_nrank == 0 ||
- conf->force_nrank > 16) {
- EAL_LOG(ERR, "invalid rank number");
+ }
+ if (args.no_huge) {
+ int_cfg->no_hugetlbfs = 1;
+ /* no-huge is legacy mem */
+ int_cfg->legacy_mem = 1;
+ }
+ if (args.in_memory) {
+ int_cfg->in_memory = 1;
+ /* in-memory is a superset of noshconf and huge-unlink */
+ int_cfg->no_shconf = 1;
+ int_cfg->hugepage_file.unlink_before_mapping = true;
+ }
+ if (args.legacy_mem)
+ int_cfg->legacy_mem = 1;
+ if (args.single_file_segments)
+ int_cfg->single_file_segments = 1;
+ if (args.huge_dir != NULL) {
+ free(int_cfg->hugepage_dir); /* free old hugepage dir */
+ int_cfg->hugepage_dir = strdup(args.huge_dir);
+ if (int_cfg->hugepage_dir == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for hugepage dir parameter");
return -1;
}
- break;
- /* force loading of external driver */
- case 'd':
- if (eal_plugin_add(optarg) == -1)
+ }
+ if (args.file_prefix != NULL) {
+ free(int_cfg->hugefile_prefix); /* free old file prefix */
+ int_cfg->hugefile_prefix = strdup(args.file_prefix);
+ if (int_cfg->hugefile_prefix == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for file prefix parameter");
return -1;
- break;
- case 'v':
- /* since message is explicitly requested by user, we
- * write message at highest log level so it can always
- * be seen
- * even if info or warning messages are disabled */
- EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- break;
-
- /* long options */
- case OPT_HUGE_UNLINK_NUM:
- if (eal_parse_huge_unlink(optarg, &conf->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid --"OPT_HUGE_UNLINK" option");
+ }
+ }
+ if (args.numa_mem != NULL) {
+ if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
+ EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
return -1;
}
- break;
-
- case OPT_NO_HUGE_NUM:
- conf->no_hugetlbfs = 1;
- /* no-huge is legacy mem */
- conf->legacy_mem = 1;
- break;
-
- case OPT_NO_PCI_NUM:
- conf->no_pci = 1;
- break;
-
- case OPT_NO_HPET_NUM:
- conf->no_hpet = 1;
- break;
-
- case OPT_VMWARE_TSC_MAP_NUM:
- conf->vmware_tsc_map = 1;
- break;
-
- case OPT_NO_SHCONF_NUM:
- conf->no_shconf = 1;
- break;
-
- case OPT_IN_MEMORY_NUM:
- conf->in_memory = 1;
- /* in-memory is a superset of noshconf and huge-unlink */
- conf->no_shconf = 1;
- conf->hugepage_file.unlink_before_mapping = true;
- break;
-
- case OPT_PROC_TYPE_NUM:
- conf->process_type = eal_parse_proc_type(optarg);
- break;
-
- case OPT_MAIN_LCORE_NUM:
- if (eal_parse_main_lcore(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_MAIN_LCORE);
+ int_cfg->force_numa = 1;
+ }
+ if (args.numa_limit != NULL) {
+ if (eal_parse_socket_arg(args.numa_limit, int_cfg->numa_limit) < 0) {
+ EAL_LOG(ERR, "invalid numa-limit parameter: '%s'", args.numa_limit);
return -1;
}
- break;
+ int_cfg->force_numa_limits = 1;
+ }
- case OPT_VDEV_NUM:
- if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
- optarg) < 0) {
+ /* tracing settings, not supported on windows */
+#ifdef RTE_EXEC_ENV_WINDOWS
+ if (args.trace != NULL ||
+ args.trace_dir != NULL ||
+ args.trace_bufsz != NULL ||
+ args.trace_mode != NULL)
+ EAL_LOG(WARNING, "Tracing is not supported on Windows, ignoring tracing parameters");
+#else
+ if (args.trace != NULL) {
+ if (eal_trace_args_save(args.trace) < 0) {
+ EAL_LOG(ERR, "invalid trace parameter, '%s'", args.trace);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_SYSLOG_NUM:
- if (eal_log_syslog(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_SYSLOG);
+ }
+ if (args.trace_dir != NULL) {
+ if (eal_trace_dir_args_save(args.trace_dir) < 0) {
+ EAL_LOG(ERR, "invalid trace directory, '%s'", args.trace_dir);
return -1;
}
- break;
-#endif
-
- case OPT_LOG_LEVEL_NUM:
- if (eal_parse_log_level(optarg) < 0) {
- EAL_LOG(ERR,
- "invalid parameters for --"
- OPT_LOG_LEVEL);
+ }
+ if (args.trace_bufsz != NULL) {
+ if (eal_trace_bufsz_args_save(args.trace_bufsz) < 0) {
+ EAL_LOG(ERR, "invalid trace buffer size, '%s'", args.trace_bufsz);
return -1;
}
- break;
-
- case OPT_LOG_TIMESTAMP_NUM:
- if (eal_log_timestamp(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_TIMESTAMP);
+ }
+ if (args.trace_mode != NULL) {
+ if (eal_trace_mode_args_save(args.trace_mode) < 0) {
+ EAL_LOG(ERR, "invalid trace mode, '%s'", args.trace_mode);
return -1;
}
- break;
+ }
+#endif
- case OPT_LOG_COLOR_NUM:
- if (eal_log_color(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_LOG_COLOR);
+ /* simple flag settings
+ * Only set these to 1, as we don't want to set them to 0 in case
+ * other options above have already set them.
+ */
+ if (args.no_pci)
+ int_cfg->no_pci = 1;
+ if (args.no_hpet)
+ int_cfg->no_hpet = 1;
+ if (args.vmware_tsc_map)
+ int_cfg->vmware_tsc_map = 1;
+ if (args.no_shconf)
+ int_cfg->no_shconf = 1;
+ if (args.no_telemetry)
+ int_cfg->no_telemetry = 1;
+ if (args.match_allocations)
+ int_cfg->match_allocations = 1;
+ if (args.create_uio_dev)
+ int_cfg->create_uio_dev = 1;
+
+
+ /* other misc settings */
+ if (args.iova_mode != NULL) {
+ if (eal_parse_iova_mode(args.iova_mode) < 0) {
+ EAL_LOG(ERR, "invalid iova mode parameter '%s'", args.iova_mode);
return -1;
}
- break;
-
-#ifndef RTE_EXEC_ENV_WINDOWS
- case OPT_TRACE_NUM: {
- if (eal_trace_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE);
+ };
+ if (args.base_virtaddr != NULL) {
+ if (eal_parse_base_virtaddr(args.base_virtaddr) < 0) {
+ EAL_LOG(ERR, "invalid base virtaddr '%s'", args.base_virtaddr);
return -1;
}
- break;
}
-
- case OPT_TRACE_DIR_NUM: {
- if (eal_trace_dir_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_DIR);
+ if (args.force_max_simd_bitwidth != NULL) {
+ if (eal_parse_simd_bitwidth(args.force_max_simd_bitwidth) < 0) {
+ EAL_LOG(ERR, "invalid SIMD bitwidth parameter '%s'",
+ args.force_max_simd_bitwidth);
return -1;
}
- break;
}
-
- case OPT_TRACE_BUF_SIZE_NUM: {
- if (eal_trace_bufsz_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_BUF_SIZE);
+ if (args.vfio_intr != NULL) {
+ if (eal_parse_vfio_intr(args.vfio_intr) < 0) {
+ EAL_LOG(ERR, "invalid vfio interrupt parameter: '%s'", args.vfio_intr);
return -1;
}
- break;
}
-
- case OPT_TRACE_MODE_NUM: {
- if (eal_trace_mode_args_save(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_TRACE_MODE);
+ if (args.vfio_vf_token != NULL) {
+ if (eal_parse_vfio_vf_token(args.vfio_vf_token) < 0) {
+ EAL_LOG(ERR, "invalid vfio vf token parameter: '%s'", args.vfio_vf_token);
return -1;
}
- break;
}
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- case OPT_LEGACY_MEM_NUM:
- conf->legacy_mem = 1;
- break;
- case OPT_SINGLE_FILE_SEGMENTS_NUM:
- conf->single_file_segments = 1;
- break;
- case OPT_IOVA_MODE_NUM:
- if (eal_parse_iova_mode(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_IOVA_MODE);
+ if (args.huge_worker_stack != NULL) {
+ if (args.huge_worker_stack == (void *)1)
+ args.huge_worker_stack = NULL;
+ if (eal_parse_huge_worker_stack(args.huge_worker_stack) < 0) {
+ EAL_LOG(ERR, "invalid huge worker stack parameter");
return -1;
}
- break;
- case OPT_BASE_VIRTADDR_NUM:
- if (eal_parse_base_virtaddr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_BASE_VIRTADDR);
+ }
+ if (args.mbuf_pool_ops_name != NULL) {
+ free(int_cfg->user_mbuf_pool_ops_name); /* free old ops name */
+ int_cfg->user_mbuf_pool_ops_name = strdup(args.mbuf_pool_ops_name);
+ if (int_cfg->user_mbuf_pool_ops_name == NULL) {
+ EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
- break;
- case OPT_TELEMETRY_NUM:
- break;
- case OPT_NO_TELEMETRY_NUM:
- conf->no_telemetry = 1;
- break;
- case OPT_FORCE_MAX_SIMD_BITWIDTH_NUM:
- if (eal_parse_simd_bitwidth(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_FORCE_MAX_SIMD_BITWIDTH);
+ }
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+ /* create runtime data directory. In no_shconf mode, skip any errors */
+ if (eal_create_runtime_dir() < 0) {
+ if (int_cfg->no_shconf == 0) {
+ EAL_LOG(ERR, "Cannot create runtime directory");
return -1;
}
- break;
+ EAL_LOG(WARNING, "No DPDK runtime directory created");
+ }
+#endif
- /* don't know what to do, leave this to caller */
- default:
- return 1;
+ if (eal_adjust_config(int_cfg) != 0) {
+ EAL_LOG(ERR, "Invalid configuration");
+ return -1;
+ }
+ if (eal_check_common_options(int_cfg) != 0) {
+ EAL_LOG(ERR, "Checking common options failed");
+ return -1;
}
return 0;
-
-ba_conflict:
- EAL_LOG(ERR,
- "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
}
static void
@@ -2153,13 +2221,8 @@ eal_check_common_options(struct internal_config *internal_cfg)
"option");
return -1;
}
- if (mem_parsed && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Options -m and --"OPT_NUMA_MEM" cannot "
- "be specified at the same time");
- return -1;
- }
if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_MEM" cannot "
+ EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
"be specified together with --"OPT_NO_HUGE);
return -1;
}
@@ -2245,98 +2308,3 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth)
internal_conf->max_simd_bitwidth.bitwidth = bitwidth;
return 0;
}
-
-void
-eal_common_usage(void)
-{
- printf("[options]\n\n"
- "EAL common options:\n"
- " -c COREMASK Hexadecimal bitmask of cores to run on\n"
- " -l, --"OPT_LCORES" CORELIST\n"
- " List of cores to run on\n"
- " The basic argument format is <c1>[-c2][,c3[-c4],...]\n"
- " where c1, c2, etc are core indexes between 0 and %d\n"
- " Can also be used to map lcore set to physical CPU set\n"
- " The argument format is\n"
- " '<lcores[@cpus]>[<,lcores[@cpus]>...]'\n"
- " lcores and cpus list are grouped by '(' and ')'\n"
- " Within the group, '-' is used for range separator,\n"
- " ',' is used for single number separator.\n"
- " '( )' can be omitted for single element group,\n"
- " '@' can be omitted if cpus and lcores have the same value\n"
- " -s SERVICE COREMASK Hexadecimal bitmask of cores to be used as service cores\n"
- " -S SERVICE CORELIST List of cores to run services on\n"
- " --"OPT_MAIN_LCORE" ID Core ID that is used as main\n"
- " --"OPT_MBUF_POOL_OPS_NAME" Pool ops name for mbuf to use\n"
- " -n CHANNELS Number of memory channels\n"
- " -m MB Memory to allocate (see also --"OPT_NUMA_MEM")\n"
- " -r RANKS Force number of memory ranks (don't detect)\n"
- " -b, --block Add a device to the blocked list.\n"
- " Prevent EAL from using this device. The argument\n"
- " format for PCI devices is <domain:bus:devid.func>.\n"
- " -a, --allow Add a device to the allow list.\n"
- " Only use the specified devices. The argument format\n"
- " for PCI devices is <[domain:]bus:devid.func>.\n"
- " This option can be present several times.\n"
- " [NOTE: " OPT_DEV_ALLOW " cannot be used with "OPT_DEV_BLOCK" option]\n"
- " --"OPT_VDEV" Add a virtual device.\n"
- " The argument format is <driver><id>[,key=val,...]\n"
- " (ex: --vdev=net_pcap0,iface=eth2).\n"
- " --"OPT_IOVA_MODE" Set IOVA mode. 'pa' for IOVA_PA\n"
- " 'va' for IOVA_VA\n"
- " -d LIB.so|DIR Add a driver or driver directory\n"
- " (can be used multiple times)\n"
- " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n"
- " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_SYSLOG"[=<facility>] Enable use of syslog (and optionally set facility)\n"
-#endif
- " --"OPT_LOG_LEVEL"=<level> Set global log level\n"
- " --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
- " Set specific log level\n"
- " --"OPT_LOG_LEVEL"=help Show log types and levels\n"
- " --"OPT_LOG_TIMESTAMP"[=<format>] Timestamp log output\n"
- " --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
-#ifndef RTE_EXEC_ENV_WINDOWS
- " --"OPT_TRACE"=<regex-match>\n"
- " Enable trace based on regular expression trace name.\n"
- " By default, the trace is disabled.\n"
- " User must specify this option to enable trace.\n"
- " --"OPT_TRACE_DIR"=<directory path>\n"
- " Specify trace directory for trace output.\n"
- " By default, trace output will created at\n"
- " $HOME directory and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_BUF_SIZE"=<int>\n"
- " Specify maximum size of allocated memory\n"
- " for trace output for each thread. Valid\n"
- " unit can be either 'B|K|M' for 'Bytes',\n"
- " 'KBytes' and 'MBytes' respectively.\n"
- " Default is 1MB and parameter must be\n"
- " specified once only.\n"
- " --"OPT_TRACE_MODE"=<o[verwrite] | d[iscard]>\n"
- " Specify the mode of update of trace\n"
- " output file. Either update on a file can\n"
- " be wrapped or discarded when file size\n"
- " reaches its maximum limit.\n"
- " Default mode is 'overwrite' and parameter\n"
- " must be specified once only.\n"
-#endif /* !RTE_EXEC_ENV_WINDOWS */
- " -v Display version information on startup\n"
- " -h, --"OPT_HELP" This help\n"
- " --"OPT_IN_MEMORY" Operate entirely in memory. This will\n"
- " disable secondary process support\n"
- " --"OPT_BASE_VIRTADDR" Base virtual address\n"
- " --"OPT_TELEMETRY" Enable telemetry support (on by default)\n"
- " --"OPT_NO_TELEMETRY" Disable telemetry support\n"
- " --"OPT_FORCE_MAX_SIMD_BITWIDTH" Force the max SIMD bitwidth\n"
- "\nEAL options for DEBUG use only:\n"
- " --"OPT_HUGE_UNLINK"[=existing|always|never]\n"
- " When to unlink files in hugetlbfs\n"
- " ('existing' by default, no value means 'always')\n"
- " --"OPT_NO_HUGE" Use malloc instead of hugetlbfs\n"
- " --"OPT_NO_PCI" Disable PCI\n"
- " --"OPT_NO_HPET" Disable HPET\n"
- " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n"
- "\n", RTE_MAX_LCORE);
-}
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index 6ef45559f0..c4d2cc84dc 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -115,18 +115,12 @@ enum {
OPT_LONG_MAX_NUM
};
-extern const char eal_short_options[];
-extern const struct option eal_long_options[];
-
-bool eal_option_is_log(int opt);
-int eal_parse_log_options(int argc, char * const argv[]);
-int eal_parse_common_option(int opt, const char *argv,
- struct internal_config *conf);
+int eal_parse_log_options(void);
+int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
int eal_check_common_options(struct internal_config *internal_cfg);
-void eal_common_usage(void);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index 5846917cc5..ab8b37b956 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -72,6 +72,17 @@ struct rte_config {
*/
struct rte_config *rte_eal_get_configuration(void);
+/**
+ * Put the argument list into a structure.
+ *
+ * This allows the arguments to then be processed out-of-order.
+ *
+ * @return
+ * - 0 on success
+ * - Negative on error
+ */
+int eal_collate_args(int argc, char **argv);
+
/**
* Initialize the memzone subsystem (private to eal).
*
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index c1ab8d86d2..ee8bf92bff 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -160,7 +160,7 @@ rte_eal_config_create(void)
cfg_len_aligned, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, mem_cfg_fd, 0);
if (mapped_mem_cfg_addr == MAP_FAILED) {
- EAL_LOG(ERR, "Cannot remap memory for rte_config");
+ EAL_LOG(ERR, "Cannot remap memory for rte_config: %s", strerror(errno));
munmap(rte_mem_cfg_addr, cfg_len);
close(mem_cfg_fd);
mem_cfg_fd = -1;
@@ -245,11 +245,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
- /* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option",
- rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
@@ -332,21 +329,6 @@ rte_config_init(void)
return 0;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
static inline size_t
eal_get_hugepage_mem_size(void)
{
@@ -367,123 +349,6 @@ eal_get_hugepage_mem_size(void)
return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX;
}
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- const int old_optreset = optreset;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
- optreset = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on FreeBSD", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on FreeBSD",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on FreeBSD", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optreset = old_optreset;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -553,8 +418,18 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* Save and collate args at the top */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("invalid command-line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -585,18 +460,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
@@ -605,8 +476,7 @@ rte_eal_init(int argc, char **argv)
/* FreeBSD always uses legacy memory model */
internal_conf->legacy_mem = true;
if (internal_conf->in_memory) {
- EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '%s'",
- OPT_IN_MEMORY);
+ EAL_LOG(WARNING, "Warning: ignoring unsupported flag, '--in-memory'");
internal_conf->in_memory = false;
}
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 52efb8626b..f59cb43b0e 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -59,9 +59,6 @@
#include "log_internal.h"
#define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
-
-#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
-
#define KERNEL_IOMMU_GROUPS_PATH "/sys/kernel/iommu_groups"
/* define fd variable here, because file needs to be kept open for the
@@ -438,362 +435,6 @@ eal_hugedirs_unlock(void)
}
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- printf("EAL Linux options:\n"
- " --"OPT_NUMA_MEM" Memory to allocate on NUMA nodes (comma separated values)\n"
- " --"OPT_NUMA_LIMIT" Limit memory allocation on NUMA nodes (comma separated values)\n"
- " --"OPT_HUGE_DIR" Directory where hugetlbfs is mounted\n"
- " --"OPT_FILE_PREFIX" Prefix for hugepage filenames\n"
- " --"OPT_CREATE_UIO_DEV" Create /dev/uioX (usually done by hotplug)\n"
- " --"OPT_VFIO_INTR" Interrupt mode for VFIO (legacy|msi|msix)\n"
- " --"OPT_VFIO_VF_TOKEN" VF token (UUID) shared between SR-IOV PF and VFs\n"
- " --"OPT_LEGACY_MEM" Legacy memory mode (no dynamic allocation, contiguous segments)\n"
- " --"OPT_SINGLE_FILE_SEGMENTS" Put all hugepage memory in single files\n"
- " --"OPT_MATCH_ALLOCATIONS" Free hugepages exactly as allocated\n"
- " --"OPT_HUGE_WORKER_STACK"[=size]\n"
- " Allocate worker thread stacks from hugepage memory.\n"
- " Size is in units of kbytes and defaults to system\n"
- " thread stack size if not specified.\n"
- "\n");
- /* Allow the application to print its usage message too if hook is set */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-static int
-eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
-{
- char * arg[RTE_MAX_NUMA_NODES];
- char *end;
- int arg_num, i, len;
-
- len = strnlen(strval, SOCKET_MEM_STRLEN);
- if (len == SOCKET_MEM_STRLEN) {
- EAL_LOG(ERR, "--socket-mem is too long");
- return -1;
- }
-
- /* all other error cases will be caught later */
- if (!isdigit(strval[len-1]))
- return -1;
-
- /* split the optarg into separate socket values */
- arg_num = rte_strsplit(strval, len,
- arg, RTE_MAX_NUMA_NODES, ',');
-
- /* if split failed, or 0 arguments */
- if (arg_num <= 0)
- return -1;
-
- /* parse each defined socket option */
- errno = 0;
- for (i = 0; i < arg_num; i++) {
- uint64_t val;
- end = NULL;
- val = strtoull(arg[i], &end, 10);
-
- /* check for invalid input */
- if ((errno != 0) ||
- (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
- return -1;
- val <<= 20;
- socket_arg[i] = val;
- }
-
- return 0;
-}
-
-static int
-eal_parse_vfio_intr(const char *mode)
-{
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
- unsigned i;
- static struct {
- const char *name;
- enum rte_intr_mode value;
- } map[] = {
- { "legacy", RTE_INTR_MODE_LEGACY },
- { "msi", RTE_INTR_MODE_MSI },
- { "msix", RTE_INTR_MODE_MSIX },
- };
-
- for (i = 0; i < RTE_DIM(map); i++) {
- if (!strcmp(mode, map[i].name)) {
- internal_conf->vfio_intr_mode = map[i].value;
- return 0;
- }
- }
- return -1;
-}
-
-static int
-eal_parse_vfio_vf_token(const char *vf_token)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
- rte_uuid_t uuid;
-
- if (!rte_uuid_parse(vf_token, uuid)) {
- rte_uuid_copy(cfg->vfio_vf_token, uuid);
- return 0;
- }
-
- return -1;
-}
-
-static int
-eal_parse_huge_worker_stack(const char *arg)
-{
- struct internal_config *cfg = eal_get_internal_configuration();
-
- if (arg == NULL || arg[0] == '\0') {
- pthread_attr_t attr;
- int ret;
-
- if (pthread_attr_init(&attr) != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
- pthread_attr_destroy(&attr);
- if (ret != 0) {
- EAL_LOG(ERR, "Could not retrieve default stack size");
- return -1;
- }
- } else {
- unsigned long stack_size;
- char *end;
-
- errno = 0;
- stack_size = strtoul(arg, &end, 10);
- if (errno || end == NULL || stack_size == 0 ||
- stack_size >= (size_t)-1 / 1024)
- return -1;
-
- cfg->huge_worker_stack_size = stack_size * 1024;
- }
-
- EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
- cfg->huge_worker_stack_size / 1024);
- return 0;
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- const int old_optind = optind;
- const int old_optopt = optopt;
- char * const old_optarg = optarg;
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
- optind = 1;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- /* getopt didn't recognise the option */
- if (opt == '?') {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
-
- case OPT_HUGE_DIR_NUM:
- {
- char *hdir = strdup(optarg);
- if (hdir == NULL)
- EAL_LOG(ERR, "Could not store hugepage directory");
- else {
- /* free old hugepage dir */
- free(internal_conf->hugepage_dir);
- internal_conf->hugepage_dir = hdir;
- }
- break;
- }
- case OPT_FILE_PREFIX_NUM:
- {
- char *prefix = strdup(optarg);
- if (prefix == NULL)
- EAL_LOG(ERR, "Could not store file prefix");
- else {
- /* free old prefix */
- free(internal_conf->hugefile_prefix);
- internal_conf->hugefile_prefix = prefix;
- }
- break;
- }
- case OPT_NUMA_MEM_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_mem) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_MEM
- " (aka --"
- OPT_SOCKET_MEM
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa = 1;
- break;
-
- case OPT_NUMA_LIMIT_NUM:
- if (eal_parse_socket_arg(optarg,
- internal_conf->numa_limit) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_NUMA_LIMIT
- " (aka --"
- OPT_SOCKET_LIMIT
- ")");
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- internal_conf->force_numa_limits = 1;
- break;
-
- case OPT_VFIO_INTR_NUM:
- if (eal_parse_vfio_intr(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_INTR);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_VFIO_VF_TOKEN_NUM:
- if (eal_parse_vfio_vf_token(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameters for --"
- OPT_VFIO_VF_TOKEN);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- case OPT_CREATE_UIO_DEV_NUM:
- internal_conf->create_uio_dev = 1;
- break;
-
- case OPT_MBUF_POOL_OPS_NAME_NUM:
- {
- char *ops_name = strdup(optarg);
- if (ops_name == NULL)
- EAL_LOG(ERR, "Could not store mbuf pool ops name");
- else {
- /* free old ops name */
- free(internal_conf->user_mbuf_pool_ops_name);
-
- internal_conf->user_mbuf_pool_ops_name =
- ops_name;
- }
- break;
- }
- case OPT_MATCH_ALLOCATIONS_NUM:
- internal_conf->match_allocations = 1;
- break;
-
- case OPT_HUGE_WORKER_STACK_NUM:
- if (eal_parse_huge_worker_stack(optarg) < 0) {
- EAL_LOG(ERR, "invalid parameter for --"
- OPT_HUGE_WORKER_STACK);
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- break;
-
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Linux", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Linux",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Linux", opt);
- }
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
- }
-
- /* create runtime data directory. In no_shconf mode, skip any errors */
- if (eal_create_runtime_dir() < 0) {
- if (internal_conf->no_shconf == 0) {
- EAL_LOG(ERR, "Cannot create runtime directory");
- ret = -1;
- goto out;
- } else
- EAL_LOG(WARNING, "No DPDK runtime directory created");
- }
-
- if (eal_adjust_config(internal_conf) != 0) {
- ret = -1;
- goto out;
- }
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- ret = -1;
- goto out;
- }
-
- if (optind >= 0)
- argv[optind-1] = prgname;
- ret = optind-1;
-
-out:
- /* restore getopt lib */
- optind = old_optind;
- optopt = old_optopt;
- optarg = old_optarg;
-
- return ret;
-}
-
static int
check_socket(const struct rte_memseg_list *msl, void *arg)
{
@@ -938,8 +579,18 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -970,18 +621,14 @@ rte_eal_init(int argc, char **argv)
eal_reset_internal_config(internal_conf);
- /* clone argv to report out later in telemetry */
- eal_save_args(argc, argv);
-
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0) {
- rte_eal_init_alert("Invalid 'command line' arguments.");
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
return -1;
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 4f0a164d9b..14547d5ac9 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -82,99 +82,6 @@ rte_mp_disable(void)
return true;
}
-/* display usage */
-static void
-eal_usage(const char *prgname)
-{
- rte_usage_hook_t hook = eal_get_application_usage_hook();
-
- printf("\nUsage: %s ", prgname);
- eal_common_usage();
- /* Allow the application to print its usage message too
- * if hook is set
- */
- if (hook) {
- printf("===== Application Usage =====\n\n");
- (hook)(prgname);
- }
-}
-
-/* Parse the argument given in the command line of the application */
-static int
-eal_parse_args(int argc, char **argv)
-{
- int opt, ret;
- char **argvopt;
- int option_index;
- char *prgname = argv[0];
- struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- argvopt = argv;
-
- while ((opt = getopt_long(argc, argvopt, eal_short_options,
- eal_long_options, &option_index)) != EOF) {
-
- int ret;
-
- /* getopt is not happy, stop right now */
- if (opt == '?') {
- eal_usage(prgname);
- return -1;
- }
-
- /* eal_parse_log_options() already handled this option */
- if (eal_option_is_log(opt))
- continue;
-
- ret = eal_parse_common_option(opt, optarg, internal_conf);
- /* common parser is not happy */
- if (ret < 0) {
- eal_usage(prgname);
- return -1;
- }
- /* common parser handled this option */
- if (ret == 0)
- continue;
-
- switch (opt) {
- case OPT_HELP_NUM:
- eal_usage(prgname);
- exit(EXIT_SUCCESS);
- default:
- if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
- EAL_LOG(ERR, "Option %c is not supported "
- "on Windows", opt);
- } else if (opt >= OPT_LONG_MIN_NUM &&
- opt < OPT_LONG_MAX_NUM) {
- EAL_LOG(ERR, "Option %s is not supported "
- "on Windows",
- eal_long_options[option_index].name);
- } else {
- EAL_LOG(ERR, "Option %d is not supported "
- "on Windows", opt);
- }
- eal_usage(prgname);
- return -1;
- }
- }
-
- if (eal_adjust_config(internal_conf) != 0)
- return -1;
-
- /* sanity checks */
- if (eal_check_common_options(internal_conf) != 0) {
- eal_usage(prgname);
- return -1;
- }
-
- if (optind >= 0)
- argv[optind - 1] = prgname;
- ret = optind - 1;
- optind = 0; /* reset getopt lib */
- return ret;
-}
-
static int
sync_func(void *arg __rte_unused)
{
@@ -260,8 +167,18 @@ rte_eal_init(int argc, char **argv)
char cpuset[RTE_CPU_AFFINITY_STR_LEN];
char thread_name[RTE_THREAD_NAME_SIZE];
+ /* clone argv to report out later in telemetry */
+ eal_save_args(argc, argv);
+
+ fctret = eal_collate_args(argc, argv);
+ if (fctret < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
/* setup log as early as possible */
- if (eal_parse_log_options(argc, argv) < 0) {
+ if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
return -1;
@@ -288,9 +205,11 @@ rte_eal_init(int argc, char **argv)
return -1;
}
- fctret = eal_parse_args(argc, argv);
- if (fctret < 0)
- exit(1);
+ if (eal_parse_args() < 0) {
+ rte_eal_init_alert("Invalid command line arguments.");
+ rte_errno = EINVAL;
+ return -1;
+ }
if (eal_option_device_parse()) {
rte_errno = ENODEV;
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 7/9] eal: ensure proper cleanup on EAL init failure
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
` (5 preceding siblings ...)
2025-07-22 14:03 ` [PATCH v6 6/9] eal: gather EAL args before processing Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 8/9] eal: combine parameter validation checks Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk
When rte_eal_init fails part way through, any saved EAL arguments need
to be freed, and the run_once flag needs to be set back to zero again.
The former task was never done on failure, and the latter was only done
on some occasions. Rework the error handling to always go to an err_out
label where cleanup is done.
To prevent memory leaks from the saved arguments when eal_init is called
twice, the check for multiple calls must be done first before the
argument saving and parsing is done.
This patch modifies all three eal.c files. Windows doesn't actually need
changes, since there are no args saved, and no run_once sentinel value,
but updating it keeps it consistent with FreeBSD and Linux versions.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
NOTE: this patch can probably be squashed in with the changes in the
previous one, but for easier review I've kept it separate for now.
---
lib/eal/common/eal_common_options.c | 37 ++++++++----
lib/eal/common/eal_options.h | 1 +
lib/eal/freebsd/eal.c | 83 +++++++++++++-------------
lib/eal/linux/eal.c | 90 ++++++++++++++---------------
lib/eal/windows/eal.c | 47 ++++++++-------
5 files changed, 137 insertions(+), 121 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index aea2c813ed..9c27d44a96 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -271,6 +271,8 @@ rte_set_application_usage_hook(rte_usage_hook_t usage_func)
int
eal_save_args(__rte_unused int argc, __rte_unused char **argv) { return 0; }
+void
+eal_clean_saved_args(void) { /* no-op */ }
#else /* RTE_EXEC_ENV_WINDOWS */
static char **eal_args;
@@ -302,6 +304,28 @@ handle_eal_info_request(const char *cmd, const char *params __rte_unused,
return used;
}
+void
+eal_clean_saved_args(void)
+{
+ int i;
+
+ if (eal_args == NULL)
+ return;
+
+ if (eal_app_args != NULL) {
+ i = 0;
+ while (eal_app_args[i] != NULL)
+ free(eal_app_args[i++]);
+ free(eal_app_args);
+ eal_app_args = NULL;
+ }
+ i = 0;
+ while (eal_args[i] != NULL)
+ free(eal_args[i++]);
+ free(eal_args);
+ eal_args = NULL;
+}
+
int
eal_save_args(int argc, char **argv)
{
@@ -346,18 +370,7 @@ eal_save_args(int argc, char **argv)
return 0;
error:
- if (eal_app_args != NULL) {
- i = 0;
- while (eal_app_args[i] != NULL)
- free(eal_app_args[i++]);
- free(eal_app_args);
- eal_app_args = NULL;
- }
- i = 0;
- while (eal_args[i] != NULL)
- free(eal_args[i++]);
- free(eal_args);
- eal_args = NULL;
+ eal_clean_saved_args();
return -1;
}
#endif /* !RTE_EXEC_ENV_WINDOWS */
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index c4d2cc84dc..fd28111e73 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -124,6 +124,7 @@ int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
+void eal_clean_saved_args(void);
int handle_eal_info_request(const char *cmd, const char *params __rte_unused,
struct rte_tel_data *d);
diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c
index ee8bf92bff..2882d218f6 100644
--- a/lib/eal/freebsd/eal.c
+++ b/lib/eal/freebsd/eal.c
@@ -418,6 +418,14 @@ rte_eal_init(int argc, char **argv)
bool has_phys_addr;
enum rte_iova_mode iova_mode;
+ /* first check if we have been run before */
+ if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
+ rte_memory_order_relaxed, rte_memory_order_relaxed)) {
+ rte_eal_init_alert("already called initialization.");
+ rte_errno = EALREADY;
+ return -1;
+ }
+
/* Save and collate args at the top */
eal_save_args(argc, argv);
@@ -425,14 +433,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("invalid command-line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(getprogname());
@@ -441,21 +449,14 @@ rte_eal_init(int argc, char **argv)
if (!rte_cpu_is_supported()) {
rte_eal_init_alert("unsupported cpu type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
- }
-
- if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
- rte_memory_order_relaxed, rte_memory_order_relaxed)) {
- rte_eal_init_alert("already called initialization.");
- rte_errno = EALREADY;
- return -1;
+ goto err_out;
}
eal_reset_internal_config(internal_conf);
@@ -463,14 +464,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
rte_eal_init_alert("Error parsing command-line arguments.");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
/* FreeBSD always uses legacy memory model */
@@ -483,37 +483,34 @@ rte_eal_init(int argc, char **argv)
if (eal_plugins_init() < 0) {
rte_eal_init_alert("Cannot init plugins");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_trace_init() < 0) {
rte_eal_init_alert("Cannot init trace");
rte_errno = EFAULT;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (rte_config_init() < 0) {
rte_eal_init_alert("Cannot init config");
- return -1;
+ goto err_out;
}
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_alarm_init() < 0) {
rte_eal_init_alert("Cannot init alarm");
/* rte_eal_alarm_init sets rte_errno on failure. */
- return -1;
+ goto err_out;
}
/* Put mp channel init before bus scan so that we can init the vdev
@@ -523,15 +520,14 @@ rte_eal_init(int argc, char **argv)
rte_eal_init_alert("failed to init mp channel");
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
}
if (rte_bus_scan()) {
rte_eal_init_alert("Cannot scan the buses for devices");
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
/*
@@ -562,13 +558,13 @@ rte_eal_init(int argc, char **argv)
if (iova_mode == RTE_IOVA_PA && !has_phys_addr) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (iova_mode == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
rte_eal_get_configuration()->iova_mode = iova_mode;
@@ -583,8 +579,7 @@ rte_eal_init(int argc, char **argv)
if (ret < 0) {
rte_eal_init_alert("Cannot get hugepage information.");
rte_errno = EACCES;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
}
@@ -613,7 +608,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -622,14 +617,14 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
if (rte_eal_malloc_heap_init() < 0) {
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -637,19 +632,19 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init HPET or TSC timers");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -660,7 +655,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -713,14 +708,14 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/* Probe all the buses and devices/drivers on them */
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* initialize default service/lcore mappings and start running. Ignore
@@ -729,7 +724,7 @@ rte_eal_init(int argc, char **argv)
ret = rte_service_start_with_defaults();
if (ret < 0 && ret != -ENOTSUP) {
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/*
@@ -744,18 +739,22 @@ rte_eal_init(int argc, char **argv)
*/
if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
rte_eal_init_alert("Cannot clear runtime directory");
- return -1;
+ goto err_out;
}
if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
if (rte_telemetry_init(rte_eal_get_runtime_dir(),
rte_version(),
&internal_conf->ctrl_cpuset) != 0)
- return -1;
+ goto err_out;
}
eal_mcfg_complete();
return fctret;
+err_out:
+ rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
+ eal_clean_saved_args();
+ return -1;
}
RTE_EXPORT_SYMBOL(rte_eal_cleanup)
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index f59cb43b0e..210d461497 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -579,6 +579,14 @@ rte_eal_init(int argc, char **argv)
struct internal_config *internal_conf =
eal_get_internal_configuration();
+ /* first check if we have been run before */
+ if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
+ rte_memory_order_relaxed, rte_memory_order_relaxed)) {
+ rte_eal_init_alert("already called initialization.");
+ rte_errno = EALREADY;
+ return -1;
+ }
+
/* clone argv to report out later in telemetry */
eal_save_args(argc, argv);
@@ -586,14 +594,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(program_invocation_short_name);
@@ -602,21 +610,14 @@ rte_eal_init(int argc, char **argv)
if (!rte_cpu_is_supported()) {
rte_eal_init_alert("unsupported cpu type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
- }
-
- if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
- rte_memory_order_relaxed, rte_memory_order_relaxed)) {
- rte_eal_init_alert("already called initialization.");
- rte_errno = EALREADY;
- return -1;
+ goto err_out;
}
eal_reset_internal_config(internal_conf);
@@ -624,49 +625,46 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
- rte_eal_init_alert("Invalid command line arguments.");
+ rte_eal_init_alert("Error parsing command line arguments.");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_plugins_init() < 0) {
rte_eal_init_alert("Cannot init plugins");
rte_errno = EINVAL;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (eal_trace_init() < 0) {
rte_eal_init_alert("Cannot init trace");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
if (rte_config_init() < 0) {
rte_eal_init_alert("Cannot init config");
- return -1;
+ goto err_out;
}
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_alarm_init() < 0) {
rte_eal_init_alert("Cannot init alarm");
/* rte_eal_alarm_init sets rte_errno on failure. */
- return -1;
+ goto err_out;
}
/* Put mp channel init before bus scan so that we can init the vdev
@@ -676,15 +674,14 @@ rte_eal_init(int argc, char **argv)
rte_eal_init_alert("failed to init mp channel");
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
}
if (rte_bus_scan()) {
rte_eal_init_alert("Cannot scan the buses for devices");
rte_errno = ENODEV;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
phys_addrs = rte_eal_using_phys_addrs() != 0;
@@ -727,13 +724,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_iova_mode() == RTE_IOVA_PA && !phys_addrs) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (rte_eal_iova_mode() == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
EAL_LOG(INFO, "Selected IOVA mode '%s'",
@@ -747,8 +744,7 @@ rte_eal_init(int argc, char **argv)
if (ret < 0) {
rte_eal_init_alert("Cannot get hugepage information.");
rte_errno = EACCES;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
}
@@ -772,8 +768,7 @@ rte_eal_init(int argc, char **argv)
if (rte_vfio_enable("vfio")) {
rte_eal_init_alert("Cannot init VFIO");
rte_errno = EAGAIN;
- rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
- return -1;
+ goto err_out;
}
#endif
/* in secondary processes, memory init may allocate additional fbarrays
@@ -783,7 +778,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -792,7 +787,7 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
/* the directories are locked during eal_hugepage_info_init */
@@ -802,7 +797,7 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -810,25 +805,25 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
/* register multi-process action callbacks for hotplug after memory init */
if (eal_mp_dev_hotplug_init() < 0) {
rte_eal_init_alert("failed to register mp callback for hotplug");
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init HPET or TSC timers");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -839,7 +834,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -890,14 +885,14 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/* Probe all the buses and devices/drivers on them */
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/* initialize default service/lcore mappings and start running. Ignore
@@ -906,7 +901,7 @@ rte_eal_init(int argc, char **argv)
ret = rte_service_start_with_defaults();
if (ret < 0 && ret != -ENOTSUP) {
rte_errno = -ret;
- return -1;
+ goto err_out;
}
/*
@@ -921,18 +916,23 @@ rte_eal_init(int argc, char **argv)
*/
if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
rte_eal_init_alert("Cannot clear runtime directory");
- return -1;
+ goto err_out;
}
if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
if (rte_telemetry_init(rte_eal_get_runtime_dir(),
rte_version(),
&internal_conf->ctrl_cpuset) != 0)
- return -1;
+ goto err_out;
}
eal_mcfg_complete();
return fctret;
+
+err_out:
+ rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
+ eal_clean_saved_args();
+ return -1;
}
static int
diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c
index 14547d5ac9..cd9a72a0fc 100644
--- a/lib/eal/windows/eal.c
+++ b/lib/eal/windows/eal.c
@@ -174,14 +174,14 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
/* setup log as early as possible */
if (eal_parse_log_options() < 0) {
rte_eal_init_alert("invalid log arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
eal_log_init(NULL);
@@ -189,31 +189,31 @@ rte_eal_init(int argc, char **argv)
if (eal_create_cpu_map() < 0) {
rte_eal_init_alert("Cannot discover CPU and NUMA.");
/* rte_errno is set */
- return -1;
+ goto err_out;
}
/* verify if DPDK supported on architecture MMU */
if (!eal_mmu_supported()) {
rte_eal_init_alert("Unsupported MMU type.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (rte_eal_cpu_init() < 0) {
rte_eal_init_alert("Cannot detect lcores.");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
if (eal_parse_args() < 0) {
rte_eal_init_alert("Invalid command line arguments.");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (eal_option_device_parse()) {
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
/* Prevent creation of shared memory files. */
@@ -227,7 +227,7 @@ rte_eal_init(int argc, char **argv)
if (!internal_conf->no_hugetlbfs && (eal_hugepage_info_init() < 0)) {
rte_eal_init_alert("Cannot get hugepage information");
rte_errno = EACCES;
- return -1;
+ goto err_out;
}
if (internal_conf->memory == 0 && !internal_conf->force_numa) {
@@ -237,26 +237,26 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_intr_init() < 0) {
rte_eal_init_alert("Cannot init interrupt-handling thread");
- return -1;
+ goto err_out;
}
if (rte_eal_timer_init() < 0) {
rte_eal_init_alert("Cannot init TSC timer");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
bscan = rte_bus_scan();
if (bscan < 0) {
rte_eal_init_alert("Cannot scan the buses");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (eal_mem_win32api_init() < 0) {
rte_eal_init_alert("Cannot access Win32 memory management");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
has_phys_addr = true;
@@ -289,13 +289,13 @@ rte_eal_init(int argc, char **argv)
if (iova_mode == RTE_IOVA_PA && !has_phys_addr) {
rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
if (iova_mode == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
EAL_LOG(DEBUG, "Selected IOVA mode '%s'",
@@ -305,7 +305,7 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_memzone_init() < 0) {
rte_eal_init_alert("Cannot init memzone");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_lock();
@@ -314,14 +314,14 @@ rte_eal_init(int argc, char **argv)
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init memory");
rte_errno = ENOMEM;
- return -1;
+ goto err_out;
}
if (rte_eal_malloc_heap_init() < 0) {
rte_mcfg_mem_read_unlock();
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
rte_mcfg_mem_read_unlock();
@@ -329,13 +329,13 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_malloc_heap_populate() < 0) {
rte_eal_init_alert("Cannot init malloc heap");
rte_errno = ENODEV;
- return -1;
+ goto err_out;
}
if (rte_eal_tailqs_init() < 0) {
rte_eal_init_alert("Cannot init tail queues for objects");
rte_errno = EFAULT;
- return -1;
+ goto err_out;
}
eal_rand_init();
@@ -344,7 +344,7 @@ rte_eal_init(int argc, char **argv)
&lcore_config[config->main_lcore].cpuset) != 0) {
rte_eal_init_alert("Cannot set affinity");
rte_errno = EINVAL;
- return -1;
+ goto err_out;
}
__rte_thread_init(config->main_lcore,
&lcore_config[config->main_lcore].cpuset);
@@ -390,13 +390,13 @@ rte_eal_init(int argc, char **argv)
if (ret) {
rte_eal_init_alert("rte_service_init() failed");
rte_errno = -ret;
- return -1;
+ goto err_out;
}
if (rte_bus_probe()) {
rte_eal_init_alert("Cannot probe devices");
rte_errno = ENOTSUP;
- return -1;
+ goto err_out;
}
/*
@@ -409,6 +409,9 @@ rte_eal_init(int argc, char **argv)
eal_mcfg_complete();
return fctret;
+err_out:
+ eal_clean_saved_args();
+ return -1;
}
/* Don't use MinGW asprintf() to have identical code with all toolchains. */
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 8/9] eal: combine parameter validation checks
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
` (6 preceding siblings ...)
2025-07-22 14:03 ` [PATCH v6 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Anatoly Burakov, Tyler Retzlaff
Remove the separate function to check combinations of cmdline
parameters. Instead, just do those checks when parsing the parameters
since we have all info about what parameters are provided at that point.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_memory.c | 3 +-
lib/eal/common/eal_common_options.c | 262 +++++++++++-----------------
lib/eal/common/eal_options.h | 107 ------------
lib/eal/linux/eal.c | 5 +-
lib/eal/linux/eal_memory.c | 2 +-
5 files changed, 106 insertions(+), 273 deletions(-)
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 38ccc734e8..c62edf5e55 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -258,8 +258,7 @@ eal_memseg_list_alloc(struct rte_memseg_list *msl, int reserve_flags)
* including common code, so don't duplicate the message.
*/
if (rte_errno == EADDRNOTAVAIL)
- EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - "
- "please use '--" OPT_BASE_VIRTADDR "' option",
+ EAL_LOG(ERR, "Cannot reserve %llu bytes at [%p] - please use '--base-virtaddr' option",
(unsigned long long)mem_sz, msl->base_va);
#endif
return -1;
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 9c27d44a96..486e2ad854 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -243,7 +243,6 @@ struct device_option {
static struct device_option_list devopt_list =
TAILQ_HEAD_INITIALIZER(devopt_list);
-static int main_lcore_parsed;
static int core_parsed;
/* Returns rte_usage_hook_t */
@@ -751,15 +750,6 @@ eal_parse_service_coremask(const char *coremask)
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE;
j++, idx++) {
if ((1 << j) & val) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (main_lcore_parsed &&
- cfg->main_lcore == lcore) {
- EAL_LOG(ERR,
- "lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (eal_cpu_detected(idx) == 0) {
EAL_LOG(ERR,
@@ -982,15 +972,6 @@ eal_parse_service_corelist(const char *corelist)
min = idx;
for (idx = min; idx <= max; idx++) {
if (cfg->lcore_role[idx] != ROLE_SERVICE) {
- /* handle main lcore already parsed */
- uint32_t lcore = idx;
- if (cfg->main_lcore == lcore &&
- main_lcore_parsed) {
- EAL_LOG(ERR,
- "Error: lcore %u is main lcore, cannot use as service core",
- idx);
- return -1;
- }
if (cfg->lcore_role[idx] == ROLE_RTE)
taken_lcore_count++;
@@ -1030,12 +1011,15 @@ eal_parse_main_lcore(const char *arg)
return -1;
if (cfg->main_lcore >= RTE_MAX_LCORE)
return -1;
- main_lcore_parsed = 1;
/* ensure main core is not used as service core */
if (lcore_config[cfg->main_lcore].core_role == ROLE_SERVICE) {
- EAL_LOG(ERR,
- "Error: Main lcore is used as a service core");
+ EAL_LOG(ERR, "Error: Main lcore is used as a service core");
+ return -1;
+ }
+ /* check that we have the core recorded in the core list */
+ if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
+ EAL_LOG(ERR, "Error: Main lcore is not enabled for DPDK");
return -1;
}
@@ -1330,11 +1314,11 @@ eal_log_usage(void)
rte_log_list_types(stdout, "\t");
printf("\n");
printf("Syntax using globbing pattern: ");
- printf("--"OPT_LOG_LEVEL" pattern:level\n");
+ printf("--log-level pattern:level\n");
printf("Syntax using regular expression: ");
- printf("--"OPT_LOG_LEVEL" regexp,level\n");
+ printf("--log-level regexp,level\n");
printf("Syntax for the global level: ");
- printf("--"OPT_LOG_LEVEL" level\n");
+ printf("--log-level level\n");
printf("Logs are emitted if allowed by both global and specific levels.\n");
printf("\n");
printf("Log level can be a number or the first letters of its name:\n");
@@ -1614,7 +1598,7 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
return 0;
}
if (strcmp(arg, HUGE_UNLINK_NEVER) == 0) {
- EAL_LOG(WARNING, "Using --"OPT_HUGE_UNLINK"="
+ EAL_LOG(WARNING, "Using --huge-unlink="
HUGE_UNLINK_NEVER" may create data leaks.");
out->unlink_existing = false;
return 0;
@@ -1793,6 +1777,7 @@ int
eal_parse_args(void)
{
struct internal_config *int_cfg = eal_get_internal_configuration();
+ struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
/* check for conflicting options */
@@ -1818,19 +1803,62 @@ eal_parse_args(void)
}
/* can't have both -m and --socket-mem */
if (args.memory_size != NULL && args.numa_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --socket-mem can't be used at the same time");
+ EAL_LOG(ERR, "Options -m and --numa-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use both no-huge and socket-mem */
+ if (args.no_huge && args.numa_mem) {
+ EAL_LOG(ERR, "Options --no-huge and --numa-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-worker-stack */
+ if (args.huge_worker_stack != NULL && args.no_huge) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
+ return -1;
+ }
+ /* can't use socket-limit and legacy-mem */
+ if (args.numa_limit != NULL && args.legacy_mem) {
+ EAL_LOG(ERR, "Options --numa-limit and --legacy-mem can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and in-memory */
+ if (args.legacy_mem && args.in_memory) {
+ EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
+ return -1;
+ }
+ /* can't use legacy-mem and match-allocations */
+ if (args.legacy_mem && args.match_allocations) {
+ EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and match-allocations */
+ if (args.no_huge && args.match_allocations) {
+ EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
+ return -1;
+ }
+ /* can't use no-huge and huge-unlink */
+ if (args.no_huge && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use single-file-segments and huge-unlink */
+ if (args.single_file_segments && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
+ return -1;
+ }
+ /* can't use in-memory and huge-unlink */
+ if (args.in_memory && args.huge_unlink) {
+ EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
return -1;
}
- /* parse options */
/* print version before anything else */
- if (args.version) {
- /* since message is explicitly requested by user, we write message
- * at highest log level so it can always be seen even if info or
- * warning messages are disabled
- */
+ /* since message is explicitly requested by user, we write message
+ * at highest log level so it can always be seen even if info or
+ * warning messages are disabled
+ */
+ if (args.version)
EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
- }
/* parse the process type */
if (args.proc_type != NULL) {
@@ -1856,7 +1884,7 @@ eal_parse_args(void)
if (eal_plugin_add(arg->arg) < 0)
return -1;
- /* parse the coremask /core-list */
+ /* parse the core list arguments */
if (args.coremask != NULL) {
int lcore_indexes[RTE_MAX_LCORE];
@@ -1880,13 +1908,6 @@ eal_parse_args(void)
}
core_parsed = 1;
}
- if (args.main_lcore != NULL) {
- if (eal_parse_main_lcore(args.main_lcore) < 0) {
- EAL_LOG(ERR, "invalid main-lcore parameter");
- return -1;
- }
- }
-
/* service core options */
if (args.service_coremask != NULL) {
if (eal_parse_service_coremask(args.service_coremask) < 0) {
@@ -1901,6 +1922,17 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.main_lcore != NULL) {
+ if (eal_parse_main_lcore(args.main_lcore) < 0)
+ return -1;
+ } else {
+ /* default main lcore is the first one */
+ rte_cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
+ if (rte_cfg->main_lcore >= RTE_MAX_LCORE) {
+ EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
+ return -1;
+ }
+ }
/* memory options */
if (args.memory_size != NULL) {
@@ -1922,14 +1954,6 @@ eal_parse_args(void)
return -1;
}
}
- if (args.huge_unlink != NULL) {
- if (args.huge_unlink == (void *)1)
- args.huge_unlink = NULL;
- if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
- EAL_LOG(ERR, "invalid huge-unlink parameter");
- return -1;
- }
- }
if (args.no_huge) {
int_cfg->no_hugetlbfs = 1;
/* no-huge is legacy mem */
@@ -1941,11 +1965,18 @@ eal_parse_args(void)
int_cfg->no_shconf = 1;
int_cfg->hugepage_file.unlink_before_mapping = true;
}
- if (args.legacy_mem)
+ if (args.legacy_mem) {
int_cfg->legacy_mem = 1;
+ if (args.memory_size == NULL && args.numa_mem == NULL)
+ EAL_LOG(NOTICE, "Static memory layout is selected, amount of reserved memory can be adjusted with -m or --socket-mem");
+ }
if (args.single_file_segments)
int_cfg->single_file_segments = 1;
if (args.huge_dir != NULL) {
+ if (strlen(args.huge_dir) < 1) {
+ EAL_LOG(ERR, "Invalid hugepage dir parameter");
+ return -1;
+ }
free(int_cfg->hugepage_dir); /* free old hugepage dir */
int_cfg->hugepage_dir = strdup(args.huge_dir);
if (int_cfg->hugepage_dir == NULL) {
@@ -1954,6 +1985,14 @@ eal_parse_args(void)
}
}
if (args.file_prefix != NULL) {
+ if (strlen(args.file_prefix) < 1) {
+ EAL_LOG(ERR, "Invalid file prefix parameter");
+ return -1;
+ }
+ if (strchr(args.file_prefix, '%') != NULL) {
+ EAL_LOG(ERR, "Invalid char, '%%', in file_prefix parameter");
+ return -1;
+ }
free(int_cfg->hugefile_prefix); /* free old file prefix */
int_cfg->hugefile_prefix = strdup(args.file_prefix);
if (int_cfg->hugefile_prefix == NULL) {
@@ -1961,6 +2000,14 @@ eal_parse_args(void)
return -1;
}
}
+ if (args.huge_unlink != NULL) {
+ if (args.huge_unlink == (void *)1)
+ args.huge_unlink = NULL;
+ if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
+ EAL_LOG(ERR, "invalid huge-unlink parameter");
+ return -1;
+ }
+ }
if (args.numa_mem != NULL) {
if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
@@ -2078,6 +2125,10 @@ eal_parse_args(void)
EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
return -1;
}
+ if (strlen(int_cfg->user_mbuf_pool_ops_name) < 1) {
+ EAL_LOG(ERR, "Invalid mbuf pool ops name parameter");
+ return -1;
+ }
}
#ifndef RTE_EXEC_ENV_WINDOWS
@@ -2096,11 +2147,6 @@ eal_parse_args(void)
return -1;
}
- if (eal_check_common_options(int_cfg) != 0) {
- EAL_LOG(ERR, "Checking common options failed");
- return -1;
- }
-
return 0;
}
@@ -2180,14 +2226,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
if (internal_conf->process_type == RTE_PROC_AUTO)
internal_conf->process_type = eal_proc_type_detect();
- /* default main lcore is the first one */
- if (!main_lcore_parsed) {
- cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
- if (cfg->main_lcore >= RTE_MAX_LCORE)
- return -1;
- lcore_config[cfg->main_lcore].core_role = ROLE_RTE;
- }
-
compute_ctrl_threads_cpuset(internal_cfg);
/* if no memory amounts were requested, this will result in 0 and
@@ -2198,102 +2236,6 @@ eal_adjust_config(struct internal_config *internal_cfg)
return 0;
}
-int
-eal_check_common_options(struct internal_config *internal_cfg)
-{
- struct rte_config *cfg = rte_eal_get_configuration();
- const struct internal_config *internal_conf =
- eal_get_internal_configuration();
-
- if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
- EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
- return -1;
- }
-
- if (internal_cfg->process_type == RTE_PROC_INVALID) {
- EAL_LOG(ERR, "Invalid process type specified");
- return -1;
- }
- if (internal_cfg->hugefile_prefix != NULL &&
- strlen(internal_cfg->hugefile_prefix) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_FILE_PREFIX " option");
- return -1;
- }
- if (internal_cfg->hugepage_dir != NULL &&
- strlen(internal_cfg->hugepage_dir) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_HUGE_DIR" option");
- return -1;
- }
- if (internal_cfg->user_mbuf_pool_ops_name != NULL &&
- strlen(internal_cfg->user_mbuf_pool_ops_name) < 1) {
- EAL_LOG(ERR, "Invalid length of --" OPT_MBUF_POOL_OPS_NAME" option");
- return -1;
- }
- if (strchr(eal_get_hugefile_prefix(), '%') != NULL) {
- EAL_LOG(ERR, "Invalid char, '%%', in --"OPT_FILE_PREFIX" "
- "option");
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->force_numa == 1) {
- EAL_LOG(ERR, "Option --"OPT_SOCKET_MEM" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_UNLINK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs &&
- internal_cfg->huge_worker_stack_size != 0) {
- EAL_LOG(ERR, "Option --"OPT_HUGE_WORKER_STACK" cannot "
- "be specified together with --"OPT_NO_HUGE);
- return -1;
- }
- if (internal_conf->force_numa_limits && internal_conf->legacy_mem) {
- EAL_LOG(ERR, "Option --"OPT_NUMA_LIMIT
- " is only supported in non-legacy memory mode");
- }
- if (internal_cfg->single_file_segments &&
- internal_cfg->hugepage_file.unlink_before_mapping &&
- !internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
- "not compatible with --"OPT_HUGE_UNLINK);
- return -1;
- }
- if (!internal_cfg->hugepage_file.unlink_existing &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_IN_MEMORY" is not compatible "
- "with --"OPT_HUGE_UNLINK"="HUGE_UNLINK_NEVER);
- return -1;
- }
- if (internal_cfg->legacy_mem &&
- internal_cfg->in_memory) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_IN_MEMORY);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_LEGACY_MEM" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->no_hugetlbfs && internal_cfg->match_allocations) {
- EAL_LOG(ERR, "Option --"OPT_NO_HUGE" is not compatible "
- "with --"OPT_MATCH_ALLOCATIONS);
- return -1;
- }
- if (internal_cfg->legacy_mem && internal_cfg->memory == 0) {
- EAL_LOG(NOTICE, "Static memory layout is selected, "
- "amount of reserved memory can be adjusted with "
- "-m or --"OPT_NUMA_MEM);
- }
-
- return 0;
-}
-
RTE_EXPORT_SYMBOL(rte_vect_get_max_simd_bitwidth)
uint16_t
rte_vect_get_max_simd_bitwidth(void)
diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h
index fd28111e73..4a8a0f1df7 100644
--- a/lib/eal/common/eal_options.h
+++ b/lib/eal/common/eal_options.h
@@ -9,118 +9,11 @@
struct rte_tel_data;
-enum {
- /* long options mapped to a short option */
-#define OPT_HELP "help"
- OPT_HELP_NUM = 'h',
-#define OPT_DEV_ALLOW "allow"
- OPT_DEV_ALLOW_NUM = 'a',
-#define OPT_DEV_BLOCK "block"
- OPT_DEV_BLOCK_NUM = 'b',
-#define OPT_COREMASK "coremask"
- OPT_COREMASK_NUM = 'c',
-#define OPT_DRIVER_PATH "driver-path"
- OPT_DRIVER_PATH_NUM = 'd',
-#define OPT_LCORES "lcores"
- OPT_LCORES_NUM = 'l',
-#define OPT_MEMORY_SIZE "memory-size"
- OPT_MEMORY_SIZE_NUM = 'm',
-#define OPT_MEMORY_CHANNELS "memory-channels"
- OPT_MEMORY_CHANNELS_NUM = 'n',
-#define OPT_MEMORY_RANKS "memory-ranks"
- OPT_MEMORY_RANKS_NUM = 'r',
-#define OPT_SERVICE_COREMASK "service-coremask"
- OPT_SERVICE_COREMASK_NUM = 's',
-#define OPT_SERVICE_CORELIST "service-corelist"
- OPT_SERVICE_CORELIST_NUM = 'S',
-#define OPT_VERSION "version"
- OPT_VERSION_NUM = 'v',
-
- /* first long only option value must be >= 256, so that we won't
- * conflict with short options */
- OPT_LONG_MIN_NUM = 256,
-#define OPT_BASE_VIRTADDR "base-virtaddr"
- OPT_BASE_VIRTADDR_NUM,
-#define OPT_CREATE_UIO_DEV "create-uio-dev"
- OPT_CREATE_UIO_DEV_NUM,
-#define OPT_FILE_PREFIX "file-prefix"
- OPT_FILE_PREFIX_NUM,
-#define OPT_HUGE_DIR "huge-dir"
- OPT_HUGE_DIR_NUM,
-#define OPT_HUGE_UNLINK "huge-unlink"
- OPT_HUGE_UNLINK_NUM,
-#define OPT_LOG_COLOR "log-color"
- OPT_LOG_COLOR_NUM,
-#define OPT_LOG_LEVEL "log-level"
- OPT_LOG_LEVEL_NUM,
-#define OPT_LOG_TIMESTAMP "log-timestamp"
- OPT_LOG_TIMESTAMP_NUM,
-#define OPT_TRACE "trace"
- OPT_TRACE_NUM,
-#define OPT_TRACE_DIR "trace-dir"
- OPT_TRACE_DIR_NUM,
-#define OPT_TRACE_BUF_SIZE "trace-bufsz"
- OPT_TRACE_BUF_SIZE_NUM,
-#define OPT_TRACE_MODE "trace-mode"
- OPT_TRACE_MODE_NUM,
-#define OPT_MAIN_LCORE "main-lcore"
- OPT_MAIN_LCORE_NUM,
-#define OPT_MBUF_POOL_OPS_NAME "mbuf-pool-ops-name"
- OPT_MBUF_POOL_OPS_NAME_NUM,
-#define OPT_PROC_TYPE "proc-type"
- OPT_PROC_TYPE_NUM,
-#define OPT_NO_HPET "no-hpet"
- OPT_NO_HPET_NUM,
-#define OPT_NO_HUGE "no-huge"
- OPT_NO_HUGE_NUM,
-#define OPT_NO_PCI "no-pci"
- OPT_NO_PCI_NUM,
-#define OPT_NO_SHCONF "no-shconf"
- OPT_NO_SHCONF_NUM,
-#define OPT_IN_MEMORY "in-memory"
- OPT_IN_MEMORY_NUM,
-#define OPT_SOCKET_MEM "socket-mem"
-#define OPT_NUMA_MEM "numa-mem"
- OPT_NUMA_MEM_NUM,
-#define OPT_SOCKET_LIMIT "socket-limit"
-#define OPT_NUMA_LIMIT "numa-limit"
- OPT_NUMA_LIMIT_NUM,
-#define OPT_SYSLOG "syslog"
- OPT_SYSLOG_NUM,
-#define OPT_VDEV "vdev"
- OPT_VDEV_NUM,
-#define OPT_VFIO_INTR "vfio-intr"
- OPT_VFIO_INTR_NUM,
-#define OPT_VFIO_VF_TOKEN "vfio-vf-token"
- OPT_VFIO_VF_TOKEN_NUM,
-#define OPT_VMWARE_TSC_MAP "vmware-tsc-map"
- OPT_VMWARE_TSC_MAP_NUM,
-#define OPT_LEGACY_MEM "legacy-mem"
- OPT_LEGACY_MEM_NUM,
-#define OPT_SINGLE_FILE_SEGMENTS "single-file-segments"
- OPT_SINGLE_FILE_SEGMENTS_NUM,
-#define OPT_IOVA_MODE "iova-mode"
- OPT_IOVA_MODE_NUM,
-#define OPT_MATCH_ALLOCATIONS "match-allocations"
- OPT_MATCH_ALLOCATIONS_NUM,
-#define OPT_TELEMETRY "telemetry"
- OPT_TELEMETRY_NUM,
-#define OPT_NO_TELEMETRY "no-telemetry"
- OPT_NO_TELEMETRY_NUM,
-#define OPT_FORCE_MAX_SIMD_BITWIDTH "force-max-simd-bitwidth"
- OPT_FORCE_MAX_SIMD_BITWIDTH_NUM,
-#define OPT_HUGE_WORKER_STACK "huge-worker-stack"
- OPT_HUGE_WORKER_STACK_NUM,
-
- OPT_LONG_MAX_NUM
-};
-
int eal_parse_log_options(void);
int eal_parse_args(void);
int eal_option_device_parse(void);
int eal_adjust_config(struct internal_config *internal_cfg);
int eal_cleanup_config(struct internal_config *internal_cfg);
-int eal_check_common_options(struct internal_config *internal_cfg);
enum rte_proc_type_t eal_proc_type_detect(void);
int eal_plugins_init(void);
int eal_save_args(int argc, char **argv);
diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c
index 210d461497..babd36bf37 100644
--- a/lib/eal/linux/eal.c
+++ b/lib/eal/linux/eal.c
@@ -329,9 +329,8 @@ rte_eal_config_reattach(void)
if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
if (mem_config != MAP_FAILED) {
/* errno is stale, don't use */
- EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p]"
- " - please use '--" OPT_BASE_VIRTADDR
- "' option", rte_mem_cfg_addr, mem_config);
+ EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
+ rte_mem_cfg_addr, mem_config);
munmap(mem_config, sizeof(struct rte_mem_config));
return -1;
}
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index e433c1afee..a366083822 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -1967,7 +1967,7 @@ rte_eal_memseg_init(void)
if (!internal_conf->legacy_mem && rte_socket_count() > 1) {
EAL_LOG(WARNING, "DPDK is running on a NUMA system, but is compiled without NUMA support.");
EAL_LOG(WARNING, "This will have adverse consequences for performance and usability.");
- EAL_LOG(WARNING, "Please use --"OPT_LEGACY_MEM" option, or recompile with NUMA support.");
+ EAL_LOG(WARNING, "Please use --legacy-mem option, or recompile with NUMA support.");
}
#endif
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v6 9/9] eal: simplify handling of conflicting cmdline options
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
` (7 preceding siblings ...)
2025-07-22 14:03 ` [PATCH v6 8/9] eal: combine parameter validation checks Bruce Richardson
@ 2025-07-22 14:03 ` Bruce Richardson
8 siblings, 0 replies; 67+ messages in thread
From: Bruce Richardson @ 2025-07-22 14:03 UTC (permalink / raw)
To: dev; +Cc: david.marchand, Bruce Richardson, Tyler Retzlaff
Use a utility function and macro to simplify the code for checking for
conflicting cmdline options. The checking can also be done at the
initial argument collating stage, shortening the argument
processing function which is very much on the long side.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/eal/common/eal_common_options.c | 119 +++++++++++-----------------
1 file changed, 47 insertions(+), 72 deletions(-)
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 486e2ad854..c568e59ef3 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -178,6 +178,29 @@ struct rte_argparse eal_argparse = {
}
};
+static inline bool
+conflicting_options(uintptr_t opt1, uintptr_t opt2, const char *opt1_name, const char *opt2_name)
+{
+ char name1[64]; /* should be the max length of any argument */
+ char name2[64];
+
+ strlcpy(name1, opt1_name, sizeof(name1));
+ strlcpy(name2, opt2_name, sizeof(name2));
+ for (int i = 0; name1[i] != '\0'; i++)
+ if (name1[i] == '_')
+ name1[i] = '-';
+ for (int i = 0; name2[i] != '\0'; i++)
+ if (name2[i] == '_')
+ name2[i] = '-';
+ if (opt1 && opt2) {
+ EAL_LOG(ERR, "Options '%s' and '%s' can't be used at the same time", name1, name2);
+ return true;
+ }
+ return false; /* no conflicts */
+}
+#define CONFLICTING_OPTIONS(args, opt1, opt2) \
+ conflicting_options((uintptr_t)(args.opt1), (uintptr_t)(args.opt2), #opt1, #opt2)
+
/* function to call into argparse library to parse the passed argc/argv parameters
* to the eal_init_args structure.
*/
@@ -200,6 +223,30 @@ eal_collate_args(int argc, char **argv)
if (retval < 0)
return retval;
+ /* check for conflicting options */
+ /* both -a and -b cannot be used together (one list must be empty at least) */
+ if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
+ EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
+ return -1;
+ }
+
+ /* for non-list args, we can just check for zero/null values using macro */
+ if (CONFLICTING_OPTIONS(args, coremask, lcores) ||
+ CONFLICTING_OPTIONS(args, service_coremask, service_corelist) ||
+ CONFLICTING_OPTIONS(args, no_telemetry, telemetry) ||
+ CONFLICTING_OPTIONS(args, memory_size, numa_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, numa_mem) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_worker_stack) ||
+ CONFLICTING_OPTIONS(args, numa_limit, legacy_mem) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, in_memory) ||
+ CONFLICTING_OPTIONS(args, legacy_mem, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, match_allocations) ||
+ CONFLICTING_OPTIONS(args, no_huge, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, single_file_segments, huge_unlink) ||
+ CONFLICTING_OPTIONS(args, no_huge, single_file_segments) ||
+ CONFLICTING_OPTIONS(args, in_memory, huge_unlink))
+ return -1;
+
argv[retval - 1] = argv[0];
return retval - 1;
}
@@ -1780,78 +1827,6 @@ eal_parse_args(void)
struct rte_config *rte_cfg = rte_eal_get_configuration();
struct arg_list_elem *arg;
- /* check for conflicting options */
- /* both -a and -b cannot be used together (one list must be empty at least) */
- if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
- EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
- return -1;
- }
- /* both -l and -c cannot be used at the same time */
- if (args.coremask != NULL && args.lcores != NULL) {
- EAL_LOG(ERR, "Options coremask (-c) and core list (-l) can't be used at the same time");
- return -1;
- }
- /* both -s and -S cannot be used at the same time */
- if (args.service_coremask != NULL && args.service_corelist != NULL) {
- EAL_LOG(ERR, "Options service coremask (-s) and service core list (-S) can't be used at the same time");
- return -1;
- }
- /* can't have both telemetry and no-telemetry */
- if (args.no_telemetry && args.telemetry) {
- EAL_LOG(ERR, "Options telemetry and no-telemetry can't be used at the same time");
- return -1;
- }
- /* can't have both -m and --socket-mem */
- if (args.memory_size != NULL && args.numa_mem != NULL) {
- EAL_LOG(ERR, "Options -m and --numa-mem can't be used at the same time");
- return -1;
- }
- /* can't use both no-huge and socket-mem */
- if (args.no_huge && args.numa_mem) {
- EAL_LOG(ERR, "Options --no-huge and --numa-mem can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-worker-stack */
- if (args.huge_worker_stack != NULL && args.no_huge) {
- EAL_LOG(ERR, "Options --no-huge and --huge-worker-stack can't be used at the same time");
- return -1;
- }
- /* can't use socket-limit and legacy-mem */
- if (args.numa_limit != NULL && args.legacy_mem) {
- EAL_LOG(ERR, "Options --numa-limit and --legacy-mem can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and in-memory */
- if (args.legacy_mem && args.in_memory) {
- EAL_LOG(ERR, "Options --legacy-mem and --in-memory can't be used at the same time");
- return -1;
- }
- /* can't use legacy-mem and match-allocations */
- if (args.legacy_mem && args.match_allocations) {
- EAL_LOG(ERR, "Options --legacy-mem and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and match-allocations */
- if (args.no_huge && args.match_allocations) {
- EAL_LOG(ERR, "Options --no-huge and --match-allocations can't be used at the same time");
- return -1;
- }
- /* can't use no-huge and huge-unlink */
- if (args.no_huge && args.huge_unlink) {
- EAL_LOG(ERR, "Options --no-huge and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use single-file-segments and huge-unlink */
- if (args.single_file_segments && args.huge_unlink) {
- EAL_LOG(ERR, "Options --single-file-segments and --huge-unlink can't be used at the same time");
- return -1;
- }
- /* can't use in-memory and huge-unlink */
- if (args.in_memory && args.huge_unlink) {
- EAL_LOG(ERR, "Options --in-memory and --huge-unlink can't be used at the same time");
- return -1;
- }
-
/* print version before anything else */
/* since message is explicitly requested by user, we write message
* at highest log level so it can always be seen even if info or
--
2.48.1
^ permalink raw reply [flat|nested] 67+ messages in thread
end of thread, other threads:[~2025-07-22 14:05 UTC | newest]
Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-20 16:40 [RFC PATCH 0/7] rework EAL argument parsing in DPDK Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 1/7] eal: add long options for each short option Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 2/7] argparse: add support for string and boolean args Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 3/7] argparse: make argparse EAL-args compatible Bruce Richardson
2025-05-22 10:44 ` Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 4/7] eal: define the EAL parameters in argparse format Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 5/7] eal: gather EAL args before processing Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 6/7] eal: combine parameter validation checks Bruce Richardson
2025-05-20 16:40 ` [RFC PATCH 7/7] eal: simplify handling of conflicting cmdline options Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 1/5] eal: add long options for each short option Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 2/5] eal: define the EAL parameters in argparse format Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 3/5] eal: gather EAL args before processing Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 4/5] eal: combine parameter validation checks Bruce Richardson
2025-07-08 17:20 ` [RFC PATCH v2 5/5] eal: simplify handling of conflicting cmdline options Bruce Richardson
2025-07-08 18:41 ` [RFC PATCH v2 0/5] rework EAL argument parsing in DPDK Stephen Hemminger
2025-07-09 7:50 ` Bruce Richardson
2025-07-09 12:30 ` David Marchand
2025-07-09 12:54 ` Bruce Richardson
2025-07-17 10:41 ` David Marchand
2025-07-17 10:54 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 1/9] build: add define for the OS environment name Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 2/9] argparse: export function to print help text for object Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 3/9] argparse: allow user-override of help printing Bruce Richardson
2025-07-21 8:43 ` David Marchand
2025-07-21 9:00 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 4/9] eal: add long options for each short option Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
2025-07-21 8:41 ` David Marchand
2025-07-21 9:05 ` Bruce Richardson
2025-07-21 12:53 ` Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 6/9] eal: gather EAL args before processing Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 8/9] eal: combine parameter validation checks Bruce Richardson
2025-07-18 14:33 ` [PATCH v3 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
2025-07-18 14:41 ` [PATCH v3 0/9] rework EAL argument parsing Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 " Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 1/9] build: add define for the OS environment name Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 2/9] argparse: export function to print help text for object Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 3/9] argparse: allow user-override of help printing Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 4/9] eal: add long options for each short option Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 6/9] eal: gather EAL args before processing Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 8/9] eal: combine parameter validation checks Bruce Richardson
2025-07-21 15:08 ` [PATCH v4 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 0/9] rework EAL argument parsing Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 1/9] build: add define for the OS environment name Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 2/9] argparse: export function to print help text for object Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 3/9] argparse: allow user-override of help printing Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 4/9] eal: add long options for each short option Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 6/9] eal: gather EAL args before processing Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 8/9] eal: combine parameter validation checks Bruce Richardson
2025-07-21 15:16 ` [PATCH v5 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 0/9] rework EAL argument parsing Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 1/9] build: add define for the OS environment name Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 2/9] argparse: export function to print help text for object Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 3/9] argparse: allow user-override of help printing Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 4/9] eal: add long options for each short option Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 5/9] eal: define the EAL parameters in argparse format Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 6/9] eal: gather EAL args before processing Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 7/9] eal: ensure proper cleanup on EAL init failure Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 8/9] eal: combine parameter validation checks Bruce Richardson
2025-07-22 14:03 ` [PATCH v6 9/9] eal: simplify handling of conflicting cmdline options Bruce Richardson
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).