xref: /dpdk/lib/rib/rte_rib.c (revision 3401a4afbb54a1b897551847a3e16c36afdf707a)
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