diff --git a/app/graph/examples/l3fwd.cli b/app/graph/examples/l3fwd.cli
new file mode 100644
index 0000000000..6b0d9ac770
--- /dev/null
+++ b/app/graph/examples/l3fwd.cli
@@ -0,0 +1,87 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2023 Marvell.
+
+;
+; Graph configuration for given usecase
+;
+graph l3fwd coremask 0xff bsz 32 tmo 10 model default
+
+;
+; 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:04:00.0 rxq 1 txq 8 mempool0
+ethdev 0002:05:00.0 rxq 1 txq 8 mempool0
+ethdev 0002:06:00.0 rxq 1 txq 8 mempool0
+ethdev 0002:07:00.0 rxq 1 txq 8 mempool0
+ethdev 0002:04:00.0 mtu 1700
+ethdev 0002:05:00.0 promiscuous on
+
+;
+; IPv4 addresses assigned to DPDK devices
+;
+ethdev 0002:04:00.0 ip4 addr add 10.0.2.1 netmask 255.255.255.0
+ethdev 0002:05:00.0 ip4 addr add 20.0.2.1 netmask 255.255.255.0
+ethdev 0002:06:00.0 ip4 addr add 30.0.2.1 netmask 255.255.255.0
+ethdev 0002:07:00.0 ip4 addr add 40.0.2.1 netmask 255.255.255.0
+
+;
+; IPv6 addresses assigned to DPDK devices
+;
+ethdev 0002:04:00.0 ip6 addr add 52:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4A netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00
+ethdev 0002:05:00.0 ip6 addr add 62:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4B netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00
+ethdev 0002:06:00.0 ip6 addr add 72:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4C netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00
+ethdev 0002:07:00.0 ip6 addr add 82:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4D netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00
+
+;
+; IPv4 routes which are installed to ipv4_lookup node for LPM processing
+;
+ipv4_lookup route add ipv4 10.0.2.0 netmask 255.255.255.0 via 10.0.2.1
+ipv4_lookup route add ipv4 20.0.2.0 netmask 255.255.255.0 via 20.0.2.1
+ipv4_lookup route add ipv4 30.0.2.0 netmask 255.255.255.0 via 30.0.2.1
+ipv4_lookup route add ipv4 40.0.2.0 netmask 255.255.255.0 via 40.0.2.1
+
+;
+; IPv6 routes which are installed to ipv6_lookup node for LPM processing
+;
+ipv6_lookup route add ipv6 52:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4A netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 via 52:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4A
+ipv6_lookup route add ipv6 62:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4B netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 via 62:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4B
+ipv6_lookup route add ipv6 72:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4C netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 via 72:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4C
+ipv6_lookup route add ipv6 82:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4D netmask FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00 via 82:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4D
+
+;
+; Peer MAC and IPv4 address mapping
+;
+neigh add ipv4 10.0.2.2 52:20:DA:4F:68:70
+neigh add ipv4 20.0.2.2 62:20:DA:4F:68:70
+neigh add ipv4 30.0.2.2 72:20:DA:4F:68:70
+neigh add ipv4 40.0.2.2 82:20:DA:4F:68:70
+
+;
+; Peer MAC and IPv6 address mapping
+;
+neigh add ipv6 52:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4A 52:20:DA:4F:68:70
+neigh add ipv6 62:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4B 62:20:DA:4F:68:70
+neigh add ipv6 72:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4C 72:20:DA:4F:68:70
+neigh add ipv6 82:20:DA:4F:68:70:52:20:DA:4F:68:70:52:20:DA:4D 82:20:DA:4F:68:70
+
+;
+; Port-Queue-Core mapping for ethdev_rx node
+;
+ethdev_rx map port 0002:04:00.0 queue 0 core 1
+ethdev_rx map port 0002:05:00.0 queue 0 core 2
+ethdev_rx map port 0002:06:00.0 queue 0 core 3
+ethdev_rx map port 0002:07:00.0 queue 0 core 4
+
+;
+; 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 d44c5f0464..659ed654bd 100644
--- a/app/graph/graph.c
+++ b/app/graph/graph.c
@@ -257,7 +257,7 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c
 	for (i = 0; i < MAX_GRAPH_USECASES; i++) {
 		if (!strcmp(graph_config.usecases[i].name, "l3fwd")) {
 			if (graph_config.usecases[i].enabled) {
-				RTE_SET_USED(conf);
+				usecase_l3fwd_configure(conf, nb_conf, nb_graphs);
 				break;
 			}
 		}
diff --git a/app/graph/l3fwd.c b/app/graph/l3fwd.c
new file mode 100644
index 0000000000..5ab57dfa00
--- /dev/null
+++ b/app/graph/l3fwd.c
@@ -0,0 +1,138 @@
+/* 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 char pcap_filename[RTE_GRAPH_PCAP_FILE_SZ];
+static uint64_t packet_to_capture;
+static int pcap_trace_enable;
+
+static int
+l3fwd_pattern_configure(void)
+{
+	/* Graph initialization. 8< */
+	static const char * const default_patterns[] = {
+		"ip4*",
+		"ethdev_tx-*",
+		"pkt_drop",
+	};
+
+	struct rte_graph_param graph_conf;
+	const char **node_patterns;
+	struct lcore_conf *qconf;
+	uint16_t nb_patterns;
+	uint8_t lcore_id;
+	int rc;
+
+	nb_patterns = RTE_DIM(default_patterns);
+	node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) *
+			sizeof(*node_patterns));
+	if (!node_patterns)
+		return -ENOMEM;
+	memcpy(node_patterns, default_patterns,
+			nb_patterns * sizeof(*node_patterns));
+
+	memset(&graph_conf, 0, sizeof(graph_conf));
+	graph_conf.node_patterns = node_patterns;
+
+	/* Pcap config */
+	graph_conf.pcap_enable = pcap_trace_enable;
+	graph_conf.num_pkt_to_capture = packet_to_capture;
+	graph_conf.pcap_filename = pcap_filename;
+
+	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);
+	}
+
+	rc = route_ip4_add_to_lookup();
+	if (rc < 0)
+		rte_exit(EXIT_FAILURE, "Unable to add v4 route to lookup table\n");
+
+	rc = route_ip6_add_to_lookup();
+	if (rc < 0)
+		rte_exit(EXIT_FAILURE, "Unable to add v6 route to lookup table\n");
+
+	rc = neigh_ip4_add_to_rewrite();
+	if (rc < 0)
+		rte_exit(EXIT_FAILURE, "Unable to add v4 to rewrite node\n");
+
+	rc = neigh_ip6_add_to_rewrite();
+	if (rc < 0)
+		rte_exit(EXIT_FAILURE, "Unable to add v6 to rewrite node\n");
+
+	/* 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 rc;
+}
+
+int
+usecase_l3fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs)
+{
+	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);
+
+	rc = l3fwd_pattern_configure();
+	if (rc)
+		rte_exit(EXIT_FAILURE, "l3fwd_pattern_failure: err=%d\n", rc);
+
+	return rc;
+}
diff --git a/app/graph/l3fwd.h b/app/graph/l3fwd.h
new file mode 100644
index 0000000000..e1d23165e6
--- /dev/null
+++ b/app/graph/l3fwd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Marvell.
+ */
+
+#ifndef APP_GRAPH_L3FWD_H
+#define APP_GRAPH_L3FWD_H
+
+int usecase_l3fwd_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 6292fc9684..d8434fc90f 100644
--- a/app/graph/meson.build
+++ b/app/graph/meson.build
@@ -16,6 +16,7 @@ sources = files(
         'graph.c',
         'ip4_route.c',
         'ip6_route.c',
+        'l3fwd.c',
         'main.c',
         'mempool.c',
         'neigh.c',
diff --git a/app/graph/module_api.h b/app/graph/module_api.h
index 9bb4b39edd..73f013143f 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 "l3fwd.h"
 #include "mempool.h"
 #include "neigh.h"
 #include "route.h"
