Replace the per-FIB tbl8 allocation with a common refcounted tbl8 pool (fib_tbl8_pool).
A FIB can either use an internal pool (created transparently from the existing num_tbl8 config parameter) or attach to an external shared pool via the new tbl8_pool config field. The shared pool allows multiple FIB instances (e.g. one per VRF) to draw tbl8 groups from the same memory, reducing overall allocation. The pool is refcounted: internal pools start at refcount 1 and are freed when the owning FIB is destroyed. External pools are incremented on FIB attach and decremented on FIB detach; the creator releases its reference via rte_fib_tbl8_pool_free(). The per-FIB RCU defer queue callback is shared across both backends (fib_tbl8_pool_rcu_free_cb). New public API: - rte_fib_tbl8_pool_create() - rte_fib_tbl8_pool_free() Signed-off-by: Maxime Leroy <[email protected]> --- lib/fib/dir24_8.c | 128 ++++++++++--------------------- lib/fib/dir24_8.h | 6 +- lib/fib/fib_tbl8_pool.c | 148 ++++++++++++++++++++++++++++++++++++ lib/fib/fib_tbl8_pool.h | 74 ++++++++++++++++++ lib/fib/meson.build | 5 +- lib/fib/rte_fib.h | 3 + lib/fib/rte_fib6.h | 3 + lib/fib/rte_fib_tbl8_pool.h | 76 ++++++++++++++++++ lib/fib/trie.c | 134 ++++++++++---------------------- lib/fib/trie.h | 6 +- 10 files changed, 394 insertions(+), 189 deletions(-) create mode 100644 lib/fib/fib_tbl8_pool.c create mode 100644 lib/fib/fib_tbl8_pool.h create mode 100644 lib/fib/rte_fib_tbl8_pool.h diff --git a/lib/fib/dir24_8.c b/lib/fib/dir24_8.c index 935eca12c3..b8e588a56a 100644 --- a/lib/fib/dir24_8.c +++ b/lib/fib/dir24_8.c @@ -152,41 +152,18 @@ dir24_8_get_lookup_fn(void *p, enum rte_fib_lookup_type type, bool be_addr) return NULL; } -/* - * Get an index of a free tbl8 from the pool - */ -static inline int32_t -tbl8_get(struct dir24_8_tbl *dp) -{ - if (dp->tbl8_pool_pos == dp->number_tbl8s) - /* no more free tbl8 */ - return -ENOSPC; - - /* next index */ - return dp->tbl8_pool[dp->tbl8_pool_pos++]; -} - -/* - * Put an index of a free tbl8 back to the pool - */ -static inline void -tbl8_put(struct dir24_8_tbl *dp, uint32_t tbl8_ind) -{ - dp->tbl8_pool[--dp->tbl8_pool_pos] = tbl8_ind; -} - static int tbl8_alloc(struct dir24_8_tbl *dp, uint64_t nh) { int64_t tbl8_idx; uint8_t *tbl8_ptr; - tbl8_idx = tbl8_get(dp); + tbl8_idx = fib_tbl8_pool_get(dp->pool); /* If there are no tbl8 groups try to reclaim one. */ if (unlikely(tbl8_idx == -ENOSPC && dp->dq && !rte_rcu_qsbr_dq_reclaim(dp->dq, 1, NULL, NULL, NULL))) - tbl8_idx = tbl8_get(dp); + tbl8_idx = fib_tbl8_pool_get(dp->pool); if (tbl8_idx < 0) return tbl8_idx; @@ -200,24 +177,6 @@ tbl8_alloc(struct dir24_8_tbl *dp, uint64_t nh) return tbl8_idx; } -static void -tbl8_cleanup_and_free(struct dir24_8_tbl *dp, uint64_t tbl8_idx) -{ - uint8_t *ptr = (uint8_t *)dp->tbl8 + (tbl8_idx * FIB_TBL8_GRP_NUM_ENT << dp->nh_sz); - - memset(ptr, 0, FIB_TBL8_GRP_NUM_ENT << dp->nh_sz); - tbl8_put(dp, tbl8_idx); -} - -static void -__rcu_qsbr_free_resource(void *p, void *data, unsigned int n __rte_unused) -{ - struct dir24_8_tbl *dp = p; - uint64_t tbl8_idx = *(uint64_t *)data; - - tbl8_cleanup_and_free(dp, tbl8_idx); -} - static void tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t tbl8_idx) { @@ -276,10 +235,10 @@ tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t tbl8_idx) } if (dp->v == NULL) { - tbl8_cleanup_and_free(dp, tbl8_idx); + fib_tbl8_pool_cleanup_and_free(dp->pool, tbl8_idx); } else if (dp->rcu_mode == RTE_FIB_QSBR_MODE_SYNC) { rte_rcu_qsbr_synchronize(dp->v, RTE_QSBR_THRID_INVALID); - tbl8_cleanup_and_free(dp, tbl8_idx); + fib_tbl8_pool_cleanup_and_free(dp->pool, tbl8_idx); } else { /* RTE_FIB_QSBR_MODE_DQ */ if (rte_rcu_qsbr_dq_enqueue(dp->dq, &tbl8_idx)) FIB_LOG(ERR, "Failed to push QSBR FIFO"); @@ -310,14 +269,14 @@ install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge, uint32_t redge, * needs tbl8 for ledge and redge. */ tbl8_idx = tbl8_alloc(dp, tbl24_tmp); - tmp_tbl8_idx = tbl8_get(dp); + tmp_tbl8_idx = fib_tbl8_pool_get(dp->pool); if (tbl8_idx < 0) return -ENOSPC; else if (tmp_tbl8_idx < 0) { - tbl8_put(dp, tbl8_idx); + fib_tbl8_pool_cleanup_and_free(dp->pool, tbl8_idx); return -ENOSPC; } - tbl8_put(dp, tmp_tbl8_idx); + fib_tbl8_pool_put(dp->pool, tmp_tbl8_idx); /*update dir24 entry with tbl8 index*/ fib_tbl8_write(get_tbl24_p(dp, ledge, dp->nh_sz), (tbl8_idx << 1)| @@ -477,7 +436,7 @@ dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t depth, tmp = rte_rib_get_nxt(rib, ip, 24, NULL, RTE_RIB_GET_NXT_COVER); if ((tmp == NULL) && - (dp->rsvd_tbl8s >= dp->number_tbl8s)) + (dp->rsvd_tbl8s >= dp->pool->num_tbl8s)) return -ENOSPC; } @@ -533,18 +492,13 @@ dir24_8_create(const char *name, int socket_id, struct rte_fib_conf *fib_conf) { char mem_name[DIR24_8_NAMESIZE]; struct dir24_8_tbl *dp; + struct rte_fib_tbl8_pool *pool; uint64_t def_nh; - uint64_t tbl8_sz; - uint32_t num_tbl8; - uint32_t i; enum rte_fib_dir24_8_nh_sz nh_sz; if ((name == NULL) || (fib_conf == NULL) || (fib_conf->dir24_8.nh_sz < RTE_FIB_DIR24_8_1B) || (fib_conf->dir24_8.nh_sz > RTE_FIB_DIR24_8_8B) || - (fib_conf->dir24_8.num_tbl8 > - get_max_nh(fib_conf->dir24_8.nh_sz)) || - (fib_conf->dir24_8.num_tbl8 == 0) || (fib_conf->default_nh > get_max_nh(fib_conf->dir24_8.nh_sz))) { rte_errno = EINVAL; @@ -553,46 +507,47 @@ dir24_8_create(const char *name, int socket_id, struct rte_fib_conf *fib_conf) def_nh = fib_conf->default_nh; nh_sz = fib_conf->dir24_8.nh_sz; - num_tbl8 = fib_conf->dir24_8.num_tbl8; + + if (fib_conf->dir24_8.tbl8_pool != NULL) { + /* External shared pool */ + pool = fib_conf->dir24_8.tbl8_pool; + if (pool->nh_sz != nh_sz) { + rte_errno = EINVAL; + return NULL; + } + fib_tbl8_pool_ref(pool); + } else { + /* Internal pool */ + if ((fib_conf->dir24_8.num_tbl8 > + get_max_nh(fib_conf->dir24_8.nh_sz)) || + (fib_conf->dir24_8.num_tbl8 == 0)) { + rte_errno = EINVAL; + return NULL; + } + struct rte_fib_tbl8_pool_conf pool_conf = { + .num_tbl8 = fib_conf->dir24_8.num_tbl8, + .nh_sz = nh_sz, + .socket_id = socket_id, + }; + pool = rte_fib_tbl8_pool_create(name, &pool_conf); + if (pool == NULL) + return NULL; + } snprintf(mem_name, sizeof(mem_name), "DP_%s", name); dp = rte_zmalloc_socket(name, sizeof(struct dir24_8_tbl) + DIR24_8_TBL24_NUM_ENT * (1 << nh_sz) + sizeof(uint32_t), RTE_CACHE_LINE_SIZE, socket_id); if (dp == NULL) { + fib_tbl8_pool_unref(pool); rte_errno = ENOMEM; return NULL; } - snprintf(mem_name, sizeof(mem_name), "TBL8_%p", dp); - tbl8_sz = FIB_TBL8_GRP_NUM_ENT * (1ULL << nh_sz) * - (num_tbl8 + 1); - dp->tbl8 = rte_zmalloc_socket(mem_name, tbl8_sz, - RTE_CACHE_LINE_SIZE, socket_id); - if (dp->tbl8 == NULL) { - rte_errno = ENOMEM; - rte_free(dp); - return NULL; - } + dp->pool = pool; + dp->tbl8 = pool->tbl8; dp->def_nh = def_nh; dp->nh_sz = nh_sz; - dp->number_tbl8s = num_tbl8; - - snprintf(mem_name, sizeof(mem_name), "TBL8_idxes_%p", dp); - dp->tbl8_pool = rte_zmalloc_socket(mem_name, - sizeof(uint32_t) * dp->number_tbl8s, - RTE_CACHE_LINE_SIZE, socket_id); - if (dp->tbl8_pool == NULL) { - rte_errno = ENOMEM; - rte_free(dp->tbl8); - rte_free(dp); - return NULL; - } - - /* Init pool with all tbl8 indices free */ - for (i = 0; i < dp->number_tbl8s; i++) - dp->tbl8_pool[i] = i; - dp->tbl8_pool_pos = 0; /* Init table with default value */ fib_tbl8_write(dp->tbl24, (def_nh << 1), nh_sz, 1 << 24); @@ -606,8 +561,7 @@ dir24_8_free(void *p) struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p; rte_rcu_qsbr_dq_delete(dp->dq); - rte_free(dp->tbl8_pool); - rte_free(dp->tbl8); + fib_tbl8_pool_unref(dp->pool); rte_free(dp); } @@ -639,8 +593,8 @@ dir24_8_rcu_qsbr_add(struct dir24_8_tbl *dp, struct rte_fib_rcu_config *cfg, if (params.max_reclaim_size == 0) params.max_reclaim_size = RTE_FIB_RCU_DQ_RECLAIM_MAX; params.esize = sizeof(uint64_t); - params.free_fn = __rcu_qsbr_free_resource; - params.p = dp; + params.free_fn = fib_tbl8_pool_rcu_free_cb; + params.p = dp->pool; params.v = cfg->v; dp->dq = rte_rcu_qsbr_dq_create(¶ms); if (dp->dq == NULL) { diff --git a/lib/fib/dir24_8.h b/lib/fib/dir24_8.h index e75bd120ad..287b91ef4b 100644 --- a/lib/fib/dir24_8.h +++ b/lib/fib/dir24_8.h @@ -14,7 +14,7 @@ #include <rte_branch_prediction.h> #include <rte_rcu_qsbr.h> -#include "fib_tbl8.h" +#include "fib_tbl8_pool.h" /** * @file @@ -26,9 +26,7 @@ #define DIR24_8_TBL24_MASK 0xffffff00 struct dir24_8_tbl { - uint32_t number_tbl8s; /**< Total number of tbl8s */ uint32_t rsvd_tbl8s; /**< Number of reserved tbl8s */ - uint32_t tbl8_pool_pos; /**< Next free index in pool */ enum rte_fib_dir24_8_nh_sz nh_sz; /**< Size of nexthop entry */ /* RCU config. */ enum rte_fib_qsbr_mode rcu_mode;/* Blocking, defer queue. */ @@ -36,7 +34,7 @@ struct dir24_8_tbl { struct rte_rcu_qsbr_dq *dq; /* RCU QSBR defer queue. */ uint64_t def_nh; /**< Default next hop */ uint64_t *tbl8; /**< tbl8 table. */ - uint32_t *tbl8_pool; /**< Stack of free tbl8 indices */ + struct rte_fib_tbl8_pool *pool; /**< tbl8 pool */ /* tbl24 table. */ alignas(RTE_CACHE_LINE_SIZE) uint64_t tbl24[]; }; diff --git a/lib/fib/fib_tbl8_pool.c b/lib/fib/fib_tbl8_pool.c new file mode 100644 index 0000000000..5f8ba74219 --- /dev/null +++ b/lib/fib/fib_tbl8_pool.c @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2026 Maxime Leroy, Free Mobile + */ + +#include <stdint.h> +#include <string.h> + +#include <eal_export.h> +#include <rte_debug.h> +#include <rte_errno.h> +#include <rte_malloc.h> + +#include "fib_tbl8_pool.h" + +static void +pool_init_free_list(struct rte_fib_tbl8_pool *pool) +{ + uint32_t i; + + /* put entire range of indexes to the tbl8 pool */ + for (i = 0; i < pool->num_tbl8s; i++) + pool->free_list[i] = i; + + pool->cur_tbl8s = 0; +} + +int32_t +fib_tbl8_pool_get(struct rte_fib_tbl8_pool *pool) +{ + if (pool->cur_tbl8s == pool->num_tbl8s) + /* no more free tbl8 */ + return -ENOSPC; + + /* next index */ + return pool->free_list[pool->cur_tbl8s++]; +} + +void +fib_tbl8_pool_put(struct rte_fib_tbl8_pool *pool, uint32_t idx) +{ + RTE_ASSERT(pool->cur_tbl8s > 0); + pool->free_list[--pool->cur_tbl8s] = idx; +} + +void +fib_tbl8_pool_cleanup_and_free(struct rte_fib_tbl8_pool *pool, uint64_t idx) +{ + uint8_t *ptr = (uint8_t *)pool->tbl8 + + ((idx * FIB_TBL8_GRP_NUM_ENT) << pool->nh_sz); + + memset(ptr, 0, FIB_TBL8_GRP_NUM_ENT << pool->nh_sz); + fib_tbl8_pool_put(pool, idx); +} + +void +fib_tbl8_pool_rcu_free_cb(void *p, void *data, + unsigned int n __rte_unused) +{ + struct rte_fib_tbl8_pool *pool = p; + uint64_t tbl8_idx = *(uint64_t *)data; + + fib_tbl8_pool_cleanup_and_free(pool, tbl8_idx); +} + +void +fib_tbl8_pool_ref(struct rte_fib_tbl8_pool *pool) +{ + pool->refcnt++; +} + +static void +pool_free(struct rte_fib_tbl8_pool *pool) +{ + rte_free(pool->free_list); + rte_free(pool->tbl8); + rte_free(pool); +} + +void +fib_tbl8_pool_unref(struct rte_fib_tbl8_pool *pool) +{ + if (--pool->refcnt == 0) + pool_free(pool); +} + +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_fib_tbl8_pool_create, 26.07) +struct rte_fib_tbl8_pool * +rte_fib_tbl8_pool_create(const char *name, + const struct rte_fib_tbl8_pool_conf *conf) +{ + struct rte_fib_tbl8_pool *pool; + char mem_name[64]; + + if (name == NULL || conf == NULL || conf->num_tbl8 == 0 || + conf->nh_sz > 3) { + rte_errno = EINVAL; + return NULL; + } + + snprintf(mem_name, sizeof(mem_name), "TBL8_POOL_%s", name); + pool = rte_zmalloc_socket(mem_name, sizeof(*pool), + RTE_CACHE_LINE_SIZE, conf->socket_id); + if (pool == NULL) { + rte_errno = ENOMEM; + return NULL; + } + + pool->nh_sz = conf->nh_sz; + pool->num_tbl8s = conf->num_tbl8; + pool->socket_id = conf->socket_id; + pool->refcnt = 1; + + snprintf(mem_name, sizeof(mem_name), "TBL8_%s", name); + pool->tbl8 = rte_zmalloc_socket(mem_name, + FIB_TBL8_GRP_NUM_ENT * (1ULL << pool->nh_sz) * + (pool->num_tbl8s + 1), + RTE_CACHE_LINE_SIZE, conf->socket_id); + if (pool->tbl8 == NULL) { + rte_errno = ENOMEM; + rte_free(pool); + return NULL; + } + + snprintf(mem_name, sizeof(mem_name), "TBL8_FL_%s", name); + pool->free_list = rte_zmalloc_socket(mem_name, + sizeof(uint32_t) * pool->num_tbl8s, + RTE_CACHE_LINE_SIZE, conf->socket_id); + if (pool->free_list == NULL) { + rte_errno = ENOMEM; + rte_free(pool->tbl8); + rte_free(pool); + return NULL; + } + + pool_init_free_list(pool); + + return pool; +} + +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_fib_tbl8_pool_free, 26.07) +void +rte_fib_tbl8_pool_free(struct rte_fib_tbl8_pool *pool) +{ + if (pool == NULL) + return; + + fib_tbl8_pool_unref(pool); +} diff --git a/lib/fib/fib_tbl8_pool.h b/lib/fib/fib_tbl8_pool.h new file mode 100644 index 0000000000..285f06d87f --- /dev/null +++ b/lib/fib/fib_tbl8_pool.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2026 Maxime Leroy, Free Mobile + */ + +#ifndef _FIB_TBL8_POOL_H_ +#define _FIB_TBL8_POOL_H_ + +/** + * @file + * Internal tbl8 pool header. + * + * The pool is not thread-safe. When multiple FIBs share a pool, + * all operations (route modifications, FIB creation/destruction) + * must be serialized by the caller. + */ + +#include <stdint.h> +#include <string.h> + +#include <rte_common.h> + +#include "fib_tbl8.h" +#include "rte_fib_tbl8_pool.h" + +struct rte_fib_tbl8_pool { + uint64_t *tbl8; /**< tbl8 group array */ + uint32_t *free_list; /**< Stack of free group indices */ + uint32_t cur_tbl8s; /**< Number of allocated groups */ + uint32_t num_tbl8s; /**< Total number of tbl8 groups */ + uint8_t nh_sz; /**< Nexthop entry size (0-3) */ + int socket_id; + uint32_t refcnt; /**< Reference count */ +}; + +/** + * Get a free tbl8 group index from the pool. + * @return index on success, -ENOSPC if pool is full + */ +int32_t +fib_tbl8_pool_get(struct rte_fib_tbl8_pool *pool); + +/** + * Return a tbl8 group index to the pool. + */ +void +fib_tbl8_pool_put(struct rte_fib_tbl8_pool *pool, uint32_t idx); + +/** + * Clear a tbl8 group and return its index to the pool. + */ +void +fib_tbl8_pool_cleanup_and_free(struct rte_fib_tbl8_pool *pool, uint64_t idx); + +/** + * RCU defer queue callback for tbl8 group reclamation. + * Shared by dir24_8 and trie backends. + * Use as params.free_fn with params.p = pool. + */ +void +fib_tbl8_pool_rcu_free_cb(void *p, void *data, unsigned int n); + +/** + * Increment pool reference count. + */ +void +fib_tbl8_pool_ref(struct rte_fib_tbl8_pool *pool); + +/** + * Decrement pool reference count. Free the pool if it reaches 0. + */ +void +fib_tbl8_pool_unref(struct rte_fib_tbl8_pool *pool); + +#endif /* _FIB_TBL8_POOL_H_ */ diff --git a/lib/fib/meson.build b/lib/fib/meson.build index 573fc50ff1..6ecd954b26 100644 --- a/lib/fib/meson.build +++ b/lib/fib/meson.build @@ -2,8 +2,9 @@ # Copyright(c) 2018 Vladimir Medvedkin <[email protected]> # Copyright(c) 2019 Intel Corporation -sources = files('rte_fib.c', 'rte_fib6.c', 'dir24_8.c', 'trie.c') -headers = files('rte_fib.h', 'rte_fib6.h') +sources = files('rte_fib.c', 'rte_fib6.c', 'dir24_8.c', 'trie.c', + 'fib_tbl8_pool.c') +headers = files('rte_fib.h', 'rte_fib6.h', 'rte_fib_tbl8_pool.h') deps += ['rib'] deps += ['rcu'] deps += ['net'] diff --git a/lib/fib/rte_fib.h b/lib/fib/rte_fib.h index b16a653535..b8c86566ad 100644 --- a/lib/fib/rte_fib.h +++ b/lib/fib/rte_fib.h @@ -19,6 +19,7 @@ #include <rte_common.h> #include <rte_rcu_qsbr.h> +#include <rte_fib_tbl8_pool.h> #ifdef __cplusplus extern "C" { @@ -107,6 +108,8 @@ struct rte_fib_conf { struct { enum rte_fib_dir24_8_nh_sz nh_sz; uint32_t num_tbl8; + /** Shared tbl8 pool (NULL = internal pool) */ + struct rte_fib_tbl8_pool *tbl8_pool; } dir24_8; }; unsigned int flags; /**< Optional feature flags from RTE_FIB_F_* */ diff --git a/lib/fib/rte_fib6.h b/lib/fib/rte_fib6.h index 4527328bf0..655a4c9501 100644 --- a/lib/fib/rte_fib6.h +++ b/lib/fib/rte_fib6.h @@ -20,6 +20,7 @@ #include <rte_common.h> #include <rte_ip6.h> #include <rte_rcu_qsbr.h> +#include <rte_fib_tbl8_pool.h> #ifdef __cplusplus extern "C" { @@ -95,6 +96,8 @@ struct rte_fib6_conf { struct { enum rte_fib_trie_nh_sz nh_sz; uint32_t num_tbl8; + /** Shared tbl8 pool (NULL = internal pool) */ + struct rte_fib_tbl8_pool *tbl8_pool; } trie; }; }; diff --git a/lib/fib/rte_fib_tbl8_pool.h b/lib/fib/rte_fib_tbl8_pool.h new file mode 100644 index 0000000000..e362efe74b --- /dev/null +++ b/lib/fib/rte_fib_tbl8_pool.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2026 Maxime Leroy, Free Mobile + */ + +#ifndef _RTE_FIB_TBL8_POOL_H_ +#define _RTE_FIB_TBL8_POOL_H_ + +/** + * @file + * Shared tbl8 pool for FIB backends. + * + * A tbl8 pool manages a shared array of tbl8 groups that can be used + * across multiple FIB instances (e.g., one per VRF). + * + * Two modes of operation: + * - Internal pool: set num_tbl8 in the FIB config and leave tbl8_pool + * NULL. The pool is created and destroyed with the FIB. + * - External shared pool: create with rte_fib_tbl8_pool_create(), pass + * the handle via the tbl8_pool config field. Each FIB holds a + * reference; the creator releases its reference with + * rte_fib_tbl8_pool_free(). The pool is freed when the last + * reference is dropped. + * + * Thread safety: none. The pool is not thread-safe. All operations + * on FIBs sharing the same pool (route updates, FIB creation and + * destruction, pool create/free) must be serialized by the caller. + */ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct rte_fib_tbl8_pool; + +/** tbl8 pool configuration */ +struct rte_fib_tbl8_pool_conf { + uint32_t num_tbl8; /**< Number of tbl8 groups */ + uint8_t nh_sz; /**< Nexthop size: 0=1B, 1=2B, 2=4B, 3=8B */ + int socket_id; /**< NUMA socket for memory allocation */ +}; + +/** + * Create a tbl8 pool. + * + * @param name + * Pool name (for memory allocation tracking) + * @param conf + * Pool configuration + * @return + * Pool handle on success, NULL on failure with rte_errno set + */ +__rte_experimental +struct rte_fib_tbl8_pool * +rte_fib_tbl8_pool_create(const char *name, + const struct rte_fib_tbl8_pool_conf *conf); + +/** + * Release the creator's reference on a tbl8 pool. + * + * The pool is freed when the last reference is dropped (i.e. after + * all FIBs using this pool have been destroyed). + * + * @param pool + * Pool handle (NULL is allowed) + */ +__rte_experimental +void +rte_fib_tbl8_pool_free(struct rte_fib_tbl8_pool *pool); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_FIB_TBL8_POOL_H_ */ diff --git a/lib/fib/trie.c b/lib/fib/trie.c index 198fc54395..798d322b1e 100644 --- a/lib/fib/trie.c +++ b/lib/fib/trie.c @@ -99,53 +99,18 @@ trie_get_lookup_fn(void *p, enum rte_fib6_lookup_type type) return NULL; } -static void -tbl8_pool_init(struct rte_trie_tbl *dp) -{ - uint32_t i; - - /* put entire range of indexes to the tbl8 pool */ - for (i = 0; i < dp->number_tbl8s; i++) - dp->tbl8_pool[i] = i; - - dp->tbl8_pool_pos = 0; -} - -/* - * Get an index of a free tbl8 from the pool - */ -static inline int32_t -tbl8_get(struct rte_trie_tbl *dp) -{ - if (dp->tbl8_pool_pos == dp->number_tbl8s) - /* no more free tbl8 */ - return -ENOSPC; - - /* next index */ - return dp->tbl8_pool[dp->tbl8_pool_pos++]; -} - -/* - * Put an index of a free tbl8 back to the pool - */ -static inline void -tbl8_put(struct rte_trie_tbl *dp, uint32_t tbl8_ind) -{ - dp->tbl8_pool[--dp->tbl8_pool_pos] = tbl8_ind; -} - static int tbl8_alloc(struct rte_trie_tbl *dp, uint64_t nh) { int64_t tbl8_idx; uint8_t *tbl8_ptr; - tbl8_idx = tbl8_get(dp); + tbl8_idx = fib_tbl8_pool_get(dp->pool); /* If there are no tbl8 groups try to reclaim one. */ if (unlikely(tbl8_idx == -ENOSPC && dp->dq && !rte_rcu_qsbr_dq_reclaim(dp->dq, 1, NULL, NULL, NULL))) - tbl8_idx = tbl8_get(dp); + tbl8_idx = fib_tbl8_pool_get(dp->pool); if (tbl8_idx < 0) return tbl8_idx; @@ -157,23 +122,6 @@ tbl8_alloc(struct rte_trie_tbl *dp, uint64_t nh) return tbl8_idx; } -static void -tbl8_cleanup_and_free(struct rte_trie_tbl *dp, uint64_t tbl8_idx) -{ - uint8_t *ptr = (uint8_t *)dp->tbl8 + (tbl8_idx * FIB_TBL8_GRP_NUM_ENT << dp->nh_sz); - - memset(ptr, 0, FIB_TBL8_GRP_NUM_ENT << dp->nh_sz); - tbl8_put(dp, tbl8_idx); -} - -static void -__rcu_qsbr_free_resource(void *p, void *data, unsigned int n __rte_unused) -{ - struct rte_trie_tbl *dp = p; - uint64_t tbl8_idx = *(uint64_t *)data; - tbl8_cleanup_and_free(dp, tbl8_idx); -} - static void tbl8_recycle(struct rte_trie_tbl *dp, void *par, uint64_t tbl8_idx) { @@ -223,10 +171,10 @@ tbl8_recycle(struct rte_trie_tbl *dp, void *par, uint64_t tbl8_idx) } if (dp->v == NULL) { - tbl8_cleanup_and_free(dp, tbl8_idx); + fib_tbl8_pool_cleanup_and_free(dp->pool, tbl8_idx); } else if (dp->rcu_mode == RTE_FIB6_QSBR_MODE_SYNC) { rte_rcu_qsbr_synchronize(dp->v, RTE_QSBR_THRID_INVALID); - tbl8_cleanup_and_free(dp, tbl8_idx); + fib_tbl8_pool_cleanup_and_free(dp->pool, tbl8_idx); } else { /* RTE_FIB6_QSBR_MODE_DQ */ if (rte_rcu_qsbr_dq_enqueue(dp->dq, &tbl8_idx)) FIB_LOG(ERR, "Failed to push QSBR FIFO"); @@ -583,7 +531,7 @@ trie_modify(struct rte_fib6 *fib, const struct rte_ipv6_addr *ip, return 0; } - if ((depth > 24) && (dp->rsvd_tbl8s + depth_diff > dp->number_tbl8s)) + if ((depth > 24) && (dp->rsvd_tbl8s + depth_diff > dp->pool->num_tbl8s)) return -ENOSPC; node = rte_rib6_insert(rib, &ip_masked, depth); @@ -636,63 +584,66 @@ trie_create(const char *name, int socket_id, { char mem_name[TRIE_NAMESIZE]; struct rte_trie_tbl *dp = NULL; + struct rte_fib_tbl8_pool *pool; uint64_t def_nh; - uint32_t num_tbl8; enum rte_fib_trie_nh_sz nh_sz; if ((name == NULL) || (conf == NULL) || (conf->trie.nh_sz < RTE_FIB6_TRIE_2B) || (conf->trie.nh_sz > RTE_FIB6_TRIE_8B) || - (conf->trie.num_tbl8 > - get_max_nh(conf->trie.nh_sz)) || - (conf->trie.num_tbl8 == 0) || (conf->default_nh > get_max_nh(conf->trie.nh_sz))) { - rte_errno = EINVAL; return NULL; } def_nh = conf->default_nh; nh_sz = conf->trie.nh_sz; - num_tbl8 = conf->trie.num_tbl8; + + if (conf->trie.tbl8_pool != NULL) { + /* External shared pool: validate nh_sz matches. */ + pool = conf->trie.tbl8_pool; + if (pool->nh_sz != nh_sz) { + rte_errno = EINVAL; + return NULL; + } + fib_tbl8_pool_ref(pool); + } else { + /* Internal pool: create from config. */ + struct rte_fib_tbl8_pool_conf pool_conf = { + .num_tbl8 = conf->trie.num_tbl8, + .nh_sz = nh_sz, + .socket_id = socket_id, + }; + + if (conf->trie.num_tbl8 == 0 || + conf->trie.num_tbl8 > + get_max_nh(nh_sz)) { + rte_errno = EINVAL; + return NULL; + } + + pool = rte_fib_tbl8_pool_create(name, &pool_conf); + if (pool == NULL) + return NULL; + } snprintf(mem_name, sizeof(mem_name), "DP_%s", name); dp = rte_zmalloc_socket(name, sizeof(struct rte_trie_tbl) + TRIE_TBL24_NUM_ENT * (1 << nh_sz) + sizeof(uint32_t), RTE_CACHE_LINE_SIZE, socket_id); if (dp == NULL) { + fib_tbl8_pool_unref(pool); rte_errno = ENOMEM; - return dp; - } - - fib_tbl8_write(&dp->tbl24, (def_nh << 1), nh_sz, 1 << 24); - - snprintf(mem_name, sizeof(mem_name), "TBL8_%p", dp); - dp->tbl8 = rte_zmalloc_socket(mem_name, FIB_TBL8_GRP_NUM_ENT * - (1ll << nh_sz) * (num_tbl8 + 1), - RTE_CACHE_LINE_SIZE, socket_id); - if (dp->tbl8 == NULL) { - rte_errno = ENOMEM; - rte_free(dp); return NULL; } + dp->def_nh = def_nh; dp->nh_sz = nh_sz; - dp->number_tbl8s = num_tbl8; + dp->pool = pool; + dp->tbl8 = pool->tbl8; - snprintf(mem_name, sizeof(mem_name), "TBL8_idxes_%p", dp); - dp->tbl8_pool = rte_zmalloc_socket(mem_name, - sizeof(uint32_t) * dp->number_tbl8s, - RTE_CACHE_LINE_SIZE, socket_id); - if (dp->tbl8_pool == NULL) { - rte_errno = ENOMEM; - rte_free(dp->tbl8); - rte_free(dp); - return NULL; - } - - tbl8_pool_init(dp); + fib_tbl8_write(&dp->tbl24, (def_nh << 1), nh_sz, 1 << 24); return dp; } @@ -703,8 +654,7 @@ trie_free(void *p) struct rte_trie_tbl *dp = (struct rte_trie_tbl *)p; rte_rcu_qsbr_dq_delete(dp->dq); - rte_free(dp->tbl8_pool); - rte_free(dp->tbl8); + fib_tbl8_pool_unref(dp->pool); rte_free(dp); } @@ -735,8 +685,8 @@ trie_rcu_qsbr_add(struct rte_trie_tbl *dp, struct rte_fib6_rcu_config *cfg, if (params.max_reclaim_size == 0) params.max_reclaim_size = RTE_FIB6_RCU_DQ_RECLAIM_MAX; params.esize = sizeof(uint64_t); - params.free_fn = __rcu_qsbr_free_resource; - params.p = dp; + params.free_fn = fib_tbl8_pool_rcu_free_cb; + params.p = dp->pool; params.v = cfg->v; dp->dq = rte_rcu_qsbr_dq_create(¶ms); if (dp->dq == NULL) { diff --git a/lib/fib/trie.h b/lib/fib/trie.h index 30fa886792..61df56b1bb 100644 --- a/lib/fib/trie.h +++ b/lib/fib/trie.h @@ -11,7 +11,7 @@ #include <rte_common.h> #include <rte_fib6.h> -#include "fib_tbl8.h" +#include "fib_tbl8_pool.h" /** * @file @@ -26,13 +26,11 @@ #define TRIE_EXT_ENT 1 struct rte_trie_tbl { - uint32_t number_tbl8s; /**< Total number of tbl8s */ uint32_t rsvd_tbl8s; /**< Number of reserved tbl8s */ uint64_t def_nh; /**< Default next hop */ enum rte_fib_trie_nh_sz nh_sz; /**< Size of nexthop entry */ uint64_t *tbl8; /**< tbl8 table. */ - uint32_t *tbl8_pool; /**< bitmap containing free tbl8 idxes*/ - uint32_t tbl8_pool_pos; + struct rte_fib_tbl8_pool *pool; /**< tbl8 pool */ /* RCU config. */ enum rte_fib6_qsbr_mode rcu_mode; /**< Blocking, defer queue. */ struct rte_rcu_qsbr *v; /**< RCU QSBR variable. */ -- 2.43.0

