DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH 1/2] node: forward packet from ethdev_rx node
@ 2023-11-23  6:15 Rakesh Kudurumalla
  2023-11-23  6:15 ` [PATCH 2/2] app/graph: implement L2FWD usecase Rakesh Kudurumalla
                   ` (2 more replies)
  0 siblings, 3 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-11-23  6:15 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 lib/node/ethdev_ctrl.c      | 40 +++++++++++++++++++++++++++++++++++++
 lib/node/rte_node_eth_api.h | 17 ++++++++++++++++
 lib/node/version.map        |  1 +
 3 files changed, 58 insertions(+)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..d64fc33655 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -129,3 +129,43 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t count;
+	uint16_t i = 0;
+
+	if (id == RTE_EDGE_ID_INVALID)
+		return id;
+
+	count = rte_node_edge_get(id, NULL);
+	next_nodes = malloc(count);
+	if (next_nodes == NULL)
+		return rc;
+
+	count = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto found;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+found:
+	free(next_nodes);
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..66cea2d31e 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -57,6 +57,23 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   RTE_EDGE_ID_INVALID if id is invalid
+ *   EINVAL if edge name doesn't exist
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..07abc3a79f 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -16,6 +16,7 @@ EXPERIMENTAL {
 	rte_node_ip6_route_add;
 
 	# added in 23.11
+	rte_node_ethdev_rx_next_update;
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH 2/2] app/graph: implement L2FWD usecase
  2023-11-23  6:15 [PATCH 1/2] node: forward packet from ethdev_rx node Rakesh Kudurumalla
@ 2023-11-23  6:15 ` Rakesh Kudurumalla
  2023-11-24  8:13   ` Sunil Kumar Kori
  2023-11-24  7:45 ` [EXT] [PATCH 1/2] node: forward packet from ethdev_rx node Sunil Kumar Kori
  2023-12-04 18:04 ` [PATCH v2 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 1 reply; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-11-23  6:15 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added l2fwd usecase for graph

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/cli.c              |   1 +
 app/graph/examples/l2fwd.cli |  41 ++++++++++
 app/graph/graph.c            |   8 +-
 app/graph/l2fwd.c            | 148 +++++++++++++++++++++++++++++++++++
 app/graph/l2fwd.h            |  11 +++
 app/graph/meson.build        |   2 +
 app/graph/module_api.h       |   2 +
 app/graph/portfwd.c          | 110 ++++++++++++++++++++++++++
 app/graph/portfwd.h          |  21 +++++
 app/graph/portfwd_priv.h     |  14 ++++
 10 files changed, 357 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 app/graph/portfwd.c
 create mode 100644 app/graph/portfwd.h
 create mode 100644 app/graph/portfwd_priv.h

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..af24a5836a
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; L2 mac forwarding rules
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..1f18d69ea8
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	struct port_forwarding *port_fwd = NULL;
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int rc;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		port_fwd = find_pf_entry_rx_port(port_id);
+		if (port_fwd) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", port_fwd->tx_port);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				return rc;
+		}
+	}
+	return 0;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..d8b1f63988 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,9 +17,11 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
         'neigh.c',
+        'portfwd.c',
         'utils.c',
 )
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..751d6cfb3b 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,9 +13,11 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
+#include "portfwd.h"
 #include "route.h"
 #include "utils.h"
 
