[v8,01/12] app/graph: add application framework to read CLI

Message ID 20230929095814.692890-2-skori@marvell.com (mailing list archive)
State Changes Requested, archived
Delegated to: Thomas Monjalon
Headers
Series add CLI based graph application |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Sunil Kumar Kori Sept. 29, 2023, 9:58 a.m. UTC
  From: Sunil Kumar Kori <skori@marvell.com>

It adds base framework to read a given .cli file as a command line
parameter "-s".

Example:
 # ./dpdk-graph -c 0xff -- -s ./app/graph/examples/dummy.cli

Each .cli file will contain commands to configure different module like
mempool, ethdev, lookup tables, graph etc. Command parsing is backed by
commandline library.

Each module needs to expose its supported commands & corresponding
callback functions to commandline library to get them parsed.

Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
v7..v8:
 - Fix klocwork issues.

v6..v7:
 - Fix FreeBSD build error.
 - Make route and neigh runtime configuration too.

v5..v6:
 - Fix build errors.
 - Fix checkpatch errors.
 - Fix individual patch build errors.

v4..v5:
 - Fix application exit issue.
 - Enable graph packet capture feature.
 - Fix graph coremask synchronization with eal coremask.
 - Update user guide.

https://patches.dpdk.org/project/dpdk/patch/20230919160455.1678716-1-skori@marvell.com/

v3..v4:
 - Use commandline library to parse command tokens.
 - Split to multiple smaller patches.
 - Make neigh and route as dynamic database.
 - add ethdev and graph stats command via telnet.
 - Update user guide.

https://patches.dpdk.org/project/dpdk/patch/20230908104907.4060511-1-skori@marvell.com/

 MAINTAINERS                |   7 ++
 app/graph/cli.c            | 113 ++++++++++++++++++++++++++++++++
 app/graph/cli.h            |  32 ++++++++++
 app/graph/main.c           | 128 +++++++++++++++++++++++++++++++++++++
 app/graph/meson.build      |  15 +++++
 app/graph/module_api.h     |  16 +++++
 app/meson.build            |   1 +
 doc/guides/tools/graph.rst |  82 ++++++++++++++++++++++++
 doc/guides/tools/index.rst |   1 +
 9 files changed, 395 insertions(+)
 create mode 100644 app/graph/cli.c
 create mode 100644 app/graph/cli.h
 create mode 100644 app/graph/main.c
 create mode 100644 app/graph/meson.build
 create mode 100644 app/graph/module_api.h
 create mode 100644 doc/guides/tools/graph.rst
  

Comments

Jerin Jacob Oct. 16, 2023, 9 a.m. UTC | #1
Unaddressed
On Fri, Sep 29, 2023 at 3:28 PM <skori@marvell.com> wrote:
>
> From: Sunil Kumar Kori <skori@marvell.com>
>
> It adds base framework to read a given .cli file as a command line
> parameter "-s".
>
> Example:
>  # ./dpdk-graph -c 0xff -- -s ./app/graph/examples/dummy.cli
>
> Each .cli file will contain commands to configure different module like
> mempool, ethdev, lookup tables, graph etc. Command parsing is backed by
> commandline library.
>
> Each module needs to expose its supported commands & corresponding
> callback functions to commandline library to get them parsed.
>
> Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>

