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