diff --git a/app/graph/portfwd.c b/app/graph/portfwd.c
new file mode 100644
index 0000000000..6c4b54e1db
--- /dev/null
+++ b/app/graph/portfwd.c
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <stdio.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_ethdev.h>
+#include <rte_node_ip4_api.h>
+
+#include "module_api.h"
+#include "portfwd_priv.h"
+
+static const char
+cmd_ethdev_l2fwd_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
+static struct prt_fw pfw = TAILQ_HEAD_INITIALIZER(pfw);
+
+struct port_forwarding *
+find_pf_entry_rx_port(uint16_t portid_rx)
+{
+	struct port_forwarding *port_fwd;
+
+	TAILQ_FOREACH(port_fwd, &pfw, next) {
+		if (port_fwd->rx_port == portid_rx)
+			return port_fwd;
+	}
+	return NULL;
+}
+
+static struct port_forwarding *
+find_l2_entry(uint16_t portid_tx, uint16_t portid_rx)
+{
+	struct port_forwarding *port_fwd;
+
+	TAILQ_FOREACH(port_fwd, &pfw, next) {
+		if ((port_fwd->tx_port == portid_tx) &&
+				(port_fwd->rx_port == portid_rx))
+			return port_fwd;
+	}
+	return NULL;
+}
+
+static int
+ethdev_pfw_config(char *tx_name, char *rx_name)
+{
+	struct port_forwarding *pfwd;
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	int rc;
+
+	rc = rte_eth_dev_get_port_by_name(tx_name, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_name, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	pfwd = find_l2_entry(portid_tx, portid_rx);
+	if (!pfwd) {
+		pfwd = malloc(sizeof(struct port_forwarding));
+		pfwd->tx_port = portid_tx;
+		pfwd->rx_port = portid_rx;
+		TAILQ_INSERT_TAIL(&pfw, pfwd, next);
+		return 0;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_pfw_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+
+cmdline_parse_token_string_t ethdev_l2_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_l2fwd_help,
+	.tokens = {
+		(void *)&ethdev_l2_cmd,
+		(void *)&ethdev_fwd_cmd,
+		(void *)&ethdev_tx_device,
+		(void *)&ethdev_rx_device,
+		NULL,
+	},
+};
+
diff --git a/app/graph/portfwd.h b/app/graph/portfwd.h
new file mode 100644
index 0000000000..420fa73746
--- /dev/null
+++ b/app/graph/portfwd.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_PORTFWD_H
+#define APP_GRAPH_PORTFWD_H
+
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
+
+struct port_forwarding {
+	TAILQ_ENTRY(port_forwarding) next;
+	uint16_t tx_port;
+	uint16_t rx_port;
+	bool is_used;
+} __rte_cache_aligned;
+
+TAILQ_HEAD(prt_fw, port_forwarding);
+
+struct port_forwarding *find_pf_entry_rx_port(uint16_t portid_rx);
+
+#endif
diff --git a/app/graph/portfwd_priv.h b/app/graph/portfwd_priv.h
new file mode 100644
index 0000000000..9da1ce6e68
--- /dev/null
+++ b/app/graph/portfwd_priv.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_PORTFWD_PRIV_H
+#define APP_GRAPH_PORTFWD_PRIV_H
+
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+#endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [EXT] [PATCH 1/2] node: forward packet from ethdev_rx node
  2023-11-23  6:15 [PATCH 1/2] node: forward packet from ethdev_rx node Rakesh Kudurumalla
  2023-11-23  6:15 ` [PATCH 2/2] app/graph: implement L2FWD usecase Rakesh Kudurumalla
@ 2023-11-24  7:45 ` Sunil Kumar Kori
  2023-12-04 18:04 ` [PATCH v2 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2023-11-24  7:45 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Nithin Kumar Dabilpuram, Pavan Nikhilesh Bhagavatula
  Cc: dev, Jerin Jacob Kollanukkaran, Rakesh Kudurumalla

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Thursday, November 23, 2023 11:46 AM
> To: Nithin Kumar Dabilpuram <ndabilpuram@marvell.com>; Pavan
> Nikhilesh Bhagavatula <pbhagavatula@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Subject: [EXT] [PATCH 1/2] node: forward packet from ethdev_rx node
> 
> External Email
> 
> ----------------------------------------------------------------------
> By default all packets received on ethdev_rx node is forwarded to pkt_cls
> node.This patch provides library support to add a new node as next node to
> ethdev_rx node and forward packet to new node from rx node.
> 
IMO, Subject "node: add API to update ethdev_rx next node" or similar is more suitable to reflect the implementation.
Please run check-git-log.sh also to make sure that subject is aligned.

> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  lib/node/ethdev_ctrl.c      | 40
> +++++++++++++++++++++++++++++++++++++
>  lib/node/rte_node_eth_api.h | 17 ++++++++++++++++
>  lib/node/version.map        |  1 +
>  3 files changed, 58 insertions(+)
> 
> diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c index
> d564b80e37..d64fc33655 100644
> --- a/lib/node/ethdev_ctrl.c
> +++ b/lib/node/ethdev_ctrl.c
> @@ -129,3 +129,43 @@ rte_node_eth_config(struct
> rte_node_ethdev_config *conf, uint16_t nb_confs,
>  	ctrl.nb_graphs = nb_graphs;
>  	return 0;
>  }
> +
> +int
> +rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name) {
> +	struct ethdev_rx_node_main *data;
> +	ethdev_rx_node_elem_t *elem;
> +	char **next_nodes;
> +	int rc = -EINVAL;
> +	uint32_t count;
> +	uint16_t i = 0;
> +
> +	if (id == RTE_EDGE_ID_INVALID)
> +		return id;
Return type and returned value are mismatched.

> +
Add a NULL check for edge_name too. 

> +	count = rte_node_edge_get(id, NULL);
This API itself return error if id is invalid. Use returned value instead of above check.

> +	next_nodes = malloc(count);
> +	if (next_nodes == NULL)
> +		return rc;
> +
> +	count = rte_node_edge_get(id, next_nodes);
> +
> +	while (next_nodes[i] != NULL) {
> +		if (strcmp(edge_name, next_nodes[i]) == 0) {
> +			data = ethdev_rx_get_node_data_get();
> +			elem = data->head;
> +			while (elem->next != data->head) {
> +				if (elem->nid == id) {
> +					elem->ctx.cls_next = i;
> +					rc = 0;
> +					goto found;
> +				}
> +				elem = elem->next;
> +			}
> +		}
> +		i++;
> +	}
> +found:
Cosmetic: use "exit" keyword instead of "found". 

> +	free(next_nodes);
> +	return rc;
> +}
> diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h index
> eaae50772d..66cea2d31e 100644
> --- a/lib/node/rte_node_eth_api.h
> +++ b/lib/node/rte_node_eth_api.h
> @@ -57,6 +57,23 @@ struct rte_node_ethdev_config {
>   */
>  int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
>  			uint16_t cnt, uint16_t nb_graphs);
> +
> +/**
> + * Update ethdev rx next node.
> + *
> + * @param id
> + *   Node id whose edge is to be updated.
> + * @param edge_name
> + *   Name of the next node.
> + *
> + * @return
> + *   RTE_EDGE_ID_INVALID if id is invalid
> + *   EINVAL if edge name doesn't exist
> + *   0 on successful initialization.
> + */
Does it make sense to add error codes like below:
-ENINVAL: Either of input parameters are invalid.
-ENODATA: If edge_name is not found.
-ENOMEM: If memory allocation failed.
0: on Success

What's your thoughts on this ?

> +__rte_experimental
> +int rte_node_ethdev_rx_next_update(rte_node_t id, const char
> +*edge_name);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/node/version.map b/lib/node/version.map index
> 99ffcdd414..07abc3a79f 100644
> --- a/lib/node/version.map
> +++ b/lib/node/version.map
> @@ -16,6 +16,7 @@ EXPERIMENTAL {
>  	rte_node_ip6_route_add;
> 
>  	# added in 23.11
> +	rte_node_ethdev_rx_next_update;
>  	rte_node_ip4_reassembly_configure;
>  	rte_node_udp4_dst_port_add;
>  	rte_node_udp4_usr_node_add;
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [PATCH 2/2] app/graph: implement L2FWD usecase
  2023-11-23  6:15 ` [PATCH 2/2] app/graph: implement L2FWD usecase Rakesh Kudurumalla
@ 2023-11-24  8:13   ` Sunil Kumar Kori
  0 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2023-11-24  8:13 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Rakesh Kudurumalla
  Cc: dev, Jerin Jacob Kollanukkaran, Nithin Kumar Dabilpuram

[-- Attachment #1: Type: text/plain, Size: 15496 bytes --]

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Thursday, November 23, 2023 11:46 AM
> To: Sunil Kumar Kori <skori@marvell.com>; Rakesh Kudurumalla
> <rkudurumalla@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Nithin
> Kumar Dabilpuram <ndabilpuram@marvell.com>
> Subject: [PATCH 2/2] app/graph: implement L2FWD usecase
> 
> Added l2fwd usecase for graph
> 
Need details about patch. Please refer commit to add l3fwd usecase.

> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  app/graph/cli.c              |   1 +
>  app/graph/examples/l2fwd.cli |  41 ++++++++++
>  app/graph/graph.c            |   8 +-
>  app/graph/l2fwd.c            | 148 +++++++++++++++++++++++++++++++++++
>  app/graph/l2fwd.h            |  11 +++
>  app/graph/meson.build        |   2 +
>  app/graph/module_api.h       |   2 +
>  app/graph/portfwd.c          | 110 ++++++++++++++++++++++++++
>  app/graph/portfwd.h          |  21 +++++
>  app/graph/portfwd_priv.h     |  14 ++++
>  10 files changed, 357 insertions(+), 1 deletion(-)  create mode 100644
> app/graph/examples/l2fwd.cli  create mode 100644 app/graph/l2fwd.c
> create mode 100644 app/graph/l2fwd.h  create mode 100644
> app/graph/portfwd.c  create mode 100644 app/graph/portfwd.h  create
> mode 100644 app/graph/portfwd_priv.h
> 
1. Split patch into 2 separate patches. One to add new ethdev command and second to add l2fwd usecase.
2. Code related to ethdev command can be moved to ethdev.c, ethdev.h and ethdev_priv.h. No need to add new files.
3. Update " doc/guides/tools/graph.rst " to support l2fwd usecase.

> diff --git a/app/graph/cli.c b/app/graph/cli.c index
> 30b12312d6..76f5b8e670 100644
> --- a/app/graph/cli.c
> +++ b/app/graph/cli.c
> @@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
>  	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
> +	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx, diff --git
> a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli new file
> mode 100644 index 0000000000..af24a5836a
> --- /dev/null
> +++ b/app/graph/examples/l2fwd.cli
> @@ -0,0 +1,41 @@
> +; SPDX-License-Identifier: BSD-3-Clause ; Copyright(c) 2023 Marvell.
> +
> +;
> +; Graph configuration for given usecase ; graph l2fwd coremask 0xff bsz
> +32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file
> +/tmp/output.pcap
> +
> +;
> +; Mempools to be attached with ethdev
> +;
> +mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
> +
> +;
> +; DPDK devices and configuration.
> +;
> +; Note: Customize the parameters below to match your setup.
> +;
> +ethdev 0002:01:00.1 rxq 1 txq 8 mempool0 ethdev 0002:01:00.4 rxq 1 txq
> +8 mempool0 ethdev 0002:01:00.6 rxq 1 txq 8 mempool0 ethdev
> 0002:02:00.0
> +rxq 1 txq 8 mempool0
> +
> +;
> +; L2 mac forwarding rules
> +;
> +ethdev forward 0002:01:00.4 0002:02:00.0 ethdev forward 0002:01:00.1
> +0002:01:00.6
> +
> +;
> +; Port-Queue-Core mapping for ethdev_rx node ; ethdev_rx map port
> +0002:02:00.0 queue 0 core 1 ethdev_rx map port 0002:01:00.6 queue 0
> +core 2
> +
> +;
> +; Graph start command to create graph.
> +;
> +; Note: No more command should come after this.
> +;
> +graph start
> diff --git a/app/graph/graph.c b/app/graph/graph.c index
> a65723a196..4e0441f1a7 100644
> --- a/app/graph/graph.c
> +++ b/app/graph/graph.c
> @@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size>
> tmo <ns> coremask <bitmask> "
>  		   "model <rtc | mcd | default> pcap_enable <0 | 1>
> num_pcap_pkts <num>"
>  		   "pcap_file <output_capture_file>";
> 
> -static const char * const supported_usecases[] = {"l3fwd"};
> +static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
>  struct graph_config graph_config;
>  bool graph_started;
> 
> @@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result,
> __rte_unused struct cmdline *c
>  				break;
>  			}
>  		}
> +		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
> +			if (graph_config.usecases[i].enabled) {
> +				rc  = usecase_l2fwd_configure(conf,
> nb_conf, nb_graphs);
> +				break;
> +			}
> +		}
>  	}
> 
>  	if (!rc)
> diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c new file mode 100644
> index 0000000000..1f18d69ea8
> --- /dev/null
> +++ b/app/graph/l2fwd.c
> @@ -0,0 +1,148 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Marvell.
> + */
> +
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <rte_common.h>
> +#include <rte_ethdev.h>
> +#include <rte_graph.h>
> +#include <rte_graph_worker.h>
> +#include <rte_lcore.h>
> +#include <rte_node_eth_api.h>
> +
> +#include "module_api.h"
> +
> +static int
> +l2fwd_pattern_configure(void)
> +{
> +	struct rte_graph_param graph_conf;
> +	const char **node_patterns;
> +	uint64_t pcap_pkts_count;
> +	struct lcore_conf *qconf;
> +	uint16_t nb_patterns;
> +	uint8_t pcap_ena;
> +	char *pcap_file;
> +	int lcore_id;
> +
> +	nb_patterns = 0;
> +	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX +
> nb_patterns) *
> +			sizeof(*node_patterns));
> +	if (!node_patterns)
> +		return -ENOMEM;
> +
> +	memset(&graph_conf, 0, sizeof(graph_conf));
> +	graph_conf.node_patterns = node_patterns;
> +
> +	/* Pcap config */
> +	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count,
> &pcap_file);
> +	graph_conf.pcap_enable = pcap_ena;
> +	graph_conf.num_pkt_to_capture = pcap_pkts_count;
> +	graph_conf.pcap_filename = strdup(pcap_file);
> +
> +	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
> +		rte_graph_t graph_id;
> +		rte_edge_t i;
> +
> +		if (rte_lcore_is_enabled(lcore_id) == 0)
> +			continue;
> +
> +		qconf = &lcore_conf[lcore_id];
> +
> +		/* Skip graph creation if no source exists */
> +		if (!qconf->n_rx_queue)
> +			continue;
> +
> +		/* Add rx node patterns of this lcore */
> +		for (i = 0; i < qconf->n_rx_queue; i++) {
> +			graph_conf.node_patterns[nb_patterns + i] =
> +				qconf->rx_queue_list[i].node_name;
> +		}
> +
> +		graph_conf.nb_node_patterns = nb_patterns + i;
> +		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
> +
> +		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
> +				lcore_id);
> +
> +		graph_id = rte_graph_create(qconf->name, &graph_conf);
> +		if (graph_id == RTE_GRAPH_ID_INVALID)
> +			rte_exit(EXIT_FAILURE,
> +					"rte_graph_create(): graph_id invalid"
> +					" for lcore %u\n", lcore_id);
> +
> +		qconf->graph_id = graph_id;
> +		qconf->graph = rte_graph_lookup(qconf->name);
> +		/* >8 End of graph initialization. */
> +		if (!qconf->graph)
> +			rte_exit(EXIT_FAILURE,
> +					"rte_graph_lookup(): graph %s not
> found\n",
> +					qconf->name);
> +	}
> +
> +	/* Launch per-lcore init on every worker lcore */
> +	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
> +
> +	/* Accumulate and print stats on main until exit */
> +	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
> +		graph_stats_print();
> +
> +	return 0;
> +}
> +
> +static int
> +ethdev_rx_to_tx_node_link(uint32_t lcore_id) {
> +	struct port_forwarding *port_fwd = NULL;
> +	char name[RTE_NODE_NAMESIZE];
> +	const char *next_node = name;
> +	struct lcore_conf *qconf;
> +	uint16_t queue, port_id;
> +	rte_node_t rx_id;
> +	int rc;
> +
> +	qconf = &lcore_conf[lcore_id];
> +
> +	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
> +		port_id = qconf->rx_queue_list[queue].port_id;
> +		port_fwd = find_pf_entry_rx_port(port_id);
Here IMO, Instead of returning port_forwarding information from find_pf_entry_rx_port, return tx_port only. That will solve purpose.
This way, we move port_forwarding structure to private header.


> +		if (port_fwd) {
> +			rx_id = rte_node_from_name(qconf-
> >rx_queue_list[queue].node_name);
> +			snprintf(name, sizeof(name), "ethdev_tx-%u",
> port_fwd->tx_port);
> +			rte_node_edge_update(rx_id,
> RTE_EDGE_ID_INVALID, &next_node, 1);
> +			rc = rte_node_ethdev_rx_next_update(rx_id, name);
> +			if (rc)
> +				return rc;
> +		}
> +	}
> +	return 0;
> +}
> +
> +
> +int
> +usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t
> +nb_confs, uint16_t nb_graphs) {
> +	uint32_t lcore_id;
> +	int rc;
> +
> +	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
> +	if (rc)
> +		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
> +
> +	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
> +		rc = ethdev_rx_to_tx_node_link(lcore_id);
> +		if (rc)
> +			rte_exit(EXIT_FAILURE, "rte_node_eth_config:
> err=%d\n", rc);
> +	}
> +
> +	rc = l2fwd_pattern_configure();
> +	if (rc)
> +		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n",
> rc);
> +
> +	return rc;
> +}
> diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h new file mode 100644
> index 0000000000..3486ce52b2
> --- /dev/null
> +++ b/app/graph/l2fwd.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Marvell.
> + */
> +
> +#ifndef APP_GRAPH_L2FWD_H
> +#define APP_GRAPH_L2FWD_H
> +
> +int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf,
> uint16_t nb_conf,
> +			    uint16_t nb_graphs);
> +
> +#endif
> diff --git a/app/graph/meson.build b/app/graph/meson.build index
> 5b0f966d99..d8b1f63988 100644
> --- a/app/graph/meson.build
> +++ b/app/graph/meson.build
> @@ -17,9 +17,11 @@ sources = files(
>          'graph.c',
>          'ip4_route.c',
>          'ip6_route.c',
> +        'l2fwd.c',
>          'l3fwd.c',
>          'main.c',
>          'mempool.c',
>          'neigh.c',
> +        'portfwd.c',
>          'utils.c',
>  )
> diff --git a/app/graph/module_api.h b/app/graph/module_api.h index
> 7193e0b616..751d6cfb3b 100644
> --- a/app/graph/module_api.h
> +++ b/app/graph/module_api.h
> @@ -13,9 +13,11 @@
>  #include "ethdev.h"
>  #include "ethdev_rx.h"
>  #include "graph.h"
> +#include "l2fwd.h"
>  #include "l3fwd.h"
>  #include "mempool.h"
>  #include "neigh.h"
> +#include "portfwd.h"
>  #include "route.h"
>  #include "utils.h"
> 
> diff --git a/app/graph/portfwd.c b/app/graph/portfwd.c new file mode
> 100644 index 0000000000..6c4b54e1db
> --- /dev/null
> +++ b/app/graph/portfwd.c
> @@ -0,0 +1,110 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Marvell.
> + */
> +
> +#include <stdio.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_ethdev.h>
> +#include <rte_node_ip4_api.h>
> +
> +#include "module_api.h"
> +#include "portfwd_priv.h"
> +
> +static const char
> +cmd_ethdev_l2fwd_help[] = "ethdev forward <tx_dev_name>
Replace with cmd_ethdev_forward_help.

> <rx_dev_name>";
> +
> +static struct prt_fw pfw = TAILQ_HEAD_INITIALIZER(pfw);
> +
> +struct port_forwarding *
> +find_pf_entry_rx_port(uint16_t portid_rx) {
> +	struct port_forwarding *port_fwd;
> +
> +	TAILQ_FOREACH(port_fwd, &pfw, next) {
> +		if (port_fwd->rx_port == portid_rx)
> +			return port_fwd;
> +	}
> +	return NULL;
> +}
> +
> +static struct port_forwarding *
> +find_l2_entry(uint16_t portid_tx, uint16_t portid_rx) {
> +	struct port_forwarding *port_fwd;
Use correct naming convention i.e. action should be at last. Please refer other APIs/function. 

> +
> +	TAILQ_FOREACH(port_fwd, &pfw, next) {
> +		if ((port_fwd->tx_port == portid_tx) &&
> +				(port_fwd->rx_port == portid_rx))
> +			return port_fwd;
> +	}
> +	return NULL;
> +}
> +
> +static int
> +ethdev_pfw_config(char *tx_name, char *rx_name) {
Replace with ethdev_forward_config()

> +	struct port_forwarding *pfwd;
> +	uint16_t portid_rx = 0;
> +	uint16_t portid_tx = 0;
> +	int rc;
> +
> +	rc = rte_eth_dev_get_port_by_name(tx_name, &portid_tx);
> +	if (rc < 0)
> +		return rc;
> +
> +	rc = rte_eth_dev_get_port_by_name(rx_name, &portid_rx);
> +	if (rc < 0)
> +		return rc;
> +
> +	pfwd = find_l2_entry(portid_tx, portid_rx);
> +	if (!pfwd) {
> +		pfwd = malloc(sizeof(struct port_forwarding));
> +		pfwd->tx_port = portid_tx;
> +		pfwd->rx_port = portid_rx;
> +		TAILQ_INSERT_TAIL(&pfw, pfwd, next);
> +		return 0;
> +	}
> +
> +	return rc;
> +}
> +
> +static void
> +cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline
> +*cl, void *data __rte_unused) {
> +	struct ethdev_fwd_cmd_tokens *res = parsed_result;
> +	int rc = -EINVAL;
> +
> +	rc = ethdev_pfw_config(res->tx_dev, res->rx_dev);
> +	if (rc < 0)
> +		printf(MSG_CMD_FAIL, res->cmd);
> +}
> +
> +
> +cmdline_parse_token_string_t ethdev_l2_cmd =
> +	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd,
> "ethdev");
> +cmdline_parse_token_string_t ethdev_fwd_cmd =
> +	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd,
> +"forward"); cmdline_parse_token_string_t ethdev_tx_device =
> +	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens,
> tx_dev, NULL);
> +cmdline_parse_token_string_t ethdev_rx_device =
> +	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens,
> rx_dev, NULL);
> +
> +cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
> +	.f = cli_ethdev_forward,
> +	.data = NULL,
> +	.help_str = cmd_ethdev_l2fwd_help,
> +	.tokens = {
> +		(void *)&ethdev_l2_cmd,
> +		(void *)&ethdev_fwd_cmd,
> +		(void *)&ethdev_tx_device,
> +		(void *)&ethdev_rx_device,
> +		NULL,
> +	},
> +};
> +
> diff --git a/app/graph/portfwd.h b/app/graph/portfwd.h new file mode
> 100644 index 0000000000..420fa73746
> --- /dev/null
> +++ b/app/graph/portfwd.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Marvell.
> + */
> +
> +#ifndef APP_GRAPH_PORTFWD_H
> +#define APP_GRAPH_PORTFWD_H
> +
> +extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
> +
> +struct port_forwarding {
> +	TAILQ_ENTRY(port_forwarding) next;
> +	uint16_t tx_port;
> +	uint16_t rx_port;
> +	bool is_used;
Looks like "is_used" is unused. Please check.
Can't be this mapping in " struct ethdev_config". IMO, " struct ethdev_config" is used to contain device specific configuration.
Is there any other purpose of "struct port_forwarding" ?

> +} __rte_cache_aligned;
> +
> +TAILQ_HEAD(prt_fw, port_forwarding);
> +
> +struct port_forwarding *find_pf_entry_rx_port(uint16_t portid_rx);
> +
> +#endif
> diff --git a/app/graph/portfwd_priv.h b/app/graph/portfwd_priv.h new file
> mode 100644 index 0000000000..9da1ce6e68
> --- /dev/null
> +++ b/app/graph/portfwd_priv.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Marvell.
> + */
> +
> +#ifndef APP_GRAPH_PORTFWD_PRIV_H
> +#define APP_GRAPH_PORTFWD_PRIV_H
> +
> +struct ethdev_fwd_cmd_tokens {
> +	cmdline_fixed_string_t cmd;
> +	cmdline_fixed_string_t fwd;
> +	cmdline_fixed_string_t tx_dev;
> +	cmdline_fixed_string_t rx_dev;
> +};
> +#endif
> --
> 2.25.1


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 41303 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v2 1/3] node: support to add next node to ethdev Rx node
  2023-11-23  6:15 [PATCH 1/2] node: forward packet from ethdev_rx node Rakesh Kudurumalla
  2023-11-23  6:15 ` [PATCH 2/2] app/graph: implement L2FWD usecase Rakesh Kudurumalla
  2023-11-24  7:45 ` [EXT] [PATCH 1/2] node: forward packet from ethdev_rx node Sunil Kumar Kori
@ 2023-12-04 18:04 ` Rakesh Kudurumalla
  2023-12-04 18:04   ` [PATCH v2 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                     ` (2 more replies)
  2 siblings, 3 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-04 18:04 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
V2: Addressed comments 
    Splitted patches to add command and usecsase
    Updated doc for portforward usecase

 lib/node/ethdev_ctrl.c      | 44 +++++++++++++++++++++++++++++++++++++
 lib/node/rte_node_eth_api.h | 19 ++++++++++++++++
 lib/node/version.map        |  1 +
 3 files changed, 64 insertions(+)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..e057847cb5 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -129,3 +129,47 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t count;
+	uint16_t i = 0;
+
+	if (edge_name == NULL)
+		return -ENODATA;
+
+	count = rte_node_edge_get(id, NULL);
+
+	if (count == RTE_NODE_ID_INVALID)
+		return rc;
+
+	next_nodes = malloc(count);
+	if (next_nodes == NULL)
+		return -ENOMEM;
+
+	count = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto exit;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+exit:
+	free(next_nodes);
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..f99e565b30 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -57,6 +57,25 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   RTE_EDGE_ID_INVALID if id is invalid
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENODATA: If edge_name is not found
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..07abc3a79f 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -16,6 +16,7 @@ EXPERIMENTAL {
 	rte_node_ip6_route_add;
 
 	# added in 23.11
+	rte_node_ethdev_rx_next_update;
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v2 2/3] app/graph: add ethdev forward command
  2023-12-04 18:04 ` [PATCH v2 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
@ 2023-12-04 18:04   ` Rakesh Kudurumalla
  2023-12-04 18:04   ` [PATCH v2 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
  2023-12-05  7:46   ` [PATCH v3 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-04 18:04 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/cli.c         |  1 +
 app/graph/ethdev.c      | 62 +++++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h      |  1 +
 app/graph/ethdev_priv.h |  8 ++++++
 4 files changed, 72 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bceee659a2 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,10 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +892,61 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_name, char *rx_name)
+{
+	struct ethdev *port;
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_name, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_name, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->config.tx_port_id = portid_tx;
+		rc = 0;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_l2_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_l2_cmd,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..e5e5fbc9ae 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -98,6 +105,7 @@ struct ethdev_config {
 		uint32_t queue_size;
 	} tx;
 
+	uint16_t tx_port_id;
 	int promiscuous;
 	uint32_t mtu;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v2 3/3] app/graph: implement port forward usecase
  2023-12-04 18:04 ` [PATCH v2 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2023-12-04 18:04   ` [PATCH v2 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2023-12-04 18:04   ` Rakesh Kudurumalla
  2023-12-05  7:46   ` [PATCH v3 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-04 18:04 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/ethdev.c                           |  12 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 148 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  27 ++++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  84 +++++++++++
 11 files changed, 370 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bceee659a2..d048a65555 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -77,6 +77,18 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+find_txport_by_rxport(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->config.tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..946e14d801 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -33,6 +33,7 @@ extern uint32_t enabled_port_mask;
 
 void ethdev_start(void);
 void ethdev_stop(void);
+int16_t find_txport_by_rxport(uint16_t portid_rx);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..af24a5836a
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; L2 mac forwarding rules
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..718347f568
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; L2 mac forwarding rules
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..a780caa394
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = find_txport_by_rxport(port_id);
+		if (txport) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				return rc;
+		}
+	}
+	return 0;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..33b5e750b2 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -110,6 +124,12 @@ For current use case, following routing table is used:
 On the successful execution of ``l3fwd.cli`` or ``l3fwd_pcap.cli``,
 user needs to send traffic with mentioned DIP.
 
+``l2fwd.cli`` and ``l2fwd_pcap.cli`` creates setup with two network ports.
+Packet received on one port is forwarded to other port.
+
+On the successful execution of ``l2fwd.cli`` or ``l2fwd_pcap.cli``,
+user needs to send traffic on RX port.
+
 For net_pcapX devices, required pcap file should be created and passed to application.
 These pcap files can be created in several ways.
 Scapy is one of the method to get the same:
@@ -321,3 +341,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..6b70af3380
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_rx -> pkt_drop [color="green"]
+}
+
+ -->
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="299pt" height="204pt"
+ viewBox="0.00 0.00 299.40 204.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 200)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-200 295.4,-200 295.4,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="171.9,-196 65.9,-196 65.9,-160 171.9,-160 171.9,-196"/>
+<text text-anchor="middle" x="118.9" y="-174.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="118.9" cy="-91" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="118.9" y="-87.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M118.9,-159.8C118.9,-148.16 118.9,-132.55 118.9,-119.24"/>
+<polygon fill="black" stroke="black" points="122.4,-119.18 118.9,-109.18 115.4,-119.18 122.4,-119.18"/>
+<text text-anchor="middle" x="171.4" y="-130.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="55.9" cy="-18" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="55.9" y="-14.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M104.28,-73.53C96.37,-64.61 86.43,-53.41 77.62,-43.49"/>
+<polygon fill="black" stroke="black" points="80.12,-41.03 70.87,-35.87 74.88,-45.67 80.12,-41.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="181.9" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="181.9" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_rx&#45;&gt;pkt_drop -->
+<g id="edge3" class="edge">
+<title>ethdev_rx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="green" d="M133.51,-73.53C141.54,-64.48 151.65,-53.09 160.55,-43.06"/>
+<polygon fill="green" stroke="green" points="163.34,-45.18 167.36,-35.38 158.11,-40.53 163.34,-45.18"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="291.4,-196 190.4,-196 190.4,-160 291.4,-160 291.4,-196"/>
+<text text-anchor="middle" x="240.9" y="-174.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v3 1/3] node: support to add next node to ethdev Rx node
  2023-12-04 18:04 ` [PATCH v2 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2023-12-04 18:04   ` [PATCH v2 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2023-12-04 18:04   ` [PATCH v2 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2023-12-05  7:46   ` Rakesh Kudurumalla
  2023-12-05  7:46     ` [PATCH v3 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                       ` (2 more replies)
  2 siblings, 3 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-05  7:46 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
V3: Resolve compilation Issue

 lib/node/ethdev_ctrl.c      | 45 +++++++++++++++++++++++++++++++++++++
 lib/node/rte_node_eth_api.h | 19 ++++++++++++++++
 lib/node/version.map        |  1 +
 3 files changed, 65 insertions(+)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..4580c123d1 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -3,6 +3,7 @@
  */
 
 #include <stdlib.h>
+#include <errno.h>
 
 #include <rte_ethdev.h>
 #include <rte_graph.h>
@@ -129,3 +130,47 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t count;
+	uint16_t i = 0;
+
+	if (edge_name == NULL)
+		return -ENODATA;
+
+	count = rte_node_edge_get(id, NULL);
+
+	if (count == RTE_NODE_ID_INVALID)
+		return rc;
+
+	next_nodes = malloc(count);
+	if (next_nodes == NULL)
+		return -ENOMEM;
+
+	count = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto exit;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+exit:
+	free(next_nodes);
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..f99e565b30 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -57,6 +57,25 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   RTE_EDGE_ID_INVALID if id is invalid
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENODATA: If edge_name is not found
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..07abc3a79f 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -16,6 +16,7 @@ EXPERIMENTAL {
 	rte_node_ip6_route_add;
 
 	# added in 23.11
+	rte_node_ethdev_rx_next_update;
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v3 2/3] app/graph: add ethdev forward command
  2023-12-05  7:46   ` [PATCH v3 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
@ 2023-12-05  7:46     ` Rakesh Kudurumalla
  2023-12-05  7:46     ` [PATCH v3 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
  2023-12-05  9:27     ` [PATCH v4 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-05  7:46 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/cli.c         |  1 +
 app/graph/ethdev.c      | 62 +++++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h      |  1 +
 app/graph/ethdev_priv.h |  8 ++++++
 4 files changed, 72 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bceee659a2 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,10 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +892,61 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_name, char *rx_name)
+{
+	struct ethdev *port;
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_name, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_name, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->config.tx_port_id = portid_tx;
+		rc = 0;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_l2_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_l2_cmd,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..e5e5fbc9ae 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -98,6 +105,7 @@ struct ethdev_config {
 		uint32_t queue_size;
 	} tx;
 
+	uint16_t tx_port_id;
 	int promiscuous;
 	uint32_t mtu;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v3 3/3] app/graph: implement port forward usecase
  2023-12-05  7:46   ` [PATCH v3 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2023-12-05  7:46     ` [PATCH v3 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2023-12-05  7:46     ` Rakesh Kudurumalla
  2023-12-05  9:27     ` [PATCH v4 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-05  7:46 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/ethdev.c                           |  12 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 148 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  27 ++++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  84 +++++++++++
 11 files changed, 370 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bceee659a2..d048a65555 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -77,6 +77,18 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+find_txport_by_rxport(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->config.tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..946e14d801 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -33,6 +33,7 @@ extern uint32_t enabled_port_mask;
 
 void ethdev_start(void);
 void ethdev_stop(void);
+int16_t find_txport_by_rxport(uint16_t portid_rx);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..af24a5836a
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; L2 mac forwarding rules
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..718347f568
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; L2 mac forwarding rules
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..a780caa394
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = find_txport_by_rxport(port_id);
+		if (txport) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				return rc;
+		}
+	}
+	return 0;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..33b5e750b2 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -110,6 +124,12 @@ For current use case, following routing table is used:
 On the successful execution of ``l3fwd.cli`` or ``l3fwd_pcap.cli``,
 user needs to send traffic with mentioned DIP.
 
+``l2fwd.cli`` and ``l2fwd_pcap.cli`` creates setup with two network ports.
+Packet received on one port is forwarded to other port.
+
+On the successful execution of ``l2fwd.cli`` or ``l2fwd_pcap.cli``,
+user needs to send traffic on RX port.
+
 For net_pcapX devices, required pcap file should be created and passed to application.
 These pcap files can be created in several ways.
 Scapy is one of the method to get the same:
@@ -321,3 +341,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..6b70af3380
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_rx -> pkt_drop [color="green"]
+}
+
+ -->
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="299pt" height="204pt"
+ viewBox="0.00 0.00 299.40 204.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 200)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-200 295.4,-200 295.4,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="171.9,-196 65.9,-196 65.9,-160 171.9,-160 171.9,-196"/>
+<text text-anchor="middle" x="118.9" y="-174.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="118.9" cy="-91" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="118.9" y="-87.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M118.9,-159.8C118.9,-148.16 118.9,-132.55 118.9,-119.24"/>
+<polygon fill="black" stroke="black" points="122.4,-119.18 118.9,-109.18 115.4,-119.18 122.4,-119.18"/>
+<text text-anchor="middle" x="171.4" y="-130.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="55.9" cy="-18" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="55.9" y="-14.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M104.28,-73.53C96.37,-64.61 86.43,-53.41 77.62,-43.49"/>
+<polygon fill="black" stroke="black" points="80.12,-41.03 70.87,-35.87 74.88,-45.67 80.12,-41.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="181.9" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="181.9" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_rx&#45;&gt;pkt_drop -->
+<g id="edge3" class="edge">
+<title>ethdev_rx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="green" d="M133.51,-73.53C141.54,-64.48 151.65,-53.09 160.55,-43.06"/>
+<polygon fill="green" stroke="green" points="163.34,-45.18 167.36,-35.38 158.11,-40.53 163.34,-45.18"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="291.4,-196 190.4,-196 190.4,-160 291.4,-160 291.4,-196"/>
+<text text-anchor="middle" x="240.9" y="-174.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v4 1/3] node: support to add next node to ethdev Rx node
  2023-12-05  7:46   ` [PATCH v3 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2023-12-05  7:46     ` [PATCH v3 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2023-12-05  7:46     ` [PATCH v3 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2023-12-05  9:27     ` Rakesh Kudurumalla
  2023-12-05  9:27       ` [PATCH v4 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                         ` (4 more replies)
  2 siblings, 5 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-05  9:27 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
v4: Resolve compilation issues

 lib/node/ethdev_ctrl.c      | 45 +++++++++++++++++++++++++++++++++++++
 lib/node/rte_node_eth_api.h | 19 ++++++++++++++++
 lib/node/version.map        |  1 +
 3 files changed, 65 insertions(+)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..0faf4c19f2 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -3,6 +3,7 @@
  */
 
 #include <stdlib.h>
+#include <errno.h>
 
 #include <rte_ethdev.h>
 #include <rte_graph.h>
@@ -129,3 +130,47 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t count;
+	uint16_t i = 0;
+
+	if (edge_name == NULL)
+		return rc;
+
+	count = rte_node_edge_get(id, NULL);
+
+	if (count == RTE_NODE_ID_INVALID)
+		return rc;
+
+	next_nodes = malloc(count);
+	if (next_nodes == NULL)
+		return -ENOMEM;
+
+	count = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto exit;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+exit:
+	free(next_nodes);
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..b082a5bec1 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -23,6 +23,7 @@ extern "C" {
 #include <rte_compat.h>
 #include <rte_common.h>
 #include <rte_mempool.h>
+#include <rte_graph.h>
 
 /**
  * Port config for ethdev_rx and ethdev_tx node.
@@ -57,6 +58,24 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   RTE_EDGE_ID_INVALID if id is invalid
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..07abc3a79f 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -16,6 +16,7 @@ EXPERIMENTAL {
 	rte_node_ip6_route_add;
 
 	# added in 23.11
+	rte_node_ethdev_rx_next_update;
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v4 2/3] app/graph: add ethdev forward command
  2023-12-05  9:27     ` [PATCH v4 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
@ 2023-12-05  9:27       ` Rakesh Kudurumalla
  2023-12-07 10:38         ` Sunil Kumar Kori
  2023-12-05  9:27       ` [PATCH v4 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
                         ` (3 subsequent siblings)
  4 siblings, 1 reply; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-05  9:27 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/cli.c         |  1 +
 app/graph/ethdev.c      | 62 +++++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h      |  1 +
 app/graph/ethdev_priv.h |  8 ++++++
 4 files changed, 72 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bceee659a2 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,10 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +892,61 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_name, char *rx_name)
+{
+	struct ethdev *port;
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_name, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_name, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->config.tx_port_id = portid_tx;
+		rc = 0;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_l2_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_l2_cmd,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..e5e5fbc9ae 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -98,6 +105,7 @@ struct ethdev_config {
 		uint32_t queue_size;
 	} tx;
 
+	uint16_t tx_port_id;
 	int promiscuous;
 	uint32_t mtu;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v4 3/3] app/graph: implement port forward usecase
  2023-12-05  9:27     ` [PATCH v4 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2023-12-05  9:27       ` [PATCH v4 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2023-12-05  9:27       ` Rakesh Kudurumalla
  2023-12-07 11:07         ` Sunil Kumar Kori
  2023-12-07  8:26       ` [EXT] [PATCH v4 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
                         ` (2 subsequent siblings)
  4 siblings, 1 reply; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-05  9:27 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/ethdev.c                           |  12 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 148 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  27 ++++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  84 +++++++++++
 11 files changed, 370 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bceee659a2..d048a65555 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -77,6 +77,18 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+find_txport_by_rxport(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->config.tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..946e14d801 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -33,6 +33,7 @@ extern uint32_t enabled_port_mask;
 
 void ethdev_start(void);
 void ethdev_stop(void);
+int16_t find_txport_by_rxport(uint16_t portid_rx);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..af24a5836a
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; L2 mac forwarding rules
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..718347f568
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; L2 mac forwarding rules
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..a780caa394
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = find_txport_by_rxport(port_id);
+		if (txport) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				return rc;
+		}
+	}
+	return 0;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..33b5e750b2 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -110,6 +124,12 @@ For current use case, following routing table is used:
 On the successful execution of ``l3fwd.cli`` or ``l3fwd_pcap.cli``,
 user needs to send traffic with mentioned DIP.
 
+``l2fwd.cli`` and ``l2fwd_pcap.cli`` creates setup with two network ports.
+Packet received on one port is forwarded to other port.
+
+On the successful execution of ``l2fwd.cli`` or ``l2fwd_pcap.cli``,
+user needs to send traffic on RX port.
+
 For net_pcapX devices, required pcap file should be created and passed to application.
 These pcap files can be created in several ways.
 Scapy is one of the method to get the same:
@@ -321,3 +341,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..6b70af3380
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_rx -> pkt_drop [color="green"]
+}
+
+ -->
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="299pt" height="204pt"
+ viewBox="0.00 0.00 299.40 204.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 200)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-200 295.4,-200 295.4,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="171.9,-196 65.9,-196 65.9,-160 171.9,-160 171.9,-196"/>
+<text text-anchor="middle" x="118.9" y="-174.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="118.9" cy="-91" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="118.9" y="-87.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M118.9,-159.8C118.9,-148.16 118.9,-132.55 118.9,-119.24"/>
+<polygon fill="black" stroke="black" points="122.4,-119.18 118.9,-109.18 115.4,-119.18 122.4,-119.18"/>
+<text text-anchor="middle" x="171.4" y="-130.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="55.9" cy="-18" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="55.9" y="-14.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M104.28,-73.53C96.37,-64.61 86.43,-53.41 77.62,-43.49"/>
+<polygon fill="black" stroke="black" points="80.12,-41.03 70.87,-35.87 74.88,-45.67 80.12,-41.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="181.9" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="181.9" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_rx&#45;&gt;pkt_drop -->
+<g id="edge3" class="edge">
+<title>ethdev_rx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="green" d="M133.51,-73.53C141.54,-64.48 151.65,-53.09 160.55,-43.06"/>
+<polygon fill="green" stroke="green" points="163.34,-45.18 167.36,-35.38 158.11,-40.53 163.34,-45.18"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="291.4,-196 190.4,-196 190.4,-160 291.4,-160 291.4,-196"/>
+<text text-anchor="middle" x="240.9" y="-174.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [EXT] [PATCH v4 1/3] node: support to add next node to ethdev Rx node
  2023-12-05  9:27     ` [PATCH v4 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2023-12-05  9:27       ` [PATCH v4 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2023-12-05  9:27       ` [PATCH v4 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2023-12-07  8:26       ` Sunil Kumar Kori
  2023-12-07  9:30       ` David Marchand
  2023-12-15  9:15       ` [PATCH v5 " Rakesh Kudurumalla
  4 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2023-12-07  8:26 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Nithin Kumar Dabilpuram, Pavan Nikhilesh Bhagavatula
  Cc: dev, Jerin Jacob Kollanukkaran, Rakesh Kudurumalla

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Tuesday, December 5, 2023 2:57 PM
> To: Nithin Kumar Dabilpuram <ndabilpuram@marvell.com>; Pavan
> Nikhilesh Bhagavatula <pbhagavatula@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Subject: [EXT] [PATCH v4 1/3] node: support to add next node to ethdev Rx
> node
> 
> External Email
> 
> ----------------------------------------------------------------------
> By default all packets received on ethdev_rx node is forwarded to pkt_cls
> node.This patch provides library support to add a new node as next node to
> ethdev_rx node and forward packet to new node from rx node.
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
> v4: Resolve compilation issues
> 
>  lib/node/ethdev_ctrl.c      | 45
> +++++++++++++++++++++++++++++++++++++
>  lib/node/rte_node_eth_api.h | 19 ++++++++++++++++
>  lib/node/version.map        |  1 +
>  3 files changed, 65 insertions(+)
> 
> diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c index
> d564b80e37..0faf4c19f2 100644
> --- a/lib/node/ethdev_ctrl.c
> +++ b/lib/node/ethdev_ctrl.c
> @@ -3,6 +3,7 @@
>   */
> 
>  #include <stdlib.h>
> +#include <errno.h>
> 
>  #include <rte_ethdev.h>
>  #include <rte_graph.h>
> @@ -129,3 +130,47 @@ rte_node_eth_config(struct
> rte_node_ethdev_config *conf, uint16_t nb_confs,
>  	ctrl.nb_graphs = nb_graphs;
>  	return 0;
>  }
> +
> +int
> +rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name) {
> +	struct ethdev_rx_node_main *data;
> +	ethdev_rx_node_elem_t *elem;
> +	char **next_nodes;
> +	int rc = -EINVAL;
> +	uint32_t count;
> +	uint16_t i = 0;
> +
> +	if (edge_name == NULL)
> +		return rc;
> +
Better to use goto scheme. 

> +	count = rte_node_edge_get(id, NULL);
> +
> +	if (count == RTE_NODE_ID_INVALID)
> +		return rc;
> +
> +	next_nodes = malloc(count);
> +	if (next_nodes == NULL)
> +		return -ENOMEM;
> +
> +	count = rte_node_edge_get(id, next_nodes);
> +
Here it looks like that loop can misbehave for invalid edge_name. I might be wrong.
Consider the case. 
1. edge_name = "test_name"
2. number of elements in next_nodes is 2 and no element is matching with edge_name.
In this case, loop might misbehave as there will not be any NULL entry. 

Did you try a negative test case on this API ?

> +	while (next_nodes[i] != NULL) {
> +		if (strcmp(edge_name, next_nodes[i]) == 0) {
> +			data = ethdev_rx_get_node_data_get();
> +			elem = data->head;
> +			while (elem->next != data->head) {
> +				if (elem->nid == id) {
> +					elem->ctx.cls_next = i;
> +					rc = 0;
> +					goto exit;
> +				}
> +				elem = elem->next;
> +			}
> +		}
> +		i++;
> +	}
> +exit:
> +	free(next_nodes);
> +	return rc;
> +}
> diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h index
> eaae50772d..b082a5bec1 100644
> --- a/lib/node/rte_node_eth_api.h
> +++ b/lib/node/rte_node_eth_api.h
> @@ -23,6 +23,7 @@ extern "C" {
>  #include <rte_compat.h>
>  #include <rte_common.h>
>  #include <rte_mempool.h>
> +#include <rte_graph.h>
> 
>  /**
>   * Port config for ethdev_rx and ethdev_tx node.
> @@ -57,6 +58,24 @@ struct rte_node_ethdev_config {
>   */
>  int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
>  			uint16_t cnt, uint16_t nb_graphs);
> +
> +/**
> + * Update ethdev rx next node.
> + *
> + * @param id
> + *   Node id whose edge is to be updated.
> + * @param edge_name
> + *   Name of the next node.
> + *
> + * @return
> + *   RTE_EDGE_ID_INVALID if id is invalid
I think, This is not needed now. Below error code handles for invalid ID too. 

> + *   ENINVAL: Either of input parameters are invalid
> + *   ENOMEM: If memory allocation failed
> + *   0 on successful initialization.
> + */
> +__rte_experimental
> +int rte_node_ethdev_rx_next_update(rte_node_t id, const char
> +*edge_name);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/node/version.map b/lib/node/version.map index
> 99ffcdd414..07abc3a79f 100644
> --- a/lib/node/version.map
> +++ b/lib/node/version.map
> @@ -16,6 +16,7 @@ EXPERIMENTAL {
>  	rte_node_ip6_route_add;
> 
>  	# added in 23.11
> +	rte_node_ethdev_rx_next_update;
>  	rte_node_ip4_reassembly_configure;
>  	rte_node_udp4_dst_port_add;
>  	rte_node_udp4_usr_node_add;
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v4 1/3] node: support to add next node to ethdev Rx node
  2023-12-05  9:27     ` [PATCH v4 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
                         ` (2 preceding siblings ...)
  2023-12-07  8:26       ` [EXT] [PATCH v4 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
@ 2023-12-07  9:30       ` David Marchand
  2023-12-15  9:15       ` [PATCH v5 " Rakesh Kudurumalla
  4 siblings, 0 replies; 45+ messages in thread
From: David Marchand @ 2023-12-07  9:30 UTC (permalink / raw)
  To: Rakesh Kudurumalla; +Cc: Nithin Dabilpuram, Pavan Nikhilesh, dev, jerinj

On Tue, Dec 5, 2023 at 10:27 AM Rakesh Kudurumalla
<rkudurumalla@marvell.com> wrote:
> diff --git a/lib/node/version.map b/lib/node/version.map
> index 99ffcdd414..07abc3a79f 100644
> --- a/lib/node/version.map
> +++ b/lib/node/version.map
> @@ -16,6 +16,7 @@ EXPERIMENTAL {
>         rte_node_ip6_route_add;
>
>         # added in 23.11
> +       rte_node_ethdev_rx_next_update;
>         rte_node_ip4_reassembly_configure;
>         rte_node_udp4_dst_port_add;
>         rte_node_udp4_usr_node_add;


This is added in v24.03.


-- 
David Marchand


^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [PATCH v4 2/3] app/graph: add ethdev forward command
  2023-12-05  9:27       ` [PATCH v4 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2023-12-07 10:38         ` Sunil Kumar Kori
  0 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2023-12-07 10:38 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Rakesh Kudurumalla
  Cc: dev, Jerin Jacob Kollanukkaran, Nithin Kumar Dabilpuram

[-- Attachment #1: Type: text/plain, Size: 5541 bytes --]

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Tuesday, December 5, 2023 2:57 PM
> To: Sunil Kumar Kori <skori@marvell.com>; Rakesh Kudurumalla
> <rkudurumalla@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Nithin
> Kumar Dabilpuram <ndabilpuram@marvell.com>
> Subject: [PATCH v4 2/3] app/graph: add ethdev forward command
> 
> Adds a txport to forward packet for every rxport
> 
> Mapping will be used to forward packets to txport received on rxport
> 
> Following commands are exposed:
> 	- ethdev forward <tx_dev_name> <rx_dev_name>"
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  app/graph/cli.c         |  1 +
>  app/graph/ethdev.c      | 62
> +++++++++++++++++++++++++++++++++++++++++
>  app/graph/ethdev.h      |  1 +
>  app/graph/ethdev_priv.h |  8 ++++++
>  4 files changed, 72 insertions(+)
> 
> diff --git a/app/graph/cli.c b/app/graph/cli.c index
> 30b12312d6..76f5b8e670 100644
> --- a/app/graph/cli.c
> +++ b/app/graph/cli.c
> @@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
>  	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
> +	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
>  	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx, diff --git
> a/app/graph/ethdev.c b/app/graph/ethdev.c index
> c9b09168c1..bceee659a2 100644
> --- a/app/graph/ethdev.c
> +++ b/app/graph/ethdev.c
> @@ -38,6 +38,10 @@ cmd_ethdev_ip4_addr_help[] = "ethdev
> <ethdev_name> ip4 addr add <ip> netmask <ma  static const char
> cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip>
> netmask <mask>";
> 
> +static const char
> +cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name>
> +<rx_dev_name>";
> +
> +
Remove extra line.

>  static struct rte_eth_conf port_conf_default = {
>  	.link_speeds = 0,
>  	.rxmode = {
> @@ -888,3 +892,61 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
>  		NULL,
>  	},
>  };
> +
> +static int
> +ethdev_forward_config(char *tx_name, char *rx_name) {
Replace tx_name -> tx_dev and rx_name -> rx_dev

> +	struct ethdev *port;
> +	uint16_t portid_rx = 0;
> +	uint16_t portid_tx = 0;
> +	int rc = -EINVAL;
> +
Use reverse x-max tree method to declare the variables.

> +	rc = rte_eth_dev_get_port_by_name(tx_name, &portid_tx);
> +	if (rc < 0)
> +		return rc;
> +
> +	rc = rte_eth_dev_get_port_by_name(rx_name, &portid_rx);
> +	if (rc < 0)
> +		return rc;
> +
> +	port = ethdev_port_by_id(portid_rx);
> +	if (port) {
> +		port->config.tx_port_id = portid_tx;
> +		rc = 0;
> +	}
> +
If port is NULL then rc will be returned with value >= 0. Means in case of failure, success  is returned. 

> +	return rc;
> +}
> +
> +static void
> +cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline
> +*cl, void *data __rte_unused) {
> +	struct ethdev_fwd_cmd_tokens *res = parsed_result;
> +	int rc = -EINVAL;
> +
> +	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
> +	if (rc < 0)
> +		printf(MSG_CMD_FAIL, res->cmd);
> +}
> +
> +cmdline_parse_token_string_t ethdev_l2_cmd =
Better to rename as ethdev_forward_xyz to align with other's naming convention.

> +	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd,
> "ethdev");
> +cmdline_parse_token_string_t ethdev_fwd_cmd =
> +	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd,
> +"forward"); cmdline_parse_token_string_t ethdev_tx_device =
> +	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens,
> tx_dev, NULL);
> +cmdline_parse_token_string_t ethdev_rx_device =
> +	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens,
> rx_dev, NULL);
> +
> +cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
> +	.f = cli_ethdev_forward,
> +	.data = NULL,
> +	.help_str = cmd_ethdev_forward_help,
> +	.tokens = {
> +	       (void *)&ethdev_l2_cmd,
> +	       (void *)&ethdev_fwd_cmd,
> +	       (void *)&ethdev_tx_device,
> +	       (void *)&ethdev_rx_device,
> +	       NULL,
> +	},
> +};
> diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h index
> 94d3247a2c..836052046b 100644
> --- a/app/graph/ethdev.h
> +++ b/app/graph/ethdev.h
> @@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
> extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;  extern
> cmdline_parse_inst_t ethdev_ip4_cmd_ctx;  extern cmdline_parse_inst_t
> ethdev_ip6_cmd_ctx;
> +extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
>  extern cmdline_parse_inst_t ethdev_cmd_ctx;  extern
> cmdline_parse_inst_t ethdev_help_cmd_ctx;
> 
> diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h index
> f231f3f3e1..e5e5fbc9ae 100644
> --- a/app/graph/ethdev_priv.h
> +++ b/app/graph/ethdev_priv.h
> @@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
>  	cmdline_fixed_string_t mask;
>  };
> 
> +struct ethdev_fwd_cmd_tokens {
> +	cmdline_fixed_string_t cmd;
> +	cmdline_fixed_string_t fwd;
> +	cmdline_fixed_string_t tx_dev;
> +	cmdline_fixed_string_t rx_dev;
> +};
> +
>  struct ethdev_cmd_tokens {
>  	cmdline_fixed_string_t cmd;
>  	cmdline_fixed_string_t dev;
> @@ -98,6 +105,7 @@ struct ethdev_config {
>  		uint32_t queue_size;
>  	} tx;
> 
> +	uint16_t tx_port_id;
Please move it to struct ethdev{}.

>  	int promiscuous;
>  	uint32_t mtu;
>  };
> --
> 2.25.1


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 37229 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [PATCH v4 3/3] app/graph: implement port forward usecase
  2023-12-05  9:27       ` [PATCH v4 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2023-12-07 11:07         ` Sunil Kumar Kori
  0 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2023-12-07 11:07 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Rakesh Kudurumalla
  Cc: dev, Jerin Jacob Kollanukkaran, Nithin Kumar Dabilpuram

[-- Attachment #1: Type: text/plain, Size: 18710 bytes --]

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Tuesday, December 5, 2023 2:57 PM
> To: Sunil Kumar Kori <skori@marvell.com>; Rakesh Kudurumalla
> <rkudurumalla@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Nithin
> Kumar Dabilpuram <ndabilpuram@marvell.com>
> Subject: [PATCH v4 3/3] app/graph: implement port forward usecase
> 
> Added portforward usecase.In this usecase packets received Rx port is
> forwarded to respective Tx port.
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  app/graph/ethdev.c                           |  12 ++
>  app/graph/ethdev.h                           |   1 +
>  app/graph/examples/l2fwd.cli                 |  41 +++++
>  app/graph/examples/l2fwd_pcap.cli            |  37 +++++
>  app/graph/graph.c                            |   8 +-
>  app/graph/l2fwd.c                            | 148 +++++++++++++++++++
>  app/graph/l2fwd.h                            |  11 ++
>  app/graph/meson.build                        |   1 +
>  app/graph/module_api.h                       |   1 +
>  doc/guides/tools/graph.rst                   |  27 ++++
>  doc/guides/tools/img/graph-usecase-l2fwd.svg |  84 +++++++++++
>  11 files changed, 370 insertions(+), 1 deletion(-)  create mode 100644
> app/graph/examples/l2fwd.cli  create mode 100644
> app/graph/examples/l2fwd_pcap.cli  create mode 100644
> app/graph/l2fwd.c  create mode 100644 app/graph/l2fwd.h  create mode
> 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg
> 
> diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c index
> bceee659a2..d048a65555 100644
> --- a/app/graph/ethdev.c
> +++ b/app/graph/ethdev.c
> @@ -77,6 +77,18 @@ ethdev_port_by_id(uint16_t port_id)
>  	return NULL;
>  }
> 
> +int16_t
> +find_txport_by_rxport(uint16_t portid_rx) {
> +	int portid = -EINVAL;
> +	struct ethdev *port;
Need one line space here. 

> +	port = ethdev_port_by_id(portid_rx);
> +	if (port)
> +		portid = port->config.tx_port_id;
> +
> +	return portid;
> +}
> +
>  void *
>  ethdev_mempool_list_by_portid(uint16_t portid)  { diff --git
> a/app/graph/ethdev.h b/app/graph/ethdev.h index
> 836052046b..946e14d801 100644
> --- a/app/graph/ethdev.h
> +++ b/app/graph/ethdev.h
> @@ -33,6 +33,7 @@ extern uint32_t enabled_port_mask;
> 
>  void ethdev_start(void);
>  void ethdev_stop(void);
> +int16_t find_txport_by_rxport(uint16_t portid_rx);
>  void *ethdev_mempool_list_by_portid(uint16_t portid);  int16_t
> ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);  int16_t
> ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask); diff --git
> a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli new file
> mode 100644 index 0000000000..af24a5836a
> --- /dev/null
> +++ b/app/graph/examples/l2fwd.cli
> @@ -0,0 +1,41 @@
> +; SPDX-License-Identifier: BSD-3-Clause ; Copyright(c) 2023 Marvell.
> +
> +;
> +; Graph configuration for given usecase ; graph l2fwd coremask 0xff bsz
> +32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file
> +/tmp/output.pcap
> +
> +;
> +; Mempools to be attached with ethdev
> +;
> +mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
> +
> +;
> +; DPDK devices and configuration.
> +;
> +; Note: Customize the parameters below to match your setup.
> +;
> +ethdev 0002:01:00.1 rxq 1 txq 8 mempool0 ethdev 0002:01:00.4 rxq 1 txq
> +8 mempool0 ethdev 0002:01:00.6 rxq 1 txq 8 mempool0 ethdev
> 0002:02:00.0
> +rxq 1 txq 8 mempool0
> +
> +;
> +; L2 mac forwarding rules
> +;
Replace "L2 mac forwarding rules" --> "Rx/Tx port mapping"

> +ethdev forward 0002:01:00.4 0002:02:00.0 ethdev forward 0002:01:00.1
> +0002:01:00.6
> +
> +;
> +; Port-Queue-Core mapping for ethdev_rx node ; ethdev_rx map port
> +0002:02:00.0 queue 0 core 1 ethdev_rx map port 0002:01:00.6 queue 0
> +core 2
> +
> +;
> +; Graph start command to create graph.
> +;
> +; Note: No more command should come after this.
> +;
> +graph start
> diff --git a/app/graph/examples/l2fwd_pcap.cli
> b/app/graph/examples/l2fwd_pcap.cli
> new file mode 100644
> index 0000000000..718347f568
> --- /dev/null
> +++ b/app/graph/examples/l2fwd_pcap.cli
> @@ -0,0 +1,37 @@
> +; SPDX-License-Identifier: BSD-3-Clause ; Copyright(c) 2023 Marvell.
> +
> +;
> +; Graph configuration for given usecase ; graph l2fwd coremask 0xff bsz
> +32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file
> +/tmp/output.pcap
> +
> +;
> +; Mempools to be attached with ethdev
> +;
> +mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
> +
> +;
> +; DPDK devices and configuration.
> +;
> +; Note: Customize the parameters below to match your setup.
> +;
> +ethdev net_pcap0 rxq 1 txq 8 mempool0
> +ethdev net_pcap1 rxq 1 txq 8 mempool0
> +
> +;
> +; L2 mac forwarding rules
> +;
> +ethdev forward net_pcap1 net_pcap0
> +
> +;
> +; Port-Queue-Core mapping for ethdev_rx node ; ethdev_rx map port
> +net_pcap0 queue 0 core 1
> +
> +;
> +; Graph start command to create graph.
> +;
> +; Note: No more command should come after this.
> +;
> +graph start
> diff --git a/app/graph/graph.c b/app/graph/graph.c index
> a65723a196..4e0441f1a7 100644
> --- a/app/graph/graph.c
> +++ b/app/graph/graph.c
> @@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size>
> tmo <ns> coremask <bitmask> "
>  		   "model <rtc | mcd | default> pcap_enable <0 | 1>
> num_pcap_pkts <num>"
>  		   "pcap_file <output_capture_file>";
> 
> -static const char * const supported_usecases[] = {"l3fwd"};
> +static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
>  struct graph_config graph_config;
>  bool graph_started;
> 
> @@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result,
> __rte_unused struct cmdline *c
>  				break;
>  			}
>  		}
> +		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
> +			if (graph_config.usecases[i].enabled) {
> +				rc  = usecase_l2fwd_configure(conf,
> nb_conf, nb_graphs);
> +				break;
> +			}
> +		}
>  	}
> 
>  	if (!rc)
> diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c new file mode 100644
> index 0000000000..a780caa394
> --- /dev/null
> +++ b/app/graph/l2fwd.c
> @@ -0,0 +1,148 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Marvell.
> + */
> +
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <rte_common.h>
> +#include <rte_ethdev.h>
> +#include <rte_graph.h>
> +#include <rte_graph_worker.h>
> +#include <rte_lcore.h>
> +#include <rte_node_eth_api.h>
> +
> +#include "module_api.h"
> +
> +static int
> +l2fwd_pattern_configure(void)
> +{
> +	struct rte_graph_param graph_conf;
> +	const char **node_patterns;
> +	uint64_t pcap_pkts_count;
> +	struct lcore_conf *qconf;
> +	uint16_t nb_patterns;
> +	uint8_t pcap_ena;
> +	char *pcap_file;
> +	int lcore_id;
> +
> +	nb_patterns = 0;
> +	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX +
> nb_patterns) *
> +			sizeof(*node_patterns));
> +	if (!node_patterns)
> +		return -ENOMEM;
> +
> +	memset(&graph_conf, 0, sizeof(graph_conf));
> +	graph_conf.node_patterns = node_patterns;
> +
> +	/* Pcap config */
> +	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count,
> &pcap_file);
> +	graph_conf.pcap_enable = pcap_ena;
> +	graph_conf.num_pkt_to_capture = pcap_pkts_count;
> +	graph_conf.pcap_filename = strdup(pcap_file);
> +
> +	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
> +		rte_graph_t graph_id;
> +		rte_edge_t i;
> +
> +		if (rte_lcore_is_enabled(lcore_id) == 0)
> +			continue;
> +
> +		qconf = &lcore_conf[lcore_id];
> +
> +		/* Skip graph creation if no source exists */
> +		if (!qconf->n_rx_queue)
> +			continue;
> +
> +		/* Add rx node patterns of this lcore */
> +		for (i = 0; i < qconf->n_rx_queue; i++) {
> +			graph_conf.node_patterns[nb_patterns + i] =
> +				qconf->rx_queue_list[i].node_name;
> +		}
> +
> +		graph_conf.nb_node_patterns = nb_patterns + i;
> +		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
> +
> +		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
> +				lcore_id);
> +
> +		graph_id = rte_graph_create(qconf->name, &graph_conf);
> +		if (graph_id == RTE_GRAPH_ID_INVALID)
> +			rte_exit(EXIT_FAILURE,
> +					"rte_graph_create(): graph_id invalid"
> +					" for lcore %u\n", lcore_id);
> +
> +		qconf->graph_id = graph_id;
> +		qconf->graph = rte_graph_lookup(qconf->name);
> +		/* >8 End of graph initialization. */
> +		if (!qconf->graph)
> +			rte_exit(EXIT_FAILURE,
> +					"rte_graph_lookup(): graph %s not
> found\n",
> +					qconf->name);
> +	}
> +
> +	/* Launch per-lcore init on every worker lcore */
> +	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
> +
> +	/* Accumulate and print stats on main until exit */
> +	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
> +		graph_stats_print();
> +
> +	return 0;
> +}
> +
> +static int
> +ethdev_rx_to_tx_node_link(uint32_t lcore_id) {
> +	char name[RTE_NODE_NAMESIZE];
> +	const char *next_node = name;
> +	struct lcore_conf *qconf;
> +	uint16_t queue, port_id;
> +	rte_node_t rx_id;
> +	int16_t txport;
> +	int rc;
> +
> +	qconf = &lcore_conf[lcore_id];
> +
> +	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
> +		port_id = qconf->rx_queue_list[queue].port_id;
> +		txport = find_txport_by_rxport(port_id);
> +		if (txport) {
> +			rx_id = rte_node_from_name(qconf-
> >rx_queue_list[queue].node_name);
> +			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
> +			rte_node_edge_update(rx_id,
> RTE_EDGE_ID_INVALID, &next_node, 1);
> +			rc = rte_node_ethdev_rx_next_update(rx_id, name);
> +			if (rc)
> +				return rc;
> +		}
> +	}
> +	return 0;
> +}
> +
> +
> +int
> +usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t
> +nb_confs, uint16_t nb_graphs) {
> +	uint32_t lcore_id;
> +	int rc;
> +
> +	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
> +	if (rc)
> +		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
> +
> +	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
> +		rc = ethdev_rx_to_tx_node_link(lcore_id);
> +		if (rc)
> +			rte_exit(EXIT_FAILURE, "rte_node_eth_config:
> err=%d\n", rc);
> +	}
> +
> +	rc = l2fwd_pattern_configure();
> +	if (rc)
> +		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n",
> rc);
> +
> +	return rc;
> +}
> diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h new file mode 100644
> index 0000000000..3486ce52b2
> --- /dev/null
> +++ b/app/graph/l2fwd.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Marvell.
> + */
> +
> +#ifndef APP_GRAPH_L2FWD_H
> +#define APP_GRAPH_L2FWD_H
> +
> +int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf,
> uint16_t nb_conf,
> +			    uint16_t nb_graphs);
> +
> +#endif
> diff --git a/app/graph/meson.build b/app/graph/meson.build index
> 5b0f966d99..edd6b17ebc 100644
> --- a/app/graph/meson.build
> +++ b/app/graph/meson.build
> @@ -17,6 +17,7 @@ sources = files(
>          'graph.c',
>          'ip4_route.c',
>          'ip6_route.c',
> +        'l2fwd.c',
>          'l3fwd.c',
>          'main.c',
>          'mempool.c',
> diff --git a/app/graph/module_api.h b/app/graph/module_api.h index
> 7193e0b616..c80eeb704c 100644
> --- a/app/graph/module_api.h
> +++ b/app/graph/module_api.h
> @@ -13,6 +13,7 @@
>  #include "ethdev.h"
>  #include "ethdev_rx.h"
>  #include "graph.h"
> +#include "l2fwd.h"
>  #include "l3fwd.h"
>  #include "mempool.h"
>  #include "neigh.h"
> diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst index
> 1855d12891..33b5e750b2 100644
> --- a/doc/guides/tools/graph.rst
> +++ b/doc/guides/tools/graph.rst
> @@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP
> vdev network devices.
>  To demonstrate, corresponding ``.cli`` files are available at
> ``app/graph/examples/``  named as ``l3fwd.cli`` and
> ``l3fwd_pcap.cli`` respectively.
> 
> +l2fwd
> +~~~~~
> +
> +This use case is supported for both H/W and PCAP vdev network devices.
> +To demonstrate, corresponding ``.cli`` files are available at
> +``app/graph/examples/`` named as ``l2fwd.cli`` and
> ``l2fwd_pcap.cli`` respectively.
> +
>  Example Commands
>  ^^^^^^^^^^^^^^^^
>  For H/W devices
> @@ -86,6 +93,9 @@ For H/W devices
>     ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
>                  -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
> 
> +   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
> +                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
> +
>  For net_pcapX devices
> 
>  .. code-block:: console
> @@ -94,6 +104,10 @@ For net_pcapX devices
>                          --
> vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pca
> p
>                          -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
> 
> +   ./dpdk-graph -c 0xff --
> vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pca
> p
> +                        --
> vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pca
> p
> +                        -- -s
> + <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
> +
>  Verifying traffic
>  ^^^^^^^^^^^^^^^^^
> 
> @@ -110,6 +124,12 @@ For current use case, following routing table is
> used:
>  On the successful execution of ``l3fwd.cli`` or ``l3fwd_pcap.cli``,  user
> needs to send traffic with mentioned DIP.
> 
> +``l2fwd.cli`` and ``l2fwd_pcap.cli`` creates setup with two network
> ports.
> +Packet received on one port is forwarded to other port.
> +
> +On the successful execution of ``l2fwd.cli`` or ``l2fwd_pcap.cli``,
> +user needs to send traffic on RX port.
> +
>  For net_pcapX devices, required pcap file should be created and passed to
> application.
>  These pcap files can be created in several ways.
>  Scapy is one of the method to get the same:
> @@ -321,3 +341,10 @@ l3fwd
>  .. _figure_l3fwd_graph:
> 
>  .. figure:: img/graph-usecase-l3fwd.*
> +
> +l2fwd
> +~~~~~
> +
> +.. _figure_l2fwd_graph:
> +
> +.. figure:: img/graph-usecase-l2fwd.*
> diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg
> b/doc/guides/tools/img/graph-usecase-l2fwd.svg
> new file mode 100644
> index 0000000000..6b70af3380
> --- /dev/null
> +++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
> @@ -0,0 +1,84 @@
> +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE
> svg
> +PUBLIC "-//W3C//DTD SVG 1.1//EN"
> + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> +<!-- Generated by graphviz version 2.43.0 (0)
> + -->
> +<!-- SPDX-License-Identifier: BSD-3-Clause -->
> +<!-- Copyright(C) 2023 Marvell. -->
> +<!--
> +
> +Generated with following command
> +dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
> +
> +cat dot.dot
> +digraph dpdk_app_graph_l2fwd_nodes_flow {
> +    ingress_port [shape=rect]
> +    ethdev_rx
> +    ethdev_tx
> +    pkt_drop
> +    egress_port  [shape=rect]
> +
> +    ingress_port -> ethdev_rx [label="ingress packet"]
> +
> +    ethdev_rx -> ethdev_tx
> +    ethdev_rx -> pkt_drop [color="green"] }
> +
ethdev_tx -> egress_port mapping is missing.
Also to align, use same coloring methods as in l3fwd.

> + -->
> +<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 --> <svg
> +width="299pt" height="204pt"
> + viewBox="0.00 0.00 299.40 204.00" xmlns="http://www.w3.org/2000/svg"
> +xmlns:xlink="http://www.w3.org/1999/xlink">
> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0)
> +translate(4 200)"> <title>dpdk_app_graph_l2fwd_nodes_flow</title>
> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-200
> +295.4,-200 295.4,4 -4,4"/>
> +<!-- ingress_port -->
> +<g id="node1" class="node">
> +<title>ingress_port</title>
> +<polygon fill="none" stroke="black" points="171.9,-196 65.9,-196
> +65.9,-160 171.9,-160 171.9,-196"/> <text text-anchor="middle" x="118.9"
> +y="-174.3" font-family="Times,serif"
> +font-size="14.00">ingress_port</text>
> +</g>
> +<!-- ethdev_rx -->
> +<g id="node2" class="node">
> +<title>ethdev_rx</title>
> +<ellipse fill="none" stroke="black" cx="118.9" cy="-91" rx="56.59"
> +ry="18"/> <text text-anchor="middle" x="118.9" y="-87.3"
> +font-family="Times,serif" font-size="14.00">ethdev_rx</text>
> +</g>
> +<!-- ingress_port&#45;&gt;ethdev_rx --> <g id="edge1" class="edge">
> +<title>ingress_port&#45;&gt;ethdev_rx</title>
> +<path fill="none" stroke="black" d="M118.9,-159.8C118.9,-148.16
> +118.9,-132.55 118.9,-119.24"/> <polygon fill="black" stroke="black"
> +points="122.4,-119.18 118.9,-109.18 115.4,-119.18 122.4,-119.18"/>
> +<text text-anchor="middle" x="171.4" y="-130.8"
> +font-family="Times,serif" font-size="14.00">ingress packet</text> </g>
> +<!-- ethdev_tx -->
> +<g id="node3" class="node">
> +<title>ethdev_tx</title>
> +<ellipse fill="none" stroke="black" cx="55.9" cy="-18" rx="55.79"
> +ry="18"/> <text text-anchor="middle" x="55.9" y="-14.3"
> +font-family="Times,serif" font-size="14.00">ethdev_tx</text>
> +</g>
> +<!-- ethdev_rx&#45;&gt;ethdev_tx -->
> +<g id="edge2" class="edge">
> +<title>ethdev_rx&#45;&gt;ethdev_tx</title>
> +<path fill="none" stroke="black" d="M104.28,-73.53C96.37,-64.61
> +86.43,-53.41 77.62,-43.49"/> <polygon fill="black" stroke="black"
> +points="80.12,-41.03 70.87,-35.87 74.88,-45.67 80.12,-41.03"/> </g>
> +<!-- pkt_drop -->
> +<g id="node4" class="node">
> +<title>pkt_drop</title>
> +<ellipse fill="none" stroke="black" cx="181.9" cy="-18" rx="51.99"
> +ry="18"/> <text text-anchor="middle" x="181.9" y="-14.3"
> +font-family="Times,serif" font-size="14.00">pkt_drop</text> </g>
> +<!-- ethdev_rx&#45;&gt;pkt_drop -->
> +<g id="edge3" class="edge">
> +<title>ethdev_rx&#45;&gt;pkt_drop</title>
> +<path fill="none" stroke="green" d="M133.51,-73.53C141.54,-64.48
> +151.65,-53.09 160.55,-43.06"/> <polygon fill="green" stroke="green"
> +points="163.34,-45.18 167.36,-35.38 158.11,-40.53 163.34,-45.18"/> </g>
> +<!-- egress_port -->
> +<g id="node5" class="node">
> +<title>egress_port</title>
> +<polygon fill="none" stroke="black" points="291.4,-196 190.4,-196
> +190.4,-160 291.4,-160 291.4,-196"/> <text text-anchor="middle"
> +x="240.9" y="-174.3" font-family="Times,serif"
> +font-size="14.00">egress_port</text>
> +</g>
> +</g>
> +</svg>
> --
> 2.25.1


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 42741 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v5 1/3] node: support to add next node to ethdev Rx node
  2023-12-05  9:27     ` [PATCH v4 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
                         ` (3 preceding siblings ...)
  2023-12-07  9:30       ` David Marchand
@ 2023-12-15  9:15       ` Rakesh Kudurumalla
  2023-12-15  9:15         ` [PATCH v5 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                           ` (3 more replies)
  4 siblings, 4 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-15  9:15 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
V5: Addressed comments
    Handled negative test case

 lib/node/ethdev_ctrl.c      | 48 +++++++++++++++++++++++++++++++++++++
 lib/node/rte_node_eth_api.h | 18 ++++++++++++++
 lib/node/version.map        |  3 +++
 3 files changed, 69 insertions(+)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..b886d2fe32 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -3,6 +3,7 @@
  */
 
 #include <stdlib.h>
+#include <errno.h>
 
 #include <rte_ethdev.h>
 #include <rte_graph.h>
@@ -129,3 +130,50 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t count;
+	uint16_t i = 0;
+
+	if (edge_name == NULL)
+		goto exit;
+
+	count = rte_node_edge_get(id, NULL);
+
+	if (count == RTE_NODE_ID_INVALID)
+		goto exit;
+
+	next_nodes = malloc(count);
+	if (next_nodes == NULL) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	count = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL && i < count) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto found;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+found:
+	free(next_nodes);
+exit:
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..5b5ca491dc 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -23,6 +23,7 @@ extern "C" {
 #include <rte_compat.h>
 #include <rte_common.h>
 #include <rte_mempool.h>
+#include <rte_graph.h>
 
 /**
  * Port config for ethdev_rx and ethdev_tx node.
@@ -57,6 +58,23 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..6bdb944c4c 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -19,4 +19,7 @@ EXPERIMENTAL {
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
+
+	# added in 24.03
+	rte_node_ethdev_rx_next_update;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v5 2/3] app/graph: add ethdev forward command
  2023-12-15  9:15       ` [PATCH v5 " Rakesh Kudurumalla
@ 2023-12-15  9:15         ` Rakesh Kudurumalla
  2023-12-18 10:44           ` Sunil Kumar Kori
  2023-12-15  9:15         ` [PATCH v5 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-15  9:15 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/cli.c         |  1 +
 app/graph/ethdev.c      | 63 +++++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h      |  1 +
 app/graph/ethdev_priv.h |  8 ++++++
 4 files changed, 73 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bb502a6134 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,9 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +891,63 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_dev, char *rx_dev)
+{
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	struct ethdev *port;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->tx_port_id = portid_tx;
+		rc = 0;
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_fwd_cfg =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_fwd_cfg,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..af79553438 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -104,6 +111,7 @@ struct ethdev_config {
 
 struct ethdev {
 	TAILQ_ENTRY(ethdev) next;
+	uint16_t tx_port_id;
 	struct ethdev_config config;
 	struct ipv4_addr_config ip4_addr;
 	struct ipv6_addr_config ip6_addr;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v5 3/3] app/graph: implement port forward usecase
  2023-12-15  9:15       ` [PATCH v5 " Rakesh Kudurumalla
  2023-12-15  9:15         ` [PATCH v5 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2023-12-15  9:15         ` Rakesh Kudurumalla
  2023-12-18 10:57           ` Sunil Kumar Kori
  2023-12-18 10:41         ` [EXT] [PATCH v5 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
  2023-12-20  8:59         ` [PATCH v6 " Rakesh Kudurumalla
  3 siblings, 1 reply; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-15  9:15 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/ethdev.c                           |  13 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 152 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  27 ++++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  92 +++++++++++
 11 files changed, 383 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bb502a6134..9a89bd3e1d 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -76,6 +76,19 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+find_txport_by_rxport(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..946e14d801 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -33,6 +33,7 @@ extern uint32_t enabled_port_mask;
 
 void ethdev_start(void);
 void ethdev_stop(void);
+int16_t find_txport_by_rxport(uint16_t portid_rx);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..861e83bd70
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..67308b3b72
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..279f73db5b
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc = 0;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = find_txport_by_rxport(port_id);
+		if (txport >= 0) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				goto exit;
+		} else {
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+exit:
+	return rc;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..33b5e750b2 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -110,6 +124,12 @@ For current use case, following routing table is used:
 On the successful execution of ``l3fwd.cli`` or ``l3fwd_pcap.cli``,
 user needs to send traffic with mentioned DIP.
 
+``l2fwd.cli`` and ``l2fwd_pcap.cli`` creates setup with two network ports.
+Packet received on one port is forwarded to other port.
+
+On the successful execution of ``l2fwd.cli`` or ``l2fwd_pcap.cli``,
+user needs to send traffic on RX port.
+
 For net_pcapX devices, required pcap file should be created and passed to application.
 These pcap files can be created in several ways.
 Scapy is one of the method to get the same:
@@ -321,3 +341,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..15763d8fa5
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_tx -> egress_port [label="egress packet"]
+    ethdev_tx -> pkt_drop [color="red" style="dashed"]
+}
+ -->
+
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="253pt" height="291pt"
+ viewBox="0.00 0.00 253.00 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-287 249,-287 249,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="165,-283 59,-283 59,-247 165,-247 165,-283"/>
+<text text-anchor="middle" x="112" y="-261.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-178" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="112" y="-174.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M112,-246.8C112,-235.16 112,-219.55 112,-206.24"/>
+<polygon fill="black" stroke="black" points="115.5,-206.18 112,-196.18 108.5,-206.18 115.5,-206.18"/>
+<text text-anchor="middle" x="164.5" y="-217.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-105" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="112" y="-101.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M112,-159.81C112,-151.79 112,-142.05 112,-133.07"/>
+<polygon fill="black" stroke="black" points="115.5,-133.03 112,-123.03 108.5,-133.03 115.5,-133.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="52" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="52" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_tx&#45;&gt;pkt_drop -->
+<g id="edge4" class="edge">
+<title>ethdev_tx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="red" stroke-dasharray="5,2" d="M100.14,-87.21C91.43,-74.87 79.45,-57.89 69.62,-43.97"/>
+<polygon fill="red" stroke="red" points="72.45,-41.91 63.82,-35.76 66.73,-45.95 72.45,-41.91"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="222.5,-36 121.5,-36 121.5,0 222.5,0 222.5,-36"/>
+<text text-anchor="middle" x="172" y="-14.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+<!-- ethdev_tx&#45;&gt;egress_port -->
+<g id="edge3" class="edge">
+<title>ethdev_tx&#45;&gt;egress_port</title>
+<path fill="none" stroke="black" d="M123.85,-87.21C132.5,-74.95 144.39,-58.11 154.18,-44.24"/>
+<polygon fill="black" stroke="black" points="157.05,-46.24 159.96,-36.05 151.33,-42.2 157.05,-46.24"/>
+<text text-anchor="middle" x="195" y="-57.8" font-family="Times,serif" font-size="14.00">egress packet</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [EXT] [PATCH v5 1/3] node: support to add next node to ethdev Rx node
  2023-12-15  9:15       ` [PATCH v5 " Rakesh Kudurumalla
  2023-12-15  9:15         ` [PATCH v5 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2023-12-15  9:15         ` [PATCH v5 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2023-12-18 10:41         ` Sunil Kumar Kori
  2023-12-20  8:59         ` [PATCH v6 " Rakesh Kudurumalla
  3 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2023-12-18 10:41 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Nithin Kumar Dabilpuram, Pavan Nikhilesh Bhagavatula
  Cc: dev, Jerin Jacob Kollanukkaran, Rakesh Kudurumalla

Overall patch looks okay. 
Just a minor comments. 

Regards
Sunil Kumar Kori

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Friday, December 15, 2023 2:46 PM
> To: Nithin Kumar Dabilpuram <ndabilpuram@marvell.com>; Pavan
> Nikhilesh Bhagavatula <pbhagavatula@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Subject: [EXT] [PATCH v5 1/3] node: support to add next node to ethdev Rx
> node
> 
> External Email
> 
> ----------------------------------------------------------------------
> By default all packets received on ethdev_rx node is forwarded to pkt_cls
> node.This patch provides library support to add a new node as next node to
> ethdev_rx node and forward packet to new node from rx node.
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
> V5: Addressed comments
>     Handled negative test case
> 
>  lib/node/ethdev_ctrl.c      | 48
> +++++++++++++++++++++++++++++++++++++
>  lib/node/rte_node_eth_api.h | 18 ++++++++++++++
>  lib/node/version.map        |  3 +++
>  3 files changed, 69 insertions(+)
> 
> diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c index
> d564b80e37..b886d2fe32 100644
> --- a/lib/node/ethdev_ctrl.c
> +++ b/lib/node/ethdev_ctrl.c
> @@ -3,6 +3,7 @@
>   */
> 
>  #include <stdlib.h>
> +#include <errno.h>
> 
Sort the header files.

>  #include <rte_ethdev.h>
>  #include <rte_graph.h>
> @@ -129,3 +130,50 @@ rte_node_eth_config(struct
> rte_node_ethdev_config *conf, uint16_t nb_confs,
>  	ctrl.nb_graphs = nb_graphs;
>  	return 0;
>  }
> +
> +int
> +rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name) {
> +	struct ethdev_rx_node_main *data;
> +	ethdev_rx_node_elem_t *elem;
> +	char **next_nodes;
> +	int rc = -EINVAL;
> +	uint32_t count;
> +	uint16_t i = 0;
> +
> +	if (edge_name == NULL)
> +		goto exit;
> +
> +	count = rte_node_edge_get(id, NULL);
> +
> +	if (count == RTE_NODE_ID_INVALID)
> +		goto exit;
> +
> +	next_nodes = malloc(count);
> +	if (next_nodes == NULL) {
> +		rc = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	count = rte_node_edge_get(id, next_nodes);
> +
> +	while (next_nodes[i] != NULL && i < count) {
I believe, both conditions are not needed. Any of the condition will be sufficient to cater the loop termination.
Please avoid either of them. 

> +		if (strcmp(edge_name, next_nodes[i]) == 0) {
> +			data = ethdev_rx_get_node_data_get();
> +			elem = data->head;
> +			while (elem->next != data->head) {
> +				if (elem->nid == id) {
> +					elem->ctx.cls_next = i;
> +					rc = 0;
> +					goto found;
> +				}
> +				elem = elem->next;
> +			}
> +		}
> +		i++;
> +	}
> +found:
> +	free(next_nodes);
> +exit:
> +	return rc;
> +}
> diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h index
> eaae50772d..5b5ca491dc 100644
> --- a/lib/node/rte_node_eth_api.h
> +++ b/lib/node/rte_node_eth_api.h
> @@ -23,6 +23,7 @@ extern "C" {
>  #include <rte_compat.h>
>  #include <rte_common.h>
>  #include <rte_mempool.h>
> +#include <rte_graph.h>
> 
Sort the header files. 
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [PATCH v5 2/3] app/graph: add ethdev forward command
  2023-12-15  9:15         ` [PATCH v5 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2023-12-18 10:44           ` Sunil Kumar Kori
  0 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2023-12-18 10:44 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Rakesh Kudurumalla
  Cc: dev, Jerin Jacob Kollanukkaran, Nithin Kumar Dabilpuram

[-- Attachment #1: Type: text/plain, Size: 1019 bytes --]

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Friday, December 15, 2023 2:46 PM
> To: Sunil Kumar Kori <skori@marvell.com>; Rakesh Kudurumalla
> <rkudurumalla@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Nithin
> Kumar Dabilpuram <ndabilpuram@marvell.com>
> Subject: [PATCH v5 2/3] app/graph: add ethdev forward command
> 
> Adds a txport to forward packet for every rxport
> 
> Mapping will be used to forward packets to txport received on rxport
> 
> Following commands are exposed:
> 	- ethdev forward <tx_dev_name> <rx_dev_name>"
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  app/graph/cli.c         |  1 +
>  app/graph/ethdev.c      | 63
> +++++++++++++++++++++++++++++++++++++++++
>  app/graph/ethdev.h      |  1 +
>  app/graph/ethdev_priv.h |  8 ++++++
>  4 files changed, 73 insertions(+)
Document change are missing. Please update commands table in graph.rst.
Rest is fine.

[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 35529 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [PATCH v5 3/3] app/graph: implement port forward usecase
  2023-12-15  9:15         ` [PATCH v5 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2023-12-18 10:57           ` Sunil Kumar Kori
  0 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2023-12-18 10:57 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Rakesh Kudurumalla
  Cc: dev, Jerin Jacob Kollanukkaran, Nithin Kumar Dabilpuram

[-- Attachment #1: Type: text/plain, Size: 3286 bytes --]

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Friday, December 15, 2023 2:46 PM
> To: Sunil Kumar Kori <skori@marvell.com>; Rakesh Kudurumalla
> <rkudurumalla@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Nithin
> Kumar Dabilpuram <ndabilpuram@marvell.com>
> Subject: [PATCH v5 3/3] app/graph: implement port forward usecase
> 
> Added portforward usecase.In this usecase packets received Rx port is
> forwarded to respective Tx port.
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  app/graph/ethdev.c                           |  13 ++
>  app/graph/ethdev.h                           |   1 +
>  app/graph/examples/l2fwd.cli                 |  41 +++++
>  app/graph/examples/l2fwd_pcap.cli            |  37 +++++
>  app/graph/graph.c                            |   8 +-
>  app/graph/l2fwd.c                            | 152 +++++++++++++++++++
>  app/graph/l2fwd.h                            |  11 ++
>  app/graph/meson.build                        |   1 +
>  app/graph/module_api.h                       |   1 +
>  doc/guides/tools/graph.rst                   |  27 ++++
>  doc/guides/tools/img/graph-usecase-l2fwd.svg |  92 +++++++++++
>  11 files changed, 383 insertions(+), 1 deletion(-)  create mode 100644
> app/graph/examples/l2fwd.cli  create mode 100644
> app/graph/examples/l2fwd_pcap.cli  create mode 100644
> app/graph/l2fwd.c  create mode 100644 app/graph/l2fwd.h  create mode
> 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg
> 
> diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c index
> bb502a6134..9a89bd3e1d 100644
> --- a/app/graph/ethdev.c
> +++ b/app/graph/ethdev.c
> @@ -76,6 +76,19 @@ ethdev_port_by_id(uint16_t port_id)
>  	return NULL;
>  }
> 
> +int16_t
> +find_txport_by_rxport(uint16_t portid_rx) {
> +	int portid = -EINVAL;
> +	struct ethdev *port;
> +
> +	port = ethdev_port_by_id(portid_rx);
> +	if (port)
> +		portid = port->tx_port_id;
> +
> +	return portid;
> +}
> +
>  void *
>  ethdev_mempool_list_by_portid(uint16_t portid)  { diff --git
> a/app/graph/ethdev.h b/app/graph/ethdev.h index
> 836052046b..946e14d801 100644
> --- a/app/graph/ethdev.h
> +++ b/app/graph/ethdev.h
> @@ -33,6 +33,7 @@ extern uint32_t enabled_port_mask;
> 
>  void ethdev_start(void);
>  void ethdev_stop(void);
> +int16_t find_txport_by_rxport(uint16_t portid_rx);
This function is exposed to other modules in application. Please align this name with other function's name. 


>  void *ethdev_mempool_list_by_portid(uint16_t portid);  int16_t
> ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);  int16_t
> ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask); diff --git
> 
> @@ -110,6 +124,12 @@ For current use case, following routing table is
> used:
>  On the successful execution of ``l3fwd.cli`` or ``l3fwd_pcap.cli``,  user
> needs to send traffic with mentioned DIP.
> 
> +``l2fwd.cli`` and ``l2fwd_pcap.cli`` creates setup with two network
> ports.
> +Packet received on one port is forwarded to other port.
> +
> +On the successful execution of ``l2fwd.cli`` or ``l2fwd_pcap.cli``,
> +user needs to send traffic on RX port.
> +
This is para is not needed. 

> 2.25.1


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 36517 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v6 1/3] node: support to add next node to ethdev Rx node
  2023-12-15  9:15       ` [PATCH v5 " Rakesh Kudurumalla
                           ` (2 preceding siblings ...)
  2023-12-18 10:41         ` [EXT] [PATCH v5 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
@ 2023-12-20  8:59         ` Rakesh Kudurumalla
  2023-12-20  8:59           ` [PATCH v6 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                             ` (2 more replies)
  3 siblings, 3 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-20  8:59 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
V6: Addressed comments
    updated documentation

 lib/node/ethdev_ctrl.c      | 49 ++++++++++++++++++++++++++++++++++++-
 lib/node/rte_node_eth_api.h | 18 ++++++++++++++
 lib/node/version.map        |  3 +++
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..ab54b7f0d4 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(C) 2020 Marvell International Ltd.
  */
-
+#include <errno.h>
 #include <stdlib.h>
 
 #include <rte_ethdev.h>
@@ -129,3 +129,50 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t size;
+	uint16_t i = 0;
+
+	if (edge_name == NULL)
+		goto exit;
+
+	size = rte_node_edge_get(id, NULL);
+
+	if (size == RTE_NODE_ID_INVALID)
+		goto exit;
+
+	next_nodes = calloc(size + 1, sizeof(*next_nodes));
+	if (next_nodes == NULL) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	size = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto found;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+found:
+	free(next_nodes);
+exit:
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..d2f705e908 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -22,6 +22,7 @@ extern "C" {
 
 #include <rte_compat.h>
 #include <rte_common.h>
+#include <rte_graph.h>
 #include <rte_mempool.h>
 
 /**
@@ -57,6 +58,23 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..6bdb944c4c 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -19,4 +19,7 @@ EXPERIMENTAL {
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
+
+	# added in 24.03
+	rte_node_ethdev_rx_next_update;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v6 2/3] app/graph: add ethdev forward command
  2023-12-20  8:59         ` [PATCH v6 " Rakesh Kudurumalla
@ 2023-12-20  8:59           ` Rakesh Kudurumalla
  2023-12-20  8:59           ` [PATCH v6 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
  2023-12-20  9:44           ` [PATCH v7 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-20  8:59 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/cli.c            |  1 +
 app/graph/ethdev.c         | 63 ++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h         |  1 +
 app/graph/ethdev_priv.h    |  8 +++++
 doc/guides/tools/graph.rst |  4 +++
 5 files changed, 77 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bb502a6134 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,9 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +891,63 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_dev, char *rx_dev)
+{
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	struct ethdev *port;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->tx_port_id = portid_tx;
+		rc = 0;
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_fwd_cfg =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_fwd_cfg,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..af79553438 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -104,6 +111,7 @@ struct ethdev_config {
 
 struct ethdev {
 	TAILQ_ENTRY(ethdev) next;
+	uint16_t tx_port_id;
 	struct ethdev_config config;
 	struct ipv4_addr_config ip4_addr;
 	struct ipv6_addr_config ip6_addr;
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..0b07c12cec 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -195,6 +195,9 @@ file to express the requested use case configuration.
    | ethdev <ethdev_name> mtu <mtu_sz>    | | Command to configure MTU of DPDK|   Yes   |    Yes   |
    |                                      | | port.                           |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
+   | ethdev forward <tx_dev_name>         | | Command to configure port       |   No    |    Yes   |
+   | <rx_dev_name>                        | | forwading of DPDK               |         |          |
+   +--------------------------------------+-----------------------------------+---------+----------+
    |  | ethdev <ethdev_name> promiscuous  | | Command to enable/disable       |   Yes   |    Yes   |
    |  | <on/off>                          | | promiscuous mode on DPDK port.  |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
@@ -297,6 +300,7 @@ Example: ``dpdk-graph`` is started with ``-h 10.28.35.207`` and ``-p 50000`` the
    ethdev <ethdev_name> rxq <n_queues> txq <n_queues> <mempool_name>
    ethdev <ethdev_name> ip4 addr add <ip> netmask <mask>
    ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>
+   ethdev forward <tx_dev_name> <rx_dev_name>
    ethdev <ethdev_name> promiscuous <on/off>
    ethdev <ethdev_name> mtu <mtu_sz>
    ethdev <ethdev_name> stats
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v6 3/3] app/graph: implement port forward usecase
  2023-12-20  8:59         ` [PATCH v6 " Rakesh Kudurumalla
  2023-12-20  8:59           ` [PATCH v6 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2023-12-20  8:59           ` Rakesh Kudurumalla
  2023-12-20  9:44           ` [PATCH v7 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-20  8:59 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/ethdev.c                           |  13 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 152 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  21 +++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  92 +++++++++++
 11 files changed, 377 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bb502a6134..a622275338 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -76,6 +76,19 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+ethdev_txport_by_rxport_get(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..ec457b89bf 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -36,6 +36,7 @@ void ethdev_stop(void);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
+int16_t ethdev_txport_by_rxport_get(uint16_t portid_rx);
 void ethdev_list_clean(void);
 
 #endif
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..861e83bd70
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..67308b3b72
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..20894b64fe
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc = 0;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = ethdev_txport_by_rxport_get(port_id);
+		if (txport >= 0) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				goto exit;
+		} else {
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+exit:
+	return rc;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 0b07c12cec..b4997e13ea 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -325,3 +339,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..15763d8fa5
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_tx -> egress_port [label="egress packet"]
+    ethdev_tx -> pkt_drop [color="red" style="dashed"]
+}
+ -->
+
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="253pt" height="291pt"
+ viewBox="0.00 0.00 253.00 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-287 249,-287 249,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="165,-283 59,-283 59,-247 165,-247 165,-283"/>
+<text text-anchor="middle" x="112" y="-261.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-178" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="112" y="-174.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M112,-246.8C112,-235.16 112,-219.55 112,-206.24"/>
+<polygon fill="black" stroke="black" points="115.5,-206.18 112,-196.18 108.5,-206.18 115.5,-206.18"/>
+<text text-anchor="middle" x="164.5" y="-217.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-105" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="112" y="-101.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M112,-159.81C112,-151.79 112,-142.05 112,-133.07"/>
+<polygon fill="black" stroke="black" points="115.5,-133.03 112,-123.03 108.5,-133.03 115.5,-133.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="52" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="52" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_tx&#45;&gt;pkt_drop -->
+<g id="edge4" class="edge">
+<title>ethdev_tx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="red" stroke-dasharray="5,2" d="M100.14,-87.21C91.43,-74.87 79.45,-57.89 69.62,-43.97"/>
+<polygon fill="red" stroke="red" points="72.45,-41.91 63.82,-35.76 66.73,-45.95 72.45,-41.91"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="222.5,-36 121.5,-36 121.5,0 222.5,0 222.5,-36"/>
+<text text-anchor="middle" x="172" y="-14.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+<!-- ethdev_tx&#45;&gt;egress_port -->
+<g id="edge3" class="edge">
+<title>ethdev_tx&#45;&gt;egress_port</title>
+<path fill="none" stroke="black" d="M123.85,-87.21C132.5,-74.95 144.39,-58.11 154.18,-44.24"/>
+<polygon fill="black" stroke="black" points="157.05,-46.24 159.96,-36.05 151.33,-42.2 157.05,-46.24"/>
+<text text-anchor="middle" x="195" y="-57.8" font-family="Times,serif" font-size="14.00">egress packet</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 1/3] node: support to add next node to ethdev Rx node
  2023-12-20  8:59         ` [PATCH v6 " Rakesh Kudurumalla
  2023-12-20  8:59           ` [PATCH v6 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2023-12-20  8:59           ` [PATCH v6 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2023-12-20  9:44           ` Rakesh Kudurumalla
  2023-12-20  9:44             ` [PATCH v7 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                               ` (2 more replies)
  2 siblings, 3 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-20  9:44 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
v7: 
   Remove warning
 lib/node/ethdev_ctrl.c      | 49 ++++++++++++++++++++++++++++++++++++-
 lib/node/rte_node_eth_api.h | 18 ++++++++++++++
 lib/node/version.map        |  3 +++
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..ab54b7f0d4 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(C) 2020 Marvell International Ltd.
  */
-
+#include <errno.h>
 #include <stdlib.h>
 
 #include <rte_ethdev.h>
@@ -129,3 +129,50 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t size;
+	uint16_t i = 0;
+
+	if (edge_name == NULL)
+		goto exit;
+
+	size = rte_node_edge_get(id, NULL);
+
+	if (size == RTE_NODE_ID_INVALID)
+		goto exit;
+
+	next_nodes = calloc(size + 1, sizeof(*next_nodes));
+	if (next_nodes == NULL) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	size = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto found;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+found:
+	free(next_nodes);
+exit:
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..d2f705e908 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -22,6 +22,7 @@ extern "C" {
 
 #include <rte_compat.h>
 #include <rte_common.h>
+#include <rte_graph.h>
 #include <rte_mempool.h>
 
 /**
@@ -57,6 +58,23 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..6bdb944c4c 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -19,4 +19,7 @@ EXPERIMENTAL {
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
+
+	# added in 24.03
+	rte_node_ethdev_rx_next_update;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 2/3] app/graph: add ethdev forward command
  2023-12-20  9:44           ` [PATCH v7 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
@ 2023-12-20  9:44             ` Rakesh Kudurumalla
  2023-12-20  9:44             ` [PATCH v7 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
  2024-01-01  8:37             ` [PATCH v8 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-20  9:44 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/cli.c            |  1 +
 app/graph/ethdev.c         | 63 ++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h         |  1 +
 app/graph/ethdev_priv.h    |  8 +++++
 doc/guides/tools/graph.rst |  4 +++
 5 files changed, 77 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bb502a6134 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,9 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +891,63 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_dev, char *rx_dev)
+{
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	struct ethdev *port;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->tx_port_id = portid_tx;
+		rc = 0;
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_fwd_cfg =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_fwd_cfg,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..af79553438 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -104,6 +111,7 @@ struct ethdev_config {
 
 struct ethdev {
 	TAILQ_ENTRY(ethdev) next;
+	uint16_t tx_port_id;
 	struct ethdev_config config;
 	struct ipv4_addr_config ip4_addr;
 	struct ipv6_addr_config ip6_addr;
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..d33af8ff2a 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -195,6 +195,9 @@ file to express the requested use case configuration.
    | ethdev <ethdev_name> mtu <mtu_sz>    | | Command to configure MTU of DPDK|   Yes   |    Yes   |
    |                                      | | port.                           |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
+   | ethdev forward <tx_dev_name>         | | Command to configure port       |   No    |    Yes   |
+   | <rx_dev_name>                        | | forwarding of DPDK              |         |          |
+   +--------------------------------------+-----------------------------------+---------+----------+
    |  | ethdev <ethdev_name> promiscuous  | | Command to enable/disable       |   Yes   |    Yes   |
    |  | <on/off>                          | | promiscuous mode on DPDK port.  |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
@@ -297,6 +300,7 @@ Example: ``dpdk-graph`` is started with ``-h 10.28.35.207`` and ``-p 50000`` the
    ethdev <ethdev_name> rxq <n_queues> txq <n_queues> <mempool_name>
    ethdev <ethdev_name> ip4 addr add <ip> netmask <mask>
    ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>
+   ethdev forward <tx_dev_name> <rx_dev_name>
    ethdev <ethdev_name> promiscuous <on/off>
    ethdev <ethdev_name> mtu <mtu_sz>
    ethdev <ethdev_name> stats
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 3/3] app/graph: implement port forward usecase
  2023-12-20  9:44           ` [PATCH v7 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2023-12-20  9:44             ` [PATCH v7 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2023-12-20  9:44             ` Rakesh Kudurumalla
  2024-01-01  8:37             ` [PATCH v8 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2023-12-20  9:44 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/ethdev.c                           |  13 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 152 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  21 +++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  92 +++++++++++
 11 files changed, 377 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bb502a6134..a622275338 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -76,6 +76,19 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+ethdev_txport_by_rxport_get(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..ec457b89bf 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -36,6 +36,7 @@ void ethdev_stop(void);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
+int16_t ethdev_txport_by_rxport_get(uint16_t portid_rx);
 void ethdev_list_clean(void);
 
 #endif
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..861e83bd70
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..67308b3b72
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..20894b64fe
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc = 0;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = ethdev_txport_by_rxport_get(port_id);
+		if (txport >= 0) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				goto exit;
+		} else {
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+exit:
+	return rc;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index d33af8ff2a..01282ab90c 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -325,3 +339,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..15763d8fa5
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_tx -> egress_port [label="egress packet"]
+    ethdev_tx -> pkt_drop [color="red" style="dashed"]
+}
+ -->
+
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="253pt" height="291pt"
+ viewBox="0.00 0.00 253.00 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-287 249,-287 249,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="165,-283 59,-283 59,-247 165,-247 165,-283"/>
+<text text-anchor="middle" x="112" y="-261.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-178" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="112" y="-174.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M112,-246.8C112,-235.16 112,-219.55 112,-206.24"/>
+<polygon fill="black" stroke="black" points="115.5,-206.18 112,-196.18 108.5,-206.18 115.5,-206.18"/>
+<text text-anchor="middle" x="164.5" y="-217.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-105" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="112" y="-101.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M112,-159.81C112,-151.79 112,-142.05 112,-133.07"/>
+<polygon fill="black" stroke="black" points="115.5,-133.03 112,-123.03 108.5,-133.03 115.5,-133.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="52" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="52" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_tx&#45;&gt;pkt_drop -->
+<g id="edge4" class="edge">
+<title>ethdev_tx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="red" stroke-dasharray="5,2" d="M100.14,-87.21C91.43,-74.87 79.45,-57.89 69.62,-43.97"/>
+<polygon fill="red" stroke="red" points="72.45,-41.91 63.82,-35.76 66.73,-45.95 72.45,-41.91"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="222.5,-36 121.5,-36 121.5,0 222.5,0 222.5,-36"/>
+<text text-anchor="middle" x="172" y="-14.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+<!-- ethdev_tx&#45;&gt;egress_port -->
+<g id="edge3" class="edge">
+<title>ethdev_tx&#45;&gt;egress_port</title>
+<path fill="none" stroke="black" d="M123.85,-87.21C132.5,-74.95 144.39,-58.11 154.18,-44.24"/>
+<polygon fill="black" stroke="black" points="157.05,-46.24 159.96,-36.05 151.33,-42.2 157.05,-46.24"/>
+<text text-anchor="middle" x="195" y="-57.8" font-family="Times,serif" font-size="14.00">egress packet</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v8 1/3] node: support to add next node to ethdev Rx node
  2023-12-20  9:44           ` [PATCH v7 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2023-12-20  9:44             ` [PATCH v7 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2023-12-20  9:44             ` [PATCH v7 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2024-01-01  8:37             ` Rakesh Kudurumalla
  2024-01-01  8:37               ` [PATCH v8 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                                 ` (2 more replies)
  2 siblings, 3 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-01  8:37 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
v8: Doc correction 

 lib/node/ethdev_ctrl.c      | 48 +++++++++++++++++++++++++++++++++++++
 lib/node/rte_node_eth_api.h | 18 ++++++++++++++
 lib/node/version.map        |  3 +++
 3 files changed, 69 insertions(+)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..a5fa8ee54b 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -2,6 +2,7 @@
  * Copyright(C) 2020 Marvell International Ltd.
  */
 
+#include <errno.h>
 #include <stdlib.h>
 
 #include <rte_ethdev.h>
@@ -129,3 +130,50 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t size;
+	uint16_t i = 0;
+
+	if (edge_name == NULL)
+		goto exit;
+
+	size = rte_node_edge_get(id, NULL);
+
+	if (size == RTE_NODE_ID_INVALID)
+		goto exit;
+
+	next_nodes = calloc(size + 1, sizeof(**next_nodes));
+	if (next_nodes == NULL) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	size = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto found;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+found:
+	free(next_nodes);
+exit:
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..d2f705e908 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -22,6 +22,7 @@ extern "C" {
 
 #include <rte_compat.h>
 #include <rte_common.h>
+#include <rte_graph.h>
 #include <rte_mempool.h>
 
 /**
@@ -57,6 +58,23 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..6bdb944c4c 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -19,4 +19,7 @@ EXPERIMENTAL {
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
+
+	# added in 24.03
+	rte_node_ethdev_rx_next_update;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v8 2/3] app/graph: add ethdev forward command
  2024-01-01  8:37             ` [PATCH v8 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
@ 2024-01-01  8:37               ` Rakesh Kudurumalla
  2024-01-02  6:45                 ` Sunil Kumar Kori
  2024-01-01  8:37               ` [PATCH v8 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
  2024-01-02  7:28               ` [PATCH v9 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 1 reply; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-01  8:37 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/cli.c            |  1 +
 app/graph/ethdev.c         | 63 ++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h         |  1 +
 app/graph/ethdev_priv.h    |  8 +++++
 doc/guides/tools/graph.rst |  4 +++
 5 files changed, 77 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bb502a6134 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,9 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +891,63 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_dev, char *rx_dev)
+{
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	struct ethdev *port;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->tx_port_id = portid_tx;
+		rc = 0;
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_fwd_cfg =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_fwd_cfg,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..af79553438 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -104,6 +111,7 @@ struct ethdev_config {
 
 struct ethdev {
 	TAILQ_ENTRY(ethdev) next;
+	uint16_t tx_port_id;
 	struct ethdev_config config;
 	struct ipv4_addr_config ip4_addr;
 	struct ipv6_addr_config ip6_addr;
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..0aab41cbca 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -195,6 +195,9 @@ file to express the requested use case configuration.
    | ethdev <ethdev_name> mtu <mtu_sz>    | | Command to configure MTU of DPDK|   Yes   |    Yes   |
    |                                      | | port.                           |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
+   | | ethdev forward <tx_dev_name>       | | Command to configure port       |   No    |    Yes   |
+   | | <rx_dev_name>                      | | forwarding of DPDK              |         |          |
+   +--------------------------------------+-----------------------------------+---------+----------+
    |  | ethdev <ethdev_name> promiscuous  | | Command to enable/disable       |   Yes   |    Yes   |
    |  | <on/off>                          | | promiscuous mode on DPDK port.  |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
@@ -297,6 +300,7 @@ Example: ``dpdk-graph`` is started with ``-h 10.28.35.207`` and ``-p 50000`` the
    ethdev <ethdev_name> rxq <n_queues> txq <n_queues> <mempool_name>
    ethdev <ethdev_name> ip4 addr add <ip> netmask <mask>
    ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>
+   ethdev forward <tx_dev_name> <rx_dev_name>
    ethdev <ethdev_name> promiscuous <on/off>
    ethdev <ethdev_name> mtu <mtu_sz>
    ethdev <ethdev_name> stats
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v8 3/3] app/graph: implement port forward usecase
  2024-01-01  8:37             ` [PATCH v8 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2024-01-01  8:37               ` [PATCH v8 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2024-01-01  8:37               ` Rakesh Kudurumalla
  2024-01-02  6:46                 ` Sunil Kumar Kori
  2024-01-02  7:28               ` [PATCH v9 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 1 reply; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-01  8:37 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
 app/graph/ethdev.c                           |  13 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 152 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  21 +++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  92 +++++++++++
 11 files changed, 377 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bb502a6134..a622275338 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -76,6 +76,19 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+ethdev_txport_by_rxport_get(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..ec457b89bf 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -36,6 +36,7 @@ void ethdev_stop(void);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
+int16_t ethdev_txport_by_rxport_get(uint16_t portid_rx);
 void ethdev_list_clean(void);
 
 #endif
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..861e83bd70
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..67308b3b72
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..20894b64fe
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc = 0;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = ethdev_txport_by_rxport_get(port_id);
+		if (txport >= 0) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				goto exit;
+		} else {
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+exit:
+	return rc;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 0aab41cbca..5308967b6b 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -325,3 +339,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..15763d8fa5
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_tx -> egress_port [label="egress packet"]
+    ethdev_tx -> pkt_drop [color="red" style="dashed"]
+}
+ -->
+
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="253pt" height="291pt"
+ viewBox="0.00 0.00 253.00 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-287 249,-287 249,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="165,-283 59,-283 59,-247 165,-247 165,-283"/>
+<text text-anchor="middle" x="112" y="-261.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-178" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="112" y="-174.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M112,-246.8C112,-235.16 112,-219.55 112,-206.24"/>
+<polygon fill="black" stroke="black" points="115.5,-206.18 112,-196.18 108.5,-206.18 115.5,-206.18"/>
+<text text-anchor="middle" x="164.5" y="-217.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-105" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="112" y="-101.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M112,-159.81C112,-151.79 112,-142.05 112,-133.07"/>
+<polygon fill="black" stroke="black" points="115.5,-133.03 112,-123.03 108.5,-133.03 115.5,-133.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="52" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="52" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_tx&#45;&gt;pkt_drop -->
+<g id="edge4" class="edge">
+<title>ethdev_tx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="red" stroke-dasharray="5,2" d="M100.14,-87.21C91.43,-74.87 79.45,-57.89 69.62,-43.97"/>
+<polygon fill="red" stroke="red" points="72.45,-41.91 63.82,-35.76 66.73,-45.95 72.45,-41.91"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="222.5,-36 121.5,-36 121.5,0 222.5,0 222.5,-36"/>
+<text text-anchor="middle" x="172" y="-14.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+<!-- ethdev_tx&#45;&gt;egress_port -->
+<g id="edge3" class="edge">
+<title>ethdev_tx&#45;&gt;egress_port</title>
+<path fill="none" stroke="black" d="M123.85,-87.21C132.5,-74.95 144.39,-58.11 154.18,-44.24"/>
+<polygon fill="black" stroke="black" points="157.05,-46.24 159.96,-36.05 151.33,-42.2 157.05,-46.24"/>
+<text text-anchor="middle" x="195" y="-57.8" font-family="Times,serif" font-size="14.00">egress packet</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [PATCH v8 2/3] app/graph: add ethdev forward command
  2024-01-01  8:37               ` [PATCH v8 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2024-01-02  6:45                 ` Sunil Kumar Kori
  0 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2024-01-02  6:45 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Rakesh Kudurumalla
  Cc: dev, Jerin Jacob Kollanukkaran, Nithin Kumar Dabilpuram

[-- Attachment #1: Type: text/plain, Size: 1045 bytes --]

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Monday, January 1, 2024 2:07 PM
> To: Sunil Kumar Kori <skori@marvell.com>; Rakesh Kudurumalla
> <rkudurumalla@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Nithin
> Kumar Dabilpuram <ndabilpuram@marvell.com>
> Subject: [PATCH v8 2/3] app/graph: add ethdev forward command
> 
> Adds a txport to forward packet for every rxport
> 
> Mapping will be used to forward packets to txport received on rxport
> 
> Following commands are exposed:
> 	- ethdev forward <tx_dev_name> <rx_dev_name>"
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  app/graph/cli.c            |  1 +
>  app/graph/ethdev.c         | 63
> ++++++++++++++++++++++++++++++++++++++
>  app/graph/ethdev.h         |  1 +
>  app/graph/ethdev_priv.h    |  8 +++++
>  doc/guides/tools/graph.rst |  4 +++
>  5 files changed, 77 insertions(+)
> 

Acked-by: Sunil Kumar Kori <skori@marvell.com>

> 2.25.1


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 35521 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [PATCH v8 3/3] app/graph: implement port forward usecase
  2024-01-01  8:37               ` [PATCH v8 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2024-01-02  6:46                 ` Sunil Kumar Kori
  0 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2024-01-02  6:46 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Rakesh Kudurumalla
  Cc: dev, Jerin Jacob Kollanukkaran, Nithin Kumar Dabilpuram

[-- Attachment #1: Type: text/plain, Size: 1644 bytes --]

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Monday, January 1, 2024 2:07 PM
> To: Sunil Kumar Kori <skori@marvell.com>; Rakesh Kudurumalla
> <rkudurumalla@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Nithin
> Kumar Dabilpuram <ndabilpuram@marvell.com>
> Subject: [PATCH v8 3/3] app/graph: implement port forward usecase
> 
> Added portforward usecase.In this usecase packets received Rx port is
> forwarded to respective Tx port.
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  app/graph/ethdev.c                           |  13 ++
>  app/graph/ethdev.h                           |   1 +
>  app/graph/examples/l2fwd.cli                 |  41 +++++
>  app/graph/examples/l2fwd_pcap.cli            |  37 +++++
>  app/graph/graph.c                            |   8 +-
>  app/graph/l2fwd.c                            | 152 +++++++++++++++++++
>  app/graph/l2fwd.h                            |  11 ++
>  app/graph/meson.build                        |   1 +
>  app/graph/module_api.h                       |   1 +
>  doc/guides/tools/graph.rst                   |  21 +++
>  doc/guides/tools/img/graph-usecase-l2fwd.svg |  92 +++++++++++
>  11 files changed, 377 insertions(+), 1 deletion(-)  create mode 100644
> app/graph/examples/l2fwd.cli  create mode 100644
> app/graph/examples/l2fwd_pcap.cli  create mode 100644
> app/graph/l2fwd.c  create mode 100644 app/graph/l2fwd.h  create mode
> 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg
> 
Acked-by: Sunil Kumar Kori <skori@marvell.com>

> 2.25.1


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 35669 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v9 1/3] node: support to add next node to ethdev Rx node
  2024-01-01  8:37             ` [PATCH v8 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2024-01-01  8:37               ` [PATCH v8 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2024-01-01  8:37               ` [PATCH v8 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2024-01-02  7:28               ` Rakesh Kudurumalla
  2024-01-02  7:28                 ` [PATCH v9 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                                   ` (2 more replies)
  2 siblings, 3 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-02  7:28 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
v9: Resolve memory issue

 lib/node/ethdev_ctrl.c      | 48 +++++++++++++++++++++++++++++++++++++
 lib/node/rte_node_eth_api.h | 18 ++++++++++++++
 lib/node/version.map        |  3 +++
 3 files changed, 69 insertions(+)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..cffe15976f 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -2,6 +2,7 @@
  * Copyright(C) 2020 Marvell International Ltd.
  */
 
+#include <errno.h>
 #include <stdlib.h>
 
 #include <rte_ethdev.h>
@@ -129,3 +130,50 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint32_t size;
+	uint16_t i = 0;
+
+	if (edge_name == NULL)
+		goto exit;
+
+	size = rte_node_edge_get(id, NULL);
+
+	if (size == RTE_NODE_ID_INVALID)
+		goto exit;
+
+	next_nodes = calloc((size / sizeof(char *)) + 1, sizeof(*next_nodes));
+	if (next_nodes == NULL) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	size = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto found;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+found:
+	free(next_nodes);
+exit:
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..d2f705e908 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -22,6 +22,7 @@ extern "C" {
 
 #include <rte_compat.h>
 #include <rte_common.h>
+#include <rte_graph.h>
 #include <rte_mempool.h>
 
 /**
@@ -57,6 +58,23 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..6bdb944c4c 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -19,4 +19,7 @@ EXPERIMENTAL {
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
+
+	# added in 24.03
+	rte_node_ethdev_rx_next_update;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v9 2/3] app/graph: add ethdev forward command
  2024-01-02  7:28               ` [PATCH v9 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
@ 2024-01-02  7:28                 ` Rakesh Kudurumalla
  2024-01-02  7:28                 ` [PATCH v9 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
  2024-01-02  7:30                 ` [PATCH v10 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-02  7:28 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
Acked-by: Sunil Kumar Kori <skori@marvell.com>
---
 app/graph/cli.c            |  1 +
 app/graph/ethdev.c         | 63 ++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h         |  1 +
 app/graph/ethdev_priv.h    |  8 +++++
 doc/guides/tools/graph.rst |  4 +++
 5 files changed, 77 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bb502a6134 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,9 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +891,63 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_dev, char *rx_dev)
+{
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	struct ethdev *port;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->tx_port_id = portid_tx;
+		rc = 0;
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_fwd_cfg =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_fwd_cfg,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..af79553438 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -104,6 +111,7 @@ struct ethdev_config {
 
 struct ethdev {
 	TAILQ_ENTRY(ethdev) next;
+	uint16_t tx_port_id;
 	struct ethdev_config config;
 	struct ipv4_addr_config ip4_addr;
 	struct ipv6_addr_config ip6_addr;
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..0aab41cbca 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -195,6 +195,9 @@ file to express the requested use case configuration.
    | ethdev <ethdev_name> mtu <mtu_sz>    | | Command to configure MTU of DPDK|   Yes   |    Yes   |
    |                                      | | port.                           |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
+   | | ethdev forward <tx_dev_name>       | | Command to configure port       |   No    |    Yes   |
+   | | <rx_dev_name>                      | | forwarding of DPDK              |         |          |
+   +--------------------------------------+-----------------------------------+---------+----------+
    |  | ethdev <ethdev_name> promiscuous  | | Command to enable/disable       |   Yes   |    Yes   |
    |  | <on/off>                          | | promiscuous mode on DPDK port.  |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
@@ -297,6 +300,7 @@ Example: ``dpdk-graph`` is started with ``-h 10.28.35.207`` and ``-p 50000`` the
    ethdev <ethdev_name> rxq <n_queues> txq <n_queues> <mempool_name>
    ethdev <ethdev_name> ip4 addr add <ip> netmask <mask>
    ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>
+   ethdev forward <tx_dev_name> <rx_dev_name>
    ethdev <ethdev_name> promiscuous <on/off>
    ethdev <ethdev_name> mtu <mtu_sz>
    ethdev <ethdev_name> stats
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v9 3/3] app/graph: implement port forward usecase
  2024-01-02  7:28               ` [PATCH v9 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2024-01-02  7:28                 ` [PATCH v9 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2024-01-02  7:28                 ` Rakesh Kudurumalla
  2024-01-02  7:30                 ` [PATCH v10 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-02  7:28 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
Acked-by: Sunil Kumar Kori <skori@marvell.com>
---
 app/graph/ethdev.c                           |  13 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 152 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  21 +++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  92 +++++++++++
 11 files changed, 377 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bb502a6134..a622275338 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -76,6 +76,19 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+ethdev_txport_by_rxport_get(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..ec457b89bf 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -36,6 +36,7 @@ void ethdev_stop(void);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
+int16_t ethdev_txport_by_rxport_get(uint16_t portid_rx);
 void ethdev_list_clean(void);
 
 #endif
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..861e83bd70
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..67308b3b72
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..20894b64fe
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc = 0;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = ethdev_txport_by_rxport_get(port_id);
+		if (txport >= 0) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				goto exit;
+		} else {
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+exit:
+	return rc;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 0aab41cbca..5308967b6b 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -325,3 +339,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..15763d8fa5
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_tx -> egress_port [label="egress packet"]
+    ethdev_tx -> pkt_drop [color="red" style="dashed"]
+}
+ -->
+
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="253pt" height="291pt"
+ viewBox="0.00 0.00 253.00 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-287 249,-287 249,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="165,-283 59,-283 59,-247 165,-247 165,-283"/>
+<text text-anchor="middle" x="112" y="-261.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-178" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="112" y="-174.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M112,-246.8C112,-235.16 112,-219.55 112,-206.24"/>
+<polygon fill="black" stroke="black" points="115.5,-206.18 112,-196.18 108.5,-206.18 115.5,-206.18"/>
+<text text-anchor="middle" x="164.5" y="-217.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-105" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="112" y="-101.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M112,-159.81C112,-151.79 112,-142.05 112,-133.07"/>
+<polygon fill="black" stroke="black" points="115.5,-133.03 112,-123.03 108.5,-133.03 115.5,-133.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="52" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="52" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_tx&#45;&gt;pkt_drop -->
+<g id="edge4" class="edge">
+<title>ethdev_tx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="red" stroke-dasharray="5,2" d="M100.14,-87.21C91.43,-74.87 79.45,-57.89 69.62,-43.97"/>
+<polygon fill="red" stroke="red" points="72.45,-41.91 63.82,-35.76 66.73,-45.95 72.45,-41.91"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="222.5,-36 121.5,-36 121.5,0 222.5,0 222.5,-36"/>
+<text text-anchor="middle" x="172" y="-14.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+<!-- ethdev_tx&#45;&gt;egress_port -->
+<g id="edge3" class="edge">
+<title>ethdev_tx&#45;&gt;egress_port</title>
+<path fill="none" stroke="black" d="M123.85,-87.21C132.5,-74.95 144.39,-58.11 154.18,-44.24"/>
+<polygon fill="black" stroke="black" points="157.05,-46.24 159.96,-36.05 151.33,-42.2 157.05,-46.24"/>
+<text text-anchor="middle" x="195" y="-57.8" font-family="Times,serif" font-size="14.00">egress packet</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v10 1/3] node: support to add next node to ethdev Rx node
  2024-01-02  7:28               ` [PATCH v9 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2024-01-02  7:28                 ` [PATCH v9 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2024-01-02  7:28                 ` [PATCH v9 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2024-01-02  7:30                 ` Rakesh Kudurumalla
  2024-01-02  7:30                   ` [PATCH v10 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
                                     ` (4 more replies)
  2 siblings, 5 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-02  7:30 UTC (permalink / raw)
  To: Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, jerinj, Rakesh Kudurumalla

By default all packets received on ethdev_rx node
is forwarded to pkt_cls node.This patch provides
library support to add a new node as next node to
ethdev_rx node and forward packet to new node from
rx node.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
v10: Code style

 lib/node/ethdev_ctrl.c      | 48 +++++++++++++++++++++++++++++++++++++
 lib/node/rte_node_eth_api.h | 18 ++++++++++++++
 lib/node/version.map        |  3 +++
 3 files changed, 69 insertions(+)

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index d564b80e37..cd52e8be08 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -2,6 +2,7 @@
  * Copyright(C) 2020 Marvell International Ltd.
  */
 
+#include <errno.h>
 #include <stdlib.h>
 
 #include <rte_ethdev.h>
@@ -129,3 +130,50 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	ctrl.nb_graphs = nb_graphs;
 	return 0;
 }
+
+int
+rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name)
+{
+	struct ethdev_rx_node_main *data;
+	ethdev_rx_node_elem_t *elem;
+	char **next_nodes;
+	int rc = -EINVAL;
+	uint16_t i = 0;
+	uint32_t size;
+
+	if (edge_name == NULL)
+		goto exit;
+
+	size = rte_node_edge_get(id, NULL);
+
+	if (size == RTE_NODE_ID_INVALID)
+		goto exit;
+
+	next_nodes = calloc((size / sizeof(char *)) + 1, sizeof(*next_nodes));
+	if (next_nodes == NULL) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	size = rte_node_edge_get(id, next_nodes);
+
+	while (next_nodes[i] != NULL) {
+		if (strcmp(edge_name, next_nodes[i]) == 0) {
+			data = ethdev_rx_get_node_data_get();
+			elem = data->head;
+			while (elem->next != data->head) {
+				if (elem->nid == id) {
+					elem->ctx.cls_next = i;
+					rc = 0;
+					goto found;
+				}
+				elem = elem->next;
+			}
+		}
+		i++;
+	}
+found:
+	free(next_nodes);
+exit:
+	return rc;
+}
diff --git a/lib/node/rte_node_eth_api.h b/lib/node/rte_node_eth_api.h
index eaae50772d..d2f705e908 100644
--- a/lib/node/rte_node_eth_api.h
+++ b/lib/node/rte_node_eth_api.h
@@ -22,6 +22,7 @@ extern "C" {
 
 #include <rte_compat.h>
 #include <rte_common.h>
+#include <rte_graph.h>
 #include <rte_mempool.h>
 
 /**
@@ -57,6 +58,23 @@ struct rte_node_ethdev_config {
  */
 int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
 			uint16_t cnt, uint16_t nb_graphs);
+
+/**
+ * Update ethdev rx next node.
+ *
+ * @param id
+ *   Node id whose edge is to be updated.
+ * @param edge_name
+ *   Name of the next node.
+ *
+ * @return
+ *   ENINVAL: Either of input parameters are invalid
+ *   ENOMEM: If memory allocation failed
+ *   0 on successful initialization.
+ */
+__rte_experimental
+int rte_node_ethdev_rx_next_update(rte_node_t id, const char *edge_name);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/node/version.map b/lib/node/version.map
index 99ffcdd414..6bdb944c4c 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -19,4 +19,7 @@ EXPERIMENTAL {
 	rte_node_ip4_reassembly_configure;
 	rte_node_udp4_dst_port_add;
 	rte_node_udp4_usr_node_add;
+
+	# added in 24.03
+	rte_node_ethdev_rx_next_update;
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v10 2/3] app/graph: add ethdev forward command
  2024-01-02  7:30                 ` [PATCH v10 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
@ 2024-01-02  7:30                   ` Rakesh Kudurumalla
  2024-01-02  7:30                   ` [PATCH v10 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
                                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-02  7:30 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Adds a txport to forward packet for every rxport

Mapping will be used to forward packets to txport
received on rxport

Following commands are exposed:
	- ethdev forward <tx_dev_name> <rx_dev_name>"

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
Acked-by: Sunil Kumar Kori <skori@marvell.com>
---
 app/graph/cli.c            |  1 +
 app/graph/ethdev.c         | 63 ++++++++++++++++++++++++++++++++++++++
 app/graph/ethdev.h         |  1 +
 app/graph/ethdev_priv.h    |  8 +++++
 doc/guides/tools/graph.rst |  4 +++
 5 files changed, 77 insertions(+)

diff --git a/app/graph/cli.c b/app/graph/cli.c
index 30b12312d6..76f5b8e670 100644
--- a/app/graph/cli.c
+++ b/app/graph/cli.c
@@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = {
 	(cmdline_parse_inst_t *)&ethdev_prom_mode_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip4_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_ip6_cmd_ctx,
+	(cmdline_parse_inst_t *)&ethdev_forward_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_help_cmd_ctx,
 	(cmdline_parse_inst_t *)&ethdev_rx_cmd_ctx,
diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index c9b09168c1..bb502a6134 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -38,6 +38,9 @@ cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <ma
 static const char
 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
 
+static const char
+cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
+
 static struct rte_eth_conf port_conf_default = {
 	.link_speeds = 0,
 	.rxmode = {
@@ -888,3 +891,63 @@ cmdline_parse_inst_t ethdev_help_cmd_ctx = {
 		NULL,
 	},
 };
+
+static int
+ethdev_forward_config(char *tx_dev, char *rx_dev)
+{
+	uint16_t portid_rx = 0;
+	uint16_t portid_tx = 0;
+	struct ethdev *port;
+	int rc = -EINVAL;
+
+	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
+	if (rc < 0)
+		return rc;
+
+	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
+	if (rc < 0)
+		return rc;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port) {
+		port->tx_port_id = portid_tx;
+		rc = 0;
+	} else {
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void
+cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
+{
+	struct ethdev_fwd_cmd_tokens *res = parsed_result;
+	int rc = -EINVAL;
+
+	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
+	if (rc < 0)
+		printf(MSG_CMD_FAIL, res->cmd);
+}
+
+cmdline_parse_token_string_t ethdev_fwd_cfg =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
+cmdline_parse_token_string_t ethdev_fwd_cmd =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
+cmdline_parse_token_string_t ethdev_tx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
+cmdline_parse_token_string_t ethdev_rx_device =
+	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
+
+cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
+	.f = cli_ethdev_forward,
+	.data = NULL,
+	.help_str = cmd_ethdev_forward_help,
+	.tokens = {
+	       (void *)&ethdev_fwd_cfg,
+	       (void *)&ethdev_fwd_cmd,
+	       (void *)&ethdev_tx_device,
+	       (void *)&ethdev_rx_device,
+	       NULL,
+	},
+};
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 94d3247a2c..836052046b 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -15,6 +15,7 @@ extern cmdline_parse_inst_t ethdev_mtu_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip4_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_ip6_cmd_ctx;
+extern cmdline_parse_inst_t ethdev_forward_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_cmd_ctx;
 extern cmdline_parse_inst_t ethdev_help_cmd_ctx;
 
diff --git a/app/graph/ethdev_priv.h b/app/graph/ethdev_priv.h
index f231f3f3e1..af79553438 100644
--- a/app/graph/ethdev_priv.h
+++ b/app/graph/ethdev_priv.h
@@ -61,6 +61,13 @@ struct ethdev_ip6_cmd_tokens {
 	cmdline_fixed_string_t mask;
 };
 
+struct ethdev_fwd_cmd_tokens {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t fwd;
+	cmdline_fixed_string_t tx_dev;
+	cmdline_fixed_string_t rx_dev;
+};
+
 struct ethdev_cmd_tokens {
 	cmdline_fixed_string_t cmd;
 	cmdline_fixed_string_t dev;
@@ -104,6 +111,7 @@ struct ethdev_config {
 
 struct ethdev {
 	TAILQ_ENTRY(ethdev) next;
+	uint16_t tx_port_id;
 	struct ethdev_config config;
 	struct ipv4_addr_config ip4_addr;
 	struct ipv6_addr_config ip6_addr;
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 1855d12891..0aab41cbca 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -195,6 +195,9 @@ file to express the requested use case configuration.
    | ethdev <ethdev_name> mtu <mtu_sz>    | | Command to configure MTU of DPDK|   Yes   |    Yes   |
    |                                      | | port.                           |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
+   | | ethdev forward <tx_dev_name>       | | Command to configure port       |   No    |    Yes   |
+   | | <rx_dev_name>                      | | forwarding of DPDK              |         |          |
+   +--------------------------------------+-----------------------------------+---------+----------+
    |  | ethdev <ethdev_name> promiscuous  | | Command to enable/disable       |   Yes   |    Yes   |
    |  | <on/off>                          | | promiscuous mode on DPDK port.  |         |          |
    +--------------------------------------+-----------------------------------+---------+----------+
@@ -297,6 +300,7 @@ Example: ``dpdk-graph`` is started with ``-h 10.28.35.207`` and ``-p 50000`` the
    ethdev <ethdev_name> rxq <n_queues> txq <n_queues> <mempool_name>
    ethdev <ethdev_name> ip4 addr add <ip> netmask <mask>
    ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>
+   ethdev forward <tx_dev_name> <rx_dev_name>
    ethdev <ethdev_name> promiscuous <on/off>
    ethdev <ethdev_name> mtu <mtu_sz>
    ethdev <ethdev_name> stats
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v10 3/3] app/graph: implement port forward usecase
  2024-01-02  7:30                 ` [PATCH v10 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2024-01-02  7:30                   ` [PATCH v10 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
@ 2024-01-02  7:30                   ` Rakesh Kudurumalla
  2024-02-18 22:22                     ` Thomas Monjalon
  2024-01-02  9:20                   ` [EXT] [PATCH v10 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
                                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 45+ messages in thread
From: Rakesh Kudurumalla @ 2024-01-02  7:30 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla; +Cc: dev, jerinj, ndabilpuram

Added portforward usecase.In this usecase
packets received Rx port is forwarded to
respective Tx port.

Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
Acked-by: Sunil Kumar Kori <skori@marvell.com>
---
 app/graph/ethdev.c                           |  13 ++
 app/graph/ethdev.h                           |   1 +
 app/graph/examples/l2fwd.cli                 |  41 +++++
 app/graph/examples/l2fwd_pcap.cli            |  37 +++++
 app/graph/graph.c                            |   8 +-
 app/graph/l2fwd.c                            | 152 +++++++++++++++++++
 app/graph/l2fwd.h                            |  11 ++
 app/graph/meson.build                        |   1 +
 app/graph/module_api.h                       |   1 +
 doc/guides/tools/graph.rst                   |  21 +++
 doc/guides/tools/img/graph-usecase-l2fwd.svg |  92 +++++++++++
 11 files changed, 377 insertions(+), 1 deletion(-)
 create mode 100644 app/graph/examples/l2fwd.cli
 create mode 100644 app/graph/examples/l2fwd_pcap.cli
 create mode 100644 app/graph/l2fwd.c
 create mode 100644 app/graph/l2fwd.h
 create mode 100644 doc/guides/tools/img/graph-usecase-l2fwd.svg

diff --git a/app/graph/ethdev.c b/app/graph/ethdev.c
index bb502a6134..a622275338 100644
--- a/app/graph/ethdev.c
+++ b/app/graph/ethdev.c
@@ -76,6 +76,19 @@ ethdev_port_by_id(uint16_t port_id)
 	return NULL;
 }
 
+int16_t
+ethdev_txport_by_rxport_get(uint16_t portid_rx)
+{
+	int portid = -EINVAL;
+	struct ethdev *port;
+
+	port = ethdev_port_by_id(portid_rx);
+	if (port)
+		portid = port->tx_port_id;
+
+	return portid;
+}
+
 void *
 ethdev_mempool_list_by_portid(uint16_t portid)
 {
diff --git a/app/graph/ethdev.h b/app/graph/ethdev.h
index 836052046b..ec457b89bf 100644
--- a/app/graph/ethdev.h
+++ b/app/graph/ethdev.h
@@ -36,6 +36,7 @@ void ethdev_stop(void);
 void *ethdev_mempool_list_by_portid(uint16_t portid);
 int16_t ethdev_portid_by_ip4(uint32_t ip, uint32_t mask);
 int16_t ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask);
+int16_t ethdev_txport_by_rxport_get(uint16_t portid_rx);
 void ethdev_list_clean(void);
 
 #endif
diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli
new file mode 100644
index 0000000000..861e83bd70
--- /dev/null
+++ b/app/graph/examples/l2fwd.cli
@@ -0,0 +1,41 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev 0002:01:00.1 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.4 rxq 1 txq 8 mempool0
+ethdev 0002:01:00.6 rxq 1 txq 8 mempool0
+ethdev 0002:02:00.0 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward 0002:01:00.4 0002:02:00.0
+ethdev forward 0002:01:00.1 0002:01:00.6
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:02:00.0 queue 0 core 1
+ethdev_rx map port 0002:01:00.6 queue 0 core 2
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/examples/l2fwd_pcap.cli b/app/graph/examples/l2fwd_pcap.cli
new file mode 100644
index 0000000000..67308b3b72
--- /dev/null
+++ b/app/graph/examples/l2fwd_pcap.cli
@@ -0,0 +1,37 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap
+
+;
+; Mempools to be attached with ethdev
+;
+mempool mempool0 size 8192 buffers 4000 cache 256 numa 0
+
+;
+; DPDK devices and configuration.
+;
+; Note: Customize the parameters below to match your setup.
+;
+ethdev net_pcap0 rxq 1 txq 8 mempool0
+ethdev net_pcap1 rxq 1 txq 8 mempool0
+
+;
+; Rx/Tx port mapping
+;
+ethdev forward net_pcap1 net_pcap0
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port net_pcap0 queue 0 core 1
+
+;
+; Graph start command to create graph.
+;
+; Note: No more command should come after this.
+;
+graph start
diff --git a/app/graph/graph.c b/app/graph/graph.c
index a65723a196..4e0441f1a7 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
 		   "pcap_file <output_capture_file>";
 
-static const char * const supported_usecases[] = {"l3fwd"};
+static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
 struct graph_config graph_config;
 bool graph_started;
 
@@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 				break;
 			}
 		}
+		if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
+			if (graph_config.usecases[i].enabled) {
+				rc  = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
+				break;
+			}
+		}
 	}
 
 	if (!rc)
diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c
new file mode 100644
index 0000000000..20894b64fe
--- /dev/null
+++ b/app/graph/l2fwd.c
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_lcore.h>
+#include <rte_node_eth_api.h>
+
+#include "module_api.h"
+
+static int
+l2fwd_pattern_configure(void)
+{
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	uint64_t pcap_pkts_count;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t pcap_ena;
+	char *pcap_file;
+	int lcore_id;
+
+	nb_patterns = 0;
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file);
+	graph_conf.pcap_enable = pcap_ena;
+	graph_conf.num_pkt_to_capture = pcap_pkts_count;
+	graph_conf.pcap_filename = strdup(pcap_file);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rte_graph_t graph_id;
+		rte_edge_t i;
+
+		if (rte_lcore_is_enabled(lcore_id) == 0)
+			continue;
+
+		qconf = &lcore_conf[lcore_id];
+
+		/* Skip graph creation if no source exists */
+		if (!qconf->n_rx_queue)
+			continue;
+
+		/* Add rx node patterns of this lcore */
+		for (i = 0; i < qconf->n_rx_queue; i++) {
+			graph_conf.node_patterns[nb_patterns + i] =
+				qconf->rx_queue_list[i].node_name;
+		}
+
+		graph_conf.nb_node_patterns = nb_patterns + i;
+		graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);
+
+		snprintf(qconf->name, sizeof(qconf->name), "worker_%u",
+				lcore_id);
+
+		graph_id = rte_graph_create(qconf->name, &graph_conf);
+		if (graph_id == RTE_GRAPH_ID_INVALID)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_create(): graph_id invalid"
+					" for lcore %u\n", lcore_id);
+
+		qconf->graph_id = graph_id;
+		qconf->graph = rte_graph_lookup(qconf->name);
+		/* >8 End of graph initialization. */
+		if (!qconf->graph)
+			rte_exit(EXIT_FAILURE,
+					"rte_graph_lookup(): graph %s not found\n",
+					qconf->name);
+	}
+
+	/* Launch per-lcore init on every worker lcore */
+	rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN);
+
+	/* Accumulate and print stats on main until exit */
+	if (rte_graph_has_stats_feature() && app_graph_stats_enabled())
+		graph_stats_print();
+
+	return 0;
+}
+
+static int
+ethdev_rx_to_tx_node_link(uint32_t lcore_id)
+{
+	char name[RTE_NODE_NAMESIZE];
+	const char *next_node = name;
+	struct lcore_conf *qconf;
+	uint16_t queue, port_id;
+	rte_node_t rx_id;
+	int16_t txport;
+	int rc = 0;
+
+	qconf = &lcore_conf[lcore_id];
+
+	for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+		port_id = qconf->rx_queue_list[queue].port_id;
+		txport = ethdev_txport_by_rxport_get(port_id);
+		if (txport >= 0) {
+			rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name);
+			snprintf(name, sizeof(name), "ethdev_tx-%u", txport);
+			rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1);
+			rc = rte_node_ethdev_rx_next_update(rx_id, name);
+			if (rc)
+				goto exit;
+		} else {
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+exit:
+	return rc;
+}
+
+
+int
+usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	uint32_t lcore_id;
+	int rc;
+
+	rc = rte_node_eth_config(conf, nb_confs, nb_graphs);
+	if (rc)
+		rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+		rc = ethdev_rx_to_tx_node_link(lcore_id);
+		if (rc)
+			rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc);
+	}
+
+	rc = l2fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h
new file mode 100644
index 0000000000..3486ce52b2
--- /dev/null
+++ b/app/graph/l2fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L2FWD_H
+#define APP_GRAPH_L2FWD_H
+
+int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf,
+			    uint16_t nb_graphs);
+
+#endif
diff --git a/app/graph/meson.build b/app/graph/meson.build
index 5b0f966d99..edd6b17ebc 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -17,6 +17,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l2fwd.c',
         'l3fwd.c',
         'main.c',
         'mempool.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 7193e0b616..c80eeb704c 100644
--- a/app/graph/module_api.h
+++ b/app/graph/module_api.h
@@ -13,6 +13,7 @@
 #include "ethdev.h"
 #include "ethdev_rx.h"
 #include "graph.h"
+#include "l2fwd.h"
 #include "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
diff --git a/doc/guides/tools/graph.rst b/doc/guides/tools/graph.rst
index 0aab41cbca..5308967b6b 100644
--- a/doc/guides/tools/graph.rst
+++ b/doc/guides/tools/graph.rst
@@ -77,6 +77,13 @@ This use case is supported for both H/W and PCAP vdev network devices.
 To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
 named as ``l3fwd.cli`` and ``l3fwd_pcap.cli`` respectively.
 
+l2fwd
+~~~~~
+
+This use case is supported for both H/W and PCAP vdev network devices.
+To demonstrate, corresponding ``.cli`` files are available at ``app/graph/examples/``
+named as ``l2fwd.cli`` and ``l2fwd_pcap.cli`` respectively.
+
 Example Commands
 ^^^^^^^^^^^^^^^^
 For H/W devices
@@ -86,6 +93,9 @@ For H/W devices
    ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
                 -s <dpdk_root_dir>/app/graph/examples/l3fwd.cli
 
+   ./dpdk-graph -c 0xff -a 0002:02:00.0 -a 0002:03:00.0 --
+                -s <dpdk_root_dir>/app/graph/examples/l2fwd.cli
+
 For net_pcapX devices
 
 .. code-block:: console
@@ -94,6 +104,10 @@ For net_pcapX devices
                         --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
                         -- -s <dpdk_root_dir>/app/graph/examples/l3fwd_pcap.cli
 
+   ./dpdk-graph -c 0xff --vdev=net_pcap0,rx_pcap=in_net_pcap0.pcap,tx_pcap=out_net_pcap1.pcap
+                        --vdev=net_pcap1,rx_pcap=in_net_pcap1.pcap,tx_pcap=out_net_pcap0.pcap
+                        -- -s <dpdk_root_dir>/app/graph/examples/l2fwd_pcap.cli
+
 Verifying traffic
 ^^^^^^^^^^^^^^^^^
 
@@ -325,3 +339,10 @@ l3fwd
 .. _figure_l3fwd_graph:
 
 .. figure:: img/graph-usecase-l3fwd.*
+
+l2fwd
+~~~~~
+
+.. _figure_l2fwd_graph:
+
+.. figure:: img/graph-usecase-l2fwd.*
diff --git a/doc/guides/tools/img/graph-usecase-l2fwd.svg b/doc/guides/tools/img/graph-usecase-l2fwd.svg
new file mode 100644
index 0000000000..15763d8fa5
--- /dev/null
+++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.43.0 (0)
+ -->
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright(C) 2023 Marvell. -->
+<!--
+
+Generated with following command
+dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
+
+cat dot.dot
+digraph dpdk_app_graph_l2fwd_nodes_flow {
+    ingress_port [shape=rect]
+    ethdev_rx
+    ethdev_tx
+    pkt_drop
+    egress_port  [shape=rect]
+
+    ingress_port -> ethdev_rx [label="ingress packet"]
+
+    ethdev_rx -> ethdev_tx
+    ethdev_tx -> egress_port [label="egress packet"]
+    ethdev_tx -> pkt_drop [color="red" style="dashed"]
+}
+ -->
+
+<!-- Title: dpdk_app_graph_l2fwd_nodes_flow Pages: 1 -->
+<svg width="253pt" height="291pt"
+ viewBox="0.00 0.00 253.00 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
+<title>dpdk_app_graph_l2fwd_nodes_flow</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-287 249,-287 249,4 -4,4"/>
+<!-- ingress_port -->
+<g id="node1" class="node">
+<title>ingress_port</title>
+<polygon fill="none" stroke="black" points="165,-283 59,-283 59,-247 165,-247 165,-283"/>
+<text text-anchor="middle" x="112" y="-261.3" font-family="Times,serif" font-size="14.00">ingress_port</text>
+</g>
+<!-- ethdev_rx -->
+<g id="node2" class="node">
+<title>ethdev_rx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-178" rx="56.59" ry="18"/>
+<text text-anchor="middle" x="112" y="-174.3" font-family="Times,serif" font-size="14.00">ethdev_rx</text>
+</g>
+<!-- ingress_port&#45;&gt;ethdev_rx -->
+<g id="edge1" class="edge">
+<title>ingress_port&#45;&gt;ethdev_rx</title>
+<path fill="none" stroke="black" d="M112,-246.8C112,-235.16 112,-219.55 112,-206.24"/>
+<polygon fill="black" stroke="black" points="115.5,-206.18 112,-196.18 108.5,-206.18 115.5,-206.18"/>
+<text text-anchor="middle" x="164.5" y="-217.8" font-family="Times,serif" font-size="14.00">ingress packet</text>
+</g>
+<!-- ethdev_tx -->
+<g id="node3" class="node">
+<title>ethdev_tx</title>
+<ellipse fill="none" stroke="black" cx="112" cy="-105" rx="55.79" ry="18"/>
+<text text-anchor="middle" x="112" y="-101.3" font-family="Times,serif" font-size="14.00">ethdev_tx</text>
+</g>
+<!-- ethdev_rx&#45;&gt;ethdev_tx -->
+<g id="edge2" class="edge">
+<title>ethdev_rx&#45;&gt;ethdev_tx</title>
+<path fill="none" stroke="black" d="M112,-159.81C112,-151.79 112,-142.05 112,-133.07"/>
+<polygon fill="black" stroke="black" points="115.5,-133.03 112,-123.03 108.5,-133.03 115.5,-133.03"/>
+</g>
+<!-- pkt_drop -->
+<g id="node4" class="node">
+<title>pkt_drop</title>
+<ellipse fill="none" stroke="black" cx="52" cy="-18" rx="51.99" ry="18"/>
+<text text-anchor="middle" x="52" y="-14.3" font-family="Times,serif" font-size="14.00">pkt_drop</text>
+</g>
+<!-- ethdev_tx&#45;&gt;pkt_drop -->
+<g id="edge4" class="edge">
+<title>ethdev_tx&#45;&gt;pkt_drop</title>
+<path fill="none" stroke="red" stroke-dasharray="5,2" d="M100.14,-87.21C91.43,-74.87 79.45,-57.89 69.62,-43.97"/>
+<polygon fill="red" stroke="red" points="72.45,-41.91 63.82,-35.76 66.73,-45.95 72.45,-41.91"/>
+</g>
+<!-- egress_port -->
+<g id="node5" class="node">
+<title>egress_port</title>
+<polygon fill="none" stroke="black" points="222.5,-36 121.5,-36 121.5,0 222.5,0 222.5,-36"/>
+<text text-anchor="middle" x="172" y="-14.3" font-family="Times,serif" font-size="14.00">egress_port</text>
+</g>
+<!-- ethdev_tx&#45;&gt;egress_port -->
+<g id="edge3" class="edge">
+<title>ethdev_tx&#45;&gt;egress_port</title>
+<path fill="none" stroke="black" d="M123.85,-87.21C132.5,-74.95 144.39,-58.11 154.18,-44.24"/>
+<polygon fill="black" stroke="black" points="157.05,-46.24 159.96,-36.05 151.33,-42.2 157.05,-46.24"/>
+<text text-anchor="middle" x="195" y="-57.8" font-family="Times,serif" font-size="14.00">egress packet</text>
+</g>
+</g>
+</svg>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* RE: [EXT] [PATCH v10 1/3] node: support to add next node to ethdev Rx node
  2024-01-02  7:30                 ` [PATCH v10 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
  2024-01-02  7:30                   ` [PATCH v10 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
  2024-01-02  7:30                   ` [PATCH v10 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2024-01-02  9:20                   ` Sunil Kumar Kori
  2024-02-18 23:15                   ` Thomas Monjalon
  2024-02-18 23:17                   ` Thomas Monjalon
  4 siblings, 0 replies; 45+ messages in thread
From: Sunil Kumar Kori @ 2024-01-02  9:20 UTC (permalink / raw)
  To: Rakesh Kudurumalla, Nithin Kumar Dabilpuram, Pavan Nikhilesh Bhagavatula
  Cc: dev, Jerin Jacob Kollanukkaran, Rakesh Kudurumalla

> -----Original Message-----
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Sent: Tuesday, January 2, 2024 1:01 PM
> To: Nithin Kumar Dabilpuram <ndabilpuram@marvell.com>; Pavan
> Nikhilesh Bhagavatula <pbhagavatula@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> Rakesh Kudurumalla <rkudurumalla@marvell.com>
> Subject: [EXT] [PATCH v10 1/3] node: support to add next node to ethdev Rx
> node
> 
> External Email
> 
> ----------------------------------------------------------------------
> By default all packets received on ethdev_rx node is forwarded to pkt_cls
> node.This patch provides library support to add a new node as next node to
> ethdev_rx node and forward packet to new node from rx node.
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
> v10: Code style
> 
>  lib/node/ethdev_ctrl.c      | 48
> +++++++++++++++++++++++++++++++++++++
>  lib/node/rte_node_eth_api.h | 18 ++++++++++++++
>  lib/node/version.map        |  3 +++
>  3 files changed, 69 insertions(+)
> 

Acked-by: Sunil Kumar Kori <skori@marvell.com>

> 2.25.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v10 3/3] app/graph: implement port forward usecase
  2024-01-02  7:30                   ` [PATCH v10 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
@ 2024-02-18 22:22                     ` Thomas Monjalon
  2024-02-19  3:14                       ` Jerin Jacob
  0 siblings, 1 reply; 45+ messages in thread
From: Thomas Monjalon @ 2024-02-18 22:22 UTC (permalink / raw)
  To: Sunil Kumar Kori, Rakesh Kudurumalla, jerinj; +Cc: dev, ndabilpuram

02/01/2024 08:30, Rakesh Kudurumalla:
> --- /dev/null
> +++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
> @@ -0,0 +1,92 @@
> +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> +<!-- Generated by graphviz version 2.43.0 (0)
> + -->
> +<!-- SPDX-License-Identifier: BSD-3-Clause -->
> +<!-- Copyright(C) 2023 Marvell. -->
> +<!--
> +
> +Generated with following command
> +dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
> +
> +cat dot.dot
> +digraph dpdk_app_graph_l2fwd_nodes_flow {
> +    ingress_port [shape=rect]
> +    ethdev_rx
> +    ethdev_tx
> +    pkt_drop
> +    egress_port  [shape=rect]
> +
> +    ingress_port -> ethdev_rx [label="ingress packet"]
> +
> +    ethdev_rx -> ethdev_tx
> +    ethdev_tx -> egress_port [label="egress packet"]
> +    ethdev_tx -> pkt_drop [color="red" style="dashed"]
> +}
> + -->

We could include this syntax directly in .rst file
with this Sphinx extension:
https://www.sphinx-doc.org/en/master/usage/extensions/graphviz.html




^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v10 1/3] node: support to add next node to ethdev Rx node
  2024-01-02  7:30                 ` [PATCH v10 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
                                     ` (2 preceding siblings ...)
  2024-01-02  9:20                   ` [EXT] [PATCH v10 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
@ 2024-02-18 23:15                   ` Thomas Monjalon
  2024-02-18 23:17                   ` Thomas Monjalon
  4 siblings, 0 replies; 45+ messages in thread
From: Thomas Monjalon @ 2024-02-18 23:15 UTC (permalink / raw)
  To: Rakesh Kudurumalla; +Cc: Nithin Dabilpuram, Pavan Nikhilesh, dev, jerinj

02/01/2024 08:30, Rakesh Kudurumalla:
> +/**
> + * Update ethdev rx next node.
> + *
> + * @param id
> + *   Node id whose edge is to be updated.
> + * @param edge_name
> + *   Name of the next node.
> + *
> + * @return
> + *   ENINVAL: Either of input parameters are invalid

typo: EINVAL

> + *   ENOMEM: If memory allocation failed
> + *   0 on successful initialization.

The errors are rendered on the same line by Doxygen.
Fixed by making it a list.




^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v10 1/3] node: support to add next node to ethdev Rx node
  2024-01-02  7:30                 ` [PATCH v10 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
                                     ` (3 preceding siblings ...)
  2024-02-18 23:15                   ` Thomas Monjalon
@ 2024-02-18 23:17                   ` Thomas Monjalon
  4 siblings, 0 replies; 45+ messages in thread
From: Thomas Monjalon @ 2024-02-18 23:17 UTC (permalink / raw)
  To: Rakesh Kudurumalla; +Cc: Nithin Dabilpuram, Pavan Nikhilesh, dev, jerinj

02/01/2024 08:30, Rakesh Kudurumalla:
> By default all packets received on ethdev_rx node
> is forwarded to pkt_cls node.This patch provides
> library support to add a new node as next node to
> ethdev_rx node and forward packet to new node from
> rx node.
> 
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>

Series applied with few doxygen fixes.




^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v10 3/3] app/graph: implement port forward usecase
  2024-02-18 22:22                     ` Thomas Monjalon
@ 2024-02-19  3:14                       ` Jerin Jacob
  0 siblings, 0 replies; 45+ messages in thread
From: Jerin Jacob @ 2024-02-19  3:14 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: Sunil Kumar Kori, Rakesh Kudurumalla, jerinj, dev, ndabilpuram

On Mon, Feb 19, 2024 at 4:00 AM Thomas Monjalon <thomas@monjalon.net> wrote:
>
> 02/01/2024 08:30, Rakesh Kudurumalla:
> > --- /dev/null
> > +++ b/doc/guides/tools/img/graph-usecase-l2fwd.svg
> > @@ -0,0 +1,92 @@
> > +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
> > +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> > + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> > +<!-- Generated by graphviz version 2.43.0 (0)
> > + -->
> > +<!-- SPDX-License-Identifier: BSD-3-Clause -->
> > +<!-- Copyright(C) 2023 Marvell. -->
> > +<!--
> > +
> > +Generated with following command
> > +dot -Tsvg dot.dot -o doc/guides/tools/img/graph-usecase-l2fwd.svg
> > +
> > +cat dot.dot
> > +digraph dpdk_app_graph_l2fwd_nodes_flow {
> > +    ingress_port [shape=rect]
> > +    ethdev_rx
> > +    ethdev_tx
> > +    pkt_drop
> > +    egress_port  [shape=rect]
> > +
> > +    ingress_port -> ethdev_rx [label="ingress packet"]
> > +
> > +    ethdev_rx -> ethdev_tx
> > +    ethdev_tx -> egress_port [label="egress packet"]
> > +    ethdev_tx -> pkt_drop [color="red" style="dashed"]
> > +}
> > + -->
>
> We could include this syntax directly in .rst file
> with this Sphinx extension:
> https://www.sphinx-doc.org/en/master/usage/extensions/graphviz.html

I checked that option earlier. Created this scheme to avoid graphviz
package dependency
to DPDK.


commit 597f51c34826b3b12b6a1ac9d54e9160aaa49ef7
Author: Jerin Jacob <jerinj@marvell.com>
Date:   Fri Jun 23 13:06:00 2023 +0530

    doc: add inbuilt graph nodes data flow

    Added diagram to depict the data flow between inbuilt
    graph nodes.

    In order to avoid graphviz package dependency to DPDK
    documentation, manual step added to create a svg file
    from the dot file. The details for the same is documented
    in graph_inbuilt_node_flow.svg as a comment.

    Signed-off-by: Jerin Jacob <jerinj@marvell.com>
    Reviewed-by: Zhirun Yan <zhirun.yan@intel.com>
>
>
>

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2024-02-19  3:14 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-23  6:15 [PATCH 1/2] node: forward packet from ethdev_rx node Rakesh Kudurumalla
2023-11-23  6:15 ` [PATCH 2/2] app/graph: implement L2FWD usecase Rakesh Kudurumalla
2023-11-24  8:13   ` Sunil Kumar Kori
2023-11-24  7:45 ` [EXT] [PATCH 1/2] node: forward packet from ethdev_rx node Sunil Kumar Kori
2023-12-04 18:04 ` [PATCH v2 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
2023-12-04 18:04   ` [PATCH v2 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2023-12-04 18:04   ` [PATCH v2 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2023-12-05  7:46   ` [PATCH v3 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
2023-12-05  7:46     ` [PATCH v3 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2023-12-05  7:46     ` [PATCH v3 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2023-12-05  9:27     ` [PATCH v4 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
2023-12-05  9:27       ` [PATCH v4 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2023-12-07 10:38         ` Sunil Kumar Kori
2023-12-05  9:27       ` [PATCH v4 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2023-12-07 11:07         ` Sunil Kumar Kori
2023-12-07  8:26       ` [EXT] [PATCH v4 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
2023-12-07  9:30       ` David Marchand
2023-12-15  9:15       ` [PATCH v5 " Rakesh Kudurumalla
2023-12-15  9:15         ` [PATCH v5 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2023-12-18 10:44           ` Sunil Kumar Kori
2023-12-15  9:15         ` [PATCH v5 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2023-12-18 10:57           ` Sunil Kumar Kori
2023-12-18 10:41         ` [EXT] [PATCH v5 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
2023-12-20  8:59         ` [PATCH v6 " Rakesh Kudurumalla
2023-12-20  8:59           ` [PATCH v6 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2023-12-20  8:59           ` [PATCH v6 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2023-12-20  9:44           ` [PATCH v7 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
2023-12-20  9:44             ` [PATCH v7 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2023-12-20  9:44             ` [PATCH v7 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2024-01-01  8:37             ` [PATCH v8 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
2024-01-01  8:37               ` [PATCH v8 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2024-01-02  6:45                 ` Sunil Kumar Kori
2024-01-01  8:37               ` [PATCH v8 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2024-01-02  6:46                 ` Sunil Kumar Kori
2024-01-02  7:28               ` [PATCH v9 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
2024-01-02  7:28                 ` [PATCH v9 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2024-01-02  7:28                 ` [PATCH v9 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2024-01-02  7:30                 ` [PATCH v10 1/3] node: support to add next node to ethdev Rx node Rakesh Kudurumalla
2024-01-02  7:30                   ` [PATCH v10 2/3] app/graph: add ethdev forward command Rakesh Kudurumalla
2024-01-02  7:30                   ` [PATCH v10 3/3] app/graph: implement port forward usecase Rakesh Kudurumalla
2024-02-18 22:22                     ` Thomas Monjalon
2024-02-19  3:14                       ` Jerin Jacob
2024-01-02  9:20                   ` [EXT] [PATCH v10 1/3] node: support to add next node to ethdev Rx node Sunil Kumar Kori
2024-02-18 23:15                   ` Thomas Monjalon
2024-02-18 23:17                   ` Thomas Monjalon

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