get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 6313,
    "url": "https://patches.dpdk.org/api/patches/6313/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1436565467-13328-4-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": "<1436565467-13328-4-git-send-email-pablo.de.lara.guarch@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1436565467-13328-4-git-send-email-pablo.de.lara.guarch@intel.com",
    "date": "2015-07-10T21:57:43",
    "name": "[dpdk-dev,v5,3/7] hash: add new functionality to store data in hash table",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b3c82f0ecd0f2785140d65b7b4b8b4d483f3ca3e",
    "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/1436565467-13328-4-git-send-email-pablo.de.lara.guarch@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/6313/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/6313/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 57C70C484;\n\tFri, 10 Jul 2015 23:58:22 +0200 (CEST)",
            "from mga09.intel.com (mga09.intel.com [134.134.136.24])\n\tby dpdk.org (Postfix) with ESMTP id 55A21C412\n\tfor <dev@dpdk.org>; Fri, 10 Jul 2015 23:58:16 +0200 (CEST)",
            "from orsmga003.jf.intel.com ([10.7.209.27])\n\tby orsmga102.jf.intel.com with ESMTP; 10 Jul 2015 14:57:59 -0700",
            "from unknown ([10.252.9.115])\n\tby orsmga003.jf.intel.com with SMTP; 10 Jul 2015 14:57:57 -0700",
            "by  (sSMTP sendmail emulation); Fri, 10 Jul 2015 22:57:57 +0100"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.15,450,1432623600\"; d=\"scan'208\";a=\"603973950\"",
        "From": "Pablo de Lara <pablo.de.lara.guarch@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 10 Jul 2015 22:57:43 +0100",
        "Message-Id": "<1436565467-13328-4-git-send-email-pablo.de.lara.guarch@intel.com>",
        "X-Mailer": "git-send-email 2.4.5",
        "In-Reply-To": "<1436565467-13328-1-git-send-email-pablo.de.lara.guarch@intel.com>",
        "References": "<1436549064-5200-1-git-send-email-pablo.de.lara.guarch@intel.com>\n\t<1436565467-13328-1-git-send-email-pablo.de.lara.guarch@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v5 3/7] hash: add new functionality to store data\n\tin hash table",
        "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": "Usually hash tables not only store keys, but also data associated\nto them. In order to maintain the existing API, the old functions\nwill still return the index where the key was stored.\nThe new functions will return the data associated to that key.\nIn the case of the lookup_bulk function, it will return also\nthe number of entries found and a bitmask of which entries\nwere found.\n\nUnit tests have been updated to use these new functions.\n\nAs a final point, a flag has been added in rte_hash_parameters\nto indicate if there are new parameters for future versions,\nso there is no need to maintain multiple versions\nof the existing functions in the future.\n\nSigned-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>\n---\n app/test/test_hash_perf.c            | 254 +++++++++++++++++++++++++----------\n lib/librte_hash/rte_cuckoo_hash.c    | 193 ++++++++++++++++++++------\n lib/librte_hash/rte_hash.h           | 108 ++++++++++++++-\n lib/librte_hash/rte_hash_version.map |   6 +\n 4 files changed, 441 insertions(+), 120 deletions(-)",
    "diff": "diff --git a/app/test/test_hash_perf.c b/app/test/test_hash_perf.c\nindex b01b040..e09f45d 100644\n--- a/app/test/test_hash_perf.c\n+++ b/app/test/test_hash_perf.c\n@@ -55,6 +55,7 @@\n #define NUM_KEYSIZES 10\n #define NUM_SHUFFLES 10\n #define BURST_SIZE 16\n+#define DATA_MULTIPLIER 13 /* Used for storing data */\n \n enum operations {\n \tADD = 0,\n@@ -83,7 +84,7 @@ struct rte_hash *h[NUM_KEYSIZES];\n uint8_t slot_taken[MAX_ENTRIES];\n \n /* Array to store number of cycles per operation */\n-uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS][2];\n+uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS][2][2];\n \n /* Array to store all input keys */\n uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE];\n@@ -106,11 +107,16 @@ static struct rte_hash_parameters ut_params = {\n };\n \n static int\n-create_table(unsigned table_index)\n+create_table(unsigned with_data, unsigned table_index)\n {\n \tchar name[RTE_HASH_NAMESIZE];\n \n-\tsprintf(name, \"test_hash%d\", hashtest_key_lens[table_index]);\n+\tif (with_data)\n+\t\t/* Table will store 8-byte data */\n+\t\tsprintf(name, \"test_hash%d_data\", hashtest_key_lens[table_index]);\n+\telse\n+\t\tsprintf(name, \"test_hash%d\", hashtest_key_lens[table_index]);\n+\n \tut_params.name = name;\n \tut_params.key_len = hashtest_key_lens[table_index];\n \tut_params.socket_id = rte_socket_id();\n@@ -234,6 +240,7 @@ get_input_keys(unsigned with_pushes, unsigned table_index)\n \t\t\telse {\n \t\t\t\t/* Store the returned position and mark slot as taken */\n \t\t\t\tslot_taken[ret] = 1;\n+\t\t\t\tpositions[i] = ret;\n \t\t\t\tbuckets[bucket_idx]++;\n \t\t\t\tsuccess = 1;\n \t\t\t\ti++;\n@@ -249,54 +256,116 @@ get_input_keys(unsigned with_pushes, unsigned table_index)\n }\n \n static int\n-timed_adds(unsigned with_hash, unsigned table_index)\n+timed_adds(unsigned with_hash, unsigned with_data, unsigned table_index)\n {\n \tunsigned i;\n \tconst uint64_t start_tsc = rte_rdtsc();\n+\tuintptr_t data;\n \tint32_t ret;\n \n \tfor (i = 0; i < KEYS_TO_ADD; i++) {\n-\t\tif (with_hash)\n+\t\tdata = (uint64_t) signatures[i] * DATA_MULTIPLIER;\n+\t\tif (with_hash && with_data) {\n+\t\t\tret = rte_hash_add_key_with_hash_data(h[table_index],\n+\t\t\t\t\t\t(const void *) keys[i],\n+\t\t\t\t\t\tsignatures[i], data);\n+\t\t\tif (ret < 0) {\n+\t\t\t\tprintf(\"Failed to add key number %u\\n\", ret);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t} else if (with_hash && !with_data) {\n \t\t\tret = rte_hash_add_key_with_hash(h[table_index],\n \t\t\t\t\t\t(const void *) keys[i],\n \t\t\t\t\t\tsignatures[i]);\n-\t\telse\n+\t\t\tif (ret >= 0)\n+\t\t\t\tpositions[i] = ret;\n+\t\t\telse {\n+\t\t\t\tprintf(\"Failed to add key number %u\\n\", ret);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t} else if (!with_hash && with_data) {\n+\t\t\tret = rte_hash_add_key_data(h[table_index],\n+\t\t\t\t\t\t(const void *) keys[i],\n+\t\t\t\t\t\tdata);\n+\t\t\tif (ret < 0) {\n+\t\t\t\tprintf(\"Failed to add key number %u\\n\", ret);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t} else {\n \t\t\tret = rte_hash_add_key(h[table_index], keys[i]);\n-\n-\t\tif (ret >= 0)\n-\t\t\tpositions[i] = ret;\n-\t\telse {\n-\t\t\tprintf(\"Failed to add key number %u\\n\", ret);\n-\t\t\treturn -1;\n+\t\t\tif (ret >= 0)\n+\t\t\t\tpositions[i] = ret;\n+\t\t\telse {\n+\t\t\t\tprintf(\"Failed to add key number %u\\n\", ret);\n+\t\t\t\treturn -1;\n+\t\t\t}\n \t\t}\n \t}\n \n \tconst uint64_t end_tsc = rte_rdtsc();\n \tconst uint64_t time_taken = end_tsc - start_tsc;\n \n-\tcycles[table_index][ADD][with_hash] = time_taken/KEYS_TO_ADD;\n+\tcycles[table_index][ADD][with_hash][with_data] = time_taken/KEYS_TO_ADD;\n+\n \treturn 0;\n }\n \n static int\n-timed_lookups(unsigned with_hash, unsigned table_index)\n+timed_lookups(unsigned with_hash, unsigned with_data, unsigned table_index)\n {\n \tunsigned i, j;\n \tconst uint64_t start_tsc = rte_rdtsc();\n+\tuintptr_t ret_data;\n+\tuintptr_t expected_data;\n \tint32_t ret;\n \n \tfor (i = 0; i < NUM_LOOKUPS/KEYS_TO_ADD; i++) {\n \t\tfor (j = 0; j < KEYS_TO_ADD; j++) {\n-\t\t\tif (with_hash)\n+\t\t\tif (with_hash && with_data) {\n+\t\t\t\tret = rte_hash_lookup_with_hash_data(h[table_index],\n+\t\t\t\t\t\t\t(const void *) keys[j],\n+\t\t\t\t\t\t\tsignatures[j], &ret_data);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\tprintf(\"Key number %u was not found\\n\", j);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t\texpected_data = (uint64_t) signatures[j] * DATA_MULTIPLIER;\n+\t\t\t\tif (ret_data != expected_data) {\n+\t\t\t\t\tprintf(\"Data returned for key number %u is %\"PRIxPTR\",\"\n+\t\t\t\t\t       \" but should be %\"PRIxPTR\"\\n\", j, ret_data,\n+\t\t\t\t\t\texpected_data);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t} else if (with_hash && !with_data) {\n \t\t\t\tret = rte_hash_lookup_with_hash(h[table_index],\n \t\t\t\t\t\t\t(const void *) keys[j],\n \t\t\t\t\t\t\tsignatures[j]);\n-\t\t\telse\n+\t\t\t\tif (ret < 0 || ret != positions[j]) {\n+\t\t\t\t\tprintf(\"Key looked up in %d, should be in %d\\n\",\n+\t\t\t\t\t\tret, positions[j]);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t} else if (!with_hash && with_data) {\n+\t\t\t\tret = rte_hash_lookup_data(h[table_index],\n+\t\t\t\t\t\t\t(const void *) keys[j], &ret_data);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\tprintf(\"Key number %u was not found\\n\", j);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t\texpected_data = (uint64_t) signatures[j] * DATA_MULTIPLIER;\n+\t\t\t\tif (ret_data != expected_data) {\n+\t\t\t\t\tprintf(\"Data returned for key number %u is %\"PRIxPTR\",\"\n+\t\t\t\t\t       \" but should be %\"PRIxPTR\"\\n\", j, ret_data,\n+\t\t\t\t\t\texpected_data);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t} else {\n \t\t\t\tret = rte_hash_lookup(h[table_index], keys[j]);\n-\t\t\tif (ret < 0 || ret != positions[j]) {\n-\t\t\t\tprintf(\"Key looked up in %d, should be in %d\\n\",\n-\t\t\t\t\tret, positions[j]);\n-\t\t\t\treturn -1;\n+\t\t\t\tif (ret < 0 || ret != positions[j]) {\n+\t\t\t\t\tprintf(\"Key looked up in %d, should be in %d\\n\",\n+\t\t\t\t\t\tret, positions[j]);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n \t\t\t}\n \t\t}\n \t}\n@@ -304,34 +373,66 @@ timed_lookups(unsigned with_hash, unsigned table_index)\n \tconst uint64_t end_tsc = rte_rdtsc();\n \tconst uint64_t time_taken = end_tsc - start_tsc;\n \n-\tcycles[table_index][LOOKUP][with_hash] = time_taken/NUM_LOOKUPS;\n+\tcycles[table_index][LOOKUP][with_hash][with_data] = time_taken/NUM_LOOKUPS;\n \n \treturn 0;\n }\n \n static int\n-timed_lookups_multi(unsigned table_index)\n+timed_lookups_multi(unsigned with_data, unsigned table_index)\n {\n \tunsigned i, j, k;\n \tint32_t positions_burst[BURST_SIZE];\n \tconst void *keys_burst[BURST_SIZE];\n+\tuintptr_t expected_data[BURST_SIZE];\n+\tuintptr_t ret_data[BURST_SIZE];\n+\tuint64_t hit_mask;\n+\tint ret;\n+\n \tconst uint64_t start_tsc = rte_rdtsc();\n \n \tfor (i = 0; i < NUM_LOOKUPS/KEYS_TO_ADD; i++) {\n \t\tfor (j = 0; j < KEYS_TO_ADD/BURST_SIZE; j++) {\n \t\t\tfor (k = 0; k < BURST_SIZE; k++)\n \t\t\t\tkeys_burst[k] = keys[j * BURST_SIZE + k];\n-\n-\t\t\trte_hash_lookup_bulk(h[table_index],\n+\t\t\tif (with_data) {\n+\t\t\t\tret = rte_hash_lookup_bulk_data(h[table_index],\n+\t\t\t\t\t(const void **) keys_burst,\n+\t\t\t\t\tBURST_SIZE,\n+\t\t\t\t\t&hit_mask,\n+\t\t\t\t\tret_data);\n+\t\t\t\tif (ret != BURST_SIZE) {\n+\t\t\t\t\tprintf(\"Expect to find %u keys,\"\n+\t\t\t\t\t       \" but found %d\\n\", BURST_SIZE, ret);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t\tfor (k = 0; k < BURST_SIZE; k++) {\n+\t\t\t\t\tif ((hit_mask & (1ULL << k))  == 0) {\n+\t\t\t\t\t\tprintf(\"Key number %u not found\\n\",\n+\t\t\t\t\t\t\tj * BURST_SIZE + k);\n+\t\t\t\t\t\treturn -1;\n+\t\t\t\t\t}\n+\t\t\t\t\texpected_data[k] = (uint64_t)signatures[j * BURST_SIZE + k]\n+\t\t\t\t\t\t\t\t* DATA_MULTIPLIER;\n+\t\t\t\t\tif (ret_data[k] != expected_data[k]) {\n+\t\t\t\t\t\tprintf(\"Data returned for key number %u is %\"PRIxPTR\",\"\n+\t\t\t\t\t\t       \" but should be %\"PRIxPTR\"\\n\", j * BURST_SIZE + k,\n+\t\t\t\t\t\t\tret_data[k], expected_data[k]);\n+\t\t\t\t\t\treturn -1;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\trte_hash_lookup_bulk(h[table_index],\n \t\t\t\t\t\t(const void **) keys_burst,\n \t\t\t\t\t\tBURST_SIZE,\n \t\t\t\t\t\tpositions_burst);\n-\t\t\tfor (k = 0; k < BURST_SIZE; k++) {\n-\t\t\t\tif (positions_burst[k] != positions[j * BURST_SIZE + k]) {\n-\t\t\t\t\tprintf(\"Key looked up in %d, should be in %d\\n\",\n-\t\t\t\t\t\tpositions_burst[k],\n-\t\t\t\t\t\tpositions[j * BURST_SIZE + k]);\n-\t\t\t\t\treturn -1;\n+\t\t\t\tfor (k = 0; k < BURST_SIZE; k++) {\n+\t\t\t\t\tif (positions_burst[k] != positions[j * BURST_SIZE + k]) {\n+\t\t\t\t\t\tprintf(\"Key looked up in %d, should be in %d\\n\",\n+\t\t\t\t\t\t\tpositions_burst[k],\n+\t\t\t\t\t\t\tpositions[j * BURST_SIZE + k]);\n+\t\t\t\t\t\treturn -1;\n+\t\t\t\t\t}\n \t\t\t\t}\n \t\t\t}\n \t\t}\n@@ -340,19 +441,20 @@ timed_lookups_multi(unsigned table_index)\n \tconst uint64_t end_tsc = rte_rdtsc();\n \tconst uint64_t time_taken = end_tsc - start_tsc;\n \n-\tcycles[table_index][LOOKUP_MULTI][0] = time_taken/NUM_LOOKUPS;\n+\tcycles[table_index][LOOKUP_MULTI][0][with_data] = time_taken/NUM_LOOKUPS;\n \n \treturn 0;\n }\n \n static int\n-timed_deletes(unsigned with_hash, unsigned table_index)\n+timed_deletes(unsigned with_hash, unsigned with_data, unsigned table_index)\n {\n \tunsigned i;\n \tconst uint64_t start_tsc = rte_rdtsc();\n \tint32_t ret;\n \n \tfor (i = 0; i < KEYS_TO_ADD; i++) {\n+\t\t/* There are no delete functions with data, so just call two functions */\n \t\tif (with_hash)\n \t\t\tret = rte_hash_del_key_with_hash(h[table_index],\n \t\t\t\t\t\t\t(const void *) keys[i],\n@@ -371,7 +473,7 @@ timed_deletes(unsigned with_hash, unsigned table_index)\n \tconst uint64_t end_tsc = rte_rdtsc();\n \tconst uint64_t time_taken = end_tsc - start_tsc;\n \n-\tcycles[table_index][DELETE][with_hash] = time_taken/KEYS_TO_ADD;\n+\tcycles[table_index][DELETE][with_hash][with_data] = time_taken/KEYS_TO_ADD;\n \n \treturn 0;\n }\n@@ -391,62 +493,67 @@ reset_table(unsigned table_index)\n static int\n run_all_tbl_perf_tests(unsigned with_pushes)\n {\n-\tunsigned i, j, with_hash;\n+\tunsigned i, j, with_data, with_hash;\n \n \tprintf(\"Measuring performance, please wait\");\n \tfflush(stdout);\n-\tfor (i = 0; i < NUM_KEYSIZES; i++) {\n-\t\tif (create_table(i) < 0)\n-\t\t\treturn -1;\n \n-\t\tif (get_input_keys(with_pushes, i) < 0)\n-\t\t\treturn -1;\n-\t\tfor (with_hash = 0; with_hash <= 1; with_hash++) {\n-\t\t\tif (timed_adds(with_hash, i) < 0)\n+\tfor (with_data = 0; with_data <= 1; with_data++) {\n+\t\tfor (i = 0; i < NUM_KEYSIZES; i++) {\n+\t\t\tif (create_table(with_data, i) < 0)\n \t\t\t\treturn -1;\n \n-\t\t\tfor (j = 0; j < NUM_SHUFFLES; j++)\n-\t\t\t\tshuffle_input_keys(i);\n-\n-\t\t\tif (timed_lookups(with_hash, i) < 0)\n+\t\t\tif (get_input_keys(with_pushes, i) < 0)\n \t\t\t\treturn -1;\n+\t\t\tfor (with_hash = 0; with_hash <= 1; with_hash++) {\n+\t\t\t\tif (timed_adds(with_hash, with_data, i) < 0)\n+\t\t\t\t\treturn -1;\n \n-\t\t\tif (timed_lookups_multi(i) < 0)\n-\t\t\t\treturn -1;\n+\t\t\t\tfor (j = 0; j < NUM_SHUFFLES; j++)\n+\t\t\t\t\tshuffle_input_keys(i);\n \n-\t\t\tif (timed_deletes(with_hash, i) < 0)\n-\t\t\t\treturn -1;\n+\t\t\t\tif (timed_lookups(with_hash, with_data, i) < 0)\n+\t\t\t\t\treturn -1;\n \n-\t\t\treset_table(i);\n+\t\t\t\tif (timed_lookups_multi(with_data, i) < 0)\n+\t\t\t\t\treturn -1;\n \n-\t\t\t/* Print a dot to show progress on operations */\n-\t\t\tprintf(\".\");\n-\t\t\tfflush(stdout);\n-\t\t}\n+\t\t\t\tif (timed_deletes(with_hash, with_data, i) < 0)\n+\t\t\t\t\treturn -1;\n \n-\t\tfree_table(i);\n+\t\t\t\t/* Print a dot to show progress on operations */\n+\t\t\t\tprintf(\".\");\n+\t\t\t\tfflush(stdout);\n+\n+\t\t\t\treset_table(i);\n+\t\t\t}\n+\t\t\tfree_table(i);\n+\t\t}\n \t}\n+\n \tprintf(\"\\nResults (in CPU cycles/operation)\\n\");\n-\tprintf(\"---------------------------------\\n\");\n-\tprintf(\"\\nWithout pre-computed hash values\\n\");\n-\tprintf(\"\\n%-18s%-18s%-18s%-18s%-18s\\n\",\n-\t\t\t\"Keysize\", \"Add\", \"Lookup\", \"Lookup_bulk\", \"Delete\");\n-\tfor (i = 0; i < NUM_KEYSIZES; i++) {\n-\t\tprintf(\"%-18d\", hashtest_key_lens[i]);\n-\t\tfor (j = 0; j < NUM_OPERATIONS; j++)\n-\t\t\tprintf(\"%-18\"PRIu64, cycles[i][j][0]);\n-\t\tprintf(\"\\n\");\n-\t}\n-\tprintf(\"\\nWith pre-computed hash values\\n\");\n-\tprintf(\"\\n%-18s%-18s%-18s%-18s%-18s\\n\",\n+\tprintf(\"-----------------------------------\\n\");\n+\tfor (with_data = 0; with_data <= 1; with_data++) {\n+\t\tif (with_data)\n+\t\t\tprintf(\"\\n Operations with 8-byte data\\n\");\n+\t\telse\n+\t\t\tprintf(\"\\n Operations without data\\n\");\n+\t\tfor (with_hash = 0; with_hash <= 1; with_hash++) {\n+\t\t\tif (with_hash)\n+\t\t\t\tprintf(\"\\nWith pre-computed hash values\\n\");\n+\t\t\telse\n+\t\t\t\tprintf(\"\\nWithout pre-computed hash values\\n\");\n+\n+\t\t\tprintf(\"\\n%-18s%-18s%-18s%-18s%-18s\\n\",\n \t\t\t\"Keysize\", \"Add\", \"Lookup\", \"Lookup_bulk\", \"Delete\");\n-\tfor (i = 0; i < NUM_KEYSIZES; i++) {\n-\t\tprintf(\"%-18d\", hashtest_key_lens[i]);\n-\t\tfor (j = 0; j < NUM_OPERATIONS; j++)\n-\t\t\tprintf(\"%-18\"PRIu64, cycles[i][j][1]);\n-\t\tprintf(\"\\n\");\n+\t\t\tfor (i = 0; i < NUM_KEYSIZES; i++) {\n+\t\t\t\tprintf(\"%-18d\", hashtest_key_lens[i]);\n+\t\t\t\tfor (j = 0; j < NUM_OPERATIONS; j++)\n+\t\t\t\t\tprintf(\"%-18\"PRIu64, cycles[i][j][with_hash][with_data]);\n+\t\t\t\tprintf(\"\\n\");\n+\t\t\t}\n+\t\t}\n \t}\n-\n \treturn 0;\n }\n \n@@ -546,7 +653,6 @@ test_hash_perf(void)\n \t\tif (run_all_tbl_perf_tests(with_pushes) < 0)\n \t\t\treturn -1;\n \t}\n-\n \tif (fbk_hash_perf_test() < 0)\n \t\treturn -1;\n \ndiff --git a/lib/librte_hash/rte_cuckoo_hash.c b/lib/librte_hash/rte_cuckoo_hash.c\nindex 15c5da5..5777036 100644\n--- a/lib/librte_hash/rte_cuckoo_hash.c\n+++ b/lib/librte_hash/rte_cuckoo_hash.c\n@@ -56,6 +56,7 @@\n #include <rte_rwlock.h>\n #include <rte_spinlock.h>\n #include <rte_ring.h>\n+#include <rte_compat.h>\n \n #include \"rte_hash.h\"\n \n@@ -90,6 +91,8 @@ EAL_REGISTER_TAILQ(rte_hash_tailq)\n \n #define NULL_SIGNATURE\t\t\t0\n \n+#define KEY_ALIGNMENT\t\t\t16\n+\n typedef int (*rte_hash_cmp_eq_t)(const void *key1, const void *key2, size_t key_len);\n static int rte_hash_k16_cmp_eq(const void *key1, const void *key2, size_t key_len);\n static int rte_hash_k32_cmp_eq(const void *key1, const void *key2, size_t key_len);\n@@ -132,6 +135,16 @@ struct rte_hash_signatures {\n \t};\n };\n \n+/* Structure that stores key-value pair */\n+struct rte_hash_key {\n+\tunion {\n+\t\tuintptr_t idata;\n+\t\tvoid *pdata;\n+\t};\n+\t/* Variable key size */\n+\tchar key[];\n+} __attribute__((aligned(KEY_ALIGNMENT)));\n+\n /** Bucket structure */\n struct rte_hash_bucket {\n \tstruct rte_hash_signatures signatures[RTE_HASH_BUCKET_ENTRIES];\n@@ -227,7 +240,8 @@ rte_hash_create(const struct rte_hash_parameters *params)\n \t\tgoto err;\n \t}\n \n-\tconst uint32_t key_entry_size = params->key_len;\n+\tconst uint32_t key_entry_size = sizeof(struct rte_hash_key) + params->key_len;\n+\n \t/* Store all keys and leave the first entry as a dummy entry for lookup_bulk */\n \tconst uint64_t key_tbl_size = key_entry_size * (params->entries + 1);\n \n@@ -461,13 +475,13 @@ make_space_bucket(const struct rte_hash *h, struct rte_hash_bucket *bkt)\n \n static inline int32_t\n __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,\n-\t\t\t\t\t\thash_sig_t sig)\n+\t\t\t\t\t\thash_sig_t sig, uintptr_t data)\n {\n \thash_sig_t alt_hash;\n \tuint32_t prim_bucket_idx, sec_bucket_idx;\n \tunsigned i;\n \tstruct rte_hash_bucket *prim_bkt, *sec_bkt;\n-\tvoid *new_k, *k, *keys = h->key_store;\n+\tstruct rte_hash_key *new_k, *k, *keys = h->key_store;\n \tvoid *slot_id;\n \tuint32_t new_idx;\n \tint ret;\n@@ -492,9 +506,12 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,\n \tfor (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {\n \t\tif (prim_bkt->signatures[i].current == sig &&\n \t\t\t\tprim_bkt->signatures[i].alt == alt_hash)  {\n-\t\t\tk = (char *)keys + prim_bkt->key_idx[i] * h->key_entry_size;\n-\t\t\tif (h->rte_hash_cmp_eq(key, k, h->key_len) == 0) {\n+\t\t\tk = (struct rte_hash_key *) ((char *)keys +\n+\t\t\t\t\tprim_bkt->key_idx[i] * h->key_entry_size);\n+\t\t\tif (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {\n \t\t\t\trte_ring_sp_enqueue(h->free_slots, &slot_id);\n+\t\t\t\t/* Update data */\n+\t\t\t\tk->idata = data;\n \t\t\t\t/*\n \t\t\t\t * Return index where key is stored,\n \t\t\t\t * substracting the first dummy index\n@@ -508,9 +525,12 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,\n \tfor (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {\n \t\tif (sec_bkt->signatures[i].alt == sig &&\n \t\t\t\tsec_bkt->signatures[i].current == alt_hash)  {\n-\t\t\tk = (char *)keys + sec_bkt->key_idx[i] * h->key_entry_size;\n-\t\t\tif (h->rte_hash_cmp_eq(key, k, h->key_len) == 0) {\n+\t\t\tk = (struct rte_hash_key *) ((char *)keys +\n+\t\t\t\t\tsec_bkt->key_idx[i] * h->key_entry_size);\n+\t\t\tif (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {\n \t\t\t\trte_ring_sp_enqueue(h->free_slots, &slot_id);\n+\t\t\t\t/* Update data */\n+\t\t\t\tk->idata = data;\n \t\t\t\t/*\n \t\t\t\t * Return index where key is stored,\n \t\t\t\t * substracting the first dummy index\n@@ -521,7 +541,8 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,\n \t}\n \n \t/* Copy key */\n-\trte_memcpy(new_k, key, h->key_len);\n+\trte_memcpy(new_k->key, key, h->key_len);\n+\tnew_k->idata = data;\n \n \t/* Insert new entry is there is room in the primary bucket */\n \tfor (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {\n@@ -561,25 +582,52 @@ rte_hash_add_key_with_hash(const struct rte_hash *h,\n \t\t\tconst void *key, hash_sig_t sig)\n {\n \tRETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);\n-\treturn __rte_hash_add_key_with_hash(h, key, sig);\n+\treturn __rte_hash_add_key_with_hash(h, key, sig, 0);\n }\n \n int32_t\n rte_hash_add_key(const struct rte_hash *h, const void *key)\n {\n \tRETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);\n-\treturn __rte_hash_add_key_with_hash(h, key, rte_hash_hash(h, key));\n+\treturn __rte_hash_add_key_with_hash(h, key, rte_hash_hash(h, key), 0);\n+}\n+\n+int\n+rte_hash_add_key_with_hash_data(const struct rte_hash *h,\n+\t\t\tconst void *key, hash_sig_t sig, uintptr_t data)\n+{\n+\tint ret;\n+\n+\tRETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);\n+\tret = __rte_hash_add_key_with_hash(h, key, sig, data);\n+\tif (ret >= 0)\n+\t\treturn 0;\n+\telse\n+\t\treturn ret;\n }\n \n+int\n+rte_hash_add_key_data(const struct rte_hash *h, const void *key, uintptr_t data)\n+{\n+\tint ret;\n+\n+\tRETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);\n+\n+\tret = __rte_hash_add_key_with_hash(h, key, rte_hash_hash(h, key), data);\n+\tif (ret >= 0)\n+\t\treturn 0;\n+\telse\n+\t\treturn ret;\n+}\n static inline int32_t\n __rte_hash_lookup_with_hash(const struct rte_hash *h, const void *key,\n-\t\t\t\t\thash_sig_t sig)\n+\t\t\t\t\thash_sig_t sig, uintptr_t *data)\n {\n \tuint32_t bucket_idx;\n \thash_sig_t alt_hash;\n \tunsigned i;\n \tstruct rte_hash_bucket *bkt;\n-\tvoid *k, *keys = h->key_store;\n+\tstruct rte_hash_key *k, *keys = h->key_store;\n \n \tbucket_idx = sig & h->bucket_bitmask;\n \tbkt = &h->buckets[bucket_idx];\n@@ -588,13 +636,17 @@ __rte_hash_lookup_with_hash(const struct rte_hash *h, const void *key,\n \tfor (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {\n \t\tif (bkt->signatures[i].current == sig &&\n \t\t\t\tbkt->signatures[i].sig != NULL_SIGNATURE) {\n-\t\t\tk = (char *)keys + bkt->key_idx[i] * h->key_entry_size;\n-\t\t\tif (h->rte_hash_cmp_eq(key, k, h->key_len) == 0)\n+\t\t\tk = (struct rte_hash_key *) ((char *)keys +\n+\t\t\t\t\tbkt->key_idx[i] * h->key_entry_size);\n+\t\t\tif (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {\n+\t\t\t\tif (data != NULL)\n+\t\t\t\t\t*data = k->idata;\n \t\t\t\t/*\n \t\t\t\t * Return index where key is stored,\n \t\t\t\t * substracting the first dummy index\n \t\t\t\t */\n \t\t\t\treturn (bkt->key_idx[i] - 1);\n+\t\t\t}\n \t\t}\n \t}\n \n@@ -607,13 +659,17 @@ __rte_hash_lookup_with_hash(const struct rte_hash *h, const void *key,\n \tfor (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {\n \t\tif (bkt->signatures[i].current == alt_hash &&\n \t\t\t\tbkt->signatures[i].alt == sig) {\n-\t\t\tk = (char *)keys + bkt->key_idx[i] * h->key_entry_size;\n-\t\t\tif (h->rte_hash_cmp_eq(key, k, h->key_len) == 0)\n+\t\t\tk = (struct rte_hash_key *) ((char *)keys +\n+\t\t\t\t\tbkt->key_idx[i] * h->key_entry_size);\n+\t\t\tif (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {\n+\t\t\t\tif (data != NULL)\n+\t\t\t\t\t*data = k->idata;\n \t\t\t\t/*\n \t\t\t\t * Return index where key is stored,\n \t\t\t\t * substracting the first dummy index\n \t\t\t\t */\n \t\t\t\treturn (bkt->key_idx[i] - 1);\n+\t\t\t}\n \t\t}\n \t}\n \n@@ -625,14 +681,29 @@ rte_hash_lookup_with_hash(const struct rte_hash *h,\n \t\t\tconst void *key, hash_sig_t sig)\n {\n \tRETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);\n-\treturn __rte_hash_lookup_with_hash(h, key, sig);\n+\treturn __rte_hash_lookup_with_hash(h, key, sig, NULL);\n }\n \n int32_t\n rte_hash_lookup(const struct rte_hash *h, const void *key)\n {\n \tRETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);\n-\treturn __rte_hash_lookup_with_hash(h, key, rte_hash_hash(h, key));\n+\treturn __rte_hash_lookup_with_hash(h, key, rte_hash_hash(h, key), NULL);\n+}\n+\n+int\n+rte_hash_lookup_with_hash_data(const struct rte_hash *h,\n+\t\t\tconst void *key, hash_sig_t sig, uintptr_t *data)\n+{\n+\tRETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);\n+\treturn __rte_hash_lookup_with_hash(h, key, sig, data);\n+}\n+\n+int\n+rte_hash_lookup_data(const struct rte_hash *h, const void *key, uintptr_t *data)\n+{\n+\tRETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL);\n+\treturn __rte_hash_lookup_with_hash(h, key, rte_hash_hash(h, key), data);\n }\n \n static inline int32_t\n@@ -643,7 +714,7 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,\n \thash_sig_t alt_hash;\n \tunsigned i;\n \tstruct rte_hash_bucket *bkt;\n-\tvoid *k, *keys = h->key_store;\n+\tstruct rte_hash_key *k, *keys = h->key_store;\n \n \tbucket_idx = sig & h->bucket_bitmask;\n \tbkt = &h->buckets[bucket_idx];\n@@ -652,8 +723,9 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,\n \tfor (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {\n \t\tif (bkt->signatures[i].current == sig &&\n \t\t\t\tbkt->signatures[i].sig != NULL_SIGNATURE) {\n-\t\t\tk = (char *)keys + bkt->key_idx[i] * h->key_entry_size;\n-\t\t\tif (h->rte_hash_cmp_eq(key, k, h->key_len) == 0) {\n+\t\t\tk = (struct rte_hash_key *) ((char *)keys +\n+\t\t\t\t\tbkt->key_idx[i] * h->key_entry_size);\n+\t\t\tif (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {\n \t\t\t\tbkt->signatures[i].sig = NULL_SIGNATURE;\n \t\t\t\trte_ring_sp_enqueue(h->free_slots,\n \t\t\t\t\t\t(void *)((uintptr_t)bkt->key_idx[i]));\n@@ -675,8 +747,9 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,\n \tfor (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {\n \t\tif (bkt->signatures[i].current == alt_hash &&\n \t\t\t\tbkt->signatures[i].sig != NULL_SIGNATURE) {\n-\t\t\tk = (char *)keys + bkt->key_idx[i] * h->key_entry_size;\n-\t\t\tif (h->rte_hash_cmp_eq(key, k, h->key_len) == 0) {\n+\t\t\tk = (struct rte_hash_key *) ((char *)keys +\n+\t\t\t\t\tbkt->key_idx[i] * h->key_entry_size);\n+\t\t\tif (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {\n \t\t\t\tbkt->signatures[i].sig = NULL_SIGNATURE;\n \t\t\t\trte_ring_sp_enqueue(h->free_slots,\n \t\t\t\t\t\t(void *)((uintptr_t)bkt->key_idx[i]));\n@@ -750,7 +823,7 @@ static inline void\n lookup_stage2(unsigned idx, hash_sig_t prim_hash, hash_sig_t sec_hash,\n \t\tconst struct rte_hash_bucket *prim_bkt,\n \t\tconst struct rte_hash_bucket *sec_bkt,\n-\t\tconst void **key_slot, int32_t *positions,\n+\t\tconst struct rte_hash_key **key_slot, int32_t *positions,\n \t\tuint64_t *extra_hits_mask, const void *keys,\n \t\tconst struct rte_hash *h)\n {\n@@ -770,7 +843,8 @@ lookup_stage2(unsigned idx, hash_sig_t prim_hash, hash_sig_t sec_hash,\n \n \ttotal_hash_matches = (prim_hash_matches |\n \t\t\t\t(sec_hash_matches << (RTE_HASH_BUCKET_ENTRIES + 1)));\n-\t*key_slot = (const char *)keys + key_idx * h->key_entry_size;\n+\t*key_slot = (const struct rte_hash_key *) ((const char *)keys +\n+\t\t\t\t\tkey_idx * h->key_entry_size);\n \n \trte_prefetch0(*key_slot);\n \t/*\n@@ -784,26 +858,31 @@ lookup_stage2(unsigned idx, hash_sig_t prim_hash, hash_sig_t sec_hash,\n }\n \n \n-/* Lookup bulk stage 3: Check if key matches, update hit mask */\n+/* Lookup bulk stage 3: Check if key matches, update hit mask and return data */\n static inline void\n-lookup_stage3(unsigned idx, const void *key_slot, const void * const *keys,\n-\t\tuint64_t *hits, const struct rte_hash *h)\n+lookup_stage3(unsigned idx, const struct rte_hash_key *key_slot, const void * const *keys,\n+\t\tuintptr_t data[], uint64_t *hits, const struct rte_hash *h)\n {\n \tunsigned hit;\n \n-\thit = !h->rte_hash_cmp_eq(key_slot, keys[idx], h->key_len);\n+\thit = !h->rte_hash_cmp_eq(key_slot->key, keys[idx], h->key_len);\n+\tif (data != NULL)\n+\t\tdata[idx] = key_slot->idata;\n+\n \t*hits |= (uint64_t)(hit) << idx;\n }\n \n static inline void\n __rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n-\t\t      uint32_t num_keys, int32_t *positions)\n+\t\t\tuint32_t num_keys, int32_t *positions,\n+\t\t\tuint64_t *hit_mask, uintptr_t data[])\n {\n \tuint64_t hits = 0;\n \tuint64_t extra_hits_mask = 0;\n \tuint64_t lookup_mask, miss_mask;\n \tunsigned idx;\n \tconst void *key_store = h->key_store;\n+\tint ret;\n \thash_sig_t hash_vals[RTE_HASH_LOOKUP_BULK_MAX];\n \n \tunsigned idx00, idx01, idx10, idx11, idx20, idx21, idx30, idx31;\n@@ -811,7 +890,7 @@ __rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n \tconst struct rte_hash_bucket *secondary_bkt10, *secondary_bkt11;\n \tconst struct rte_hash_bucket *primary_bkt20, *primary_bkt21;\n \tconst struct rte_hash_bucket *secondary_bkt20, *secondary_bkt21;\n-\tconst void *k_slot20, *k_slot21, *k_slot30, *k_slot31;\n+\tconst struct rte_hash_key *k_slot20, *k_slot21, *k_slot30, *k_slot31;\n \thash_sig_t primary_hash10, primary_hash11;\n \thash_sig_t secondary_hash10, secondary_hash11;\n \thash_sig_t primary_hash20, primary_hash21;\n@@ -882,8 +961,8 @@ __rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n \t\tlookup_stage2(idx21, primary_hash21, secondary_hash21,\n \t\t\tprimary_bkt21, secondary_bkt21,\t&k_slot21, positions,\n \t\t\t&extra_hits_mask, key_store, h);\n-\t\tlookup_stage3(idx30, k_slot30, keys, &hits, h);\n-\t\tlookup_stage3(idx31, k_slot31, keys, &hits, h);\n+\t\tlookup_stage3(idx30, k_slot30, keys, data, &hits, h);\n+\t\tlookup_stage3(idx31, k_slot31, keys, data, &hits, h);\n \t}\n \n \tk_slot30 = k_slot20, k_slot31 = k_slot21;\n@@ -909,8 +988,8 @@ __rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n \tlookup_stage2(idx21, primary_hash21, secondary_hash21, primary_bkt21,\n \t\tsecondary_bkt21, &k_slot21, positions, &extra_hits_mask,\n \t\tkey_store, h);\n-\tlookup_stage3(idx30, k_slot30, keys, &hits, h);\n-\tlookup_stage3(idx31, k_slot31, keys, &hits, h);\n+\tlookup_stage3(idx30, k_slot30, keys, data, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, keys, data, &hits, h);\n \n \tk_slot30 = k_slot20, k_slot31 = k_slot21;\n \tidx30 = idx20, idx31 = idx21;\n@@ -930,14 +1009,14 @@ __rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n \tlookup_stage2(idx21, primary_hash21, secondary_hash21, primary_bkt21,\n \t\tsecondary_bkt21, &k_slot21, positions, &extra_hits_mask,\n \t\tkey_store, h);\n-\tlookup_stage3(idx30, k_slot30, keys, &hits, h);\n-\tlookup_stage3(idx31, k_slot31, keys, &hits, h);\n+\tlookup_stage3(idx30, k_slot30, keys, data, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, keys, data, &hits, h);\n \n \tk_slot30 = k_slot20, k_slot31 = k_slot21;\n \tidx30 = idx20, idx31 = idx21;\n \n-\tlookup_stage3(idx30, k_slot30, keys, &hits, h);\n-\tlookup_stage3(idx31, k_slot31, keys, &hits, h);\n+\tlookup_stage3(idx30, k_slot30, keys, data, &hits, h);\n+\tlookup_stage3(idx31, k_slot31, keys, data, &hits, h);\n \n \t/* ignore any items we have already found */\n \textra_hits_mask &= ~hits;\n@@ -946,11 +1025,18 @@ __rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n \t\t/* run a single search for each remaining item */\n \t\tdo {\n \t\t\tidx = __builtin_ctzl(extra_hits_mask);\n-\t\t\tpositions[idx] = rte_hash_lookup_with_hash(h, keys[idx],\n-\t\t\t\t\t\t\thash_vals[idx]);\n+\t\t\tif (data != NULL) {\n+\t\t\t\tret = rte_hash_lookup_with_hash_data(h,\n+\t\t\t\t\t\tkeys[idx], hash_vals[idx], &data[idx]);\n+\t\t\t\tif (ret >= 0)\n+\t\t\t\t\thits |= 1ULL << idx;\n+\t\t\t} else {\n+\t\t\t\tpositions[idx] = rte_hash_lookup_with_hash(h,\n+\t\t\t\t\t\t\tkeys[idx], hash_vals[idx]);\n+\t\t\t\tif (positions[idx] >= 0)\n+\t\t\t\t\thits |= 1llu << idx;\n+\t\t\t}\n \t\t\textra_hits_mask &= ~(1llu << idx);\n-\t\t\tif (positions[idx] >= 0)\n-\t\t\t\thits |= 1llu << idx;\n \t\t} while (extra_hits_mask);\n \t}\n \n@@ -962,6 +1048,9 @@ __rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n \t\t\tmiss_mask &= ~(1llu << idx);\n \t\t} while (miss_mask);\n \t}\n+\n+\tif (hit_mask != NULL)\n+\t\t*hit_mask = hits;\n }\n \n int\n@@ -972,10 +1061,26 @@ rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n \t\t\t(num_keys > RTE_HASH_LOOKUP_BULK_MAX) ||\n \t\t\t(positions == NULL)), -EINVAL);\n \n-\t__rte_hash_lookup_bulk(h, keys, num_keys, positions);\n+\t__rte_hash_lookup_bulk(h, keys, num_keys, positions, NULL, NULL);\n \treturn 0;\n }\n \n+int\n+rte_hash_lookup_bulk_data(const struct rte_hash *h, const void **keys,\n+\t\t      uint32_t num_keys, uint64_t *hit_mask, uintptr_t data[])\n+{\n+\tRETURN_IF_TRUE(((h == NULL) || (keys == NULL) || (num_keys == 0) ||\n+\t\t\t(num_keys > RTE_HASH_LOOKUP_BULK_MAX),\n+\t\t\t(hit_mask == NULL)), -EINVAL);\n+\n+\tint32_t positions[num_keys];\n+\n+\t__rte_hash_lookup_bulk(h, keys, num_keys, positions, hit_mask, data);\n+\n+\t/* Return number of hits */\n+\treturn __builtin_popcountl(*hit_mask);\n+}\n+\n /* Functions to compare multiple of 16 byte keys (up to 128 bytes) */\n static int\n rte_hash_k16_cmp_eq(const void *key1, const void *key2, size_t key_len __rte_unused)\ndiff --git a/lib/librte_hash/rte_hash.h b/lib/librte_hash/rte_hash.h\nindex 8bbc9f0..15f8b2f 100644\n--- a/lib/librte_hash/rte_hash.h\n+++ b/lib/librte_hash/rte_hash.h\n@@ -80,12 +80,12 @@ struct rte_hash_parameters {\n \trte_hash_function hash_func;\t/**< Primary Hash function used to calculate hash. */\n \tuint32_t hash_func_init_val;\t/**< Init value used by hash_func. */\n \tint socket_id;\t\t\t/**< NUMA Socket ID for memory. */\n+\tuint8_t extra_flag;\t\t/**< Indicate if additional parameters are present. */\n };\n \n /** @internal A hash table structure. */\n struct rte_hash;\n \n-\n /**\n  * Create a new hash table.\n  *\n@@ -136,6 +136,48 @@ void\n rte_hash_reset(struct rte_hash *h);\n \n /**\n+ * Add a key-value pair to an existing hash table.\n+ * This operation is not multi-thread safe\n+ * and should only be called from one thread.\n+ *\n+ * @param h\n+ *   Hash table to add the key to.\n+ * @param key\n+ *   Key to add to the hash table.\n+ * @param data\n+ *   Data to add to the hash table.\n+ * @return\n+ *   - 0 if added successfully\n+ *   - -EINVAL if the parameters are invalid.\n+ *   - -ENOSPC if there is no space in the hash for this key.\n+ */\n+int\n+rte_hash_add_key_data(const struct rte_hash *h, const void *key, uintptr_t data);\n+\n+/**\n+ * Add a key-value pair with a pre-computed hash value\n+ * to an existing hash table.\n+ * This operation is not multi-thread safe\n+ * and should only be called from one thread.\n+ *\n+ * @param h\n+ *   Hash table to add the key to.\n+ * @param key\n+ *   Key to add to the hash table.\n+ * @param sig\n+ *   Precomputed hash value for 'key'\n+ * @param data\n+ *   Data to add to the hash table.\n+ * @return\n+ *   - 0 if added successfully\n+ *   - -EINVAL if the parameters are invalid.\n+ *   - -ENOSPC if there is no space in the hash for this key.\n+ */\n+int32_t\n+rte_hash_add_key_with_hash_data(const struct rte_hash *h, const void *key,\n+\t\t\t\t\t\thash_sig_t sig, uintptr_t data);\n+\n+/**\n  * Add a key to an existing hash table. This operation is not multi-thread safe\n  * and should only be called from one thread.\n  *\n@@ -212,6 +254,47 @@ rte_hash_del_key(const struct rte_hash *h, const void *key);\n int32_t\n rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key, hash_sig_t sig);\n \n+\n+/**\n+ * Find a key-value pair in the hash table.\n+ * This operation is multi-thread safe.\n+ *\n+ * @param h\n+ *   Hash table to look in.\n+ * @param key\n+ *   Key to find.\n+ * @param data\n+ *   Output with pointer to data returned from the hash table.\n+ * @return\n+ *   0 if successful lookup\n+ *   - EINVAL if the parameters are invalid.\n+ *   - ENOENT if the key is not found.\n+ */\n+int\n+rte_hash_lookup_data(const struct rte_hash *h, const void *key, uintptr_t *data);\n+\n+/**\n+ * Find a key-value pair with a pre-computed hash value\n+ * to an existing hash table.\n+ * This operation is multi-thread safe.\n+ *\n+ * @param h\n+ *   Hash table to look in.\n+ * @param key\n+ *   Key to find.\n+ * @param sig\n+ *   Precomputed hash value for 'key'\n+ * @param data\n+ *   Output with pointer to data returned from the hash table.\n+ * @return\n+ *   0 if successful lookup\n+ *   - EINVAL if the parameters are invalid.\n+ *   - ENOENT if the key is not found.\n+ */\n+int\n+rte_hash_lookup_with_hash_data(const struct rte_hash *h, const void *key,\n+\t\t\t\t\thash_sig_t sig, uintptr_t *data);\n+\n /**\n  * Find a key in the hash table.\n  * This operation is multi-thread safe.\n@@ -266,6 +349,28 @@ hash_sig_t\n rte_hash_hash(const struct rte_hash *h, const void *key);\n \n #define rte_hash_lookup_multi rte_hash_lookup_bulk\n+#define rte_hash_lookup_multi_data rte_hash_lookup_bulk_data\n+/**\n+ * Find multiple keys in the hash table.\n+ * This operation is multi-thread safe.\n+ *\n+ * @param h\n+ *   Hash table to look in.\n+ * @param keys\n+ *   A pointer to a list of keys to look for.\n+ * @param num_keys\n+ *   How many keys are in the keys list (less than RTE_HASH_LOOKUP_BULK_MAX).\n+ * @param hit_mask\n+ *   Output containing a bitmask with all successful lookups.\n+ * @param data\n+ *   Output containing array of data returned from all the successful lookups.\n+ * @return\n+ *   -EINVAL if there's an error, otherwise number of successful lookups.\n+ */\n+int\n+rte_hash_lookup_bulk_data(const struct rte_hash *h, const void **keys,\n+\t\t      uint32_t num_keys, uint64_t *hit_mask, uintptr_t data[]);\n+\n /**\n  * Find multiple keys in the hash table.\n  * This operation is multi-thread safe.\n@@ -288,7 +393,6 @@ rte_hash_hash(const struct rte_hash *h, const void *key);\n int\n rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,\n \t\t      uint32_t num_keys, int32_t *positions);\n-\n #ifdef __cplusplus\n }\n #endif\ndiff --git a/lib/librte_hash/rte_hash_version.map b/lib/librte_hash/rte_hash_version.map\nindex d5f5af5..a97eac1 100644\n--- a/lib/librte_hash/rte_hash_version.map\n+++ b/lib/librte_hash/rte_hash_version.map\n@@ -22,6 +22,12 @@ DPDK_2.0 {\n DPDK_2.1 {\n \tglobal:\n \n+\trte_hash_add_key_data;\n+\trte_hash_add_key_with_hash_data;\n+\trte_hash_create;\n+\trte_hash_lookup_bulk_data;\n+\trte_hash_lookup_data;\n+\trte_hash_lookup_with_hash_data;\n \trte_hash_reset;\n \n \tlocal: *;\n",
    "prefixes": [
        "dpdk-dev",
        "v5",
        "3/7"
    ]
}