> +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;
> +       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 -EINVAL;
> +
> +       msg_in = malloc(msg_in_len_max + 1);
> +       msg_out = malloc(msg_out_len_max + 1);
> +       if ((msg_in == NULL) || (msg_out == NULL)) {

Use goto to avod dupliciting this section.

> +               free(msg_out);
> +               free(msg_in);
> +               return -ENOMEM;
> +       }
> +
> +       /* Open input file */
> +       f = fopen(file_name, "r");
> +       if (f == NULL) {
> +               free(msg_out);
> +               free(msg_in);
> +               return -EIO;
> +       }
> +
> +       /* 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);

See above:

> +       free(msg_out);
> +       free(msg_in);
> +       return 0;
> +}
>
new file mode 100644
> index 0000000000..08d0a48cd9
> --- /dev/null
> +++ b/app/graph/meson.build
> @@ -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')

Is this required?

> +if not build
> +    subdir_done()
> +endif
> +
> +deps += ['bus_pci', 'graph', 'eal', 'lpm', 'ethdev', 'node', 'cmdline']

Check bus_pci really required?

> +sources = files(
> +        'cli.c',
> +        'main.c',
> +)
> diff --git a/app/graph/module_api.h b/app/graph/module_api.h
> new file mode 100644
> index 0000000000..372aeae7e3
> --- /dev/null
> +++ b/app/graph/module_api.h
> @@ -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>

Have a new line here.

> +#include "cli.h"
> +/*
> + * Externs
> + */
> new file mode 100644
> index 0000000000..271a85896d
> --- /dev/null
> +++ b/doc/guides/tools/graph.rst
> @@ -0,0 +1,82 @@
> +..  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.

Could you add some detailed text to describe the fact that, due to
modular nature
this app framework can be used by other graph based application OR SO.

> +
> +Supported Use cases
> +-------------------
> + *

This * can be removed in this patch. Add it when l3fwd adds it.


> +
> +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

Is it possible to make it as more vertical placement ? More horizontal
placement is not PDF friendly.
  
Sunil Kumar Kori Oct. 17, 2023, 6:19 a.m. UTC | #2
Unaddressed
> -----Original Message-----
> From: Jerin Jacob <jerinjacobk@gmail.com>
> Sent: Monday, October 16, 2023 2:31 PM
> To: Sunil Kumar Kori <skori@marvell.com>
> Cc: Thomas Monjalon <thomas@monjalon.net>; Rakesh Kudurumalla
> <rkudurumalla@marvell.com>; dev@dpdk.org
> Subject: [EXT] Re: [PATCH v8 01/12] app/graph: add application framework
> to read CLI
> 
> External Email
> 
> ----------------------------------------------------------------------
> On Fri, Sep 29, 2023 at 3:28 PM <skori@marvell.com> wrote:
> >
> > From: Sunil Kumar Kori <skori@marvell.com>
> >
> > It adds base framework to read a given .cli file as a command line
> > parameter "-s".
> >
> > Example:
> >  # ./dpdk-graph -c 0xff -- -s ./app/graph/examples/dummy.cli
> >
> > Each .cli file will contain commands to configure different module
> > like mempool, ethdev, lookup tables, graph etc. Command parsing is
> > backed by commandline library.
> >
> > Each module needs to expose its supported commands & corresponding
> > callback functions to commandline library to get them parsed.
> >
> > Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
> > Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> 
> > +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;
> > +       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 -EINVAL;
> > +
> > +       msg_in = malloc(msg_in_len_max + 1);
> > +       msg_out = malloc(msg_out_len_max + 1);
> > +       if ((msg_in == NULL) || (msg_out == NULL)) {
> 
> Use goto to avod dupliciting this section.
> 
Will fix in next version.

> > +               free(msg_out);
> > +               free(msg_in);
> > +               return -ENOMEM;
> > +       }
> > +
> > +       /* Open input file */
> > +       f = fopen(file_name, "r");
> > +       if (f == NULL) {
> > +               free(msg_out);
> > +               free(msg_in);
> > +               return -EIO;
> > +       }
> > +
> > +       /* 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);
> 
> See above:
> 
Will fix in next version.

> > +       free(msg_out);
> > +       free(msg_in);
> > +       return 0;
> > +}
> >
> new file mode 100644
Will fix in next version.

> > index 0000000000..08d0a48cd9
> > --- /dev/null
> > +++ b/app/graph/meson.build
> > @@ -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')
> 
> Is this required?
> 
Yes. It is needed to compiled  the application for FreeBSD.

> > +if not build
> > +    subdir_done()
> > +endif
> > +
> > +deps += ['bus_pci', 'graph', 'eal', 'lpm', 'ethdev', 'node',
> > +'cmdline']
> 
> Check bus_pci really required?
> 
Will check.

> > +sources = files(
> > +        'cli.c',
> > +        'main.c',
> > +)
> > diff --git a/app/graph/module_api.h b/app/graph/module_api.h new file
> > mode 100644 index 0000000000..372aeae7e3
> > --- /dev/null
> > +++ b/app/graph/module_api.h
> > @@ -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>
> 
> Have a new line here.
> 
Will fix in next version.

> > +#include "cli.h"
> > +/*
> > + * Externs
> > + */
> > new file mode 100644
> > index 0000000000..271a85896d
> > --- /dev/null
> > +++ b/doc/guides/tools/graph.rst
> > @@ -0,0 +1,82 @@
> > +..  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.
> 
> Could you add some detailed text to describe the fact that, due to modular
> nature this app framework can be used by other graph based application OR
> SO.
> 
> > +
> > +Supported Use cases
> > +-------------------
> > + *
> 
> This * can be removed in this patch. Add it when l3fwd adds it.
> 
Will fix in next version.

