1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Vladimir Medvedkin <[email protected]>
3 * Copyright(c) 2019 Intel Corporation
4 */
5
6 #include <stdint.h>
7 #include <string.h>
8
9 #include <rte_eal_memconfig.h>
10 #include <rte_errno.h>
11 #include <rte_malloc.h>
12 #include <rte_string_fns.h>
13 #include <rte_tailq.h>
14
15 #include <rte_rib.h>
16 #include <rte_fib.h>
17
18 #include "dir24_8.h"
19
20 TAILQ_HEAD(rte_fib_list, rte_tailq_entry);
21 static struct rte_tailq_elem rte_fib_tailq = {
22 .name = "RTE_FIB",
23 };
24 EAL_REGISTER_TAILQ(rte_fib_tailq)
25
26 /* Maximum length of a FIB name. */
27 #define RTE_FIB_NAMESIZE 64
28
29 #if defined(RTE_LIBRTE_FIB_DEBUG)
30 #define FIB_RETURN_IF_TRUE(cond, retval) do { \
31 if (cond) \
32 return retval; \
33 } while (0)
34 #else
35 #define FIB_RETURN_IF_TRUE(cond, retval)
36 #endif
37
38 struct rte_fib {
39 char name[RTE_FIB_NAMESIZE];
40 enum rte_fib_type type; /**< Type of FIB struct */
41 struct rte_rib *rib; /**< RIB helper datastructure */
42 void *dp; /**< pointer to the dataplane struct*/
43 rte_fib_lookup_fn_t lookup; /**< FIB lookup function */
44 rte_fib_modify_fn_t modify; /**< modify FIB datastructure */
45 uint64_t def_nh;
46 };
47
48 static void
dummy_lookup(void * fib_p,const uint32_t * ips,uint64_t * next_hops,const unsigned int n)49 dummy_lookup(void *fib_p, const uint32_t *ips, uint64_t *next_hops,
50 const unsigned int n)
51 {
52 unsigned int i;
53 struct rte_fib *fib = fib_p;
54 struct rte_rib_node *node;
55
56 for (i = 0; i < n; i++) {
57 node = rte_rib_lookup(fib->rib, ips[i]);
58 if (node != NULL)
59 rte_rib_get_nh(node, &next_hops[i]);
60 else
61 next_hops[i] = fib->def_nh;
62 }
63 }
64
65 static int
dummy_modify(struct rte_fib * fib,uint32_t ip,uint8_t depth,uint64_t next_hop,int op)66 dummy_modify(struct rte_fib *fib, uint32_t ip, uint8_t depth,
67 uint64_t next_hop, int op)
68 {
69 struct rte_rib_node *node;
70 if ((fib == NULL) || (depth > RTE_FIB_MAXDEPTH))
71 return -EINVAL;
72
73 node = rte_rib_lookup_exact(fib->rib, ip, depth);
74
75 switch (op) {
76 case RTE_FIB_ADD:
77 if (node == NULL)
78 node = rte_rib_insert(fib->rib, ip, depth);
79 if (node == NULL)
80 return -rte_errno;
81 return rte_rib_set_nh(node, next_hop);
82 case RTE_FIB_DEL:
83 if (node == NULL)
84 return -ENOENT;
85 rte_rib_remove(fib->rib, ip, depth);
86 return 0;
87 }
88 return -EINVAL;
89 }
90
91 static int
init_dataplane(struct rte_fib * fib,__rte_unused int socket_id,struct rte_fib_conf * conf)92 init_dataplane(struct rte_fib *fib, __rte_unused int socket_id,
93 struct rte_fib_conf *conf)
94 {
95 char dp_name[sizeof(void *)];
96
97 snprintf(dp_name, sizeof(dp_name), "%p", fib);
98 switch (conf->type) {
99 case RTE_FIB_DUMMY:
100 fib->dp = fib;
101 fib->lookup = dummy_lookup;
102 fib->modify = dummy_modify;
103 return 0;
104 case RTE_FIB_DIR24_8:
105 fib->dp = dir24_8_create(dp_name, socket_id, conf);
106 if (fib->dp == NULL)
107 return -rte_errno;
108 fib->lookup = dir24_8_get_lookup_fn(fib->dp,
109 RTE_FIB_LOOKUP_DEFAULT);
110 fib->modify = dir24_8_modify;
111 return 0;
112 default:
113 return -EINVAL;
114 }
115 return 0;
116 }
117
118 int
rte_fib_add(struct rte_fib * fib,uint32_t ip,uint8_t depth,uint64_t next_hop)119 rte_fib_add(struct rte_fib *fib, uint32_t ip, uint8_t depth, uint64_t next_hop)
120 {
121 if ((fib == NULL) || (fib->modify == NULL) ||
122 (depth > RTE_FIB_MAXDEPTH))
123 return -EINVAL;
124 return fib->modify(fib, ip, depth, next_hop, RTE_FIB_ADD);
125 }
126
127 int
rte_fib_delete(struct rte_fib * fib,uint32_t ip,uint8_t depth)128 rte_fib_delete(struct rte_fib *fib, uint32_t ip, uint8_t depth)
129 {
130 if ((fib == NULL) || (fib->modify == NULL) ||
131 (depth > RTE_FIB_MAXDEPTH))
132 return -EINVAL;
133 return fib->modify(fib, ip, depth, 0, RTE_FIB_DEL);
134 }
135
136 int
rte_fib_lookup_bulk(struct rte_fib * fib,uint32_t * ips,uint64_t * next_hops,int n)137 rte_fib_lookup_bulk(struct rte_fib *fib, uint32_t *ips,
138 uint64_t *next_hops, int n)
139 {
140 FIB_RETURN_IF_TRUE(((fib == NULL) || (ips == NULL) ||
141 (next_hops == NULL) || (fib->lookup == NULL)), -EINVAL);
142
143 fib->lookup(fib->dp, ips, next_hops, n);
144 return 0;
145 }
146
147 struct rte_fib *
rte_fib_create(const char * name,int socket_id,struct rte_fib_conf * conf)148 rte_fib_create(const char *name, int socket_id, struct rte_fib_conf *conf)
149 {
150 char mem_name[RTE_FIB_NAMESIZE];
151 int ret;
152 struct rte_fib *fib = NULL;
153 struct rte_rib *rib = NULL;
154 struct rte_tailq_entry *te;
155 struct rte_fib_list *fib_list;
156 struct rte_rib_conf rib_conf;
157
158 /* Check user arguments. */
159 if ((name == NULL) || (conf == NULL) || (conf->max_routes < 0) ||
160 (conf->type > RTE_FIB_DIR24_8)) {
161 rte_errno = EINVAL;
162 return NULL;
163 }
164
165 rib_conf.ext_sz = conf->rib_ext_sz;
166 rib_conf.max_nodes = conf->max_routes * 2;
167
168 rib = rte_rib_create(name, socket_id, &rib_conf);
169 if (rib == NULL) {
170 RTE_LOG(ERR, LPM,
171 "Can not allocate RIB %s\n", name);
172 return NULL;
173 }
174
175 snprintf(mem_name, sizeof(mem_name), "FIB_%s", name);
176 fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_list);
177
178 rte_mcfg_tailq_write_lock();
179
180 /* guarantee there's no existing */
181 TAILQ_FOREACH(te, fib_list, next) {
182 fib = (struct rte_fib *)te->data;
183 if (strncmp(name, fib->name, RTE_FIB_NAMESIZE) == 0)
184 break;
185 }
186 fib = NULL;
187 if (te != NULL) {
188 rte_errno = EEXIST;
189 goto exit;
190 }
191
192 /* allocate tailq entry */
193 te = rte_zmalloc("FIB_TAILQ_ENTRY", sizeof(*te), 0);
194 if (te == NULL) {
195 RTE_LOG(ERR, LPM,
196 "Can not allocate tailq entry for FIB %s\n", name);
197 rte_errno = ENOMEM;
198 goto exit;
199 }
200
201 /* Allocate memory to store the FIB data structures. */
202 fib = rte_zmalloc_socket(mem_name,
203 sizeof(struct rte_fib), RTE_CACHE_LINE_SIZE, socket_id);
204 if (fib == NULL) {
205 RTE_LOG(ERR, LPM, "FIB %s memory allocation failed\n", name);
206 rte_errno = ENOMEM;
207 goto free_te;
208 }
209
210 rte_strlcpy(fib->name, name, sizeof(fib->name));
211 fib->rib = rib;
212 fib->type = conf->type;
213 fib->def_nh = conf->default_nh;
214 ret = init_dataplane(fib, socket_id, conf);
215 if (ret < 0) {
216 RTE_LOG(ERR, LPM,
217 "FIB dataplane struct %s memory allocation failed "
218 "with err %d\n", name, ret);
219 rte_errno = -ret;
220 goto free_fib;
221 }
222
223 te->data = (void *)fib;
224 TAILQ_INSERT_TAIL(fib_list, te, next);
225
226 rte_mcfg_tailq_write_unlock();
227
228 return fib;
229
230 free_fib:
231 rte_free(fib);
232 free_te:
233 rte_free(te);
234 exit:
235 rte_mcfg_tailq_write_unlock();
236 rte_rib_free(rib);
237
238 return NULL;
239 }
240
241 struct rte_fib *
rte_fib_find_existing(const char * name)242 rte_fib_find_existing(const char *name)
243 {
244 struct rte_fib *fib = NULL;
245 struct rte_tailq_entry *te;
246 struct rte_fib_list *fib_list;
247
248 fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_list);
249
250 rte_mcfg_tailq_read_lock();
251 TAILQ_FOREACH(te, fib_list, next) {
252 fib = (struct rte_fib *) te->data;
253 if (strncmp(name, fib->name, RTE_FIB_NAMESIZE) == 0)
254 break;
255 }
256 rte_mcfg_tailq_read_unlock();
257
258 if (te == NULL) {
259 rte_errno = ENOENT;
260 return NULL;
261 }
262
263 return fib;
264 }
265
266 static void
free_dataplane(struct rte_fib * fib)267 free_dataplane(struct rte_fib *fib)
268 {
269 switch (fib->type) {
270 case RTE_FIB_DUMMY:
271 return;
272 case RTE_FIB_DIR24_8:
273 dir24_8_free(fib->dp);
274 default:
275 return;
276 }
277 }
278
279 void
rte_fib_free(struct rte_fib * fib)280 rte_fib_free(struct rte_fib *fib)
281 {
282 struct rte_tailq_entry *te;
283 struct rte_fib_list *fib_list;
284
285 if (fib == NULL)
286 return;
287
288 fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_list);
289
290 rte_mcfg_tailq_write_lock();
291
292 /* find our tailq entry */
293 TAILQ_FOREACH(te, fib_list, next) {
294 if (te->data == (void *)fib)
295 break;
296 }
297 if (te != NULL)
298 TAILQ_REMOVE(fib_list, te, next);
299
300 rte_mcfg_tailq_write_unlock();
301
302 free_dataplane(fib);
303 rte_rib_free(fib->rib);
304 rte_free(fib);
305 rte_free(te);
306 }
307
308 void *
rte_fib_get_dp(struct rte_fib * fib)309 rte_fib_get_dp(struct rte_fib *fib)
310 {
311 return (fib == NULL) ? NULL : fib->dp;
312 }
313
314 struct rte_rib *
rte_fib_get_rib(struct rte_fib * fib)315 rte_fib_get_rib(struct rte_fib *fib)
316 {
317 return (fib == NULL) ? NULL : fib->rib;
318 }
319
320 int
rte_fib_select_lookup(struct rte_fib * fib,enum rte_fib_lookup_type type)321 rte_fib_select_lookup(struct rte_fib *fib,
322 enum rte_fib_lookup_type type)
323 {
324 rte_fib_lookup_fn_t fn;
325
326 switch (fib->type) {
327 case RTE_FIB_DIR24_8:
328 fn = dir24_8_get_lookup_fn(fib->dp, type);
329 if (fn == NULL)
330 return -EINVAL;
331 fib->lookup = fn;
332 return 0;
333 default:
334 return -EINVAL;
335 }
336 }
337