46287eacc1
Introduce simple hash list to the mlx5 utilities. User can define its own data structure containing the mlx5_hlist_entry and create the hash list table via the creation interface. Then the entry will be inserted into the table and linked to the corresponding list head. User should guarantee there is no collision of the key and provide a callback function to handle all the remaining entries in the table when destroying the hash list. User should define a proper number of the list heads in the table in order to get a better performance. The LSB of the 'key' is used to calculate the index of the head in the list heads array. This implementation is not multi-threads safe right now. Signed-off-by: Bing Zhao <bingz@mellanox.com> Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
120 lines
2.9 KiB
C
120 lines
2.9 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright 2019 Mellanox Technologies, Ltd
|
|
*/
|
|
|
|
#include <rte_malloc.h>
|
|
#include <rte_hash_crc.h>
|
|
|
|
#include "mlx5_utils.h"
|
|
|
|
struct mlx5_hlist *
|
|
mlx5_hlist_create(const char *name, uint32_t size)
|
|
{
|
|
struct mlx5_hlist *h;
|
|
uint32_t act_size;
|
|
uint32_t alloc_size;
|
|
|
|
if (!size)
|
|
return NULL;
|
|
/* Align to the next power of 2, 32bits integer is enough now. */
|
|
if (!rte_is_power_of_2(size)) {
|
|
act_size = rte_align32pow2(size);
|
|
DRV_LOG(WARNING, "Size 0x%" PRIX32 " is not power of 2, will "
|
|
"be aligned to 0x%" PRIX32 ".\n", size, act_size);
|
|
} else {
|
|
act_size = size;
|
|
}
|
|
alloc_size = sizeof(struct mlx5_hlist) +
|
|
sizeof(struct mlx5_hlist_head) * act_size;
|
|
/* Using zmalloc, then no need to initialize the heads. */
|
|
h = rte_zmalloc(name, alloc_size, RTE_CACHE_LINE_SIZE);
|
|
if (!h) {
|
|
DRV_LOG(ERR, "No memory for hash list %s creation\n",
|
|
name ? name : "None");
|
|
return NULL;
|
|
}
|
|
if (name)
|
|
snprintf(h->name, MLX5_HLIST_NAMESIZE, "%s", name);
|
|
h->table_sz = act_size;
|
|
h->mask = act_size - 1;
|
|
DRV_LOG(DEBUG, "Hash list with %s size 0x%" PRIX32 " is created.\n",
|
|
h->name, act_size);
|
|
return h;
|
|
}
|
|
|
|
struct mlx5_hlist_entry *
|
|
mlx5_hlist_lookup(struct mlx5_hlist *h, uint64_t key)
|
|
{
|
|
uint32_t idx;
|
|
struct mlx5_hlist_head *first;
|
|
struct mlx5_hlist_entry *node;
|
|
|
|
assert(h);
|
|
idx = rte_hash_crc_8byte(key, 0) & h->mask;
|
|
first = &h->heads[idx];
|
|
LIST_FOREACH(node, first, next) {
|
|
if (node->key == key)
|
|
return node;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
mlx5_hlist_insert(struct mlx5_hlist *h, struct mlx5_hlist_entry *entry)
|
|
{
|
|
uint32_t idx;
|
|
struct mlx5_hlist_head *first;
|
|
struct mlx5_hlist_entry *node;
|
|
|
|
assert(h && entry);
|
|
idx = rte_hash_crc_8byte(entry->key, 0) & h->mask;
|
|
first = &h->heads[idx];
|
|
/* No need to reuse the lookup function. */
|
|
LIST_FOREACH(node, first, next) {
|
|
if (node->key == entry->key)
|
|
return -EEXIST;
|
|
}
|
|
LIST_INSERT_HEAD(first, entry, next);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
mlx5_hlist_remove(struct mlx5_hlist *h __rte_unused,
|
|
struct mlx5_hlist_entry *entry)
|
|
{
|
|
assert(entry && entry->next.le_prev);
|
|
LIST_REMOVE(entry, next);
|
|
/* Set to NULL to get rid of removing action for more than once. */
|
|
entry->next.le_prev = NULL;
|
|
}
|
|
|
|
void
|
|
mlx5_hlist_destroy(struct mlx5_hlist *h,
|
|
mlx5_hlist_destroy_callback_fn cb, void *ctx)
|
|
{
|
|
uint32_t idx;
|
|
struct mlx5_hlist_entry *entry;
|
|
|
|
assert(h);
|
|
for (idx = 0; idx < h->table_sz; ++idx) {
|
|
/* no LIST_FOREACH_SAFE, using while instead */
|
|
while (!LIST_EMPTY(&h->heads[idx])) {
|
|
entry = LIST_FIRST(&h->heads[idx]);
|
|
LIST_REMOVE(entry, next);
|
|
/*
|
|
* The owner of whole element which contains data entry
|
|
* is the user, so it's the user's duty to do the clean
|
|
* up and the free work because someone may not put the
|
|
* hlist entry at the beginning(suggested to locate at
|
|
* the beginning). Or else the default free function
|
|
* will be used.
|
|
*/
|
|
if (cb)
|
|
cb(entry, ctx);
|
|
else
|
|
rte_free(entry);
|
|
}
|
|
}
|
|
rte_free(h);
|
|
}
|