DPDK patches and discussions
 help / color / mirror / Atom feed
From: Nitin Saxena <nsaxena@marvell.com>
To: Jerin Jacob <jerinj@marvell.com>,
	Kiran Kumar K <kirankumark@marvell.com>,
	 Nithin Dabilpuram <ndabilpuram@marvell.com>,
	Zhirun Yan <yanzhirun_163@163.com>,
	Robin Jarry <rjarry@redhat.com>,
	Christophe Fontaine <cfontain@redhat.com>
Cc: <dev@dpdk.org>, Nitin Saxena <nsaxena16@gmail.com>
Subject: [PATCH v6 3/4] ip4: add ip4 output feature arc
Date: Fri, 3 Jan 2025 11:36:06 +0530	[thread overview]
Message-ID: <20250103060612.2671836-4-nsaxena@marvell.com> (raw)
In-Reply-To: <20250103060612.2671836-1-nsaxena@marvell.com>

Added ip4 output arc to allow applications to hook feature nodes in ip4
egress direction

Signed-off-by: Nitin Saxena <nsaxena@marvell.com>
---
 lib/node/ethdev_ctrl.c               |   8 +
 lib/node/interface_tx_feature.c      | 133 ++++++++++++
 lib/node/interface_tx_feature_priv.h |  33 +++
 lib/node/ip4_rewrite.c               | 298 ++++++++++++++++++++++++++-
 lib/node/meson.build                 |   1 +
 lib/node/node_private.h              |   1 +
 lib/node/rte_node_ip4_api.h          |   4 +
 7 files changed, 474 insertions(+), 4 deletions(-)
 create mode 100644 lib/node/interface_tx_feature.c
 create mode 100644 lib/node/interface_tx_feature_priv.h

diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index cd52e8be08..93ef7fbb95 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -14,6 +14,7 @@
 #include "ethdev_tx_priv.h"
 #include "ip4_rewrite_priv.h"
 #include "ip6_rewrite_priv.h"
+#include "interface_tx_feature_priv.h"
 #include "node_private.h"
 
 static struct ethdev_ctrl {
@@ -24,6 +25,7 @@ int
 rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 		    uint16_t nb_graphs)
 {
+	struct rte_node_register *if_tx_feature_node;
 	struct rte_node_register *ip4_rewrite_node;
 	struct rte_node_register *ip6_rewrite_node;
 	struct ethdev_tx_node_main *tx_node_data;
@@ -35,6 +37,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 	int i, j, rc;
 	uint32_t id;
 
+	if_tx_feature_node = if_tx_feature_node_get();
 	ip4_rewrite_node = ip4_rewrite_node_get();
 	ip6_rewrite_node = ip6_rewrite_node_get();
 	tx_node_data = ethdev_tx_node_data_get();
@@ -125,6 +128,11 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
 		if (rc < 0)
 			return rc;
 
+		/* Add this tx port node to if_tx_feature_node */
+		rte_node_edge_update(if_tx_feature_node->id, RTE_EDGE_ID_INVALID,
+				     &next_nodes, 1);
+		rc = if_tx_feature_node_set_next(port_id,
+						 rte_node_edge_count(if_tx_feature_node->id) - 1);
 	}
 
 	ctrl.nb_graphs = nb_graphs;
