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_fib.h>
11 : : #include <rte_graph.h>
12 : : #include <rte_graph_worker.h>
13 : : #include <rte_ip.h>
14 : :
15 : : #include "rte_node_ip4_api.h"
16 : :
17 : : #include "node_private.h"
18 : :
19 : : /* IP4 Lookup global data struct */
20 : : struct ip4_lookup_fib_node_main {
21 : : struct rte_fib *fib[RTE_MAX_NUMA_NODES];
22 : : };
23 : :
24 : : struct ip4_lookup_fib_node_ctx {
25 : : /* Socket's FIB */
26 : : struct rte_fib *fib;
27 : : /* Dynamic offset to mbuf priv1 */
28 : : int mbuf_priv1_off;
29 : : };
30 : :
31 : : static struct ip4_lookup_fib_node_main ip4_lookup_fib_nm;
32 : :
33 : : #define FIB_DEFAULT_MAX_ROUTES (UINT16_MAX)
34 : : #define FIB_DEFAULT_NUM_TBL8 (UINT16_MAX / 2)
35 : : #define FIB_DEFAULT_NH (RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP << 16)
36 : :
37 : : #define IP4_LOOKUP_NODE_FIB(ctx) \
38 : : (((struct ip4_lookup_fib_node_ctx *)ctx)->fib)
39 : :
40 : : #define IP4_LOOKUP_FIB_NODE_PRIV1_OFF(ctx) \
41 : : (((struct ip4_lookup_fib_node_ctx *)ctx)->mbuf_priv1_off)
42 : :
43 : : static uint16_t
44 : 0 : ip4_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 = IP4_LOOKUP_FIB_NODE_PRIV1_OFF(node->ctx);
49 : 0 : struct rte_fib *fib = IP4_LOOKUP_NODE_FIB(node->ctx);
50 : : uint64_t next_hop[RTE_GRAPH_BURST_SIZE];
51 : : uint32_t ip[RTE_GRAPH_BURST_SIZE];
52 : : struct rte_ipv4_hdr *ipv4_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_IP4_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 : ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv4_hdr *,
107 : : sizeof(struct rte_ether_hdr));
108 : : /* Extract cksum, ttl as ipv4 hdr is in cache */
109 [ # # ]: 0 : node_mbuf_priv1(mbuf0, dyn)->cksum = ipv4_hdr->hdr_checksum;
110 : 0 : node_mbuf_priv1(mbuf0, dyn)->ttl = ipv4_hdr->time_to_live;
111 : :
112 [ # # ]: 0 : ip[i++] = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
113 : :
114 : : /* Extract DIP of mbuf1 */
115 : 0 : ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf1, struct rte_ipv4_hdr *,
116 : : sizeof(struct rte_ether_hdr));
117 : : /* Extract cksum, ttl as ipv4 hdr is in cache */
118 [ # # ]: 0 : node_mbuf_priv1(mbuf1, dyn)->cksum = ipv4_hdr->hdr_checksum;
119 : 0 : node_mbuf_priv1(mbuf1, dyn)->ttl = ipv4_hdr->time_to_live;
120 : :
121 [ # # ]: 0 : ip[i++] = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
122 : :
123 : : /* Extract DIP of mbuf2 */
124 : 0 : ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf2, struct rte_ipv4_hdr *,
125 : : sizeof(struct rte_ether_hdr));
126 : : /* Extract cksum, ttl as ipv4 hdr is in cache */
127 [ # # # # ]: 0 : node_mbuf_priv1(mbuf2, dyn)->cksum = ipv4_hdr->hdr_checksum;
128 : 0 : node_mbuf_priv1(mbuf2, dyn)->ttl = ipv4_hdr->time_to_live;
129 : :
130 [ # # ]: 0 : ip[i++] = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
131 : :
132 : : /* Extract DIP of mbuf3 */
133 : 0 : ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf3, struct rte_ipv4_hdr *,
134 : : sizeof(struct rte_ether_hdr));
135 : :
136 : : /* Extract cksum, ttl as ipv4 hdr is in cache */
137 [ # # ]: 0 : node_mbuf_priv1(mbuf3, dyn)->cksum = ipv4_hdr->hdr_checksum;
138 : 0 : node_mbuf_priv1(mbuf3, dyn)->ttl = ipv4_hdr->time_to_live;
139 : :
140 [ # # ]: 0 : ip[i++] = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
141 : : }
142 [ # # ]: 0 : while (n_left_from > 0) {
143 : 0 : mbuf0 = pkts[0];
144 : 0 : pkts += 1;
145 : 0 : n_left_from -= 1;
146 : :
147 : : /* Extract DIP of mbuf0 */
148 : 0 : ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv4_hdr *,
149 : : sizeof(struct rte_ether_hdr));
150 : : /* Extract cksum, ttl as ipv4 hdr is in cache */
151 [ # # ]: 0 : node_mbuf_priv1(mbuf0, dyn)->cksum = ipv4_hdr->hdr_checksum;
152 : 0 : node_mbuf_priv1(mbuf0, dyn)->ttl = ipv4_hdr->time_to_live;
153 : :
154 [ # # ]: 0 : ip[i++] = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
155 : : }
156 : :
157 : 0 : rte_fib_lookup_bulk(fib, ip, next_hop, nb_objs);
158 : :
159 [ # # ]: 0 : for (i = 0; i < nb_objs; i++) {
160 : 0 : mbuf0 = (struct rte_mbuf *)objs[i];
161 [ # # ]: 0 : node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop[i];
162 : 0 : next = (uint16_t)(next_hop[i] >> 16);
163 : :
164 [ # # ]: 0 : if (unlikely(next_index ^ next)) {
165 : : /* Copy things successfully speculated till now */
166 [ # # ]: 0 : rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
167 : 0 : from += last_spec;
168 : 0 : to_next += last_spec;
169 : 0 : held += last_spec;
170 : : last_spec = 0;
171 : :
172 : 0 : rte_node_enqueue_x1(graph, node, next, from[0]);
173 : 0 : from += 1;
174 : : } else {
175 : 0 : last_spec += 1;
176 : : }
177 : :
178 [ # # ]: 0 : if (unlikely(next_hop[i] == FIB_DEFAULT_NH))
179 : 0 : lookup_err += 1;
180 : : }
181 : :
182 : : /* !!! Home run !!! */
183 [ # # ]: 0 : if (likely(last_spec == nb_objs)) {
184 : 0 : rte_node_next_stream_move(graph, node, next_index);
185 : 0 : return nb_objs;
186 : : }
187 : :
188 [ # # ]: 0 : NODE_INCREMENT_XSTAT_ID(node, 0, lookup_err != 0, lookup_err);
189 : 0 : held += last_spec;
190 [ # # ]: 0 : rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
191 : : rte_node_next_stream_put(graph, node, next_index, held);
192 : :
193 : : return nb_objs;
194 : : }
195 : :
196 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_node_ip4_fib_create, 25.07)
197 : : int
198 : 0 : rte_node_ip4_fib_create(int socket, struct rte_fib_conf *conf)
199 : : {
200 : : struct ip4_lookup_fib_node_main *nm = &ip4_lookup_fib_nm;
201 : : char s[RTE_FIB_NAMESIZE];
202 : :
203 : : /* One fib per socket */
204 [ # # ]: 0 : if (nm->fib[socket])
205 : : return 0;
206 : :
207 : 0 : conf->default_nh = FIB_DEFAULT_NH;
208 : : snprintf(s, sizeof(s), "IPV4_LOOKUP_FIB_%d", socket);
209 : 0 : nm->fib[socket] = rte_fib_create(s, socket, conf);
210 [ # # ]: 0 : if (nm->fib[socket] == NULL)
211 : 0 : return -rte_errno;
212 : :
213 : : return 0;
214 : : }
215 : :
216 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_node_ip4_fib_route_add, 25.07)
217 : : int
218 : 0 : rte_node_ip4_fib_route_add(uint32_t ip, uint8_t depth, uint16_t next_hop,
219 : : enum rte_node_ip4_lookup_next next_node)
220 : : {
221 : : char abuf[INET6_ADDRSTRLEN];
222 : : unsigned int nb_sockets;
223 : : struct in_addr in;
224 : : uint8_t socket;
225 : : uint32_t val;
226 : : int ret;
227 : :
228 : 0 : nb_sockets = rte_socket_count();
229 : 0 : in.s_addr = htonl(ip);
230 : 0 : inet_ntop(AF_INET, &in, abuf, sizeof(abuf));
231 : : /* Embedded next node id into 24 bit next hop */
232 : 0 : val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1);
233 : 0 : node_dbg("ip4_lookup_fib", "FIB: Adding route %s / %d nh (0x%x)", abuf, depth, val);
234 : :
235 [ # # ]: 0 : for (socket = 0; socket < nb_sockets; socket++) {
236 [ # # ]: 0 : if (!ip4_lookup_fib_nm.fib[socket])
237 : 0 : continue;
238 : :
239 : 0 : ret = rte_fib_add(ip4_lookup_fib_nm.fib[socket], ip, depth, val);
240 [ # # ]: 0 : if (ret < 0) {
241 : 0 : node_err("ip4_lookup_fib",
242 : : "Unable to add entry %s / %d nh (%x) to FIB on sock %d, rc=%d",
243 : : abuf, depth, val, socket, ret);
244 : 0 : return ret;
245 : : }
246 : : }
247 : :
248 : : return 0;
249 : : }
250 : :
251 : : static int
252 : 0 : setup_fib(int socket)
253 : : {
254 : : struct ip4_lookup_fib_node_main *nm = &ip4_lookup_fib_nm;
255 : : struct rte_fib_conf conf;
256 : : char s[RTE_FIB_NAMESIZE];
257 : :
258 : : /* One fib per socket */
259 [ # # ]: 0 : if (nm->fib[socket])
260 : : return 0;
261 : :
262 : 0 : conf.type = RTE_FIB_DIR24_8;
263 : 0 : conf.default_nh = FIB_DEFAULT_NH;
264 : 0 : conf.max_routes = FIB_DEFAULT_MAX_ROUTES;
265 : 0 : conf.rib_ext_sz = 0;
266 : 0 : conf.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B;
267 : 0 : conf.dir24_8.num_tbl8 = FIB_DEFAULT_NUM_TBL8;
268 : 0 : conf.flags = 0;
269 : : snprintf(s, sizeof(s), "IPV4_LOOKUP_FIB_%d", socket);
270 : 0 : nm->fib[socket] = rte_fib_create(s, socket, &conf);
271 [ # # ]: 0 : if (nm->fib[socket] == NULL)
272 : 0 : return -rte_errno;
273 : :
274 : : return 0;
275 : : }
276 : :
277 : : static int
278 : 0 : ip4_lookup_fib_node_init(const struct rte_graph *graph, struct rte_node *node)
279 : : {
280 : : int rc, dyn;
281 : :
282 : : RTE_BUILD_BUG_ON(sizeof(struct ip4_lookup_fib_node_ctx) > RTE_NODE_CTX_SZ);
283 : :
284 : 0 : dyn = rte_node_mbuf_dynfield_register();
285 [ # # ]: 0 : if (dyn < 0) {
286 : 0 : node_err("ip4_lookup_fib", "Failed to register mbuf dynfield, rc=%d",
287 : : -rte_errno);
288 : 0 : return -rte_errno;
289 : : }
290 : :
291 : 0 : rc = setup_fib(graph->socket);
292 [ # # ]: 0 : if (rc) {
293 : 0 : node_err("ip4_lookup_fib", "Failed to setup fib for sock %u, rc=%d",
294 : : graph->socket, rc);
295 : 0 : return rc;
296 : : }
297 : :
298 : : /* Update socket's FIB and mbuf dyn priv1 offset in node ctx */
299 : 0 : IP4_LOOKUP_NODE_FIB(node->ctx) = ip4_lookup_fib_nm.fib[graph->socket];
300 : 0 : IP4_LOOKUP_FIB_NODE_PRIV1_OFF(node->ctx) = dyn;
301 : :
302 : 0 : node_dbg("ip4_lookup_fib", "Initialized ip4_lookup_fib node");
303 : :
304 : 0 : return 0;
305 : : }
306 : :
307 : : static struct rte_node_xstats ip4_lookup_fib_xstats = {
308 : : .nb_xstats = 1,
309 : : .xstat_desc = {
310 : : [0] = "ip4_lookup_fib_error",
311 : : },
312 : : };
313 : :
314 : : static struct rte_node_register ip4_lookup_fib_node = {
315 : : .process = ip4_lookup_fib_node_process,
316 : : .name = "ip4_lookup_fib",
317 : :
318 : : .init = ip4_lookup_fib_node_init,
319 : : .xstats = &ip4_lookup_fib_xstats,
320 : :
321 : : .nb_edges = RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP + 1,
322 : : .next_nodes = {
323 : : [RTE_NODE_IP4_LOOKUP_NEXT_IP4_LOCAL] = "ip4_local",
324 : : [RTE_NODE_IP4_LOOKUP_NEXT_REWRITE] = "ip4_rewrite",
325 : : [RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP] = "pkt_drop",
326 : : },
327 : : };
328 : :
329 : 254 : RTE_NODE_REGISTER(ip4_lookup_fib_node);
|