Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2025 Marvell.
3 : : */
4 : :
5 : : #include <arpa/inet.h>
6 : :
7 : : #include <eal_export.h>
8 : : #include <rte_errno.h>
9 : : #include <rte_ether.h>
10 : : #include <rte_fib6.h>
11 : : #include <rte_graph.h>
12 : : #include <rte_graph_worker.h>
13 : : #include <rte_ip.h>
14 : :
15 : : #include "rte_node_ip6_api.h"
16 : :
17 : : #include "node_private.h"
18 : :
19 : : /* IP6 Lookup FIB global data struct */
20 : : struct ip6_lookup_fib_node_main {
21 : : struct rte_fib6 *fib6[RTE_MAX_NUMA_NODES];
22 : : };
23 : :
24 : : struct ip6_lookup_fib_node_ctx {
25 : : /* Socket's FIB6 */
26 : : struct rte_fib6 *fib6;
27 : : /* Dynamic offset to mbuf priv1 */
28 : : int mbuf_priv1_off;
29 : : };
30 : :
31 : : static struct ip6_lookup_fib_node_main ip6_lookup_fib_nm;
32 : :
33 : : #define FIB6_DEFAULT_MAX_ROUTES (UINT16_MAX)
34 : : #define FIB6_DEFAULT_NUM_TBL8 (UINT16_MAX / 2)
35 : : #define FIB6_DEFAULT_NH (RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP << 16)
36 : :
37 : : #define IP6_LOOKUP_FIB_NODE(ctx) \
38 : : (((struct ip6_lookup_fib_node_ctx *)ctx)->fib6)
39 : :
40 : : #define IP6_LOOKUP_FIB_NODE_PRIV1_OFF(ctx) \
41 : : (((struct ip6_lookup_fib_node_ctx *)ctx)->mbuf_priv1_off)
42 : :
43 : : static uint16_t
44 : 0 : ip6_lookup_fib_node_process(struct rte_graph *graph, struct rte_node *node, void **objs,
45 : : uint16_t nb_objs)
46 : : {
47 : : struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
48 : 0 : const int dyn = IP6_LOOKUP_FIB_NODE_PRIV1_OFF(node->ctx);
49 : 0 : struct rte_fib6 *fib = IP6_LOOKUP_FIB_NODE(node->ctx);
50 : 0 : struct rte_ipv6_addr ip[RTE_GRAPH_BURST_SIZE] = { 0 };
51 : : uint64_t next_hop[RTE_GRAPH_BURST_SIZE];
52 : : struct rte_ipv6_hdr *ipv6_hdr;
53 : : uint16_t lookup_err = 0;
54 : : void **to_next, **from;
55 : : uint16_t last_spec = 0;
56 : : rte_edge_t next_index;
57 : : uint16_t n_left_from;
58 : : uint16_t held = 0;
59 : : uint16_t next;
60 : : int i;
61 : :
62 : : /* Speculative next */
63 : : next_index = RTE_NODE_IP6_LOOKUP_NEXT_REWRITE;
64 : :
65 : : pkts = (struct rte_mbuf **)objs;
66 : : from = objs;
67 : : n_left_from = nb_objs;
68 : :
69 : : /* Get stream for the speculated next node */
70 : 0 : to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
71 : :
72 [ # # # # ]: 0 : for (i = 0; i < 4 && i < n_left_from; i++)
73 : 0 : rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[i], void *,
74 : : sizeof(struct rte_ether_hdr)));
75 : :
76 : : i = 0;
77 [ # # ]: 0 : while (n_left_from >= 4) {
78 [ # # ]: 0 : if (likely(n_left_from > 7)) {
79 : :
80 : : /* Prefetch next-next mbufs */
81 [ # # ]: 0 : if (likely(n_left_from > 11)) {
82 : 0 : rte_prefetch0(pkts[8]);
83 : 0 : rte_prefetch0(pkts[9]);
84 : 0 : rte_prefetch0(pkts[10]);
85 : 0 : rte_prefetch0(pkts[11]);
86 : : }
87 : :
88 : : /* Prefetch next mbuf data */
89 : 0 : rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[4], void *,
90 : : sizeof(struct rte_ether_hdr)));
91 : 0 : rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[5], void *,
92 : : sizeof(struct rte_ether_hdr)));
93 : 0 : rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[6], void *,
94 : : sizeof(struct rte_ether_hdr)));
95 : 0 : rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[7], void *,
96 : : sizeof(struct rte_ether_hdr)));
97 : : }
98 : :
99 : 0 : mbuf0 = pkts[0];
100 : 0 : mbuf1 = pkts[1];
101 : 0 : mbuf2 = pkts[2];
102 : 0 : mbuf3 = pkts[3];
103 : 0 : pkts += 4;
104 : 0 : n_left_from -= 4;
105 : : /* Extract DIP of mbuf0 */
106 : 0 : ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
107 : : sizeof(struct rte_ether_hdr));
108 : : /* Extract hop_limits as ipv6 hdr is in cache */
109 : 0 : node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
110 : :
111 : 0 : ip[i++] = ipv6_hdr->dst_addr;
112 : :
113 : : /* Extract DIP of mbuf1 */
114 : 0 : ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf1, struct rte_ipv6_hdr *,
115 : : sizeof(struct rte_ether_hdr));
116 : : /* Extract hop_limits as ipv6 hdr is in cache */
117 : 0 : node_mbuf_priv1(mbuf1, dyn)->ttl = ipv6_hdr->hop_limits;
118 : :
119 : 0 : ip[i++] = ipv6_hdr->dst_addr;
120 : :
121 : : /* Extract DIP of mbuf2 */
122 : 0 : ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf2, struct rte_ipv6_hdr *,
123 : : sizeof(struct rte_ether_hdr));
124 : : /* Extract hop_limits as ipv6 hdr is in cache */
125 : 0 : node_mbuf_priv1(mbuf2, dyn)->ttl = ipv6_hdr->hop_limits;
126 : :
127 : 0 : ip[i++] = ipv6_hdr->dst_addr;
128 : :
129 : : /* Extract DIP of mbuf3 */
130 : 0 : ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf3, struct rte_ipv6_hdr *,
131 : : sizeof(struct rte_ether_hdr));
132 : : /* Extract hop_limits as ipv6 hdr is in cache */
133 : 0 : node_mbuf_priv1(mbuf3, dyn)->ttl = ipv6_hdr->hop_limits;
134 : :
135 : 0 : ip[i++] = ipv6_hdr->dst_addr;
136 : : }
137 [ # # ]: 0 : while (n_left_from > 0) {
138 : 0 : mbuf0 = pkts[0];
139 : 0 : pkts += 1;
140 : 0 : n_left_from -= 1;
141 : :
142 : : /* Extract DIP of mbuf0 */
143 : 0 : ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
144 : : sizeof(struct rte_ether_hdr));
145 : : /* Extract hop_limits as ipv6 hdr is in cache */
146 : 0 : node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
147 : :
148 : 0 : ip[i++] = ipv6_hdr->dst_addr;
149 : : }
150 : :
151 : 0 : rte_fib6_lookup_bulk(fib, ip, next_hop, nb_objs);
152 : :
153 [ # # ]: 0 : for (i = 0; i < nb_objs; i++) {
154 : 0 : mbuf0 = (struct rte_mbuf *)objs[i];
155 [ # # ]: 0 : node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop[i];
156 : 0 : next = (uint16_t)(next_hop[i] >> 16);
157 : :
158 [ # # ]: 0 : if (unlikely(next_index ^ next)) {
159 : : /* Copy things successfully speculated till now */
160 [ # # ]: 0 : rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
161 : 0 : from += last_spec;
162 : 0 : to_next += last_spec;
163 : 0 : held += last_spec;
164 : : last_spec = 0;
165 : :
166 : 0 : rte_node_enqueue_x1(graph, node, next, from[0]);
167 : 0 : from += 1;
168 : : } else {
169 : 0 : last_spec += 1;
170 : : }
171 : :
172 [ # # ]: 0 : if (unlikely(next_hop[i] == FIB6_DEFAULT_NH))
173 : 0 : lookup_err += 1;
174 : : }
175 : :
176 : : /* !!! Home run !!! */
177 [ # # ]: 0 : if (likely(last_spec == nb_objs)) {
178 : 0 : rte_node_next_stream_move(graph, node, next_index);
179 : 0 : return nb_objs;
180 : : }
181 : :
182 [ # # ]: 0 : NODE_INCREMENT_XSTAT_ID(node, 0, lookup_err != 0, lookup_err);
183 : 0 : held += last_spec;
184 [ # # ]: 0 : rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
185 : : rte_node_next_stream_put(graph, node, next_index, held);
186 : :
187 : : return nb_objs;
188 : : }
189 : :
190 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_node_ip6_fib_create, 25.07)
191 : : int
192 : 0 : rte_node_ip6_fib_create(int socket, struct rte_fib6_conf *conf)
193 : : {
194 : : struct ip6_lookup_fib_node_main *nm = &ip6_lookup_fib_nm;
195 : : char s[RTE_FIB6_NAMESIZE];
196 : :
197 : : /* One fib6 per socket */
198 [ # # ]: 0 : if (nm->fib6[socket])
199 : : return 0;
200 : :
201 : 0 : conf->default_nh = FIB6_DEFAULT_NH;
202 : : snprintf(s, sizeof(s), "IPV6_LOOKUP_FIB_%u", socket);
203 : 0 : nm->fib6[socket] = rte_fib6_create(s, socket, conf);
204 [ # # ]: 0 : if (nm->fib6[socket] == NULL)
205 : 0 : return -rte_errno;
206 : :
207 : : return 0;
208 : : }
209 : :
210 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_node_ip6_fib_route_add, 25.07)
211 : : int
212 : 0 : rte_node_ip6_fib_route_add(const struct rte_ipv6_addr *ip, uint8_t depth, uint16_t next_hop,
213 : : enum rte_node_ip6_lookup_next next_node)
214 : : {
215 : : char abuf[INET6_ADDRSTRLEN];
216 : : unsigned int nb_sockets;
217 : : uint8_t socket;
218 : : uint32_t val;
219 : : int ret;
220 : :
221 : 0 : nb_sockets = rte_socket_count();
222 : 0 : inet_ntop(AF_INET6, ip, abuf, sizeof(abuf));
223 : : /* Embedded next node id into 24 bit next hop */
224 : 0 : val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1);
225 : 0 : node_dbg("ip6_lookup_fib", "FIB6: Adding route %s / %d nh (0x%x)", abuf, depth, val);
226 : :
227 [ # # ]: 0 : for (socket = 0; socket < nb_sockets; socket++) {
228 [ # # ]: 0 : if (!ip6_lookup_fib_nm.fib6[socket])
229 : 0 : continue;
230 : :
231 : 0 : ret = rte_fib6_add(ip6_lookup_fib_nm.fib6[socket], ip, depth, val);
232 [ # # ]: 0 : if (ret < 0) {
233 : 0 : node_err("ip6_lookup_fib",
234 : : "Unable to add entry %s / %d nh (%x) to FIB on sock %d, rc=%d",
235 : : abuf, depth, val, socket, ret);
236 : 0 : return ret;
237 : : }
238 : : }
239 : :
240 : : return 0;
241 : : }
242 : :
243 : : static int
244 : 0 : setup_fib6(int socket)
245 : : {
246 : : struct ip6_lookup_fib_node_main *nm = &ip6_lookup_fib_nm;
247 : : struct rte_fib6_conf conf;
248 : : char s[RTE_FIB6_NAMESIZE];
249 : :
250 : : /* One fib6 per socket */
251 [ # # ]: 0 : if (nm->fib6[socket])
252 : : return 0;
253 : :
254 : 0 : conf.type = RTE_FIB6_TRIE;
255 : 0 : conf.default_nh = FIB6_DEFAULT_NH;
256 : 0 : conf.max_routes = FIB6_DEFAULT_MAX_ROUTES;
257 : 0 : conf.rib_ext_sz = 0;
258 : 0 : conf.trie.nh_sz = RTE_FIB6_TRIE_4B;
259 : 0 : conf.trie.num_tbl8 = FIB6_DEFAULT_NUM_TBL8;
260 : : snprintf(s, sizeof(s), "IPV6_LOOKUP_FIB_%u", socket);
261 : 0 : nm->fib6[socket] = rte_fib6_create(s, socket, &conf);
262 [ # # ]: 0 : if (nm->fib6[socket] == NULL)
263 : 0 : return -rte_errno;
264 : :
265 : : return 0;
266 : : }
267 : :
268 : : static int
269 : 0 : ip6_lookup_fib_node_init(const struct rte_graph *graph, struct rte_node *node)
270 : : {
271 : : int rc, dyn;
272 : :
273 : : RTE_BUILD_BUG_ON(sizeof(struct ip6_lookup_fib_node_ctx) > RTE_NODE_CTX_SZ);
274 : :
275 : 0 : dyn = rte_node_mbuf_dynfield_register();
276 [ # # ]: 0 : if (dyn < 0) {
277 : 0 : node_err("ip6_lookup_fib", "Failed to register mbuf dynfield, rc=%d",
278 : : -rte_errno);
279 : 0 : return -rte_errno;
280 : : }
281 : :
282 : 0 : rc = setup_fib6(graph->socket);
283 [ # # ]: 0 : if (rc) {
284 : 0 : node_err("ip6_lookup_fib", "Failed to setup fib6 for sock %u, rc=%d",
285 : : graph->socket, rc);
286 : 0 : return rc;
287 : : }
288 : :
289 : : /* Update socket's FIB and mbuf dyn priv1 offset in node ctx */
290 : 0 : IP6_LOOKUP_FIB_NODE(node->ctx) = ip6_lookup_fib_nm.fib6[graph->socket];
291 : 0 : IP6_LOOKUP_FIB_NODE_PRIV1_OFF(node->ctx) = dyn;
292 : :
293 : 0 : node_dbg("ip6_lookup_fib", "Initialized ip6_lookup_fib node");
294 : :
295 : 0 : return 0;
296 : : }
297 : :
298 : : static struct rte_node_xstats ip6_lookup_fib_xstats = {
299 : : .nb_xstats = 1,
300 : : .xstat_desc = {
301 : : [0] = "ip6_lookup_fib_error",
302 : : },
303 : : };
304 : :
305 : : static struct rte_node_register ip6_lookup_fib_node = {
306 : : .process = ip6_lookup_fib_node_process,
307 : : .name = "ip6_lookup_fib",
308 : :
309 : : .init = ip6_lookup_fib_node_init,
310 : : .xstats = &ip6_lookup_fib_xstats,
311 : :
312 : : .nb_edges = RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP + 1,
313 : : .next_nodes = {
314 : : [RTE_NODE_IP6_LOOKUP_NEXT_REWRITE] = "ip6_rewrite",
315 : : [RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP] = "pkt_drop",
316 : : },
317 : : };
318 : :
319 : 254 : RTE_NODE_REGISTER(ip6_lookup_fib_node);
|