You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
4.2 KiB
197 lines
4.2 KiB
/* |
|
* netlink/hashtable.c Netlink hashtable Utilities |
|
* |
|
* This library is free software; you can redistribute it and/or |
|
* modify it under the terms of the GNU Lesser General Public |
|
* License as published by the Free Software Foundation version 2.1 |
|
* of the License. |
|
* |
|
* Copyright (c) 2012 Cumulus Networks, Inc |
|
*/ |
|
#include <string.h> |
|
#include <netlink-private/netlink.h> |
|
#include <netlink/object.h> |
|
#include <netlink/hash.h> |
|
#include <netlink/hashtable.h> |
|
|
|
/** |
|
* @ingroup core_types |
|
* @defgroup hashtable Hashtable |
|
* @{ |
|
*/ |
|
|
|
/** |
|
* Allocate hashtable |
|
* @arg size Size of hashtable in number of elements |
|
* |
|
* @return Allocated hashtable or NULL. |
|
*/ |
|
nl_hash_table_t *nl_hash_table_alloc(int size) |
|
{ |
|
nl_hash_table_t *ht; |
|
|
|
ht = calloc(1, sizeof (*ht)); |
|
if (!ht) |
|
goto errout; |
|
|
|
ht->nodes = calloc(size, sizeof (*ht->nodes)); |
|
if (!ht->nodes) { |
|
free(ht); |
|
goto errout; |
|
} |
|
|
|
ht->size = size; |
|
|
|
return ht; |
|
errout: |
|
return NULL; |
|
} |
|
|
|
/** |
|
* Free hashtable including all nodes |
|
* @arg ht Hashtable |
|
* |
|
* @note Reference counter of all objects in the hashtable will be decremented. |
|
*/ |
|
void nl_hash_table_free(nl_hash_table_t *ht) |
|
{ |
|
int i; |
|
|
|
for(i = 0; i < ht->size; i++) { |
|
nl_hash_node_t *node = ht->nodes[i]; |
|
nl_hash_node_t *saved_node; |
|
|
|
while (node) { |
|
saved_node = node; |
|
node = node->next; |
|
nl_object_put(saved_node->obj); |
|
free(saved_node); |
|
} |
|
} |
|
|
|
free(ht->nodes); |
|
free(ht); |
|
} |
|
|
|
/** |
|
* Lookup identical object in hashtable |
|
* @arg ht Hashtable |
|
* @arg obj Object to lookup |
|
* |
|
* Generates hashkey for `obj` and traverses the corresponding chain calling |
|
* `nl_object_identical()` on each trying to find a match. |
|
* |
|
* @return Pointer to object if match was found or NULL. |
|
*/ |
|
struct nl_object* nl_hash_table_lookup(nl_hash_table_t *ht, |
|
struct nl_object *obj) |
|
{ |
|
nl_hash_node_t *node; |
|
uint32_t key_hash; |
|
|
|
nl_object_keygen(obj, &key_hash, ht->size); |
|
node = ht->nodes[key_hash]; |
|
|
|
while (node) { |
|
if (nl_object_identical(node->obj, obj)) |
|
return node->obj; |
|
node = node->next; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
/** |
|
* Add object to hashtable |
|
* @arg ht Hashtable |
|
* @arg obj Object to add |
|
* |
|
* Adds `obj` to the hashtable. Object type must support hashing, otherwise all |
|
* objects will be added to the chain `0`. |
|
* |
|
* @note The reference counter of the object is incremented. |
|
* |
|
* @return 0 on success or a negative error code |
|
* @retval -NLE_EXIST Identical object already present in hashtable |
|
*/ |
|
int nl_hash_table_add(nl_hash_table_t *ht, struct nl_object *obj) |
|
{ |
|
nl_hash_node_t *node; |
|
uint32_t key_hash; |
|
|
|
nl_object_keygen(obj, &key_hash, ht->size); |
|
node = ht->nodes[key_hash]; |
|
|
|
while (node) { |
|
if (nl_object_identical(node->obj, obj)) { |
|
NL_DBG(2, "Warning: Add to hashtable found duplicate...\n"); |
|
return -NLE_EXIST; |
|
} |
|
node = node->next; |
|
} |
|
|
|
NL_DBG (5, "adding cache entry of obj %p in table %p, with hash 0x%x\n", |
|
obj, ht, key_hash); |
|
|
|
node = malloc(sizeof(nl_hash_node_t)); |
|
if (!node) |
|
return -NLE_NOMEM; |
|
nl_object_get(obj); |
|
node->obj = obj; |
|
node->key = key_hash; |
|
node->key_size = sizeof(uint32_t); |
|
node->next = ht->nodes[key_hash]; |
|
ht->nodes[key_hash] = node; |
|
|
|
return 0; |
|
} |
|
|
|
/** |
|
* Remove object from hashtable |
|
* @arg ht Hashtable |
|
* @arg obj Object to remove |
|
* |
|
* Remove `obj` from hashtable if it exists. |
|
* |
|
* @note Reference counter of object will be decremented. |
|
* |
|
* @return 0 on success or a negative error code. |
|
* @retval -NLE_OBJ_NOTFOUND Object not present in hashtable. |
|
*/ |
|
int nl_hash_table_del(nl_hash_table_t *ht, struct nl_object *obj) |
|
{ |
|
nl_hash_node_t *node, *prev; |
|
uint32_t key_hash; |
|
|
|
nl_object_keygen(obj, &key_hash, ht->size); |
|
prev = node = ht->nodes[key_hash]; |
|
|
|
while (node) { |
|
if (nl_object_identical(node->obj, obj)) { |
|
nl_object_put(obj); |
|
|
|
NL_DBG (5, "deleting cache entry of obj %p in table %p, with" |
|
" hash 0x%x\n", obj, ht, key_hash); |
|
|
|
if (node == ht->nodes[key_hash]) |
|
ht->nodes[key_hash] = node->next; |
|
else |
|
prev->next = node->next; |
|
|
|
free(node); |
|
|
|
return 0; |
|
} |
|
prev = node; |
|
node = node->next; |
|
} |
|
|
|
return -NLE_OBJ_NOTFOUND; |
|
} |
|
|
|
uint32_t nl_hash(void *k, size_t length, uint32_t initval) |
|
{ |
|
return(__nl_hash(k, length, initval)); |
|
} |
|
|
|
/** @} */
|
|
|