diff --git a/lib/node/interface_tx_feature.c b/lib/node/interface_tx_feature.c
new file mode 100644
index 0000000000..35ac00f21e
--- /dev/null
+++ b/lib/node/interface_tx_feature.c
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2025 Marvell International Ltd.
+ */
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_graph_feature_arc_worker.h>
+#include <rte_malloc.h>
+
+#include "rte_node_ip4_api.h"
+#include "node_private.h"
+#include "interface_tx_feature_priv.h"
+
+#define IF_TX_FEATURE_LAST_NEXT_INDEX(ctx) \
+	(((struct if_tx_feature_node_ctx *)ctx)->last_index)
+/*
+ * @internal array for mapping port to next node index
+ */
+struct if_tx_feature_node_main  {
+	uint16_t next_index[RTE_MAX_ETHPORTS];
+};
+
+struct if_tx_feature_node_ctx {
+	uint16_t last_index;
+};
+
+static struct if_tx_feature_node_main *if_tx_feature_nm;
+
+int
+if_tx_feature_node_set_next(uint16_t port_id, uint16_t next_index)
+{
+	if (if_tx_feature_nm == NULL) {
+		if_tx_feature_nm = rte_zmalloc(
+			"if_tx_feature_nm", sizeof(struct if_tx_feature_node_main),
+			RTE_CACHE_LINE_SIZE);
+		if (if_tx_feature_nm == NULL)
+			return -ENOMEM;
+	}
+	if_tx_feature_nm->next_index[port_id] = next_index;
+
+	return 0;
+}
+
+static int
+if_tx_feature_node_init(const struct rte_graph *graph, struct rte_node *node)
+{
+	RTE_SET_USED(graph);
+
+	/* pkt_drop */
+	IF_TX_FEATURE_LAST_NEXT_INDEX(node->ctx) = 0;
+
+	return 0;
+}
+
+static uint16_t
+if_tx_feature_node_process(struct rte_graph *graph, struct rte_node *node,
+			   void **objs, uint16_t nb_objs)
+{
+	uint16_t held = 0, next;
+	void **to_next, **from;
+	uint16_t last_spec = 0;
+	rte_edge_t next_index;
+	struct rte_mbuf *mbuf;
+	int i;
+
+	/* Speculative next */
+	next_index = IF_TX_FEATURE_LAST_NEXT_INDEX(node->ctx);
+
+	from = objs;
+	to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
+	for (i = 0; i < nb_objs; i++) {
+
+		mbuf = (struct rte_mbuf *)objs[i];
+
+		/* port-tx node starts from next edge 1*/
+		next = if_tx_feature_nm->next_index[mbuf->port];
+
+		if (unlikely(next_index != next)) {
+			/* Copy things successfully speculated till now */
+			rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+			from += last_spec;
+			to_next += last_spec;
+			held += last_spec;
+			last_spec = 0;
+
+			rte_node_enqueue_x1(graph, node, next, from[0]);
+			from += 1;
+		} else {
+			last_spec += 1;
+		}
+	}
+	/* !!! Home run !!! */
+	if (likely(last_spec == nb_objs)) {
+		rte_node_next_stream_move(graph, node, next_index);
+		return nb_objs;
+	}
+	held += last_spec;
+	rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+	rte_node_next_stream_put(graph, node, next_index, held);
+
+	IF_TX_FEATURE_LAST_NEXT_INDEX(node->ctx) = next;
+
+	return nb_objs;
+}
+
+static struct rte_node_register if_tx_feature_node = {
+	.process = if_tx_feature_node_process,
+	.init = if_tx_feature_node_init,
+	.name = "interface_tx",
+	.nb_edges = 1,
+	.next_nodes = {
+		[0] = "pkt_drop",
+	},
+};
+
+struct rte_node_register *
+if_tx_feature_node_get(void)
+{
+	return &if_tx_feature_node;
+}
+
+RTE_NODE_REGISTER(if_tx_feature_node);
+
+/* if_tx feature node */
+struct rte_graph_feature_register if_tx_feature = {
+	.feature_name = RTE_IP4_OUTPUT_END_FEATURE_NAME,
+	.arc_name = RTE_IP4_OUTPUT_FEATURE_ARC_NAME,
+	.feature_process_fn = if_tx_feature_node_process,
+	.feature_node = &if_tx_feature_node,
+};
diff --git a/lib/node/interface_tx_feature_priv.h b/lib/node/interface_tx_feature_priv.h
new file mode 100644
index 0000000000..846191572d
--- /dev/null
+++ b/lib/node/interface_tx_feature_priv.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2025 Marvell International Ltd.
+ */
+#ifndef __INCLUDE_IF_TX_FEATURE_PRIV_H__
+#define __INCLUDE_IF_TX_FEATURE_PRIV_H__
+
+#include <rte_common.h>
+
+extern struct rte_graph_feature_register if_tx_feature;
+
+/**
+ * @internal
+ *
+ * Get the ipv4 rewrite node.
+ *
+ * @return
+ *   Pointer to the ipv4 rewrite node.
+ */
+struct rte_node_register *if_tx_feature_node_get(void);
+
+/**
+ * @internal
+ *
+ * Set the Edge index of a given port_id.
+ *
+ * @param port_id
+ *   Ethernet port identifier.
+ * @param next_index
+ *   Edge index of the Given Tx node.
+ */
+int if_tx_feature_node_set_next(uint16_t port_id, uint16_t next_index);
+
+#endif /* __INCLUDE_INTERFCE_TX_FEATURE_PRIV_H */
diff --git a/lib/node/ip4_rewrite.c b/lib/node/ip4_rewrite.c
index 34a920df5e..ab64aa0a3c 100644
--- a/lib/node/ip4_rewrite.c
+++ b/lib/node/ip4_rewrite.c
@@ -6,6 +6,7 @@
 #include <rte_ether.h>
 #include <rte_graph.h>
 #include <rte_graph_worker.h>
