lpm: add const to lookup parameter
[dpdk.git] / lib / fib / rte_fib.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>
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
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
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
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
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
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
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 *
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 *
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
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
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 *
309 rte_fib_get_dp(struct rte_fib *fib)
310 {
311         return (fib == NULL) ? NULL : fib->dp;
312 }
313
314 struct rte_rib *
315 rte_fib_get_rib(struct rte_fib *fib)
316 {
317         return (fib == NULL) ? NULL : fib->rib;
318 }
319
320 int
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 }