Home | History | Annotate | Download | only in lib
      1 /*
      2  * netlink/hashtable.c      Netlink hashtable Utilities
      3  *
      4  *      This library is free software; you can redistribute it and/or
      5  *      modify it under the terms of the GNU Lesser General Public
      6  *      License as published by the Free Software Foundation version 2.1
      7  *      of the License.
      8  *
      9  * Copyright (c) 2012 Cumulus Networks, Inc
     10  */
     11 #include <string.h>
     12 #include <netlink-private/netlink.h>
     13 #include <netlink/object.h>
     14 #include <netlink/hash.h>
     15 #include <netlink/hashtable.h>
     16 
     17 /**
     18  * @ingroup core_types
     19  * @defgroup hashtable Hashtable
     20  * @{
     21  */
     22 
     23 /**
     24  * Allocate hashtable
     25  * @arg size		Size of hashtable in number of elements
     26  *
     27  * @return Allocated hashtable or NULL.
     28  */
     29 nl_hash_table_t *nl_hash_table_alloc(int size)
     30 {
     31 	nl_hash_table_t *ht;
     32 
     33 	ht = calloc(1, sizeof (*ht));
     34 	if (!ht)
     35 		goto errout;
     36 
     37 	ht->nodes = calloc(size, sizeof (*ht->nodes));
     38 	if (!ht->nodes) {
     39 		free(ht);
     40 		goto errout;
     41 	}
     42 
     43 	ht->size = size;
     44 
     45 	return ht;
     46 errout:
     47 	return NULL;
     48 }
     49 
     50 /**
     51  * Free hashtable including all nodes
     52  * @arg ht		Hashtable
     53  *
     54  * @note Reference counter of all objects in the hashtable will be decremented.
     55  */
     56 void nl_hash_table_free(nl_hash_table_t *ht)
     57 {
     58 	int i;
     59 
     60 	for(i = 0; i < ht->size; i++) {
     61 	    nl_hash_node_t *node = ht->nodes[i];
     62 	    nl_hash_node_t *saved_node;
     63 
     64 	    while (node) {
     65 		   saved_node = node;
     66 		   node = node->next;
     67 		   nl_object_put(saved_node->obj);
     68 		   free(saved_node);
     69 	    }
     70 	}
     71 
     72 	free(ht->nodes);
     73 	free(ht);
     74 }
     75 
     76 /**
     77  * Lookup identical object in hashtable
     78  * @arg ht		Hashtable
     79  * @arg	obj		Object to lookup
     80  *
     81  * Generates hashkey for `obj` and traverses the corresponding chain calling
     82  * `nl_object_identical()` on each trying to find a match.
     83  *
     84  * @return Pointer to object if match was found or NULL.
     85  */
     86 struct nl_object* nl_hash_table_lookup(nl_hash_table_t *ht,
     87 				       struct nl_object *obj)
     88 {
     89 	nl_hash_node_t *node;
     90 	uint32_t key_hash;
     91 
     92 	nl_object_keygen(obj, &key_hash, ht->size);
     93 	node = ht->nodes[key_hash];
     94 
     95 	while (node) {
     96 	       if (nl_object_identical(node->obj, obj))
     97 		   return node->obj;
     98 	       node = node->next;
     99 	}
    100 
    101 	return NULL;
    102 }
    103 
    104 /**
    105  * Add object to hashtable
    106  * @arg ht		Hashtable
    107  * @arg obj		Object to add
    108  *
    109  * Adds `obj` to the hashtable. Object type must support hashing, otherwise all
    110  * objects will be added to the chain `0`.
    111  *
    112  * @note The reference counter of the object is incremented.
    113  *
    114  * @return 0 on success or a negative error code
    115  * @retval -NLE_EXIST Identical object already present in hashtable
    116  */
    117 int nl_hash_table_add(nl_hash_table_t *ht, struct nl_object *obj)
    118 {
    119 	nl_hash_node_t *node;
    120 	uint32_t key_hash;
    121 
    122 	nl_object_keygen(obj, &key_hash, ht->size);
    123 	node = ht->nodes[key_hash];
    124 
    125 	while (node) {
    126 	       if (nl_object_identical(node->obj, obj)) {
    127 		   NL_DBG(2, "Warning: Add to hashtable found duplicate...\n");
    128 		   return -NLE_EXIST;
    129 	       }
    130 	       node = node->next;
    131 	}
    132 
    133 	NL_DBG (5, "adding cache entry of obj %p in table %p, with hash 0x%x\n",
    134 		obj, ht, key_hash);
    135 
    136 	node = malloc(sizeof(nl_hash_node_t));
    137 	if (!node)
    138 		return -NLE_NOMEM;
    139 	nl_object_get(obj);
    140 	node->obj = obj;
    141 	node->key = key_hash;
    142 	node->key_size = sizeof(uint32_t);
    143 	node->next = ht->nodes[key_hash];
    144 	ht->nodes[key_hash] = node;
    145 
    146 	return 0;
    147 }
    148 
    149 /**
    150  * Remove object from hashtable
    151  * @arg ht		Hashtable
    152  * @arg obj		Object to remove
    153  *
    154  * Remove `obj` from hashtable if it exists.
    155  *
    156  * @note Reference counter of object will be decremented.
    157  *
    158  * @return 0 on success or a negative error code.
    159  * @retval -NLE_OBJ_NOTFOUND Object not present in hashtable.
    160  */
    161 int nl_hash_table_del(nl_hash_table_t *ht, struct nl_object *obj)
    162 {
    163 	nl_hash_node_t *node, *prev;
    164 	uint32_t key_hash;
    165 
    166 	nl_object_keygen(obj, &key_hash, ht->size);
    167 	prev = node = ht->nodes[key_hash];
    168 
    169 	while (node) {
    170 	       if (nl_object_identical(node->obj, obj)) {
    171 		   nl_object_put(obj);
    172 
    173 		   NL_DBG (5, "deleting cache entry of obj %p in table %p, with"
    174 			   " hash 0x%x\n", obj, ht, key_hash);
    175 
    176 	           if (node == ht->nodes[key_hash])
    177 		       ht->nodes[key_hash] = node->next;
    178 	           else
    179 		       prev->next = node->next;
    180 
    181 	           free(node);
    182 
    183 	           return 0;
    184 		}
    185 		prev = node;
    186 		node = node->next;
    187 	}
    188 
    189 	return -NLE_OBJ_NOTFOUND;
    190 }
    191 
    192 uint32_t nl_hash(void *k, size_t length, uint32_t initval)
    193 {
    194 	return(__nl_hash(k, length, initval));
    195 }
    196 
    197 /** @} */
    198