[dpdk-dev] [PATCH v3 1/2] Add RIB library

Bruce Richardson bruce.richardson at intel.com
Thu Mar 15 15:27:09 CET 2018


On Thu, Feb 22, 2018 at 10:50:55PM +0000, Medvedkin Vladimir wrote:
> RIB is an alternative to current LPM library.
> It solves the following problems
>  - Increases the speed of control plane operations against lpm such as
>    adding/deleting routes
>  - Adds abstraction from dataplane algorithms, so it is possible to add
>    different ip route lookup algorythms such as DXR/poptrie/lpc-trie/etc
>    in addition to current dir24_8
>  - It is possible to keep user defined application specific additional
>    information in struct rte_rib_node which represents route entry.
>    It can be next hop/set of next hops (i.e. active and feasible),
>    pointers to link rte_rib_node based on some criteria (i.e. next_hop),
>    plenty of additional control plane information.
>  - For dir24_8 implementation it is possible to remove
>    rte_lpm_tbl_entry.depth field that helps to save 6 bits.
>  - Also new dir24_8 implementation supports different next_hop sizes
>    (1/2/4/8 bytes per next hop)
>  - Removed RTE_LPM_LOOKUP_SUCCESS to save 1 bit and to eleminate
>    ternary operator.
>    Instead it returns special default value if there is no route.
> 
> Signed-off-by: Medvedkin Vladimir <medvedkinv at gmail.com>

More comments inline below. Mostly for rte_rib.c file.

/Bruce

> ---
>  config/common_base                 |   6 +
>  doc/api/doxy-api.conf              |   1 +
>  lib/Makefile                       |   2 +
>  lib/librte_rib/Makefile            |  23 ++

Don't forget meson.build file too, to build with meson and ninja. [Strongly
recommend it for your day-to-day development work too, incremental builds
are much, much faster using ninja].

>  lib/librte_rib/rte_dir24_8.c       | 482 +++++++++++++++++++++++++++++++++
>  lib/librte_rib/rte_dir24_8.h       | 115 ++++++++
>  lib/librte_rib/rte_rib.c           | 526 +++++++++++++++++++++++++++++++++++++
>  lib/librte_rib/rte_rib.h           | 322 +++++++++++++++++++++++
>  lib/librte_rib/rte_rib_version.map |  18 ++
>  mk/rte.app.mk                      |   1 +
>  10 files changed, 1496 insertions(+)
>  create mode 100644 lib/librte_rib/Makefile
>  create mode 100644 lib/librte_rib/rte_dir24_8.c
>  create mode 100644 lib/librte_rib/rte_dir24_8.h
>  create mode 100644 lib/librte_rib/rte_rib.c
>  create mode 100644 lib/librte_rib/rte_rib.h
>  create mode 100644 lib/librte_rib/rte_rib_version.map
> 
> diff --git a/config/common_base b/config/common_base
> index ad03cf4..aceeff5 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -679,6 +679,12 @@ CONFIG_RTE_LIBRTE_LPM=y
>  CONFIG_RTE_LIBRTE_LPM_DEBUG=n
>  
>  #
> +# Compile librte_rib
> +#
> +CONFIG_RTE_LIBRTE_RIB=y
> +CONFIG_RTE_LIBRTE_RIB_DEBUG=n
> +
> +#
>  # Compile librte_acl
>  #
>  CONFIG_RTE_LIBRTE_ACL=y
> diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
> index cda52fd..8e4f969 100644
> --- a/doc/api/doxy-api.conf
> +++ b/doc/api/doxy-api.conf
> @@ -60,6 +60,7 @@ INPUT                   = doc/api/doxy-api-index.md \
>                            lib/librte_kvargs \
>                            lib/librte_latencystats \
>                            lib/librte_lpm \
> +                          lib/librte_rib \
>                            lib/librte_mbuf \
>                            lib/librte_member \
>                            lib/librte_mempool \
> diff --git a/lib/Makefile b/lib/Makefile
> index ec965a6..e4faf10 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -43,6 +43,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_EFD) += librte_efd
>  DEPDIRS-librte_efd := librte_eal librte_ring librte_hash
>  DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
>  DEPDIRS-librte_lpm := librte_eal
> +DIRS-$(CONFIG_RTE_LIBRTE_RIB) += librte_rib
> +DEPDIRS-librte_rib := librte_eal librte_mempool
>  DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
>  DEPDIRS-librte_acl := librte_eal
>  DIRS-$(CONFIG_RTE_LIBRTE_MEMBER) += librte_member
> diff --git a/lib/librte_rib/Makefile b/lib/librte_rib/Makefile
> new file mode 100644
> index 0000000..f6431b6
> --- /dev/null
> +++ b/lib/librte_rib/Makefile
> @@ -0,0 +1,23 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Vladimir Medvedkin <medvedkinv at gmail.com>
> +
> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +# library name
> +LIB = librte_rib.a
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)
> +LDLIBS += -lrte_eal -lrte_mempool
> +
> +EXPORT_MAP := rte_rib_version.map
> +
> +LIBABIVER := 1
> +
> +# all source are stored in SRCS-y
> +SRCS-$(CONFIG_RTE_LIBRTE_RIB) := rte_rib.c rte_dir24_8.c
> +
> +# install this header file
> +SYMLINK-$(CONFIG_RTE_LIBRTE_RIB)-include := rte_rib.h rte_dir24_8.h
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_rib/rte_dir24_8.c b/lib/librte_rib/rte_dir24_8.c
> new file mode 100644
> index 0000000..2fc55fe
> --- /dev/null
> +++ b/lib/librte_rib/rte_dir24_8.c

