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