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