@@ -1825,6 +1825,13 @@ F: dts/
F: devtools/dts-check-format.sh
F: doc/guides/tools/dts.rst
+Graph application
+M: Sunil Kumar Kori <skori@marvell.com>
+M: Rakesh Kudurumalla <rkudurumalla@marvell.com>
+F: app/graph/
+F: doc/guides/tools/graph.rst
+F: doc/guides/tools/img/graph-usecase-l3fwd.svg
+
Other Example Applications
--------------------------
new file mode 100644
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_socket.h>
+#include <rte_common.h>
+
+#include "module_api.h"
+
+#define CMD_MAX_TOKENS 256
+#define MAX_LINE_SIZE 2048
+
+cmdline_parse_ctx_t modules_ctx[] = {
+ NULL,
+};
+
+static struct cmdline *cl;
+
+static int
+is_comment(char *in)
+{
+ if ((strlen(in) && index("!#%;", in[0])) ||
+ (strncmp(in, "//", 2) == 0) ||
+ (strncmp(in, "--", 2) == 0))
+ return 1;
+
+ return 0;
+}
+
+void
+cli_init(void)
+{
+ cl = cmdline_stdin_new(modules_ctx, "");
+}
+
+void
+cli_exit(void)
+{
+ cmdline_stdin_exit(cl);
+}
+
+void
+cli_process(char *in, char *out, size_t out_size, __rte_unused void *obj)
+{
+ int rc;
+
+ if (is_comment(in))
+ return;
+
+ rc = cmdline_parse(cl, in);
+ if (rc == CMDLINE_PARSE_AMBIGUOUS)
+ snprintf(out, out_size, MSG_CMD_FAIL, "Ambiguous command");
+ else if (rc == CMDLINE_PARSE_NOMATCH)
+ snprintf(out, out_size, MSG_CMD_FAIL, "Command mismatch");
+ else if (rc == CMDLINE_PARSE_BAD_ARGS)
+ snprintf(out, out_size, MSG_CMD_FAIL, "Bad arguments");
+
+ return;
+
+}
+
+int
+cli_script_process(const char *file_name, size_t msg_in_len_max, size_t msg_out_len_max, void *obj)
+{
+ char *msg_in = NULL, *msg_out = NULL;
+ int rc = -EINVAL;
+ FILE *f = NULL;
+
+ /* Check input arguments */
+ if ((file_name == NULL) || (strlen(file_name) == 0) || (msg_in_len_max == 0) ||
+ (msg_out_len_max == 0))
+ return rc;
+
+ msg_in = malloc(msg_in_len_max + 1);
+ msg_out = malloc(msg_out_len_max + 1);
+ if ((msg_in == NULL) || (msg_out == NULL)) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ /* Open input file */
+ f = fopen(file_name, "r");
+ if (f == NULL) {
+ rc = -EIO;
+ goto exit;
+ }
+
+ /* Read file */
+ while (fgets(msg_in, msg_in_len_max, f) != NULL) {
+ msg_out[0] = 0;
+
+ cli_process(msg_in, msg_out, msg_out_len_max, obj);
+
+ if (strlen(msg_out))
+ printf("%s", msg_out);
+ }
+
+ /* Close file */
+ fclose(f);
+ rc = 0;
+
+exit:
+ free(msg_out);
+ free(msg_in);
+ return rc;
+}
new file mode 100644
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_CLI_H
+#define APP_GRAPH_CLI_H
+
+/* Macros */
+#define MSG_OUT_OF_MEMORY "Not enough memory.\n"
+#define MSG_CMD_UNKNOWN "Unknown command \"%s\".\n"
+#define MSG_CMD_UNIMPLEM "Command \"%s\" not implemented.\n"
+#define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n"
+#define MSG_ARG_TOO_MANY "Too many arguments for command \"%s\".\n"
+#define MSG_ARG_MISMATCH "Wrong number of arguments for command \"%s\".\n"
+#define MSG_ARG_NOT_FOUND "Argument \"%s\" not found.\n"
+#define MSG_ARG_INVALID "Invalid value for argument \"%s\".\n"
+#define MSG_FILE_ERR "Error in file \"%s\" at line %u.\n"
+#define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
+#define MSG_CMD_FAIL "Command \"%s\" failed.\n"
+
+#define APP_CLI_CMD_NAME_SIZE 64
+
+void cli_init(void);
+
+void cli_exit(void);
+
+void cli_process(char *in, char *out, size_t out_size, void *arg);
+
+int cli_script_process(const char *file_name, size_t msg_in_len_max, size_t msg_out_len_max,
+ void *arg);
+
+#endif
new file mode 100644
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include <rte_eal.h>
+#include <rte_launch.h>
+
+#include "module_api.h"
+
+volatile bool force_quit;
+
+static const char usage[] = "%s EAL_ARGS -- -s SCRIPT "
+ "[--help]\n";
+
+static struct app_params {
+ char *script_name;
+} app = {
+ .script_name = NULL,
+};
+
+static void
+signal_handler(int signum)
+{
+ if (signum == SIGINT || signum == SIGTERM) {
+ printf("\n\nSignal %d received, preparing to exit...\n", signum);
+ force_quit = true;
+ }
+}
+
+static int
+app_args_parse(int argc, char **argv)
+{
+ struct option lgopts[] = {
+ {"help", 0, 0, 'H'},
+ };
+ int s_present, n_args, i;
+ char *app_name = argv[0];
+ int opt, option_index;
+
+ /* Skip EAL input args */
+ n_args = argc;
+ for (i = 0; i < n_args; i++)
+ if (strcmp(argv[i], "--") == 0) {
+ argc -= i;
+ argv += i;
+ break;
+ }
+
+ if (i == n_args)
+ return 0;
+
+ /* Parse args */
+ s_present = 0;
+
+ while ((opt = getopt_long(argc, argv, "s:", lgopts, &option_index)) != EOF) {
+ switch (opt) {
+ case 's':
+ if (s_present) {
+ printf("Error: Multiple -s arguments\n");
+ return -1;
+ }
+ s_present = 1;
+
+ if (!strlen(optarg)) {
+ printf("Error: Argument for -s not provided\n");
+ return -1;
+ }
+
+ app.script_name = strdup(optarg);
+ if (app.script_name == NULL) {
+ printf("Error: Not enough memory\n");
+ return -1;
+ }
+ break;
+
+ case 'H':
+ default:
+ printf(usage, app_name);
+ return -1;
+ }
+ }
+ optind = 1; /* reset getopt lib */
+
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int rc;
+
+ /* Parse application arguments */
+ rc = app_args_parse(argc, argv);
+ if (rc < 0)
+ return rc;
+
+ /* EAL */
+ rc = rte_eal_init(argc, argv);
+ if (rc < 0) {
+ printf("Error: EAL initialization failed (%d)\n", rc);
+ return rc;
+ };
+
+ force_quit = false;
+ signal(SIGINT, signal_handler);
+ signal(SIGTERM, signal_handler);
+
+ cli_init();
+
+ /* Script */
+ if (app.script_name) {
+ cli_script_process(app.script_name, 0,
+ 0, NULL);
+ }
+
+ cli_exit();
+ rte_eal_cleanup();
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2023 Marvell.
+
+# override default name to drop the hyphen
+name = 'graph'
+build = cc.has_header('sys/epoll.h')
+if not build
+ subdir_done()
+endif
+
+deps += ['graph', 'eal', 'lpm', 'ethdev', 'node', 'cmdline']
+sources = files(
+ 'cli.c',
+ 'main.c',
+)
new file mode 100644
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_MODULE_API_H
+#define APP_GRAPH_MODULE_API_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "cli.h"
+/*
+ * Externs
+ */
+extern volatile bool force_quit;
+
+#endif
@@ -17,6 +17,7 @@ endif
apps = [
'dumpcap',
'pdump',
+ 'graph',
'proc-info',
'test-acl',
'test-bbdev',
@@ -244,6 +244,13 @@ New Features
Added dispatcher library which purpose is to help decouple different
parts (modules) of an eventdev-based application.
+* **Added CLI based graph application.**
+
+ Added CLI based graph application which exercises on different usecases.
+ Application provides a framework so that each usecase can be added via CLI
+ file. Each CLI will further be translated into a graph representing user's
+ required usecase.
+
Removed Items
-------------
new file mode 100644
@@ -0,0 +1,80 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+ Copyright(c) 2023 Marvell.
+
+dpdk-graph Application
+======================
+
+The ``dpdk-graph`` tool is a Data Plane Development Kit (DPDK)
+application that allows exercising various graph use cases.
+This application has a generic framework to add new graph based use cases to
+verify functionality. Each use case is defined as a ``<usecase>.cli`` file.
+Based on the input file, application creates a graph to cater the use case.
+
+Also this application framework can be used by other graph based applications.
+
+Running the Application
+-----------------------
+
+The application has a number of command line options which can be provided in
+following syntax
+
+.. code-block:: console
+
+ dpdk-graph [EAL Options] -- [application options]
+
+EAL Options
+~~~~~~~~~~~
+
+Following are the EAL command-line options that can be used in conjunction
+with the ``dpdk-graph`` application.
+See the DPDK Getting Started Guides for more information on these options.
+
+* ``-c <COREMASK>`` or ``-l <CORELIST>``
+
+ Set the hexadecimal bit mask of the cores to run on. The CORELIST is a
+ list of cores to be used.
+
+Application Options
+~~~~~~~~~~~~~~~~~~~
+
+Following are the application command-line options:
+
+* ``-s``
+
+ Script name with absolute path which specifies the use case. It is
+ a mandatory parameter which will be used to create desired graph
+ for a given use case.
+
+* ``--help``
+
+ Dumps application usage
+
+Supported CLI commands
+----------------------
+
+This section provides details on commands which can be used in ``<usecase>.cli``
+file to express the requested use case configuration.
+
+.. list-table:: Exposed CLIs
+ :widths: 40 40 10 10
+ :header-rows: 1
+ :class: longtable
+
+ * - Command
+ - Description
+ - Dynamic
+ - Optional
+ * - Dummy command
+ - Dummy command description
+ - No
+ - No
+
+Runtime configuration
+---------------------
+
+
+Created graph for use case
+--------------------------
+
+On the successful execution of ``<usecase>.cli`` file, corresponding graph will be created.
+This section mentions the created graph for each use case.
@@ -23,4 +23,5 @@ DPDK Tools User Guides
testeventdev
testregex
testmldev
+ graph
dts