get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/132200/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 132200,
    "url": "http://patches.dpdk.org/api/patches/132200/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20230929095814.692890-11-skori@marvell.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20230929095814.692890-11-skori@marvell.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230929095814.692890-11-skori@marvell.com",
    "date": "2023-09-29T09:58:12",
    "name": "[v8,10/12] app/graph: add graph command line interfaces",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": true,
    "hash": "859580d3be775fab42c1110ec1b40796e08ad609",
    "submitter": {
        "id": 1318,
        "url": "http://patches.dpdk.org/api/people/1318/?format=api",
        "name": "Sunil Kumar Kori",
        "email": "skori@marvell.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20230929095814.692890-11-skori@marvell.com/mbox/",
    "series": [
        {
            "id": 29693,
            "url": "http://patches.dpdk.org/api/series/29693/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=29693",
            "date": "2023-09-29T09:58:02",
            "name": "add CLI based graph application",
            "version": 8,
            "mbox": "http://patches.dpdk.org/series/29693/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/132200/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/132200/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 9C92442671;\n\tFri, 29 Sep 2023 11:59:36 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id D972D40ED8;\n\tFri, 29 Sep 2023 11:58:48 +0200 (CEST)",
            "from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com\n [67.231.148.174])\n by mails.dpdk.org (Postfix) with ESMTP id A91A440E4A\n for <dev@dpdk.org>; Fri, 29 Sep 2023 11:58:41 +0200 (CEST)",
            "from pps.filterd (m0045849.ppops.net [127.0.0.1])\n by mx0a-0016f401.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id\n 38T273WT031723 for <dev@dpdk.org>; Fri, 29 Sep 2023 02:58:40 -0700",
            "from dc5-exch01.marvell.com ([199.233.59.181])\n by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 3td7y6vw0b-1\n (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT)\n for <dev@dpdk.org>; Fri, 29 Sep 2023 02:58:40 -0700",
            "from DC5-EXCH01.marvell.com (10.69.176.38) by DC5-EXCH01.marvell.com\n (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.48;\n Fri, 29 Sep 2023 02:58:38 -0700",
            "from maili.marvell.com (10.69.176.80) by DC5-EXCH01.marvell.com\n (10.69.176.38) with Microsoft SMTP Server id 15.0.1497.48 via Frontend\n Transport; Fri, 29 Sep 2023 02:58:38 -0700",
            "from localhost.localdomain (unknown [10.28.34.25])\n by maili.marvell.com (Postfix) with ESMTP id 3C6645B6923;\n Fri, 29 Sep 2023 02:58:36 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com;\n h=from : to : cc :\n subject : date : message-id : in-reply-to : references : mime-version :\n content-transfer-encoding : content-type; s=pfpt0220;\n bh=UIGinhZEPoCch9GdB26znBJX7uPWB7D31aMZW8xAS6c=;\n b=eCrFe8bSsnNotCPIn4PSkc8MvLwRd//5seSRbml39PuYeZ6EU0qp95Lm2nzqgC9NQryc\n 5Zh7sOrGMQU8BrNylEs2jea6si6/43tTbKW5X5aVweVnaDBahy+TcTCKMLLKQjHUzv6O\n hAGHZb33nh9epk/IWwWacx10VxBCc1d5HQiKBobmTJOzHSz+dTbJJLm2Fpw7CKuiVWXe\n PPZu21kUprPv8aBgiMwPTF/WhGppItakZyOta7mkD9HCu4P0jUefgcyZngDbJxyO13g6\n +kHsvb3J+Rvr6Dmj2k0bR9rHYpxzu/NrQyi5zVEVyOuoZ+u/F5bARWS0ZU3FmeSsgOHF Jw==",
        "From": "<skori@marvell.com>",
        "To": "Sunil Kumar Kori <skori@marvell.com>, Rakesh Kudurumalla\n <rkudurumalla@marvell.com>",
        "CC": "<dev@dpdk.org>",
        "Subject": "[PATCH v8 10/12] app/graph: add graph command line interfaces",
        "Date": "Fri, 29 Sep 2023 15:28:12 +0530",
        "Message-ID": "<20230929095814.692890-11-skori@marvell.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20230929095814.692890-1-skori@marvell.com>",
        "References": "<20230927115412.55018-13-skori@marvell.com>\n <20230929095814.692890-1-skori@marvell.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-Proofpoint-ORIG-GUID": "E95lz3_RUbUbkX1OaFpV10l1HNvD1LzF",
        "X-Proofpoint-GUID": "E95lz3_RUbUbkX1OaFpV10l1HNvD1LzF",
        "X-Proofpoint-Virus-Version": "vendor=baseguard\n engine=ICAP:2.0.267,Aquarius:18.0.980,Hydra:6.0.619,FMLib:17.11.176.26\n definitions=2023-09-29_07,2023-09-28_03,2023-05-22_02",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "From: Rakesh Kudurumalla <rkudurumalla@marvell.com>\n\nIt adds graph module to create a graph for a given use case like\nl3fwd.\n\nFollowing commands are exposed:\n - graph <usecases> [bsz <size>] [tmo <ns>] [coremask <bitmask>] \\\n\tmodel <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num> \\\n\tpcap_file <output_capture_file>\n - graph start\n - graph stats show\n - help graph\n\nSigned-off-by: Sunil Kumar Kori <skori@marvell.com>\nSigned-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>\n---\n app/graph/cli.c            |   4 +\n app/graph/ethdev_rx.c      |   2 +-\n app/graph/graph.c          | 550 +++++++++++++++++++++++++++++++++++++\n app/graph/graph.h          |  21 ++\n app/graph/graph_priv.h     |  70 +++++\n app/graph/ip4_route.c      |   5 +-\n app/graph/ip6_route.c      |   5 +-\n app/graph/meson.build      |   1 +\n app/graph/module_api.h     |   1 +\n app/graph/neigh.c          |  10 +-\n doc/guides/tools/graph.rst |  19 +-\n 11 files changed, 681 insertions(+), 7 deletions(-)\n create mode 100644 app/graph/graph.c\n create mode 100644 app/graph/graph.h\n create mode 100644 app/graph/graph_priv.h",
    "diff": "diff --git a/app/graph/cli.c b/app/graph/cli.c\nindex e947f61ee4..c43af5925c 100644\n--- a/app/graph/cli.c\n+++ b/app/graph/cli.c\n@@ -20,6 +20,10 @@\n #define MAX_LINE_SIZE 2048\n \n cmdline_parse_ctx_t modules_ctx[] = {\n+\t(cmdline_parse_inst_t *)&graph_config_cmd_ctx,\n+\t(cmdline_parse_inst_t *)&graph_start_cmd_ctx,\n+\t(cmdline_parse_inst_t *)&graph_stats_cmd_ctx,\n+\t(cmdline_parse_inst_t *)&graph_help_cmd_ctx,\n \t(cmdline_parse_inst_t *)&mempool_config_cmd_ctx,\n \t(cmdline_parse_inst_t *)&mempool_help_cmd_ctx,\n \t(cmdline_parse_inst_t *)&ethdev_show_cmd_ctx,\ndiff --git a/app/graph/ethdev_rx.c b/app/graph/ethdev_rx.c\nindex f2cb8cf9a5..03f8effcca 100644\n--- a/app/graph/ethdev_rx.c\n+++ b/app/graph/ethdev_rx.c\n@@ -69,7 +69,7 @@ ethdev_rx_map_add(char *name, uint32_t queue, uint32_t core)\n \tif (rc)\n \t\treturn -EINVAL;\n \n-\tcoremask = 0xff; /* FIXME: Read from graph configuration */\n+\tcoremask = graph_coremask_get();\n \n \tif (!(coremask & (1 << core)))\n \t\treturn -EINVAL;\ndiff --git a/app/graph/graph.c b/app/graph/graph.c\nnew file mode 100644\nindex 0000000000..b27abcf1f9\n--- /dev/null\n+++ b/app/graph/graph.c\n@@ -0,0 +1,550 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 Marvell.\n+ */\n+\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <string.h>\n+\n+#include <cmdline_parse.h>\n+#include <cmdline_parse_num.h>\n+#include <cmdline_parse_string.h>\n+#include <cmdline_socket.h>\n+#include <rte_ethdev.h>\n+#include <rte_graph_worker.h>\n+#include <rte_log.h>\n+\n+#include \"graph_priv.h\"\n+#include \"module_api.h\"\n+\n+#define RTE_LOGTYPE_APP_GRAPH RTE_LOGTYPE_USER1\n+\n+static const char\n+cmd_graph_help[] = \"graph <usecases> bsz <size> tmo <ns> coremask <bitmask> \"\n+\t\t   \"model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>\"\n+\t\t   \"pcap_file <output_capture_file>\";\n+\n+static const char * const supported_usecases[] = {\"l3fwd\"};\n+struct graph_config graph_config;\n+bool graph_started;\n+\n+/* Check the link rc of all ports in up to 9s, and print them finally */\n+static void\n+check_all_ports_link_status(uint32_t port_mask)\n+{\n+#define CHECK_INTERVAL 100 /* 100ms */\n+#define MAX_CHECK_TIME 90  /* 9s (90 * 100ms) in total */\n+\tchar link_rc_text[RTE_ETH_LINK_MAX_STR_LEN];\n+\tuint8_t count, all_ports_up, print_flag = 0;\n+\tstruct rte_eth_link link;\n+\tuint16_t portid;\n+\tint rc;\n+\n+\tprintf(\"\\nChecking link rc\");\n+\tfflush(stdout);\n+\tfor (count = 0; count <= MAX_CHECK_TIME; count++) {\n+\t\tif (force_quit)\n+\t\t\treturn;\n+\n+\t\tall_ports_up = 1;\n+\t\tRTE_ETH_FOREACH_DEV(portid)\n+\t\t{\n+\t\t\tif (force_quit)\n+\t\t\t\treturn;\n+\n+\t\t\tif ((port_mask & (1 << portid)) == 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\tmemset(&link, 0, sizeof(link));\n+\t\t\trc = rte_eth_link_get_nowait(portid, &link);\n+\t\t\tif (rc < 0) {\n+\t\t\t\tall_ports_up = 0;\n+\t\t\t\tif (print_flag == 1)\n+\t\t\t\t\tprintf(\"Port %u link get failed: %s\\n\",\n+\t\t\t\t\t       portid, rte_strerror(-rc));\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/* Print link rc if flag set */\n+\t\t\tif (print_flag == 1) {\n+\t\t\t\trte_eth_link_to_str(link_rc_text, sizeof(link_rc_text),\n+\t\t\t\t\t&link);\n+\t\t\t\tprintf(\"Port %d %s\\n\", portid, link_rc_text);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/* Clear all_ports_up flag if any link down */\n+\t\t\tif (link.link_status == RTE_ETH_LINK_DOWN) {\n+\t\t\t\tall_ports_up = 0;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* After finally printing all link rc, get out */\n+\t\tif (print_flag == 1)\n+\t\t\tbreak;\n+\n+\t\tif (all_ports_up == 0) {\n+\t\t\tprintf(\".\");\n+\t\t\tfflush(stdout);\n+\t\t\trte_delay_ms(CHECK_INTERVAL);\n+\t\t}\n+\n+\t\t/* Set the print_flag if all ports up or timeout */\n+\t\tif (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {\n+\t\t\tprint_flag = 1;\n+\t\t\tprintf(\"Done\\n\");\n+\t\t}\n+\t}\n+}\n+\n+static bool\n+parser_usecases_read(char *usecases)\n+{\n+\tbool valid = false;\n+\tuint32_t i, j = 0;\n+\tchar *token;\n+\n+\ttoken = strtok(usecases, \",\");\n+\twhile (token != NULL) {\n+\t\tfor (i = 0; i < RTE_DIM(supported_usecases); i++) {\n+\t\t\tif (strcmp(supported_usecases[i], token) == 0) {\n+\t\t\t\tgraph_config.usecases[j].enabled = true;\n+\t\t\t\tstrncpy(graph_config.usecases[j].name, token, 31);\n+\t\t\t\tvalid = true;\n+\t\t\t\tj++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\ttoken = strtok(NULL, \",\");\n+\t}\n+\n+\treturn valid;\n+}\n+\n+static uint64_t\n+graph_worker_count_get(void)\n+{\n+\tuint64_t nb_worker = 0;\n+\tuint64_t coremask;\n+\n+\tcoremask = graph_config.params.coremask;\n+\twhile (coremask) {\n+\t\tif (coremask & 0x1)\n+\t\t\tnb_worker++;\n+\n+\t\tcoremask = (coremask >> 1);\n+\t}\n+\n+\treturn nb_worker;\n+}\n+\n+static struct rte_node_ethdev_config *\n+graph_rxtx_node_config_get(uint32_t *num_conf, uint32_t *num_graphs)\n+{\n+\tuint32_t n_tx_queue, nb_conf = 0, lcore_id;\n+\tuint16_t queueid, portid, nb_graphs = 0;\n+\tuint8_t nb_rx_queue, queue;\n+\tstruct lcore_conf *qconf;\n+\n+\tn_tx_queue = graph_worker_count_get();\n+\tif (n_tx_queue > RTE_MAX_ETHPORTS)\n+\t\tn_tx_queue = RTE_MAX_ETHPORTS;\n+\n+\tRTE_ETH_FOREACH_DEV(portid) {\n+\t\t/* Skip ports that are not enabled */\n+\t\tif ((enabled_port_mask & (1 << portid)) == 0) {\n+\t\t\tprintf(\"\\nSkipping disabled port %d\\n\", portid);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tnb_rx_queue = ethdev_rx_num_rx_queues_get(portid);\n+\n+\t\t/* Setup ethdev node config */\n+\t\tethdev_conf[nb_conf].port_id = portid;\n+\t\tethdev_conf[nb_conf].num_rx_queues = nb_rx_queue;\n+\t\tethdev_conf[nb_conf].num_tx_queues = n_tx_queue;\n+\t\tethdev_conf[nb_conf].mp = ethdev_mempool_list_by_portid(portid);\n+\t\tethdev_conf[nb_conf].mp_count = 1; /* Check with pools */\n+\n+\t\tnb_conf++;\n+\t}\n+\n+\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\tif (rte_lcore_is_enabled(lcore_id) == 0)\n+\t\t\tcontinue;\n+\n+\t\tqconf = &lcore_conf[lcore_id];\n+\t\tprintf(\"\\nInitializing rx queues on lcore %u ... \", lcore_id);\n+\t\tfflush(stdout);\n+\n+\t\t/* Init RX queues */\n+\t\tfor (queue = 0; queue < qconf->n_rx_queue; ++queue) {\n+\t\t\tportid = qconf->rx_queue_list[queue].port_id;\n+\t\t\tqueueid = qconf->rx_queue_list[queue].queue_id;\n+\n+\t\t\t/* Add this queue node to its graph */\n+\t\t\tsnprintf(qconf->rx_queue_list[queue].node_name, RTE_NODE_NAMESIZE,\n+\t\t\t\t \"ethdev_rx-%u-%u\", portid, queueid);\n+\t\t}\n+\t\tif (qconf->n_rx_queue)\n+\t\t\tnb_graphs++;\n+\t}\n+\n+\tprintf(\"\\n\");\n+\n+\tethdev_start();\n+\tcheck_all_ports_link_status(enabled_port_mask);\n+\n+\t*num_conf = nb_conf;\n+\t*num_graphs = nb_graphs;\n+\treturn ethdev_conf;\n+}\n+\n+static void\n+graph_stats_print_to_file(void)\n+{\n+\tstruct rte_graph_cluster_stats_param s_param;\n+\tstruct rte_graph_cluster_stats *stats;\n+\tconst char *pattern = \"worker_*\";\n+\tFILE *fp = NULL;\n+\tsize_t sz, len;\n+\n+\t/* Prepare stats object */\n+\tfp = fopen(\"/tmp/graph_stats.txt\", \"w+\");\n+\tif (fp == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Errot in opening stats file\\n\");\n+\n+\tmemset(&s_param, 0, sizeof(s_param));\n+\ts_param.f = fp;\n+\ts_param.socket_id = SOCKET_ID_ANY;\n+\ts_param.graph_patterns = &pattern;\n+\ts_param.nb_graph_patterns = 1;\n+\n+\tstats = rte_graph_cluster_stats_create(&s_param);\n+\tif (stats == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Unable to create stats object\\n\");\n+\n+\t/* Clear screen and move to top left */\n+\trte_graph_cluster_stats_get(stats, 0);\n+\trte_delay_ms(1E3);\n+\n+\tfseek(fp, 0L, SEEK_END);\n+\tsz = ftell(fp);\n+\tfseek(fp, 0L, SEEK_SET);\n+\n+\tlen = strlen(conn->msg_out);\n+\tconn->msg_out += len;\n+\n+\tsz = fread(conn->msg_out, sizeof(char), sz, fp);\n+\tlen = strlen(conn->msg_out);\n+\tconn->msg_out_len_max -= len;\n+\trte_graph_cluster_stats_destroy(stats);\n+\n+\tfclose(fp);\n+}\n+\n+static void\n+cli_graph_stats(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,\n+\t\t__rte_unused void *data)\n+{\n+\tgraph_stats_print_to_file();\n+}\n+\n+bool\n+graph_status_get(void)\n+{\n+\treturn graph_started;\n+}\n+\n+static void\n+cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,\n+\t\t__rte_unused void *data)\n+{\n+\tstruct rte_node_ethdev_config *conf;\n+\tuint32_t nb_graphs = 0, nb_conf, i;\n+\tint rc = -EINVAL;\n+\n+\tconf = graph_rxtx_node_config_get(&nb_conf, &nb_graphs);\n+\tfor (i = 0; i < MAX_GRAPH_USECASES; i++) {\n+\t\tif (!strcmp(graph_config.usecases[i].name, \"l3fwd\")) {\n+\t\t\tif (graph_config.usecases[i].enabled) {\n+\t\t\t\tRTE_SET_USED(conf);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (!rc)\n+\t\tgraph_started = true;\n+}\n+\n+static int\n+graph_config_add(char *usecases, struct graph_config *config)\n+{\n+\tuint64_t lcore_id, core_num;\n+\tuint64_t eal_coremask = 0;\n+\n+\tif (!parser_usecases_read(usecases))\n+\t\treturn -EINVAL;\n+\n+\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\tif (rte_lcore_is_enabled(lcore_id))\n+\t\t\teal_coremask |= RTE_BIT64(lcore_id);\n+\t}\n+\n+\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\tcore_num = 1 << lcore_id;\n+\t\tif (config->params.coremask & core_num) {\n+\t\t\tif (eal_coremask & core_num)\n+\t\t\t\tcontinue;\n+\t\t\telse\n+\t\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\tgraph_config.params.bsz = config->params.bsz;\n+\tgraph_config.params.tmo = config->params.tmo;\n+\tgraph_config.params.coremask = config->params.coremask;\n+\tgraph_config.model = config->model;\n+\tgraph_config.pcap_ena = config->pcap_ena;\n+\tgraph_config.num_pcap_pkts = config->num_pcap_pkts;\n+\tgraph_config.pcap_file = strdup(config->pcap_file);\n+\n+\treturn 0;\n+}\n+\n+void\n+graph_pcap_config_get(uint8_t *pcap_ena, uint64_t *num_pkts, char **file)\n+{\n+\n+\t*pcap_ena = graph_config.pcap_ena;\n+\t*num_pkts = graph_config.num_pcap_pkts;\n+\t*file = graph_config.pcap_file;\n+}\n+\n+int\n+graph_walk_start(void *conf)\n+{\n+\tstruct lcore_conf *qconf;\n+\tstruct rte_graph *graph;\n+\tuint32_t lcore_id;\n+\n+\tRTE_SET_USED(conf);\n+\n+\tlcore_id = rte_lcore_id();\n+\tqconf = &lcore_conf[lcore_id];\n+\tgraph = qconf->graph;\n+\n+\tif (!graph) {\n+\t\tRTE_LOG(INFO, APP_GRAPH, \"Lcore %u has nothing to do\\n\", lcore_id);\n+\t\treturn 0;\n+\t}\n+\n+\tRTE_LOG(INFO, APP_GRAPH, \"Entering main loop on lcore %u, graph %s(%p)\\n\", lcore_id,\n+\t\tqconf->name, graph);\n+\n+\twhile (likely(!force_quit))\n+\t\trte_graph_walk(graph);\n+\n+\treturn 0;\n+}\n+\n+void\n+graph_stats_print(void)\n+{\n+\tconst char topLeft[] = {27, '[', '1', ';', '1', 'H', '\\0'};\n+\tconst char clr[] = {27, '[', '2', 'J', '\\0'};\n+\tstruct rte_graph_cluster_stats_param s_param;\n+\tstruct rte_graph_cluster_stats *stats;\n+\tconst char *pattern = \"worker_*\";\n+\n+\t/* Prepare stats object */\n+\tmemset(&s_param, 0, sizeof(s_param));\n+\ts_param.f = stdout;\n+\ts_param.socket_id = SOCKET_ID_ANY;\n+\ts_param.graph_patterns = &pattern;\n+\ts_param.nb_graph_patterns = 1;\n+\n+\tstats = rte_graph_cluster_stats_create(&s_param);\n+\tif (stats == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Unable to create stats object\\n\");\n+\n+\twhile (!force_quit) {\n+\t\t/* Clear screen and move to top left */\n+\t\tprintf(\"%s%s\", clr, topLeft);\n+\t\trte_graph_cluster_stats_get(stats, 0);\n+\t\trte_delay_ms(1E3);\n+\t\tif (app_graph_exit())\n+\t\t\tforce_quit = true;\n+\t}\n+\n+\trte_graph_cluster_stats_destroy(stats);\n+}\n+\n+uint64_t\n+graph_coremask_get(void)\n+{\n+\treturn graph_config.params.coremask;\n+}\n+\n+static void\n+cli_graph(void *parsed_result, __rte_unused struct cmdline *cl, __rte_unused void *data)\n+{\n+\tstruct graph_config_cmd_tokens *res = parsed_result;\n+\tstruct graph_config config;\n+\tchar *model_name;\n+\tuint8_t model;\n+\tint rc;\n+\n+\tmodel_name = res->model_name;\n+\tif (strcmp(model_name, \"default\") == 0) {\n+\t\tmodel = GRAPH_MODEL_RTC;\n+\t} else if (strcmp(model_name, \"rtc\") == 0) {\n+\t\tmodel = GRAPH_MODEL_RTC;\n+\t} else if (strcmp(model_name, \"mcd\") == 0) {\n+\t\tmodel = GRAPH_MODEL_MCD;\n+\t} else {\n+\t\tprintf(MSG_ARG_NOT_FOUND, \"model arguments\");\n+\t\treturn;\n+\t}\n+\n+\tconfig.params.bsz = res->size;\n+\tconfig.params.tmo = res->ns;\n+\tconfig.params.coremask = res->mask;\n+\tconfig.model = model;\n+\tconfig.pcap_ena = res->pcap_ena;\n+\tconfig.num_pcap_pkts = res->num_pcap_pkts;\n+\tconfig.pcap_file = res->pcap_file;\n+\trc = graph_config_add(res->usecase, &config);\n+\tif (rc < 0) {\n+\t\tcli_exit();\n+\t\tprintf(MSG_CMD_FAIL, res->graph);\n+\t\trte_exit(EXIT_FAILURE, \"coremask is Invalid\\n\");\n+\t}\n+}\n+\n+static void\n+cli_graph_help(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,\n+\t       __rte_unused void *data)\n+{\n+\tsize_t len;\n+\n+\tlen = strlen(conn->msg_out);\n+\tconn->msg_out += len;\n+\tsnprintf(conn->msg_out, conn->msg_out_len_max, \"\\n%s\\n%s\\n%s\\n\",\n+\t\t \"----------------------------- graph command help -----------------------------\",\n+\t\t cmd_graph_help, \"graph start\");\n+\n+\tlen = strlen(conn->msg_out);\n+\tconn->msg_out_len_max -= len;\n+}\n+\n+cmdline_parse_token_string_t graph_display_graph =\n+\tTOKEN_STRING_INITIALIZER(struct graph_stats_cmd_tokens, graph, \"graph\");\n+cmdline_parse_token_string_t graph_display_stats =\n+\tTOKEN_STRING_INITIALIZER(struct graph_stats_cmd_tokens, stats, \"stats\");\n+cmdline_parse_token_string_t graph_display_show =\n+\tTOKEN_STRING_INITIALIZER(struct graph_stats_cmd_tokens, show, \"show\");\n+\n+cmdline_parse_inst_t graph_stats_cmd_ctx = {\n+\t.f = cli_graph_stats,\n+\t.data = NULL,\n+\t.help_str = \"graph stats show\",\n+\t.tokens = {\n+\t\t(void *)&graph_display_graph,\n+\t\t(void *)&graph_display_stats,\n+\t\t(void *)&graph_display_show,\n+\t\tNULL,\n+\t},\n+};\n+\n+cmdline_parse_token_string_t graph_config_start_graph =\n+\tTOKEN_STRING_INITIALIZER(struct graph_start_cmd_tokens, graph, \"graph\");\n+cmdline_parse_token_string_t graph_config_start =\n+\tTOKEN_STRING_INITIALIZER(struct graph_start_cmd_tokens, start, \"start\");\n+\n+cmdline_parse_inst_t graph_start_cmd_ctx = {\n+\t.f = cli_graph_start,\n+\t.data = NULL,\n+\t.help_str = \"graph start\",\n+\t.tokens = {\n+\t\t(void *)&graph_config_start_graph,\n+\t\t(void *)&graph_config_start,\n+\t\tNULL,\n+\t},\n+};\n+\n+cmdline_parse_token_string_t graph_config_add_graph =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, graph, \"graph\");\n+cmdline_parse_token_string_t graph_config_add_usecase =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, usecase, NULL);\n+cmdline_parse_token_string_t graph_config_add_coremask =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, coremask, \"coremask\");\n+cmdline_parse_token_num_t graph_config_add_mask =\n+\tTOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, mask, RTE_UINT64);\n+cmdline_parse_token_string_t graph_config_add_bsz =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, bsz, \"bsz\");\n+cmdline_parse_token_num_t graph_config_add_size =\n+\tTOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, size, RTE_UINT16);\n+cmdline_parse_token_string_t graph_config_add_tmo =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, tmo, \"tmo\");\n+cmdline_parse_token_num_t graph_config_add_ns =\n+\tTOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, ns, RTE_UINT64);\n+cmdline_parse_token_string_t graph_config_add_model =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, model, \"model\");\n+cmdline_parse_token_string_t graph_config_add_model_name =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, model_name, \"rtc#mcd#default\");\n+cmdline_parse_token_string_t graph_config_add_capt_ena =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, capt_ena, \"pcap_enable\");\n+cmdline_parse_token_num_t graph_config_add_pcap_ena =\n+\tTOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, pcap_ena, RTE_UINT8);\n+cmdline_parse_token_string_t graph_config_add_capt_pkts_count =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, capt_pkts_count, \"num_pcap_pkts\");\n+cmdline_parse_token_num_t graph_config_add_num_pcap_pkts =\n+\tTOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, num_pcap_pkts, RTE_UINT64);\n+cmdline_parse_token_string_t graph_config_add_capt_file =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, capt_file, \"pcap_file\");\n+cmdline_parse_token_string_t graph_config_add_pcap_file =\n+\tTOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, pcap_file, NULL);\n+\n+cmdline_parse_inst_t graph_config_cmd_ctx = {\n+\t.f = cli_graph,\n+\t.data = NULL,\n+\t.help_str = cmd_graph_help,\n+\t.tokens = {\n+\t\t(void *)&graph_config_add_graph,\n+\t\t(void *)&graph_config_add_usecase,\n+\t\t(void *)&graph_config_add_coremask,\n+\t\t(void *)&graph_config_add_mask,\n+\t\t(void *)&graph_config_add_bsz,\n+\t\t(void *)&graph_config_add_size,\n+\t\t(void *)&graph_config_add_tmo,\n+\t\t(void *)&graph_config_add_ns,\n+\t\t(void *)&graph_config_add_model,\n+\t\t(void *)&graph_config_add_model_name,\n+\t\t(void *)&graph_config_add_capt_ena,\n+\t\t(void *)&graph_config_add_pcap_ena,\n+\t\t(void *)&graph_config_add_capt_pkts_count,\n+\t\t(void *)&graph_config_add_num_pcap_pkts,\n+\t\t(void *)&graph_config_add_capt_file,\n+\t\t(void *)&graph_config_add_pcap_file,\n+\t\tNULL,\n+\t},\n+};\n+\n+cmdline_parse_token_string_t graph_help_cmd =\n+\tTOKEN_STRING_INITIALIZER(struct graph_help_cmd_tokens, help, \"help\");\n+cmdline_parse_token_string_t graph_help_graph =\n+\tTOKEN_STRING_INITIALIZER(struct graph_help_cmd_tokens, graph, \"graph\");\n+\n+cmdline_parse_inst_t graph_help_cmd_ctx = {\n+\t.f = cli_graph_help,\n+\t.data = NULL,\n+\t.help_str = \"\",\n+\t.tokens = {\n+\t\t(void *)&graph_help_cmd,\n+\t\t(void *)&graph_help_graph,\n+\t\tNULL,\n+\t},\n+};\ndiff --git a/app/graph/graph.h b/app/graph/graph.h\nnew file mode 100644\nindex 0000000000..a14fa37ccd\n--- /dev/null\n+++ b/app/graph/graph.h\n@@ -0,0 +1,21 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 Marvell.\n+ */\n+\n+#ifndef APP_GRAPH_H\n+#define APP_GRAPH_H\n+\n+#include <cmdline_parse.h>\n+\n+extern cmdline_parse_inst_t graph_config_cmd_ctx;\n+extern cmdline_parse_inst_t graph_start_cmd_ctx;\n+extern cmdline_parse_inst_t graph_stats_cmd_ctx;\n+extern cmdline_parse_inst_t graph_help_cmd_ctx;\n+\n+int graph_walk_start(void *conf);\n+void graph_stats_print(void);\n+void graph_pcap_config_get(uint8_t *pcap_ena, uint64_t *num_pkts, char **file);\n+uint64_t graph_coremask_get(void);\n+bool graph_status_get(void);\n+\n+#endif\ndiff --git a/app/graph/graph_priv.h b/app/graph/graph_priv.h\nnew file mode 100644\nindex 0000000000..a48a35daa3\n--- /dev/null\n+++ b/app/graph/graph_priv.h\n@@ -0,0 +1,70 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 Marvell.\n+ */\n+\n+#ifndef APP_GRAPH_PRIV_H\n+#define APP_GRAPH_PRIV_H\n+\n+#define MAX_GRAPH_USECASES 32\n+\n+struct graph_help_cmd_tokens {\n+\tcmdline_fixed_string_t help;\n+\tcmdline_fixed_string_t graph;\n+};\n+\n+struct graph_start_cmd_tokens {\n+\tcmdline_fixed_string_t graph;\n+\tcmdline_fixed_string_t start;\n+};\n+\n+struct graph_stats_cmd_tokens {\n+\tcmdline_fixed_string_t show;\n+\tcmdline_fixed_string_t graph;\n+\tcmdline_fixed_string_t stats;\n+};\n+\n+struct graph_config_cmd_tokens {\n+\tcmdline_fixed_string_t graph;\n+\tcmdline_fixed_string_t usecase;\n+\tcmdline_fixed_string_t bsz;\n+\tcmdline_fixed_string_t tmo;\n+\tcmdline_fixed_string_t coremask;\n+\tcmdline_fixed_string_t model;\n+\tcmdline_fixed_string_t capt_ena;\n+\tcmdline_fixed_string_t capt_pkts_count;\n+\tcmdline_fixed_string_t capt_file;\n+\tcmdline_fixed_string_t model_name;\n+\tcmdline_fixed_string_t pcap_file;\n+\tuint16_t size;\n+\tuint64_t ns;\n+\tuint64_t mask;\n+\tuint64_t num_pcap_pkts;\n+\tuint8_t pcap_ena;\n+};\n+\n+enum graph_model {\n+\tGRAPH_MODEL_RTC = 0x01,\n+\tGRAPH_MODEL_MCD = 0x02,\n+};\n+\n+struct usecases {\n+\tchar name[32];\n+\tbool enabled;\n+};\n+\n+struct usecase_params {\n+\tuint64_t coremask;\n+\tuint32_t bsz;\n+\tuint32_t tmo;\n+};\n+\n+struct graph_config {\n+\tstruct usecases usecases[MAX_GRAPH_USECASES];\n+\tstruct usecase_params params;\n+\tenum graph_model model;\n+\tuint64_t num_pcap_pkts;\n+\tchar *pcap_file;\n+\tuint8_t pcap_ena;\n+};\n+\n+#endif\ndiff --git a/app/graph/ip4_route.c b/app/graph/ip4_route.c\nindex db3354c270..fc83586427 100644\n--- a/app/graph/ip4_route.c\n+++ b/app/graph/ip4_route.c\n@@ -97,11 +97,14 @@ route_ip4_add(struct route_ipv4_config *route)\n \tipv4route->via = route->via;\n \tipv4route->is_used = true;\n \n-\t/* FIXME: Get graph status here and then update table */\n+\tif (!graph_status_get())\n+\t\tgoto exit;\n+\n \trc = route4_rewirte_table_update(ipv4route);\n \tif (rc)\n \t\tgoto free;\n \n+exit:\n \tTAILQ_INSERT_TAIL(&route4, ipv4route, next);\n \treturn 0;\n free:\ndiff --git a/app/graph/ip6_route.c b/app/graph/ip6_route.c\nindex e793cde830..1fa4865220 100644\n--- a/app/graph/ip6_route.c\n+++ b/app/graph/ip6_route.c\n@@ -102,11 +102,14 @@ route_ip6_add(struct route_ipv6_config *route)\n \t}\n \tipv6route->is_used = true;\n \n-\t/* FIXME: Get graph status here and then update table */\n+\tif (!graph_status_get())\n+\t\tgoto exit;\n+\n \trc = route6_rewirte_table_update(ipv6route);\n \tif (rc)\n \t\tgoto free;\n \n+exit:\n \tTAILQ_INSERT_TAIL(&route6, ipv6route, next);\n \treturn 0;\n free:\ndiff --git a/app/graph/meson.build b/app/graph/meson.build\nindex cafab04f70..c0b59b9a92 100644\n--- a/app/graph/meson.build\n+++ b/app/graph/meson.build\n@@ -14,6 +14,7 @@ sources = files(\n         'conn.c',\n         'ethdev_rx.c',\n         'ethdev.c',\n+        'graph.c',\n         'ip4_route.c',\n         'ip6_route.c',\n         'main.c',\ndiff --git a/app/graph/module_api.h b/app/graph/module_api.h\nindex 56b7c94ecc..392dcfb222 100644\n--- a/app/graph/module_api.h\n+++ b/app/graph/module_api.h\n@@ -12,6 +12,7 @@\n #include \"conn.h\"\n #include \"ethdev.h\"\n #include \"ethdev_rx.h\"\n+#include \"graph.h\"\n #include \"mempool.h\"\n #include \"neigh.h\"\n #include \"route.h\"\ndiff --git a/app/graph/neigh.c b/app/graph/neigh.c\nindex af69fc8ade..706be3840f 100644\n--- a/app/graph/neigh.c\n+++ b/app/graph/neigh.c\n@@ -156,11 +156,14 @@ neigh_ip4_add(uint32_t ip, uint64_t mac)\n \tv4_config->mac = mac;\n \tv4_config->is_used = true;\n \n-\t/* FIXME: Get graph status here and then update table */\n+\tif (!graph_status_get())\n+\t\tgoto exit;\n+\n \trc = ip4_rewrite_node_add(v4_config);\n \tif (rc)\n \t\tgoto free;\n \n+exit:\n \tTAILQ_INSERT_TAIL(&neigh4, v4_config, next);\n \treturn 0;\n free:\n@@ -189,11 +192,14 @@ neigh_ip6_add(uint8_t *ip, uint64_t mac)\n \tv6_config->mac = mac;\n \tv6_config->is_used = true;\n \n-\t/* FIXME: Get graph status here and then update table */\n+\tif (!graph_status_get())\n+\t\tgoto exit;\n+\n \trc =  ip6_rewrite_node_add(v6_config);\n \tif (rc)\n \t\tgoto free;\n \n+exit:\n \tTAILQ_INSERT_TAIL(&neigh6, v6_config, next);\n \treturn 0;\n free:\ndiff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst\nindex f2920ff136..7d2aa95c95 100644\n--- a/doc/guides/tools/graph.rst\n+++ b/doc/guides/tools/graph.rst\n@@ -76,10 +76,25 @@ file to express the requested use case configuration.\n      - Description\n      - Dynamic\n      - Optional\n-   * - Dummy command\n-     - Dummy command description\n+   * - graph <usecases> [bsz <size>] [tmo <ns>] [coremask <bitmask>] model <rtc | mcd | default>\n+       pcap_enable <0 | 1> num_pcap_pkts <num> pcap_file <output_capture_file>\n+     - Command to express the desired use case. Also enables/disable pcap capturing\n      - No\n      - No\n+   * - graph start\n+     - Command to start the graph.\n+       This command triggers that no more commands are left to be parsed and graph\n+       initialization can be started now. It must be the last command in ``<usecase>.cli``\n+     - No\n+     - No\n+   * - graph stats show\n+     - Command to dump current graph statistics\n+     - Yes\n+     - Yes\n+   * - help graph\n+     - Command to dump graph help message\n+     - Yes\n+     - Yes\n    * - mempool <mempool_name> size <mbuf_size> buffers <number_of_buffers> cache <cache_size> numa <numa_id>\n      - Command to create mempool which will be further associated to RxQ to dequeue the packets\n      - No\n",
    "prefixes": [
        "v8",
        "10/12"
    ]
}