Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2023 Marvell.
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_ip6_api.h"
15 : :
16 : : #include "ip6_rewrite_priv.h"
17 : : #include "node_private.h"
18 : :
19 : : struct ip6_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 ip6_rewrite_node_main *ip6_rewrite_nm;
27 : :
28 : : #define IP6_REWRITE_NODE_LAST_NEXT(ctx) \
29 : : (((struct ip6_rewrite_node_ctx *)ctx)->next_index)
30 : :
31 : : #define IP6_REWRITE_NODE_PRIV1_OFF(ctx) \
32 : : (((struct ip6_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
33 : :
34 : : static uint16_t
35 : 0 : ip6_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 ip6_rewrite_nh_header *nh = ip6_rewrite_nm->nh;
40 : 0 : const int dyn = IP6_REWRITE_NODE_PRIV1_OFF(node->ctx);
41 : : uint16_t next0, next1, next2, next3, next_index;
42 : : uint16_t n_left_from, held = 0, last_spec = 0;
43 : : struct rte_ipv6_hdr *ip0, *ip1, *ip2, *ip3;
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 = IP6_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 : : /* Update next_hop rewrite ethernet hdr on mbuf0 */
88 : 0 : d0 = rte_pktmbuf_mtod(mbuf0, void *);
89 : 0 : rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
90 [ # # ]: 0 : nh[priv01.u16[0]].rewrite_len);
91 : :
92 : 0 : next0 = nh[priv01.u16[0]].tx_node;
93 : : ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
94 : : sizeof(struct rte_ether_hdr));
95 : 0 : ip0->hop_limits = priv01.u16[1] - 1;
96 : :
97 : : /* Update next_hop rewrite ethernet hdr on mbuf1 */
98 : 0 : d1 = rte_pktmbuf_mtod(mbuf1, void *);
99 : 0 : rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
100 [ # # ]: 0 : nh[priv01.u16[4]].rewrite_len);
101 : :
102 : 0 : next1 = nh[priv01.u16[4]].tx_node;
103 : : ip1 = (struct rte_ipv6_hdr *)((uint8_t *)d1 +
104 : : sizeof(struct rte_ether_hdr));
105 : 0 : ip1->hop_limits = priv01.u16[5] - 1;
106 : :
107 : : /* Update next_hop rewrite ethernet hdr on mbuf2 */
108 : 0 : d2 = rte_pktmbuf_mtod(mbuf2, void *);
109 : 0 : rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
110 [ # # ]: 0 : nh[priv23.u16[0]].rewrite_len);
111 : 0 : next2 = nh[priv23.u16[0]].tx_node;
112 : : ip2 = (struct rte_ipv6_hdr *)((uint8_t *)d2 +
113 : : sizeof(struct rte_ether_hdr));
114 : 0 : ip2->hop_limits = priv23.u16[1] - 1;
115 : :
116 : : /* Update next_hop rewrite ethernet hdr on mbuf3 */
117 : 0 : d3 = rte_pktmbuf_mtod(mbuf3, void *);
118 : 0 : rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
119 [ # # ]: 0 : nh[priv23.u16[4]].rewrite_len);
120 : :
121 : 0 : next3 = nh[priv23.u16[4]].tx_node;
122 : : ip3 = (struct rte_ipv6_hdr *)((uint8_t *)d3 +
123 : : sizeof(struct rte_ether_hdr));
124 : 0 : ip3->hop_limits = priv23.u16[5] - 1;
125 : :
126 : : /* Enqueue four packets to next node */
127 : 0 : rte_edge_t fix_spec =
128 : 0 : ((next_index == next0) && (next0 == next1) &&
129 [ # # # # ]: 0 : (next1 == next2) && (next2 == next3));
130 : :
131 [ # # ]: 0 : if (unlikely(fix_spec == 0)) {
132 : : /* Copy things successfully speculated till now */
133 [ # # ]: 0 : rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
134 : 0 : from += last_spec;
135 : 0 : to_next += last_spec;
136 : 0 : held += last_spec;
137 : : last_spec = 0;
138 : :
139 : : /* next0 */
140 [ # # ]: 0 : if (next_index == next0) {
141 : 0 : to_next[0] = from[0];
142 : 0 : to_next++;
143 : 0 : held++;
144 : : } else {
145 : 0 : rte_node_enqueue_x1(graph, node, next0,
146 : : from[0]);
147 : : }
148 : :
149 : : /* next1 */
150 [ # # ]: 0 : if (next_index == next1) {
151 : 0 : to_next[0] = from[1];
152 : 0 : to_next++;
153 : 0 : held++;
154 : : } else {
155 : 0 : rte_node_enqueue_x1(graph, node, next1,
156 : : from[1]);
157 : : }
158 : :
159 : : /* next2 */
160 [ # # ]: 0 : if (next_index == next2) {
161 : 0 : to_next[0] = from[2];
162 : 0 : to_next++;
163 : 0 : held++;
164 : : } else {
165 : 0 : rte_node_enqueue_x1(graph, node, next2,
166 : : from[2]);
167 : : }
168 : :
169 : : /* next3 */
170 [ # # ]: 0 : if (next_index == next3) {
171 : 0 : to_next[0] = from[3];
172 : 0 : to_next++;
173 : 0 : held++;
174 : : } else {
175 : 0 : rte_node_enqueue_x1(graph, node, next3,
176 : : from[3]);
177 : : }
178 : :
179 : 0 : from += 4;
180 : :
181 : : /* Change speculation if last two are same */
182 [ # # ]: 0 : if ((next_index != next3) && (next2 == next3)) {
183 : : /* Put the current speculated node */
184 [ # # ]: 0 : rte_node_next_stream_put(graph, node,
185 : : next_index, held);
186 : : held = 0;
187 : :
188 : : /* Get next speculated stream */
189 : : next_index = next3;
190 : 0 : to_next = rte_node_next_stream_get(
191 : : graph, node, next_index, nb_objs);
192 : : }
193 : : } else {
194 : 0 : last_spec += 4;
195 : : }
196 : : }
197 : :
198 [ # # ]: 0 : while (n_left_from > 0) {
199 : 0 : mbuf0 = pkts[0];
200 : :
201 : 0 : pkts += 1;
202 : 0 : n_left_from -= 1;
203 : :
204 [ # # ]: 0 : d0 = rte_pktmbuf_mtod(mbuf0, void *);
205 : 0 : rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,
206 [ # # ]: 0 : nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);
207 : :
208 : 0 : next0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;
209 : : ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
210 : : sizeof(struct rte_ether_hdr));
211 : 0 : ip0->hop_limits = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
212 : :
213 [ # # ]: 0 : if (unlikely(next_index ^ next0)) {
214 : : /* Copy things successfully speculated till now */
215 [ # # ]: 0 : rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
216 : 0 : from += last_spec;
217 : 0 : to_next += last_spec;
218 : 0 : held += last_spec;
219 : : last_spec = 0;
220 : :
221 : 0 : rte_node_enqueue_x1(graph, node, next0, from[0]);
222 : 0 : from += 1;
223 : : } else {
224 : 0 : last_spec += 1;
225 : : }
226 : : }
227 : :
228 : : /* !!! Home run !!! */
229 [ # # ]: 0 : if (likely(last_spec == nb_objs)) {
230 : 0 : rte_node_next_stream_move(graph, node, next_index);
231 : 0 : return nb_objs;
232 : : }
233 : :
234 : 0 : held += last_spec;
235 [ # # ]: 0 : rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
236 [ # # ]: 0 : rte_node_next_stream_put(graph, node, next_index, held);
237 : : /* Save the last next used */
238 : 0 : IP6_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
239 : :
240 : 0 : return nb_objs;
241 : : }
242 : :
243 : : static int
244 : 0 : ip6_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
245 : : {
246 : : static bool init_once;
247 : :
248 : : RTE_SET_USED(graph);
249 : : RTE_BUILD_BUG_ON(sizeof(struct ip6_rewrite_node_ctx) > RTE_NODE_CTX_SZ);
250 : :
251 [ # # ]: 0 : if (!init_once) {
252 : 0 : node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(
253 : : &node_mbuf_priv1_dynfield_desc);
254 [ # # ]: 0 : if (node_mbuf_priv1_dynfield_offset < 0)
255 : 0 : return -rte_errno;
256 : 0 : init_once = true;
257 : : }
258 : 0 : IP6_REWRITE_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset;
259 : :
260 : 0 : node_dbg("ip6_rewrite", "Initialized ip6_rewrite node");
261 : :
262 : 0 : return 0;
263 : : }
264 : :
265 : : int
266 : 0 : ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index)
267 : : {
268 [ # # ]: 0 : if (ip6_rewrite_nm == NULL) {
269 : 0 : ip6_rewrite_nm = rte_zmalloc(
270 : : "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
271 : : RTE_CACHE_LINE_SIZE);
272 [ # # ]: 0 : if (ip6_rewrite_nm == NULL)
273 : : return -ENOMEM;
274 : : }
275 : 0 : ip6_rewrite_nm->next_index[port_id] = next_index;
276 : :
277 : 0 : return 0;
278 : : }
279 : :
280 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_node_ip6_rewrite_add, 23.07)
281 : : int
282 : 0 : rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
283 : : uint8_t rewrite_len, uint16_t dst_port)
284 : : {
285 : : struct ip6_rewrite_nh_header *nh;
286 : :
287 [ # # ]: 0 : if (next_hop >= RTE_GRAPH_IP6_REWRITE_MAX_NH)
288 : : return -EINVAL;
289 : :
290 [ # # ]: 0 : if (rewrite_len > RTE_GRAPH_IP6_REWRITE_MAX_LEN)
291 : : return -EINVAL;
292 : :
293 [ # # ]: 0 : if (ip6_rewrite_nm == NULL) {
294 : 0 : ip6_rewrite_nm = rte_zmalloc(
295 : : "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
296 : : RTE_CACHE_LINE_SIZE);
297 [ # # ]: 0 : if (ip6_rewrite_nm == NULL)
298 : : return -ENOMEM;
299 : : }
300 : :
301 : : /* Check if dst port doesn't exist as edge */
302 [ # # ]: 0 : if (!ip6_rewrite_nm->next_index[dst_port])
303 : : return -EINVAL;
304 : :
305 : : /* Update next hop */
306 : 0 : nh = &ip6_rewrite_nm->nh[next_hop];
307 : :
308 : 0 : memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
309 : 0 : nh->tx_node = ip6_rewrite_nm->next_index[dst_port];
310 : 0 : nh->rewrite_len = rewrite_len;
311 : 0 : nh->enabled = true;
312 : :
313 : 0 : return 0;
314 : : }
315 : :
316 : : static struct rte_node_register ip6_rewrite_node = {
317 : : .process = ip6_rewrite_node_process,
318 : : .name = "ip6_rewrite",
319 : : /* Default edge i.e '0' is pkt drop */
320 : : .nb_edges = 1,
321 : : .next_nodes = {
322 : : [0] = "pkt_drop",
323 : : },
324 : : .init = ip6_rewrite_node_init,
325 : : };
326 : :
327 : : struct rte_node_register *
328 : 0 : ip6_rewrite_node_get(void)
329 : : {
330 : 0 : return &ip6_rewrite_node;
331 : : }
332 : :
333 : 252 : RTE_NODE_REGISTER(ip6_rewrite_node);
|