+#include <rte_graph_feature_arc_worker.h>
 #include <rte_ip.h>
 #include <rte_malloc.h>
 #include <rte_vect.h>
@@ -14,15 +15,27 @@
 
 #include "ip4_rewrite_priv.h"
 #include "node_private.h"
+#include "interface_tx_feature_priv.h"
+
+#ifndef RTE_IP4_OUTPUT_ARC_INDEXES
+#define RTE_IP4_OUTPUT_ARC_INDEXES RTE_MAX_ETHPORTS
+#endif
 
 struct ip4_rewrite_node_ctx {
 	/* Dynamic offset to mbuf priv1 */
 	int mbuf_priv1_off;
+	/* Dynamic offset to feature arc field */
+	int arc_dyn_off;
 	/* Cached next index */
 	uint16_t next_index;
+	/* tx interface of last mbuf */
+	uint16_t last_tx_if;
+	/* Cached feature arc handle */
+	rte_graph_feature_arc_t output_feature_arc;
 };
 
 static struct ip4_rewrite_node_main *ip4_rewrite_nm;
+static int port_to_next_index_diff;
 
 #define IP4_REWRITE_NODE_LAST_NEXT(ctx) \
 	(((struct ip4_rewrite_node_ctx *)ctx)->next_index)
@@ -30,16 +43,175 @@ static struct ip4_rewrite_node_main *ip4_rewrite_nm;
 #define IP4_REWRITE_NODE_PRIV1_OFF(ctx) \
 	(((struct ip4_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
 
-static uint16_t
-ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
-			 void **objs, uint16_t nb_objs)
+#define IP4_REWRITE_NODE_FEAT_OFF(ctx) \
+	(((struct ip4_rewrite_node_ctx *)ctx)->arc_dyn_off)
+
+#define IP4_REWRITE_NODE_OUTPUT_FEATURE_ARC(ctx) \
+	(((struct ip4_rewrite_node_ctx *)ctx)->output_feature_arc)
+
+#define IP4_REWRITE_NODE_LAST_TX_IF(ctx) \
+	(((struct ip4_rewrite_node_ctx *)ctx)->last_tx_if)
+
+static __rte_always_inline void
+check_output_feature_arc_x1(struct rte_graph_feature_arc *arc, uint16_t *tx_if,
+			    struct rte_mbuf *mbuf0, uint16_t *next0,
+			    uint16_t *last_next_index,
+			    rte_graph_feature_data_t *feature_data, const int dyn)
+{
+	struct rte_graph_feature_arc_mbuf_dynfields *d0 = NULL;
+	uint16_t port0;
+
+	/* make sure packets are not being sent to pkt_drop node */
+	if (unlikely(!(*next0)))
+		return;
+
+	port0 = (*next0) - port_to_next_index_diff;
+
+	/* get pointer to feature arc mbuf */
+	d0 = rte_graph_feature_arc_mbuf_dynfields_get(mbuf0, dyn);
+
+	/* Check if last packet's tx port not same as current */
+	if (unlikely(*tx_if != port0)) {
+		if (unlikely(rte_graph_feature_data_first_feature_get(arc, port0,
+								      &d0->feature_data))) {
+			*next0 = rte_graph_feature_data_edge_get(arc, d0->feature_data);
+			mbuf0->port = port0;
+		}
+
+		*last_next_index = *next0;
+		*tx_if = port0;
+		*feature_data = d0->feature_data;
+	} else {
+		if (unlikely(rte_graph_feature_data_is_valid(*feature_data))) {
+			*next0 = *last_next_index;
+			mbuf0->port = *tx_if;
+			d0->feature_data = *feature_data;
+		}
+	}
+}
+
+static __rte_always_inline void
+check_output_feature_arc_x4(struct rte_graph_feature_arc *arc, uint16_t *tx_if,
+			    struct rte_mbuf *mbuf0, struct rte_mbuf *mbuf1,
+			    struct rte_mbuf *mbuf2, struct rte_mbuf *mbuf3,
+			    uint16_t *next0, uint16_t *next1, uint16_t *next2,
+			    uint16_t *next3, uint16_t *last_next_index,
+			    rte_graph_feature_data_t *feature_data, const int dyn)
+{
+	struct rte_graph_feature_arc_mbuf_dynfields *d0 = NULL, *d1 = NULL, *d2 = NULL, *d3 = NULL;
+	uint16_t port0, port1, port2, port3;
+	uint16_t xor = 0;
+
+	/* If no ip4_rewrite_set_next() is called yet */
+	if (unlikely(!port_to_next_index_diff))
+		return;
+
+	/* get pointer to feature arc dyn field */
+	d0 = rte_graph_feature_arc_mbuf_dynfields_get(mbuf0, dyn);
+	d1 = rte_graph_feature_arc_mbuf_dynfields_get(mbuf1, dyn);
+	d2 = rte_graph_feature_arc_mbuf_dynfields_get(mbuf2, dyn);
+	d3 = rte_graph_feature_arc_mbuf_dynfields_get(mbuf3, dyn);
+
+	/*
+	 * Check if all four packets are going to same next_index/port
+	 */
+	xor = ((*tx_if) + port_to_next_index_diff) ^ (*next0);
+	xor += (*next0) ^ (*next1);
+	xor += (*next1) ^ (*next2);
+	xor += (*next2) ^ (*next3);
+
+	if (xor) {
+		/* packets tx ports are not same, check first feature for each mbuf
+		 * make sure next0 != 0 which is pkt_drop
+		 */
+		port0 = (*next0) - port_to_next_index_diff;
+		port1 = (*next1) - port_to_next_index_diff;
+		port2 = (*next2) - port_to_next_index_diff;
+		port3 = (*next3) - port_to_next_index_diff;
+		if (unlikely((*next0 >= port_to_next_index_diff) &&
+			     rte_graph_feature_data_first_feature_get(arc, port0,
+								      &d0->feature_data))) {
+			/* update next0 from feature arc */
+			*next0 = rte_graph_feature_data_edge_get(arc, d0->feature_data);
+			mbuf0->port = port0;
+
+			*tx_if = port0;
+			*last_next_index = *next0;
+			*feature_data = d0->feature_data;
+		}
+
+		if (unlikely((*next1 >= port_to_next_index_diff) &&
+			     rte_graph_feature_data_first_feature_get(arc, port1,
+								      &d1->feature_data))) {
+			port1 = (*next1) - port_to_next_index_diff;
+			*next1 = rte_graph_feature_data_edge_get(arc, d1->feature_data);
+			mbuf1->port = port1;
+			*tx_if = port1;
+			*last_next_index = *next1;
+			*feature_data = d1->feature_data;
+		}
+
+		if (unlikely((*next2 >= port_to_next_index_diff) &&
+			     rte_graph_feature_data_first_feature_get(arc, port2,
+								      &d2->feature_data))) {
+			port2 = (*next2) - port_to_next_index_diff;
+			*next2 = rte_graph_feature_data_edge_get(arc, d2->feature_data);
+			mbuf2->port = port2;
+			*tx_if = port2;
+			*last_next_index = *next2;
+			*feature_data = d2->feature_data;
+		}
+
+		if (unlikely((*next3 >= port_to_next_index_diff) &&
+			     rte_graph_feature_data_first_feature_get(arc, port3,
+								      &d3->feature_data))) {
+			port3 = (*next3) - port_to_next_index_diff;
+			*next3 = rte_graph_feature_data_edge_get(arc, d3->feature_data);
+			mbuf3->port = port3;
+			*tx_if = port3;
+			*last_next_index = *next3;
+			*feature_data = d3->feature_data;
+		}
+	} else {
+		/* All packets are same as last tx port. Check if feature enabled
+		 * on last packet is valid or not. If invalid no need to
+		 * change any next[0-3]
+		 * Also check packet is not being sent to pkt_drop node
+		 */
+		if (unlikely(rte_graph_feature_data_is_valid(*feature_data) &&
+			     (*next0 != 0))) {
+			*next0 = *last_next_index;
+			*next1 = *last_next_index;
+			*next2 = *last_next_index;
+			*next3 = *last_next_index;
+
+			d0->feature_data = *feature_data;
+			d1->feature_data = *feature_data;
+			d2->feature_data = *feature_data;
+			d3->feature_data = *feature_data;
+
+			mbuf0->port = *tx_if;
+			mbuf1->port = *tx_if;
+			mbuf2->port = *tx_if;
+			mbuf3->port = *tx_if;
+		}
+	}
+}
+
+static __rte_always_inline uint16_t
+__ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
+			   void **objs, uint16_t nb_objs,
+			   const int dyn, const int check_enabled_features,
+			   const int feat_dyn,
+			   struct rte_graph_feature_arc *out_feature_arc)
 {
 	struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
 	struct ip4_rewrite_nh_header *nh = ip4_rewrite_nm->nh;
-	const int dyn = IP4_REWRITE_NODE_PRIV1_OFF(node->ctx);
 	uint16_t next0, next1, next2, next3, next_index;
 	struct rte_ipv4_hdr *ip0, *ip1, *ip2, *ip3;
 	uint16_t n_left_from, held = 0, last_spec = 0;
+	rte_graph_feature_data_t feature_data;
+	uint16_t last_tx_if, last_next_index;
 	void *d0, *d1, *d2, *d3;
 	void **to_next, **from;
 	rte_xmm_t priv01;
@@ -57,6 +229,27 @@ ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
 	for (i = 0; i < 4 && i < n_left_from; i++)
 		rte_prefetch0(pkts[i]);
 
+	if (check_enabled_features) {
+		rte_graph_feature_arc_prefetch(out_feature_arc);
+
+		last_tx_if = IP4_REWRITE_NODE_LAST_TX_IF(node->ctx);
+
+		/* If feature is enabled on last_tx_if, prefetch data
+		 * corresponding to first feature
+		 */
+		if (unlikely(rte_graph_feature_data_first_feature_get(out_feature_arc,
+								      last_tx_if,
+								      &feature_data)))
+			rte_graph_feature_arc_feature_data_prefetch(out_feature_arc,
+								    feature_data);
+
+		/* Reset last_tx_if and last_next_index to call feature arc APIs
+		 * for initial packets in every node loop
+		 */
+		last_tx_if = UINT16_MAX;
+		last_next_index = UINT16_MAX;
+	}
+
 	/* Get stream for the speculated next node */
 	to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
 	/* Update Ethernet header of pkts */
@@ -78,6 +271,7 @@ ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
 
 		pkts += 4;
 		n_left_from -= 4;
+
 		priv01.u64[0] = node_mbuf_priv1(mbuf0, dyn)->u;
 		priv01.u64[1] = node_mbuf_priv1(mbuf1, dyn)->u;
 		priv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;
@@ -132,6 +326,16 @@ ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
 		ip3->time_to_live = priv23.u16[5] - 1;
 		ip3->hdr_checksum = priv23.u16[6] + priv23.u16[7];
 
+		/* Once all mbufs are updated with next hop data.
+		 * check if any feature is enabled to override
+		 * next edges
+		 */
+		if (check_enabled_features)
+			check_output_feature_arc_x4(out_feature_arc, &last_tx_if,
+						    mbuf0, mbuf1, mbuf2, mbuf3,
+						    &next0, &next1, &next2, &next3,
+						    &last_next_index, &feature_data, feat_dyn);
+
 		/* Enqueue four to next node */
 		rte_edge_t fix_spec =
 			((next_index == next0) && (next0 == next1) &&
@@ -225,6 +429,11 @@ ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
 		ip0->hdr_checksum = chksum;
 		ip0->time_to_live = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
 
+		if (check_enabled_features)
+			check_output_feature_arc_x1(out_feature_arc, &last_tx_if,
+						    mbuf0, &next0, &last_next_index,
+						    &feature_data, feat_dyn);
+
 		if (unlikely(next_index ^ next0)) {
 			/* Copy things successfully speculated till now */
 			rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
@@ -252,12 +461,49 @@ ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
 	/* Save the last next used */
 	IP4_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
 
+	if (check_enabled_features)
+		IP4_REWRITE_NODE_LAST_TX_IF(node->ctx) = last_tx_if;
+
 	return nb_objs;
 }
 
+static uint16_t
+ip4_rewrite_feature_node_process(struct rte_graph *graph, struct rte_node *node,
+				 void **objs, uint16_t nb_objs)
+{
+	struct rte_graph_feature_arc *arc = NULL;
+		rte_graph_feature_arc_get(IP4_REWRITE_NODE_OUTPUT_FEATURE_ARC(node->ctx));
+	const int feat_dyn = IP4_REWRITE_NODE_FEAT_OFF(node->ctx);
+	const int dyn = IP4_REWRITE_NODE_PRIV1_OFF(node->ctx);
+
+	arc = rte_graph_feature_arc_get(IP4_REWRITE_NODE_OUTPUT_FEATURE_ARC(node->ctx));
+	if (unlikely(arc && rte_graph_feature_arc_is_any_feature_enabled(arc)))
+		return __ip4_rewrite_node_process(graph, node, objs, nb_objs, dyn,
+						  1 /* check features */, feat_dyn, arc);
+
+	return __ip4_rewrite_node_process(graph, node, objs, nb_objs, dyn,
+					  0/* don't check features*/,
+					  0 /* don't care */,
+					  NULL /* don't care*/);
+}
+
+static uint16_t
+ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
+			 void **objs, uint16_t nb_objs)
+{
+	const int dyn = IP4_REWRITE_NODE_PRIV1_OFF(node->ctx);
+
+	return __ip4_rewrite_node_process(graph, node, objs, nb_objs, dyn,
+					  0/* don't check features*/,
+					  0 /* don't care */,
+					  NULL/* don't care */);
+}
+
+
 static int
 ip4_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
 {
+	rte_graph_feature_arc_t feature_arc;
 	static bool init_once;
 
 	RTE_SET_USED(graph);
@@ -268,9 +514,27 @@ ip4_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
 				&node_mbuf_priv1_dynfield_desc);
 		if (node_mbuf_priv1_dynfield_offset < 0)
 			return -rte_errno;
+
+		/* Create ipv4-output feature arc, if not created
+		 */
+		if (rte_graph_feature_arc_lookup_by_name(RTE_IP4_OUTPUT_FEATURE_ARC_NAME,
+						     &feature_arc) < 0) {
+			node_err("ip4_rewrite", "Feature arc \"%s\" not found",
+				 RTE_IP4_OUTPUT_FEATURE_ARC_NAME);
+		} else {
+			node_err("ip4_rewrite", "Feature arc \"%s\" found",
+				 RTE_IP4_OUTPUT_FEATURE_ARC_NAME);
+		}
+
 		init_once = true;
 	}
 	IP4_REWRITE_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset;
+	IP4_REWRITE_NODE_FEAT_OFF(node->ctx) = rte_graph_feature_arc_mbuf_dynfield_offset_get();
+	IP4_REWRITE_NODE_OUTPUT_FEATURE_ARC(node->ctx) = feature_arc;
+
+	/* By default, set cached next node to pkt_drop */
+	IP4_REWRITE_NODE_LAST_NEXT(node->ctx) = 0;
+	IP4_REWRITE_NODE_LAST_TX_IF(node->ctx) = 0;
 
 	node_dbg("ip4_rewrite", "Initialized ip4_rewrite node initialized");
 
@@ -280,6 +544,8 @@ ip4_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
 int
 ip4_rewrite_set_next(uint16_t port_id, uint16_t next_index)
 {
+	static int once;
+
 	if (ip4_rewrite_nm == NULL) {
 		ip4_rewrite_nm = rte_zmalloc(
 			"ip4_rewrite", sizeof(struct ip4_rewrite_node_main),
@@ -287,6 +553,10 @@ ip4_rewrite_set_next(uint16_t port_id, uint16_t next_index)
 		if (ip4_rewrite_nm == NULL)
 			return -ENOMEM;
 	}
+	if (!once) {
+		port_to_next_index_diff = next_index - port_id;
+		once = 1;
+	}
 	ip4_rewrite_nm->next_index[port_id] = next_index;
 
 	return 0;
@@ -345,3 +615,23 @@ ip4_rewrite_node_get(void)
 }
 
 RTE_NODE_REGISTER(ip4_rewrite_node);
+
+/* IP4 output arc */
+static struct rte_graph_feature_arc_register ip4_output_arc = {
+	.arc_name = RTE_IP4_OUTPUT_FEATURE_ARC_NAME,
+
+	/* This arc works on all ethdevs */
+	.max_indexes = RTE_IP4_OUTPUT_ARC_INDEXES,
+
+	.start_node = &ip4_rewrite_node,
+
+	/* overwrites start_node->process() function with following only if
+	 * application calls rte_graph_feature_arc_init()
+	 */
+	.start_node_feature_process_fn = ip4_rewrite_feature_node_process,
+
+	/* end feature node of an arc*/
+	.end_feature = &if_tx_feature,
+};
+
+RTE_GRAPH_FEATURE_ARC_REGISTER(ip4_output_arc);
diff --git a/lib/node/meson.build b/lib/node/meson.build
index 0bed97a96c..11e03d9ef6 100644
--- a/lib/node/meson.build
+++ b/lib/node/meson.build
@@ -24,6 +24,7 @@ sources = files(
         'pkt_cls.c',
         'pkt_drop.c',
         'udp4_input.c',
+        'interface_tx_feature.c'
 )
 headers = files(
         'rte_node_eth_api.h',
diff --git a/lib/node/node_private.h b/lib/node/node_private.h
index 4fafab19be..9488df225c 100644
--- a/lib/node/node_private.h
+++ b/lib/node/node_private.h
@@ -13,6 +13,7 @@
 #include <rte_mbuf_dyn.h>
 
 #include <rte_graph_worker_common.h>
+#include <rte_graph_feature_arc_worker.h>
 
 extern int rte_node_logtype;
 #define RTE_LOGTYPE_NODE rte_node_logtype
diff --git a/lib/node/rte_node_ip4_api.h b/lib/node/rte_node_ip4_api.h
index 950751a525..8cfae14b46 100644
--- a/lib/node/rte_node_ip4_api.h
+++ b/lib/node/rte_node_ip4_api.h
@@ -24,6 +24,10 @@
 extern "C" {
 #endif
 
+/** IP4 output arc */
+#define RTE_IP4_OUTPUT_FEATURE_ARC_NAME "rte_ip4_output_arc"
+#define RTE_IP4_OUTPUT_END_FEATURE_NAME "rte_if_tx_feature"
+
 /**
  * IP4 lookup next nodes.
  */
-- 
2.43.0


  parent reply	other threads:[~2025-01-03  6:06 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-07  7:31 [RFC PATCH 0/3] add feature arc in rte_graph Nitin Saxena
2024-09-07  7:31 ` [RFC PATCH 1/3] graph: add feature arc support Nitin Saxena
2024-09-11  4:41   ` Kiran Kumar Kokkilagadda
2024-10-10  4:42     ` Nitin Saxena
2024-09-07  7:31 ` [RFC PATCH 2/3] graph: add feature arc option in graph create Nitin Saxena
2024-09-07  7:31 ` [RFC PATCH 3/3] graph: add IPv4 output feature arc Nitin Saxena
2024-10-08  8:04 ` [RFC PATCH 0/3] add feature arc in rte_graph David Marchand
2024-10-08 14:26   ` [EXTERNAL] " Nitin Saxena
2024-10-14 11:11   ` Nitin Saxena
2024-10-16  9:24     ` David Marchand
2024-10-16  9:38       ` Robin Jarry
2024-10-16 13:50         ` Nitin Saxena
2024-10-17  7:03           ` Nitin Saxena
2024-10-17  7:50             ` Robin Jarry
2024-10-17  8:32               ` [EXTERNAL] " Christophe Fontaine
2024-10-17 10:56                 ` Nitin Saxena
2024-10-17  8:48               ` [EXTERNAL] " Nitin Saxena
2024-10-08 13:30 ` [RFC PATCH v2 0/5] " Nitin Saxena
2024-10-08 13:30   ` [RFC PATCH v2 1/5] graph: add feature arc support Nitin Saxena
2024-10-08 13:30   ` [RFC PATCH v2 2/5] graph: add feature arc option in graph create Nitin Saxena
2024-10-08 13:30   ` [RFC PATCH v2 3/5] graph: add IPv4 output feature arc Nitin Saxena
2024-10-08 13:30   ` [RFC PATCH v2 4/5] test/graph_feature_arc: add functional tests Nitin Saxena
2024-10-08 13:30   ` [RFC PATCH v2 5/5] docs: add programming guide for feature arc Nitin Saxena
2024-10-09 13:29   ` [PATCH v3 0/5] add feature arc in rte_graph Nitin Saxena
2024-10-09 13:29     ` [PATCH v3 1/5] graph: add feature arc support Nitin Saxena
2024-10-09 13:29     ` [PATCH v3 2/5] graph: add feature arc option in graph create Nitin Saxena
2024-10-09 13:30     ` [PATCH v3 3/5] graph: add IPv4 output feature arc Nitin Saxena
2024-10-09 13:30     ` [PATCH v3 4/5] test/graph_feature_arc: add functional tests Nitin Saxena
2024-10-09 13:30     ` [PATCH v3 5/5] docs: add programming guide for feature arc Nitin Saxena
2024-10-09 14:21     ` [PATCH v3 0/5] add feature arc in rte_graph Christophe Fontaine
2024-10-10  4:13       ` [EXTERNAL] " Nitin Saxena
2024-10-09 17:37     ` Stephen Hemminger
2024-10-10  4:24       ` [EXTERNAL] " Nitin Saxena
2024-10-10 13:31     ` [PATCH v4 " Nitin Saxena
2024-10-10 13:31       ` [PATCH v4 1/5] graph: add feature arc support Nitin Saxena
2024-10-10 13:31       ` [PATCH v4 2/5] graph: add feature arc option in graph create Nitin Saxena
2024-10-10 13:31       ` [PATCH v4 3/5] graph: add IPv4 output feature arc Nitin Saxena
2024-10-10 13:31       ` [PATCH v4 4/5] test/graph_feature_arc: add functional tests Nitin Saxena
2024-10-10 13:31       ` [PATCH v4 5/5] docs: add programming guide for feature arc Nitin Saxena
2024-10-14 14:33       ` [PATCH v5 0/5] add feature arc in rte_graph Nitin Saxena
2024-10-14 14:33         ` [PATCH v5 1/5] graph: add feature arc support Nitin Saxena
2024-10-14 14:33         ` [PATCH v5 2/5] graph: add feature arc option in graph create Nitin Saxena
2024-10-14 14:33         ` [PATCH v5 3/5] graph: add IPv4 output feature arc Nitin Saxena
2024-10-14 14:33         ` [PATCH v5 4/5] test/graph_feature_arc: add functional tests Nitin Saxena
2024-10-14 19:54           ` Stephen Hemminger
2024-10-14 14:33         ` [PATCH v5 5/5] docs: add programming guide for feature arc Nitin Saxena
2025-01-03  6:06         ` [PATCH v6 0/4] add feature arc in rte_graph Nitin Saxena
2025-01-03  6:06           ` [PATCH v6 1/4] graph: add API to override node process function Nitin Saxena
2025-01-03  6:06           ` [PATCH v6 2/4] graph: add feature arc abstraction Nitin Saxena
2025-01-03  6:06           ` Nitin Saxena [this message]
2025-01-03  6:06           ` [PATCH v6 4/4] app/graph: add custom feature nodes for ip4 output arc Nitin Saxena
     [not found]           ` <SJ0PR18MB5111B56B4323FB3DFD147801B6152@SJ0PR18MB5111.namprd18.prod.outlook.com>
2025-01-03 14:59             ` Feature arc slides Nitin Saxena
2025-01-06  0:15               ` Stephen Hemminger
2025-01-07 12:37                 ` Nitin Saxena

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250103060612.2671836-4-nsaxena@marvell.com \
    --to=nsaxena@marvell.com \
    --cc=cfontain@redhat.com \
    --cc=dev@dpdk.org \
    --cc=jerinj@marvell.com \
    --cc=kirankumark@marvell.com \
    --cc=ndabilpuram@marvell.com \
    --cc=nsaxena16@gmail.com \
    --cc=rjarry@redhat.com \
    --cc=yanzhirun_163@163.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).