remove version in all files
[dpdk.git] / lib / librte_hash / rte_hash.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without 
8  *   modification, are permitted provided that the following conditions 
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright 
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright 
14  *       notice, this list of conditions and the following disclaimer in 
15  *       the documentation and/or other materials provided with the 
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its 
18  *       contributors may be used to endorse or promote products derived 
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  * 
33  */
34
35 #include <string.h>
36 #include <stdint.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <sys/queue.h>
41
42 #include <rte_common.h>
43 #include <rte_memory.h>         /* for definition of CACHE_LINE_SIZE */
44 #include <rte_log.h>
45 #include <rte_memcpy.h>
46 #include <rte_prefetch.h>
47 #include <rte_branch_prediction.h>
48 #include <rte_memzone.h>
49 #include <rte_malloc.h>
50 #include <rte_tailq.h>
51 #include <rte_eal.h>
52 #include <rte_per_lcore.h>
53 #include <rte_errno.h>
54 #include <rte_string_fns.h>
55 #include <rte_cpuflags.h>
56 #include <rte_log.h>
57
58 #include "rte_hash.h"
59 #include "rte_jhash.h"
60 #include "rte_hash_crc.h"
61
62
63 TAILQ_HEAD(rte_hash_list, rte_hash);
64
65 /* global list of hashes (used for debug/dump) */
66 static struct rte_hash_list *hash_list;
67
68 /* macro to prevent duplication of list creation check code */
69 #define CHECK_HASH_LIST_CREATED() do { \
70         if (hash_list == NULL) \
71                 if ((hash_list = RTE_TAILQ_RESERVE("RTE_HASH", rte_hash_list)) == NULL){ \
72                         rte_errno = E_RTE_NO_TAILQ; \
73                         return NULL; \
74                 } \
75 } while (0)
76
77 /* Macro to enable/disable run-time checking of function parameters */
78 #if defined(RTE_LIBRTE_HASH_DEBUG)
79 #define RETURN_IF_TRUE(cond, retval) do { \
80         if (cond) return (retval); \
81 } while (0)
82 #else
83 #define RETURN_IF_TRUE(cond, retval)
84 #endif
85
86 /* Hash function used if none is specified */
87 #define DEFAULT_HASH_FUNC       rte_hash_crc
88
89 /* Signature bucket size is a multiple of this value */
90 #define SIG_BUCKET_ALIGNMENT    16
91
92 /* Stoered key size is a multiple of this value */
93 #define KEY_ALIGNMENT           16
94
95 /* The high bit is always set in real signatures */
96 #define NULL_SIGNATURE          0
97
98 /* Returns a pointer to the first signature in specified bucket. */
99 static inline hash_sig_t *
100 get_sig_tbl_bucket(const struct rte_hash *h, uint32_t bucket_index)
101 {
102         return (hash_sig_t *)
103                         &(h->sig_tbl[bucket_index * h->sig_tbl_bucket_size]);
104 }
105
106 /* Returns a pointer to the first key in specified bucket. */
107 static inline uint8_t *
108 get_key_tbl_bucket(const struct rte_hash *h, uint32_t bucket_index)
109 {
110         return (uint8_t *) &(h->key_tbl[bucket_index * h->bucket_entries *
111                                      h->key_tbl_key_size]);
112 }
113
114 /* Returns a pointer to a key at a specific position in a specified bucket. */
115 static inline void *
116 get_key_from_bucket(const struct rte_hash *h, uint8_t *bkt, uint32_t pos)
117 {
118         return (void *) &bkt[pos * h->key_tbl_key_size];
119 }
120
121 /* Does integer division with rounding-up of result. */
122 static inline uint32_t
123 div_roundup(uint32_t numerator, uint32_t denominator)
124 {
125         return (numerator + denominator - 1) / denominator;
126 }
127
128 /* Increases a size (if needed) to a multiple of alignment. */
129 static inline uint32_t
130 align_size(uint32_t val, uint32_t alignment)
131 {
132         return alignment * div_roundup(val, alignment);
133 }
134
135 /* Returns the index into the bucket of the first occurrence of a signature. */
136 static inline int
137 find_first(uint32_t sig, const uint32_t *sig_bucket, uint32_t num_sigs)
138 {
139         uint32_t i;
140         for (i = 0; i < num_sigs; i++) {
141                 if (sig == sig_bucket[i])
142                         return i;
143         }
144         return -1;
145 }
146
147 struct rte_hash *
148 rte_hash_find_existing(const char *name)
149 {
150         struct rte_hash *h;
151
152         /* check that we have an initialised tail queue */
153         CHECK_HASH_LIST_CREATED();
154
155         TAILQ_FOREACH(h, hash_list, next) {
156                 if (strncmp(name, h->name, RTE_HASH_NAMESIZE) == 0)
157                         break;
158         }
159         if (h == NULL)
160                 rte_errno = ENOENT;
161         return h;
162 }
163
164 struct rte_hash *
165 rte_hash_create(const struct rte_hash_parameters *params)
166 {
167         struct rte_hash *h = NULL;
168         uint32_t num_buckets, sig_bucket_size, key_size,
169                 hash_tbl_size, sig_tbl_size, key_tbl_size, mem_size;
170         char hash_name[RTE_HASH_NAMESIZE];
171
172         if (rte_eal_process_type() == RTE_PROC_SECONDARY){
173                 rte_errno = E_RTE_SECONDARY;
174                 return NULL;
175         }
176
177         /* check that we have an initialised tail queue */
178         CHECK_HASH_LIST_CREATED();
179
180         /* Check for valid parameters */
181         if ((params == NULL) ||
182                         (params->entries > RTE_HASH_ENTRIES_MAX) ||
183                         (params->bucket_entries > RTE_HASH_BUCKET_ENTRIES_MAX) ||
184                         (params->entries < params->bucket_entries) ||
185                         !rte_is_power_of_2(params->entries) ||
186                         !rte_is_power_of_2(params->bucket_entries) ||
187                         (params->key_len == 0) ||
188                         (params->key_len > RTE_HASH_KEY_LENGTH_MAX)) {
189                 rte_errno = EINVAL;
190                 RTE_LOG(ERR, HASH, "rte_hash_create has invalid parameters\n");
191                 return NULL;
192         }
193
194         rte_snprintf(hash_name, sizeof(hash_name), "HT_%s", params->name);
195
196         /* Calculate hash dimensions */
197         num_buckets = params->entries / params->bucket_entries;
198         sig_bucket_size = align_size(params->bucket_entries *
199                                      sizeof(hash_sig_t), SIG_BUCKET_ALIGNMENT);
200         key_size =  align_size(params->key_len, KEY_ALIGNMENT);
201
202         hash_tbl_size = align_size(sizeof(struct rte_hash), CACHE_LINE_SIZE);
203         sig_tbl_size = align_size(num_buckets * sig_bucket_size,
204                                   CACHE_LINE_SIZE);
205         key_tbl_size = align_size(num_buckets * key_size *
206                                   params->bucket_entries, CACHE_LINE_SIZE);
207
208         /* Total memory required for hash context */
209         mem_size = hash_tbl_size + sig_tbl_size + key_tbl_size;
210
211         /* Allocate as a memzone, or in normal memory space */
212 #if defined(RTE_LIBRTE_HASH_USE_MEMZONE)
213         const struct rte_memzone *mz;
214         mz = rte_memzone_reserve(hash_name, mem_size, params->socket_id, 0);
215         if (mz == NULL) {
216                 RTE_LOG(ERR, HASH, "memzone reservation failed\n");
217                 return NULL;
218         }
219         memset(mz->addr, 0, mem_size);
220         h = (struct rte_hash *)mz->addr;
221 #else
222         h = (struct rte_hash *)rte_zmalloc(hash_name, mem_size,
223                                            CACHE_LINE_SIZE);
224         if (h == NULL) {
225                 RTE_LOG(ERR, HASH, "memory allocation failed\n");
226                 return NULL;
227         }
228 #endif
229
230         /* Setup hash context */
231         rte_snprintf(h->name, sizeof(h->name), "%s", params->name);
232         h->entries = params->entries;
233         h->bucket_entries = params->bucket_entries;
234         h->key_len = params->key_len;
235         h->hash_func_init_val = params->hash_func_init_val;
236         h->num_buckets = num_buckets;
237         h->bucket_bitmask = h->num_buckets - 1;
238         h->sig_msb = 1 << (sizeof(hash_sig_t) * 8 - 1);
239         h->sig_tbl = (uint8_t *)h + hash_tbl_size;
240         h->sig_tbl_bucket_size = sig_bucket_size;
241         h->key_tbl = h->sig_tbl + sig_tbl_size;
242         h->key_tbl_key_size = key_size;
243         h->hash_func = (params->hash_func == NULL) ?
244                 DEFAULT_HASH_FUNC : params->hash_func;
245
246         if (h->hash_func == rte_hash_crc &&
247                         !rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_2)) {
248                 RTE_LOG(WARNING, HASH, "CRC32 instruction requires SSE4.2, "
249                                 "which is not supported on this system. "
250                                 "Falling back to software hash\n.");
251                 h->hash_func = rte_jhash;
252         }
253
254         TAILQ_INSERT_TAIL(hash_list, h, next);
255         return h;
256 }
257
258 void
259 rte_hash_free(struct rte_hash *h)
260 {
261         if (h == NULL)
262                 return;
263 #if !defined(RTE_LIBRTE_HASH_USE_MEMZONE)
264         TAILQ_REMOVE(hash_list, h, next);
265         rte_free(h);
266 #endif
267         /* No way to deallocate memzones */
268         return;
269 }
270
271 int32_t
272 rte_hash_add_key(const struct rte_hash *h, const void *key)
273 {
274         hash_sig_t sig, *sig_bucket;
275         uint8_t *key_bucket;
276         uint32_t bucket_index, i;
277         int32_t pos;
278
279         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
280
281         /* Get the hash signature and bucket index */
282         sig = h->hash_func(key, h->key_len, h->hash_func_init_val) | h->sig_msb;
283         bucket_index = sig & h->bucket_bitmask;
284         sig_bucket = get_sig_tbl_bucket(h, bucket_index);
285         key_bucket = get_key_tbl_bucket(h, bucket_index);
286
287         /* Check if key is already present in the hash */
288         for (i = 0; i < h->bucket_entries; i++) {
289                 if ((sig == sig_bucket[i]) &&
290                     likely(memcmp(key, get_key_from_bucket(h, key_bucket, i),
291                                   h->key_len) == 0)) {
292                         return bucket_index * h->bucket_entries + i;
293                 }
294         }
295
296         /* Check if any free slot within the bucket to add the new key */
297         pos = find_first(NULL_SIGNATURE, sig_bucket, h->bucket_entries);
298
299         if (unlikely(pos < 0))
300                 return -ENOSPC;
301
302         /* Add the new key to the bucket */
303         sig_bucket[pos] = sig;
304         rte_memcpy(get_key_from_bucket(h, key_bucket, pos), key, h->key_len);
305         return bucket_index * h->bucket_entries + pos;
306 }
307
308 int32_t
309 rte_hash_del_key(const struct rte_hash *h, const void *key)
310 {
311         hash_sig_t sig, *sig_bucket;
312         uint8_t *key_bucket;
313         uint32_t bucket_index, i;
314
315         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
316
317         /* Get the hash signature and bucket index */
318         sig = h->hash_func(key, h->key_len, h->hash_func_init_val) | h->sig_msb;
319         bucket_index = sig & h->bucket_bitmask;
320         sig_bucket = get_sig_tbl_bucket(h, bucket_index);
321         key_bucket = get_key_tbl_bucket(h, bucket_index);
322
323         /* Check if key is already present in the hash */
324         for (i = 0; i < h->bucket_entries; i++) {
325                 if ((sig == sig_bucket[i]) &&
326                     likely(memcmp(key, get_key_from_bucket(h, key_bucket, i),
327                                   h->key_len) == 0)) {
328                         sig_bucket[i] = NULL_SIGNATURE;
329                         return bucket_index * h->bucket_entries + i;
330                 }
331         }
332
333         return -ENOENT;
334 }
335
336 int32_t
337 rte_hash_lookup(const struct rte_hash *h, const void *key)
338 {
339         hash_sig_t sig, *sig_bucket;
340         uint8_t *key_bucket;
341         uint32_t bucket_index, i;
342
343         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
344
345         /* Get the hash signature and bucket index */
346         sig = h->hash_func(key, h->key_len, h->hash_func_init_val) | h->sig_msb;
347         bucket_index = sig & h->bucket_bitmask;
348         sig_bucket = get_sig_tbl_bucket(h, bucket_index);
349         key_bucket = get_key_tbl_bucket(h, bucket_index);
350
351         /* Check if key is already present in the hash */
352         for (i = 0; i < h->bucket_entries; i++) {
353                 if ((sig == sig_bucket[i]) &&
354                     likely(memcmp(key, get_key_from_bucket(h, key_bucket, i),
355                                   h->key_len) == 0)) {
356                         return bucket_index * h->bucket_entries + i;
357                 }
358         }
359
360         return -ENOENT;
361 }
362
363 int
364 rte_hash_lookup_multi(const struct rte_hash *h, const void **keys,
365                       uint32_t num_keys, int32_t *positions)
366 {
367         uint32_t i, j, bucket_index;
368         hash_sig_t sigs[RTE_HASH_LOOKUP_MULTI_MAX];
369
370         RETURN_IF_TRUE(((h == NULL) || (keys == NULL) || (num_keys == 0) ||
371                         (num_keys > RTE_HASH_LOOKUP_MULTI_MAX) ||
372                         (positions == NULL)), -EINVAL);
373
374         /* Get the hash signature and bucket index */
375         for (i = 0; i < num_keys; i++) {
376                 sigs[i] = h->hash_func(keys[i], h->key_len,
377                                 h->hash_func_init_val) | h->sig_msb;
378                 bucket_index = sigs[i] & h->bucket_bitmask;
379
380                 /* Pre-fetch relevant buckets */
381                 rte_prefetch1((void *) get_sig_tbl_bucket(h, bucket_index));
382                 rte_prefetch1((void *) get_key_tbl_bucket(h, bucket_index));
383         }
384
385         /* Check if key is already present in the hash */
386         for (i = 0; i < num_keys; i++) {
387                 bucket_index = sigs[i] & h->bucket_bitmask;
388                 hash_sig_t *sig_bucket = get_sig_tbl_bucket(h, bucket_index);
389                 uint8_t *key_bucket = get_key_tbl_bucket(h, bucket_index);
390
391                 positions[i] = -ENOENT;
392
393                 for (j = 0; j < h->bucket_entries; j++) {
394                         if ((sigs[i] == sig_bucket[j]) &&
395                             likely(memcmp(keys[i],
396                                           get_key_from_bucket(h, key_bucket, j),
397                                           h->key_len) == 0)) {
398                                 positions[i] = bucket_index *
399                                         h->bucket_entries + j;
400                                 break;
401                         }
402                 }
403         }
404
405         return 0;
406 }