xref: /dpdk/lib/node/ip4_rewrite.c (revision 30a1de10)
1*99a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2*99a2dd95SBruce Richardson  * Copyright(C) 2020 Marvell International Ltd.
3*99a2dd95SBruce Richardson  */
4*99a2dd95SBruce Richardson 
5*99a2dd95SBruce Richardson #include <rte_ethdev.h>
6*99a2dd95SBruce Richardson #include <rte_ether.h>
7*99a2dd95SBruce Richardson #include <rte_graph.h>
8*99a2dd95SBruce Richardson #include <rte_graph_worker.h>
9*99a2dd95SBruce Richardson #include <rte_ip.h>
10*99a2dd95SBruce Richardson #include <rte_malloc.h>
11*99a2dd95SBruce Richardson #include <rte_vect.h>
12*99a2dd95SBruce Richardson 
13*99a2dd95SBruce Richardson #include "rte_node_ip4_api.h"
14*99a2dd95SBruce Richardson 
15*99a2dd95SBruce Richardson #include "ip4_rewrite_priv.h"
16*99a2dd95SBruce Richardson #include "node_private.h"
17*99a2dd95SBruce Richardson 
18*99a2dd95SBruce Richardson struct ip4_rewrite_node_ctx {
19*99a2dd95SBruce Richardson 	/* Dynamic offset to mbuf priv1 */
20*99a2dd95SBruce Richardson 	int mbuf_priv1_off;
21*99a2dd95SBruce Richardson 	/* Cached next index */
22*99a2dd95SBruce Richardson 	uint16_t next_index;
23*99a2dd95SBruce Richardson };
24*99a2dd95SBruce Richardson 
25*99a2dd95SBruce Richardson static struct ip4_rewrite_node_main *ip4_rewrite_nm;
26*99a2dd95SBruce Richardson 
27*99a2dd95SBruce Richardson #define IP4_REWRITE_NODE_LAST_NEXT(ctx) \
28*99a2dd95SBruce Richardson 	(((struct ip4_rewrite_node_ctx *)ctx)->next_index)
29*99a2dd95SBruce Richardson 
30*99a2dd95SBruce Richardson #define IP4_REWRITE_NODE_PRIV1_OFF(ctx) \
31*99a2dd95SBruce Richardson 	(((struct ip4_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
32*99a2dd95SBruce Richardson 
33*99a2dd95SBruce Richardson static uint16_t
ip4_rewrite_node_process(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)34*99a2dd95SBruce Richardson ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
35*99a2dd95SBruce Richardson 			 void **objs, uint16_t nb_objs)
36*99a2dd95SBruce Richardson {
37*99a2dd95SBruce Richardson 	struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
38*99a2dd95SBruce Richardson 	struct ip4_rewrite_nh_header *nh = ip4_rewrite_nm->nh;
39*99a2dd95SBruce Richardson 	const int dyn = IP4_REWRITE_NODE_PRIV1_OFF(node->ctx);
40*99a2dd95SBruce Richardson 	uint16_t next0, next1, next2, next3, next_index;
41*99a2dd95SBruce Richardson 	struct rte_ipv4_hdr *ip0, *ip1, *ip2, *ip3;
42*99a2dd95SBruce Richardson 	uint16_t n_left_from, held = 0, last_spec = 0;
43*99a2dd95SBruce Richardson 	void *d0, *d1, *d2, *d3;
44*99a2dd95SBruce Richardson 	void **to_next, **from;
45*99a2dd95SBruce Richardson 	rte_xmm_t priv01;
46*99a2dd95SBruce Richardson 	rte_xmm_t priv23;
47*99a2dd95SBruce Richardson 	int i;
48*99a2dd95SBruce Richardson 
49*99a2dd95SBruce Richardson 	/* Speculative next as last next */
50*99a2dd95SBruce Richardson 	next_index = IP4_REWRITE_NODE_LAST_NEXT(node->ctx);
51*99a2dd95SBruce Richardson 	rte_prefetch0(nh);
52*99a2dd95SBruce Richardson 
53*99a2dd95SBruce Richardson 	pkts = (struct rte_mbuf **)objs;
54*99a2dd95SBruce Richardson 	from = objs;
55*99a2dd95SBruce Richardson 	n_left_from = nb_objs;
56*99a2dd95SBruce Richardson 
57*99a2dd95SBruce Richardson 	for (i = 0; i < 4 && i < n_left_from; i++)
58*99a2dd95SBruce Richardson 		rte_prefetch0(pkts[i]);
59*99a2dd95SBruce Richardson 
60*99a2dd95SBruce Richardson 	/* Get stream for the speculated next node */
61*99a2dd95SBruce Richardson 	to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
62*99a2dd95SBruce Richardson 	/* Update Ethernet header of pkts */
63*99a2dd95SBruce Richardson 	while (n_left_from >= 4) {
64*99a2dd95SBruce Richardson 		if (likely(n_left_from > 7)) {
65*99a2dd95SBruce Richardson 			/* Prefetch only next-mbuf struct and priv area.
66*99a2dd95SBruce Richardson 			 * Data need not be prefetched as we only write.
67*99a2dd95SBruce Richardson 			 */
68*99a2dd95SBruce Richardson 			rte_prefetch0(pkts[4]);
69*99a2dd95SBruce Richardson 			rte_prefetch0(pkts[5]);
70*99a2dd95SBruce Richardson 			rte_prefetch0(pkts[6]);
71*99a2dd95SBruce Richardson 			rte_prefetch0(pkts[7]);
72*99a2dd95SBruce Richardson 		}
73*99a2dd95SBruce Richardson 
74*99a2dd95SBruce Richardson 		mbuf0 = pkts[0];
75*99a2dd95SBruce Richardson 		mbuf1 = pkts[1];
76*99a2dd95SBruce Richardson 		mbuf2 = pkts[2];
77*99a2dd95SBruce Richardson 		mbuf3 = pkts[3];
78*99a2dd95SBruce Richardson 
79*99a2dd95SBruce Richardson 		pkts += 4;
80*99a2dd95SBruce Richardson 		n_left_from -= 4;
81*99a2dd95SBruce Richardson 		priv01.u64[0] = node_mbuf_priv1(mbuf0, dyn)->u;
82*99a2dd95SBruce Richardson 		priv01.u64[1] = node_mbuf_priv1(mbuf1, dyn)->u;
83*99a2dd95SBruce Richardson 		priv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;
84*99a2dd95SBruce Richardson 		priv23.u64[1] = node_mbuf_priv1(mbuf3, dyn)->u;
85*99a2dd95SBruce Richardson 
86*99a2dd95SBruce Richardson 		/* Increment checksum by one. */
87*99a2dd95SBruce Richardson 		priv01.u32[1] += rte_cpu_to_be_16(0x0100);
88*99a2dd95SBruce Richardson 		priv01.u32[3] += rte_cpu_to_be_16(0x0100);
89*99a2dd95SBruce Richardson 		priv23.u32[1] += rte_cpu_to_be_16(0x0100);
90*99a2dd95SBruce Richardson 		priv23.u32[3] += rte_cpu_to_be_16(0x0100);
91*99a2dd95SBruce Richardson 
92*99a2dd95SBruce Richardson 		/* Update ttl,cksum rewrite ethernet hdr on mbuf0 */
93*99a2dd95SBruce Richardson 		d0 = rte_pktmbuf_mtod(mbuf0, void *);
94*99a2dd95SBruce Richardson 		rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
95*99a2dd95SBruce Richardson 			   nh[priv01.u16[0]].rewrite_len);
96*99a2dd95SBruce Richardson 
97*99a2dd95SBruce Richardson 		next0 = nh[priv01.u16[0]].tx_node;
98*99a2dd95SBruce Richardson 		ip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +
99*99a2dd95SBruce Richardson 					      sizeof(struct rte_ether_hdr));
100*99a2dd95SBruce Richardson 		ip0->time_to_live = priv01.u16[1] - 1;
101*99a2dd95SBruce Richardson 		ip0->hdr_checksum = priv01.u16[2] + priv01.u16[3];
102*99a2dd95SBruce Richardson 
103*99a2dd95SBruce Richardson 		/* Update ttl,cksum rewrite ethernet hdr on mbuf1 */
104*99a2dd95SBruce Richardson 		d1 = rte_pktmbuf_mtod(mbuf1, void *);
105*99a2dd95SBruce Richardson 		rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
106*99a2dd95SBruce Richardson 			   nh[priv01.u16[4]].rewrite_len);
107*99a2dd95SBruce Richardson 
108*99a2dd95SBruce Richardson 		next1 = nh[priv01.u16[4]].tx_node;
109*99a2dd95SBruce Richardson 		ip1 = (struct rte_ipv4_hdr *)((uint8_t *)d1 +
110*99a2dd95SBruce Richardson 					      sizeof(struct rte_ether_hdr));
111*99a2dd95SBruce Richardson 		ip1->time_to_live = priv01.u16[5] - 1;
112*99a2dd95SBruce Richardson 		ip1->hdr_checksum = priv01.u16[6] + priv01.u16[7];
113*99a2dd95SBruce Richardson 
114*99a2dd95SBruce Richardson 		/* Update ttl,cksum rewrite ethernet hdr on mbuf2 */
115*99a2dd95SBruce Richardson 		d2 = rte_pktmbuf_mtod(mbuf2, void *);
116*99a2dd95SBruce Richardson 		rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
117*99a2dd95SBruce Richardson 			   nh[priv23.u16[0]].rewrite_len);
118*99a2dd95SBruce Richardson 		next2 = nh[priv23.u16[0]].tx_node;
119*99a2dd95SBruce Richardson 		ip2 = (struct rte_ipv4_hdr *)((uint8_t *)d2 +
120*99a2dd95SBruce Richardson 					      sizeof(struct rte_ether_hdr));
121*99a2dd95SBruce Richardson 		ip2->time_to_live = priv23.u16[1] - 1;
122*99a2dd95SBruce Richardson 		ip2->hdr_checksum = priv23.u16[2] + priv23.u16[3];
123*99a2dd95SBruce Richardson 
124*99a2dd95SBruce Richardson 		/* Update ttl,cksum rewrite ethernet hdr on mbuf3 */
125*99a2dd95SBruce Richardson 		d3 = rte_pktmbuf_mtod(mbuf3, void *);
126*99a2dd95SBruce Richardson 		rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
127*99a2dd95SBruce Richardson 			   nh[priv23.u16[4]].rewrite_len);
128*99a2dd95SBruce Richardson 
129*99a2dd95SBruce Richardson 		next3 = nh[priv23.u16[4]].tx_node;
130*99a2dd95SBruce Richardson 		ip3 = (struct rte_ipv4_hdr *)((uint8_t *)d3 +
131*99a2dd95SBruce Richardson 					      sizeof(struct rte_ether_hdr));
132*99a2dd95SBruce Richardson 		ip3->time_to_live = priv23.u16[5] - 1;
133*99a2dd95SBruce Richardson 		ip3->hdr_checksum = priv23.u16[6] + priv23.u16[7];
134*99a2dd95SBruce Richardson 
135*99a2dd95SBruce Richardson 		/* Enqueue four to next node */
136*99a2dd95SBruce Richardson 		rte_edge_t fix_spec =
137*99a2dd95SBruce Richardson 			((next_index == next0) && (next0 == next1) &&
138*99a2dd95SBruce Richardson 			 (next1 == next2) && (next2 == next3));
139*99a2dd95SBruce Richardson 
140*99a2dd95SBruce Richardson 		if (unlikely(fix_spec == 0)) {
141*99a2dd95SBruce Richardson 			/* Copy things successfully speculated till now */
142*99a2dd95SBruce Richardson 			rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
143*99a2dd95SBruce Richardson 			from += last_spec;
144*99a2dd95SBruce Richardson 			to_next += last_spec;
145*99a2dd95SBruce Richardson 			held += last_spec;
146*99a2dd95SBruce Richardson 			last_spec = 0;
147*99a2dd95SBruce Richardson 
148*99a2dd95SBruce Richardson 			/* next0 */
149*99a2dd95SBruce Richardson 			if (next_index == next0) {
150*99a2dd95SBruce Richardson 				to_next[0] = from[0];
151*99a2dd95SBruce Richardson 				to_next++;
152*99a2dd95SBruce Richardson 				held++;
153*99a2dd95SBruce Richardson 			} else {
154*99a2dd95SBruce Richardson 				rte_node_enqueue_x1(graph, node, next0,
155*99a2dd95SBruce Richardson 						    from[0]);
156*99a2dd95SBruce Richardson 			}
157*99a2dd95SBruce Richardson 
158*99a2dd95SBruce Richardson 			/* next1 */
159*99a2dd95SBruce Richardson 			if (next_index == next1) {
160*99a2dd95SBruce Richardson 				to_next[0] = from[1];
161*99a2dd95SBruce Richardson 				to_next++;
162*99a2dd95SBruce Richardson 				held++;
163*99a2dd95SBruce Richardson 			} else {
164*99a2dd95SBruce Richardson 				rte_node_enqueue_x1(graph, node, next1,
165*99a2dd95SBruce Richardson 						    from[1]);
166*99a2dd95SBruce Richardson 			}
167*99a2dd95SBruce Richardson 
168*99a2dd95SBruce Richardson 			/* next2 */
169*99a2dd95SBruce Richardson 			if (next_index == next2) {
170*99a2dd95SBruce Richardson 				to_next[0] = from[2];
171*99a2dd95SBruce Richardson 				to_next++;
172*99a2dd95SBruce Richardson 				held++;
173*99a2dd95SBruce Richardson 			} else {
174*99a2dd95SBruce Richardson 				rte_node_enqueue_x1(graph, node, next2,
175*99a2dd95SBruce Richardson 						    from[2]);
176*99a2dd95SBruce Richardson 			}
177*99a2dd95SBruce Richardson 
178*99a2dd95SBruce Richardson 			/* next3 */
179*99a2dd95SBruce Richardson 			if (next_index == next3) {
180*99a2dd95SBruce Richardson 				to_next[0] = from[3];
181*99a2dd95SBruce Richardson 				to_next++;
182*99a2dd95SBruce Richardson 				held++;
183*99a2dd95SBruce Richardson 			} else {
184*99a2dd95SBruce Richardson 				rte_node_enqueue_x1(graph, node, next3,
185*99a2dd95SBruce Richardson 						    from[3]);
186*99a2dd95SBruce Richardson 			}
187*99a2dd95SBruce Richardson 
188*99a2dd95SBruce Richardson 			from += 4;
189*99a2dd95SBruce Richardson 
190*99a2dd95SBruce Richardson 			/* Change speculation if last two are same */
191*99a2dd95SBruce Richardson 			if ((next_index != next3) && (next2 == next3)) {
192*99a2dd95SBruce Richardson 				/* Put the current speculated node */
193*99a2dd95SBruce Richardson 				rte_node_next_stream_put(graph, node,
194*99a2dd95SBruce Richardson 							 next_index, held);
195*99a2dd95SBruce Richardson 				held = 0;
196*99a2dd95SBruce Richardson 
197*99a2dd95SBruce Richardson 				/* Get next speculated stream */
198*99a2dd95SBruce Richardson 				next_index = next3;
199*99a2dd95SBruce Richardson 				to_next = rte_node_next_stream_get(
200*99a2dd95SBruce Richardson 					graph, node, next_index, nb_objs);
201*99a2dd95SBruce Richardson 			}
202*99a2dd95SBruce Richardson 		} else {
203*99a2dd95SBruce Richardson 			last_spec += 4;
204*99a2dd95SBruce Richardson 		}
205*99a2dd95SBruce Richardson 	}
206*99a2dd95SBruce Richardson 
207*99a2dd95SBruce Richardson 	while (n_left_from > 0) {
208*99a2dd95SBruce Richardson 		uint16_t chksum;
209*99a2dd95SBruce Richardson 
210*99a2dd95SBruce Richardson 		mbuf0 = pkts[0];
211*99a2dd95SBruce Richardson 
212*99a2dd95SBruce Richardson 		pkts += 1;
213*99a2dd95SBruce Richardson 		n_left_from -= 1;
214*99a2dd95SBruce Richardson 
215*99a2dd95SBruce Richardson 		d0 = rte_pktmbuf_mtod(mbuf0, void *);
216*99a2dd95SBruce Richardson 		rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,
217*99a2dd95SBruce Richardson 			   nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);
218*99a2dd95SBruce Richardson 
219*99a2dd95SBruce Richardson 		next0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;
220*99a2dd95SBruce Richardson 		ip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +
221*99a2dd95SBruce Richardson 					      sizeof(struct rte_ether_hdr));
222*99a2dd95SBruce Richardson 		chksum = node_mbuf_priv1(mbuf0, dyn)->cksum +
223*99a2dd95SBruce Richardson 			 rte_cpu_to_be_16(0x0100);
224*99a2dd95SBruce Richardson 		chksum += chksum >= 0xffff;
225*99a2dd95SBruce Richardson 		ip0->hdr_checksum = chksum;
226*99a2dd95SBruce Richardson 		ip0->time_to_live = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
227*99a2dd95SBruce Richardson 
228*99a2dd95SBruce Richardson 		if (unlikely(next_index ^ next0)) {
229*99a2dd95SBruce Richardson 			/* Copy things successfully speculated till now */
230*99a2dd95SBruce Richardson 			rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
231*99a2dd95SBruce Richardson 			from += last_spec;
232*99a2dd95SBruce Richardson 			to_next += last_spec;
233*99a2dd95SBruce Richardson 			held += last_spec;
234*99a2dd95SBruce Richardson 			last_spec = 0;
235*99a2dd95SBruce Richardson 
236*99a2dd95SBruce Richardson 			rte_node_enqueue_x1(graph, node, next0, from[0]);
237*99a2dd95SBruce Richardson 			from += 1;
238*99a2dd95SBruce Richardson 		} else {
239*99a2dd95SBruce Richardson 			last_spec += 1;
240*99a2dd95SBruce Richardson 		}
241*99a2dd95SBruce Richardson 	}
242*99a2dd95SBruce Richardson 
243*99a2dd95SBruce Richardson 	/* !!! Home run !!! */
244*99a2dd95SBruce Richardson 	if (likely(last_spec == nb_objs)) {
245*99a2dd95SBruce Richardson 		rte_node_next_stream_move(graph, node, next_index);
246*99a2dd95SBruce Richardson 		return nb_objs;
247*99a2dd95SBruce Richardson 	}
248*99a2dd95SBruce Richardson 
249*99a2dd95SBruce Richardson 	held += last_spec;
250*99a2dd95SBruce Richardson 	rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
251*99a2dd95SBruce Richardson 	rte_node_next_stream_put(graph, node, next_index, held);
252*99a2dd95SBruce Richardson 	/* Save the last next used */
253*99a2dd95SBruce Richardson 	IP4_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
254*99a2dd95SBruce Richardson 
255*99a2dd95SBruce Richardson 	return nb_objs;
256*99a2dd95SBruce Richardson }
257*99a2dd95SBruce Richardson 
258*99a2dd95SBruce Richardson static int
ip4_rewrite_node_init(const struct rte_graph * graph,struct rte_node * node)259*99a2dd95SBruce Richardson ip4_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
260*99a2dd95SBruce Richardson {
261*99a2dd95SBruce Richardson 	static bool init_once;
262*99a2dd95SBruce Richardson 
263*99a2dd95SBruce Richardson 	RTE_SET_USED(graph);
264*99a2dd95SBruce Richardson 	RTE_BUILD_BUG_ON(sizeof(struct ip4_rewrite_node_ctx) > RTE_NODE_CTX_SZ);
265*99a2dd95SBruce Richardson 
266*99a2dd95SBruce Richardson 	if (!init_once) {
267*99a2dd95SBruce Richardson 		node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(
268*99a2dd95SBruce Richardson 				&node_mbuf_priv1_dynfield_desc);
269*99a2dd95SBruce Richardson 		if (node_mbuf_priv1_dynfield_offset < 0)
270*99a2dd95SBruce Richardson 			return -rte_errno;
271*99a2dd95SBruce Richardson 		init_once = true;
272*99a2dd95SBruce Richardson 	}
273*99a2dd95SBruce Richardson 	IP4_REWRITE_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset;
274*99a2dd95SBruce Richardson 
275*99a2dd95SBruce Richardson 	node_dbg("ip4_rewrite", "Initialized ip4_rewrite node initialized");
276*99a2dd95SBruce Richardson 
277*99a2dd95SBruce Richardson 	return 0;
278*99a2dd95SBruce Richardson }
279*99a2dd95SBruce Richardson 
280*99a2dd95SBruce Richardson int
ip4_rewrite_set_next(uint16_t port_id,uint16_t next_index)281*99a2dd95SBruce Richardson ip4_rewrite_set_next(uint16_t port_id, uint16_t next_index)
282*99a2dd95SBruce Richardson {
283*99a2dd95SBruce Richardson 	if (ip4_rewrite_nm == NULL) {
284*99a2dd95SBruce Richardson 		ip4_rewrite_nm = rte_zmalloc(
285*99a2dd95SBruce Richardson 			"ip4_rewrite", sizeof(struct ip4_rewrite_node_main),
286*99a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE);
287*99a2dd95SBruce Richardson 		if (ip4_rewrite_nm == NULL)
288*99a2dd95SBruce Richardson 			return -ENOMEM;
289*99a2dd95SBruce Richardson 	}
290*99a2dd95SBruce Richardson 	ip4_rewrite_nm->next_index[port_id] = next_index;
291*99a2dd95SBruce Richardson 
292*99a2dd95SBruce Richardson 	return 0;
293*99a2dd95SBruce Richardson }
294*99a2dd95SBruce Richardson 
295*99a2dd95SBruce Richardson int
rte_node_ip4_rewrite_add(uint16_t next_hop,uint8_t * rewrite_data,uint8_t rewrite_len,uint16_t dst_port)296*99a2dd95SBruce Richardson rte_node_ip4_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
297*99a2dd95SBruce Richardson 			 uint8_t rewrite_len, uint16_t dst_port)
298*99a2dd95SBruce Richardson {
299*99a2dd95SBruce Richardson 	struct ip4_rewrite_nh_header *nh;
300*99a2dd95SBruce Richardson 
301*99a2dd95SBruce Richardson 	if (next_hop >= RTE_GRAPH_IP4_REWRITE_MAX_NH)
302*99a2dd95SBruce Richardson 		return -EINVAL;
303*99a2dd95SBruce Richardson 
304*99a2dd95SBruce Richardson 	if (rewrite_len > RTE_GRAPH_IP4_REWRITE_MAX_LEN)
305*99a2dd95SBruce Richardson 		return -EINVAL;
306*99a2dd95SBruce Richardson 
307*99a2dd95SBruce Richardson 	if (ip4_rewrite_nm == NULL) {
308*99a2dd95SBruce Richardson 		ip4_rewrite_nm = rte_zmalloc(
309*99a2dd95SBruce Richardson 			"ip4_rewrite", sizeof(struct ip4_rewrite_node_main),
310*99a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE);
311*99a2dd95SBruce Richardson 		if (ip4_rewrite_nm == NULL)
312*99a2dd95SBruce Richardson 			return -ENOMEM;
313*99a2dd95SBruce Richardson 	}
314*99a2dd95SBruce Richardson 
315*99a2dd95SBruce Richardson 	/* Check if dst port doesn't exist as edge */
316*99a2dd95SBruce Richardson 	if (!ip4_rewrite_nm->next_index[dst_port])
317*99a2dd95SBruce Richardson 		return -EINVAL;
318*99a2dd95SBruce Richardson 
319*99a2dd95SBruce Richardson 	/* Update next hop */
320*99a2dd95SBruce Richardson 	nh = &ip4_rewrite_nm->nh[next_hop];
321*99a2dd95SBruce Richardson 
322*99a2dd95SBruce Richardson 	memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
323*99a2dd95SBruce Richardson 	nh->tx_node = ip4_rewrite_nm->next_index[dst_port];
324*99a2dd95SBruce Richardson 	nh->rewrite_len = rewrite_len;
325*99a2dd95SBruce Richardson 	nh->enabled = true;
326*99a2dd95SBruce Richardson 
327*99a2dd95SBruce Richardson 	return 0;
328*99a2dd95SBruce Richardson }
329*99a2dd95SBruce Richardson 
330*99a2dd95SBruce Richardson static struct rte_node_register ip4_rewrite_node = {
331*99a2dd95SBruce Richardson 	.process = ip4_rewrite_node_process,
332*99a2dd95SBruce Richardson 	.name = "ip4_rewrite",
333*99a2dd95SBruce Richardson 	/* Default edge i.e '0' is pkt drop */
334*99a2dd95SBruce Richardson 	.nb_edges = 1,
335*99a2dd95SBruce Richardson 	.next_nodes = {
336*99a2dd95SBruce Richardson 		[0] = "pkt_drop",
337*99a2dd95SBruce Richardson 	},
338*99a2dd95SBruce Richardson 	.init = ip4_rewrite_node_init,
339*99a2dd95SBruce Richardson };
340*99a2dd95SBruce Richardson 
341*99a2dd95SBruce Richardson struct rte_node_register *
ip4_rewrite_node_get(void)342*99a2dd95SBruce Richardson ip4_rewrite_node_get(void)
343*99a2dd95SBruce Richardson {
344*99a2dd95SBruce Richardson 	return &ip4_rewrite_node;
345*99a2dd95SBruce Richardson }
346*99a2dd95SBruce Richardson 
347*99a2dd95SBruce Richardson RTE_NODE_REGISTER(ip4_rewrite_node);
348