Peng, please find quick review bellow.

The main comment is you need to split this patch on 3 patches:
- "api:" patch with proposal api change;
- implementation patch
- validation test patch.

I just wanted to move code from helper to linux-generic and reuse it for shm ipc.
But now it looks like it's needed to move ring code to main odp api.


  CC       cuckoo_hash.lo
cuckoo_hash.c:248:10: warning: Function call argument is an uninitialized value
                while (odph_ring_sc_dequeue(r, ptr) == 0) {
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cuckoo_hash.c:339:9: warning: Function call argument is an uninitialized value
        while (odph_ring_sc_dequeue(h->free_slots, ptr) == 0) {
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  CC       odp_cuckoo_hash.o
odp_cuckoo_hash.c:217:2: warning: Value stored to 'ret' is never read
        ret = odph_cuckoo_hash_create(&handle, &ut_params);
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
odp_cuckoo_hash.c:453:2: warning: Value stored to 'ret' is never read
        ret = odph_cuckoo_hash_create(&handle, NULL);
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
odp_cuckoo_hash.c:463:2: warning: Value stored to 'ret' is never read
        ret =  odph_cuckoo_hash_create(&handle, &params);
        ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
odp_cuckoo_hash.c:483:2: warning: Value stored to 'ret' is never read
        ret = odph_cuckoo_hash_create(&handle, &params);
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
odp_cuckoo_hash.c:525:2: warning: Value stored to 'ret' is never read
        ret = odph_cuckoo_hash_create(&tmp, &params);
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
odp_cuckoo_hash.c:543:2: warning: Value stored to 'ret' is never read
        ret = odph_cuckoo_hash_create(&tmp, &params);
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
odp_cuckoo_hash.c:575:2: warning: Value stored to 'ret' is never read
        ret = odph_cuckoo_hash_create(&handle, &ut_params);
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
odp_cuckoo_hash.c:595:19: warning: The right operand of '!=' is a garbage value
                                if (next_data != data[i]) {
                                              ^  ~~~~~~~
odp_cuckoo_hash.c:649:2: warning: Value stored to 'ret' is never read
        ret = odph_cuckoo_hash_create(&handle, &ut_params);
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

On 11/26/2015 05:26, Peng wrote:
Signed-off-by: Peng <xnhp0...@icloud.com>
---
  helper/Makefile.am                      |    2 +
  helper/cuckoo_hash.c                    | 1117 +++++++++++++++++++++++++++++++
  helper/include/odp/helper/cuckoo_hash.h |  435 ++++++++++++
  helper/include/odp/helper/ring.h        |   43 ++
  helper/ring.c                           |   28 +
  helper/test/Makefile.am                 |    4 +-
  helper/test/odp_cuckoo_hash.c           |  779 +++++++++++++++++++++
  include/odp/api/hash.h                  |   14 +
  8 files changed, 2421 insertions(+), 1 deletion(-)
  create mode 100644 helper/cuckoo_hash.c
  create mode 100644 helper/include/odp/helper/cuckoo_hash.h
  create mode 100644 helper/test/odp_cuckoo_hash.c

diff --git a/helper/Makefile.am b/helper/Makefile.am
index e72507e..e923aa8 100644
--- a/helper/Makefile.am
+++ b/helper/Makefile.am
@@ -18,6 +18,7 @@ helperinclude_HEADERS = \
                  $(srcdir)/include/odp/helper/ipsec.h\
                  $(srcdir)/include/odp/helper/tcp.h\
                  $(srcdir)/include/odp/helper/table.h\
alphabetic order
+                 $(srcdir)/include/odp/helper/cuckoo_hash.h\
                  $(srcdir)/include/odp/helper/udp.h
noinst_HEADERS = \
@@ -30,6 +31,7 @@ noinst_HEADERS = \
  __LIB__libodphelper_la_SOURCES = \
                                        linux.c \
                                        ring.c \
+                                       cuckoo_hash.c \
alphabetic order here also
                                        hashtable.c \
                                        lineartable.c
diff --git a/helper/cuckoo_hash.c b/helper/cuckoo_hash.c
new file mode 100644
index 0000000..4a4b56b
--- /dev/null
+++ b/helper/cuckoo_hash.c
@@ -0,0 +1,1117 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/queue.h>
+
+#include <odp/helper/cuckoo_hash.h>
+#include <odp/shared_memory.h>
+#include <odp/spinlock.h>
+#include <odp/align.h>
+#include <odp/api/errno.h>
+#include <odp/rwlock.h>
+#include <odp/hints.h>
+#include <odp/helper/ring.h>
+#include "odph_debug.h"
+
+/* Macro to enable/disable run-time checking of function parameters */
+#define RETURN_IF_TRUE(cond, retval) do { \
+       if (cond) \
+               return retval; \
+} while (0)
+
+/* Hash function used if none is specified */
+#include <odp/hash.h>
+
+/** Number of items per bucket. */
+#define HASH_BUCKET_ENTRIES            4
+#define NULL_SIGNATURE                 0
+#define KEY_ALIGNMENT                  16
+
+/** Maximum size of hash table that can be created. */
+#define HASH_ENTRIES_MAX        1048576
+
+/** Maximum number of keys that can be
+ *  searched for using odph_hash_lookup_bulk. */
+#define HASH_LOOKUP_BULK_MAX   64
+#define HASH_LOOKUP_MULTI_MAX  HASH_LOOKUP_BULK_MAX
+
+/* Structure storing both primary and secondary hashes */
+struct cuckoo_hash_signatures {
+       union {
+               struct {
+                       uint32_t current;
+                       uint32_t alt;
+               };
+               uint64_t sig;
+       };
+};
+
+/* Structure that stores key-value pair */
+struct cuckoo_hash_key {
+       union {
+               uintptr_t idata;
+               void *pdata;
+       };
+       /* Variable key size */
+       char key[0];
+} ODP_ALIGNED(KEY_ALIGNMENT);
+
+/** Bucket structure */
+struct cuckoo_hash_bucket {
+       struct cuckoo_hash_signatures signatures[HASH_BUCKET_ENTRIES];
+       /* Includes dummy key index that always contains index 0 */
+       uint32_t key_idx[HASH_BUCKET_ENTRIES + 1];
+       uint8_t flag[HASH_BUCKET_ENTRIES];
+} ODP_ALIGNED_CACHE;
+
+/**
+ * Aligns input parameter to the next power of 2
+ *
+ * @param x
+ *   The integer value to algin
+ *
+ * @return
+ *   Input parameter aligned to the next power of 2
+ */
+static inline uint32_t
+align32pow2(uint32_t x)
+{
+       x--;
+       x |= x >> 1;
+       x |= x >> 2;
+       x |= x >> 4;
+       x |= x >> 8;
+       x |= x >> 16;
+
+       return x + 1;
+}
+
+/**
+ * Returns true if n is a power of 2
+ * @param n
+ *     Number to check
+ * @return 1 if true, 0 otherwise
+ */
+static inline int
+is_power_of_2(uint32_t n)
+{
+       return n && !(n & (n - 1));
+}
+
+odph_cuckoo_hash_tbl_t *
+odph_cuckoo_hash_find_existing(const char *name)
+{
+       odph_cuckoo_hash_tbl_t *h = NULL;
+       odp_shm_t shm = odp_shm_lookup(name);
+
+       if (shm == ODP_SHM_INVALID)
+               return NULL;
+
+       h = (odph_cuckoo_hash_tbl_t *)odp_shm_addr(shm);
+       return h;
+}
+
+int
+odph_cuckoo_hash_create(odph_cuckoo_hash_tbl_t **ht,
+                       const odph_cuckoo_hash_param_t *params)
+{
+       odph_cuckoo_hash_tbl_t *h;
+       odph_ring_t *r = NULL;
+       odp_shm_t shm_h, shm_b, shm_k;
+
+       char bucket_name[ODPH_CUCKOO_HASH_NAMESIZE + 2],
+            key_name[ODPH_CUCKOO_HASH_NAMESIZE + 2];
+
+       void *ptr, *k = NULL;
+       void *buckets = NULL;
+       char ring_name[ODPH_RING_NAMESIZE];
+       unsigned i;
+
+       if (params == NULL) {
+               ODPH_ERR("no parameters\n");
+               *ht = NULL;
+               return -EINVAL;
+       }
+
+       /* Check for valid parameters */
+       if (
+           (params->entries > HASH_ENTRIES_MAX) ||
+           (params->entries < HASH_BUCKET_ENTRIES) ||
+           (params->key_len == 0) ||
+           (strlen(params->name) == 0)) {
+               ODPH_ERR("invalid parameters\n");
+               *ht = NULL;
+               return -EINVAL;
+       }
+
+       /* Guarantee there's no existing */
+       h = odph_cuckoo_hash_find_existing(params->name);
+       if (h != NULL) {
+               ODPH_ERR("cuckoo hash table %s already exists\n", params->name);
+               *ht = h;
+               return -EEXIST;
+       }
+
+       shm_h = odp_shm_reserve(
+                               params->name, sizeof(odph_cuckoo_hash_tbl_t),
+                               ODP_CACHE_LINE_SIZE, ODP_SHM_SW_ONLY);
+
+       if (shm_h == ODP_SHM_INVALID) {
+               ODPH_ERR("shm allocation failed for odph_cuckoo_hash_tbl %s\n",
+                        params->name);
+               *ht = NULL;
+               return -ENOMEM;
+       }
+       h = odp_shm_addr(shm_h);
+
+       snprintf(bucket_name, sizeof(bucket_name), "B_%s", params->name);
+       const uint32_t num_buckets =
+               align32pow2(params->entries) / HASH_BUCKET_ENTRIES;
+
+       shm_b = odp_shm_reserve(
+                               bucket_name,
+                               num_buckets * sizeof(struct cuckoo_hash_bucket),
+                               ODP_CACHE_LINE_SIZE, ODP_SHM_SW_ONLY);
+
+       if (shm_b == ODP_SHM_INVALID) {
+               ODPH_ERR("shm allocation failed for cuckoo_hash_bucket\n");
+               odp_shm_free(shm_h);
+               *ht = NULL;
+               return -ENOMEM;
+       }
+
+       buckets = odp_shm_addr(shm_b);
+
+       snprintf(key_name, sizeof(key_name), "K_%s", params->name);
+       const uint32_t key_entry_size =
+               sizeof(struct cuckoo_hash_key) + params->key_len;
+       /* Store all keys and leave the first entry
+          as a dummy entry for lookup_bulk */
+       const uint64_t key_tbl_size = key_entry_size * (params->entries + 1);
+
+       shm_k = odp_shm_reserve(key_name, key_tbl_size, ODP_CACHE_LINE_SIZE,
+                               ODP_SHM_SW_ONLY);
+       if (shm_k == ODP_SHM_INVALID) {
+               ODPH_ERR("shm allocation failed for key_store\n");
+               odp_shm_free(shm_b);
+               odp_shm_free(shm_h);
+               *ht = NULL;
+               return -ENOMEM;
+       }
+       k = odp_shm_addr(shm_k);
+
+       snprintf(ring_name, sizeof(ring_name), "RI_%s", params->name);
+       r = odph_ring_lookup(ring_name);
+       if (r != NULL) {
+               /* clear the free ring */
+               while (odph_ring_sc_dequeue(r, ptr) == 0) {
+                       /* empty */
+               }
+       } else {
+               r = odph_ring_create(ring_name,
+                                    align32pow2(params->entries + 1), 0);
+       }
+
+       if (r == NULL) {
+               odp_shm_free(shm_k);
+               odp_shm_free(shm_b);
+               odp_shm_free(shm_h);
+               *ht = NULL;
+               return -ENOMEM;
+       }
+
+       /* Setup hash context */
+       snprintf(h->name, sizeof(h->name), "%s", params->name);
+       h->entries = params->entries;
+       h->key_len = params->key_len;
+       h->key_entry_size = key_entry_size;
+       h->hash_func_init_val = params->hash_func_init_val;
+       h->hash_cmp_eq = memcmp;
+
+       h->num_buckets = num_buckets;
+       h->bucket_bitmask = h->num_buckets - 1;
+       h->buckets = buckets;
+
+       /*default hash function is CRC 32*/
+       h->hash_func = (params->hash_func == NULL) ?
+               odp_hash_crc32c : params->hash_func;
+
+       h->key_store = k;
+       h->free_slots = r;
+
+       h->shm_bucket = shm_b;
+       h->shm_key = shm_k;
+
+       /* populate the free slots ring.
+        * Entry zero is reserved for key misses
+        */
+       for (i = 1; i < params->entries + 1; i++)
+               odph_ring_sp_enqueue(r, (void *)((uintptr_t)i));
+       *ht = h;
+       return 0;
+}
+
+void
+odph_cuckoo_hash_destroy(odph_cuckoo_hash_tbl_t *h)
+{
+       if (h == NULL)
+               return;
+
+       odph_ring_free(h->free_slots);
+       odp_shm_free(h->shm_key);
+       odp_shm_free(h->shm_bucket);
+       odp_shm_free(odp_shm_lookup(h->name));
+}
+
+static uint32_t hash(const odph_cuckoo_hash_tbl_t *h, const void *key)
+{
+       /* calc hash result by key */
+       return h->hash_func(key, h->key_len, h->hash_func_init_val);
+}
+
+/* Calc the secondary hash value from the primary hash value of a given key */
+static inline uint32_t
+hash_secondary(const uint32_t primary_hash)
+{
+       static const unsigned all_bits_shift = 12;
+       static const unsigned alt_bits_xor = 0x5bd1e995;
+
+       uint32_t tag = primary_hash >> all_bits_shift;
+
+       return (primary_hash ^ ((tag + 1) * alt_bits_xor));
+}
+
+void
+odph_cuckoo_hash_reset(odph_cuckoo_hash_tbl_t *h)
+{
+       void *ptr;
+       unsigned i;
+
+       if (h == NULL)
+               return;
+
+       memset(h->buckets, 0,
+              h->num_buckets * sizeof(struct cuckoo_hash_bucket));
+       memset(h->key_store, 0, h->key_entry_size * (h->entries + 1));
+
+       /* clear the free ring */
+       while (odph_ring_sc_dequeue(h->free_slots, ptr) == 0) {
+               /* empty */
+       }
+
+       /* Repopulate the free slots ring.
+        * Entry zero is reserved for key misses */
+       for (i = 1; i < h->entries + 1; i++)
+               odph_ring_sp_enqueue(h->free_slots, (void *)((uintptr_t)i));
+}
+
+/* Search for an entry that can be pushed to its alternative location */
+static inline int
+make_space_bucket(const odph_cuckoo_hash_tbl_t *h,
+                 struct cuckoo_hash_bucket *bkt)
+{
+       unsigned i, j;
+       int ret;
+       uint32_t next_bucket_idx;
+       struct cuckoo_hash_bucket *next_bkt[HASH_BUCKET_ENTRIES];
+
+       /*
+        * Push existing item (search for bucket with space in
+        * alternative locations) to its alternative location
+        */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               /* Search for space in alternative locations */
+               next_bucket_idx = bkt->signatures[i].alt & h->bucket_bitmask;
+               next_bkt[i] = &h->buckets[next_bucket_idx];
+               for (j = 0; j < HASH_BUCKET_ENTRIES; j++) {
+                       if (next_bkt[i]->signatures[j].sig == NULL_SIGNATURE)
+                               break;
+               }
+
+               if (j != HASH_BUCKET_ENTRIES)
+                       break;
+       }
+
+       /* Alternative location has spare room (end of recursive function) */
+       if (i != HASH_BUCKET_ENTRIES) {
+               next_bkt[i]->signatures[j].alt = bkt->signatures[i].current;
+               next_bkt[i]->signatures[j].current = bkt->signatures[i].alt;
+               next_bkt[i]->key_idx[j] = bkt->key_idx[i];
+               return i;
+       }
+
+       /* Pick entry that has not been pushed yet */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++)
+               if (bkt->flag[i] == 0)
+                       break;
+
+       /* All entries have been pushed, so entry cannot be added */
+       if (i == HASH_BUCKET_ENTRIES)
+               return -ENOSPC;
+
+       /* Set flag to indicate that this entry is going to be pushed */
+       bkt->flag[i] = 1;
+       /* Need room in alternative bucket to insert the pushed entry */
+       ret = make_space_bucket(h, next_bkt[i]);
+       /*
+        * After recursive function.
+        * Clear flags and insert the pushed entry
+        * in its alternative location if successful,
+        * or return error
+        */
+       bkt->flag[i] = 0;
+       if (ret >= 0) {
+               next_bkt[i]->signatures[ret].alt = bkt->signatures[i].current;
+               next_bkt[i]->signatures[ret].current = bkt->signatures[i].alt;
+               next_bkt[i]->key_idx[ret] = bkt->key_idx[i];
+               return i;
+       }
+
+       return ret;
+}
+
+static inline int32_t
+cuckoo_hash_add_key_with_hash(
+               const odph_cuckoo_hash_tbl_t *h, const void *key,
+               uint32_t sig, void *data)
+{
+       uint32_t alt_hash;
+       uint32_t prim_bucket_idx, sec_bucket_idx;
+       unsigned i;
+       struct cuckoo_hash_bucket *prim_bkt, *sec_bkt;
+       struct cuckoo_hash_key *new_k, *k, *keys = h->key_store;
+       void *slot_id;
+       uint32_t new_idx;
+       int ret;
+
+       prim_bucket_idx = sig & h->bucket_bitmask;
+       prim_bkt = &h->buckets[prim_bucket_idx];
+       __builtin_prefetch((const void *)(uintptr_t)prim_bkt, 0, 3);
+
+       alt_hash = hash_secondary(sig);
+       sec_bucket_idx = alt_hash & h->bucket_bitmask;
+       sec_bkt = &h->buckets[sec_bucket_idx];
+       __builtin_prefetch((const void *)(uintptr_t)sec_bkt, 0, 3);
+
+       /* Get a new slot for storing the new key */
+       if (odph_ring_sc_dequeue_bulk(h->free_slots, &slot_id, 1) != 0)
+               return -ENOSPC;
+       new_k = (void *)((uintptr_t)(keys)
+                       + ((uintptr_t)slot_id * h->key_entry_size));
+       __builtin_prefetch((const void *)(uintptr_t)new_k, 0, 3);
+       new_idx = (uint32_t)((uintptr_t)slot_id);
+
+       /* Check if key is already inseodpd in primary location */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               if (
+                       prim_bkt->signatures[i].current == sig &&
+                       prim_bkt->signatures[i].alt == alt_hash)  {
+                       k = (struct cuckoo_hash_key *)((char *)keys +
+                               prim_bkt->key_idx[i] * h->key_entry_size);
+                       if (h->hash_cmp_eq(key, k->key, h->key_len) == 0) {
+                               odph_ring_sp_enqueue(h->free_slots, slot_id);
+                               /* Update data */
+                               k->pdata = data;
+                               /*
+                                * Return index where key is stored,
+                                * substracting the first dummy index
+                                */
+                               return (prim_bkt->key_idx[i] - 1);
+                       }
+               }
+       }
+
+       /* Check if key is already inseodpd in secondary location */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               if (
+                       sec_bkt->signatures[i].alt == sig &&
+                       sec_bkt->signatures[i].current == alt_hash)  {
+                       k = (struct cuckoo_hash_key *)((char *)keys +
+                               sec_bkt->key_idx[i] * h->key_entry_size);
+                       if (h->hash_cmp_eq(key, k->key, h->key_len) == 0) {
+                               odph_ring_sp_enqueue(h->free_slots, slot_id);
+                               /* Update data */
+                               k->pdata = data;
+                               /*
+                                * Return index where key is stored,
+                                * substracting the first dummy index
+                                */
+                               return (sec_bkt->key_idx[i] - 1);
+                       }
+               }
+       }
+
+       /* Copy key */
+       memcpy(new_k->key, key, h->key_len);
+       new_k->pdata = data;
+
+       /* Insert new entry is there is room in the primary bucket */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               /* Check if slot is available */
+               if (odp_likely(prim_bkt->signatures[i].sig == NULL_SIGNATURE)) {
+                       prim_bkt->signatures[i].current = sig;
+                       prim_bkt->signatures[i].alt = alt_hash;
+                       prim_bkt->key_idx[i] = new_idx;
+                       return new_idx - 1;
+               }
+       }
+
+       /* Primary bucket is full, so we need to make space for new entry */
+       ret = make_space_bucket(h, prim_bkt);
+       /*
+        * After recursive function.
+        * Insert the new entry in the position of the pushed entry
+        * if successful or return error and
+        * store the new slot back in the ring
+        */
+       if (ret >= 0) {
+               prim_bkt->signatures[ret].current = sig;
+               prim_bkt->signatures[ret].alt = alt_hash;
+               prim_bkt->key_idx[ret] = new_idx;
+               return (new_idx - 1);
+       }
+
+       /* Error in addition, store new slot back in the ring */
+       odph_ring_sp_enqueue(
+                       h->free_slots, (void *)((uintptr_t)new_idx));
+       return ret;
+}
+
+int32_t
+odph_cuckoo_hash_add_key_with_hash(
+               const odph_cuckoo_hash_tbl_t *h, const void *key, uint32_t sig)
+{
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       return cuckoo_hash_add_key_with_hash(h, key, sig, 0);
+}
+
+int32_t
+odph_cuckoo_hash_add_key(const odph_cuckoo_hash_tbl_t *h, const void *key)
+{
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       return cuckoo_hash_add_key_with_hash(
+                       h, key, hash(h, key), 0);
+}
+
+int
+odph_cuckoo_hash_add_key_with_hash_data(
+               const odph_cuckoo_hash_tbl_t *h,
+               const void *key, uint32_t sig, void *data)
+{
+       int ret;
+
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       ret = cuckoo_hash_add_key_with_hash(h, key, sig, data);
+       if (ret >= 0)
+               return 0;
+       return ret;
+}
+
+int
+odph_cuckoo_hash_add_key_data(const odph_cuckoo_hash_tbl_t *h,
+                             const void *key, void *data)
+{
+       int ret;
+
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+
+       ret = cuckoo_hash_add_key_with_hash(
+                       h, key, hash(h, key), data);
+       if (ret >= 0)
+               return 0;
+       return ret;
+}
+
+static inline int32_t
+cuckoo_hash_lookup_with_hash(
+               const odph_cuckoo_hash_tbl_t *h, const void *key,
+               uint32_t sig, void **data)
+{
+       uint32_t bucket_idx;
+       uint32_t alt_hash;
+       unsigned i;
+       struct cuckoo_hash_bucket *bkt;
+       struct cuckoo_hash_key *k, *keys = h->key_store;
+
+       bucket_idx = sig & h->bucket_bitmask;
+       bkt = &h->buckets[bucket_idx];
+
+       /* Check if key is in primary location */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               if (
+                       bkt->signatures[i].current == sig &&
+                       bkt->signatures[i].sig != NULL_SIGNATURE) {
+                       k = (void *)((uintptr_t)keys +
+                                       (bkt->key_idx[i] * h->key_entry_size));
+                       if (h->hash_cmp_eq(key, k->key, h->key_len) == 0) {
+                               if (data != NULL)
+                                       *data = k->pdata;
+                               /*
+                                * Return index where key is stored,
+                                * substracting the first dummy index
+                                */
+                               return (bkt->key_idx[i] - 1);
+                       }
+               }
+       }
+
+       /* Calculate secondary hash */
+       alt_hash = hash_secondary(sig);
+       bucket_idx = alt_hash & h->bucket_bitmask;
+       bkt = &h->buckets[bucket_idx];
+
+       /* Check if key is in secondary location */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               if (
+                       bkt->signatures[i].current == alt_hash &&
+                       bkt->signatures[i].alt == sig) {
+                       k = (struct cuckoo_hash_key *)((char *)keys +
+                                       bkt->key_idx[i] * h->key_entry_size);
+                       if (h->hash_cmp_eq(key, k->key, h->key_len) == 0) {
+                               if (data != NULL)
+                                       *data = k->pdata;
+                               /*
+                                * Return index where key is stored,
+                                * substracting the first dummy index
+                                */
+                               return (bkt->key_idx[i] - 1);
+                       }
+               }
+       }
+
+       return -ENOENT;
+}
+
+int32_t
+odph_cuckoo_hash_lookup_with_hash(
+               const odph_cuckoo_hash_tbl_t *h, const void *key, uint32_t sig)
+{
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       return cuckoo_hash_lookup_with_hash(h, key, sig, NULL);
+}
+
+int32_t
+odph_cuckoo_hash_lookup(const odph_cuckoo_hash_tbl_t *h, const void *key)
+{
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       return cuckoo_hash_lookup_with_hash(
+                       h, key, hash(h, key), NULL);
+}
+
+int
+odph_cuckoo_hash_lookup_with_hash_data(
+               const odph_cuckoo_hash_tbl_t *h,
+               const void *key, uint32_t sig, void **data)
+{
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       return cuckoo_hash_lookup_with_hash(h, key, sig, data);
+}
+
+int
+odph_cuckoo_hash_lookup_data(
+               const odph_cuckoo_hash_tbl_t *h,
+               const void *key, void **data)
+{
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       return cuckoo_hash_lookup_with_hash(
+                       h, key, hash(h, key), data);
+}
+
+static inline int32_t
+cuckoo_hash_del_key_with_hash(
+               const odph_cuckoo_hash_tbl_t *h,
+               const void *key, uint32_t sig)
+{
+       uint32_t bucket_idx;
+       uint32_t alt_hash;
+       unsigned i;
+       struct cuckoo_hash_bucket *bkt;
+       struct cuckoo_hash_key *k, *keys = h->key_store;
+
+       bucket_idx = sig & h->bucket_bitmask;
+       bkt = &h->buckets[bucket_idx];
+
+       /* Check if key is in primary location */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               if (
+                       bkt->signatures[i].current == sig &&
+                       bkt->signatures[i].sig != NULL_SIGNATURE) {
+                       k = (struct cuckoo_hash_key *)((char *)keys +
+                                       bkt->key_idx[i] * h->key_entry_size);
+                       if (h->hash_cmp_eq(key, k->key, h->key_len) == 0) {
+                               bkt->signatures[i].sig = NULL_SIGNATURE;
+                               odph_ring_sp_enqueue(
+                                       h->free_slots,
+                                       (void *)((uintptr_t)bkt->key_idx[i]));
+                               /*
+                                * Return index where key is stored,
+                                * substracting the first dummy index
+                                */
+                               return (bkt->key_idx[i] - 1);
+                       }
+               }
+       }
+
+       /* Calculate secondary hash */
+       alt_hash = hash_secondary(sig);
+       bucket_idx = alt_hash & h->bucket_bitmask;
+       bkt = &h->buckets[bucket_idx];
+
+       /* Check if key is in secondary location */
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               if (
+                       bkt->signatures[i].current == alt_hash &&
+                       bkt->signatures[i].sig != NULL_SIGNATURE) {
+                       k = (struct cuckoo_hash_key *)((char *)keys +
+                                       bkt->key_idx[i] * h->key_entry_size);
+                       if (h->hash_cmp_eq(key, k->key, h->key_len) == 0) {
+                               bkt->signatures[i].sig = NULL_SIGNATURE;
+                               odph_ring_sp_enqueue(
+                                       h->free_slots,
+                                       (void *)((uintptr_t)bkt->key_idx[i]));
+                               /*
+                                * Return index where key is stored,
+                                * substracting the first dummy index
+                                */
+                               return (bkt->key_idx[i] - 1);
+                       }
+               }
+       }
+
+       return -ENOENT;
+}
+
+int32_t
+odph_cuckoo_hash_del_key_with_hash(
+               const odph_cuckoo_hash_tbl_t *h,
+               const void *key, uint32_t sig)
+{
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       return cuckoo_hash_del_key_with_hash(h, key, sig);
+}
+
+int32_t
+odph_cuckoo_hash_del_key(const odph_cuckoo_hash_tbl_t *h, const void *key)
+{
+       RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);
+       return cuckoo_hash_del_key_with_hash(
+                       h, key, hash(h, key));
+}
+
+/* Lookup bulk stage 0: Prefetch input key */
+static inline void
+lookup_stage0(
+               unsigned *idx, uint64_t *lookup_mask,
+               const void * const *keys)
+{
+       *idx = __builtin_ctzl(*lookup_mask);
+       if (*lookup_mask == 0)
+               *idx = 0;
+
+       __builtin_prefetch((const void *)(uintptr_t)(keys[*idx]), 0, 3);
+       *lookup_mask &= ~(1llu << *idx);
+}
+
+/*
+ * Lookup bulk stage 1: Calculate primary/secondary hashes
+ * and prefetch primary/secondary buckets
+ */
+static inline void
+lookup_stage1(
+               unsigned idx, uint32_t *prim_hash, uint32_t *sec_hash,
+               const struct cuckoo_hash_bucket **primary_bkt,
+               const struct cuckoo_hash_bucket **secondary_bkt,
+               uint32_t *hash_vals, const void * const *keys,
+               const odph_cuckoo_hash_tbl_t *h)
+{
+       *prim_hash = hash(h, keys[idx]);
+       hash_vals[idx] = *prim_hash;
+       *sec_hash = hash_secondary(*prim_hash);
+
+       *primary_bkt = &h->buckets[*prim_hash & h->bucket_bitmask];
+       *secondary_bkt = &h->buckets[*sec_hash & h->bucket_bitmask];
+
+       __builtin_prefetch((const void *)(uintptr_t)(*primary_bkt), 0, 3);
+       __builtin_prefetch((const void *)(uintptr_t)(*secondary_bkt), 0, 3);
+}
+
+/*
+ * Lookup bulk stage 2:  Search for match hashes in primary/secondary locations
+ * and prefetch first key slot
+ */
+static inline void
+lookup_stage2(
+               unsigned idx, uint32_t prim_hash, uint32_t sec_hash,
+               const struct cuckoo_hash_bucket *prim_bkt,
+               const struct cuckoo_hash_bucket *sec_bkt,
+               const struct cuckoo_hash_key **key_slot, int32_t *positions,
+               uint64_t *extra_hits_mask, const void *keys,
+               const odph_cuckoo_hash_tbl_t *h)
+{
+       unsigned prim_hash_matches, sec_hash_matches, key_idx, i;
+       unsigned total_hash_matches;
+
+       prim_hash_matches = 1 << HASH_BUCKET_ENTRIES;
+       sec_hash_matches = 1 << HASH_BUCKET_ENTRIES;
+       for (i = 0; i < HASH_BUCKET_ENTRIES; i++) {
+               prim_hash_matches |=
+                       ((prim_hash == prim_bkt->signatures[i].current) << i);
+               sec_hash_matches |=
+                       ((sec_hash == sec_bkt->signatures[i].current) << i);
+       }
+
+       key_idx = prim_bkt->key_idx[__builtin_ctzl(prim_hash_matches)];
+       if (key_idx == 0)
+               key_idx = sec_bkt->key_idx[__builtin_ctzl(sec_hash_matches)];
+
+       total_hash_matches = (prim_hash_matches |
+                               (sec_hash_matches <<
+                               (HASH_BUCKET_ENTRIES + 1)));
+       *key_slot = (const struct cuckoo_hash_key *)((const char *)keys +
+                                       key_idx * h->key_entry_size);
+
+       __builtin_prefetch((const void *)(uintptr_t)(*key_slot), 0, 3);
+       /*
+        * Return index where key is stored,
+        * substracting the first dummy index
+        */
+       positions[idx] = (key_idx - 1);
+
+       *extra_hits_mask |= (uint64_t)
+               (__builtin_popcount(total_hash_matches) > 3) << idx;
+}
+
+/* Lookup bulk stage 3: Check if key matches, update hit mask and return data 
*/
+static inline void
+lookup_stage3(
+               unsigned idx, const struct cuckoo_hash_key *key_slot,
+               const void * const *keys,
+               void *data[], uint64_t *hits, const odph_cuckoo_hash_tbl_t *h)
+{
+       unsigned hit;
+
+       hit = !h->hash_cmp_eq(key_slot->key, keys[idx], h->key_len);
+       if (data != NULL)
+               data[idx] = key_slot->pdata;
+
+       *hits |= (uint64_t)(hit) << idx;
+}
+
+static inline void
+cuckoo_hash_lookup_bulk(
+               const odph_cuckoo_hash_tbl_t *h, const void **keys,
+               uint32_t num_keys, int32_t *positions,
+               uint64_t *hit_mask, void *data[])
+{
+       uint64_t hits = 0;
+       uint64_t extra_hits_mask = 0;
+       uint64_t lookup_mask, miss_mask;
+       unsigned idx;
+       const void *key_store = h->key_store;
+       int ret;
+       uint32_t hash_vals[HASH_LOOKUP_BULK_MAX];
+
+       unsigned idx00, idx01, idx10, idx11, idx20, idx21, idx30, idx31;
+       const struct cuckoo_hash_bucket *primary_bkt10, *primary_bkt11;
+       const struct cuckoo_hash_bucket *secondary_bkt10, *secondary_bkt11;
+       const struct cuckoo_hash_bucket *primary_bkt20, *primary_bkt21;
+       const struct cuckoo_hash_bucket *secondary_bkt20, *secondary_bkt21;
+       const struct cuckoo_hash_key *k_slot20, *k_slot21, *k_slot30, *k_slot31;
+       uint32_t primary_hash10, primary_hash11;
+       uint32_t secondary_hash10, secondary_hash11;
+       uint32_t primary_hash20, primary_hash21;
+       uint32_t secondary_hash20, secondary_hash21;
+
+       lookup_mask = (uint64_t)-1 >> (64 - num_keys);
+       miss_mask = lookup_mask;
+
+       lookup_stage0(&idx00, &lookup_mask, keys);
+       lookup_stage0(&idx01, &lookup_mask, keys);
+
+       idx10 = idx00, idx11 = idx01;
+
+       lookup_stage0(&idx00, &lookup_mask, keys);
+       lookup_stage0(&idx01, &lookup_mask, keys);
+       lookup_stage1(
+                       idx10, &primary_hash10, &secondary_hash10,
+                       &primary_bkt10, &secondary_bkt10, hash_vals, keys, h);
+       lookup_stage1(
+                       idx11, &primary_hash11, &secondary_hash11,
+                       &primary_bkt11,     &secondary_bkt11, hash_vals, keys, 
h);
+
+       primary_bkt20 = primary_bkt10;
+       primary_bkt21 = primary_bkt11;
+       secondary_bkt20 = secondary_bkt10;
+       secondary_bkt21 = secondary_bkt11;
+       primary_hash20 = primary_hash10;
+       primary_hash21 = primary_hash11;
+       secondary_hash20 = secondary_hash10;
+       secondary_hash21 = secondary_hash11;
+       idx20 = idx10, idx21 = idx11;
+       idx10 = idx00, idx11 = idx01;
+
+       lookup_stage0(&idx00, &lookup_mask, keys);
+       lookup_stage0(&idx01, &lookup_mask, keys);
+       lookup_stage1(
+                       idx10, &primary_hash10, &secondary_hash10,
+                       &primary_bkt10, &secondary_bkt10, hash_vals, keys, h);
+       lookup_stage1(
+                       idx11, &primary_hash11, &secondary_hash11,
+                       &primary_bkt11,     &secondary_bkt11, hash_vals, keys, 
h);
+       lookup_stage2(
+                       idx20, primary_hash20, secondary_hash20, primary_bkt20,
+                       secondary_bkt20, &k_slot20, positions, &extra_hits_mask,
+                       key_store, h);
+       lookup_stage2(
+                       idx21, primary_hash21, secondary_hash21, primary_bkt21,
+                       secondary_bkt21, &k_slot21, positions, &extra_hits_mask,
+                       key_store, h);
+
+       while (lookup_mask) {
+               k_slot30 = k_slot20, k_slot31 = k_slot21;
+               idx30 = idx20, idx31 = idx21;
+               primary_bkt20 = primary_bkt10;
+               primary_bkt21 = primary_bkt11;
+               secondary_bkt20 = secondary_bkt10;
+               secondary_bkt21 = secondary_bkt11;
+               primary_hash20 = primary_hash10;
+               primary_hash21 = primary_hash11;
+               secondary_hash20 = secondary_hash10;
+               secondary_hash21 = secondary_hash11;
+               idx20 = idx10, idx21 = idx11;
+               idx10 = idx00, idx11 = idx01;
+
+               lookup_stage0(&idx00, &lookup_mask, keys);
+               lookup_stage0(&idx01, &lookup_mask, keys);
+               lookup_stage1(
+                               idx10, &primary_hash10, &secondary_hash10,
+                               &primary_bkt10, &secondary_bkt10, hash_vals,
+                               keys, h);
+               lookup_stage1(
+                               idx11, &primary_hash11, &secondary_hash11,
+                               &primary_bkt11,     &secondary_bkt11, hash_vals,
+                               keys, h);
+               lookup_stage2(
+                               idx20, primary_hash20, secondary_hash20,
+                               primary_bkt20, secondary_bkt20, &k_slot20,
+                               positions, &extra_hits_mask, key_store, h);
+               lookup_stage2(
+                               idx21, primary_hash21, secondary_hash21,
+                               primary_bkt21, secondary_bkt21, &k_slot21,
+                               positions, &extra_hits_mask, key_store, h);
+               lookup_stage3(idx30, k_slot30, keys, data, &hits, h);
+               lookup_stage3(idx31, k_slot31, keys, data, &hits, h);
+       }
+
+       k_slot30 = k_slot20, k_slot31 = k_slot21;
+       idx30 = idx20, idx31 = idx21;
+       primary_bkt20 = primary_bkt10;
+       primary_bkt21 = primary_bkt11;
+       secondary_bkt20 = secondary_bkt10;
+       secondary_bkt21 = secondary_bkt11;
+       primary_hash20 = primary_hash10;
+       primary_hash21 = primary_hash11;
+       secondary_hash20 = secondary_hash10;
+       secondary_hash21 = secondary_hash11;
+       idx20 = idx10, idx21 = idx11;
+       idx10 = idx00, idx11 = idx01;
+
+       lookup_stage1(
+                       idx10, &primary_hash10, &secondary_hash10,
+                       &primary_bkt10, &secondary_bkt10, hash_vals, keys, h);
+       lookup_stage1(
+                       idx11, &primary_hash11, &secondary_hash11,
+                       &primary_bkt11,     &secondary_bkt11, hash_vals, keys, 
h);
+       lookup_stage2(
+                       idx20, primary_hash20, secondary_hash20, primary_bkt20,
+                       secondary_bkt20, &k_slot20, positions, &extra_hits_mask,
+                       key_store, h);
+       lookup_stage2(
+                       idx21, primary_hash21, secondary_hash21, primary_bkt21,
+                       secondary_bkt21, &k_slot21, positions, &extra_hits_mask,
+                       key_store, h);
+       lookup_stage3(idx30, k_slot30, keys, data, &hits, h);
+       lookup_stage3(idx31, k_slot31, keys, data, &hits, h);
+
+       k_slot30 = k_slot20, k_slot31 = k_slot21;
+       idx30 = idx20, idx31 = idx21;
+       primary_bkt20 = primary_bkt10;
+       primary_bkt21 = primary_bkt11;
+       secondary_bkt20 = secondary_bkt10;
+       secondary_bkt21 = secondary_bkt11;
+       primary_hash20 = primary_hash10;
+       primary_hash21 = primary_hash11;
+       secondary_hash20 = secondary_hash10;
+       secondary_hash21 = secondary_hash11;
+       idx20 = idx10, idx21 = idx11;
+
+       lookup_stage2(
+                       idx20, primary_hash20, secondary_hash20, primary_bkt20,
+                       secondary_bkt20, &k_slot20, positions, &extra_hits_mask,
+                       key_store, h);
+       lookup_stage2(
+                       idx21, primary_hash21, secondary_hash21, primary_bkt21,
+                       secondary_bkt21, &k_slot21, positions, &extra_hits_mask,
+                       key_store, h);
+       lookup_stage3(idx30, k_slot30, keys, data, &hits, h);
+       lookup_stage3(idx31, k_slot31, keys, data, &hits, h);
+
+       k_slot30 = k_slot20, k_slot31 = k_slot21;
+       idx30 = idx20, idx31 = idx21;
+
+       lookup_stage3(idx30, k_slot30, keys, data, &hits, h);
+       lookup_stage3(idx31, k_slot31, keys, data, &hits, h);
+
+       /* ignore any items we have already found */
+       extra_hits_mask &= ~hits;
+
+       if (odp_unlikely(extra_hits_mask)) {
+               /* run a single search for each remaining item */
+               do {
+                       idx = __builtin_ctzl(extra_hits_mask);
+                       if (data != NULL) {
+                               ret = odph_cuckoo_hash_lookup_with_hash_data(
+                                               h, keys[idx], hash_vals[idx],
+                                               &data[idx]);
+                               if (ret >= 0)
+                                       hits |= 1ULL << idx;
+                       } else {
+                               positions[idx] =
+                                       odph_cuckoo_hash_lookup_with_hash(
+                                               h, keys[idx], hash_vals[idx]);
+                               if (positions[idx] >= 0)
+                                       hits |= 1llu << idx;
+                       }
+                       extra_hits_mask &= ~(1llu << idx);
+               } while (extra_hits_mask);
+       }
+
+       miss_mask &= ~hits;
+       if (odp_unlikely(miss_mask)) {
+               do {
+                       idx = __builtin_ctzl(miss_mask);
+                       positions[idx] = -ENOENT;
+                       miss_mask &= ~(1llu << idx);
+               } while (miss_mask);
+       }
+
+       if (hit_mask != NULL)
+               *hit_mask = hits;
+}
+
+int
+odph_cuckoo_hash_lookup_bulk(
+               const odph_cuckoo_hash_tbl_t *h, const void **keys,
+               uint32_t num_keys, int32_t *positions)
+{
+       RETURN_IF_TRUE(((h == NULL) || (keys == NULL) || (num_keys == 0) ||
+                       (num_keys > HASH_LOOKUP_BULK_MAX) ||
+                       (positions == NULL)), -EINVAL);
+
+       cuckoo_hash_lookup_bulk(
+                       h, keys, num_keys, positions, NULL, NULL);
+       return 0;
+}
+
+int
+odph_cuckoo_hash_lookup_bulk_data(
+               const odph_cuckoo_hash_tbl_t *h, const void **keys,
+               uint32_t num_keys, uint64_t *hit_mask, void *data[])
+{
+       RETURN_IF_TRUE(((h == NULL) || (keys == NULL) || (num_keys == 0) ||
+                       (num_keys > HASH_LOOKUP_BULK_MAX) ||
+                       (hit_mask == NULL)), -EINVAL);
+
+       int32_t positions[num_keys];
+
+       cuckoo_hash_lookup_bulk(
+                       h, keys, num_keys, positions, hit_mask, data);
+
+       /* Return number of hits */
+       return __builtin_popcountl(*hit_mask);
+}
+
+int32_t
+odph_cuckoo_hash_iterate(
+               const odph_cuckoo_hash_tbl_t *h, const void **key,
+               void **data, uint32_t *next)
+{
+       uint32_t bucket_idx, idx, position;
+       struct cuckoo_hash_key *next_key;
+
+       RETURN_IF_TRUE(((h == NULL) || (next == NULL)), -EINVAL);
+
+       const uint32_t total_entries =
+               h->num_buckets * HASH_BUCKET_ENTRIES;
+       /* Out of bounds */
+       if (*next >= total_entries)
+               return -ENOENT;
+
+       /* Calculate bucket and index of current iterator */
+       bucket_idx = *next / HASH_BUCKET_ENTRIES;
+       idx = *next % HASH_BUCKET_ENTRIES;
+
+       /* If current position is empty, go to the next one */
+       while (h->buckets[bucket_idx].signatures[idx].sig == NULL_SIGNATURE) {
+               (*next)++;
+               /* End of table */
+               if (*next == total_entries)
+                       return -ENOENT;
+               bucket_idx = *next / HASH_BUCKET_ENTRIES;
+               idx = *next % HASH_BUCKET_ENTRIES;
+       }
+
+       /* Get position of entry in key table */
+       position = h->buckets[bucket_idx].key_idx[idx];
+       next_key = (struct cuckoo_hash_key *)((char *)h->key_store +
+                               position * h->key_entry_size);
+       /* Return key and data */
+       *key = next_key->key;
+       *data = next_key->pdata;
+
+       /* Increment iterator */
+       (*next)++;
+
+       return (position - 1);
+}
diff --git a/helper/include/odp/helper/cuckoo_hash.h 
b/helper/include/odp/helper/cuckoo_hash.h
new file mode 100644
index 0000000..f21b8a2
--- /dev/null
+++ b/helper/include/odp/helper/cuckoo_hash.h
@@ -0,0 +1,435 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ODPH_CUCKOO_HASH_H_
+#define ODPH_CUCKOO_HASH_H_
+
+#include <odp/shared_memory.h>
+#include <odp/helper/ring.h>
+#include <odp/hash.h>
+#include <stdint.h>
+
+/**
+ * @file
+ *
+ * ODP Cuckoo Hash Table Implementation
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Maximum number of characters in hash name.*/
+#define ODPH_CUCKOO_HASH_NAMESIZE      32
+
+/** A hash table structure. */
+typedef struct odph_cuckoo_hash_tbl {
+       /**< Name of the hash. */
+       char name[ODPH_CUCKOO_HASH_NAMESIZE];
+       /**< Total table entries. */
+       uint32_t entries;
+       /**< Number of buckets in table. */
+       uint32_t num_buckets;
+       /**< Length of hash key. */
+       uint32_t key_len;
+       /**< Function used to calculate hash. */
+       odp_hash_function hash_func;
+       /**< Init value used by hash_func. */
+       uint32_t hash_func_init_val;
+       /**< Function used to compare keys. */
+       odp_hash_cmp_eq_t hash_cmp_eq;
+       /**< Bitmask for getting bucket index from hash signature. */
+       uint32_t bucket_bitmask;
+       /**< Size of each key entry. */
+       uint32_t key_entry_size;
+       /**< Ring that stores all indexes of the free slots in the key table */
+       odph_ring_t *free_slots;
+       /**< Table storing all keys and data */
+       void *key_store;
+       /** Table with buckets storing all the hash values and key indexes
+         to the key table*/
+       struct cuckoo_hash_bucket *buckets;
+       /** memory used to store keys*/
+       odp_shm_t shm_key;
+       /** memory used to store buckets*/
+       odp_shm_t shm_bucket;
+} odph_cuckoo_hash_tbl_t ODP_ALIGNED_CACHE;
+
+/**
+ * Parameters used when creating the cuckoo hash table.
+ */
+typedef struct odph_cuckoo_hash_param_t {
+       /**< Name of the hash table. */
+       const char *name;
+       /**< Total hash table entries. */
+       uint32_t entries;
+       /**< Length of hash key. */
+       uint32_t key_len;
+       /**< Primary Hash function used to calculate hash. */
+       odp_hash_function hash_func;
+       /**< Init value used by hash_func. */
+       uint32_t hash_func_init_val;
+       /**< Indicate if additional parameters are present. */
+       uint8_t extra_flag;
+} odph_cuckoo_hash_param_t;
+
+/**
+ * Create a new cuckoo hash table.
+ *
+ * @param ht
+ *   hash table if successful
+ * @param params
+ *   Parameters used to create and initialise the hash table.
+ * @return
+ *   0 on success
+ *   negative value on errors including:
+ *    - -EINVAL - invalid parameter passed to function
+ *    - -EEXIST - a hash table with the same name already exists
+ *    - -ENOMEM - no appropriate memory area found in which to create memzone
+ */
+int
+odph_cuckoo_hash_create(odph_cuckoo_hash_tbl_t **ht,
+                       const odph_cuckoo_hash_param_t *params);
+
+/**
+ * Find an existing hash table object and return a pointer to it.
+ *
+ * @param name
+ *   Name of the hash table as passed to odph_hash_create()
+ * @return
+ *   Pointer to hash table or NULL if object not found
+ */
+odph_cuckoo_hash_tbl_t *
+odph_cuckoo_hash_find_existing(const char *name);
+
+/**
+ * De-allocate all memory used by hash table.
+ * @param h
+ *   Hash table to free
+ */
+void
+odph_cuckoo_hash_destroy(odph_cuckoo_hash_tbl_t *h);
+
+/**
+ * Reset all hash structure, by zeroing all entries
+ * @param h
+ *   Hash table to reset
+ */
+void
+odph_cuckoo_hash_reset(odph_cuckoo_hash_tbl_t *h);
+
+/**
+ * Add a key-value pair to an existing hash table.
+ * This operation is not multi-thread safe
+ * and should only be called from one thread.
+ *
+ * @param h
+ *   Hash table to add the key to.
+ * @param key
+ *   Key to add to the hash table.
+ * @param data
+ *   Data to add to the hash table.
+ * @return
+ *   - 0 if added successfully
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOSPC if there is no space in the hash for this key.
+ */
+int
+odph_cuckoo_hash_add_key_data(const odph_cuckoo_hash_tbl_t *h,
+                             const void *key, void *data);
+
+/**
+ * Add a key-value pair with a pre-computed hash value
+ * to an existing hash table.
+ * This operation is not multi-thread safe
+ * and should only be called from one thread.
+ *
+ * @param h
+ *   Hash table to add the key to.
+ * @param key
+ *   Key to add to the hash table.
+ * @param sig
+ *   Precomputed hash value for 'key'
+ * @param data
+ *   Data to add to the hash table.
+ * @return
+ *   - 0 if added successfully
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOSPC if there is no space in the hash for this key.
+ */
+int32_t
+odph_cuckoo_hash_add_key_with_hash_data(
+       const odph_cuckoo_hash_tbl_t *h, const void *key,
+       uint32_t sig, void *data);
+
+/**
+ * Add a key to an existing hash table. This operation is not multi-thread
+ * safe and should only be called from one thread.
+ *
+ * @param h
+ *   Hash table to add the key to.
+ * @param key
+ *   Key to add to the hash table.
+ * @return
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOSPC if there is no space in the hash for this key.
+ *   - A positive value that can be used by the caller as an offset into an
+ *     array of user data. This value is unique for this key.
+ */
+int32_t
+odph_cuckoo_hash_add_key(const odph_cuckoo_hash_tbl_t *h, const void *key);
+
+/**
+ * Add a key to an existing hash table.
+ * This operation is not multi-thread safe
+ * and should only be called from one thread.
+ *
+ * @param h
+ *   Hash table to add the key to.
+ * @param key
+ *   Key to add to the hash table.
+ * @param sig
+ *   Precomputed hash value for 'key'.
+ * @return
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOSPC if there is no space in the hash for this key.
+ *   - A positive value that can be used by the caller as an offset into an
+ *     array of user data. This value is unique for this key.
+ */
+int32_t
+odph_cuckoo_hash_add_key_with_hash(
+       const odph_cuckoo_hash_tbl_t *h, const void *key, uint32_t sig);
+
+/**
+ * Remove a key from an existing hash table.
+ * This operation is not multi-thread safe
+ * and should only be called from one thread.
+ *
+ * @param h
+ *   Hash table to remove the key from.
+ * @param key
+ *   Key to remove from the hash table.
+ * @return
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOENT if the key is not found.
+ *   - A positive value that can be used by the caller as an offset into an
+ *     array of user data. This value is unique for this key, and is the same
+ *     value that was returned when the key was added.
+ */
+int32_t
+odph_cuckoo_hash_del_key(const odph_cuckoo_hash_tbl_t *h, const void *key);
+
+/**
+ * Remove a key from an existing hash table.
+ * This operation is not multi-thread safe
+ * and should only be called from one thread.
+ *
+ * @param h
+ *   Hash table to remove the key from.
+ * @param key
+ *   Key to remove from the hash table.
+ * @param sig
+ *   Precomputed hash value for 'key'.
+ * @return
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOENT if the key is not found.
+ *   - A positive value that can be used by the caller as an offset into an
+ *     array of user data. This value is unique for this key, and is the same
+ *     value that was returned when the key was added.
+ */
+int32_t
+odph_cuckoo_hash_del_key_with_hash(
+       const odph_cuckoo_hash_tbl_t *h, const void *key, uint32_t sig);
+
+/**
+ * Find a key-value pair in the hash table.
+ * This operation is multi-thread safe.
+ *
+ * @param h
+ *   Hash table to look in.
+ * @param key
+ *   Key to find.
+ * @param data
+ *   Output with pointer to data returned from the hash table.
+ * @return
+ *   0 if successful lookup
+ *   - EINVAL if the parameters are invalid.
+ *   - ENOENT if the key is not found.
+ */
+int
+odph_cukoo_hash_lookup_data(
+       const odph_cuckoo_hash_tbl_t *h, const void *key, void **data);
+
+/**
+ * Find a key-value pair with a pre-computed hash value
+ * to an existing hash table.
+ * This operation is multi-thread safe.
+ *
+ * @param h
+ *   Hash table to look in.
+ * @param key
+ *   Key to find.
+ * @param sig
+ *   Precomputed hash value for 'key'
+ * @param data
+ *   Output with pointer to data returned from the hash table.
+ * @return
+ *   0 if successful lookup
+ *   - EINVAL if the parameters are invalid.
+ *   - ENOENT if the key is not found.
+ */
+int
+odph_cuckoo_hash_lookup_with_hash_data(
+       const odph_cuckoo_hash_tbl_t *h, const void *key,
+       uint32_t sig, void **data);
+
+/**
+ * Find a key in the hash table.
+ * This operation is multi-thread safe.
+ *
+ * @param h
+ *   Hash table to look in.
+ * @param key
+ *   Key to find.
+ * @return
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOENT if the key is not found.
+ *   - A positive value that can be used by the caller as an offset into an
+ *     array of user data. This value is unique for this key, and is the same
+ *     value that was returned when the key was added.
+ */
+int32_t
+odph_cuckoo_hash_lookup(const odph_cuckoo_hash_tbl_t *h, const void *key);
+
+/**
+ * Find a key in the hash table.
+ * This operation is multi-thread safe.
+ *
+ * @param h
+ *   Hash table to look in.
+ * @param key
+ *   Key to find.
+ * @param sig
+ *   Hash value to remove from the hash table.
+ * @return
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOENT if the key is not found.
+ *   - A positive value that can be used by the caller as an offset into an
+ *     array of user data. This value is unique for this key, and is the same
+ *     value that was returned when the key was added.
+ */
+int32_t
+odph_cuckoo_hash_lookup_with_hash(
+       const odph_cuckoo_hash_tbl_t *h, const void *key, uint32_t sig);
+
+/**
+ * Find multiple keys in the hash table.
+ * This operation is multi-thread safe.
+ *
+ * @param h
+ *   Hash table to look in.
+ * @param keys
+ *   A pointer to a list of keys to look for.
+ * @param num_keys
+ *   How many keys are in the keys list (less than ODPH_HASH_LOOKUP_BULK_MAX).
+ * @param hit_mask
+ *   Output containing a bitmask with all successful lookups.
+ * @param data
+ *   Output containing array of data returned from all the successful lookups.
+ * @return
+ *   -EINVAL if there's an error, otherwise number of successful lookups.
+ */
+int
+odph_cuckoo_hash_lookup_bulk_data(
+       const odph_cuckoo_hash_tbl_t *h, const void **keys,
+       uint32_t num_keys, uint64_t *hit_mask, void *data[]);
+
+/**
+ * Find multiple keys in the hash table.
+ * This operation is multi-thread safe.
+ *
+ * @param h
+ *   Hash table to look in.
+ * @param keys
+ *   A pointer to a list of keys to look for.
+ * @param num_keys
+ *   How many keys are in the keys list (less than HASH_LOOKUP_BULK_MAX).
+ * @param positions
+ *   Output containing a list of values, corresponding to the list of keys that
+ *   can be used by the caller as an offset into an array of user data. These
+ *   values are unique for each key, and are the same values that were returned
+ *   when each key was added. If a key in the list was not found, then -ENOENT
+ *   will be the value.
+ * @return
+ *   -EINVAL if there's an error, otherwise 0.
+ */
+int
+odph_cuckoo_hash_lookup_bulk(
+       const odph_cuckoo_hash_tbl_t *h, const void **keys,
+       uint32_t num_keys, int32_t *positions);
+
+/**
+ * Iterate through the hash table, returning key-value pairs.
+ *
+ * @param h
+ *   Hash table to iterate
+ * @param key
+ *   Output containing the key where current iterator
+ *   was pointing at
+ * @param data
+ *   Output containing the data associated with key.
+ *   Returns NULL if data was not stored.
+ * @param next
+ *   Pointer to iterator. Should be 0 to start iterating the hash table.
+ *   Iterator is incremented after each call of this function.
+ * @return
+ *   Position where key was stored, if successful.
+ *   - -EINVAL if the parameters are invalid.
+ *   - -ENOENT if end of the hash table.
+ */
+int32_t
+odph_cuckoo_hash_iterate(
+       const odph_cuckoo_hash_tbl_t *h,
+       const void **key, void **data, uint32_t *next);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ODPH_HASH_H_ */
diff --git a/helper/include/odp/helper/ring.h b/helper/include/odp/helper/ring.h
index 65c32ad..3c1a3bf 100644
--- a/helper/include/odp/helper/ring.h
+++ b/helper/include/odp/helper/ring.h
@@ -132,6 +132,8 @@ typedef struct odph_ring {
        /** @private Flags supplied at creation. */
        int flags;
+ odp_shm_t shm;
+
        /** @private Producer */
        struct prod {
                uint32_t watermark;      /* Maximum items */
@@ -194,6 +196,18 @@ typedef struct odph_ring {
  odph_ring_t *odph_ring_create(const char *name, unsigned count,
                            unsigned flags);
+/**
+ * Free a ring in memory.
+ *
+ * This function uses odp_shm_reserve() to allocate memory. Its size is
+ * set to *count*, which must be a power of two. Water marking is
+ * disabled by default. Note that the real usable ring size is count-1
+ * instead of count.
+ *
+ * @param r
+ *   The pointer to the ring need to be free.
+ */
+void odph_ring_free(odph_ring_t *r);
/**
   * Change the high water mark.
@@ -372,6 +386,21 @@ int odph_ring_sp_enqueue_bulk(odph_ring_t *r, void * const 
*obj_table,
                              unsigned n);
/**
+ * Enqueue one object on a ring (NOT multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj
+ *   A pointer to the object to be added.
+ * @return
+ *   - 0: Success; objects enqueued.
+ *   - -EDQUOT: Quota exceeded. The objects have been enqueued, but the
+ *     high water mark is exceeded.
+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
+ */
+int odph_ring_sp_enqueue(odph_ring_t *r, void *obj);
+
+/**
   * Dequeue several objects from a ring (multi-consumers safe).
   *
   * This function uses a "compare and set" instruction to move the
@@ -408,6 +437,20 @@ int odph_ring_mc_dequeue_bulk(odph_ring_t *r, void 
**obj_table, unsigned n);
  int odph_ring_sc_dequeue_bulk(odph_ring_t *r, void **obj_table, unsigned n);
/**
+ * Dequeue one object from a ring (NOT multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_p
+ *   A pointer to a void * pointer (object) that will be filled.
+ * @return
+ *   - 0: Success; objects dequeued.
+ *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
+ *     dequeued.
+ */
+int odph_ring_sc_dequeue(odph_ring_t *r, void *obj);
+
+/**
   * Test if a ring is full.
   *
   * @param r
diff --git a/helper/ring.c b/helper/ring.c
index 3122173..afd7244 100644
--- a/helper/ring.c
+++ b/helper/ring.c
@@ -174,12 +174,18 @@ odph_ring_create(const char *name, unsigned count, 
unsigned flags)
        /* reserve a memory zone for this ring.*/
        shm = odp_shm_reserve(ring_name, ring_size, ODP_CACHE_LINE_SIZE, 0);
+ if (shm == ODP_SHM_INVALID) {
+               ODPH_ERR("shm allocation failed for ring %s\n", ring_name);
+               return NULL;
+       }
+
        r = odp_shm_addr(shm);
if (r != NULL) {
                /* init the ring structure */
                snprintf(r->name, sizeof(r->name), "%s", name);
                r->flags = flags;
+               r->shm = shm;
                r->prod.watermark = count;
                r->prod.sp_enqueue = !!(flags & ODPH_RING_F_SP_ENQ);
                r->cons.sc_dequeue = !!(flags & ODPH_RING_F_SC_DEQ);
@@ -201,6 +207,18 @@ odph_ring_create(const char *name, unsigned count, 
unsigned flags)
        return r;
  }
+/* free a ring */
+void
+odph_ring_free(odph_ring_t *r)
+{
+       odp_rwlock_write_lock(&qlock);
+       TAILQ_REMOVE(&odp_ring_list, r, next);
+       odp_rwlock_write_unlock(&qlock);
+
+       if (r->shm != ODP_SHM_INVALID)
+               odp_shm_free(r->shm);
+}
+
  /*
   * change the high water mark. If *count* is 0, water marking is
   * disabled
@@ -471,6 +489,11 @@ int odph_ring_sp_enqueue_bulk(odph_ring_t *r, void * const 
*obj_table,
                                         ODPH_RING_QUEUE_FIXED);
  }
+int odph_ring_sp_enqueue(odph_ring_t *r, void *obj)
+{
+       return odph_ring_sp_enqueue_bulk(r, &obj, 1);
+}
+
  /**
   * Dequeue several objects from a ring (multi-consumers safe).
   */
@@ -489,6 +512,11 @@ int odph_ring_sc_dequeue_bulk(odph_ring_t *r, void 
**obj_table, unsigned n)
                                         ODPH_RING_QUEUE_FIXED);
  }
+int odph_ring_sc_dequeue(odph_ring_t *r, void *obj)
+{
+       return odph_ring_sc_dequeue_bulk(r, &obj, 1);
+}
+
  /**
   * Test if a ring is full.
   */
diff --git a/helper/test/Makefile.am b/helper/test/Makefile.am
index d6820e1..e358a87 100644
--- a/helper/test/Makefile.am
+++ b/helper/test/Makefile.am
@@ -9,7 +9,8 @@ EXECUTABLES = odp_chksum$(EXEEXT) \
                odp_thread$(EXEEXT) \
                odp_process$(EXEEXT)\
                odph_pause$(EXEEXT)\
-              odp_table$(EXEEXT)
+              odp_table$(EXEEXT)\
+                         odp_cuckoo_hash$(EXEEXT)
COMPILE_ONLY = @@ -31,3 +32,4 @@ dist_odp_process_SOURCES = odp_process.c
  odp_process_LDADD = $(LIB)/libodphelper.la $(LIB)/libodp.la
  odph_pause_SOURCES = odph_pause.c
  dist_odp_table_SOURCES = odp_table.c
+dist_odp_cuckoo_hash_SOURCES = odp_cuckoo_hash.c
diff --git a/helper/test/odp_cuckoo_hash.c b/helper/test/odp_cuckoo_hash.c
new file mode 100644
index 0000000..c51ba0a
--- /dev/null
+++ b/helper/test/odp_cuckoo_hash.c
@@ -0,0 +1,779 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <test_debug.h>
+#include <odp.h>
+#include <odp/helper/ring.h>
+#include <odp/helper/cuckoo_hash.h>
+
+/*******************************************************************************
+ * Hash function performance test configuration section. Each performance test
+ * will be performed HASHTEST_ITERATIONS times.
+ *
+ * The five arrays below control what tests are performed. Every combination
+ * from the array entries is tested.
+ */
+odp_hash_function hashtest_funcs[] = {odp_hash_crc32c};
+/******************************************************************************/
+
+/*
+ * Check condition and return an error if true. Assumes that "handle" is the
+ * name of the hash structure pointer to be freed.
+ */
+#define RETURN_IF_ERROR(cond, str, ...) do {                           \
+       if (cond) {                                                     \
+               printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \

it's better to print to stderr

+               if (handle) \
+                       odph_cuckoo_hash_destroy(handle);               \
+               return -1;                                              \
+       }                                                               \
+} while (0)
+
+/* 5-tuple key type */
+struct flow_key {
+       uint32_t ip_src;
+       uint32_t ip_dst;
+       uint16_t port_src;
+       uint16_t port_dst;
+       uint8_t proto;
+} __packed;

