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