@@ -222,6 +222,7 @@ The public API headers are grouped by topics:
[key/value args](@ref rte_kvargs.h),
[string](@ref rte_string_fns.h),
[thread](@ref rte_thread.h)
+ [cmdline args management](@ref rte_args.h),
- **debug**:
[jobstats](@ref rte_jobstats.h),
@@ -28,6 +28,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \
@TOPDIR@/lib/eal/include \
@TOPDIR@/lib/eal/include/generic \
@TOPDIR@/lib/acl \
+ @TOPDIR@/lib/args \
@TOPDIR@/lib/bbdev \
@TOPDIR@/lib/bitratestats \
@TOPDIR@/lib/bpf \
new file mode 100644
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+
+#include <stdint.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <rte_eal.h>
+#include <rte_errno.h>
+#include <rte_common.h>
+#include <rte_bitops.h>
+#include "rte_args.h"
+
+struct rte_args {
+ int array_sz;
+ int arg_count;
+ char **args;
+};
+
+#define DEFAULT_SIZE_HINT 8
+
+struct rte_args *
+rte_args_alloc(uint32_t size_hint)
+{
+ struct rte_args *a;
+
+ a = malloc(sizeof(*a));
+ if (a == NULL)
+ return NULL;
+
+ if (size_hint == 0)
+ size_hint = DEFAULT_SIZE_HINT;
+ size_hint = rte_align32pow2(size_hint);
+ a->args = calloc(size_hint, sizeof(a->args[0]));
+ if (a->args == NULL) {
+ free(a);
+ return NULL;
+ }
+
+ memset(a->args, 0, sizeof(a->args[0]) * size_hint);
+ a->arg_count = 0;
+ a->array_sz = size_hint;
+ return a;
+}
+
+struct rte_args *
+rte_args_create(int argc, char **argv)
+{
+ struct rte_args *a;
+
+ if (argc <= 0 || argv == NULL)
+ return NULL;
+
+ a = rte_args_alloc(argc + DEFAULT_SIZE_HINT);
+ if (a == NULL)
+ return NULL;
+
+ if (rte_args_add_argv(a, argc, argv) != 0) {
+ rte_args_free(a);
+ return NULL;
+ }
+ return a;
+}
+
+
+int
+rte_args_add(struct rte_args *a, const char *arg)
+{
+ if (a == NULL)
+ return -1;
+
+ if (a->arg_count == a->array_sz - 1) { /* need null at end, so subtract 1 */
+ void *new_a = reallocarray(a->args, a->array_sz * 2, sizeof(a->args[0]));
+ if (new_a == NULL)
+ return -1;
+
+ a->args = new_a;
+ /* zero out only new portion of array */
+ memset(&a->args[a->array_sz], 0, a->array_sz * sizeof(a->args[0]));
+ a->array_sz *= 2;
+ }
+
+ a->args[a->arg_count] = strdup(arg);
+ if (a->args[a->arg_count] == NULL)
+ return -1;
+ a->arg_count++;
+ return 0;
+}
+
+int
+rte_args_add_list(struct rte_args *a, int n, ...)
+{
+ va_list ap;
+ va_start(ap, n);
+ while (n > 0) {
+ if (rte_args_add(a, va_arg(ap, char *)) != 0)
+ break;
+ n--;
+ }
+ va_end(ap);
+ return n; /* return the number failing, 0 if all ok */
+}
+
+int
+rte_args_add_argv(struct rte_args *a, int argc, char **argv)
+{
+ int i;
+
+ for (i = 0; i < argc; i++)
+ if (rte_args_add(a, argv[i]) < 0)
+ break;
+ return argc - i; /* return the number failing, 0 if all ok */
+}
+
+bool
+rte_args_has_arg(struct rte_args *a, const char *arg)
+{
+ int i;
+
+ if (a == NULL || arg == NULL)
+ return false;
+
+ for (i = 0; i < a->arg_count; i++) {
+ if (strcmp(a->args[i], arg) == 0)
+ return true;
+ }
+ return false;
+}
+
+char **
+rte_args_get_argv(struct rte_args *a, int *argc)
+{
+ if (a == NULL)
+ return NULL;
+
+ if (argc != NULL)
+ *argc = a->arg_count;
+ return a->args;
+}
+
+int
+rte_args_get_argc(struct rte_args *a)
+{
+ if (a == NULL)
+ return -1;
+
+ return a->arg_count;
+}
+
+void
+rte_args_free(struct rte_args *a)
+{
+ int i;
+
+ if (a == NULL)
+ return;
+
+ for (i = 0; i < a->arg_count; i++)
+ free(a->args[i]);
+ free(a->args);
+ free(a);
+}
+
+int
+rte_args_eal_init(struct rte_args *a)
+{
+ int argc;
+ char **argv;
+
+ /* rte_args_argv does the check for NULL for us */
+ argv = rte_args_get_argv(a, &argc);
+ if (argv == NULL || argc <= 0)
+ return -1;
+
+ return rte_eal_init(argc, argv);
+}
new file mode 100644
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2023 Intel Corporation
+
+sources = files('args.c')
+headers = files('rte_args.h')
new file mode 100644
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#ifndef RTE_EAL_ARGS_H
+#define RTE_EAL_ARGS_H
+
+/**
+ * @file
+ *
+ * Command-line argument manipulation functions
+ *
+ * Simple functions for manipulating sets of commandline arguments, and then
+ * initializing DPDK / EAL based on those.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+
+struct rte_args;
+
+/**
+ * Allocate an argument structure
+ *
+ * This functions reserves memory for an argument structure. On success the returned structure
+ * is guaranteed to hold at least size_hint arguments without being resized. It is a hint only -
+ * if more elements are added than that hinted, the rte_args structure will be dynamically resized
+ * as necessary (subject to memory being available to do so).
+ *
+ * @param size_hint
+ * The returned structure is guaranteed to hold at least this many arguments without resizing.
+ * If zero, a default non-zero size value will be used.
+ * @return
+ * An empty rte_args structure, NULL on failure
+ */
+__rte_experimental
+struct rte_args *
+rte_args_alloc(uint32_t size_hint);
+
+/**
+ * Create an argument structure containing the existing parameters
+ *
+ * This functions creates an rte_args structure and initializes it with "argc" values
+ * from the "argv" array.
+ *
+ * @param argc
+ * The number of elements in argv
+ * @param argv
+ * Array of arguments to add to the created rte_args structure
+ * @return
+ * An rte_args structure holding argc elements from argv. NULL on failure.
+ */
+__rte_experimental
+struct rte_args *
+rte_args_create(int argc, char **argv);
+
+/**
+ * Add a new argument to the rte_args structure
+ *
+ * Add the argument "arg" to the rte_args structure, resizing the structure as necessary.
+ * The arg parameter will be copied using strdup, so the original string may be freed or
+ * edited as necessary after the function returns.
+ *
+ * @param a
+ * The rte_arg structure to be modified
+ * @param arg
+ * The argument to be added
+ * @return
+ * 0 on success, -1 on failure
+ */
+__rte_experimental
+int
+rte_args_add(struct rte_args *a, const char *arg);
+
+/**
+ * Add a list of arguments to the rte_args structure
+ *
+ * Add "n" arguments, given as extra function parameters to the rte_args structure, resizing
+ * the structure as necessary.
+ * The argument parameters will be copied using strdup, so the original strings may be freed or
+ * edited as necessary after the function returns.
+ *
+ * @param a
+ * The rte_arg structure to be modified
+ * @param n
+ * The number of arguments to be added
+ * @return
+ * 0 on success.
+ * On failure, returns the number of elements NOT added.
+ */
+__rte_experimental
+int
+rte_args_add_list(struct rte_args *a, int n, ...);
+
+/**
+ * Add an array of arguments to the rte_args structure
+ *
+ * Add arguments from an existing argv array to the rte_args structure.
+ * The argument parameters will be copied using strdup, so the original strings/array may
+ * be freed or edited as necessary after the function returns.
+ *
+ * @param a
+ * The rte_arg structure to be modified
+ * @param argc
+ * The number of arguments to be added
+ * @param argv
+ * The array containing the pointers to the elements to be added
+ * @return
+ * 0 on success.
+ * On failure, returns the number of elements NOT added.
+ */
+__rte_experimental
+int
+rte_args_add_argv(struct rte_args *a, int argc, char **argv);
+
+/**
+ * Query if an args list contains a given argument parameter
+ *
+ * @param a
+ * The rte_arg structure to be modified
+ * @param arg
+ * The argument to look for in the structure
+ * @return
+ * True if parameters are valid and argument is found
+ * False otherwise
+ */
+__rte_experimental
+bool
+rte_args_has_arg(struct rte_args *a, const char *arg);
+
+/**
+ * Get the array of arguments from the rte_args structure
+ *
+ * Returns an array of arguments from the structure, suitable for passing to a function which
+ * takes (argc, argv) parameters. The argc value will be optionally returned in the final output
+ * parameter if a valid pointer is passed in.
+ *
+ * NOTE: The return value points to the internals of the rte_args structure, and so the
+ * structure should not be freed while the arguments are in use.
+ *
+ * @param a
+ * The rte_arg structure to be used
+ * @param argc
+ * Pointer to store the count (argc) of elements returned. Ignored if NULL
+ * @return
+ * Pointer to an array of arguments. NULL on failure.
+ */
+__rte_experimental
+char **
+rte_args_get_argv(struct rte_args *a, int *argc);
+
+/**
+ * Gets the number of arguments stored in an rte_args structure
+ *
+ * @param a
+ * The rte_arg structure to be used
+ * @return
+ * The number of arguments stored in the structure
+ */
+__rte_experimental
+int
+rte_args_get_argc(struct rte_args *a);
+
+/**
+ * Frees an rte_args structure
+ *
+ * @param a
+ * The rte_arg structure to be freed
+ */
+__rte_experimental
+void
+rte_args_free(struct rte_args *a);
+
+/**
+ * Initialize DPDK EAL using arguments from the rte_args structure
+ *
+ * This function calls rte_eal_init(), passing in to it as parameters the argc, and argv
+ * values got from the rte_args structure "a".
+ *
+ * @param a
+ * The rte_args structure to be used. Must have at least one argument in it.
+ * @return
+ * -1 on invalid parameter
+ * Otherwise, return value from rte_eal_init()
+ */
+__rte_experimental
+int
+rte_args_eal_init(struct rte_args *a);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* RTE_EAL_ARGS_H */
new file mode 100644
@@ -0,0 +1,19 @@
+DPDK_24 {
+ local: *;
+};
+
+EXPERIMENTAL {
+ global:
+
+ # added in 24.03
+ rte_args_add;
+ rte_args_add_argv;
+ rte_args_add_list;
+ rte_args_alloc;
+ rte_args_create;
+ rte_args_eal_init;
+ rte_args_free;
+ rte_args_get_argc;
+ rte_args_get_argv;
+ rte_args_has_arg;
+};
@@ -13,6 +13,7 @@ libraries = [
'kvargs', # eal depends on kvargs
'telemetry', # basic info querying
'eal', # everything depends on eal
+ 'args',
'ring',
'rcu', # rcu depends on ring
'mempool',
@@ -76,6 +77,7 @@ if is_ms_compiler
endif
optional_libs = [
+ 'args',
'bbdev',
'bitratestats',
'bpf',