199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>
399a2dd95SBruce Richardson * Copyright(c) 2019 Intel Corporation
499a2dd95SBruce Richardson */
599a2dd95SBruce Richardson
699a2dd95SBruce Richardson #include <stdbool.h>
799a2dd95SBruce Richardson #include <stdint.h>
8a8d7389aSStephen Hemminger #include <sys/queue.h>
999a2dd95SBruce Richardson
1099a2dd95SBruce Richardson #include <rte_eal_memconfig.h>
1199a2dd95SBruce Richardson #include <rte_errno.h>
1299a2dd95SBruce Richardson #include <rte_malloc.h>
1399a2dd95SBruce Richardson #include <rte_mempool.h>
1499a2dd95SBruce Richardson #include <rte_string_fns.h>
1599a2dd95SBruce Richardson #include <rte_tailq.h>
1699a2dd95SBruce Richardson
1799a2dd95SBruce Richardson #include <rte_rib.h>
1899a2dd95SBruce Richardson
19ae67895bSDavid Marchand #include "rib_log.h"
20ae67895bSDavid Marchand
21fdb83ffbSStephen Hemminger RTE_LOG_REGISTER_DEFAULT(rib_logtype, INFO);
22fdb83ffbSStephen Hemminger
2399a2dd95SBruce Richardson TAILQ_HEAD(rte_rib_list, rte_tailq_entry);
2499a2dd95SBruce Richardson static struct rte_tailq_elem rte_rib_tailq = {
2599a2dd95SBruce Richardson .name = "RTE_RIB",
2699a2dd95SBruce Richardson };
2799a2dd95SBruce Richardson EAL_REGISTER_TAILQ(rte_rib_tailq)
2899a2dd95SBruce Richardson
2999a2dd95SBruce Richardson #define RTE_RIB_VALID_NODE 1
3099a2dd95SBruce Richardson /* Maximum depth value possible for IPv4 RIB. */
3199a2dd95SBruce Richardson #define RIB_MAXDEPTH 32
3299a2dd95SBruce Richardson /* Maximum length of a RIB name. */
3399a2dd95SBruce Richardson #define RTE_RIB_NAMESIZE 64
3499a2dd95SBruce Richardson
3599a2dd95SBruce Richardson struct rte_rib_node {
3699a2dd95SBruce Richardson struct rte_rib_node *left;
3799a2dd95SBruce Richardson struct rte_rib_node *right;
3899a2dd95SBruce Richardson struct rte_rib_node *parent;
3999a2dd95SBruce Richardson uint32_t ip;
4099a2dd95SBruce Richardson uint8_t depth;
4199a2dd95SBruce Richardson uint8_t flag;
4299a2dd95SBruce Richardson uint64_t nh;
43*3401a4afSDavid Marchand uint64_t ext[];
4499a2dd95SBruce Richardson };
4599a2dd95SBruce Richardson
4699a2dd95SBruce Richardson struct rte_rib {
4799a2dd95SBruce Richardson char name[RTE_RIB_NAMESIZE];
4899a2dd95SBruce Richardson struct rte_rib_node *tree;
4999a2dd95SBruce Richardson struct rte_mempool *node_pool;
5099a2dd95SBruce Richardson uint32_t cur_nodes;
5199a2dd95SBruce Richardson uint32_t cur_routes;
5299a2dd95SBruce Richardson uint32_t max_nodes;
5399a2dd95SBruce Richardson };
5499a2dd95SBruce Richardson
5599a2dd95SBruce Richardson static inline bool
is_valid_node(const struct rte_rib_node * node)56eeab353bSStephen Hemminger is_valid_node(const struct rte_rib_node *node)
5799a2dd95SBruce Richardson {
5899a2dd95SBruce Richardson return (node->flag & RTE_RIB_VALID_NODE) == RTE_RIB_VALID_NODE;
5999a2dd95SBruce Richardson }
6099a2dd95SBruce Richardson
6199a2dd95SBruce Richardson static inline bool
is_right_node(const struct rte_rib_node * node)62eeab353bSStephen Hemminger is_right_node(const struct rte_rib_node *node)
6399a2dd95SBruce Richardson {
6499a2dd95SBruce Richardson return node->parent->right == node;
6599a2dd95SBruce Richardson }
6699a2dd95SBruce Richardson
6799a2dd95SBruce Richardson /*
6899a2dd95SBruce Richardson * Check if ip1 is covered by ip2/depth prefix
6999a2dd95SBruce Richardson */
7099a2dd95SBruce Richardson static inline bool
is_covered(uint32_t ip1,uint32_t ip2,uint8_t depth)7199a2dd95SBruce Richardson is_covered(uint32_t ip1, uint32_t ip2, uint8_t depth)
7299a2dd95SBruce Richardson {
7399a2dd95SBruce Richardson return ((ip1 ^ ip2) & rte_rib_depth_to_mask(depth)) == 0;
7499a2dd95SBruce Richardson }
7599a2dd95SBruce Richardson
7699a2dd95SBruce Richardson static inline struct rte_rib_node *
get_nxt_node(struct rte_rib_node * node,uint32_t ip)7799a2dd95SBruce Richardson get_nxt_node(struct rte_rib_node *node, uint32_t ip)
7899a2dd95SBruce Richardson {
791b984e98SStephen Hemminger if (node->depth == RIB_MAXDEPTH)
801b984e98SStephen Hemminger return NULL;
8199a2dd95SBruce Richardson return (ip & (1 << (31 - node->depth))) ? node->right : node->left;
8299a2dd95SBruce Richardson }
8399a2dd95SBruce Richardson
8499a2dd95SBruce Richardson static struct rte_rib_node *
node_alloc(struct rte_rib * rib)8599a2dd95SBruce Richardson node_alloc(struct rte_rib *rib)
8699a2dd95SBruce Richardson {
8799a2dd95SBruce Richardson struct rte_rib_node *ent;
8899a2dd95SBruce Richardson int ret;
8999a2dd95SBruce Richardson
9099a2dd95SBruce Richardson ret = rte_mempool_get(rib->node_pool, (void *)&ent);
9199a2dd95SBruce Richardson if (unlikely(ret != 0))
9299a2dd95SBruce Richardson return NULL;
9399a2dd95SBruce Richardson ++rib->cur_nodes;
9499a2dd95SBruce Richardson return ent;
9599a2dd95SBruce Richardson }
9699a2dd95SBruce Richardson
9799a2dd95SBruce Richardson static void
node_free(struct rte_rib * rib,struct rte_rib_node * ent)9899a2dd95SBruce Richardson node_free(struct rte_rib *rib, struct rte_rib_node *ent)
9999a2dd95SBruce Richardson {
10099a2dd95SBruce Richardson --rib->cur_nodes;
10199a2dd95SBruce Richardson rte_mempool_put(rib->node_pool, ent);
10299a2dd95SBruce Richardson }
10399a2dd95SBruce Richardson
10499a2dd95SBruce Richardson struct rte_rib_node *
rte_rib_lookup(struct rte_rib * rib,uint32_t ip)10599a2dd95SBruce Richardson rte_rib_lookup(struct rte_rib *rib, uint32_t ip)
10699a2dd95SBruce Richardson {
10799a2dd95SBruce Richardson struct rte_rib_node *cur, *prev = NULL;
10899a2dd95SBruce Richardson
109eeab353bSStephen Hemminger if (unlikely(rib == NULL)) {
11099a2dd95SBruce Richardson rte_errno = EINVAL;
11199a2dd95SBruce Richardson return NULL;
11299a2dd95SBruce Richardson }
11399a2dd95SBruce Richardson
11499a2dd95SBruce Richardson cur = rib->tree;
11599a2dd95SBruce Richardson while ((cur != NULL) && is_covered(ip, cur->ip, cur->depth)) {
11699a2dd95SBruce Richardson if (is_valid_node(cur))
11799a2dd95SBruce Richardson prev = cur;
11899a2dd95SBruce Richardson cur = get_nxt_node(cur, ip);
11999a2dd95SBruce Richardson }
12099a2dd95SBruce Richardson return prev;
12199a2dd95SBruce Richardson }
12299a2dd95SBruce Richardson
12399a2dd95SBruce Richardson struct rte_rib_node *
rte_rib_lookup_parent(struct rte_rib_node * ent)12499a2dd95SBruce Richardson rte_rib_lookup_parent(struct rte_rib_node *ent)
12599a2dd95SBruce Richardson {
12699a2dd95SBruce Richardson struct rte_rib_node *tmp;
12799a2dd95SBruce Richardson
12899a2dd95SBruce Richardson if (ent == NULL)
12999a2dd95SBruce Richardson return NULL;
13099a2dd95SBruce Richardson tmp = ent->parent;
13199a2dd95SBruce Richardson while ((tmp != NULL) && !is_valid_node(tmp))
13299a2dd95SBruce Richardson tmp = tmp->parent;
13399a2dd95SBruce Richardson return tmp;
13499a2dd95SBruce Richardson }
13599a2dd95SBruce Richardson
13699a2dd95SBruce Richardson static struct rte_rib_node *
__rib_lookup_exact(struct rte_rib * rib,uint32_t ip,uint8_t depth)13799a2dd95SBruce Richardson __rib_lookup_exact(struct rte_rib *rib, uint32_t ip, uint8_t depth)
13899a2dd95SBruce Richardson {
13999a2dd95SBruce Richardson struct rte_rib_node *cur;
14099a2dd95SBruce Richardson
14199a2dd95SBruce Richardson cur = rib->tree;
14299a2dd95SBruce Richardson while (cur != NULL) {
14399a2dd95SBruce Richardson if ((cur->ip == ip) && (cur->depth == depth) &&
14499a2dd95SBruce Richardson is_valid_node(cur))
14599a2dd95SBruce Richardson return cur;
14699a2dd95SBruce Richardson if ((cur->depth > depth) ||
14799a2dd95SBruce Richardson !is_covered(ip, cur->ip, cur->depth))
14899a2dd95SBruce Richardson break;
14999a2dd95SBruce Richardson cur = get_nxt_node(cur, ip);
15099a2dd95SBruce Richardson }
15199a2dd95SBruce Richardson return NULL;
15299a2dd95SBruce Richardson }
15399a2dd95SBruce Richardson
15499a2dd95SBruce Richardson struct rte_rib_node *
rte_rib_lookup_exact(struct rte_rib * rib,uint32_t ip,uint8_t depth)15599a2dd95SBruce Richardson rte_rib_lookup_exact(struct rte_rib *rib, uint32_t ip, uint8_t depth)
15699a2dd95SBruce Richardson {
157eeab353bSStephen Hemminger if (unlikely(rib == NULL || depth > RIB_MAXDEPTH)) {
15899a2dd95SBruce Richardson rte_errno = EINVAL;
15999a2dd95SBruce Richardson return NULL;
16099a2dd95SBruce Richardson }
16199a2dd95SBruce Richardson ip &= rte_rib_depth_to_mask(depth);
16299a2dd95SBruce Richardson
16399a2dd95SBruce Richardson return __rib_lookup_exact(rib, ip, depth);
16499a2dd95SBruce Richardson }
16599a2dd95SBruce Richardson
16699a2dd95SBruce Richardson /*
16799a2dd95SBruce Richardson * Traverses on subtree and retrieves more specific routes
16899a2dd95SBruce Richardson * for a given in args ip/depth prefix
16999a2dd95SBruce Richardson * last = NULL means the first invocation
17099a2dd95SBruce Richardson */
17199a2dd95SBruce Richardson struct rte_rib_node *
rte_rib_get_nxt(struct rte_rib * rib,uint32_t ip,uint8_t depth,struct rte_rib_node * last,int flag)17299a2dd95SBruce Richardson rte_rib_get_nxt(struct rte_rib *rib, uint32_t ip,
17399a2dd95SBruce Richardson uint8_t depth, struct rte_rib_node *last, int flag)
17499a2dd95SBruce Richardson {
17599a2dd95SBruce Richardson struct rte_rib_node *tmp, *prev = NULL;
17699a2dd95SBruce Richardson
177eeab353bSStephen Hemminger if (unlikely(rib == NULL || depth > RIB_MAXDEPTH)) {
17899a2dd95SBruce Richardson rte_errno = EINVAL;
17999a2dd95SBruce Richardson return NULL;
18099a2dd95SBruce Richardson }
18199a2dd95SBruce Richardson
18299a2dd95SBruce Richardson if (last == NULL) {
18399a2dd95SBruce Richardson tmp = rib->tree;
18499a2dd95SBruce Richardson while ((tmp) && (tmp->depth < depth))
18599a2dd95SBruce Richardson tmp = get_nxt_node(tmp, ip);
18699a2dd95SBruce Richardson } else {
18799a2dd95SBruce Richardson tmp = last;
18899a2dd95SBruce Richardson while ((tmp->parent != NULL) && (is_right_node(tmp) ||
18999a2dd95SBruce Richardson (tmp->parent->right == NULL))) {
19099a2dd95SBruce Richardson tmp = tmp->parent;
19199a2dd95SBruce Richardson if (is_valid_node(tmp) &&
19299a2dd95SBruce Richardson (is_covered(tmp->ip, ip, depth) &&
19399a2dd95SBruce Richardson (tmp->depth > depth)))
19499a2dd95SBruce Richardson return tmp;
19599a2dd95SBruce Richardson }
19699a2dd95SBruce Richardson tmp = (tmp->parent) ? tmp->parent->right : NULL;
19799a2dd95SBruce Richardson }
19899a2dd95SBruce Richardson while (tmp) {
19999a2dd95SBruce Richardson if (is_valid_node(tmp) &&
20099a2dd95SBruce Richardson (is_covered(tmp->ip, ip, depth) &&
20199a2dd95SBruce Richardson (tmp->depth > depth))) {
20299a2dd95SBruce Richardson prev = tmp;
20399a2dd95SBruce Richardson if (flag == RTE_RIB_GET_NXT_COVER)
20499a2dd95SBruce Richardson return prev;
20599a2dd95SBruce Richardson }
20699a2dd95SBruce Richardson tmp = (tmp->left) ? tmp->left : tmp->right;
20799a2dd95SBruce Richardson }
20899a2dd95SBruce Richardson return prev;
20999a2dd95SBruce Richardson }
21099a2dd95SBruce Richardson
21199a2dd95SBruce Richardson void
rte_rib_remove(struct rte_rib * rib,uint32_t ip,uint8_t depth)21299a2dd95SBruce Richardson rte_rib_remove(struct rte_rib *rib, uint32_t ip, uint8_t depth)
21399a2dd95SBruce Richardson {
21499a2dd95SBruce Richardson struct rte_rib_node *cur, *prev, *child;
21599a2dd95SBruce Richardson
21699a2dd95SBruce Richardson cur = rte_rib_lookup_exact(rib, ip, depth);
21799a2dd95SBruce Richardson if (cur == NULL)
21899a2dd95SBruce Richardson return;
21999a2dd95SBruce Richardson
22099a2dd95SBruce Richardson --rib->cur_routes;
22199a2dd95SBruce Richardson cur->flag &= ~RTE_RIB_VALID_NODE;
22299a2dd95SBruce Richardson while (!is_valid_node(cur)) {
22399a2dd95SBruce Richardson if ((cur->left != NULL) && (cur->right != NULL))
22499a2dd95SBruce Richardson return;
22599a2dd95SBruce Richardson child = (cur->left == NULL) ? cur->right : cur->left;
22699a2dd95SBruce Richardson if (child != NULL)
22799a2dd95SBruce Richardson child->parent = cur->parent;
22899a2dd95SBruce Richardson if (cur->parent == NULL) {
22999a2dd95SBruce Richardson rib->tree = child;
23099a2dd95SBruce Richardson node_free(rib, cur);
23199a2dd95SBruce Richardson return;
23299a2dd95SBruce Richardson }
23399a2dd95SBruce Richardson if (cur->parent->left == cur)
23499a2dd95SBruce Richardson cur->parent->left = child;
23599a2dd95SBruce Richardson else
23699a2dd95SBruce Richardson cur->parent->right = child;
23799a2dd95SBruce Richardson prev = cur;
23899a2dd95SBruce Richardson cur = cur->parent;
23999a2dd95SBruce Richardson node_free(rib, prev);
24099a2dd95SBruce Richardson }
24199a2dd95SBruce Richardson }
24299a2dd95SBruce Richardson
24399a2dd95SBruce Richardson struct rte_rib_node *
rte_rib_insert(struct rte_rib * rib,uint32_t ip,uint8_t depth)24499a2dd95SBruce Richardson rte_rib_insert(struct rte_rib *rib, uint32_t ip, uint8_t depth)
24599a2dd95SBruce Richardson {
24699a2dd95SBruce Richardson struct rte_rib_node **tmp;
24799a2dd95SBruce Richardson struct rte_rib_node *prev = NULL;
24899a2dd95SBruce Richardson struct rte_rib_node *new_node = NULL;
24999a2dd95SBruce Richardson struct rte_rib_node *common_node = NULL;
25099a2dd95SBruce Richardson int d = 0;
25199a2dd95SBruce Richardson uint32_t common_prefix;
25299a2dd95SBruce Richardson uint8_t common_depth;
25399a2dd95SBruce Richardson
254eeab353bSStephen Hemminger if (unlikely(rib == NULL || depth > RIB_MAXDEPTH)) {
25599a2dd95SBruce Richardson rte_errno = EINVAL;
25699a2dd95SBruce Richardson return NULL;
25799a2dd95SBruce Richardson }
25899a2dd95SBruce Richardson
25999a2dd95SBruce Richardson tmp = &rib->tree;
26099a2dd95SBruce Richardson ip &= rte_rib_depth_to_mask(depth);
26199a2dd95SBruce Richardson new_node = __rib_lookup_exact(rib, ip, depth);
26299a2dd95SBruce Richardson if (new_node != NULL) {
26399a2dd95SBruce Richardson rte_errno = EEXIST;
26499a2dd95SBruce Richardson return NULL;
26599a2dd95SBruce Richardson }
26699a2dd95SBruce Richardson
26799a2dd95SBruce Richardson new_node = node_alloc(rib);
26899a2dd95SBruce Richardson if (new_node == NULL) {
26999a2dd95SBruce Richardson rte_errno = ENOMEM;
27099a2dd95SBruce Richardson return NULL;
27199a2dd95SBruce Richardson }
27299a2dd95SBruce Richardson new_node->left = NULL;
27399a2dd95SBruce Richardson new_node->right = NULL;
27499a2dd95SBruce Richardson new_node->parent = NULL;
27599a2dd95SBruce Richardson new_node->ip = ip;
27699a2dd95SBruce Richardson new_node->depth = depth;
27799a2dd95SBruce Richardson new_node->flag = RTE_RIB_VALID_NODE;
27899a2dd95SBruce Richardson
27999a2dd95SBruce Richardson /* traverse down the tree to find matching node or closest matching */
28099a2dd95SBruce Richardson while (1) {
28199a2dd95SBruce Richardson /* insert as the last node in the branch */
28299a2dd95SBruce Richardson if (*tmp == NULL) {
28399a2dd95SBruce Richardson *tmp = new_node;
28499a2dd95SBruce Richardson new_node->parent = prev;
28599a2dd95SBruce Richardson ++rib->cur_routes;
28699a2dd95SBruce Richardson return *tmp;
28799a2dd95SBruce Richardson }
28899a2dd95SBruce Richardson /*
28999a2dd95SBruce Richardson * Intermediate node found.
29099a2dd95SBruce Richardson * Previous rte_rib_lookup_exact() returned NULL
29199a2dd95SBruce Richardson * but node with proper search criteria is found.
29299a2dd95SBruce Richardson * Validate intermediate node and return.
29399a2dd95SBruce Richardson */
29499a2dd95SBruce Richardson if ((ip == (*tmp)->ip) && (depth == (*tmp)->depth)) {
29599a2dd95SBruce Richardson node_free(rib, new_node);
29699a2dd95SBruce Richardson (*tmp)->flag |= RTE_RIB_VALID_NODE;
29799a2dd95SBruce Richardson ++rib->cur_routes;
29899a2dd95SBruce Richardson return *tmp;
29999a2dd95SBruce Richardson }
30099a2dd95SBruce Richardson d = (*tmp)->depth;
30199a2dd95SBruce Richardson if ((d >= depth) || !is_covered(ip, (*tmp)->ip, d))
30299a2dd95SBruce Richardson break;
30399a2dd95SBruce Richardson prev = *tmp;
30499a2dd95SBruce Richardson tmp = (ip & (1 << (31 - d))) ? &(*tmp)->right : &(*tmp)->left;
30599a2dd95SBruce Richardson }
30699a2dd95SBruce Richardson /* closest node found, new_node should be inserted in the middle */
30799a2dd95SBruce Richardson common_depth = RTE_MIN(depth, (*tmp)->depth);
30899a2dd95SBruce Richardson common_prefix = ip ^ (*tmp)->ip;
3093d4e27fdSDavid Marchand d = (common_prefix == 0) ? 32 : rte_clz32(common_prefix);
31099a2dd95SBruce Richardson
31199a2dd95SBruce Richardson common_depth = RTE_MIN(d, common_depth);
31299a2dd95SBruce Richardson common_prefix = ip & rte_rib_depth_to_mask(common_depth);
31399a2dd95SBruce Richardson if ((common_prefix == ip) && (common_depth == depth)) {
31499a2dd95SBruce Richardson /* insert as a parent */
31599a2dd95SBruce Richardson if ((*tmp)->ip & (1 << (31 - depth)))
31699a2dd95SBruce Richardson new_node->right = *tmp;
31799a2dd95SBruce Richardson else
31899a2dd95SBruce Richardson new_node->left = *tmp;
31999a2dd95SBruce Richardson new_node->parent = (*tmp)->parent;
32099a2dd95SBruce Richardson (*tmp)->parent = new_node;
32199a2dd95SBruce Richardson *tmp = new_node;
32299a2dd95SBruce Richardson } else {
32399a2dd95SBruce Richardson /* create intermediate node */
32499a2dd95SBruce Richardson common_node = node_alloc(rib);
32599a2dd95SBruce Richardson if (common_node == NULL) {
32699a2dd95SBruce Richardson node_free(rib, new_node);
32799a2dd95SBruce Richardson rte_errno = ENOMEM;
32899a2dd95SBruce Richardson return NULL;
32999a2dd95SBruce Richardson }
33099a2dd95SBruce Richardson common_node->ip = common_prefix;
33199a2dd95SBruce Richardson common_node->depth = common_depth;
33299a2dd95SBruce Richardson common_node->flag = 0;
33399a2dd95SBruce Richardson common_node->parent = (*tmp)->parent;
33499a2dd95SBruce Richardson new_node->parent = common_node;
33599a2dd95SBruce Richardson (*tmp)->parent = common_node;
33699a2dd95SBruce Richardson if ((new_node->ip & (1 << (31 - common_depth))) == 0) {
33799a2dd95SBruce Richardson common_node->left = new_node;
33899a2dd95SBruce Richardson common_node->right = *tmp;
33999a2dd95SBruce Richardson } else {
34099a2dd95SBruce Richardson common_node->left = *tmp;
34199a2dd95SBruce Richardson common_node->right = new_node;
34299a2dd95SBruce Richardson }
34399a2dd95SBruce Richardson *tmp = common_node;
34499a2dd95SBruce Richardson }
34599a2dd95SBruce Richardson ++rib->cur_routes;
34699a2dd95SBruce Richardson return new_node;
34799a2dd95SBruce Richardson }
34899a2dd95SBruce Richardson
34999a2dd95SBruce Richardson int
rte_rib_get_ip(const struct rte_rib_node * node,uint32_t * ip)35099a2dd95SBruce Richardson rte_rib_get_ip(const struct rte_rib_node *node, uint32_t *ip)
35199a2dd95SBruce Richardson {
352eeab353bSStephen Hemminger if (unlikely(node == NULL || ip == NULL)) {
35399a2dd95SBruce Richardson rte_errno = EINVAL;
35499a2dd95SBruce Richardson return -1;
35599a2dd95SBruce Richardson }
35699a2dd95SBruce Richardson *ip = node->ip;
35799a2dd95SBruce Richardson return 0;
35899a2dd95SBruce Richardson }
35999a2dd95SBruce Richardson
36099a2dd95SBruce Richardson int
rte_rib_get_depth(const struct rte_rib_node * node,uint8_t * depth)36199a2dd95SBruce Richardson rte_rib_get_depth(const struct rte_rib_node *node, uint8_t *depth)
36299a2dd95SBruce Richardson {
363eeab353bSStephen Hemminger if (unlikely(node == NULL || depth == NULL)) {
36499a2dd95SBruce Richardson rte_errno = EINVAL;
36599a2dd95SBruce Richardson return -1;
36699a2dd95SBruce Richardson }
36799a2dd95SBruce Richardson *depth = node->depth;
36899a2dd95SBruce Richardson return 0;
36999a2dd95SBruce Richardson }
37099a2dd95SBruce Richardson
37199a2dd95SBruce Richardson void *
rte_rib_get_ext(struct rte_rib_node * node)37299a2dd95SBruce Richardson rte_rib_get_ext(struct rte_rib_node *node)
37399a2dd95SBruce Richardson {
37499a2dd95SBruce Richardson return (node == NULL) ? NULL : &node->ext[0];
37599a2dd95SBruce Richardson }
37699a2dd95SBruce Richardson
37799a2dd95SBruce Richardson int
rte_rib_get_nh(const struct rte_rib_node * node,uint64_t * nh)37899a2dd95SBruce Richardson rte_rib_get_nh(const struct rte_rib_node *node, uint64_t *nh)
37999a2dd95SBruce Richardson {
380eeab353bSStephen Hemminger if (unlikely(node == NULL || nh == NULL)) {
38199a2dd95SBruce Richardson rte_errno = EINVAL;
38299a2dd95SBruce Richardson return -1;
38399a2dd95SBruce Richardson }
38499a2dd95SBruce Richardson *nh = node->nh;
38599a2dd95SBruce Richardson return 0;
38699a2dd95SBruce Richardson }
38799a2dd95SBruce Richardson
38899a2dd95SBruce Richardson int
rte_rib_set_nh(struct rte_rib_node * node,uint64_t nh)38999a2dd95SBruce Richardson rte_rib_set_nh(struct rte_rib_node *node, uint64_t nh)
39099a2dd95SBruce Richardson {
391eeab353bSStephen Hemminger if (unlikely(node == NULL)) {
39299a2dd95SBruce Richardson rte_errno = EINVAL;
39399a2dd95SBruce Richardson return -1;
39499a2dd95SBruce Richardson }
39599a2dd95SBruce Richardson node->nh = nh;
39699a2dd95SBruce Richardson return 0;
39799a2dd95SBruce Richardson }
39899a2dd95SBruce Richardson
39999a2dd95SBruce Richardson struct rte_rib *
rte_rib_create(const char * name,int socket_id,const struct rte_rib_conf * conf)40099a2dd95SBruce Richardson rte_rib_create(const char *name, int socket_id, const struct rte_rib_conf *conf)
40199a2dd95SBruce Richardson {
40299a2dd95SBruce Richardson char mem_name[RTE_RIB_NAMESIZE];
40399a2dd95SBruce Richardson struct rte_rib *rib = NULL;
40499a2dd95SBruce Richardson struct rte_tailq_entry *te;
40599a2dd95SBruce Richardson struct rte_rib_list *rib_list;
40699a2dd95SBruce Richardson struct rte_mempool *node_pool;
40799a2dd95SBruce Richardson
40899a2dd95SBruce Richardson /* Check user arguments. */
409eeab353bSStephen Hemminger if (unlikely(name == NULL || conf == NULL || conf->max_nodes <= 0)) {
41099a2dd95SBruce Richardson rte_errno = EINVAL;
41199a2dd95SBruce Richardson return NULL;
41299a2dd95SBruce Richardson }
41399a2dd95SBruce Richardson
41499a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "MP_%s", name);
41599a2dd95SBruce Richardson node_pool = rte_mempool_create(mem_name, conf->max_nodes,
41699a2dd95SBruce Richardson sizeof(struct rte_rib_node) + conf->ext_sz, 0, 0,
41799a2dd95SBruce Richardson NULL, NULL, NULL, NULL, socket_id, 0);
41899a2dd95SBruce Richardson
41999a2dd95SBruce Richardson if (node_pool == NULL) {
420ae67895bSDavid Marchand RIB_LOG(ERR,
421ae67895bSDavid Marchand "Can not allocate mempool for RIB %s", name);
42299a2dd95SBruce Richardson return NULL;
42399a2dd95SBruce Richardson }
42499a2dd95SBruce Richardson
42599a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "RIB_%s", name);
42699a2dd95SBruce Richardson rib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);
42799a2dd95SBruce Richardson
42899a2dd95SBruce Richardson rte_mcfg_tailq_write_lock();
42999a2dd95SBruce Richardson
43099a2dd95SBruce Richardson /* guarantee there's no existing */
43199a2dd95SBruce Richardson TAILQ_FOREACH(te, rib_list, next) {
43299a2dd95SBruce Richardson rib = (struct rte_rib *)te->data;
43399a2dd95SBruce Richardson if (strncmp(name, rib->name, RTE_RIB_NAMESIZE) == 0)
43499a2dd95SBruce Richardson break;
43599a2dd95SBruce Richardson }
43699a2dd95SBruce Richardson rib = NULL;
43799a2dd95SBruce Richardson if (te != NULL) {
43899a2dd95SBruce Richardson rte_errno = EEXIST;
43999a2dd95SBruce Richardson goto exit;
44099a2dd95SBruce Richardson }
44199a2dd95SBruce Richardson
44299a2dd95SBruce Richardson /* allocate tailq entry */
44399a2dd95SBruce Richardson te = rte_zmalloc("RIB_TAILQ_ENTRY", sizeof(*te), 0);
444eeab353bSStephen Hemminger if (unlikely(te == NULL)) {
445ae67895bSDavid Marchand RIB_LOG(ERR,
446ae67895bSDavid Marchand "Can not allocate tailq entry for RIB %s", name);
44799a2dd95SBruce Richardson rte_errno = ENOMEM;
44899a2dd95SBruce Richardson goto exit;
44999a2dd95SBruce Richardson }
45099a2dd95SBruce Richardson
45199a2dd95SBruce Richardson /* Allocate memory to store the RIB data structures. */
45299a2dd95SBruce Richardson rib = rte_zmalloc_socket(mem_name,
45399a2dd95SBruce Richardson sizeof(struct rte_rib), RTE_CACHE_LINE_SIZE, socket_id);
454eeab353bSStephen Hemminger if (unlikely(rib == NULL)) {
455ae67895bSDavid Marchand RIB_LOG(ERR, "RIB %s memory allocation failed", name);
45699a2dd95SBruce Richardson rte_errno = ENOMEM;
45799a2dd95SBruce Richardson goto free_te;
45899a2dd95SBruce Richardson }
45999a2dd95SBruce Richardson
46099a2dd95SBruce Richardson rte_strlcpy(rib->name, name, sizeof(rib->name));
46199a2dd95SBruce Richardson rib->tree = NULL;
46299a2dd95SBruce Richardson rib->max_nodes = conf->max_nodes;
46399a2dd95SBruce Richardson rib->node_pool = node_pool;
46499a2dd95SBruce Richardson te->data = (void *)rib;
46599a2dd95SBruce Richardson TAILQ_INSERT_TAIL(rib_list, te, next);
46699a2dd95SBruce Richardson
46799a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock();
46899a2dd95SBruce Richardson
46999a2dd95SBruce Richardson return rib;
47099a2dd95SBruce Richardson
47199a2dd95SBruce Richardson free_te:
47299a2dd95SBruce Richardson rte_free(te);
47399a2dd95SBruce Richardson exit:
47499a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock();
47599a2dd95SBruce Richardson rte_mempool_free(node_pool);
47699a2dd95SBruce Richardson
47799a2dd95SBruce Richardson return NULL;
47899a2dd95SBruce Richardson }
47999a2dd95SBruce Richardson
48099a2dd95SBruce Richardson struct rte_rib *
rte_rib_find_existing(const char * name)48199a2dd95SBruce Richardson rte_rib_find_existing(const char *name)
48299a2dd95SBruce Richardson {
48399a2dd95SBruce Richardson struct rte_rib *rib = NULL;
48499a2dd95SBruce Richardson struct rte_tailq_entry *te;
48599a2dd95SBruce Richardson struct rte_rib_list *rib_list;
48699a2dd95SBruce Richardson
48799a2dd95SBruce Richardson rib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);
48899a2dd95SBruce Richardson
48999a2dd95SBruce Richardson rte_mcfg_tailq_read_lock();
49099a2dd95SBruce Richardson TAILQ_FOREACH(te, rib_list, next) {
49199a2dd95SBruce Richardson rib = (struct rte_rib *) te->data;
49299a2dd95SBruce Richardson if (strncmp(name, rib->name, RTE_RIB_NAMESIZE) == 0)
49399a2dd95SBruce Richardson break;
49499a2dd95SBruce Richardson }
49599a2dd95SBruce Richardson rte_mcfg_tailq_read_unlock();
49699a2dd95SBruce Richardson
49799a2dd95SBruce Richardson if (te == NULL) {
49899a2dd95SBruce Richardson rte_errno = ENOENT;
49999a2dd95SBruce Richardson return NULL;
50099a2dd95SBruce Richardson }
50199a2dd95SBruce Richardson
50299a2dd95SBruce Richardson return rib;
50399a2dd95SBruce Richardson }
50499a2dd95SBruce Richardson
50599a2dd95SBruce Richardson void
rte_rib_free(struct rte_rib * rib)50699a2dd95SBruce Richardson rte_rib_free(struct rte_rib *rib)
50799a2dd95SBruce Richardson {
50899a2dd95SBruce Richardson struct rte_tailq_entry *te;
50999a2dd95SBruce Richardson struct rte_rib_list *rib_list;
51099a2dd95SBruce Richardson struct rte_rib_node *tmp = NULL;
51199a2dd95SBruce Richardson
51299a2dd95SBruce Richardson if (rib == NULL)
51399a2dd95SBruce Richardson return;
51499a2dd95SBruce Richardson
51599a2dd95SBruce Richardson rib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);
51699a2dd95SBruce Richardson
51799a2dd95SBruce Richardson rte_mcfg_tailq_write_lock();
51899a2dd95SBruce Richardson
51999a2dd95SBruce Richardson /* find our tailq entry */
52099a2dd95SBruce Richardson TAILQ_FOREACH(te, rib_list, next) {
52199a2dd95SBruce Richardson if (te->data == (void *)rib)
52299a2dd95SBruce Richardson break;
52399a2dd95SBruce Richardson }
52499a2dd95SBruce Richardson if (te != NULL)
52599a2dd95SBruce Richardson TAILQ_REMOVE(rib_list, te, next);
52699a2dd95SBruce Richardson
52799a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock();
52899a2dd95SBruce Richardson
52999a2dd95SBruce Richardson while ((tmp = rte_rib_get_nxt(rib, 0, 0, tmp,
53099a2dd95SBruce Richardson RTE_RIB_GET_NXT_ALL)) != NULL)
53199a2dd95SBruce Richardson rte_rib_remove(rib, tmp->ip, tmp->depth);
53299a2dd95SBruce Richardson
53399a2dd95SBruce Richardson rte_mempool_free(rib->node_pool);
53499a2dd95SBruce Richardson rte_free(rib);
53599a2dd95SBruce Richardson rte_free(te);
53699a2dd95SBruce Richardson }
537