Branch data Line data Source code
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 <stdbool.h>
7 : : #include <stdint.h>
8 : : #include <sys/queue.h>
9 : :
10 : : #include <eal_export.h>
11 : : #include <rte_eal_memconfig.h>
12 : : #include <rte_errno.h>
13 : : #include <rte_log.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_mempool.h>
16 : : #include <rte_string_fns.h>
17 : : #include <rte_tailq.h>
18 : :
19 : : #include <rte_rib6.h>
20 : :
21 : : #include "rib_log.h"
22 : :
23 : : #define RTE_RIB_VALID_NODE 1
24 : : /* Maximum length of a RIB6 name. */
25 : : #define RTE_RIB6_NAMESIZE 64
26 : :
27 : : TAILQ_HEAD(rte_rib6_list, rte_tailq_entry);
28 : : static struct rte_tailq_elem rte_rib6_tailq = {
29 : : .name = "RTE_RIB6",
30 : : };
31 [ - + ]: 252 : EAL_REGISTER_TAILQ(rte_rib6_tailq)
32 : :
33 : : struct rte_rib6_node {
34 : : struct rte_rib6_node *left;
35 : : struct rte_rib6_node *right;
36 : : struct rte_rib6_node *parent;
37 : : uint64_t nh;
38 : : struct rte_ipv6_addr ip;
39 : : uint8_t depth;
40 : : uint8_t flag;
41 : : uint64_t ext[];
42 : : };
43 : :
44 : : struct rte_rib6 {
45 : : char name[RTE_RIB6_NAMESIZE];
46 : : struct rte_rib6_node *tree;
47 : : struct rte_mempool *node_pool;
48 : : uint32_t cur_nodes;
49 : : uint32_t cur_routes;
50 : : int max_nodes;
51 : : };
52 : :
53 : : static inline bool
54 : : is_valid_node(const struct rte_rib6_node *node)
55 : : {
56 : 2131705 : return (node->flag & RTE_RIB_VALID_NODE) == RTE_RIB_VALID_NODE;
57 : : }
58 : :
59 : : static inline bool
60 : : is_right_node(const struct rte_rib6_node *node)
61 : : {
62 : 762 : return node->parent->right == node;
63 : : }
64 : :
65 : : static inline int
66 : : get_dir(const struct rte_ipv6_addr *ip, uint8_t depth)
67 : : {
68 : : uint8_t index, msk;
69 : :
70 : : /*
71 : : * depth & 127 clamps depth to values that will not
72 : : * read off the end of ip.
73 : : * depth is the number of bits deep into ip to traverse, and
74 : : * is incremented in blocks of 8 (1 byte). This means the last
75 : : * 3 bits are irrelevant to what the index of ip should be.
76 : : */
77 : 2379053 : index = (depth & INT8_MAX) / CHAR_BIT;
78 : :
79 : : /*
80 : : * msk is the bitmask used to extract the bit used to decide the
81 : : * direction of the next step of the binary search.
82 : : */
83 : 2379053 : msk = 1 << (7 - (depth & 7));
84 : :
85 : 2379053 : return (ip->a[index] & msk) != 0;
86 : : }
87 : :
88 : : static inline struct rte_rib6_node *
89 : : get_nxt_node(struct rte_rib6_node *node,
90 : : const struct rte_ipv6_addr *ip)
91 : : {
92 [ + - + - : 2346294 : if (node->depth == RTE_IPV6_MAX_DEPTH)
+ + ]
93 : : return NULL;
94 : :
95 [ + + - + : 2346032 : return (get_dir(ip, node->depth)) ? node->right : node->left;
+ + ]
96 : : }
97 : :
98 : : static struct rte_rib6_node *
99 : 1030 : node_alloc(struct rte_rib6 *rib)
100 : : {
101 : : struct rte_rib6_node *ent;
102 : : int ret;
103 : :
104 [ - + ]: 1030 : ret = rte_mempool_get(rib->node_pool, (void *)&ent);
105 [ + - ]: 1030 : if (unlikely(ret != 0))
106 : : return NULL;
107 : 1030 : ++rib->cur_nodes;
108 : 1030 : return ent;
109 : : }
110 : :
111 : : static void
112 : 1025 : node_free(struct rte_rib6 *rib, struct rte_rib6_node *ent)
113 : : {
114 : 1025 : --rib->cur_nodes;
115 [ - + ]: 1025 : rte_mempool_put(rib->node_pool, ent);
116 : 1025 : }
117 : :
118 : : RTE_EXPORT_SYMBOL(rte_rib6_lookup)
119 : : struct rte_rib6_node *
120 : 66302 : rte_rib6_lookup(struct rte_rib6 *rib,
121 : : const struct rte_ipv6_addr *ip)
122 : : {
123 : : struct rte_rib6_node *cur;
124 : : struct rte_rib6_node *prev = NULL;
125 : :
126 [ - + ]: 66302 : if (unlikely(rib == NULL)) {
127 : 0 : rte_errno = EINVAL;
128 : 0 : return NULL;
129 : : }
130 : 66302 : cur = rib->tree;
131 : :
132 [ + + + + ]: 2188851 : while ((cur != NULL) && rte_ipv6_addr_eq_prefix(ip, &cur->ip, cur->depth)) {
133 [ + - ]: 2122549 : if (is_valid_node(cur))
134 : : prev = cur;
135 : : cur = get_nxt_node(cur, ip);
136 : : }
137 : : return prev;
138 : : }
139 : :
140 : : RTE_EXPORT_SYMBOL(rte_rib6_lookup_parent)
141 : : struct rte_rib6_node *
142 : 1536 : rte_rib6_lookup_parent(struct rte_rib6_node *ent)
143 : : {
144 : : struct rte_rib6_node *tmp;
145 : :
146 [ + - ]: 1536 : if (ent == NULL)
147 : : return NULL;
148 : :
149 : 1536 : tmp = ent->parent;
150 [ + + - + ]: 1536 : while ((tmp != NULL) && (!is_valid_node(tmp)))
151 : 0 : tmp = tmp->parent;
152 : :
153 : : return tmp;
154 : : }
155 : :
156 : : RTE_EXPORT_SYMBOL(rte_rib6_lookup_exact)
157 : : struct rte_rib6_node *
158 : 4105 : rte_rib6_lookup_exact(struct rte_rib6 *rib,
159 : : const struct rte_ipv6_addr *ip, uint8_t depth)
160 : : {
161 : : struct rte_rib6_node *cur;
162 : : struct rte_ipv6_addr tmp_ip;
163 : :
164 [ + - - + ]: 4105 : if (unlikely(rib == NULL || ip == NULL || depth > RTE_IPV6_MAX_DEPTH)) {
165 : 0 : rte_errno = EINVAL;
166 : 0 : return NULL;
167 : : }
168 : 4105 : cur = rib->tree;
169 : :
170 [ + + ]: 4105 : tmp_ip = *ip;
171 : : rte_ipv6_addr_mask(&tmp_ip, depth);
172 : :
173 [ + + ]: 134153 : while (cur != NULL) {
174 [ + + ]: 133116 : if (rte_ipv6_addr_eq(&cur->ip, &tmp_ip) &&
175 [ + + + - ]: 133115 : (cur->depth == depth) &&
176 : : is_valid_node(cur))
177 : 2051 : return cur;
178 : :
179 [ + + + + ]: 131065 : if (!rte_ipv6_addr_eq_prefix(&tmp_ip, &cur->ip, cur->depth) ||
180 : : (cur->depth >= depth))
181 : : break;
182 : :
183 : : cur = get_nxt_node(cur, &tmp_ip);
184 : : }
185 : :
186 : : return NULL;
187 : : }
188 : :
189 : : /*
190 : : * Traverses on subtree and retrieves more specific routes
191 : : * for a given in args ip/depth prefix
192 : : * last = NULL means the first invocation
193 : : */
194 : : RTE_EXPORT_SYMBOL(rte_rib6_get_nxt)
195 : : struct rte_rib6_node *
196 : 3560 : rte_rib6_get_nxt(struct rte_rib6 *rib,
197 : : const struct rte_ipv6_addr *ip,
198 : : uint8_t depth, struct rte_rib6_node *last, int flag)
199 : : {
200 : : struct rte_rib6_node *tmp, *prev = NULL;
201 : : struct rte_ipv6_addr tmp_ip;
202 : :
203 [ + + - + ]: 3560 : if (unlikely(rib == NULL || ip == NULL || depth > RTE_IPV6_MAX_DEPTH)) {
204 : 13 : rte_errno = EINVAL;
205 : 13 : return NULL;
206 : : }
207 : :
208 : 3547 : tmp_ip = *ip;
209 [ + + ]: 3547 : rte_ipv6_addr_mask(&tmp_ip, depth);
210 : :
211 [ + + ]: 3547 : if (last == NULL) {
212 : 2785 : tmp = rib->tree;
213 [ + + + + ]: 96482 : while ((tmp) && (tmp->depth < depth))
214 : : tmp = get_nxt_node(tmp, &tmp_ip);
215 : : } else {
216 : : tmp = last;
217 [ + + - + : 1524 : while ((tmp->parent != NULL) && (is_right_node(tmp) ||
+ - ]
218 : : (tmp->parent->right == NULL))) {
219 : : tmp = tmp->parent;
220 [ + - ]: 762 : if (is_valid_node(tmp) &&
221 [ + - ]: 762 : (rte_ipv6_addr_eq_prefix(&tmp->ip, &tmp_ip, depth) &&
222 [ - + ]: 762 : (tmp->depth > depth)))
223 : 0 : return tmp;
224 : : }
225 [ - + ]: 762 : tmp = (tmp->parent != NULL) ? tmp->parent->right : NULL;
226 : : }
227 [ + + ]: 5708 : while (tmp) {
228 [ + - ]: 4048 : if (is_valid_node(tmp) &&
229 [ + - ]: 4048 : (rte_ipv6_addr_eq_prefix(&tmp->ip, &tmp_ip, depth) &&
230 [ + + ]: 4048 : (tmp->depth > depth))) {
231 : : prev = tmp;
232 [ + + ]: 1888 : if (flag == RTE_RIB6_GET_NXT_COVER)
233 : 1887 : return prev;
234 : : }
235 [ + + ]: 2161 : tmp = (tmp->left != NULL) ? tmp->left : tmp->right;
236 : : }
237 : : return prev;
238 : : }
239 : :
240 : : RTE_EXPORT_SYMBOL(rte_rib6_remove)
241 : : void
242 : 1025 : rte_rib6_remove(struct rte_rib6 *rib,
243 : : const struct rte_ipv6_addr *ip, uint8_t depth)
244 : : {
245 : : struct rte_rib6_node *cur, *prev, *child;
246 : :
247 : 1025 : cur = rte_rib6_lookup_exact(rib, ip, depth);
248 [ + - ]: 1025 : if (cur == NULL)
249 : : return;
250 : :
251 : 1025 : --rib->cur_routes;
252 : 1025 : cur->flag &= ~RTE_RIB_VALID_NODE;
253 [ + + ]: 1533 : while (!is_valid_node(cur)) {
254 [ + + + - ]: 1025 : if ((cur->left != NULL) && (cur->right != NULL))
255 : : return;
256 [ + + ]: 1025 : child = (cur->left == NULL) ? cur->right : cur->left;
257 [ + + ]: 1025 : if (child != NULL)
258 : 508 : child->parent = cur->parent;
259 [ + + ]: 1025 : if (cur->parent == NULL) {
260 : 517 : rib->tree = child;
261 : 517 : node_free(rib, cur);
262 : 517 : return;
263 : : }
264 [ + - ]: 508 : if (cur->parent->left == cur)
265 : 508 : cur->parent->left = child;
266 : : else
267 : 0 : cur->parent->right = child;
268 : : prev = cur;
269 : : cur = cur->parent;
270 : 508 : node_free(rib, prev);
271 : : }
272 : : }
273 : :
274 : : RTE_EXPORT_SYMBOL(rte_rib6_insert)
275 : : struct rte_rib6_node *
276 : 1032 : rte_rib6_insert(struct rte_rib6 *rib,
277 : : const struct rte_ipv6_addr *ip, uint8_t depth)
278 : : {
279 : : struct rte_rib6_node **tmp;
280 : : struct rte_rib6_node *prev = NULL;
281 : : struct rte_rib6_node *new_node = NULL;
282 : : struct rte_rib6_node *common_node = NULL;
283 : : struct rte_ipv6_addr common_prefix;
284 : : struct rte_ipv6_addr tmp_ip;
285 : : int i, d;
286 : : uint8_t common_depth, ip_xor;
287 : :
288 [ + + + + ]: 1032 : if (unlikely((rib == NULL || ip == NULL || depth > RTE_IPV6_MAX_DEPTH))) {
289 : 2 : rte_errno = EINVAL;
290 : 2 : return NULL;
291 : : }
292 : :
293 : 1030 : tmp = &rib->tree;
294 : :
295 : 1030 : tmp_ip = *ip;
296 [ + + ]: 1030 : rte_ipv6_addr_mask(&tmp_ip, depth);
297 : :
298 : 1030 : new_node = rte_rib6_lookup_exact(rib, &tmp_ip, depth);
299 [ + + ]: 1030 : if (new_node != NULL) {
300 : 1 : rte_errno = EEXIST;
301 : 1 : return NULL;
302 : : }
303 : :
304 : 1029 : new_node = node_alloc(rib);
305 [ - + ]: 1029 : if (new_node == NULL) {
306 : 0 : rte_errno = ENOMEM;
307 : 0 : return NULL;
308 : : }
309 : 1029 : new_node->left = NULL;
310 : 1029 : new_node->right = NULL;
311 : 1029 : new_node->parent = NULL;
312 : 1029 : new_node->ip = tmp_ip;
313 : 1029 : new_node->depth = depth;
314 : 1029 : new_node->flag = RTE_RIB_VALID_NODE;
315 : :
316 : : /* traverse down the tree to find matching node or closest matching */
317 : : while (1) {
318 : : /* insert as the last node in the branch */
319 [ + + ]: 33541 : if (*tmp == NULL) {
320 : 520 : *tmp = new_node;
321 : 520 : new_node->parent = prev;
322 : 520 : ++rib->cur_routes;
323 : 520 : return *tmp;
324 : : }
325 : : /*
326 : : * Intermediate node found.
327 : : * Previous rte_rib6_lookup_exact() returned NULL
328 : : * but node with proper search criteria is found.
329 : : * Validate intermediate node and return.
330 : : */
331 [ + + - + ]: 33021 : if (rte_ipv6_addr_eq(&tmp_ip, &(*tmp)->ip) && (depth == (*tmp)->depth)) {
332 : 0 : node_free(rib, new_node);
333 : 0 : (*tmp)->flag |= RTE_RIB_VALID_NODE;
334 : 0 : ++rib->cur_routes;
335 : 0 : return *tmp;
336 : : }
337 : :
338 [ + + + + ]: 33021 : if (!rte_ipv6_addr_eq_prefix(&tmp_ip, &(*tmp)->ip, (*tmp)->depth) ||
339 : : ((*tmp)->depth >= depth)) {
340 : : break;
341 : : }
342 : : prev = *tmp;
343 : :
344 [ - + ]: 32512 : tmp = (get_dir(&tmp_ip, (*tmp)->depth)) ? &(*tmp)->right :
345 : : &(*tmp)->left;
346 : : }
347 : :
348 : : /* closest node found, new_node should be inserted in the middle */
349 : 509 : common_depth = RTE_MIN(depth, (*tmp)->depth);
350 [ + + ]: 8640 : for (i = 0, d = 0; i < RTE_IPV6_ADDR_SIZE; i++) {
351 : 8132 : ip_xor = tmp_ip.a[i] ^ (*tmp)->ip.a[i];
352 [ + + ]: 8132 : if (ip_xor == 0)
353 : 8131 : d += 8;
354 : : else {
355 : 1 : d += rte_clz32(ip_xor << 24);
356 : 1 : break;
357 : : }
358 : : }
359 : :
360 : 509 : common_depth = RTE_MIN(d, common_depth);
361 : :
362 [ + - ]: 509 : common_prefix = tmp_ip;
363 : : rte_ipv6_addr_mask(&common_prefix, common_depth);
364 : :
365 [ + + + - ]: 509 : if (rte_ipv6_addr_eq(&common_prefix, &tmp_ip) &&
366 : : (common_depth == depth)) {
367 : : /* insert as a parent */
368 [ - + ]: 508 : if (get_dir(&(*tmp)->ip, depth))
369 : 0 : new_node->right = *tmp;
370 : : else
371 : 508 : new_node->left = *tmp;
372 : 508 : new_node->parent = (*tmp)->parent;
373 : 508 : (*tmp)->parent = new_node;
374 : 508 : *tmp = new_node;
375 : : } else {
376 : : /* create intermediate node */
377 : 1 : common_node = node_alloc(rib);
378 [ - + ]: 1 : if (common_node == NULL) {
379 : 0 : node_free(rib, new_node);
380 : 0 : rte_errno = ENOMEM;
381 : 0 : return NULL;
382 : : }
383 : 1 : common_node->ip = common_prefix;
384 : 1 : common_node->depth = common_depth;
385 : 1 : common_node->flag = 0;
386 : 1 : common_node->parent = (*tmp)->parent;
387 : 1 : new_node->parent = common_node;
388 : 1 : (*tmp)->parent = common_node;
389 [ - + ]: 1 : if (get_dir(&(*tmp)->ip, common_depth) == 1) {
390 : 0 : common_node->left = new_node;
391 : 0 : common_node->right = *tmp;
392 : : } else {
393 : 1 : common_node->left = *tmp;
394 : 1 : common_node->right = new_node;
395 : : }
396 : 1 : *tmp = common_node;
397 : : }
398 : 509 : ++rib->cur_routes;
399 : 509 : return new_node;
400 : : }
401 : :
402 : : RTE_EXPORT_SYMBOL(rte_rib6_get_ip)
403 : : int
404 : 765 : rte_rib6_get_ip(const struct rte_rib6_node *node,
405 : : struct rte_ipv6_addr *ip)
406 : : {
407 [ + + ]: 765 : if (unlikely(node == NULL || ip == NULL)) {
408 : 2 : rte_errno = EINVAL;
409 : 2 : return -1;
410 : : }
411 : 763 : *ip = node->ip;
412 : 763 : return 0;
413 : : }
414 : :
415 : : RTE_EXPORT_SYMBOL(rte_rib6_get_depth)
416 : : int
417 : 885 : rte_rib6_get_depth(const struct rte_rib6_node *node, uint8_t *depth)
418 : : {
419 [ + + ]: 885 : if (unlikely(node == NULL || depth == NULL)) {
420 : 2 : rte_errno = EINVAL;
421 : 2 : return -1;
422 : : }
423 : 883 : *depth = node->depth;
424 : 883 : return 0;
425 : : }
426 : :
427 : : RTE_EXPORT_SYMBOL(rte_rib6_get_ext)
428 : : void *
429 : 1 : rte_rib6_get_ext(struct rte_rib6_node *node)
430 : : {
431 [ - + ]: 1 : return (node == NULL) ? NULL : &node->ext[0];
432 : : }
433 : :
434 : : RTE_EXPORT_SYMBOL(rte_rib6_get_nh)
435 : : int
436 : 50172 : rte_rib6_get_nh(const struct rte_rib6_node *node, uint64_t *nh)
437 : : {
438 [ + + ]: 50172 : if (unlikely(node == NULL || nh == NULL)) {
439 : 2 : rte_errno = EINVAL;
440 : 2 : return -1;
441 : : }
442 : 50170 : *nh = node->nh;
443 : 50170 : return 0;
444 : : }
445 : :
446 : : RTE_EXPORT_SYMBOL(rte_rib6_set_nh)
447 : : int
448 : 1027 : rte_rib6_set_nh(struct rte_rib6_node *node, uint64_t nh)
449 : : {
450 [ + + ]: 1027 : if (unlikely(node == NULL)) {
451 : 1 : rte_errno = EINVAL;
452 : 1 : return -1;
453 : : }
454 : 1026 : node->nh = nh;
455 : 1026 : return 0;
456 : : }
457 : :
458 : : RTE_EXPORT_SYMBOL(rte_rib6_create)
459 : : struct rte_rib6 *
460 : 19 : rte_rib6_create(const char *name, int socket_id,
461 : : const struct rte_rib6_conf *conf)
462 : : {
463 : : char mem_name[RTE_RIB6_NAMESIZE];
464 : : struct rte_rib6 *rib = NULL;
465 : : struct rte_tailq_entry *te;
466 : : struct rte_rib6_list *rib6_list;
467 : : struct rte_mempool *node_pool;
468 : :
469 : : /* Check user arguments. */
470 [ + + + + ]: 19 : if (unlikely(name == NULL || conf == NULL || conf->max_nodes <= 0)) {
471 : 4 : rte_errno = EINVAL;
472 : 4 : return NULL;
473 : : }
474 : :
475 : : snprintf(mem_name, sizeof(mem_name), "MP_%s", name);
476 : 15 : node_pool = rte_mempool_create(mem_name, conf->max_nodes,
477 : 15 : sizeof(struct rte_rib6_node) + conf->ext_sz, 0, 0,
478 : : NULL, NULL, NULL, NULL, socket_id, 0);
479 : :
480 [ + + ]: 15 : if (node_pool == NULL) {
481 : 2 : RIB_LOG(ERR,
482 : : "Can not allocate mempool for RIB6 %s", name);
483 : 2 : return NULL;
484 : : }
485 : :
486 : : snprintf(mem_name, sizeof(mem_name), "RIB6_%s", name);
487 : 13 : rib6_list = RTE_TAILQ_CAST(rte_rib6_tailq.head, rte_rib6_list);
488 : :
489 : 13 : rte_mcfg_tailq_write_lock();
490 : :
491 : : /* guarantee there's no existing */
492 [ - + ]: 13 : TAILQ_FOREACH(te, rib6_list, next) {
493 : 0 : rib = (struct rte_rib6 *)te->data;
494 [ # # ]: 0 : if (strncmp(name, rib->name, RTE_RIB6_NAMESIZE) == 0)
495 : : break;
496 : : }
497 : : rib = NULL;
498 [ - + ]: 13 : if (te != NULL) {
499 : 0 : rte_errno = EEXIST;
500 : 0 : goto exit;
501 : : }
502 : :
503 : : /* allocate tailq entry */
504 : 13 : te = rte_zmalloc("RIB6_TAILQ_ENTRY", sizeof(*te), 0);
505 [ - + ]: 13 : if (unlikely(te == NULL)) {
506 : 0 : RIB_LOG(ERR,
507 : : "Can not allocate tailq entry for RIB6 %s", name);
508 : 0 : rte_errno = ENOMEM;
509 : 0 : goto exit;
510 : : }
511 : :
512 : : /* Allocate memory to store the RIB6 data structures. */
513 : 13 : rib = rte_zmalloc_socket(mem_name,
514 : : sizeof(struct rte_rib6), RTE_CACHE_LINE_SIZE, socket_id);
515 [ - + ]: 13 : if (unlikely(rib == NULL)) {
516 : 0 : RIB_LOG(ERR, "RIB6 %s memory allocation failed", name);
517 : 0 : rte_errno = ENOMEM;
518 : 0 : goto free_te;
519 : : }
520 : :
521 : 13 : rte_strlcpy(rib->name, name, sizeof(rib->name));
522 : 13 : rib->tree = NULL;
523 : 13 : rib->max_nodes = conf->max_nodes;
524 : 13 : rib->node_pool = node_pool;
525 : :
526 : 13 : te->data = (void *)rib;
527 : 13 : TAILQ_INSERT_TAIL(rib6_list, te, next);
528 : :
529 : 13 : rte_mcfg_tailq_write_unlock();
530 : :
531 : 13 : return rib;
532 : :
533 : : free_te:
534 : 0 : rte_free(te);
535 : 0 : exit:
536 : 0 : rte_mcfg_tailq_write_unlock();
537 : 0 : rte_mempool_free(node_pool);
538 : :
539 : 0 : return NULL;
540 : : }
541 : :
542 : : RTE_EXPORT_SYMBOL(rte_rib6_find_existing)
543 : : struct rte_rib6 *
544 : 0 : rte_rib6_find_existing(const char *name)
545 : : {
546 : : struct rte_rib6 *rib = NULL;
547 : : struct rte_tailq_entry *te;
548 : : struct rte_rib6_list *rib6_list;
549 : :
550 [ # # ]: 0 : if (unlikely(name == NULL)) {
551 : 0 : rte_errno = EINVAL;
552 : 0 : return NULL;
553 : : }
554 : :
555 : 0 : rib6_list = RTE_TAILQ_CAST(rte_rib6_tailq.head, rte_rib6_list);
556 : :
557 : 0 : rte_mcfg_tailq_read_lock();
558 [ # # ]: 0 : TAILQ_FOREACH(te, rib6_list, next) {
559 : 0 : rib = (struct rte_rib6 *) te->data;
560 [ # # ]: 0 : if (strncmp(name, rib->name, RTE_RIB6_NAMESIZE) == 0)
561 : : break;
562 : : }
563 : 0 : rte_mcfg_tailq_read_unlock();
564 : :
565 [ # # ]: 0 : if (te == NULL) {
566 : 0 : rte_errno = ENOENT;
567 : 0 : return NULL;
568 : : }
569 : :
570 : : return rib;
571 : : }
572 : :
573 : : RTE_EXPORT_SYMBOL(rte_rib6_free)
574 : : void
575 : 14 : rte_rib6_free(struct rte_rib6 *rib)
576 : : {
577 : : struct rte_tailq_entry *te;
578 : : struct rte_rib6_list *rib6_list;
579 : : struct rte_rib6_node *tmp = NULL;
580 : :
581 [ + + ]: 14 : if (unlikely(rib == NULL)) {
582 : 1 : rte_errno = EINVAL;
583 : 1 : return;
584 : : }
585 : :
586 : 13 : rib6_list = RTE_TAILQ_CAST(rte_rib6_tailq.head, rte_rib6_list);
587 : :
588 : 13 : rte_mcfg_tailq_write_lock();
589 : :
590 : : /* find our tailq entry */
591 [ + - ]: 13 : TAILQ_FOREACH(te, rib6_list, next) {
592 [ - + ]: 13 : if (te->data == (void *)rib)
593 : : break;
594 : : }
595 [ + - ]: 13 : if (te != NULL)
596 [ - + ]: 13 : TAILQ_REMOVE(rib6_list, te, next);
597 : :
598 : 13 : rte_mcfg_tailq_write_unlock();
599 : :
600 : 13 : while ((tmp = rte_rib6_get_nxt(rib, 0, 0, tmp,
601 [ - + ]: 13 : RTE_RIB6_GET_NXT_ALL)) != NULL)
602 : 0 : rte_rib6_remove(rib, &tmp->ip, tmp->depth);
603 : :
604 : 13 : rte_mempool_free(rib->node_pool);
605 : :
606 : 13 : rte_free(rib);
607 : 13 : rte_free(te);
608 : : }
|