DPDK patches and discussions
 help / color / mirror / Atom feed
* [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
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ 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] 8+ 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
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ 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] 8+ 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
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ 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] 8+ 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-20 16:40 ` [RFC PATCH 4/7] eal: define the EAL parameters in argparse format Bruce Richardson
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ 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] 8+ 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
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ 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] 8+ 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
  2025-05-20 16:40 ` [RFC PATCH 7/7] eal: simplify handling of conflicting cmdline options Bruce Richardson
  6 siblings, 0 replies; 8+ 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] 8+ 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
  6 siblings, 0 replies; 8+ 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] 8+ 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
  6 siblings, 0 replies; 8+ 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] 8+ messages in thread

end of thread, other threads:[~2025-05-20 16:41 UTC | newest]

Thread overview: 8+ 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-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

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).