• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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