1
2
3
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_tailq.h>
12#include <rte_errno.h>
13#include <rte_rwlock.h>
14#include <rte_malloc.h>
15#include <rte_string_fns.h>
16
17#include <rte_rib6.h>
18#include <rte_fib6.h>
19
20#include "trie.h"
21
22TAILQ_HEAD(rte_fib6_list, rte_tailq_entry);
23static struct rte_tailq_elem rte_fib6_tailq = {
24 .name = "RTE_FIB6",
25};
26EAL_REGISTER_TAILQ(rte_fib6_tailq)
27
28
29#define FIB6_NAMESIZE 64
30
31#if defined(RTE_LIBRTE_FIB_DEBUG)
32#define FIB6_RETURN_IF_TRUE(cond, retval) do { \
33 if (cond) \
34 return retval; \
35} while (0)
36#else
37#define FIB6_RETURN_IF_TRUE(cond, retval)
38#endif
39
40struct rte_fib6 {
41 char name[FIB6_NAMESIZE];
42 enum rte_fib6_type type;
43 struct rte_rib6 *rib;
44 void *dp;
45 rte_fib6_lookup_fn_t lookup;
46 rte_fib6_modify_fn_t modify;
47 uint64_t def_nh;
48};
49
50static void
51dummy_lookup(void *fib_p, uint8_t ips[][RTE_FIB6_IPV6_ADDR_SIZE],
52 uint64_t *next_hops, const unsigned int n)
53{
54 unsigned int i;
55 struct rte_fib6 *fib = fib_p;
56 struct rte_rib6_node *node;
57
58 for (i = 0; i < n; i++) {
59 node = rte_rib6_lookup(fib->rib, ips[i]);
60 if (node != NULL)
61 rte_rib6_get_nh(node, &next_hops[i]);
62 else
63 next_hops[i] = fib->def_nh;
64 }
65}
66
67static int
68dummy_modify(struct rte_fib6 *fib, const uint8_t ip[RTE_FIB6_IPV6_ADDR_SIZE],
69 uint8_t depth, uint64_t next_hop, int op)
70{
71 struct rte_rib6_node *node;
72 if ((fib == NULL) || (depth > RTE_FIB6_MAXDEPTH))
73 return -EINVAL;
74
75 node = rte_rib6_lookup_exact(fib->rib, ip, depth);
76
77 switch (op) {
78 case RTE_FIB6_ADD:
79 if (node == NULL)
80 node = rte_rib6_insert(fib->rib, ip, depth);
81 if (node == NULL)
82 return -rte_errno;
83 return rte_rib6_set_nh(node, next_hop);
84 case RTE_FIB6_DEL:
85 if (node == NULL)
86 return -ENOENT;
87 rte_rib6_remove(fib->rib, ip, depth);
88 return 0;
89 }
90 return -EINVAL;
91}
92
93static int
94init_dataplane(struct rte_fib6 *fib, __rte_unused int socket_id,
95 struct rte_fib6_conf *conf)
96{
97 char dp_name[sizeof(void *)];
98
99 snprintf(dp_name, sizeof(dp_name), "%p", fib);
100 switch (conf->type) {
101 case RTE_FIB6_DUMMY:
102 fib->dp = fib;
103 fib->lookup = dummy_lookup;
104 fib->modify = dummy_modify;
105 return 0;
106 case RTE_FIB6_TRIE:
107 fib->dp = trie_create(dp_name, socket_id, conf);
108 if (fib->dp == NULL)
109 return -rte_errno;
110 fib->lookup = trie_get_lookup_fn(fib->dp, RTE_FIB6_LOOKUP_DEFAULT);
111 fib->modify = trie_modify;
112 return 0;
113 default:
114 return -EINVAL;
115 }
116 return 0;
117}
118
119int
120rte_fib6_add(struct rte_fib6 *fib, const uint8_t ip[RTE_FIB6_IPV6_ADDR_SIZE],
121 uint8_t depth, uint64_t next_hop)
122{
123 if ((fib == NULL) || (ip == NULL) || (fib->modify == NULL) ||
124 (depth > RTE_FIB6_MAXDEPTH))
125 return -EINVAL;
126 return fib->modify(fib, ip, depth, next_hop, RTE_FIB6_ADD);
127}
128
129int
130rte_fib6_delete(struct rte_fib6 *fib, const uint8_t ip[RTE_FIB6_IPV6_ADDR_SIZE],
131 uint8_t depth)
132{
133 if ((fib == NULL) || (ip == NULL) || (fib->modify == NULL) ||
134 (depth > RTE_FIB6_MAXDEPTH))
135 return -EINVAL;
136 return fib->modify(fib, ip, depth, 0, RTE_FIB6_DEL);
137}
138
139int
140rte_fib6_lookup_bulk(struct rte_fib6 *fib,
141 uint8_t ips[][RTE_FIB6_IPV6_ADDR_SIZE],
142 uint64_t *next_hops, int n)
143{
144 FIB6_RETURN_IF_TRUE((fib == NULL) || (ips == NULL) ||
145 (next_hops == NULL) || (fib->lookup == NULL), -EINVAL);
146 fib->lookup(fib->dp, ips, next_hops, n);
147 return 0;
148}
149
150struct rte_fib6 *
151rte_fib6_create(const char *name, int socket_id, struct rte_fib6_conf *conf)
152{
153 char mem_name[FIB6_NAMESIZE];
154 int ret;
155 struct rte_fib6 *fib = NULL;
156 struct rte_rib6 *rib = NULL;
157 struct rte_tailq_entry *te;
158 struct rte_fib6_list *fib_list;
159 struct rte_rib6_conf rib_conf;
160
161
162 if ((name == NULL) || (conf == NULL) || (conf->max_routes < 0) ||
163 (conf->type > RTE_FIB6_TRIE)) {
164 rte_errno = EINVAL;
165 return NULL;
166 }
167
168 rib_conf.ext_sz = 0;
169 rib_conf.max_nodes = conf->max_routes * 2;
170
171 rib = rte_rib6_create(name, socket_id, &rib_conf);
172 if (rib == NULL) {
173 RTE_LOG(ERR, LPM,
174 "Can not allocate RIB %s\n", name);
175 return NULL;
176 }
177
178 snprintf(mem_name, sizeof(mem_name), "FIB6_%s", name);
179 fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list);
180
181 rte_mcfg_tailq_write_lock();
182
183
184 TAILQ_FOREACH(te, fib_list, next) {
185 fib = (struct rte_fib6 *)te->data;
186 if (strncmp(name, fib->name, FIB6_NAMESIZE) == 0)
187 break;
188 }
189 fib = NULL;
190 if (te != NULL) {
191 rte_errno = EEXIST;
192 goto exit;
193 }
194
195
196 te = rte_zmalloc("FIB_TAILQ_ENTRY", sizeof(*te), 0);
197 if (te == NULL) {
198 RTE_LOG(ERR, LPM,
199 "Can not allocate tailq entry for FIB %s\n", name);
200 rte_errno = ENOMEM;
201 goto exit;
202 }
203
204
205 fib = rte_zmalloc_socket(mem_name,
206 sizeof(struct rte_fib6), RTE_CACHE_LINE_SIZE, socket_id);
207 if (fib == NULL) {
208 RTE_LOG(ERR, LPM, "FIB %s memory allocation failed\n", name);
209 rte_errno = ENOMEM;
210 goto free_te;
211 }
212
213 rte_strlcpy(fib->name, name, sizeof(fib->name));
214 fib->rib = rib;
215 fib->type = conf->type;
216 fib->def_nh = conf->default_nh;
217 ret = init_dataplane(fib, socket_id, conf);
218 if (ret < 0) {
219 RTE_LOG(ERR, LPM,
220 "FIB dataplane struct %s memory allocation failed\n",
221 name);
222 rte_errno = -ret;
223 goto free_fib;
224 }
225
226 te->data = (void *)fib;
227 TAILQ_INSERT_TAIL(fib_list, te, next);
228
229 rte_mcfg_tailq_write_unlock();
230
231 return fib;
232
233free_fib:
234 rte_free(fib);
235free_te:
236 rte_free(te);
237exit:
238 rte_mcfg_tailq_write_unlock();
239 rte_rib6_free(rib);
240
241 return NULL;
242}
243
244struct rte_fib6 *
245rte_fib6_find_existing(const char *name)
246{
247 struct rte_fib6 *fib = NULL;
248 struct rte_tailq_entry *te;
249 struct rte_fib6_list *fib_list;
250
251 fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list);
252
253 rte_mcfg_tailq_read_lock();
254 TAILQ_FOREACH(te, fib_list, next) {
255 fib = (struct rte_fib6 *) te->data;
256 if (strncmp(name, fib->name, FIB6_NAMESIZE) == 0)
257 break;
258 }
259 rte_mcfg_tailq_read_unlock();
260
261 if (te == NULL) {
262 rte_errno = ENOENT;
263 return NULL;
264 }
265
266 return fib;
267}
268
269static void
270free_dataplane(struct rte_fib6 *fib)
271{
272 switch (fib->type) {
273 case RTE_FIB6_DUMMY:
274 return;
275 case RTE_FIB6_TRIE:
276 trie_free(fib->dp);
277 default:
278 return;
279 }
280}
281
282void
283rte_fib6_free(struct rte_fib6 *fib)
284{
285 struct rte_tailq_entry *te;
286 struct rte_fib6_list *fib_list;
287
288 if (fib == NULL)
289 return;
290
291 fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list);
292
293 rte_mcfg_tailq_write_lock();
294
295
296 TAILQ_FOREACH(te, fib_list, next) {
297 if (te->data == (void *)fib)
298 break;
299 }
300 if (te != NULL)
301 TAILQ_REMOVE(fib_list, te, next);
302
303 rte_mcfg_tailq_write_unlock();
304
305 free_dataplane(fib);
306 rte_rib6_free(fib->rib);
307 rte_free(fib);
308 rte_free(te);
309}
310
311void *
312rte_fib6_get_dp(struct rte_fib6 *fib)
313{
314 return (fib == NULL) ? NULL : fib->dp;
315}
316
317struct rte_rib6 *
318rte_fib6_get_rib(struct rte_fib6 *fib)
319{
320 return (fib == NULL) ? NULL : fib->rib;
321}
322
323int
324rte_fib6_select_lookup(struct rte_fib6 *fib,
325 enum rte_fib6_lookup_type type)
326{
327 rte_fib6_lookup_fn_t fn;
328
329 switch (fib->type) {
330 case RTE_FIB6_TRIE:
331 fn = trie_get_lookup_fn(fib->dp, type);
332 if (fn == NULL)
333 return -EINVAL;
334 fib->lookup = fn;
335 return 0;
336 default:
337 return -EINVAL;
338 }
339}
340