For future patches, it would be good if you can split the dir24_8 code into
a separate patch from the main rib code. The more you can split it into
separate patch blocks, the easier it is to review.

> @@ -0,0 +1,482 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv at gmail.com>
> + */

<snip>

> diff --git a/lib/librte_rib/rte_rib.c b/lib/librte_rib/rte_rib.c
> new file mode 100644
> index 0000000..7783b23
> --- /dev/null
> +++ b/lib/librte_rib/rte_rib.c
> @@ -0,0 +1,526 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv at gmail.com>
> + */
> +
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <sys/queue.h>
> +
> +#include <rte_eal.h>
> +#include <rte_eal_memconfig.h>
> +#include <rte_common.h>
> +#include <rte_tailq.h>
> +#include <rte_errno.h>
> +#include <rte_rwlock.h>
> +#include <rte_memory.h>
> +#include <rte_memzone.h>
> +#include <rte_mempool.h>
> +#include <rte_malloc.h>
> +#include <rte_log.h>
> +
> +#include <rte_rib.h>
> +#include <rte_dir24_8.h>
> +
> +TAILQ_HEAD(rte_rib_list, rte_tailq_entry);
> +static struct rte_tailq_elem rte_rib_tailq = {
> +	.name = "RTE_RIB",
> +};
> +EAL_REGISTER_TAILQ(rte_rib_tailq)
> +
> +static struct rte_rib_node *
> +new_node_malloc(struct rte_rib *rib)
> +{
> +	struct rte_rib_node *ent;
> +
> +	ent =  malloc(rib->node_sz);
> +	if (unlikely(ent == NULL))
> +		return NULL;
> +	++rib->cur_nodes;
> +	return ent;
> +}
> +
> +static void
> +free_node_malloc(__rte_unused struct rte_rib *rib, struct rte_rib_node *ent)
> +{
> +	--rib->cur_nodes;
> +	free(ent);
> +}
> +
> +static struct rte_rib_node *
> +new_node_mempool(struct rte_rib *rib)
> +{
> +	struct rte_rib_node *ent;
> +	int ret;
> +
> +	ret = rte_mempool_get(rib->node_pool, (void *)&ent);
> +	if (unlikely(ret != 0))
> +		return NULL;
> +	++rib->cur_nodes;
> +	return ent;
> +}
> +
> +static void
> +free_node_mempool(struct rte_rib *rib, struct rte_rib_node *ent)
> +{
> +	--rib->cur_nodes;
> +	rte_mempool_put(rib->node_pool, ent);
> +}
> +
> +struct rte_rib_node *
> +rte_rib_tree_lookup(struct rte_rib *rib, uint32_t key)
> +{
> +	struct rte_rib_node *cur = rib->trie;
> +	struct rte_rib_node *prev = NULL;
> +
> +	while ((cur != NULL) && (((cur->key ^ key) &
> +		(uint32_t)(UINT64_MAX << (32 - cur->depth))) == 0)) {
> +		if ((cur->flag & RTE_RIB_VALID_NODE) == RTE_RIB_VALID_NODE)
> +			prev = cur;
> +		cur = RTE_RIB_GET_NXT_NODE(cur, key);
> +	}
> +	return prev;
> +}
> +
> +struct rte_rib_node *
> +rte_rib_tree_lookup_parent(struct rte_rib_node *ent)
> +{
> +	struct rte_rib_node *tmp;
> +
> +	if (ent == NULL)
> +		return NULL;
> +	tmp = ent->parent;
> +	while ((tmp != NULL) &&
> +		(tmp->flag & RTE_RIB_VALID_NODE) != RTE_RIB_VALID_NODE) {
> +		tmp = tmp->parent;
> +}
Watch indentation here. The close brace obviously needs an indent, and the
line continuation of while should have different indent to body. Coding
standards suggest double indent on the continuation, ie. two tabs before
"(tmp->flag".

> +	return tmp;
> +}
> +
> +struct rte_rib_node *
> +rte_rib_tree_lookup_exact(struct rte_rib *rib, uint32_t key, uint8_t depth)
> +{
> +	struct rte_rib_node *cur = rib->trie;
> +
> +	key &= (uint32_t)(UINT64_MAX << (32 - depth));
This mask generation seems a common idiom. Maybe make an inline fn or macro
out of it.

> +	while (cur != NULL) {
> +		if ((cur->key == key) && (cur->depth == depth) &&
> +				(cur->flag & RTE_RIB_VALID_NODE))
> +			return cur;
> +		if ((cur->depth > depth) ||
> +				(((uint64_t)key >> (32 - cur->depth)) !=
> +				((uint64_t)cur->key >> (32 - cur->depth))))
> +			break;
> +		cur = RTE_RIB_GET_NXT_NODE(cur, key);
> +	}
> +	return NULL;
> +}
> +
> +struct rte_rib_node *
> +rte_rib_tree_get_nxt(struct rte_rib *rib, uint32_t key,
> +	uint8_t depth, struct rte_rib_node *cur, int flag)
> +{
> +	struct rte_rib_node *tmp, *prev = NULL;
> +
> +	if (cur == NULL) {
> +		tmp = rib->trie;
> +		while ((tmp) && (tmp->depth < depth))
> +			tmp = RTE_RIB_GET_NXT_NODE(tmp, key);
> +	} else {
> +		tmp = cur;
> +		while ((tmp->parent != NULL) && (RTE_RIB_IS_RIGHT_NODE(tmp) ||
> +				(tmp->parent->right == NULL))) {
> +			tmp = tmp->parent;
> +			if ((tmp->flag & RTE_RIB_VALID_NODE) &&
> +				(RTE_RIB_IS_COVERED(tmp->key, tmp->depth,
> +					key, depth)))
> +				return tmp;
> +		}
> +		tmp = (tmp->parent) ? tmp->parent->right : NULL;
> +	}
> +	while (tmp) {
> +		if ((tmp->flag & RTE_RIB_VALID_NODE) &&
> +			(RTE_RIB_IS_COVERED(tmp->key, tmp->depth,
> +				key, depth))) {
> +			prev = tmp;
> +			if (flag == RTE_RIB_GET_NXT_COVER)
> +				return prev;
> +		}
> +		tmp = (tmp->left) ? tmp->left : tmp->right;
> +	}
> +	return prev;
> +}

