libnl  3.2.24-rc1
hashtable.c
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  */
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  */
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 /** @} */