get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/423/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 423,
    "url": "https://patches.dpdk.org/api/patches/423/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1411036471-3822-3-git-send-email-pablo.de.lara.guarch@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1411036471-3822-3-git-send-email-pablo.de.lara.guarch@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1411036471-3822-3-git-send-email-pablo.de.lara.guarch@intel.com",
    "date": "2014-09-18T10:34:30",
    "name": "[dpdk-dev,2/3] lib/librte_tshash: New Thread Safe Hash library for DPDK",
    "commit_ref": null,
    "pull_url": null,
    "state": "rejected",
    "archived": true,
    "hash": "f09c9cdd9c7842ebea0fbe58c24a7353833404c0",
    "submitter": {
        "id": 9,
        "url": "https://patches.dpdk.org/api/people/9/?format=api",
        "name": "De Lara Guarch, Pablo",
        "email": "pablo.de.lara.guarch@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1411036471-3822-3-git-send-email-pablo.de.lara.guarch@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/423/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/423/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 17885B3B0;\n\tThu, 18 Sep 2014 12:29:42 +0200 (CEST)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 68BFFB3AD\n\tfor <dev@dpdk.org>; Thu, 18 Sep 2014 12:29:39 +0200 (CEST)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby orsmga101.jf.intel.com with ESMTP; 18 Sep 2014 03:35:22 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga002.jf.intel.com with ESMTP; 18 Sep 2014 03:34:33 -0700",
            "from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com\n\t[10.237.217.46])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\ts8IAYWaj012110 for <dev@dpdk.org>; Thu, 18 Sep 2014 11:34:32 +0100",
            "from sivswdev02.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev02.ir.intel.com with ESMTP id s8IAYWBI003876\n\tfor <dev@dpdk.org>; Thu, 18 Sep 2014 11:34:32 +0100",
            "(from pdelarax@localhost)\n\tby sivswdev02.ir.intel.com with  id s8IAYWI6003872\n\tfor dev@dpdk.org; Thu, 18 Sep 2014 11:34:32 +0100"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.04,546,1406617200\"; d=\"scan'208\";a=\"604726790\"",
        "From": "Pablo de Lara <pablo.de.lara.guarch@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Thu, 18 Sep 2014 11:34:30 +0100",
        "Message-Id": "<1411036471-3822-3-git-send-email-pablo.de.lara.guarch@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "In-Reply-To": "<1411036471-3822-1-git-send-email-pablo.de.lara.guarch@intel.com>",
        "References": "<1411036471-3822-1-git-send-email-pablo.de.lara.guarch@intel.com>",
        "Subject": "[dpdk-dev] [PATCH 2/3] lib/librte_tshash: New Thread Safe Hash\n\tlibrary for DPDK",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Added new hash library, as an alternative to the old hash\nimplementation. This new library allows the user to have\nmultiple threads reading and writing on the same hash\ntable at the same time.\n\nSigned-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>\n---\n config/common_bsdapp                           |    6 +\n config/common_linuxapp                         |    6 +\n lib/Makefile                                   |    1 +\n lib/librte_eal/common/include/rte_log.h        |    1 +\n lib/librte_eal/common/include/rte_tailq_elem.h |    2 +\n lib/librte_tshash/Makefile                     |   49 ++\n lib/librte_tshash/rte_tshash.c                 |  580 ++++++++++++++++++++++++\n lib/librte_tshash/rte_tshash.h                 |  533 ++++++++++++++++++++++\n lib/librte_tshash/rte_vector_jhash.h           |  332 ++++++++++++++\n mk/rte.app.mk                                  |    4 +\n 10 files changed, 1514 insertions(+), 0 deletions(-)\n create mode 100644 lib/librte_tshash/Makefile\n create mode 100644 lib/librte_tshash/rte_tshash.c\n create mode 100644 lib/librte_tshash/rte_tshash.h\n create mode 100644 lib/librte_tshash/rte_vector_jhash.h",
    "diff": "diff --git a/config/common_bsdapp b/config/common_bsdapp\nindex bf6d8a0..90e2755 100644\n--- a/config/common_bsdapp\n+++ b/config/common_bsdapp\n@@ -284,6 +284,12 @@ CONFIG_RTE_LIBRTE_HASH=y\n CONFIG_RTE_LIBRTE_HASH_DEBUG=n\n \n #\n+# Compile librte_tshash\n+#\n+CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH=y\n+CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH_STATS=y\n+\n+#\n # Compile librte_lpm\n #\n CONFIG_RTE_LIBRTE_LPM=y\ndiff --git a/config/common_linuxapp b/config/common_linuxapp\nindex 9047975..1c8a3d5 100644\n--- a/config/common_linuxapp\n+++ b/config/common_linuxapp\n@@ -312,6 +312,12 @@ CONFIG_RTE_LIBRTE_HASH=y\n CONFIG_RTE_LIBRTE_HASH_DEBUG=n\n \n #\n+# Compile librte_tshash\n+#\n+CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH=y\n+CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH_STATS=y\n+\n+#\n # Compile librte_lpm\n #\n CONFIG_RTE_LIBRTE_LPM=y\ndiff --git a/lib/Makefile b/lib/Makefile\nindex 10c5bb3..728e6cf 100644\n--- a/lib/Makefile\n+++ b/lib/Makefile\n@@ -51,6 +51,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio\n DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3\n DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt\n DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash\n+DIRS-$(CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH) += librte_tshash\n DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm\n DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl\n DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net\ndiff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h\nindex 565415a..633b203 100644\n--- a/lib/librte_eal/common/include/rte_log.h\n+++ b/lib/librte_eal/common/include/rte_log.h\n@@ -68,6 +68,7 @@ extern struct rte_logs rte_logs;\n #define RTE_LOGTYPE_TIMER   0x00000010 /**< Log related to timers. */\n #define RTE_LOGTYPE_PMD     0x00000020 /**< Log related to poll mode driver. */\n #define RTE_LOGTYPE_HASH    0x00000040 /**< Log related to hash table. */\n+#define RTE_LOGTYPE_TSHASH    0x00000040 /**< Log related to thread safe hash table. */\n #define RTE_LOGTYPE_LPM     0x00000080 /**< Log related to LPM. */\n #define RTE_LOGTYPE_KNI     0x00000100 /**< Log related to KNI. */\n #define RTE_LOGTYPE_ACL     0x00000200 /**< Log related to ACL. */\ndiff --git a/lib/librte_eal/common/include/rte_tailq_elem.h b/lib/librte_eal/common/include/rte_tailq_elem.h\nindex f74fc7c..446e34b 100644\n--- a/lib/librte_eal/common/include/rte_tailq_elem.h\n+++ b/lib/librte_eal/common/include/rte_tailq_elem.h\n@@ -72,6 +72,8 @@ rte_tailq_elem(RTE_TAILQ_RING, \"RTE_RING\")\n \n rte_tailq_elem(RTE_TAILQ_HASH, \"RTE_HASH\")\n \n+rte_tailq_elem(RTE_TAILQ_TSHASH, \"RTE_TSHASH\")\n+\n rte_tailq_elem(RTE_TAILQ_FBK_HASH, \"RTE_FBK_HASH\")\n \n rte_tailq_elem(RTE_TAILQ_LPM, \"RTE_LPM\")\ndiff --git a/lib/librte_tshash/Makefile b/lib/librte_tshash/Makefile\nnew file mode 100644\nindex 0000000..193568d\n--- /dev/null\n+++ b/lib/librte_tshash/Makefile\n@@ -0,0 +1,49 @@\n+#   BSD LICENSE\n+#\n+#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+#   All rights reserved.\n+#\n+#   Redistribution and use in source and binary forms, with or without\n+#   modification, are permitted provided that the following conditions\n+#   are met:\n+#\n+#     * Redistributions of source code must retain the above copyright\n+#       notice, this list of conditions and the following disclaimer.\n+#     * Redistributions in binary form must reproduce the above copyright\n+#       notice, this list of conditions and the following disclaimer in\n+#       the documentation and/or other materials provided with the\n+#       distribution.\n+#     * Neither the name of Intel Corporation nor the names of its\n+#       contributors may be used to endorse or promote products derived\n+#       from this software without specific prior written permission.\n+#\n+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+#   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+# library name\n+LIB = librte_tshash.a\n+\n+CFLAGS += -O3\n+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)\n+\n+# all source are stored in SRCS-y\n+SRCS-$(CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH) := rte_tshash.c\n+\n+# install this header file\n+SYMLINK-$(CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH)-include := rte_tshash.h\n+\n+# this lib needs eal\n+DEPDIRS-$(CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH) += lib/librte_eal lib/librte_malloc\n+\n+include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/lib/librte_tshash/rte_tshash.c b/lib/librte_tshash/rte_tshash.c\nnew file mode 100644\nindex 0000000..87fe400\n--- /dev/null\n+++ b/lib/librte_tshash/rte_tshash.c\n@@ -0,0 +1,580 @@\n+/**\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <x86intrin.h>\n+\n+#include <rte_tailq.h>\n+#include <rte_malloc.h>\n+#include <rte_memzone.h>\n+#include <rte_eal_memconfig.h>\n+#include <rte_common.h>\n+#include <rte_string_fns.h>\n+#include <rte_errno.h>\n+#include <rte_memcpy.h>\n+#include <rte_rwlock.h>\n+#include <rte_log.h>\n+\n+#include \"rte_tshash.h\"\n+\n+#define DEFAULT_LOAD_FACTOR        (0.5)\n+\n+/* Hash function used if none is specified */\n+#ifdef RTE_MACHINE_CPUFLAG_SSE4_2\n+#include <rte_hash_crc.h>\n+#define DEFAULT_TSHASH_FUNC       rte_hash_crc\n+#else\n+#include <rte_jhash.h>\n+#define DEFAULT_TSHASH_FUNC       rte_jhash\n+#endif\n+\n+TAILQ_HEAD(rte_tshash_list, rte_tshash);\n+\n+static int rte_tshash_k16_cmp_eq(const void *key1, const void *key2,\n+\t\t\t\t__rte_unused uint8_t key_size);\n+static int rte_tshash_k32_cmp_eq(const void *key1, const void *key2,\n+\t\t\t\tuint8_t key_size);\n+static int rte_tshash_k48_cmp_eq(const void *key1, const void *key2,\n+\t\t\t\tuint8_t key_size);\n+static int rte_tshash_k64_cmp_eq(const void *key1, const void *key2,\n+\t\t\t\tuint8_t key_size);\n+static int rte_tshash_k96_cmp_eq(const void *key1, const void *key2,\n+\t\t\t\tuint8_t key_size);\n+static int rte_tshash_k128_cmp_eq(const void *key1, const void *key2,\n+\t\t\t\tuint8_t key_size);\n+\n+struct rte_tshash *\n+rte_tshash_create(const char *name, unsigned max_entries,\n+\t\tunsigned key_size, int socket_id,\n+\t\tconst struct rte_tshash_extra_args *e_args)\n+{\n+\tconst int noflags = 0;\n+\tconst unsigned anyalignment = 0;\n+\n+\tstruct rte_tshash *h = NULL;\n+\tstruct rte_tshash_list *tshash_list;\n+\tvoid *k = NULL;\n+\tstruct rte_ring *r = NULL;\n+\tchar ring_name[RTE_RING_NAMESIZE];\n+\tunsigned use_malloc = 0;\n+\tunsigned update_add = 0;\n+\tdouble load_factor = DEFAULT_LOAD_FACTOR;\n+\trte_tshash_cmp_eq_t tshash_cmp_eq_param = NULL;\n+\trte_tshash_function_t tshash_func_param = NULL;\n+\n+\tuint32_t num_hashes;\n+\tuint32_t num_buckets;\n+\tunsigned key_entry_size;\n+\tunsigned i;\n+\n+\tRTE_BUILD_BUG_ON(sizeof(struct rte_tshash_bucket) != CACHE_LINE_SIZE);\n+\n+\tif (name == NULL || max_entries < RTE_TSHASH_MIN_ENTRIES ||\n+\t\tsocket_id >= RTE_MAX_NUMA_NODES)\n+\t\tgoto param_err;\n+\n+\tif (e_args != NULL) {\n+\t\tuse_malloc = e_args->malloc_mem;\n+\t\tload_factor = e_args->max_load_factor;\n+\t\ttshash_cmp_eq_param = e_args->rte_tshash_cmp_eq;\n+\t\ttshash_func_param = e_args->hash_func;\n+\t\tupdate_add = e_args->update_add;\n+\n+\t\tif (load_factor > RTE_TSHASH_MAXIMUM_LOAD_FACTOR)\n+\t\t\tgoto param_err;\n+\t}\n+\n+\t/* check the key-size is a supported value */\n+\tif (key_size != 16 && key_size != 32 && key_size != 48 &&\n+\t\t\tkey_size != 64 && key_size != 96 && key_size != 128)\n+\t\tif (!tshash_cmp_eq_param)\n+\t\t\t\tgoto param_err;\n+\n+\tif (key_size == 0)\n+\t\tgoto param_err;\n+\n+\t/* check that we have an initialised tail queue */\n+\ttshash_list = RTE_TAILQ_LOOKUP_BY_IDX(RTE_TAILQ_TSHASH, rte_tshash_list);\n+\tif (tshash_list == NULL) {\n+\t\trte_errno = E_RTE_NO_TAILQ;\n+\t\treturn NULL;\n+\t}\n+\n+\t/* calculate number of hash values entries to be used. Floating point\n+\t * can be inaccurate, so subtract a bit so that we don't accidently\n+\t * overflow a power of 2, and then scale up to the next one unnecessarily\n+\t */\n+\tnum_hashes = ((double)max_entries / load_factor) - 2;\n+\tnum_hashes = rte_align32pow2(num_hashes);\n+\tnum_buckets = num_hashes / RTE_TSHASH_BUCKET_SIZE;\n+\n+\n+\t/* whatever number of entries for keys we want, we need 1 more as a dummy\n+\t * entry, which is used in case of a miss on a bucket scan.\n+\t */\n+\tmax_entries++;\n+\n+\tkey_entry_size = sizeof(struct rte_tshash_key) + key_size;\n+\n+\tif (use_malloc) {\n+\t\th = rte_zmalloc_socket(NULL, sizeof(*h) +\n+\t\t\t\t(sizeof(h->bkts[1]) * num_buckets),\n+\t\t\t\tanyalignment, socket_id);\n+\t\tif (h == NULL)\n+\t\t\tgoto memory_err;\n+\n+\t\tk = rte_zmalloc_socket(NULL, key_entry_size * max_entries,\n+\t\t\t\tanyalignment, socket_id);\n+\t\tif (k == NULL)\n+\t\t\tgoto memory_err;\n+\n+\t} else {\n+\t\tchar mz_name[RTE_MEMZONE_NAMESIZE];\n+\t\tchar key_mz_name[RTE_MEMZONE_NAMESIZE];\n+\t\tconst struct rte_memzone *mz;\n+\n+\t\tsnprintf(mz_name, sizeof(mz_name), \"HSH_%s\", name);\n+\t\tsnprintf(key_mz_name, sizeof(key_mz_name), \"HSH_KEYS_%s\", name);\n+\n+\t\tmz = rte_memzone_reserve(mz_name, sizeof(*h) +\n+\t\t\t\t(sizeof(h->bkts[1]) * num_buckets),\n+\t\t\t\tsocket_id, noflags);\n+\t\tif (mz == NULL)\n+\t\t\tgoto memory_err;\n+\t\th = mz->addr;\n+\n+\t\tmz = rte_memzone_reserve(key_mz_name, key_entry_size * max_entries,\n+\t\t\t\tsocket_id, noflags);\n+\t\tif (mz == NULL)\n+\t\t\tgoto memory_err;\n+\t\tk = mz->addr;\n+\t}\n+\tsnprintf(ring_name, sizeof(ring_name), \"HSH_%s\", name);\n+\tr = rte_ring_create(ring_name, rte_align32pow2(max_entries), socket_id,\n+\t\t\tnoflags);\n+\tif (r == NULL)\n+\t\tgoto memory_err;\n+\n+\tRTE_LOG(INFO, TSHASH, \"Created Hash Table\\n\");\n+\tRTE_LOG(INFO, TSHASH, \"-> Hash value slots: %u\\n\", num_hashes);\n+\tRTE_LOG(INFO, TSHASH, \"-> Hash key slots  : %u\\n\", max_entries);\n+\tRTE_LOG(INFO, TSHASH, \"-> Free ring size  : %u\\n\",\n+\t\t\t\t\trte_align32pow2(max_entries + 1));\n+\tRTE_LOG(INFO, TSHASH, \"-> Buckets         : %u\\n\", num_buckets);\n+\n+\t/* add the free slots ring to the hash table, and do other assignments */\n+\th->free_slots = r;\n+\th->key_store = k;\n+\th->socket_id = socket_id;\n+\th->bucket_mask = (num_buckets - 1);\n+\th->key_entry_size = key_entry_size;\n+\th->key_size = key_size;\n+\th->max_items = max_entries;\n+\th->rte_tshash_cmp_eq = tshash_cmp_eq_param;\n+\n+\tif (h->rte_tshash_cmp_eq == NULL)\n+\t\tswitch (h->key_size) {\n+\t\tcase 16:\n+\t\t\th->rte_tshash_cmp_eq = rte_tshash_k16_cmp_eq;\n+\t\t\tbreak;\n+\t\tcase 32:\n+\t\t\th->rte_tshash_cmp_eq = rte_tshash_k32_cmp_eq;\n+\t\t\tbreak;\n+\t\tcase 48:\n+\t\t\th->rte_tshash_cmp_eq = rte_tshash_k48_cmp_eq;\n+\t\t\tbreak;\n+\t\tcase 64:\n+\t\t\th->rte_tshash_cmp_eq = rte_tshash_k64_cmp_eq;\n+\t\t\tbreak;\n+\t\tcase 96:\n+\t\t\th->rte_tshash_cmp_eq = rte_tshash_k96_cmp_eq;\n+\t\t\tbreak;\n+\t\tcase 128:\n+\t\t\th->rte_tshash_cmp_eq = rte_tshash_k128_cmp_eq;\n+\t\t\tbreak;\n+\t\t}\n+\n+\tif (tshash_func_param)\n+\t\th->tshash_func = tshash_func_param;\n+\telse\n+\t\th->tshash_func = DEFAULT_TSHASH_FUNC;\n+\n+\th->update_add = update_add;\n+\n+\tsnprintf(h->name, sizeof(h->name), \"%s\", name);\n+\n+\t/* populate the free slots ring. Entry zero is reserved for key misses */\n+\tfor (i = 1; i < max_entries; i++)\n+\t\trte_ring_sp_enqueue(r, (void *)((uintptr_t)i));\n+\n+\tTAILQ_INSERT_TAIL(tshash_list, h, next);\n+\treturn h;\n+\n+param_err:\n+\trte_errno = EINVAL;\n+\treturn NULL;\n+\n+memory_err:\n+\tif (use_malloc) {\n+\t\tif (h != NULL)\n+\t\t\trte_free(h);\n+\t\tif (k != NULL)\n+\t\t\trte_free(k);\n+\t}\n+\trte_errno = ENOMEM;\n+\treturn NULL;\n+}\n+\n+void\n+rte_tshash_reset(struct rte_tshash *h)\n+{\n+\tunsigned i;\n+\tvoid *ptr;\n+\tstruct rte_tshash_bucket *next_bucket_to_delete, *bucket_to_delete;\n+\n+\t/* first: rte_free the extra buckets */\n+\tfor (i = 0; i < h->bucket_mask+1; i++) {\n+\t\tnext_bucket_to_delete = h->bkts[i].next;\n+\t\twhile (next_bucket_to_delete) {\n+\t\t\tbucket_to_delete = next_bucket_to_delete;\n+\t\t\tnext_bucket_to_delete = bucket_to_delete->next;\n+\t\t\trte_free(bucket_to_delete);\n+\t\t}\n+\t}\n+\t/* zero the buckets */\n+\tmemset(h->bkts, 0, (h->bucket_mask+1)*sizeof(h->bkts[0]));\n+\n+\t/* clear the free ring */\n+\twhile (rte_ring_dequeue(h->free_slots, &ptr) == 0)\n+\t\trte_pause();\n+\n+\t/* zero key slots */\n+\tmemset(h->key_store, 0, h->key_entry_size * h->max_items);\n+\t/* Repopulate the free ring. Entry zero is reserved for key misses */\n+\tfor (i = 1; i < h->max_items; i++)\n+\t\trte_ring_sp_enqueue(h->free_slots, (void *)((uintptr_t)i));\n+#ifdef RTE_LIBRTE_THREAD_SAFE_HASH_STATS\n+\t/* zero the stats */\n+\th->stats.num_extra_buckets = h->stats.used_slots = 0;\n+#endif\n+}\n+\n+struct rte_tshash *\n+rte_tshash_find_existing(const char *name)\n+{\n+\tstruct rte_tshash *h;\n+\tstruct rte_tshash_list *tshash_list;\n+\n+\t/* check that we have an initialised tail queue */\n+\ttshash_list = RTE_TAILQ_LOOKUP_BY_IDX(RTE_TAILQ_TSHASH,\trte_tshash_list);\n+\tif (tshash_list == NULL) {\n+\t\trte_errno = E_RTE_NO_TAILQ;\n+\t\treturn NULL;\n+\t}\n+\n+\trte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);\n+\tTAILQ_FOREACH(h, tshash_list, next) {\n+\t\tif (strncmp(name, h->name, RTE_TSHASH_NAMESIZE) == 0)\n+\t\t\tbreak;\n+\t}\n+\trte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);\n+\n+\tif (h == NULL)\n+\t\trte_errno = ENOENT;\n+\treturn h;\n+}\n+\n+static int\n+rte_tshash_k16_cmp_eq(const void *key1, const void *key2,\n+\t\t\t\t\t__rte_unused uint8_t key_size)\n+{\n+\tconst __m128i k1 = _mm_load_si128((const __m128i *) key1);\n+\tconst __m128i k2 = _mm_load_si128((const __m128i *) key2);\n+\tconst __m128i x = _mm_xor_si128(k1, k2);\n+\treturn _mm_test_all_zeros(x, x);\n+}\n+\n+static int\n+rte_tshash_k32_cmp_eq(const void *key1, const void *key2, uint8_t key_size)\n+{\n+\treturn rte_tshash_k16_cmp_eq(key1, key2, key_size) &&\n+\t\trte_tshash_k16_cmp_eq((const char *)key1+16,\n+\t\t\t\t(const char *)key2+16, key_size);\n+}\n+\n+static int\n+rte_tshash_k48_cmp_eq(const void *key1, const void *key2, uint8_t key_size)\n+{\n+\treturn rte_tshash_k16_cmp_eq(key1, key2, key_size) &&\n+\t\trte_tshash_k16_cmp_eq((const char *)key1+16,\n+\t\t\t\t(const char *)key2+16, key_size) &&\n+\t\trte_tshash_k16_cmp_eq((const char *)key1+32,\n+\t\t\t\t(const char *)key2+32, key_size);\n+}\n+\n+static int\n+rte_tshash_k64_cmp_eq(const void *key1, const void *key2, uint8_t key_size)\n+{\n+\treturn rte_tshash_k32_cmp_eq(key1, key2, key_size) &&\n+\t\trte_tshash_k32_cmp_eq((const char *)key1+32,\n+\t\t\t\t(const char *)key2+32, key_size);\n+}\n+\n+static int\n+rte_tshash_k96_cmp_eq(const void *key1, const void *key2, uint8_t key_size)\n+{\n+\treturn rte_tshash_k64_cmp_eq(key1, key2, key_size) &&\n+\t\trte_tshash_k32_cmp_eq((const char *)key1+64,\n+\t\t\t\t(const char *)key2+64, key_size);\n+}\n+\n+static int\n+rte_tshash_k128_cmp_eq(const void *key1, const void *key2, uint8_t key_size)\n+{\n+\treturn rte_tshash_k64_cmp_eq(key1, key2, key_size) &&\n+\t\trte_tshash_k64_cmp_eq((const char *)key1+64,\n+\t\t\t\t(const char *)key2+64, key_size);\n+}\n+\n+int\n+rte_tshash_add_key_with_hash(struct rte_tshash *h, uint64_t hash_val,\n+\t\tconst void *key, uintptr_t idata)\n+{\n+\tstruct rte_tshash_bucket *bkt = &h->bkts[hash_val & h->bucket_mask];\n+\tstruct rte_tshash_bucket *add_bkt = NULL;\n+\tstruct rte_tshash_key *key_slot, *keys = h->key_store;\n+\tvoid *slot_id;\n+\tunsigned pos = 0;\n+\tint free_pos = -1;\n+\n+\trte_prefetch0(bkt);\n+\n+\tif (rte_ring_mc_dequeue(h->free_slots, &slot_id) != 0)\n+\t\treturn -ENOSPC;\n+\n+\tkey_slot = (struct rte_tshash_key *)((char *)keys +\n+\t\t\t\t\t(uintptr_t)slot_id * h->key_entry_size);\n+\trte_prefetch0(key_slot);\n+\n+\tdo {\n+\t\tfor (pos = 0; pos < RTE_TSHASH_BUCKET_SIZE; pos++) {\n+\t\t\t/*\n+\t\t\t * If free slot has not been found yet and current one\n+\t\t\t * is empty, make it invalid for later use\n+\t\t\t */\n+\t\t\tif (free_pos == -1 && bkt->hash_val[pos] == RTE_TSHASH_EMPTY) {\n+\t\t\t\tif (__sync_bool_compare_and_swap(&bkt->hash_val[pos],\n+\t\t\t\t\tRTE_TSHASH_EMPTY, RTE_TSHASH_INVALID)) {\n+\t\t\t\t\tfree_pos = pos;\n+\t\t\t\t\tadd_bkt = bkt;\n+\t\t\t\t} else\n+\t\t\t\t\tcontinue;\n+\t\t\t} else if (bkt->hash_val[pos] == (hash_val | RTE_TSHASH_VALID)) {\n+\t\t\t\t/* check key for match */\n+\t\t\t\tstruct rte_tshash_key *k = (struct rte_tshash_key *)\n+\t\t\t\t\t\t((char *)keys + bkt->key_idx[pos] * h->key_entry_size);\n+\t\t\t\tif (h->rte_tshash_cmp_eq((const void *)k->key,\n+\t\t\t\t\t\t\t\t\t\tkey, h->key_size)) {\n+\t\t\t\t\trte_ring_mp_enqueue(h->free_slots, slot_id);\n+\t\t\t\t\tif (free_pos >= 0)\n+\t\t\t\t\t\tbkt->hash_val[free_pos] = RTE_TSHASH_EMPTY;\n+\t\t\t\t\tif (!h->update_add)\n+\t\t\t\t\t\treturn -EEXIST;\n+\t\t\t\t\t/* Update just data */\n+\t\t\t\t\trte_atomic64_set((rte_atomic64_t *)&k->idata, idata);\n+\t\t\t\t\treturn 0;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif (pos == RTE_TSHASH_BUCKET_SIZE) {\n+\t\t\tif (bkt->next == NULL && free_pos < 0) {\n+\t\t\t\tvoid *new_bkt = rte_zmalloc(NULL,\n+\t\t\t\t\t\tsizeof(struct rte_tshash_bucket), 0);\n+\t\t\t\tif (new_bkt == NULL) {\n+\t\t\t\t\trte_ring_mp_enqueue(h->free_slots, slot_id);\n+\t\t\t\t\treturn -ENOMEM;\n+\t\t\t\t}\n+\t\t\t\tif (!__sync_bool_compare_and_swap(&bkt->next, NULL, new_bkt)) {\n+\t\t\t\t\t/* if we can't add the new bucket, tell user to retry */\n+\t\t\t\t\trte_ring_mp_enqueue(h->free_slots, slot_id);\n+\t\t\t\t\trte_free(new_bkt);\n+\t\t\t\t\treturn -EAGAIN;\n+\t\t\t\t}\n+#ifdef RTE_LIBRTE_THREAD_SAFE_HASH_STATS\n+\t\t\t\t__sync_fetch_and_add(&h->stats.num_extra_buckets, 1);\n+#endif\n+\t\t\t}\n+\t\t\tbkt = bkt->next;\n+\t\t\trte_prefetch0(bkt);\n+\t\t\tpos = 0;\n+\t\t}\n+\t} while (bkt);\n+\n+\t__sync_fetch_and_add(&key_slot->counter, 1);\n+\trte_compiler_barrier();\n+\trte_memcpy(key_slot->key, key, h->key_size);\n+\tkey_slot->idata = idata;\n+\n+\tadd_bkt->key_idx[free_pos] = (uint32_t)((uintptr_t)slot_id);\n+\tadd_bkt->counter[free_pos] = key_slot->counter;\n+\trte_compiler_barrier();\n+\tadd_bkt->hash_val[free_pos] = hash_val | RTE_TSHASH_VALID;\n+#ifdef RTE_LIBRTE_THREAD_SAFE_HASH_STATS\n+\t__sync_fetch_and_add(&h->stats.used_slots, 1);\n+#endif\n+\treturn 0;\n+}\n+\n+int\n+rte_tshash_add_key(struct rte_tshash *h, const void *key, uintptr_t idata)\n+{\n+\treturn rte_tshash_add_key_with_hash(h, rte_tshash_hash(h, key), key, idata);\n+}\n+\n+int\n+rte_tshash_del_key_with_hash(struct rte_tshash *h,\n+\t\tuint64_t hash_val, const void *key, uintptr_t *value)\n+{\n+\tstruct rte_tshash_key *keys[RTE_TSHASH_BUCKET_SIZE] = {0};\n+\tunsigned i;\n+\tstruct rte_tshash_bucket *bkt = &h->bkts[hash_val & h->bucket_mask];\n+\tstruct rte_tshash_key *key_store = h->key_store;\n+\t_mm_prefetch((const char *)bkt, 0);\n+\n+\tdo {\n+\t\trte_prefetch0(bkt->next);\n+\n+\t\t/* Check if there is a hash value match */\n+\t\tfor (i = 0; i < RTE_TSHASH_BUCKET_SIZE; i++)\n+\t\t\tif (bkt->hash_val[i] == (hash_val | RTE_TSHASH_VALID)) {\n+\t\t\t\tkeys[i] = (struct rte_tshash_key *)((char *)key_store +\n+\t\t\t\t\t\t\t\t(bkt->key_idx[i] * h->key_entry_size));\n+\t\t\t\trte_prefetch0((const char *)&keys[i]);\n+\t\t\t}\n+\n+\t\tfor (i = 0; i < RTE_TSHASH_BUCKET_SIZE; i++) {\n+\t\t\tif (keys[i] != 0 &&\th->rte_tshash_cmp_eq((const void *) keys[i]->key,\n+\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey, h->key_size)) {\n+\t\t\t\tif (!__sync_bool_compare_and_swap(&bkt->hash_val[i],\n+\t\t\t\t\t\t\t\thash_val | RTE_TSHASH_VALID, RTE_TSHASH_EMPTY))\n+\t\t\t\t\t/* Already deleted */\n+\t\t\t\t\treturn 0;\n+\n+\t\t\t\trte_compiler_barrier();\n+\n+\t\t\t\t/*\n+\t\t\t\t * If user wants to free the data associated to this entry,\n+\t\t\t\t * the pointer shall be returned\n+\t\t\t\t */\n+\t\t\t\tif (value != NULL)\n+\t\t\t\t\t*value = keys[i]->idata;\n+\n+\t\t\t\t/* TODO: Remove bucket if all entries in it are empty */\n+\t\t\t\trte_ring_mp_enqueue(h->free_slots,\n+\t\t\t\t\t\t\t(void *)((uintptr_t)bkt->key_idx[i]));\n+#ifdef RTE_LIBRTE_THREAD_SAFE_HASH_STATS\n+\t\t\t\t__sync_fetch_and_sub(&h->stats.used_slots, 1);\n+#endif\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t}\n+\n+\t\tbkt = bkt->next;\n+\n+\t} while (bkt);\n+\n+\t/* No such key stored */\n+\treturn -1;\n+}\n+\n+int\n+rte_tshash_del_key(struct rte_tshash *h, const void *key, uintptr_t *value)\n+{\n+\treturn rte_tshash_del_key_with_hash(h, rte_tshash_hash(h, key), key, value);\n+}\n+\n+int\n+rte_tshash_lookup_with_hash(const struct rte_tshash *h,\n+\t\tuint64_t hash_val, const void *key, uintptr_t *value)\n+{\n+\tconst struct rte_tshash_key *keys[RTE_TSHASH_BUCKET_SIZE] = {0};\n+\tunsigned num_slots;\n+\tunsigned i;\n+\tconst struct rte_tshash_bucket *bkt = &h->bkts[hash_val & h->bucket_mask];\n+\tconst struct rte_tshash_key *key_store = h->key_store;\n+\tuint8_t counters[RTE_TSHASH_BUCKET_SIZE] = {0};\n+\n+\trte_prefetch0((const char *)bkt);\n+\n+\tdo {\n+\t\trte_prefetch0(bkt->next);\n+\t\tnum_slots = 0;\n+\n+\t\t/* Check if there is a hash value match */\n+\t\tfor (i = 0; i < RTE_TSHASH_BUCKET_SIZE; i++)\n+\t\t\tif (bkt->hash_val[i] == (hash_val | RTE_TSHASH_VALID)) {\n+\t\t\t\tkeys[num_slots] = (const struct rte_tshash_key *)\n+\t\t\t\t\t\t((const char *)key_store +\n+\t\t\t\t\t\t\t\t(bkt->key_idx[i] * h->key_entry_size));\n+\t\t\t\trte_prefetch0((const char *)&keys[num_slots]);\n+\t\t\t\tcounters[num_slots] = bkt->counter[i];\n+\t\t\t\tnum_slots++;\n+\t\t\t}\n+\n+\t\tfor (i = 0; i < num_slots; i++) {\n+\t\t\tif (h->rte_tshash_cmp_eq((const void *) keys[i]->key,\n+\t\t\t\t\t\tkey, h->key_size)) {\n+\t\t\t\t*value = keys[i]->idata;\n+\t\t\t\trte_compiler_barrier();\n+\t\t\t\t/* Check counter in key slot is same as counter in bucket */\n+\t\t\t\tif (unlikely(counters[i] != keys[i]->counter))\n+\t\t\t\t\t/* Tell user to retry */\n+\t\t\t\t\treturn -EAGAIN;\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t}\n+\n+\t\tbkt = bkt->next;\n+\n+\t} while (bkt);\n+\n+\treturn -1;\n+}\n+\n+int\n+rte_tshash_lookup(const struct rte_tshash *h, const void *key,\n+\t\tuintptr_t *value)\n+{\n+\treturn rte_tshash_lookup_with_hash(h, rte_tshash_hash(h, key), key, value);\n+}\n+\n+\ndiff --git a/lib/librte_tshash/rte_tshash.h b/lib/librte_tshash/rte_tshash.h\nnew file mode 100644\nindex 0000000..2ea05b3\n--- /dev/null\n+++ b/lib/librte_tshash/rte_tshash.h\n@@ -0,0 +1,533 @@\n+/**\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef _RTE_RTE_TSHASH_H_\n+#define _RTE_RTE_TSHASH_H_\n+\n+#include <stdint.h>\n+\n+#include <rte_memory.h>\n+#include <rte_ring.h>\n+#include <rte_prefetch.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_malloc.h>\n+#include <rte_memcpy.h>\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/** Max number of characters in hash name.*/\n+#define RTE_TSHASH_NAMESIZE         32\n+\n+/** Number of elements in each bucket */\n+#define RTE_TSHASH_BUCKET_SIZE       4\n+\n+#define RTE_TSHASH_MAX_BURST        64\n+#define RTE_TSHASH_MIN_ENTRIES      32\n+\n+#define RTE_TSHASH_MAXIMUM_LOAD_FACTOR (1.0)\n+\n+typedef uint32_t (*rte_tshash_function_t)(const void *key, uint32_t key_len,\n+\t\t\t\t      uint32_t init_val);\n+typedef int (*rte_tshash_cmp_eq_t)(const void *key1, const void *key2,\n+\t\t\t\t\t\tuint8_t key_len);\n+\n+enum {\n+\tRTE_TSHASH_EMPTY = 0,\n+\tRTE_TSHASH_INVALID = 1,\n+\tRTE_TSHASH_VALID = 3\n+};\n+\n+struct rte_tshash_extra_args {\n+\tdouble max_load_factor;\n+\tunsigned  malloc_mem;\n+\trte_tshash_cmp_eq_t rte_tshash_cmp_eq;\n+\trte_tshash_function_t hash_func;\n+\tunsigned update_add;\n+};\n+\n+struct rte_tshash_bucket {\n+\tuint64_t hash_val[RTE_TSHASH_BUCKET_SIZE];\n+\tuint32_t key_idx[RTE_TSHASH_BUCKET_SIZE + 1]; /* have dummy entry on end,\n+\t\t\t always points to entry zero */\n+\n+\tuint8_t counter[RTE_TSHASH_BUCKET_SIZE];\n+\n+\tstruct rte_tshash_bucket *next;\n+} __rte_cache_aligned;\n+\n+struct rte_tshash_key {\n+\tunion {\n+\t\tuintptr_t idata;\n+\t\tvoid *pdata;\n+\t};\n+\tuint8_t counter;\n+\t/* Variable key size */\n+\tchar key[] __attribute__((aligned(16)));\n+};\n+\n+#ifdef RTE_LIBRTE_THREAD_SAFE_HASH_STATS\n+struct rte_tshash_stats {\n+\tunsigned used_slots;\n+\tunsigned num_extra_buckets;\n+};\n+#endif\n+\n+struct rte_tshash {\n+\tTAILQ_ENTRY(rte_tshash) next;/**< Next in list. */\n+\tchar name[RTE_TSHASH_NAMESIZE];\n+\n+\tunsigned key_size __rte_cache_aligned;\n+\tunsigned key_entry_size;\n+\tunsigned bucket_mask;\n+\tunsigned socket_id;\n+\tunsigned max_items;\n+#ifdef RTE_LIBRTE_THREAD_SAFE_HASH_STATS\n+\tstruct rte_tshash_stats stats;\n+#endif\n+\n+\tstruct rte_ring *free_slots;\n+\tvoid *key_store;\n+\n+\trte_tshash_cmp_eq_t rte_tshash_cmp_eq;\n+\trte_tshash_function_t tshash_func;\n+\tuint32_t tshash_func_init_val;\n+\n+\tunsigned update_add;\n+\n+\tstruct rte_tshash_bucket bkts[];\n+} __rte_cache_aligned;\n+\n+\n+struct rte_tshash *\n+rte_tshash_create(const char *name, unsigned max_entries, unsigned key_size,\n+\t\tint socket_id, const struct rte_tshash_extra_args *e_args);\n+\n+struct rte_tshash *\n+rte_tshash_find_existing(const char *name);\n+\n+void\n+rte_tshash_reset(struct rte_tshash *h);\n+\n+static inline uint64_t\n+rte_tshash_hash(const struct rte_tshash *h, const void *key)\n+{\n+\t/* calc hash result by key */\n+\treturn h->tshash_func(key, h->key_size, h->tshash_func_init_val);\n+}\n+\n+int\n+rte_tshash_add_key_with_hash(struct rte_tshash *h, uint64_t hash_val,\n+\t\tconst void *key, uintptr_t idata);\n+int\n+rte_tshash_add_key(struct rte_tshash *h, const void *key, uintptr_t idata);\n+\n+int\n+rte_tshash_del_key_with_hash(struct rte_tshash *h, uint64_t hash_val,\n+\t\tconst void *key, uintptr_t *value);\n+\n+int\n+rte_tshash_del_key(struct rte_tshash *h, const void *key, uintptr_t *value);\n+\n+int\n+rte_tshash_lookup_with_hash(const struct rte_tshash *h,\n+\t\tuint64_t hash_val, const void *key, uintptr_t *value);\n+\n+int\n+rte_tshash_lookup(const struct rte_tshash *h, const void *key, uintptr_t *value);\n+\n+\n+/* Lookup bulk stage 0: Prefetch next hash value */\n+static inline void\n+lookup_stage0(unsigned *idx, uint64_t *lookup_mask,\n+\t\tuint64_t *const *hash_vals __rte_unused)\n+{\n+\t*idx = __builtin_ctzl(*lookup_mask);\n+\tif (*lookup_mask == 0)\n+\t\t*idx = 0;\n+\trte_prefetch0(hash_vals[*idx]);\n+\t*lookup_mask &= ~(1llu << *idx);\n+}\n+\n+/* Lookup bulk stage 0: Calculate next hash value (from new key)  */\n+static inline void\n+lookup_stage0_key(unsigned *idx, uint64_t *lookup_mask, uint64_t *calc_hash,\n+\t\tconst void * const *keys, const struct rte_tshash *h)\n+{\n+\t*idx = __builtin_ctzl(*lookup_mask);\n+\tif (*lookup_mask == 0)\n+\t\t*idx = 0;\n+\n+\t*calc_hash = rte_tshash_hash(h, keys[*idx]);\n+\t*lookup_mask &= ~(1llu << *idx);\n+}\n+\n+\n+/* Lookup bulk stage 1: Get next hash value and prefetch associated bucket */\n+static inline void\n+lookup_stage1(unsigned idx, uint64_t *hash, const struct rte_tshash_bucket **bkt,\n+\t\tuint64_t *const *hash_vals, const struct rte_tshash *h)\n+{\n+\t*hash = *hash_vals[idx];\n+\t*bkt = &h->bkts[*hash & h->bucket_mask];\n+\trte_prefetch0(*bkt);\n+\n+\t*hash |= RTE_TSHASH_VALID;\n+}\n+\n+\n+/* Lookup bulk stage 1: Prefetch associated bucket */\n+static inline void\n+lookup_stage1_key(uint64_t *hash, const struct rte_tshash_bucket **bkt,\n+\t\tconst struct rte_tshash *h)\n+{\n+\t*bkt = &h->bkts[*hash & h->bucket_mask];\n+\trte_prefetch0(*bkt);\n+\n+\t*hash |= RTE_TSHASH_VALID;\n+}\n+\n+\n+/*\n+ * Lookup bulk stage 2:  Store pointer to next bucket (if any). Search for match\n+ * hashes in first level and prefetch first key slot\n+ */\n+static inline void\n+lookup_stage2(unsigned idx, uint64_t hash, const struct rte_tshash_bucket *bkt,\n+\t\tconst struct rte_tshash_key **key_slot, uint8_t *counter,\n+\t\tuint64_t *next_mask, uint64_t *extra_hits_mask,\n+\t\tconst struct rte_tshash_bucket *next_bkts[],\n+\t\tconst struct rte_tshash_key *key_store,\tconst struct rte_tshash *h)\n+{\n+\tunsigned hash_matches, i;\n+\n+\t*next_mask |= (uint64_t)(!!bkt->next) << idx;\n+\tnext_bkts[idx] = bkt->next;\n+\n+\thash_matches = 1 << RTE_TSHASH_BUCKET_SIZE;\n+\tfor (i = 0; i < RTE_TSHASH_BUCKET_SIZE; i++)\n+\t\thash_matches |= ((hash == bkt->hash_val[i]) << i);\n+\n+\tunsigned key_idx = bkt->key_idx[__builtin_ctzl(hash_matches)];\n+\t*key_slot = (const struct rte_tshash_key *)((const char *)key_store +\n+\t\t\t\t\tkey_idx * h->key_entry_size);\n+\trte_prefetch0(*key_slot);\n+\t*counter = bkt->counter[__builtin_ctz(hash_matches)];\n+\n+\t*extra_hits_mask |= (uint64_t)(__builtin_popcount(hash_matches) > 2) << idx;\n+}\n+\n+\n+/*\n+ * Lookup bulk stage 3: Check if key matches, update hit mask\n+ * and store data in values[]\n+ */\n+static inline void\n+lookup_stage3(unsigned idx, const struct rte_tshash_key *key_slot,\n+\t\tuint8_t counter, uintptr_t values[], const void * const *keys,\n+\t\tuint64_t *hits, const struct rte_tshash *h)\n+{\n+\tvalues[idx] = key_slot->idata;\n+\tunsigned hit = h->rte_tshash_cmp_eq((const void *)key_slot->key,\n+\t\t\t\t\t\tkeys[idx], h->key_size);\n+\trte_compiler_barrier();\n+\t*hits |= (uint64_t)(hit & (key_slot->counter == counter)) << idx;\n+}\n+\n+\n+static inline int\n+rte_tshash_lookup_bulk_with_hash(const struct rte_tshash *h,\n+\t\tuint64_t lookup_mask, uint64_t *const *hash_vals,\n+\t\tconst void * const *keys, uintptr_t values[], uint64_t *hit_mask)\n+{\n+\tuint64_t hits = 0;\n+\tuint64_t next_mask = 0;\n+\tuint64_t extra_hits_mask = 0;\n+\tconst struct rte_tshash_key *key_store = h->key_store;\n+\tconst struct rte_tshash_bucket *next_bkts[RTE_TSHASH_MAX_BURST];\n+\n+\tunsigned idx00, idx01, idx10, idx11, idx20, idx21, idx30, idx31;\n+\tconst struct rte_tshash_bucket *bkt10, *bkt11, *bkt20, *bkt21;\n+\tconst struct rte_tshash_key *k_slot20, *k_slot21, *k_slot30, *k_slot31;\n+\tuint64_t hash10, hash11, hash20, hash21;\n+\tuint8_t counter20, counter21, counter30, counter31;\n+\n+\tlookup_stage0(&idx00, &lookup_mask, hash_vals);\n+\tlookup_stage0(&idx01, &lookup_mask, hash_vals);\n+\n+\tidx10 = idx00, idx11 = idx01;\n+\tlookup_stage0(&idx00, &lookup_mask, hash_vals);\n+\tlookup_stage0(&idx01, &lookup_mask, hash_vals);\n+\tlookup_stage1(idx10, &hash10, &bkt10, hash_vals, h);\n+\tlookup_stage1(idx11, &hash11, &bkt11, hash_vals, h);\n+\n+\tbkt20 = bkt10, bkt21 = bkt11;\n+\thash20 = hash10, hash21 = hash11;\n+\tidx20 = idx10, idx21 = idx11;\n+\tidx10 = idx00, idx11 = idx01;\n+\n+\tlookup_stage0(&idx00, &lookup_mask, hash_vals);\n+\tlookup_stage0(&idx01, &lookup_mask, hash_vals);\n+\tlookup_stage1(idx10, &hash10, &bkt10, hash_vals, h);\n+\tlookup_stage1(idx11, &hash11, &bkt11, hash_vals, h);\n+\tlookup_stage2(idx20, hash20, bkt20, &k_slot20, &counter20,\n+\t\t\t&next_mask, &extra_hits_mask,\n+\t\t\tnext_bkts, key_store, h);\n+\tlookup_stage2(idx21, hash21, bkt21, &k_slot21, &counter21,\n+\t\t\t&next_mask, &extra_hits_mask,\n+\t\t\tnext_bkts, key_store, h);\n+\n+\twhile (lookup_mask) {\n+\t\tk_slot30 = k_slot20, k_slot31 = k_slot21;\n+\t\tidx30 = idx20, idx31 = idx21;\n+\t\tcounter30 = counter20, counter31 = counter21;\n+\t\tbkt20 = bkt10, bkt21 = bkt11;\n+\t\thash20 = hash10, hash21 = hash11;\n+\t\tidx20 = idx10, idx21 = idx11;\n+\t\tidx10 = idx00, idx11 = idx01;\n+\n+\t\tlookup_stage0(&idx00, &lookup_mask, hash_vals);\n+\t\tlookup_stage0(&idx01, &lookup_mask, hash_vals);\n+\t\tlookup_stage1(idx10, &hash10, &bkt10, hash_vals, h);\n+\t\tlookup_stage1(idx11, &hash11, &bkt11, hash_vals, h);\n+\t\tlookup_stage2(idx20, hash20, bkt20, &k_slot20, &counter20,\n+\t\t\t&next_mask, &extra_hits_mask, next_bkts, key_store, h);\n+\t\tlookup_stage2(idx21, hash21, bkt21, &k_slot21, &counter21,\n+\t\t\t&next_mask, &extra_hits_mask, next_bkts, key_store, h);\n+\t\tlookup_stage3(idx30, k_slot30, counter30, values, keys, &hits, h);\n+\t\tlookup_stage3(idx31, k_slot31, counter31, values, keys, &hits, h);\n+\t}\n+\n+\tk_slot30 = k_slot20, k_slot31 = k_slot21;\n+\tidx30 = idx20, idx31 = idx21;\n+\tcounter30 = counter20, counter31 = counter21;\n+\tbkt20 = bkt10, bkt21 = bkt11;\n+\thash20 = hash10, hash21 = hash11;\n+\tidx20 = idx10, idx21 = idx11;\n+\tidx10 = idx00, idx11 = idx01;\n+\tlookup_stage1(idx10, &hash10, &bkt10, hash_vals, h);\n+\tlookup_stage1(idx11, &hash11, &bkt11, hash_vals, h);\n+\tlookup_stage2(idx20, hash20, bkt20,\n+\t\t\t&k_slot20, &counter20, &next_mask, &extra_hits_mask,\n+\t\t\tnext_bkts, key_store, h);\n+\tlookup_stage2(idx21, hash21, bkt21,\n+\t\t\t&k_slot21, &counter21, &next_mask, &extra_hits_mask,\n+\t\t\tnext_bkts, key_store, h);\n+\tlookup_stage3(idx30, k_slot30, counter30, values, keys, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, counter31, values, keys, &hits, h);\n+\n+\tk_slot30 = k_slot20, k_slot31 = k_slot21;\n+\tidx30 = idx20, idx31 = idx21;\n+\tcounter30 = counter20, counter31 = counter21;\n+\tbkt20 = bkt10, bkt21 = bkt11;\n+\thash20 = hash10, hash21 = hash11;\n+\tidx20 = idx10, idx21 = idx11;\n+\tlookup_stage2(idx20, hash20, bkt20, &k_slot20, &counter20, &next_mask,\n+\t\t\t&extra_hits_mask, next_bkts, key_store, h);\n+\tlookup_stage2(idx21, hash21, bkt21, &k_slot21, &counter21, &next_mask,\n+\t\t\t&extra_hits_mask, next_bkts, key_store, h);\n+\tlookup_stage3(idx30, k_slot30, counter30, values, keys, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, counter31, values, keys, &hits, h);\n+\n+\tk_slot30 = k_slot20, k_slot31 = k_slot21;\n+\tidx30 = idx20, idx31 = idx21;\n+\tcounter30 = counter20, counter31 = counter21;\n+\tlookup_stage3(idx30, k_slot30, counter30, values, keys, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, counter31, values, keys, &hits, h);\n+\n+\t/* handle extra_hits_mask */\n+\tnext_mask |= extra_hits_mask;\n+\n+\t/* ignore any items we have already found */\n+\tnext_mask &= ~hits;\n+\n+\tif (unlikely(next_mask)) {\n+\t\t/* run a single search for each remaining item */\n+\t\tdo {\n+\t\t\tunsigned idx = __builtin_ctzl(next_mask);\n+\t\t\trte_prefetch0(next_bkts[idx]);\n+\t\t\thits |= (uint64_t)(!rte_tshash_lookup_with_hash(h,\n+\t\t\t\t*hash_vals[idx], keys[idx], &values[idx])) << idx;\n+\t\t\tnext_mask &= ~(1llu << idx);\n+\t\t} while (next_mask);\n+\t}\n+\n+\t*hit_mask = hits;\n+\treturn __builtin_popcountl(hits);\n+}\n+\n+static inline int\n+rte_tshash_lookup_bulk(const struct rte_tshash *h,\n+\t\tuint64_t lookup_mask, const void * const *keys,\n+\t\tuintptr_t values[], uint64_t *hit_mask)\n+{\n+\tuint64_t hits = 0;\n+\tuint64_t next_mask = 0;\n+\tuint64_t extra_hits_mask = 0;\n+\tunsigned idx;\n+\n+\tconst struct rte_tshash_key *key_store = h->key_store;\n+\tconst struct rte_tshash_bucket *next_bkts[RTE_TSHASH_MAX_BURST];\n+\n+\tunsigned idx00, idx01, idx10, idx11, idx20, idx21, idx30, idx31;\n+\tconst struct rte_tshash_bucket *bkt10, *bkt11, *bkt20, *bkt21;\n+\tconst struct rte_tshash_key *k_slot20, *k_slot21, *k_slot30, *k_slot31;\n+\tuint64_t hash00, hash01, hash10, hash11, hash20, hash21;\n+\tuint8_t counter20, counter21, counter30, counter31;\n+\n+\tlookup_stage0_key(&idx00, &lookup_mask, &hash00, keys, h);\n+\tlookup_stage0_key(&idx01, &lookup_mask, &hash01, keys, h);\n+\n+\thash10 = hash00, hash11 = hash01;\n+\tidx10 = idx00, idx11 = idx01;\n+\tlookup_stage0_key(&idx00, &lookup_mask, &hash00, keys, h);\n+\tlookup_stage0_key(&idx01, &lookup_mask, &hash01, keys, h);\n+\tlookup_stage1_key(&hash10, &bkt10, h);\n+\tlookup_stage1_key(&hash11, &bkt11, h);\n+\n+\tbkt20 = bkt10, bkt21 = bkt11;\n+\thash20 = hash10, hash21 = hash11;\n+\tidx20 = idx10, idx21 = idx11;\n+\thash10 = hash00, hash11 = hash01;\n+\tidx10 = idx00, idx11 = idx01;\n+\n+\tlookup_stage0_key(&idx00, &lookup_mask, &hash00, keys, h);\n+\tlookup_stage0_key(&idx01, &lookup_mask, &hash01, keys, h);\n+\tlookup_stage1_key(&hash10, &bkt10, h);\n+\tlookup_stage1_key(&hash11, &bkt11, h);\n+\tlookup_stage2(idx20, hash20, bkt20, &k_slot20, &counter20,\n+\t\t\t&next_mask, &extra_hits_mask,\n+\t\t\tnext_bkts, key_store, h);\n+\tlookup_stage2(idx21, hash21, bkt21, &k_slot21, &counter21,\n+\t\t\t&next_mask, &extra_hits_mask,\n+\t\t\tnext_bkts, key_store, h);\n+\n+\twhile (lookup_mask) {\n+\t\tk_slot30 = k_slot20, k_slot31 = k_slot21;\n+\t\tidx30 = idx20, idx31 = idx21;\n+\t\tcounter30 = counter20, counter31 = counter21;\n+\t\tbkt20 = bkt10, bkt21 = bkt11;\n+\t\thash20 = hash10, hash21 = hash11;\n+\t\tidx20 = idx10, idx21 = idx11;\n+\t\thash10 = hash00, hash11 = hash01;\n+\t\tidx10 = idx00, idx11 = idx01;\n+\n+\t\tlookup_stage0_key(&idx00, &lookup_mask, &hash00, keys, h);\n+\t\tlookup_stage0_key(&idx01, &lookup_mask, &hash01, keys, h);\n+\t\tlookup_stage1_key(&hash10, &bkt10, h);\n+\t\tlookup_stage1_key(&hash11, &bkt11, h);\n+\t\tlookup_stage2(idx20, hash20, bkt20, &k_slot20, &counter20,\n+\t\t\t\t&next_mask, &extra_hits_mask, next_bkts,\n+\t\t\t\tkey_store, h);\n+\t\tlookup_stage2(idx21, hash21, bkt21, &k_slot21, &counter21,\n+\t\t\t\t&next_mask, &extra_hits_mask, next_bkts,\n+\t\t\t\tkey_store, h);\n+\t\tlookup_stage3(idx30, k_slot30, counter30, values, keys, &hits, h);\n+\t\tlookup_stage3(idx31, k_slot31, counter31, values, keys, &hits, h);\n+\t}\n+\n+\tk_slot30 = k_slot20, k_slot31 = k_slot21;\n+\tidx30 = idx20, idx31 = idx21;\n+\tcounter30 = counter20, counter31 = counter21;\n+\tbkt20 = bkt10, bkt21 = bkt11;\n+\thash20 = hash10, hash21 = hash11;\n+\tidx20 = idx10, idx21 = idx11;\n+\thash10 = hash00, hash11 = hash01;\n+\tidx10 = idx00, idx11 = idx01;\n+\tlookup_stage1_key(&hash10, &bkt10, h);\n+\tlookup_stage1_key(&hash11, &bkt11, h);\n+\tlookup_stage2(idx20, hash20, bkt20,\n+\t\t\t&k_slot20, &counter20, &next_mask, &extra_hits_mask,\n+\t\t\tnext_bkts, key_store, h);\n+\tlookup_stage2(idx21, hash21, bkt21,\n+\t\t\t&k_slot21, &counter21, &next_mask, &extra_hits_mask,\n+\t\t\tnext_bkts, key_store, h);\n+\tlookup_stage3(idx30, k_slot30, counter30, values, keys, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, counter31, values, keys, &hits, h);\n+\n+\tk_slot30 = k_slot20, k_slot31 = k_slot21;\n+\tidx30 = idx20, idx31 = idx21;\n+\tcounter30 = counter20, counter31 = counter21;\n+\tbkt20 = bkt10, bkt21 = bkt11;\n+\thash20 = hash10, hash21 = hash11;\n+\tidx20 = idx10, idx21 = idx11;\n+\tlookup_stage2(idx20, hash20, bkt20, &k_slot20, &counter20, &next_mask,\n+\t\t\t&extra_hits_mask, next_bkts, key_store, h);\n+\tlookup_stage2(idx21, hash21, bkt21, &k_slot21, &counter21, &next_mask,\n+\t\t\t&extra_hits_mask, next_bkts, key_store, h);\n+\tlookup_stage3(idx30, k_slot30, counter30, values, keys, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, counter31, values, keys, &hits, h);\n+\n+\tk_slot30 = k_slot20, k_slot31 = k_slot21;\n+\tidx30 = idx20, idx31 = idx21;\n+\tcounter30 = counter20, counter31 = counter21;\n+\tlookup_stage3(idx30, k_slot30, counter30, values, keys, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, counter31, values, keys, &hits, h);\n+\n+\t/* handle extra_hits_mask */\n+\tnext_mask |= extra_hits_mask;\n+\n+\t/* ignore any items we have already found */\n+\tnext_mask &= ~hits;\n+\n+\tif (unlikely(next_mask)) {\n+\t\t/* run a single search for each remaining item */\n+\t\tdo {\n+\t\t\tidx = __builtin_ctzl(next_mask);\n+\t\t\trte_prefetch0(next_bkts[idx]);\n+\t\t\thits |= (uint64_t)(!rte_tshash_lookup(h, keys[idx],\n+\t\t\t\t\t\t\t&values[idx])) << idx;\n+\t\t\tnext_mask &= ~(1llu << idx);\n+\t\t} while (next_mask);\n+\t}\n+\n+\t*hit_mask = hits;\n+\treturn __builtin_popcountl(hits);\n+}\n+\n+\n+#ifdef RTE_LIBRTE_THREAD_SAFE_HASH_STATS\n+static inline const struct rte_tshash_stats *\n+rte_tshash_get_stats(const struct rte_tshash *h)\n+{ return &h->stats; }\n+#endif\n+\n+\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+\n+#endif\ndiff --git a/lib/librte_tshash/rte_vector_jhash.h b/lib/librte_tshash/rte_vector_jhash.h\nnew file mode 100644\nindex 0000000..17b194e\n--- /dev/null\n+++ b/lib/librte_tshash/rte_vector_jhash.h\n@@ -0,0 +1,332 @@\n+/**\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+#ifndef _RTE_VJHASH_H\n+#define _RTE_VJHASH_H\n+\n+#ifndef RTE_LIBRTE_HASH\n+#error \"Need librte_hash enabled\"\n+#endif\n+\n+/**\n+ * @file\n+ *\n+ * jhash, vector versions functions.\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <stdint.h>\n+#include <x86intrin.h>\n+\n+#include <rte_jhash.h>\n+\n+#define __rte_jhash_mix4(a, b, c) do { \\\n+\t\ta = _mm_sub_epi32(a, b); a = _mm_sub_epi32(a, c); \\\n+\t\t\ta = _mm_xor_si128(a, _mm_srli_epi32(c, 13)); \\\n+\t\tb = _mm_sub_epi32(b, c); b = _mm_sub_epi32(b, a); \\\n+\t\t\tb = _mm_xor_si128(b, _mm_slli_epi32(a, 8)); \\\n+\t\tc = _mm_sub_epi32(c, a); c = _mm_sub_epi32(c, b); \\\n+\t\t\tc = _mm_xor_si128(c, _mm_srli_epi32(b, 13)); \\\n+\t\ta = _mm_sub_epi32(a, b); a = _mm_sub_epi32(a, c); \\\n+\t\t\ta = _mm_xor_si128(a, _mm_srli_epi32(c, 12)); \\\n+\t\tb = _mm_sub_epi32(b, c); b = _mm_sub_epi32(b, a); \\\n+\t\t\tb = _mm_xor_si128(b, _mm_slli_epi32(a, 16)); \\\n+\t\tc = _mm_sub_epi32(c, a); c = _mm_sub_epi32(c, b); \\\n+\t\t\tc = _mm_xor_si128(c, _mm_srli_epi32(b, 5)); \\\n+\t\ta = _mm_sub_epi32(a, b); a = _mm_sub_epi32(a, c); \\\n+\t\t\ta = _mm_xor_si128(a, _mm_srli_epi32(c, 3)); \\\n+\t\tb = _mm_sub_epi32(b, c); b = _mm_sub_epi32(b, a); \\\n+\t\t\tb = _mm_xor_si128(b, _mm_slli_epi32(a, 10)); \\\n+\t\tc = _mm_sub_epi32(c, a); c = _mm_sub_epi32(c, b); \\\n+\t\t\tc = _mm_xor_si128(c, _mm_srli_epi32(b, 15)); \\\n+} while (0)\n+\n+#define BURST 4\n+\n+static inline void\n+_jhash_do_burst(const void *key[], uint32_t key_length,\n+\t\tuint32_t initval, uint32_t results[])\n+{\n+\tuint32_t i = 0, len = key_length;\n+\tconst uint32_t **k32 = (void *)key;\n+\t__m128i a, b, c;\n+\t__m128i lens;\n+\n+\ta = b = _mm_set1_epi32(RTE_JHASH_GOLDEN_RATIO);\n+\tc = _mm_set1_epi32(initval);\n+\tlens = _mm_set1_epi32(key_length);\n+\n+\twhile (len >= 12) {\n+\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i+0], k32[2][i+0],\n+\t\t\t\tk32[1][i+0], k32[0][i+0]);\n+\t\tconst __m128i b1 = _mm_set_epi32(k32[3][i+1], k32[2][i+1],\n+\t\t\t\tk32[1][i+1], k32[0][i+1]);\n+\t\tconst __m128i c1 = _mm_set_epi32(k32[3][i+2], k32[2][i+2],\n+\t\t\t\tk32[1][i+2], k32[0][i+2]);\n+\n+\t\ta = _mm_add_epi32(a, a1);\n+\t\tb = _mm_add_epi32(b, b1);\n+\t\tc = _mm_add_epi32(c, c1);\n+\n+\t\t__rte_jhash_mix4(a, b, c);\n+\n+\t\tlen -= 12, i += 3;\n+\t}\n+\n+\tc = _mm_add_epi32(c, lens);\n+\n+\t/* now switch based on remaining bits */\n+\n+\tswitch (len) {\n+\tcase 1:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32((uint8_t)k32[3][i],\n+\t\t\t\t\t(uint8_t)k32[2][i],\n+\t\t\t\t\t(uint8_t)k32[1][i],\n+\t\t\t\t\t(uint8_t)k32[0][i]);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 2:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32((uint16_t)k32[3][i],\n+\t\t\t\t\t(uint16_t)k32[2][i],\n+\t\t\t\t\t(uint16_t)k32[1][i],\n+\t\t\t\t\t(uint16_t)k32[0][i]);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 3:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i] & 0xFFFFFF,\n+\t\t\t\t\tk32[2][i] & 0xFFFFFF,\n+\t\t\t\t\tk32[1][i] & 0xFFFFFF,\n+\t\t\t\t\tk32[0][i] & 0xFFFFFF);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 4:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i], k32[2][i],\n+\t\t\t\t\tk32[1][i], k32[0][i]);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 5:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i], k32[2][i],\n+\t\t\t\t\tk32[1][i], k32[0][i]);\n+\t\t\tconst __m128i b1 = _mm_set_epi32((uint8_t)k32[3][i+1],\n+\t\t\t\t\t(uint8_t)k32[2][i+1],\n+\t\t\t\t\t(uint8_t)k32[1][i+1],\n+\t\t\t\t\t(uint8_t)k32[0][i+1]);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t\tb = _mm_add_epi32(b, b1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 6:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i], k32[2][i],\n+\t\t\t\t\tk32[1][i], k32[0][i]);\n+\t\t\tconst __m128i b1 = _mm_set_epi32((uint16_t)k32[3][i+1],\n+\t\t\t\t\t(uint16_t)k32[2][i+1],\n+\t\t\t\t\t(uint16_t)k32[1][i+1],\n+\t\t\t\t\t(uint16_t)k32[0][i+1]);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t\tb = _mm_add_epi32(b, b1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 7:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i], k32[2][i],\n+\t\t\t\t\tk32[1][i], k32[0][i]);\n+\t\t\tconst __m128i b1 = _mm_set_epi32(k32[3][i+1] & 0xFFFFFF,\n+\t\t\t\t\tk32[2][i+1] & 0xFFFFFF,\n+\t\t\t\t\tk32[1][i+1] & 0xFFFFFF,\n+\t\t\t\t\tk32[0][i+1] & 0xFFFFFF);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t\tb = _mm_add_epi32(b, b1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 8:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i], k32[2][i],\n+\t\t\t\t\tk32[1][i], k32[0][i]);\n+\t\t\tconst __m128i b1 = _mm_set_epi32(k32[3][i+1], k32[2][i+1],\n+\t\t\t\t\tk32[1][i+1], k32[0][i+1]);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t\tb = _mm_add_epi32(b, b1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 9:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i], k32[2][i],\n+\t\t\t\t\tk32[1][i], k32[0][i]);\n+\t\t\tconst __m128i b1 = _mm_set_epi32(k32[3][i+1], k32[2][i+1],\n+\t\t\t\t\tk32[1][i+1], k32[0][i+1]);\n+\t\t\tconst __m128i c1 = _mm_set_epi32((k32[3][i+2] & 0xFF) << 8,\n+\t\t\t\t\t(k32[2][i+2] & 0xFF) << 8,\n+\t\t\t\t\t(k32[1][i+2] & 0xFF) << 8,\n+\t\t\t\t\t(k32[0][i+2] & 0xFF) << 8);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t\tb = _mm_add_epi32(b, b1);\n+\t\t\tc = _mm_add_epi32(c, c1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 10:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i], k32[2][i],\n+\t\t\t\t\tk32[1][i], k32[0][i]);\n+\t\t\tconst __m128i b1 = _mm_set_epi32(k32[3][i+1], k32[2][i+1],\n+\t\t\t\t\tk32[1][i+1], k32[0][i+1]);\n+\t\t\tconst __m128i c1 = _mm_set_epi32((k32[3][i+2] & 0xFFFF) << 8,\n+\t\t\t\t\t(k32[2][i+2] & 0xFFFF) << 8,\n+\t\t\t\t\t(k32[1][i+2] & 0xFFFF) << 8,\n+\t\t\t\t\t(k32[0][i+2] & 0xFFFF) << 8);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t\tb = _mm_add_epi32(b, b1);\n+\t\t\tc = _mm_add_epi32(c, c1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tcase 11:\n+\t\tdo {\n+\t\t\tconst __m128i a1 = _mm_set_epi32(k32[3][i], k32[2][i],\n+\t\t\t\t\tk32[1][i], k32[0][i]);\n+\t\t\tconst __m128i b1 = _mm_set_epi32(k32[3][i+1], k32[2][i+1],\n+\t\t\t\t\tk32[1][i+1], k32[0][i+1]);\n+\t\t\tconst __m128i c1 = _mm_set_epi32((k32[3][i+2] & 0xFFFFFF) << 8,\n+\t\t\t\t\t(k32[2][i+2] & 0xFFFFFF) << 8,\n+\t\t\t\t\t(k32[1][i+2] & 0xFFFFFF) << 8,\n+\t\t\t\t\t(k32[0][i+2] & 0xFFFFFF) << 8);\n+\t\t\ta = _mm_add_epi32(a, a1);\n+\t\t\tb = _mm_add_epi32(b, b1);\n+\t\t\tc = _mm_add_epi32(c, c1);\n+\t\t} while (0);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\t__rte_jhash_mix4(a, b, c);\n+\n+\t_mm_storeu_si128((__m128i *)results, c);\n+}\n+\n+static inline uint32_t\n+rte_jhash_multi(const void *key[], uint32_t num_keys, uint32_t key_length,\n+\t\tuint32_t initval, uint32_t results[])\n+{\n+\tuint32_t i;\n+\tfor (i = 0; i < (num_keys & ~(BURST-1)); i += BURST)\n+\t\t_jhash_do_burst(&key[i], key_length, initval, &results[i]);\n+\n+\tfor (; i < num_keys; i++)\n+\t\tresults[i] = rte_jhash(key[i], key_length, initval);\n+\treturn 0;\n+}\n+\n+static inline void\n+_jhash2_do_burst(const uint32_t *k, const size_t buf_len,\n+\t\tconst uint32_t key_len, const uint32_t initval, uint32_t results[])\n+{\n+\tconst uint32_t off0 = 0, off1 = buf_len,\n+\t\t\toff2 = buf_len * 2, off3 = buf_len * 3;\n+\tuint32_t len = key_len;\n+\t__m128i a, b, c;\n+\t__m128i lens;\n+\n+\ta = b = _mm_set1_epi32(RTE_JHASH_GOLDEN_RATIO);\n+\tc = _mm_set1_epi32(initval);\n+\tlens = _mm_set1_epi32(key_len * sizeof(*k));\n+\n+\twhile (len >= 3) {\n+\t\tconst __m128i a1 = _mm_set_epi32(k[off3], k[off2],\n+\t\t\t\tk[off1], k[off0]);\n+\t\tconst __m128i b1 = _mm_set_epi32(k[off3+1], k[off2+1],\n+\t\t\t\tk[off1+1], k[off0+1]);\n+\t\tconst __m128i c1 = _mm_set_epi32(k[off3+2], k[off2+2],\n+\t\t\t\tk[off1+2], k[off0+2]);\n+\n+\t\ta = _mm_add_epi32(a, a1);\n+\t\tb = _mm_add_epi32(b, b1);\n+\t\tc = _mm_add_epi32(c, c1);\n+\n+\t\t__rte_jhash_mix4(a, b, c);\n+\n+\t\tlen -= 3, k += 3;\n+\t}\n+\n+\tc = _mm_add_epi32(c, lens);\n+\n+\tswitch (len) {\n+\tcase 2: {\n+\t\tconst __m128i b1 = _mm_set_epi32(k[off3+1], k[off2+1],\n+\t\t\t\tk[off1+1], k[off0+1]);\n+\t\tb = _mm_add_epi32(b, b1);\n+\t}\n+\tcase 1: {\n+\t\tconst __m128i a1 = _mm_set_epi32(k[off3], k[off2],\n+\t\t\t\tk[off1], k[off0]);\n+\t\ta = _mm_add_epi32(a, a1);\n+\t}\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\t__rte_jhash_mix4(a, b, c);\n+\t_mm_storeu_si128((__m128i *)results, c);\n+}\n+\n+static inline uint32_t\n+rte_jhash2_multi(const uint32_t *key, size_t num_keys, size_t buf_len,\n+\t\tsize_t key_len, uint32_t initval, uint32_t results[])\n+{\n+\tuint32_t i;\n+\tfor (i = 0; i < (num_keys & ~(BURST-1)); i += BURST)\n+\t\t_jhash2_do_burst(&key[i*buf_len], buf_len, key_len, initval,\n+\t\t\t\t&results[i]);\n+\tfor (; i < num_keys; i++)\n+\t\tresults[i] = rte_jhash2(&key[i*buf_len], key_len, initval);\n+\treturn 0;\n+}\n+\n+\n+#undef BURST\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _RTE_VJHASH_H */\ndiff --git a/mk/rte.app.mk b/mk/rte.app.mk\nindex 34dff2a..dccd1e9 100644\n--- a/mk/rte.app.mk\n+++ b/mk/rte.app.mk\n@@ -97,6 +97,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_HASH),y)\n LDLIBS += -lrte_hash\n endif\n \n+ifeq ($(CONFIG_RTE_LIBRTE_THREAD_SAFE_HASH),y)\n+LDLIBS += -lrte_tshash\n+endif\n+\n ifeq ($(CONFIG_RTE_LIBRTE_LPM),y)\n LDLIBS += -lrte_lpm\n endif\n",
    "prefixes": [
        "dpdk-dev",
        "2/3"
    ]
}