I think this function could do with some comments explaining the logic
behind it.

> +
> +void
> +rte_rib_tree_remove(struct rte_rib *rib, uint32_t key, uint8_t depth)
> +{
> +	struct rte_rib_node *cur, *prev, *child;
> +
> +	cur = rte_rib_tree_lookup_exact(rib, key, depth);
> +	if (cur == NULL)
> +		return;
> +
> +	--rib->cur_routes;
> +	cur->flag &= ~RTE_RIB_VALID_NODE;
> +	while ((cur->flag & RTE_RIB_VALID_NODE) != RTE_RIB_VALID_NODE) {
> +		if ((cur->left != NULL) && (cur->right != NULL))
> +			return;
> +		child = (cur->left == NULL) ? cur->right : cur->left;
> +		if (child != NULL)
> +			child->parent = cur->parent;
> +		if (cur->parent == NULL) {
> +			rib->trie = child;
> +			rib->free_node(rib, cur);
> +			return;
> +		}
> +		if (cur->parent->left == cur)
> +			cur->parent->left = child;
> +		else
> +			cur->parent->right = child;
> +		prev = cur;
> +		cur = cur->parent;
> +		rib->free_node(rib, prev);
> +	}
> +}
> +
> +struct rte_rib_node *
> +rte_rib_tree_insert(struct rte_rib *rib, uint32_t key, uint8_t depth)
> +{
> +	struct rte_rib_node **tmp = &rib->trie;
> +	struct rte_rib_node *prev = NULL;
> +	struct rte_rib_node *new_node = NULL;
> +	struct rte_rib_node *common_node = NULL;
> +	int i = 0;
> +	uint32_t common_prefix;
> +	uint8_t common_depth;
> +
> +	if (depth > 32) {
> +		rte_errno = EINVAL;
> +		return NULL;
> +	}
> +
> +	key &= (uint32_t)(UINT64_MAX << (32 - depth));
> +	new_node = rte_rib_tree_lookup_exact(rib, key, depth);
> +	if (new_node != NULL) {
> +		rte_errno = EEXIST;
> +		return NULL;
> +	}
> +
> +	new_node = rib->alloc_node(rib);
> +	if (new_node == NULL) {
> +		rte_errno = ENOMEM;
> +		return NULL;
> +	}
> +	new_node->left = NULL;
> +	new_node->right = NULL;
> +	new_node->parent = NULL;
> +	new_node->key = key;
> +	new_node->depth = depth;
> +	new_node->flag = RTE_RIB_VALID_NODE;
> +
> +	while (1) {
> +		if (*tmp == NULL) {
> +			*tmp = new_node;
> +			new_node->parent = prev;
> +		}

I think it would be clearer to have a return in this block, rather than
having fallthrough to the next one.

> +		if ((key == (*tmp)->key) && (depth == (*tmp)->depth)) {
> +			if (new_node != *tmp) {
> +				rib->free_node(rib, new_node);
> +				(*tmp)->flag |= RTE_RIB_VALID_NODE;
> +			}
> +			++rib->cur_routes;
> +			return *tmp;
> +		}

Comment in the above block please. My understanding is that the previous
search just confirmed that there wasn't already a valid entry present for
this new item, but did not report if there was already an invalid entry,
which is what this block is matching.

> +		i = (*tmp)->depth;

I think "d" might be a better choice of name here, rather than "i", which
you expect to be a loop variable.

> +		if ((i >= depth) || (((uint64_t)key >> (32 - i)) !=
> +				((uint64_t)(*tmp)->key >> (32 - i))))
> +			break;
> +		prev = *tmp;
> +		tmp = (key & (1 << (31 - i))) ? &(*tmp)->right : &(*tmp)->left;
> +	}
> +	common_depth = RTE_MIN(depth, (*tmp)->depth);
> +	common_prefix = key ^ (*tmp)->key;
> +	i = __builtin_clz(common_prefix);
> +
> +	common_depth = RTE_MIN(i, common_depth);
> +	common_prefix = key & (uint32_t)(UINT64_MAX << (32 - common_depth));
> +	if ((common_prefix == key) && (common_depth == depth)) {
> +		if ((*tmp)->key & (1 << (31 - depth)))
> +			new_node->right = *tmp;
> +		else
> +			new_node->left = *tmp;
> +		new_node->parent = (*tmp)->parent;
> +		(*tmp)->parent = new_node;
> +		*tmp = new_node;
> +	} else {
> +		common_node = rib->alloc_node(rib);
> +		if (common_node == NULL) {
> +			rib->free_node(rib, new_node);
> +			rte_errno = ENOMEM;
> +			return NULL;
> +		}
> +		common_node->key = common_prefix;
> +		common_node->depth = common_depth;
> +		common_node->flag = 0;
> +		common_node->parent = (*tmp)->parent;
> +		new_node->parent = common_node;
> +		(*tmp)->parent = common_node;
> +		if ((new_node->key & (1 << (31 - common_depth))) == 0) {
> +			common_node->left = new_node;
> +			common_node->right = *tmp;
> +		} else {
> +			common_node->left = *tmp;
> +			common_node->right = new_node;
> +		}
> +		*tmp = common_node;
> +	}

Again some commenting of the logic here would help the reader.

> +	++rib->cur_routes;
> +	return new_node;
> +}
> +
> +struct rte_rib *
> +rte_rib_create(const char *name, int socket_id, struct rte_rib_conf *conf)
> +{
> +	char mem_name[RTE_RIB_NAMESIZE];
> +	struct rte_rib *rib = NULL;
> +	struct rte_tailq_entry *te;
> +	struct rte_rib_list *rib_list;
> +	struct rte_mempool *node_pool = NULL;
> +	enum rte_dir24_8_nh_sz dir24_8_nh_size;
> +
> +	/* Check user arguments. */
> +	if ((name == NULL) || (conf == NULL) || (socket_id < -1) ||
> +			(conf->type >= RTE_RIB_TYPE_MAX) ||
> +			(conf->alloc_type >= RTE_RIB_ALLOC_MAX) ||
> +			(conf->max_nodes == 0) ||
> +			(conf->node_sz < sizeof(struct rte_rib_node))) {
> +		rte_errno = EINVAL;
> +		return NULL;
> +	}
> +
> +	if (conf->alloc_type == RTE_RIB_MEMPOOL) {

Since you are forcing the user always to specify the max number of nodes,
why not always use mempool allocation type? What is the use-case for
malloc-based allocation instead?

> +		snprintf(mem_name, sizeof(mem_name), "MP_%s", name);
> +		node_pool = rte_mempool_create(mem_name, conf->max_nodes,
> +			conf->node_sz, 0, 0, NULL, NULL, NULL, NULL,
> +			socket_id, 0);
> +
> +		if (node_pool == NULL) {
> +			RTE_LOG(ERR, LPM,
> +				"Can not allocate mempool for RIB %s\n", name);
> +			rte_errno = ENOMEM;
> +			return NULL;
> +		}
> +
> +	}
> +
> +	snprintf(mem_name, sizeof(mem_name), "RIB_%s", name);
> +
> +	rib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);
> +
> +	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
> +	/* guarantee there's no existing */
> +	TAILQ_FOREACH(te, rib_list, next) {
> +		rib = (struct rte_rib *)te->data;
> +		if (strncmp(name, rib->name, RTE_RIB_NAMESIZE) == 0)
> +			break;
> +	}
> +	rib = NULL;
> +	if (te != NULL) {
> +		rte_errno = EEXIST;
> +		goto exit;
> +	}
> +
> +	/* allocate tailq entry */
> +	te = rte_zmalloc("RIB_TAILQ_ENTRY", sizeof(*te), 0);
> +	if (te == NULL) {
> +		RTE_LOG(ERR, LPM,
> +			"Can not allocate tailq entry for RIB %s\n", name);
> +		rte_errno = ENOMEM;
> +		goto exit;
> +	}
> +
> +	/* Allocate memory to store the LPM data structures. */
> +	rib = (struct rte_rib *)rte_zmalloc_socket(mem_name,
> +		sizeof(struct rte_rib),	RTE_CACHE_LINE_SIZE, socket_id);
> +	if (rib == NULL) {
> +		RTE_LOG(ERR, LPM, "RIB %s memory allocation failed\n", name);
> +		rte_errno = ENOMEM;
> +		goto free_te;
> +	}
> +	snprintf(rib->name, sizeof(rib->name), "%s", name);
> +	rib->trie = NULL;
> +	rib->max_nodes = conf->max_nodes;
> +	rib->node_sz = conf->node_sz;
> +	rib->type = conf->type;
> +	rib->alloc_type = conf->alloc_type;
> +
> +	if (conf->type <= RTE_RIB_DIR24_8_8B) {
> +		switch (conf->type) {
> +		case RTE_RIB_DIR24_8_1B:
> +			dir24_8_nh_size = RTE_DIR24_8_1B;
> +			rib->lookup = rte_dir24_8_lookup_bulk_1b;
> +			break;
> +		case RTE_RIB_DIR24_8_2B:
> +			dir24_8_nh_size = RTE_DIR24_8_2B;
> +			rib->lookup = rte_dir24_8_lookup_bulk_2b;
> +			break;
> +		case RTE_RIB_DIR24_8_4B:
> +			dir24_8_nh_size = RTE_DIR24_8_4B;
> +			rib->lookup = rte_dir24_8_lookup_bulk_4b;
> +			break;
> +		case RTE_RIB_DIR24_8_8B:
> +			dir24_8_nh_size = RTE_DIR24_8_8B;
> +			rib->lookup = rte_dir24_8_lookup_bulk_8b;
> +			break;
> +		case RTE_RIB_TYPE_MAX:
> +		default:
> +			RTE_LOG(ERR, LPM, "Bad RIB %s type\n", name);
> +			rte_errno = EINVAL;
> +			goto free_rib;
> +		}
> +		rib->fib = (void *)rte_dir24_8_create(name, socket_id,
> +				dir24_8_nh_size, conf->def_nh);
> +		if (rib->fib == NULL) {
> +			RTE_LOG(ERR, LPM, "Failed to allocate FIB %s\n", name);
> +			rte_errno = ENOMEM;
> +			goto free_rib;
> +		}
> +		rib->modify = rte_dir24_8_modify;
> +	}
> +
> +	switch (conf->alloc_type) {
> +	case RTE_RIB_MALLOC:
> +		rib->alloc_node = new_node_malloc;
> +		rib->free_node = free_node_malloc;
> +		break;
> +	case RTE_RIB_MEMPOOL:
> +		rib->node_pool = node_pool;
> +		rib->alloc_node = new_node_mempool;
> +		rib->free_node = free_node_mempool;
> +		break;
> +	case RTE_RIB_ALLOC_MAX:
> +	default:
> +		RTE_LOG(ERR, LPM, "Bad RIB %s alloc type\n", name);
> +		rte_errno = EINVAL;
> +		goto free_fib;
> +	}
> +
> +	te->data = (void *)rib;
> +	TAILQ_INSERT_TAIL(rib_list, te, next);
> +
> +	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
> +
> +	return rib;
> +
> +free_fib:
> +	switch (conf->type) {
> +	case RTE_RIB_DIR24_8_1B:
> +	case RTE_RIB_DIR24_8_2B:
> +	case RTE_RIB_DIR24_8_4B:
> +	case RTE_RIB_DIR24_8_8B:
> +		rte_dir24_8_free(rib->fib);
> +		break;
> +	default:
> +		break;
> +	}
> +free_rib:
> +	rte_free(rib);
> +free_te:
> +	rte_free(te);
> +exit:
> +	if (conf->alloc_type == RTE_RIB_MEMPOOL)
> +		rte_mempool_free(node_pool);
> +	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
> +
> +	return NULL;
> +}
> +
> +struct rte_rib *
> +rte_rib_find_existing(const char *name)
> +{
> +	struct rte_rib *rib = NULL;
> +	struct rte_tailq_entry *te;
> +	struct rte_rib_list *rib_list;
> +
> +	rib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);
> +
> +	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
> +	TAILQ_FOREACH(te, rib_list, next) {
> +		rib = (struct rte_rib *) te->data;
> +		if (strncmp(name, rib->name, RTE_RIB_NAMESIZE) == 0)
> +			break;
> +	}
> +	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
> +
> +	if (te == NULL) {
> +		rte_errno = ENOENT;
> +		return NULL;
> +	}
> +
> +	return rib;
> +}
> +
> +void
> +rte_rib_free(struct rte_rib *rib)
> +{
> +	struct rte_tailq_entry *te;
> +	struct rte_rib_list *rib_list;
> +	struct rte_rib_node *tmp = NULL;
> +
> +	if (rib == NULL)
> +		return;
> +
> +	rib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);
> +
> +	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
> +
> +	/* find our tailq entry */
> +	TAILQ_FOREACH(te, rib_list, next) {
> +		if (te->data == (void *)rib)
> +			break;
> +	}
> +	if (te != NULL)
> +		TAILQ_REMOVE(rib_list, te, next);
> +
> +	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
> +
> +	while ((tmp = rte_rib_tree_get_nxt(rib, 0, 0, tmp,
> +		RTE_RIB_GET_NXT_ALL)) != NULL)
> +		rte_rib_tree_remove(rib, tmp->key, tmp->depth);
> +
> +	if (rib->alloc_type == RTE_RIB_MEMPOOL)
> +		rte_mempool_free(rib->node_pool);
> +
> +	switch (rib->type) {
> +	case RTE_RIB_DIR24_8_1B:
> +	case RTE_RIB_DIR24_8_2B:
> +	case RTE_RIB_DIR24_8_4B:
> +	case RTE_RIB_DIR24_8_8B:
> +		rte_dir24_8_free(rib->fib);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	rte_free(rib);
> +	rte_free(te);
> +}
> +
> +int
> +rte_rib_add(struct rte_rib *rib, uint32_t ip, uint8_t depth, uint64_t next_hop)
> +{
> +	if ((rib == NULL) || (depth > RTE_RIB_MAXDEPTH))
> +		return -EINVAL;
> +
> +	return rib->modify(rib, ip, depth, next_hop, RTE_RIB_ADD);
> +}
> +
> +int
> +rte_rib_delete(struct rte_rib *rib, uint32_t ip, uint8_t depth)
> +{
> +	if ((rib == NULL) || (depth > RTE_RIB_MAXDEPTH))
> +		return -EINVAL;
> +
> +	return rib->modify(rib, ip, depth, 0, RTE_RIB_DEL);
> +}
<snip>


More information about the dev mailing list