ODP_PACKED

+
+/*
+ * Print out result of unit test hash operation.
+ */
+static void print_key_info(
+               const char *msg, const struct flow_key *key,
+               int32_t pos)
+{
+       const uint8_t *p = (const uint8_t *)key;
+       unsigned i;
+
+       printf("%s key:0x", msg);
+       for (i = 0; i < sizeof(struct flow_key); i++)
+               printf("%02X", p[i]);
+       printf(" @ pos %d\n", pos);
+}
+
+static double get_time_diff(struct timeval *start, struct timeval *end)
+{
+       int sec = end->tv_sec - start->tv_sec;
+       int usec = end->tv_usec - start->tv_usec;
+
+       if (usec < 0) {
+               sec--;
+               usec += 1000000;
+       }
+       double diff = sec + (double)usec / 1000000;
+
+       return diff;
+}

that is better to delay on odp time functions.

+
+/** Create IPv4 address */
+#define IPv4(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) | \
+       (((b) & 0xff) << 16) | \
+       (((c) & 0xff) << 8)  | \
+       ((d) & 0xff))
+
+/* Keys used by unit test functions */
+static struct flow_key keys[5] = { {
+       .ip_src = IPv4(0x03, 0x02, 0x01, 0x00),
+       .ip_dst = IPv4(0x07, 0x06, 0x05, 0x04),
+       .port_src = 0x0908,
+       .port_dst = 0x0b0a,
+       .proto = 0x0c,
+}, {
+       .ip_src = IPv4(0x13, 0x12, 0x11, 0x10),
+       .ip_dst = IPv4(0x17, 0x16, 0x15, 0x14),
+       .port_src = 0x1918,
+       .port_dst = 0x1b1a,
+       .proto = 0x1c,
+}, {
+       .ip_src = IPv4(0x23, 0x22, 0x21, 0x20),
+       .ip_dst = IPv4(0x27, 0x26, 0x25, 0x24),
+       .port_src = 0x2928,
+       .port_dst = 0x2b2a,
+       .proto = 0x2c,
+}, {
+       .ip_src = IPv4(0x33, 0x32, 0x31, 0x30),
+       .ip_dst = IPv4(0x37, 0x36, 0x35, 0x34),
+       .port_src = 0x3938,
+       .port_dst = 0x3b3a,
+       .proto = 0x3c,
+}, {
+       .ip_src = IPv4(0x43, 0x42, 0x41, 0x40),
+       .ip_dst = IPv4(0x47, 0x46, 0x45, 0x44),
+       .port_src = 0x4948,
+       .port_dst = 0x4b4a,
+       .proto = 0x4c,
+} };
+
+/* Parameters used for hash table in unit test functions. Name set later. */
+static odph_cuckoo_hash_param_t ut_params = {
+       .entries = 64,
+       .key_len = sizeof(struct flow_key), /* 13 */
+       .hash_func = odp_hash_crc32c,
+       .hash_func_init_val = 0,
+};
+
+#define CRC32_ITERATIONS 1048576
+#define CRC32_DWORDS 64
+
+static uint32_t hash(const odph_cuckoo_hash_tbl_t *h, const void *key)
+{
+       /* calc hash result by key */
+       return h->hash_func(key, h->key_len, h->hash_func_init_val);
+}
+
+/*
+ * Basic sequence of operations for a single key:
+ *     - add
+ *     - lookup (hit)
+ *     - delete
+ *     - lookup (miss)
+ */
+static int test_add_delete(void)
+{
+       odph_cuckoo_hash_tbl_t *handle;
+       /* test with standard add/lookup/delete functions */
+       int pos0, expected_pos0;
+       int ret;
+
+       ut_params.name = "test1";
+       ret = odph_cuckoo_hash_create(&handle, &ut_params);
+       RETURN_IF_ERROR(ret < 0, "cuckoo hash creation failed");
That should be CU_ASSERT_FATAL.

+
+       pos0 = odph_cuckoo_hash_add_key(handle, &keys[0]);
+       print_key_info("Add", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
+       expected_pos0 = pos0;
+
+       pos0 = odph_cuckoo_hash_lookup(handle, &keys[0]);
+       print_key_info("Lkp", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != expected_pos0,
+                       "failed to find key (pos0=%d)", pos0);
+
+       pos0 = odph_cuckoo_hash_del_key(handle, &keys[0]);
+       print_key_info("Del", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != expected_pos0,
+                       "failed to delete key (pos0=%d)", pos0);
+
+       pos0 = odph_cuckoo_hash_lookup(handle, &keys[0]);
+       print_key_info("Lkp", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != -ENOENT,
+                       "fail: found key after deleting! (pos0=%d)", pos0);
+
+       odph_cuckoo_hash_destroy(handle);
+
+       /* repeat test with precomputed hash functions */
+       uint32_t hash_value;
+       int pos1, expected_pos1;
+
+       ret = odph_cuckoo_hash_create(&handle, &ut_params);
+       RETURN_IF_ERROR(handle == NULL, "hash creation failed");
+
+       hash_value = hash(handle, &keys[0]);
+       pos1 = odph_cuckoo_hash_add_key_with_hash(handle, &keys[0], hash_value);
+       print_key_info("Add", &keys[0], pos1);
+       RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
+       expected_pos1 = pos1;
+
+       pos1 = odph_cuckoo_hash_lookup_with_hash(handle, &keys[0], hash_value);
+       print_key_info("Lkp", &keys[0], pos1);
+       RETURN_IF_ERROR(pos1 != expected_pos1,
+                       "failed to find key (pos1=%d)", pos1);
+
+       pos1 = odph_cuckoo_hash_del_key_with_hash(handle, &keys[0], hash_value);
+       print_key_info("Del", &keys[0], pos1);
+       RETURN_IF_ERROR(pos1 != expected_pos1,
+                       "failed to delete key (pos1=%d)", pos1);
+
+       pos1 = odph_cuckoo_hash_lookup_with_hash(handle, &keys[0], hash_value);
+       print_key_info("Lkp", &keys[0], pos1);
+       RETURN_IF_ERROR(pos1 != -ENOENT,
+                       "fail: found key after deleting! (pos1=%d)", pos1);
+
+       odph_cuckoo_hash_destroy(handle);
+
+       return 0;
+}
+
+/*
+ * Sequence of operations for a single key:
+ *     - delete: miss
+ *     - add
+ *     - lookup: hit
+ *     - add: update
+ *     - lookup: hit (updated data)
+ *     - delete: hit
+ *     - delete: miss
+ *     - lookup: miss
+ */
+static int test_add_update_delete(void)
+{
+       odph_cuckoo_hash_tbl_t *handle;
+       int pos0, expected_pos0;
+       int ret;
+
+       ut_params.name = "test2";
+       ret = odph_cuckoo_hash_create(&handle, &ut_params);
+       RETURN_IF_ERROR(ret < 0, "hash creation failed");
+
+       pos0 = odph_cuckoo_hash_del_key(handle, &keys[0]);
+       print_key_info("Del", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != -ENOENT,
+                       "fail: found non-existent key (pos0=%d)", pos0);
+
+       pos0 = odph_cuckoo_hash_add_key(handle, &keys[0]);
+       print_key_info("Add", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
+       expected_pos0 = pos0;
+
+       pos0 = odph_cuckoo_hash_lookup(handle, &keys[0]);
+       print_key_info("Lkp", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != expected_pos0,
+                       "failed to find key (pos0=%d)", pos0);
+
+       pos0 = odph_cuckoo_hash_add_key(handle, &keys[0]);
+       print_key_info("Add", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != expected_pos0,
+                       "failed to re-add key (pos0=%d)", pos0);
+
+       pos0 = odph_cuckoo_hash_lookup(handle, &keys[0]);
+       print_key_info("Lkp", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != expected_pos0,
+                       "failed to find key (pos0=%d)", pos0);
+
+       pos0 = odph_cuckoo_hash_del_key(handle, &keys[0]);
+       print_key_info("Del", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != expected_pos0,
+                       "failed to delete key (pos0=%d)", pos0);
+
+       pos0 = odph_cuckoo_hash_del_key(handle, &keys[0]);
+       print_key_info("Del", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != -ENOENT,
+                       "fail: deleted already deleted key (pos0=%d)", pos0);
+
+       pos0 = odph_cuckoo_hash_lookup(handle, &keys[0]);
+       print_key_info("Lkp", &keys[0], pos0);
+       RETURN_IF_ERROR(pos0 != -ENOENT,
+                       "fail: found key after deleting! (pos0=%d)", pos0);
+
+       odph_cuckoo_hash_destroy(handle);
+       return 0;
+}
+
+/*
+ * Sequence of operations for find existing hash table
+ *
+ *  - create table
+ *  - find existing table: hit
+ *  - find non-existing table: miss
+ *
+ */
+static int test_hash_find_existing(void)
+{
+       int ret;
+       odph_cuckoo_hash_tbl_t *handle = NULL, *result = NULL;
+
+       /* Create hash table. */
+       ut_params.name = "hash_find_existing";
+       ret = odph_cuckoo_hash_create(&handle, &ut_params);
+       RETURN_IF_ERROR(ret < 0, "hash creation failed");
+
+       /* Try to find existing hash table */
+       result = odph_cuckoo_hash_find_existing("hash_find_existing");
+       RETURN_IF_ERROR(result != handle, "could not find existing hash table");
+
+       /* Try to find non-existing hash table */
+       result = odph_cuckoo_hash_find_existing("hash_find_non_existing");
+       RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
+
+       /* Cleanup. */
+       odph_cuckoo_hash_destroy(handle);
+
+       return 0;
+}
+
+/*
+ * Sequence of operations for 5 keys
+ *     - add keys
+ *     - lookup keys: hit
+ *     - add keys (update)
+ *     - lookup keys: hit (updated data)
+ *     - delete keys : hit
+ *     - lookup keys: miss
+ */
+static int test_five_keys(void)
+{
+       odph_cuckoo_hash_tbl_t *handle;
+       const void *key_array[5] = {0};
+       int pos[5];
+       int expected_pos[5];
+       unsigned i;
+       int ret;
+
+       ut_params.name = "test3";
+       ret = odph_cuckoo_hash_create(&handle, &ut_params);
+       RETURN_IF_ERROR(ret < 0, "hash creation failed");
+
+       /* Add */
+       for (i = 0; i < 5; i++) {
+               pos[i] = odph_cuckoo_hash_add_key(handle, &keys[i]);
+               print_key_info("Add", &keys[i], pos[i]);
+               RETURN_IF_ERROR(pos[i] < 0,
+                               "failed to add key (pos[%u]=%d)", i, pos[i]);
+               expected_pos[i] = pos[i];
+       }
+
+       /* Lookup */
+       for (i = 0; i < 5; i++)
+               key_array[i] = &keys[i];
+
+       ret = odph_cuckoo_hash_lookup_bulk(handle, &key_array[0], 5,
+                                          (int32_t *)pos);
+       if (ret == 0)
+               for (i = 0; i < 5; i++) {
+                       print_key_info("Lkp", key_array[i], pos[i]);
+                       RETURN_IF_ERROR(
+                                       pos[i] != expected_pos[i],
+                                       "failed to find key (pos[%u]=%d)",
+                                       i, pos[i]);
+               }
+
+       /* Add - update */
+       for (i = 0; i < 5; i++) {
+               pos[i] = odph_cuckoo_hash_add_key(handle, &keys[i]);
+               print_key_info("Add", &keys[i], pos[i]);
+               RETURN_IF_ERROR(
+                               pos[i] != expected_pos[i],
+                               "failed to add key (pos[%u]=%d)", i, pos[i]);
+       }
+
+       /* Lookup */
+       for (i = 0; i < 5; i++) {
+               pos[i] = odph_cuckoo_hash_lookup(handle, &keys[i]);
+               print_key_info("Lkp", &keys[i], pos[i]);
+               RETURN_IF_ERROR(
+                               pos[i] != expected_pos[i],
+                               "failed to find key (pos[%u]=%d)", i, pos[i]);
+       }
+
+       /* Delete */
+       for (i = 0; i < 5; i++) {
+               pos[i] = odph_cuckoo_hash_del_key(handle, &keys[i]);
+               print_key_info("Del", &keys[i], pos[i]);
+               RETURN_IF_ERROR(
+                               pos[i] != expected_pos[i],
+                               "failed to delete key (pos[%u]=%d)", i, pos[i]);
+       }
+
+       /* Lookup */
+       for (i = 0; i < 5; i++) {
+               pos[i] = odph_cuckoo_hash_lookup(handle, &keys[i]);
+               print_key_info("Lkp", &keys[i], pos[i]);
+               RETURN_IF_ERROR(
+                               pos[i] != -ENOENT,
+                               "found non-existent key (pos[%u]=%d)",
+                               i, pos[i]);
+       }
+
+       /* Lookup multi */
+       ret = odph_cuckoo_hash_lookup_bulk(handle, &key_array[0], 5,
+                                          (int32_t *)pos);
+       if (ret == 0)
+               for (i = 0; i < 5; i++) {
+                       print_key_info("Lkp", key_array[i], pos[i]);
+                       RETURN_IF_ERROR(
+                                       pos[i] != -ENOENT,
+                                       "found not-existent key (pos[%u]=%d)",
+                                       i, pos[i]);
+               }
+
+       odph_cuckoo_hash_destroy(handle);
+       return 0;
+}
+
+#define BUCKET_ENTRIES 4
+#define HASH_ENTRIES_MAX 1048576
+/*
+ * Do tests for hash creation with bad parameters.
+ */
+static int test_hash_creation_with_bad_parameters(void)
+{
+       odph_cuckoo_hash_tbl_t *handle;
+       odph_cuckoo_hash_param_t params;
+       int ret;
+
+       ret = odph_cuckoo_hash_create(&handle, NULL);
+       if (handle != NULL) {
+               odph_cuckoo_hash_destroy(handle);
+               printf("Impossible creating hash successfully without any 
parameter\n");
+               return -1;
+       }
+
+       memcpy(&params, &ut_params, sizeof(params));
+       params.name = "creation_with_bad_parameters_0";
+       params.entries = HASH_ENTRIES_MAX + 1;
+       ret =  odph_cuckoo_hash_create(&handle, &params);
+       if (handle != NULL) {
+               odph_cuckoo_hash_destroy(handle);
+               printf("Impossible creating hash successfully with entries in 
parameter exceeded\n");
+               return -1;
+       }
+
+       memcpy(&params, &ut_params, sizeof(params));
+       params.name = "creation_with_bad_parameters_2";
+       params.entries = BUCKET_ENTRIES - 1;
+       ret = odph_cuckoo_hash_create(&handle, &params);
+       if (handle != NULL || ret == 0) {
+               odph_cuckoo_hash_destroy(handle);
+               printf("Impossible creating hash successfully if entries less than 
bucket_entries in parameter\n");
+               return -1;
+       }
+
+       memcpy(&params, &ut_params, sizeof(params));
+       params.name = "creation_with_bad_parameters_3";
+       params.key_len = 0;
+       ret = odph_cuckoo_hash_create(&handle, &params);
+       if (handle != NULL) {
+               odph_cuckoo_hash_destroy(handle);
+               printf("Impossible creating hash successfully if key_len in 
parameter is zero\n");
+               return -1;
+       }
+
+       odph_cuckoo_hash_destroy(handle);
+       printf("# Test successful. No more errors expected\n");
+
+       return 0;
+}
+
+/*
+ * Do tests for hash creation with parameters that look incorrect
+ * but are actually valid.
+ */
+static int
+test_hash_creation_with_good_parameters(void)
+{
+       odph_cuckoo_hash_tbl_t *handle, *tmp;
+       odph_cuckoo_hash_param_t params;
+       int ret;
+
+       /* create with null hash function - should choose DEFAULT_HASH_FUNC */
+       memcpy(&params, &ut_params, sizeof(params));
+       params.name = "same_name";
+       params.hash_func = NULL;
+       ret = odph_cuckoo_hash_create(&handle, &params);
+       if (handle == NULL || ret < 0) {
+               printf("Creating hash with null hash_func failed\n");
+               return -1;
+       }
+
+       /* this test is trying to create a hash with the same
+        * name as previous one. This should return a pointer
+        * to the hash we previously created. The previous hash
+        * isn't freed exactly for the purpose of it being in
+        * the hash list.
+        */
+       memcpy(&params, &ut_params, sizeof(params));
+       params.name = "same_name";
+       ret = odph_cuckoo_hash_create(&tmp, &params);
+
+       /* check if the returned handle is actually
+          equal to the previous hash */
+       if (handle != tmp) {
+               odph_cuckoo_hash_destroy(handle);
+               odph_cuckoo_hash_destroy(tmp);
+               printf("Creating hash with existing name was successful\n");
+               return -1;
+       }
+
+       /* try creating hash when there already are hashes in
+        * the list. The previous hash is not freed to have a
+        * non-empty hash list. The other hash that's in the
+        * list is still pointed to by "handle" var.
+        */
+       memcpy(&params, &ut_params, sizeof(params));
+       params.name = "different_name";
+       ret = odph_cuckoo_hash_create(&tmp, &params);
+       if (tmp == NULL) {
+               odph_cuckoo_hash_destroy(handle);
+               printf("Creating hash with valid parameters failed\n");
+               return -1;
+       }
+
+       odph_cuckoo_hash_destroy(tmp);
+       odph_cuckoo_hash_destroy(handle);
+
+       return 0;
+}
+
+#define ITERATIONS 50
+#define NUM_ENTRIES 1024
+#define HASH_KEY_LENGTH_MAX 64
+static int test_hash_iteration(void)
+{
+       odph_cuckoo_hash_tbl_t *handle;
+       unsigned i;
+       uint8_t keys[NUM_ENTRIES][HASH_KEY_LENGTH_MAX];
+       const void *next_key;
+       void *next_data;
+       void *data[NUM_ENTRIES];
+       unsigned added_keys;
+       uint32_t iter = 0;
+       int ret = 0;
+
+       ut_params.entries = NUM_ENTRIES;
+       ut_params.name = "test_hash_iteration";
+       ut_params.hash_func = odp_hash_crc32c;
+       ut_params.key_len = 16;
+       ret = odph_cuckoo_hash_create(&handle, &ut_params);
+       RETURN_IF_ERROR(handle == NULL, "hash creation failed");
+
+       /* Add random entries until key cannot be added */
+       for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) {
+               data[added_keys] = (void *)((uintptr_t)rand());
+               for (i = 0; i < ut_params.key_len; i++)
+                       keys[added_keys][i] = rand() % 255;
+               ret = odph_cuckoo_hash_add_key_data(
+                               handle, keys[added_keys], data[added_keys]);
+               if (ret < 0)
+                       break;
+       }
+
+       /* Iterate through the hash table */
+       while (odph_cuckoo_hash_iterate(handle,
+                                       &next_key, &next_data, &iter) >= 0) {
+               /* Search for the key in the list of keys added */
+               for (i = 0; i < NUM_ENTRIES; i++) {
+                       if (memcmp(next_key, keys[i], ut_params.key_len) == 0) {
+                               if (next_data != data[i]) {
+                                       printf("Data found in the hash table is 
not");
+                                       printf("The data added with the key\n");
+                                       goto err;
+                               }
+                               added_keys--;
+                               break;
+                       }
+               }
+               if (i == NUM_ENTRIES) {
+                       printf("Key found in the hash table was not added\n");
+                       goto err;
+               }
+       }
+
+       /* Check if all keys have been iterated */
+       if (added_keys != 0) {
+               printf("There were still %u keys to iterate\n", added_keys);
+               goto err;
+       }
+
+       odph_cuckoo_hash_destroy(handle);
+       return 0;
+
+err:
+       odph_cuckoo_hash_destroy(handle);
+       return -1;
+}
+
+#define ITERATIONS 50
+#define LOOKUP_TIMES 1000
+/*
+ * Test to see the average table utilization (entries added/max entries)
+ * before hitting a random entry that cannot be added
+ */
+static int test_average_table_utilization(void)
+{
+       odph_cuckoo_hash_tbl_t *handle;
+       uint8_t simple_key[HASH_KEY_LENGTH_MAX],
+                       lookup_key[LOOKUP_TIMES][HASH_KEY_LENGTH_MAX];
+       unsigned i, j;
+       unsigned added_keys, average_keys_added = 0;
+       int ret, pos_arr[LOOKUP_TIMES];
+       struct timeval start, end;
+       const void *bulk_key[LOOKUP_TIMES] = {0};
+       double add_time = 0, lookup_time = 0, bulk_time = 0;
+
+       printf("\n# Running test to determine average utilization\n");
+       printf("  before adding elements begins to fail\n");
+       printf("Measuring performance, please wait");
+       fflush(stdout);
+       ut_params.entries = 1 << 20;
+       ut_params.name = "test_average_utilization";
+       ut_params.hash_func = odp_hash_crc32c;
+       ret = odph_cuckoo_hash_create(&handle, &ut_params);
+       RETURN_IF_ERROR(handle == NULL, "hash creation failed");
+
+       for (j = 0; j < ITERATIONS; j++) {
+               ret = 0;
+               unsigned added_one = 0;
+
+               gettimeofday(&start, 0);
+               /* Add random entries until key cannot be added */
+               for (added_keys = 0; ret >= 0; added_keys++) {
+                       for (i = 0; i < ut_params.key_len; i++) {
+                               simple_key[i] = rand() % 255;
+                               if (added_one < LOOKUP_TIMES) {
+                                       lookup_key[added_one][i]
+                                               = simple_key[i];
+                               }
+                       }
+                       if (added_one < LOOKUP_TIMES)
+                               bulk_key[added_one] = &lookup_key[added_one];
+                       ret = odph_cuckoo_hash_add_key(handle, simple_key);
+                       added_one++;
+               }
+               gettimeofday(&end, 0);
+               add_time += get_time_diff(&start, &end);
+               if (ret != -ENOSPC) {
+                       printf("Unexpected error when adding keys\n");
+                       odph_cuckoo_hash_destroy(handle);
+                       return -1;
+               }
+
+               gettimeofday(&start, 0);
+               for (i = 0; i < LOOKUP_TIMES; i++)
+                       pos_arr[i] = odph_cuckoo_hash_lookup(handle,
+                                                            lookup_key[i]);
+               gettimeofday(&end, 0);
+               lookup_time += get_time_diff(&start, &end);
+
+               gettimeofday(&start, 0);
+               for (i = 0; i < LOOKUP_TIMES / 64; i++) {
+                       odph_cuckoo_hash_lookup_bulk(
+                                       handle, &bulk_key[i * 64],
+                                       64, &pos_arr[i * 64]);
+               }
+               gettimeofday(&end, 0);
+
+               bulk_time +=  get_time_diff(&start, &end);
+
+               average_keys_added += added_keys;
+
+               odph_cuckoo_hash_reset(handle);
+
+               /* Print a dot to show progress on operations */
+               printf(".");
+               fflush(stdout);
+       }
+
+       average_keys_added /= ITERATIONS;
+
+       printf(
+               "\nAverage table utilization = %.2f%% (%u/%u)\n",
+               ((double)average_keys_added / ut_params.entries * 100),
+               average_keys_added, ut_params.entries);
+       printf(
+               "Average insert time = %lf,", (add_time / ITERATIONS));
+       printf(
+               " lookup time = %lf, lookup_bulk time = %lf\n",
+               (lookup_time / ITERATIONS), (bulk_time / ITERATIONS));
+       odph_cuckoo_hash_destroy(handle);
+
+       return 0;
+}
+
+/*
+ * Do all unit and performance tests.
+ */
+static int
+test_cuckoo_hash_table(void)
+{
+       odph_ring_tailq_init();
+       if (test_add_delete() < 0)
+               return -1;
+       if (test_hash_find_existing() < 0)
+               return -1;
+       if (test_add_update_delete() < 0)
+               return -1;
+       if (test_five_keys() < 0)
+               return -1;
+       if (test_hash_creation_with_bad_parameters() < 0)
+               return -1;
+       if (test_hash_creation_with_good_parameters() < 0)
+               return -1;
+       if (test_hash_iteration() < 0)
+               return -1;
+       if (test_average_table_utilization() < 0)
+               return -1;
+
+       return 0;
+}
+
+int main(int argc TEST_UNUSED, char *argv[] TEST_UNUSED)
+{
+       if (odp_init_global(NULL, NULL)) {
+               LOG_ERR("Error: ODP global init failed.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (odp_init_local(ODP_THREAD_WORKER)) {
+               LOG_ERR("Error: ODP local init failed.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       int val = test_cuckoo_hash_table();
+
+       if (val < 0)
+               printf("cuckoo hash test fail!!\n");
+       else
+               printf("All Tests pass!!\n");

You don't need to print that. Take a look at others tests. There CU_ASSERT and it's friends.
If all assert passed CUnit will print that.
+
+       if (odp_term_local()) {
+               LOG_ERR("Error: ODP local term failed.\n");

same here, just

    CU_ASSERT(odp_tem_local());
+               exit(EXIT_FAILURE);
+       }
+
+       if (odp_term_global()) {
+               LOG_ERR("Error: ODP global term failed.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       return val;
+}
+
diff --git a/include/odp/api/hash.h b/include/odp/api/hash.h
index 1b2a580..a2986f0 100644
--- a/include/odp/api/hash.h
+++ b/include/odp/api/hash.h

all patches for ./include should be in separate patch with prefix "api:"
@@ -25,6 +25,20 @@ extern "C" {
   */
/**
+ * @typedef odp_hash_function
+ * odp hash function
+ */
+typedef uint32_t (*odp_hash_function)(const void *key, uint32_t data_len,
+                                     uint32_t init_val);
+
+/**
+ * @typedef odp_hash_cmp_eq_t
+ * odp hash compare function
+ */
+typedef int (*odp_hash_cmp_eq_t)(const void *key1,
+                                const void *key2, size_t data_len);
+
+/**
  * Calculate CRC-32
  *
  * Calculates CRC-32 over the data. The polynomial is 0x04c11db7.

_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to