> 
> > +
> > +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
> 
> Is it possible to make it as more vertical placement ? More horizontal
> placement is not PDF friendly.
Will check it.
  

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 00f5a5f9e6..7998be98f1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1811,6 +1811,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
 --------------------------
diff --git a/app/graph/cli.c b/app/graph/cli.c
new file mode 100644
index 0000000000..473fa1635a
--- /dev/null
+++ b/app/graph/cli.c
@@ -0,0 +1,113 @@ 
+/* 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;
+	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 -EINVAL;
+
+	msg_in = malloc(msg_in_len_max + 1);
+	msg_out = malloc(msg_out_len_max + 1);
+	if ((msg_in == NULL) || (msg_out == NULL)) {
+		free(msg_out);
+		free(msg_in);
+		return -ENOMEM;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		free(msg_out);
+		free(msg_in);
+		return -EIO;
+	}
+
+	/* 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);
+	free(msg_out);
+	free(msg_in);
+	return 0;
+}
diff --git a/app/graph/cli.h b/app/graph/cli.h
new file mode 100644
index 0000000000..652f948352
--- /dev/null
+++ b/app/graph/cli.h
@@ -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
diff --git a/app/graph/main.c b/app/graph/main.c
new file mode 100644
index 0000000000..734a94444e
--- /dev/null
+++ b/app/graph/main.c
@@ -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;
+}
diff --git a/app/graph/meson.build b/app/graph/meson.build
new file mode 100644
index 0000000000..08d0a48cd9
--- /dev/null
+++ b/app/graph/meson.build
@@ -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 += ['bus_pci', 'graph', 'eal', 'lpm', 'ethdev', 'node', 'cmdline']
+sources = files(
+        'cli.c',
+        'main.c',
+)
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
new file mode 100644
index 0000000000..372aeae7e3
--- /dev/null
+++ b/app/graph/module_api.h
@@ -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
diff --git a/app/meson.build b/app/meson.build
index e4bf5c531c..728c936383 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -17,6 +17,7 @@  endif
 apps = [
         'dumpcap',
         'pdump',
+        'graph',
         'proc-info',
         'test-acl',
         'test-bbdev',
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
new file mode 100644
index 0000000000..271a85896d
--- /dev/null
+++ b/doc/guides/tools/graph.rst
@@ -0,0 +1,82 @@ 
+..  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.
+
+Supported Use cases
+-------------------
+ *
+
+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.
diff --git a/doc/guides/tools/index.rst b/doc/guides/tools/index.rst
index f2afb1fcc5..4f4dc8b518 100644
--- a/doc/guides/tools/index.rst
+++ b/doc/guides/tools/index.rst
@@ -23,4 +23,5 @@  DPDK Tools User Guides
     testeventdev
     testregex
     testmldev
+    graph
     dts