hash: validate hash bucket entries while compiling
[dpdk.git] / lib / librte_hash / rte_cuckoo_hash.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4
5 #include <string.h>
6 #include <stdint.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <sys/queue.h>
11
12 #include <rte_common.h>
13 #include <rte_memory.h>         /* for definition of RTE_CACHE_LINE_SIZE */
14 #include <rte_log.h>
15 #include <rte_memcpy.h>
16 #include <rte_prefetch.h>
17 #include <rte_branch_prediction.h>
18 #include <rte_malloc.h>
19 #include <rte_eal.h>
20 #include <rte_eal_memconfig.h>
21 #include <rte_per_lcore.h>
22 #include <rte_errno.h>
23 #include <rte_string_fns.h>
24 #include <rte_cpuflags.h>
25 #include <rte_rwlock.h>
26 #include <rte_spinlock.h>
27 #include <rte_ring.h>
28 #include <rte_compat.h>
29 #include <rte_pause.h>
30
31 #include "rte_hash.h"
32 #include "rte_cuckoo_hash.h"
33
34 #if defined(RTE_ARCH_X86)
35 #include "rte_cuckoo_hash_x86.h"
36 #endif
37
38 TAILQ_HEAD(rte_hash_list, rte_tailq_entry);
39
40 static struct rte_tailq_elem rte_hash_tailq = {
41         .name = "RTE_HASH",
42 };
43 EAL_REGISTER_TAILQ(rte_hash_tailq)
44
45 struct rte_hash *
46 rte_hash_find_existing(const char *name)
47 {
48         struct rte_hash *h = NULL;
49         struct rte_tailq_entry *te;
50         struct rte_hash_list *hash_list;
51
52         hash_list = RTE_TAILQ_CAST(rte_hash_tailq.head, rte_hash_list);
53
54         rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
55         TAILQ_FOREACH(te, hash_list, next) {
56                 h = (struct rte_hash *) te->data;
57                 if (strncmp(name, h->name, RTE_HASH_NAMESIZE) == 0)
58                         break;
59         }
60         rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
61
62         if (te == NULL) {
63                 rte_errno = ENOENT;
64                 return NULL;
65         }
66         return h;
67 }
68
69 void rte_hash_set_cmp_func(struct rte_hash *h, rte_hash_cmp_eq_t func)
70 {
71         h->cmp_jump_table_idx = KEY_CUSTOM;
72         h->rte_hash_custom_cmp_eq = func;
73 }
74
75 static inline int
76 rte_hash_cmp_eq(const void *key1, const void *key2, const struct rte_hash *h)
77 {
78         if (h->cmp_jump_table_idx == KEY_CUSTOM)
79                 return h->rte_hash_custom_cmp_eq(key1, key2, h->key_len);
80         else
81                 return cmp_jump_table[h->cmp_jump_table_idx](key1, key2, h->key_len);
82 }
83
84 struct rte_hash *
85 rte_hash_create(const struct rte_hash_parameters *params)
86 {
87         struct rte_hash *h = NULL;
88         struct rte_tailq_entry *te = NULL;
89         struct rte_hash_list *hash_list;
90         struct rte_ring *r = NULL;
91         char hash_name[RTE_HASH_NAMESIZE];
92         void *k = NULL;
93         void *buckets = NULL;
94         char ring_name[RTE_RING_NAMESIZE];
95         unsigned num_key_slots;
96         unsigned hw_trans_mem_support = 0;
97         unsigned i;
98         rte_hash_function default_hash_func = (rte_hash_function)rte_jhash;
99
100         hash_list = RTE_TAILQ_CAST(rte_hash_tailq.head, rte_hash_list);
101
102         if (params == NULL) {
103                 RTE_LOG(ERR, HASH, "rte_hash_create has no parameters\n");
104                 return NULL;
105         }
106
107         /* Check for valid parameters */
108         if ((params->entries > RTE_HASH_ENTRIES_MAX) ||
109                         (params->entries < RTE_HASH_BUCKET_ENTRIES) ||
110                         (params->key_len == 0)) {
111                 rte_errno = EINVAL;
112                 RTE_LOG(ERR, HASH, "rte_hash_create has invalid parameters\n");
113                 return NULL;
114         }
115
116         /* Check extra flags field to check extra options. */
117         if (params->extra_flag & RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT)
118                 hw_trans_mem_support = 1;
119
120         /* Store all keys and leave the first entry as a dummy entry for lookup_bulk */
121         if (hw_trans_mem_support)
122                 /*
123                  * Increase number of slots by total number of indices
124                  * that can be stored in the lcore caches
125                  * except for the first cache
126                  */
127                 num_key_slots = params->entries + (RTE_MAX_LCORE - 1) *
128                                         LCORE_CACHE_SIZE + 1;
129         else
130                 num_key_slots = params->entries + 1;
131
132         snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name);
133         /* Create ring (Dummy slot index is not enqueued) */
134         r = rte_ring_create(ring_name, rte_align32pow2(num_key_slots - 1),
135                         params->socket_id, 0);
136         if (r == NULL) {
137                 RTE_LOG(ERR, HASH, "memory allocation failed\n");
138                 goto err;
139         }
140
141         snprintf(hash_name, sizeof(hash_name), "HT_%s", params->name);
142
143         rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
144
145         /* guarantee there's no existing: this is normally already checked
146          * by ring creation above */
147         TAILQ_FOREACH(te, hash_list, next) {
148                 h = (struct rte_hash *) te->data;
149                 if (strncmp(params->name, h->name, RTE_HASH_NAMESIZE) == 0)
150                         break;
151         }
152         h = NULL;
153         if (te != NULL) {
154                 rte_errno = EEXIST;
155                 te = NULL;
156                 goto err_unlock;
157         }
158
159         te = rte_zmalloc("HASH_TAILQ_ENTRY", sizeof(*te), 0);
160         if (te == NULL) {
161                 RTE_LOG(ERR, HASH, "tailq entry allocation failed\n");
162                 goto err_unlock;
163         }
164
165         h = (struct rte_hash *)rte_zmalloc_socket(hash_name, sizeof(struct rte_hash),
166                                         RTE_CACHE_LINE_SIZE, params->socket_id);
167
168         if (h == NULL) {
169                 RTE_LOG(ERR, HASH, "memory allocation failed\n");
170                 goto err_unlock;
171         }
172
173         const uint32_t num_buckets = rte_align32pow2(params->entries)
174                                         / RTE_HASH_BUCKET_ENTRIES;
175
176         buckets = rte_zmalloc_socket(NULL,
177                                 num_buckets * sizeof(struct rte_hash_bucket),
178                                 RTE_CACHE_LINE_SIZE, params->socket_id);
179
180         if (buckets == NULL) {
181                 RTE_LOG(ERR, HASH, "memory allocation failed\n");
182                 goto err_unlock;
183         }
184
185         const uint32_t key_entry_size = sizeof(struct rte_hash_key) + params->key_len;
186         const uint64_t key_tbl_size = (uint64_t) key_entry_size * num_key_slots;
187
188         k = rte_zmalloc_socket(NULL, key_tbl_size,
189                         RTE_CACHE_LINE_SIZE, params->socket_id);
190
191         if (k == NULL) {
192                 RTE_LOG(ERR, HASH, "memory allocation failed\n");
193                 goto err_unlock;
194         }
195
196 /*
197  * If x86 architecture is used, select appropriate compare function,
198  * which may use x86 intrinsics, otherwise use memcmp
199  */
200 #if defined(RTE_ARCH_X86) || defined(RTE_ARCH_ARM64)
201         /* Select function to compare keys */
202         switch (params->key_len) {
203         case 16:
204                 h->cmp_jump_table_idx = KEY_16_BYTES;
205                 break;
206         case 32:
207                 h->cmp_jump_table_idx = KEY_32_BYTES;
208                 break;
209         case 48:
210                 h->cmp_jump_table_idx = KEY_48_BYTES;
211                 break;
212         case 64:
213                 h->cmp_jump_table_idx = KEY_64_BYTES;
214                 break;
215         case 80:
216                 h->cmp_jump_table_idx = KEY_80_BYTES;
217                 break;
218         case 96:
219                 h->cmp_jump_table_idx = KEY_96_BYTES;
220                 break;
221         case 112:
222                 h->cmp_jump_table_idx = KEY_112_BYTES;
223                 break;
224         case 128:
225                 h->cmp_jump_table_idx = KEY_128_BYTES;
226                 break;
227         default:
228                 /* If key is not multiple of 16, use generic memcmp */
229                 h->cmp_jump_table_idx = KEY_OTHER_BYTES;
230         }
231 #else
232         h->cmp_jump_table_idx = KEY_OTHER_BYTES;
233 #endif
234
235         if (hw_trans_mem_support) {
236                 h->local_free_slots = rte_zmalloc_socket(NULL,
237                                 sizeof(struct lcore_cache) * RTE_MAX_LCORE,
238                                 RTE_CACHE_LINE_SIZE, params->socket_id);
239         }
240
241         /* Default hash function */
242 #if defined(RTE_ARCH_X86)
243         default_hash_func = (rte_hash_function)rte_hash_crc;
244 #elif defined(RTE_ARCH_ARM64)
245         if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_CRC32))
246                 default_hash_func = (rte_hash_function)rte_hash_crc;
247 #endif
248         /* Setup hash context */
249         snprintf(h->name, sizeof(h->name), "%s", params->name);
250         h->entries = params->entries;
251         h->key_len = params->key_len;
252         h->key_entry_size = key_entry_size;
253         h->hash_func_init_val = params->hash_func_init_val;
254
255         h->num_buckets = num_buckets;
256         h->bucket_bitmask = h->num_buckets - 1;
257         h->buckets = buckets;
258         h->hash_func = (params->hash_func == NULL) ?
259                 default_hash_func : params->hash_func;
260         h->key_store = k;
261         h->free_slots = r;
262         h->hw_trans_mem_support = hw_trans_mem_support;
263
264 #if defined(RTE_ARCH_X86)
265         if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
266                 h->sig_cmp_fn = RTE_HASH_COMPARE_AVX2;
267         else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE2))
268                 h->sig_cmp_fn = RTE_HASH_COMPARE_SSE;
269         else
270 #endif
271                 h->sig_cmp_fn = RTE_HASH_COMPARE_SCALAR;
272
273         /* Turn on multi-writer only with explicit flat from user and TM
274          * support.
275          */
276         if (params->extra_flag & RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD) {
277                 if (h->hw_trans_mem_support) {
278                         h->add_key = ADD_KEY_MULTIWRITER_TM;
279                 } else {
280                         h->add_key = ADD_KEY_MULTIWRITER;
281                         h->multiwriter_lock = rte_malloc(NULL,
282                                                         sizeof(rte_spinlock_t),
283                                                         LCORE_CACHE_SIZE);
284                         rte_spinlock_init(h->multiwriter_lock);
285                 }
286         } else
287                 h->add_key = ADD_KEY_SINGLEWRITER;
288
289         /* Populate free slots ring. Entry zero is reserved for key misses. */
290         for (i = 1; i < params->entries + 1; i++)
291                 rte_ring_sp_enqueue(r, (void *)((uintptr_t) i));
292
293         te->data = (void *) h;
294         TAILQ_INSERT_TAIL(hash_list, te, next);
295         rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
296
297         return h;
298 err_unlock:
299         rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
300 err:
301         rte_ring_free(r);
302         rte_free(te);
303         rte_free(h);
304         rte_free(buckets);
305         rte_free(k);
306         return NULL;
307 }
308
309 void
310 rte_hash_free(struct rte_hash *h)
311 {
312         struct rte_tailq_entry *te;
313         struct rte_hash_list *hash_list;
314
315         if (h == NULL)
316                 return;
317
318         hash_list = RTE_TAILQ_CAST(rte_hash_tailq.head, rte_hash_list);
319
320         rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
321
322         /* find out tailq entry */
323         TAILQ_FOREACH(te, hash_list, next) {
324                 if (te->data == (void *) h)
325                         break;
326         }
327
328         if (te == NULL) {
329                 rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
330                 return;
331         }
332
333         TAILQ_REMOVE(hash_list, te, next);
334
335         rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
336
337         if (h->hw_trans_mem_support)
338                 rte_free(h->local_free_slots);
339
340         if (h->add_key == ADD_KEY_MULTIWRITER)
341                 rte_free(h->multiwriter_lock);
342         rte_ring_free(h->free_slots);
343         rte_free(h->key_store);
344         rte_free(h->buckets);
345         rte_free(h);
346         rte_free(te);
347 }
348
349 hash_sig_t
350 rte_hash_hash(const struct rte_hash *h, const void *key)
351 {
352         /* calc hash result by key */
353         return h->hash_func(key, h->key_len, h->hash_func_init_val);
354 }
355
356 /* Calc the secondary hash value from the primary hash value of a given key */
357 static inline hash_sig_t
358 rte_hash_secondary_hash(const hash_sig_t primary_hash)
359 {
360         static const unsigned all_bits_shift = 12;
361         static const unsigned alt_bits_xor = 0x5bd1e995;
362
363         uint32_t tag = primary_hash >> all_bits_shift;
364
365         return primary_hash ^ ((tag + 1) * alt_bits_xor);
366 }
367
368 void
369 rte_hash_reset(struct rte_hash *h)
370 {
371         void *ptr;
372         unsigned i;
373
374         if (h == NULL)
375                 return;
376
377         memset(h->buckets, 0, h->num_buckets * sizeof(struct rte_hash_bucket));
378         memset(h->key_store, 0, h->key_entry_size * (h->entries + 1));
379
380         /* clear the free ring */
381         while (rte_ring_dequeue(h->free_slots, &ptr) == 0)
382                 rte_pause();
383
384         /* Repopulate the free slots ring. Entry zero is reserved for key misses */
385         for (i = 1; i < h->entries + 1; i++)
386                 rte_ring_sp_enqueue(h->free_slots, (void *)((uintptr_t) i));
387
388         if (h->hw_trans_mem_support) {
389                 /* Reset local caches per lcore */
390                 for (i = 0; i < RTE_MAX_LCORE; i++)
391                         h->local_free_slots[i].len = 0;
392         }
393 }
394
395 /* Search for an entry that can be pushed to its alternative location */
396 static inline int
397 make_space_bucket(const struct rte_hash *h, struct rte_hash_bucket *bkt,
398                 unsigned int *nr_pushes)
399 {
400         unsigned i, j;
401         int ret;
402         uint32_t next_bucket_idx;
403         struct rte_hash_bucket *next_bkt[RTE_HASH_BUCKET_ENTRIES];
404
405         /*
406          * Push existing item (search for bucket with space in
407          * alternative locations) to its alternative location
408          */
409         for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
410                 /* Search for space in alternative locations */
411                 next_bucket_idx = bkt->sig_alt[i] & h->bucket_bitmask;
412                 next_bkt[i] = &h->buckets[next_bucket_idx];
413                 for (j = 0; j < RTE_HASH_BUCKET_ENTRIES; j++) {
414                         if (next_bkt[i]->key_idx[j] == EMPTY_SLOT)
415                                 break;
416                 }
417
418                 if (j != RTE_HASH_BUCKET_ENTRIES)
419                         break;
420         }
421
422         /* Alternative location has spare room (end of recursive function) */
423         if (i != RTE_HASH_BUCKET_ENTRIES) {
424                 next_bkt[i]->sig_alt[j] = bkt->sig_current[i];
425                 next_bkt[i]->sig_current[j] = bkt->sig_alt[i];
426                 next_bkt[i]->key_idx[j] = bkt->key_idx[i];
427                 return i;
428         }
429
430         /* Pick entry that has not been pushed yet */
431         for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++)
432                 if (bkt->flag[i] == 0)
433                         break;
434
435         /* All entries have been pushed, so entry cannot be added */
436         if (i == RTE_HASH_BUCKET_ENTRIES || ++(*nr_pushes) > RTE_HASH_MAX_PUSHES)
437                 return -ENOSPC;
438
439         /* Set flag to indicate that this entry is going to be pushed */
440         bkt->flag[i] = 1;
441
442         /* Need room in alternative bucket to insert the pushed entry */
443         ret = make_space_bucket(h, next_bkt[i], nr_pushes);
444         /*
445          * After recursive function.
446          * Clear flags and insert the pushed entry
447          * in its alternative location if successful,
448          * or return error
449          */
450         bkt->flag[i] = 0;
451         if (ret >= 0) {
452                 next_bkt[i]->sig_alt[ret] = bkt->sig_current[i];
453                 next_bkt[i]->sig_current[ret] = bkt->sig_alt[i];
454                 next_bkt[i]->key_idx[ret] = bkt->key_idx[i];
455                 return i;
456         } else
457                 return ret;
458
459 }
460
461 /*
462  * Function called to enqueue back an index in the cache/ring,
463  * as slot has not being used and it can be used in the
464  * next addition attempt.
465  */
466 static inline void
467 enqueue_slot_back(const struct rte_hash *h,
468                 struct lcore_cache *cached_free_slots,
469                 void *slot_id)
470 {
471         if (h->hw_trans_mem_support) {
472                 cached_free_slots->objs[cached_free_slots->len] = slot_id;
473                 cached_free_slots->len++;
474         } else
475                 rte_ring_sp_enqueue(h->free_slots, slot_id);
476 }
477
478 static inline int32_t
479 __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,
480                                                 hash_sig_t sig, void *data)
481 {
482         hash_sig_t alt_hash;
483         uint32_t prim_bucket_idx, sec_bucket_idx;
484         unsigned i;
485         struct rte_hash_bucket *prim_bkt, *sec_bkt;
486         struct rte_hash_key *new_k, *k, *keys = h->key_store;
487         void *slot_id = NULL;
488         uint32_t new_idx;
489         int ret;
490         unsigned n_slots;
491         unsigned lcore_id;
492         struct lcore_cache *cached_free_slots = NULL;
493         unsigned int nr_pushes = 0;
494
495         if (h->add_key == ADD_KEY_MULTIWRITER)
496                 rte_spinlock_lock(h->multiwriter_lock);
497
498         prim_bucket_idx = sig & h->bucket_bitmask;
499         prim_bkt = &h->buckets[prim_bucket_idx];
500         rte_prefetch0(prim_bkt);
501
502         alt_hash = rte_hash_secondary_hash(sig);
503         sec_bucket_idx = alt_hash & h->bucket_bitmask;
504         sec_bkt = &h->buckets[sec_bucket_idx];
505         rte_prefetch0(sec_bkt);
506
507         /* Get a new slot for storing the new key */
508         if (h->hw_trans_mem_support) {
509                 lcore_id = rte_lcore_id();
510                 cached_free_slots = &h->local_free_slots[lcore_id];
511                 /* Try to get a free slot from the local cache */
512                 if (cached_free_slots->len == 0) {
513                         /* Need to get another burst of free slots from global ring */
514                         n_slots = rte_ring_mc_dequeue_burst(h->free_slots,
515                                         cached_free_slots->objs,
516                                         LCORE_CACHE_SIZE, NULL);
517                         if (n_slots == 0) {
518                                 ret = -ENOSPC;
519                                 goto failure;
520                         }
521
522                         cached_free_slots->len += n_slots;
523                 }
524
525                 /* Get a free slot from the local cache */
526                 cached_free_slots->len--;
527                 slot_id = cached_free_slots->objs[cached_free_slots->len];
528         } else {
529                 if (rte_ring_sc_dequeue(h->free_slots, &slot_id) != 0) {
530                         ret = -ENOSPC;
531                         goto failure;
532                 }
533         }
534
535         new_k = RTE_PTR_ADD(keys, (uintptr_t)slot_id * h->key_entry_size);
536         rte_prefetch0(new_k);
537         new_idx = (uint32_t)((uintptr_t) slot_id);
538
539         /* Check if key is already inserted in primary location */
540         for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
541                 if (prim_bkt->sig_current[i] == sig &&
542                                 prim_bkt->sig_alt[i] == alt_hash) {
543                         k = (struct rte_hash_key *) ((char *)keys +
544                                         prim_bkt->key_idx[i] * h->key_entry_size);
545                         if (rte_hash_cmp_eq(key, k->key, h) == 0) {
546                                 /* Enqueue index of free slot back in the ring. */
547                                 enqueue_slot_back(h, cached_free_slots, slot_id);
548                                 /* Update data */
549                                 k->pdata = data;
550                                 /*
551                                  * Return index where key is stored,
552                                  * subtracting the first dummy index
553                                  */
554                                 ret = prim_bkt->key_idx[i] - 1;
555                                 goto failure;
556                         }
557                 }
558         }
559
560         /* Check if key is already inserted in secondary location */
561         for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
562                 if (sec_bkt->sig_alt[i] == sig &&
563                                 sec_bkt->sig_current[i] == alt_hash) {
564                         k = (struct rte_hash_key *) ((char *)keys +
565                                         sec_bkt->key_idx[i] * h->key_entry_size);
566                         if (rte_hash_cmp_eq(key, k->key, h) == 0) {
567                                 /* Enqueue index of free slot back in the ring. */
568                                 enqueue_slot_back(h, cached_free_slots, slot_id);
569                                 /* Update data */
570                                 k->pdata = data;
571                                 /*
572                                  * Return index where key is stored,
573                                  * subtracting the first dummy index
574                                  */
575                                 ret = sec_bkt->key_idx[i] - 1;
576                                 goto failure;
577                         }
578                 }
579         }
580
581         /* Copy key */
582         rte_memcpy(new_k->key, key, h->key_len);
583         new_k->pdata = data;
584
585 #if defined(RTE_ARCH_X86) /* currently only x86 support HTM */
586         if (h->add_key == ADD_KEY_MULTIWRITER_TM) {
587                 ret = rte_hash_cuckoo_insert_mw_tm(prim_bkt,
588                                 sig, alt_hash, new_idx);
589                 if (ret >= 0)
590                         return new_idx - 1;
591
592                 /* Primary bucket full, need to make space for new entry */
593                 ret = rte_hash_cuckoo_make_space_mw_tm(h, prim_bkt, sig,
594                                                         alt_hash, new_idx);
595
596                 if (ret >= 0)
597                         return new_idx - 1;
598
599                 /* Also search secondary bucket to get better occupancy */
600                 ret = rte_hash_cuckoo_make_space_mw_tm(h, sec_bkt, sig,
601                                                         alt_hash, new_idx);
602
603                 if (ret >= 0)
604                         return new_idx - 1;
605         } else {
606 #endif
607                 for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
608                         /* Check if slot is available */
609                         if (likely(prim_bkt->key_idx[i] == EMPTY_SLOT)) {
610                                 prim_bkt->sig_current[i] = sig;
611                                 prim_bkt->sig_alt[i] = alt_hash;
612                                 prim_bkt->key_idx[i] = new_idx;
613                                 break;
614                         }
615                 }
616
617                 if (i != RTE_HASH_BUCKET_ENTRIES) {
618                         if (h->add_key == ADD_KEY_MULTIWRITER)
619                                 rte_spinlock_unlock(h->multiwriter_lock);
620                         return new_idx - 1;
621                 }
622
623                 /* Primary bucket full, need to make space for new entry
624                  * After recursive function.
625                  * Insert the new entry in the position of the pushed entry
626                  * if successful or return error and
627                  * store the new slot back in the ring
628                  */
629                 ret = make_space_bucket(h, prim_bkt, &nr_pushes);
630                 if (ret >= 0) {
631                         prim_bkt->sig_current[ret] = sig;
632                         prim_bkt->sig_alt[ret] = alt_hash;
633                         prim_bkt->key_idx[ret] = new_idx;
634                         if (h->add_key == ADD_KEY_MULTIWRITER)
635                                 rte_spinlock_unlock(h->multiwriter_lock);
636                         return new_idx - 1;
637                 }
638 #if defined(RTE_ARCH_X86)
639         }
640 #endif
641         /* Error in addition, store new slot back in the ring and return error */
642         enqueue_slot_back(h, cached_free_slots, (void *)((uintptr_t) new_idx));
643
644 failure:
645         if (h->add_key == ADD_KEY_MULTIWRITER)
646                 rte_spinlock_unlock(h->multiwriter_lock);
647         return ret;
648 }
649
650 int32_t
651 rte_hash_add_key_with_hash(const struct rte_hash *h,
652                         const void *key, hash_sig_t sig)
653 {
654         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
655         return __rte_hash_add_key_with_hash(h, key, sig, 0);
656 }
657
658 int32_t
659 rte_hash_add_key(const struct rte_hash *h, const void *key)
660 {
661         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
662         return __rte_hash_add_key_with_hash(h, key, rte_hash_hash(h, key), 0);
663 }
664
665 int
666 rte_hash_add_key_with_hash_data(const struct rte_hash *h,
667                         const void *key, hash_sig_t sig, void *data)
668 {
669         int ret;
670
671         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
672         ret = __rte_hash_add_key_with_hash(h, key, sig, data);
673         if (ret >= 0)
674                 return 0;
675         else
676                 return ret;
677 }
678
679 int
680 rte_hash_add_key_data(const struct rte_hash *h, const void *key, void *data)
681 {
682         int ret;
683
684         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
685
686         ret = __rte_hash_add_key_with_hash(h, key, rte_hash_hash(h, key), data);
687         if (ret >= 0)
688                 return 0;
689         else
690                 return ret;
691 }
692 static inline int32_t
693 __rte_hash_lookup_with_hash(const struct rte_hash *h, const void *key,
694                                         hash_sig_t sig, void **data)
695 {
696         uint32_t bucket_idx;
697         hash_sig_t alt_hash;
698         unsigned i;
699         struct rte_hash_bucket *bkt;
700         struct rte_hash_key *k, *keys = h->key_store;
701
702         bucket_idx = sig & h->bucket_bitmask;
703         bkt = &h->buckets[bucket_idx];
704
705         /* Check if key is in primary location */
706         for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
707                 if (bkt->sig_current[i] == sig &&
708                                 bkt->key_idx[i] != EMPTY_SLOT) {
709                         k = (struct rte_hash_key *) ((char *)keys +
710                                         bkt->key_idx[i] * h->key_entry_size);
711                         if (rte_hash_cmp_eq(key, k->key, h) == 0) {
712                                 if (data != NULL)
713                                         *data = k->pdata;
714                                 /*
715                                  * Return index where key is stored,
716                                  * subtracting the first dummy index
717                                  */
718                                 return bkt->key_idx[i] - 1;
719                         }
720                 }
721         }
722
723         /* Calculate secondary hash */
724         alt_hash = rte_hash_secondary_hash(sig);
725         bucket_idx = alt_hash & h->bucket_bitmask;
726         bkt = &h->buckets[bucket_idx];
727
728         /* Check if key is in secondary location */
729         for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
730                 if (bkt->sig_current[i] == alt_hash &&
731                                 bkt->sig_alt[i] == sig) {
732                         k = (struct rte_hash_key *) ((char *)keys +
733                                         bkt->key_idx[i] * h->key_entry_size);
734                         if (rte_hash_cmp_eq(key, k->key, h) == 0) {
735                                 if (data != NULL)
736                                         *data = k->pdata;
737                                 /*
738                                  * Return index where key is stored,
739                                  * subtracting the first dummy index
740                                  */
741                                 return bkt->key_idx[i] - 1;
742                         }
743                 }
744         }
745
746         return -ENOENT;
747 }
748
749 int32_t
750 rte_hash_lookup_with_hash(const struct rte_hash *h,
751                         const void *key, hash_sig_t sig)
752 {
753         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
754         return __rte_hash_lookup_with_hash(h, key, sig, NULL);
755 }
756
757 int32_t
758 rte_hash_lookup(const struct rte_hash *h, const void *key)
759 {
760         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
761         return __rte_hash_lookup_with_hash(h, key, rte_hash_hash(h, key), NULL);
762 }
763
764 int
765 rte_hash_lookup_with_hash_data(const struct rte_hash *h,
766                         const void *key, hash_sig_t sig, void **data)
767 {
768         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
769         return __rte_hash_lookup_with_hash(h, key, sig, data);
770 }
771
772 int
773 rte_hash_lookup_data(const struct rte_hash *h, const void *key, void **data)
774 {
775         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
776         return __rte_hash_lookup_with_hash(h, key, rte_hash_hash(h, key), data);
777 }
778
779 static inline void
780 remove_entry(const struct rte_hash *h, struct rte_hash_bucket *bkt, unsigned i)
781 {
782         unsigned lcore_id, n_slots;
783         struct lcore_cache *cached_free_slots;
784
785         bkt->sig_current[i] = NULL_SIGNATURE;
786         bkt->sig_alt[i] = NULL_SIGNATURE;
787         if (h->hw_trans_mem_support) {
788                 lcore_id = rte_lcore_id();
789                 cached_free_slots = &h->local_free_slots[lcore_id];
790                 /* Cache full, need to free it. */
791                 if (cached_free_slots->len == LCORE_CACHE_SIZE) {
792                         /* Need to enqueue the free slots in global ring. */
793                         n_slots = rte_ring_mp_enqueue_burst(h->free_slots,
794                                                 cached_free_slots->objs,
795                                                 LCORE_CACHE_SIZE, NULL);
796                         cached_free_slots->len -= n_slots;
797                 }
798                 /* Put index of new free slot in cache. */
799                 cached_free_slots->objs[cached_free_slots->len] =
800                                 (void *)((uintptr_t)bkt->key_idx[i]);
801                 cached_free_slots->len++;
802         } else {
803                 rte_ring_sp_enqueue(h->free_slots,
804                                 (void *)((uintptr_t)bkt->key_idx[i]));
805         }
806 }
807
808 static inline int32_t
809 __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,
810                                                 hash_sig_t sig)
811 {
812         uint32_t bucket_idx;
813         hash_sig_t alt_hash;
814         unsigned i;
815         struct rte_hash_bucket *bkt;
816         struct rte_hash_key *k, *keys = h->key_store;
817         int32_t ret;
818
819         bucket_idx = sig & h->bucket_bitmask;
820         bkt = &h->buckets[bucket_idx];
821
822         /* Check if key is in primary location */
823         for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
824                 if (bkt->sig_current[i] == sig &&
825                                 bkt->key_idx[i] != EMPTY_SLOT) {
826                         k = (struct rte_hash_key *) ((char *)keys +
827                                         bkt->key_idx[i] * h->key_entry_size);
828                         if (rte_hash_cmp_eq(key, k->key, h) == 0) {
829                                 remove_entry(h, bkt, i);
830
831                                 /*
832                                  * Return index where key is stored,
833                                  * subtracting the first dummy index
834                                  */
835                                 ret = bkt->key_idx[i] - 1;
836                                 bkt->key_idx[i] = EMPTY_SLOT;
837                                 return ret;
838                         }
839                 }
840         }
841
842         /* Calculate secondary hash */
843         alt_hash = rte_hash_secondary_hash(sig);
844         bucket_idx = alt_hash & h->bucket_bitmask;
845         bkt = &h->buckets[bucket_idx];
846
847         /* Check if key is in secondary location */
848         for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
849                 if (bkt->sig_current[i] == alt_hash &&
850                                 bkt->key_idx[i] != EMPTY_SLOT) {
851                         k = (struct rte_hash_key *) ((char *)keys +
852                                         bkt->key_idx[i] * h->key_entry_size);
853                         if (rte_hash_cmp_eq(key, k->key, h) == 0) {
854                                 remove_entry(h, bkt, i);
855
856                                 /*
857                                  * Return index where key is stored,
858                                  * subtracting the first dummy index
859                                  */
860                                 ret = bkt->key_idx[i] - 1;
861                                 bkt->key_idx[i] = EMPTY_SLOT;
862                                 return ret;
863                         }
864                 }
865         }
866
867         return -ENOENT;
868 }
869
870 int32_t
871 rte_hash_del_key_with_hash(const struct rte_hash *h,
872                         const void *key, hash_sig_t sig)
873 {
874         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
875         return __rte_hash_del_key_with_hash(h, key, sig);
876 }
877
878 int32_t
879 rte_hash_del_key(const struct rte_hash *h, const void *key)
880 {
881         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
882         return __rte_hash_del_key_with_hash(h, key, rte_hash_hash(h, key));
883 }
884
885 int
886 rte_hash_get_key_with_position(const struct rte_hash *h, const int32_t position,
887                                void **key)
888 {
889         RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
890
891         struct rte_hash_key *k, *keys = h->key_store;
892         k = (struct rte_hash_key *) ((char *) keys + (position + 1) *
893                                      h->key_entry_size);
894         *key = k->key;
895
896         if (position !=
897             __rte_hash_lookup_with_hash(h, *key, rte_hash_hash(h, *key),
898                                         NULL)) {
899                 return -ENOENT;
900         }
901
902         return 0;
903 }
904
905 static inline void
906 compare_signatures(uint32_t *prim_hash_matches, uint32_t *sec_hash_matches,
907                         const struct rte_hash_bucket *prim_bkt,
908                         const struct rte_hash_bucket *sec_bkt,
909                         hash_sig_t prim_hash, hash_sig_t sec_hash,
910                         enum rte_hash_sig_compare_function sig_cmp_fn)
911 {
912         unsigned int i;
913
914         switch (sig_cmp_fn) {
915 #ifdef RTE_MACHINE_CPUFLAG_AVX2
916         case RTE_HASH_COMPARE_AVX2:
917                 *prim_hash_matches = _mm256_movemask_ps((__m256)_mm256_cmpeq_epi32(
918                                 _mm256_load_si256(
919                                         (__m256i const *)prim_bkt->sig_current),
920                                 _mm256_set1_epi32(prim_hash)));
921                 *sec_hash_matches = _mm256_movemask_ps((__m256)_mm256_cmpeq_epi32(
922                                 _mm256_load_si256(
923                                         (__m256i const *)sec_bkt->sig_current),
924                                 _mm256_set1_epi32(sec_hash)));
925                 break;
926 #endif
927 #ifdef RTE_MACHINE_CPUFLAG_SSE2
928         case RTE_HASH_COMPARE_SSE:
929                 /* Compare the first 4 signatures in the bucket */
930                 *prim_hash_matches = _mm_movemask_ps((__m128)_mm_cmpeq_epi16(
931                                 _mm_load_si128(
932                                         (__m128i const *)prim_bkt->sig_current),
933                                 _mm_set1_epi32(prim_hash)));
934                 *prim_hash_matches |= (_mm_movemask_ps((__m128)_mm_cmpeq_epi16(
935                                 _mm_load_si128(
936                                         (__m128i const *)&prim_bkt->sig_current[4]),
937                                 _mm_set1_epi32(prim_hash)))) << 4;
938                 /* Compare the first 4 signatures in the bucket */
939                 *sec_hash_matches = _mm_movemask_ps((__m128)_mm_cmpeq_epi16(
940                                 _mm_load_si128(
941                                         (__m128i const *)sec_bkt->sig_current),
942                                 _mm_set1_epi32(sec_hash)));
943                 *sec_hash_matches |= (_mm_movemask_ps((__m128)_mm_cmpeq_epi16(
944                                 _mm_load_si128(
945                                         (__m128i const *)&sec_bkt->sig_current[4]),
946                                 _mm_set1_epi32(sec_hash)))) << 4;
947                 break;
948 #endif
949         default:
950                 for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
951                         *prim_hash_matches |=
952                                 ((prim_hash == prim_bkt->sig_current[i]) << i);
953                         *sec_hash_matches |=
954                                 ((sec_hash == sec_bkt->sig_current[i]) << i);
955                 }
956         }
957
958 }
959
960 #define PREFETCH_OFFSET 4
961 static inline void
962 __rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,
963                         int32_t num_keys, int32_t *positions,
964                         uint64_t *hit_mask, void *data[])
965 {
966         uint64_t hits = 0;
967         int32_t i;
968         uint32_t prim_hash[RTE_HASH_LOOKUP_BULK_MAX];
969         uint32_t sec_hash[RTE_HASH_LOOKUP_BULK_MAX];
970         const struct rte_hash_bucket *primary_bkt[RTE_HASH_LOOKUP_BULK_MAX];
971         const struct rte_hash_bucket *secondary_bkt[RTE_HASH_LOOKUP_BULK_MAX];
972         uint32_t prim_hitmask[RTE_HASH_LOOKUP_BULK_MAX] = {0};
973         uint32_t sec_hitmask[RTE_HASH_LOOKUP_BULK_MAX] = {0};
974
975         /* Prefetch first keys */
976         for (i = 0; i < PREFETCH_OFFSET && i < num_keys; i++)
977                 rte_prefetch0(keys[i]);
978
979         /*
980          * Prefetch rest of the keys, calculate primary and
981          * secondary bucket and prefetch them
982          */
983         for (i = 0; i < (num_keys - PREFETCH_OFFSET); i++) {
984                 rte_prefetch0(keys[i + PREFETCH_OFFSET]);
985
986                 prim_hash[i] = rte_hash_hash(h, keys[i]);
987                 sec_hash[i] = rte_hash_secondary_hash(prim_hash[i]);
988
989                 primary_bkt[i] = &h->buckets[prim_hash[i] & h->bucket_bitmask];
990                 secondary_bkt[i] = &h->buckets[sec_hash[i] & h->bucket_bitmask];
991
992                 rte_prefetch0(primary_bkt[i]);
993                 rte_prefetch0(secondary_bkt[i]);
994         }
995
996         /* Calculate and prefetch rest of the buckets */
997         for (; i < num_keys; i++) {
998                 prim_hash[i] = rte_hash_hash(h, keys[i]);
999                 sec_hash[i] = rte_hash_secondary_hash(prim_hash[i]);
1000
1001                 primary_bkt[i] = &h->buckets[prim_hash[i] & h->bucket_bitmask];
1002                 secondary_bkt[i] = &h->buckets[sec_hash[i] & h->bucket_bitmask];
1003
1004                 rte_prefetch0(primary_bkt[i]);
1005                 rte_prefetch0(secondary_bkt[i]);
1006         }
1007
1008         /* Compare signatures and prefetch key slot of first hit */
1009         for (i = 0; i < num_keys; i++) {
1010                 compare_signatures(&prim_hitmask[i], &sec_hitmask[i],
1011                                 primary_bkt[i], secondary_bkt[i],
1012                                 prim_hash[i], sec_hash[i], h->sig_cmp_fn);
1013
1014                 if (prim_hitmask[i]) {
1015                         uint32_t first_hit = __builtin_ctzl(prim_hitmask[i]);
1016                         uint32_t key_idx = primary_bkt[i]->key_idx[first_hit];
1017                         const struct rte_hash_key *key_slot =
1018                                 (const struct rte_hash_key *)(
1019                                 (const char *)h->key_store +
1020                                 key_idx * h->key_entry_size);
1021                         rte_prefetch0(key_slot);
1022                         continue;
1023                 }
1024
1025                 if (sec_hitmask[i]) {
1026                         uint32_t first_hit = __builtin_ctzl(sec_hitmask[i]);
1027                         uint32_t key_idx = secondary_bkt[i]->key_idx[first_hit];
1028                         const struct rte_hash_key *key_slot =
1029                                 (const struct rte_hash_key *)(
1030                                 (const char *)h->key_store +
1031                                 key_idx * h->key_entry_size);
1032                         rte_prefetch0(key_slot);
1033                 }
1034         }
1035
1036         /* Compare keys, first hits in primary first */
1037         for (i = 0; i < num_keys; i++) {
1038                 positions[i] = -ENOENT;
1039                 while (prim_hitmask[i]) {
1040                         uint32_t hit_index = __builtin_ctzl(prim_hitmask[i]);
1041
1042                         uint32_t key_idx = primary_bkt[i]->key_idx[hit_index];
1043                         const struct rte_hash_key *key_slot =
1044                                 (const struct rte_hash_key *)(
1045                                 (const char *)h->key_store +
1046                                 key_idx * h->key_entry_size);
1047                         /*
1048                          * If key index is 0, do not compare key,
1049                          * as it is checking the dummy slot
1050                          */
1051                         if (!!key_idx & !rte_hash_cmp_eq(key_slot->key, keys[i], h)) {
1052                                 if (data != NULL)
1053                                         data[i] = key_slot->pdata;
1054
1055                                 hits |= 1ULL << i;
1056                                 positions[i] = key_idx - 1;
1057                                 goto next_key;
1058                         }
1059                         prim_hitmask[i] &= ~(1 << (hit_index));
1060                 }
1061
1062                 while (sec_hitmask[i]) {
1063                         uint32_t hit_index = __builtin_ctzl(sec_hitmask[i]);
1064
1065                         uint32_t key_idx = secondary_bkt[i]->key_idx[hit_index];
1066                         const struct rte_hash_key *key_slot =
1067                                 (const struct rte_hash_key *)(
1068                                 (const char *)h->key_store +
1069                                 key_idx * h->key_entry_size);
1070                         /*
1071                          * If key index is 0, do not compare key,
1072                          * as it is checking the dummy slot
1073                          */
1074
1075                         if (!!key_idx & !rte_hash_cmp_eq(key_slot->key, keys[i], h)) {
1076                                 if (data != NULL)
1077                                         data[i] = key_slot->pdata;
1078
1079                                 hits |= 1ULL << i;
1080                                 positions[i] = key_idx - 1;
1081                                 goto next_key;
1082                         }
1083                         sec_hitmask[i] &= ~(1 << (hit_index));
1084                 }
1085
1086 next_key:
1087                 continue;
1088         }
1089
1090         if (hit_mask != NULL)
1091                 *hit_mask = hits;
1092 }
1093
1094 int
1095 rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,
1096                       uint32_t num_keys, int32_t *positions)
1097 {
1098         RETURN_IF_TRUE(((h == NULL) || (keys == NULL) || (num_keys == 0) ||
1099                         (num_keys > RTE_HASH_LOOKUP_BULK_MAX) ||
1100                         (positions == NULL)), -EINVAL);
1101
1102         __rte_hash_lookup_bulk(h, keys, num_keys, positions, NULL, NULL);
1103         return 0;
1104 }
1105
1106 int
1107 rte_hash_lookup_bulk_data(const struct rte_hash *h, const void **keys,
1108                       uint32_t num_keys, uint64_t *hit_mask, void *data[])
1109 {
1110         RETURN_IF_TRUE(((h == NULL) || (keys == NULL) || (num_keys == 0) ||
1111                         (num_keys > RTE_HASH_LOOKUP_BULK_MAX) ||
1112                         (hit_mask == NULL)), -EINVAL);
1113
1114         int32_t positions[num_keys];
1115
1116         __rte_hash_lookup_bulk(h, keys, num_keys, positions, hit_mask, data);
1117
1118         /* Return number of hits */
1119         return __builtin_popcountl(*hit_mask);
1120 }
1121
1122 int32_t
1123 rte_hash_iterate(const struct rte_hash *h, const void **key, void **data, uint32_t *next)
1124 {
1125         uint32_t bucket_idx, idx, position;
1126         struct rte_hash_key *next_key;
1127
1128         RETURN_IF_TRUE(((h == NULL) || (next == NULL)), -EINVAL);
1129
1130         const uint32_t total_entries = h->num_buckets * RTE_HASH_BUCKET_ENTRIES;
1131         /* Out of bounds */
1132         if (*next >= total_entries)
1133                 return -ENOENT;
1134
1135         /* Calculate bucket and index of current iterator */
1136         bucket_idx = *next / RTE_HASH_BUCKET_ENTRIES;
1137         idx = *next % RTE_HASH_BUCKET_ENTRIES;
1138
1139         /* If current position is empty, go to the next one */
1140         while (h->buckets[bucket_idx].key_idx[idx] == EMPTY_SLOT) {
1141                 (*next)++;
1142                 /* End of table */
1143                 if (*next == total_entries)
1144                         return -ENOENT;
1145                 bucket_idx = *next / RTE_HASH_BUCKET_ENTRIES;
1146                 idx = *next % RTE_HASH_BUCKET_ENTRIES;
1147         }
1148
1149         /* Get position of entry in key table */
1150         position = h->buckets[bucket_idx].key_idx[idx];
1151         next_key = (struct rte_hash_key *) ((char *)h->key_store +
1152                                 position * h->key_entry_size);
1153         /* Return key and data */
1154         *key = next_key->key;
1155         *data = next_key->pdata;
1156
1157         /* Increment iterator */
1158         (*next)++;
1159
1160         return position - 1;
1161 }