diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index fd2ff64d7..1784674df 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -161,6 +161,8 @@ The public API headers are grouped by topics:
     [table_action]     (@ref rte_table_action.h)
   * [graph]            (@ref rte_graph.h):
     [graph_worker]     (@ref rte_graph_worker.h)
+  * graph_nodes:
+    [eth_node]         (@ref rte_node_eth_api.h),
 
 - **basic**:
   [approx fraction]    (@ref rte_approx.h),
diff --git a/lib/librte_node/Makefile b/lib/librte_node/Makefile
index 7428f6c43..ea5fa77f7 100644
--- a/lib/librte_node/Makefile
+++ b/lib/librte_node/Makefile
@@ -11,7 +11,7 @@ CFLAGS += -O3 -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS)
 # Strict-aliasing rules are violated by uint8_t[] to context size casts.
 CFLAGS += -fno-strict-aliasing
-LDLIBS += -lrte_eal -lrte_graph -lrte_mbuf -lrte_ethdev
+LDLIBS += -lrte_eal -lrte_graph -lrte_mbuf -lrte_ethdev -lrte_mempool
 
 EXPORT_MAP := rte_node_version.map
 
@@ -20,5 +20,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_NODE) += null.c
 SRCS-$(CONFIG_RTE_LIBRTE_NODE) += log.c
 SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_rx.c
 SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_ctrl.c
+
+# install header files
+SYMLINK-$(CONFIG_RTE_LIBRTE_NODE)-include += rte_node_eth_api.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_node/ethdev_ctrl.c b/lib/librte_node/ethdev_ctrl.c
new file mode 100644
index 000000000..599d20b0b
--- /dev/null
+++ b/lib/librte_node/ethdev_ctrl.c
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2020 Marvell International Ltd.
+ */
+
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_graph.h>
+
+#include "rte_node_eth_api.h"
+
+#include "ethdev_rx_priv.h"
+#include "ethdev_tx_priv.h"
+#include "node_private.h"
+
+static struct ethdev_ctrl {
+	uint16_t nb_graphs;
+} ctrl;
+
+int
+rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
+		    uint16_t nb_graphs)
+{
+	struct ethdev_tx_node_main *tx_node_data;
+	uint16_t tx_q_used, rx_q_used, port_id;
+	struct rte_node_register *tx_node;
+	char name[RTE_NODE_NAMESIZE];
+	struct rte_mempool *mp;
+	uint32_t id;
+	int i, j;
+
+	tx_node_data = ethdev_tx_node_data_get();
+	tx_node = ethdev_tx_node_get();
+	for (i = 0; i < nb_confs; i++) {
+		port_id = conf[i].port_id;
+
+		if (!rte_eth_dev_is_valid_port(port_id))
+			return -EINVAL;
+
+		/* Check for mbuf minimum private size requirement */
+		for (j = 0; j < conf[i].mp_count; j++) {
+			mp = conf[i].mp[j];
+			if (!mp)
+				continue;
+			/* Check for minimum private space */
+			if (rte_pktmbuf_priv_size(mp) < NODE_MBUF_PRIV2_SIZE) {
+				node_err("ethdev",
+					 "Minimum mbuf priv size requirement not met by mp %s",
+					 mp->name);
+				return -EINVAL;
+			}
+		}
+
+		rx_q_used = conf[i].num_rx_queues;
+		tx_q_used = conf[i].num_tx_queues;
+		/* Check if we have a txq for each worker */
+		if (tx_q_used < nb_graphs)
+			return -EINVAL;
+
+		/* Create node for each rx port queue pair */
+		for (j = 0; j < rx_q_used; j++) {
+			struct ethdev_rx_node_main *rx_node_data;
+			struct rte_node_register *rx_node;
+			ethdev_rx_node_elem_t *elem;
+
+			rx_node_data = ethdev_rx_get_node_data_get();
+			rx_node = ethdev_rx_node_get();
+			snprintf(name, sizeof(name), "%u-%u", port_id, j);
+			/* Clone a new rx node with same edges as parent */
+			id = rte_node_clone(rx_node->id, name);
+			if (id == RTE_NODE_ID_INVALID)
+				return -EIO;
+
+			/* Add it to list of ethdev rx nodes for lookup */
+			elem = malloc(sizeof(ethdev_rx_node_elem_t));
+			memset(elem, 0, sizeof(ethdev_rx_node_elem_t));
+			elem->ctx.port_id = port_id;
+			elem->ctx.queue_id = j;
+			elem->nid = id;
+			elem->next = rx_node_data->head;
+			rx_node_data->head = elem;
+
+			node_dbg("ethdev", "Rx node %s-%s: is at %u",
+				 rx_node->name, name, id);
+		}
+
+		/* Create a per port tx node from base node */
+		snprintf(name, sizeof(name), "%u", port_id);
+		/* Clone a new node with same edges as parent */
+		id = rte_node_clone(tx_node->id, name);
+		tx_node_data->nodes[port_id] = id;
+
+		node_dbg("ethdev", "Tx node %s-%s: is at %u", tx_node->name,
+			 name, id);
+	}
+
+	ctrl.nb_graphs = nb_graphs;
+	return 0;
+}
diff --git a/lib/librte_node/meson.build b/lib/librte_node/meson.build
index 505c76abd..af2eb2d91 100644
--- a/lib/librte_node/meson.build
+++ b/lib/librte_node/meson.build
@@ -1,8 +1,9 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(C) 2020 Marvell International Ltd.
 
-sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c')
+sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c', 'ethdev_ctrl.c')
+headers = files('rte_node_eth_api.h')
 allow_experimental_apis = true
 # Strict-aliasing rules are violated by uint8_t[] to context size casts.
 cflags += '-fno-strict-aliasing'
-deps += ['graph', 'mbuf', 'ethdev']
+deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev']
diff --git a/lib/librte_node/node_private.h b/lib/librte_node/node_private.h
index f30902a94..975b9aa45 100644
--- a/lib/librte_node/node_private.h
+++ b/lib/librte_node/node_private.h
@@ -7,6 +7,7 @@
 
 #include <rte_common.h>
 #include <rte_log.h>
+#include <rte_mbuf.h>
 
 extern int rte_node_logtype;
 #define NODE_LOG(level, node_name, ...)                                        \
@@ -19,4 +20,60 @@ extern int rte_node_logtype;
 #define node_info(node_name, ...) NODE_LOG(INFO, node_name, __VA_ARGS__)
 #define node_dbg(node_name, ...) NODE_LOG(DEBUG, node_name, __VA_ARGS__)
 
+/**
+ *
+ * Node mbuf private data to store next hop, ttl and checksum.
+ */
+struct node_mbuf_priv1 {
+	union {
+		/* IP4 rewrite */
+		struct {
+			uint16_t nh;
+			uint16_t ttl;
+			uint32_t cksum;
+		};
+
+		uint64_t u;
+	};
+};
+
+/**
+ * Node mbuf private area 2.
+ */
+struct node_mbuf_priv2 {
+	uint64_t priv_data;
+} __rte_cache_aligned;
+
+#define NODE_MBUF_PRIV2_SIZE sizeof(struct node_mbuf_priv2)
+
+/**
+ * Get mbuf_priv1 pointer from rte_mbuf.
+ *
+ * @param
+ *   Pointer to the rte_mbuf.
+ *
+ * @return
+ *   Pointer to the mbuf_priv1.
+ */
+static __rte_always_inline struct node_mbuf_priv1 *
+node_mbuf_priv1(struct rte_mbuf *m)
+{
+	return (struct node_mbuf_priv1 *)&m->udata64;
+}
+
+/**
+ * Get mbuf_priv2 pointer from rte_mbuf.
+ *
+ * @param
+ *   Pointer to the rte_mbuf.
+ *
+ * @return
+ *   Pointer to the mbuf_priv2.
+ */
+static __rte_always_inline struct node_mbuf_priv2 *
+node_mbuf_priv2(struct rte_mbuf *m)
+{
+	return (struct node_mbuf_priv2 *)rte_mbuf_to_priv(m);
+}
+
 #endif /* __NODE_PRIVATE_H__ */
diff --git a/lib/librte_node/rte_node_eth_api.h b/lib/librte_node/rte_node_eth_api.h
new file mode 100644
index 000000000..e9a53afe5
--- /dev/null
+++ b/lib/librte_node/rte_node_eth_api.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2020 Marvell International Ltd.
+ */
+
+#ifndef __INCLUDE_RTE_NODE_ETH_API_H__
+#define __INCLUDE_RTE_NODE_ETH_API_H__
+
+/**
+ * @file rte_node_eth_api.h
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * This API allows to setup ethdev_rx and ethdev_tx nodes
+ * and its queue associations.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+#include <rte_mempool.h>
+
+/**
+ * Port config for ethdev_rx and ethdev_tx node.
+ */
+struct rte_node_ethdev_config {
+	uint16_t port_id;
+	/**< Port identifier */
+	uint16_t num_rx_queues;
+	/**< Number of Rx queues. */
+	uint16_t num_tx_queues;
+	/**< Number of Tx queues. */
+	struct rte_mempool **mp;
+	/**< Array of mempools associated to Rx queue. */
+	uint16_t mp_count;
+	/**< Size of mp array. */
+};
+
+/**
+ * Initializes ethdev nodes.
+ *
+ * @param cfg
+ *   Array of ethdev config that identifies which port's
+ *   ethdev_rx and ethdev_tx nodes need to be created
+ *   and queue association.
+ * @param cnt
+ *   Size of cfg array.
+ * @param nb_graphs
+ *   Number of graphs that will be used.
+ *
+ * @return
+ *   0 on successful initialization, negative otherwise.
+ */
+__rte_experimental
+int rte_node_eth_config(struct rte_node_ethdev_config *cfg,
+			uint16_t cnt, uint16_t nb_graphs);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_NODE_ETH_API_H__ */
diff --git a/lib/librte_node/rte_node_version.map b/lib/librte_node/rte_node_version.map
index f87163bb9..c6c71bd02 100644
--- a/lib/librte_node/rte_node_version.map
+++ b/lib/librte_node/rte_node_version.map
@@ -1,6 +1,7 @@
 EXPERIMENTAL {
 	global:
 
+	rte_node_eth_config;
 	rte_node_logtype;
 	local: *;
 };
