fib: add FIB library
[dpdk.git] / lib / librte_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.h>
10 #include <rte_eal_memconfig.h>
11 #include <rte_errno.h>
12 #include <rte_malloc.h>
13 #include <rte_rwlock.h>
14 #include <rte_string_fns.h>
15 #include <rte_tailq.h>
16
17 #include <rte_rib.h>
18 #include <rte_fib.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 datastruct */
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 datastruct */
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         switch (conf->type) {
96         case RTE_FIB_DUMMY:
97                 fib->dp = fib;
98                 fib->lookup = dummy_lookup;
99                 fib->modify = dummy_modify;
100                 return 0;
101         default:
102                 return -EINVAL;
103         }
104         return 0;
105 }
106
107 int
108 rte_fib_add(struct rte_fib *fib, uint32_t ip, uint8_t depth, uint64_t next_hop)
109 {
110         if ((fib == NULL) || (fib->modify == NULL) ||
111                         (depth > RTE_FIB_MAXDEPTH))
112                 return -EINVAL;
113         return fib->modify(fib, ip, depth, next_hop, RTE_FIB_ADD);
114 }
115
116 int
117 rte_fib_delete(struct rte_fib *fib, uint32_t ip, uint8_t depth)
118 {
119         if ((fib == NULL) || (fib->modify == NULL) ||
120                         (depth > RTE_FIB_MAXDEPTH))
121                 return -EINVAL;
122         return fib->modify(fib, ip, depth, 0, RTE_FIB_DEL);
123 }
124
125 int
126 rte_fib_lookup_bulk(struct rte_fib *fib, uint32_t *ips,
127         uint64_t *next_hops, int n)
128 {
129         FIB_RETURN_IF_TRUE(((fib == NULL) || (ips == NULL) ||
130                 (next_hops == NULL) || (fib->lookup == NULL)), -EINVAL);
131
132         fib->lookup(fib->dp, ips, next_hops, n);
133         return 0;
134 }
135
136 struct rte_fib *
137 rte_fib_create(const char *name, int socket_id, struct rte_fib_conf *conf)
138 {
139         char mem_name[RTE_FIB_NAMESIZE];
140         int ret;
141         struct rte_fib *fib = NULL;
142         struct rte_rib *rib = NULL;
143         struct rte_tailq_entry *te;
144         struct rte_fib_list *fib_list;
145         struct rte_rib_conf rib_conf;
146
147         /* Check user arguments. */
148         if ((name == NULL) || (conf == NULL) || (conf->max_routes < 0) ||
149                         (conf->type >= RTE_FIB_TYPE_MAX)) {
150                 rte_errno = EINVAL;
151                 return NULL;
152         }
153
154         rib_conf.ext_sz = 0;
155         rib_conf.max_nodes = conf->max_routes * 2;
156
157         rib = rte_rib_create(name, socket_id, &rib_conf);
158         if (rib == NULL) {
159                 RTE_LOG(ERR, LPM,
160                         "Can not allocate RIB %s\n", name);
161                 return NULL;
162         }
163
164         snprintf(mem_name, sizeof(mem_name), "FIB_%s", name);
165         fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_list);
166
167         rte_mcfg_tailq_write_lock();
168
169         /* guarantee there's no existing */
170         TAILQ_FOREACH(te, fib_list, next) {
171                 fib = (struct rte_fib *)te->data;
172                 if (strncmp(name, fib->name, RTE_FIB_NAMESIZE) == 0)
173                         break;
174         }
175         fib = NULL;
176         if (te != NULL) {
177                 rte_errno = EEXIST;
178                 goto exit;
179         }
180
181         /* allocate tailq entry */
182         te = rte_zmalloc("FIB_TAILQ_ENTRY", sizeof(*te), 0);
183         if (te == NULL) {
184                 RTE_LOG(ERR, LPM,
185                         "Can not allocate tailq entry for FIB %s\n", name);
186                 rte_errno = ENOMEM;
187                 goto exit;
188         }
189
190         /* Allocate memory to store the FIB data structures. */
191         fib = rte_zmalloc_socket(mem_name,
192                 sizeof(struct rte_fib), RTE_CACHE_LINE_SIZE, socket_id);
193         if (fib == NULL) {
194                 RTE_LOG(ERR, LPM, "FIB %s memory allocation failed\n", name);
195                 rte_errno = ENOMEM;
196                 goto free_te;
197         }
198
199         rte_strlcpy(fib->name, name, sizeof(fib->name));
200         fib->rib = rib;
201         fib->type = conf->type;
202         fib->def_nh = conf->default_nh;
203         ret = init_dataplane(fib, socket_id, conf);
204         if (ret < 0) {
205                 RTE_LOG(ERR, LPM,
206                         "FIB dataplane struct %s memory allocation failed "
207                         "with err %d\n", name, ret);
208                 rte_errno = -ret;
209                 goto free_fib;
210         }
211
212         te->data = (void *)fib;
213         TAILQ_INSERT_TAIL(fib_list, te, next);
214
215         rte_mcfg_tailq_write_unlock();
216
217         return fib;
218
219 free_fib:
220         rte_free(fib);
221 free_te:
222         rte_free(te);
223 exit:
224         rte_mcfg_tailq_write_unlock();
225         rte_rib_free(rib);
226
227         return NULL;
228 }
229
230 struct rte_fib *
231 rte_fib_find_existing(const char *name)
232 {
233         struct rte_fib *fib = NULL;
234         struct rte_tailq_entry *te;
235         struct rte_fib_list *fib_list;
236
237         fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_list);
238
239         rte_mcfg_tailq_read_lock();
240         TAILQ_FOREACH(te, fib_list, next) {
241                 fib = (struct rte_fib *) te->data;
242                 if (strncmp(name, fib->name, RTE_FIB_NAMESIZE) == 0)
243                         break;
244         }
245         rte_mcfg_tailq_read_unlock();
246
247         if (te == NULL) {
248                 rte_errno = ENOENT;
249                 return NULL;
250         }
251
252         return fib;
253 }
254
255 static void
256 free_dataplane(struct rte_fib *fib)
257 {
258         switch (fib->type) {
259         case RTE_FIB_DUMMY:
260                 return;
261         default:
262                 return;
263         }
264 }
265
266 void
267 rte_fib_free(struct rte_fib *fib)
268 {
269         struct rte_tailq_entry *te;
270         struct rte_fib_list *fib_list;
271
272         if (fib == NULL)
273                 return;
274
275         fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_list);
276
277         rte_mcfg_tailq_write_lock();
278
279         /* find our tailq entry */
280         TAILQ_FOREACH(te, fib_list, next) {
281                 if (te->data == (void *)fib)
282                         break;
283         }
284         if (te != NULL)
285                 TAILQ_REMOVE(fib_list, te, next);
286
287         rte_mcfg_tailq_write_unlock();
288
289         free_dataplane(fib);
290         rte_rib_free(fib->rib);
291         rte_free(fib);
292         rte_free(te);
293 }
294
295 void *
296 rte_fib_get_dp(struct rte_fib *fib)
297 {
298         return (fib == NULL) ? NULL : fib->dp;
299 }
300
301 struct rte_rib *
302 rte_fib_get_rib(struct rte_fib *fib)
303 {
304         return (fib == NULL) ? NULL : fib->rib;
305 }