get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 30535,
    "url": "https://patches.dpdk.org/api/patches/30535/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1508339034-171115-9-git-send-email-cristian.dumitrescu@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": "<1508339034-171115-9-git-send-email-cristian.dumitrescu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1508339034-171115-9-git-send-email-cristian.dumitrescu@intel.com",
    "date": "2017-10-18T15:03:25",
    "name": "[dpdk-dev,v3,08/18] librte_table: rework variable size key ext hash tables",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "504c05448c3d0bd182e92d378a495491192d2634",
    "submitter": {
        "id": 19,
        "url": "https://patches.dpdk.org/api/people/19/?format=api",
        "name": "Cristian Dumitrescu",
        "email": "cristian.dumitrescu@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1508339034-171115-9-git-send-email-cristian.dumitrescu@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/30535/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/30535/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 [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id C1B331B1E6;\n\tWed, 18 Oct 2017 17:04:28 +0200 (CEST)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby dpdk.org (Postfix) with ESMTP id CCD911AEEE\n\tfor <dev@dpdk.org>; Wed, 18 Oct 2017 17:04:05 +0200 (CEST)",
            "from orsmga004.jf.intel.com ([10.7.209.38])\n\tby fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t18 Oct 2017 08:04:05 -0700",
            "from silpixa00382658.ir.intel.com ([10.237.223.29])\n\tby orsmga004.jf.intel.com with ESMTP; 18 Oct 2017 08:04:04 -0700"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.43,397,1503385200\"; d=\"scan'208\";a=\"139673034\"",
        "From": "Cristian Dumitrescu <cristian.dumitrescu@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "thomas@monjalon.net",
        "Date": "Wed, 18 Oct 2017 16:03:25 +0100",
        "Message-Id": "<1508339034-171115-9-git-send-email-cristian.dumitrescu@intel.com>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1508339034-171115-1-git-send-email-cristian.dumitrescu@intel.com>",
        "References": "<1507634341-72277-2-git-send-email-cristian.dumitrescu@intel.com>\n\t<1508339034-171115-1-git-send-email-cristian.dumitrescu@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v3 08/18] librte_table: rework variable size key\n\text hash tables",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <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": "Rework for the variable size key extendible bucket (EXT) hash\ntable to use the mask-based hash function and the unified\nparameter structure.\n\nSigned-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>\n---\n .../pipeline/pipeline_flow_classification_be.c     |  12 +-\n lib/librte_table/rte_table_hash.h                  |  34 ----\n lib/librte_table/rte_table_hash_ext.c              | 179 ++++++++++++++-------\n test/test-pipeline/pipeline_hash.c                 |  10 +-\n 4 files changed, 130 insertions(+), 105 deletions(-)\n mode change 100644 => 100755 test/test-pipeline/pipeline_hash.c",
    "diff": "diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c\nindex e131a5b..4a4007c 100755\n--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c\n+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c\n@@ -516,16 +516,16 @@ static void *pipeline_fc_init(struct pipeline_params *params,\n \t\t\t.seed = 0,\n \t\t};\n \n-\t\tstruct rte_table_hash_ext_params\n-\t\t\ttable_hash_params = {\n+\t\tstruct rte_table_hash_params table_hash_params = {\n+\t\t\t.name = p->name,\n \t\t\t.key_size = p_fc->key_size,\n+\t\t\t.key_offset = p_fc->key_offset,\n+\t\t\t.key_mask = (p_fc->key_mask_present) ?\n+\t\t\t\tp_fc->key_mask : NULL,\n \t\t\t.n_keys = p_fc->n_flows,\n \t\t\t.n_buckets = p_fc->n_flows / 4,\n-\t\t\t.n_buckets_ext = p_fc->n_flows / 4,\n-\t\t\t.f_hash = hash_func[(p_fc->key_size / 8) - 1],\n+\t\t\t.f_hash = (rte_table_hash_op_hash)hash_func[(p_fc->key_size / 8) - 1],\n \t\t\t.seed = 0,\n-\t\t\t.signature_offset = p_fc->hash_offset,\n-\t\t\t.key_offset = p_fc->key_offset,\n \t\t};\n \n \t\tstruct rte_pipeline_table_params table_params = {\ndiff --git a/lib/librte_table/rte_table_hash.h b/lib/librte_table/rte_table_hash.h\nindex bb5b83d..0024b99 100755\n--- a/lib/librte_table/rte_table_hash.h\n+++ b/lib/librte_table/rte_table_hash.h\n@@ -135,40 +135,6 @@ typedef uint64_t (*rte_table_hash_op_hash_nomask)(\n \tuint32_t key_size,\n \tuint64_t seed);\n \n-/**\n- * Hash tables with configurable key size\n- *\n- */\n-/** Extendible bucket hash table parameters */\n-struct rte_table_hash_ext_params {\n-\t/** Key size (number of bytes) */\n-\tuint32_t key_size;\n-\n-\t/** Maximum number of keys */\n-\tuint32_t n_keys;\n-\n-\t/** Number of hash table buckets. Each bucket stores up to 4 keys. */\n-\tuint32_t n_buckets;\n-\n-\t/** Number of hash table bucket extensions. Each bucket extension has\n-\tspace for 4 keys and each bucket can have 0, 1 or more extensions. */\n-\tuint32_t n_buckets_ext;\n-\n-\t/** Hash function */\n-\trte_table_hash_op_hash_nomask f_hash;\n-\n-\t/** Seed value for the hash function */\n-\tuint64_t seed;\n-\n-\t/** Byte offset within packet meta-data where the 4-byte key signature\n-\tis located. Valid for pre-computed key signature tables, ignored for\n-\tdo-sig tables. */\n-\tuint32_t signature_offset;\n-\n-\t/** Byte offset within packet meta-data where the key is located */\n-\tuint32_t key_offset;\n-};\n-\n extern struct rte_table_ops rte_table_hash_ext_ops;\n \n /** LRU hash table parameters */\ndiff --git a/lib/librte_table/rte_table_hash_ext.c b/lib/librte_table/rte_table_hash_ext.c\nindex 72802b8..0a743ad 100755\n--- a/lib/librte_table/rte_table_hash_ext.c\n+++ b/lib/librte_table/rte_table_hash_ext.c\n@@ -104,9 +104,8 @@ struct rte_table_hash {\n \tuint32_t n_keys;\n \tuint32_t n_buckets;\n \tuint32_t n_buckets_ext;\n-\trte_table_hash_op_hash_nomask f_hash;\n+\trte_table_hash_op_hash f_hash;\n \tuint64_t seed;\n-\tuint32_t signature_offset;\n \tuint32_t key_offset;\n \n \t/* Internal */\n@@ -120,6 +119,7 @@ struct rte_table_hash {\n \tstruct grinder grinders[RTE_PORT_IN_BURST_SIZE_MAX];\n \n \t/* Tables */\n+\tuint64_t *key_mask;\n \tstruct bucket *buckets;\n \tstruct bucket *buckets_ext;\n \tuint8_t *key_mem;\n@@ -132,29 +132,53 @@ struct rte_table_hash {\n };\n \n static int\n-check_params_create(struct rte_table_hash_ext_params *params)\n+keycmp(void *a, void *b, void *b_mask, uint32_t n_bytes)\n {\n-\tuint32_t n_buckets_min;\n+\tuint64_t *a64 = a, *b64 = b, *b_mask64 = b_mask;\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < n_bytes / sizeof(uint64_t); i++)\n+\t\tif (a64[i] != (b64[i] & b_mask64[i]))\n+\t\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+static void\n+keycpy(void *dst, void *src, void *src_mask, uint32_t n_bytes)\n+{\n+\tuint64_t *dst64 = dst, *src64 = src, *src_mask64 = src_mask;\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < n_bytes / sizeof(uint64_t); i++)\n+\t\tdst64[i] = src64[i] & src_mask64[i];\n+}\n+\n+static int\n+check_params_create(struct rte_table_hash_params *params)\n+{\n+\t/* name */\n+\tif (params->name == NULL) {\n+\t\tRTE_LOG(ERR, TABLE, \"%s: name invalid value\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n \n \t/* key_size */\n-\tif ((params->key_size == 0) ||\n+\tif ((params->key_size < sizeof(uint64_t)) ||\n \t\t(!rte_is_power_of_2(params->key_size))) {\n \t\tRTE_LOG(ERR, TABLE, \"%s: key_size invalid value\\n\", __func__);\n \t\treturn -EINVAL;\n \t}\n \n \t/* n_keys */\n-\tif ((params->n_keys == 0) ||\n-\t\t(!rte_is_power_of_2(params->n_keys))) {\n+\tif (params->n_keys == 0) {\n \t\tRTE_LOG(ERR, TABLE, \"%s: n_keys invalid value\\n\", __func__);\n \t\treturn -EINVAL;\n \t}\n \n \t/* n_buckets */\n-\tn_buckets_min = (params->n_keys + KEYS_PER_BUCKET - 1) / params->n_keys;\n \tif ((params->n_buckets == 0) ||\n-\t\t(!rte_is_power_of_2(params->n_keys)) ||\n-\t\t(params->n_buckets < n_buckets_min)) {\n+\t\t(!rte_is_power_of_2(params->n_buckets))) {\n \t\tRTE_LOG(ERR, TABLE, \"%s: n_buckets invalid value\\n\", __func__);\n \t\treturn -EINVAL;\n \t}\n@@ -171,15 +195,13 @@ check_params_create(struct rte_table_hash_ext_params *params)\n static void *\n rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)\n {\n-\tstruct rte_table_hash_ext_params *p =\n-\t\tparams;\n+\tstruct rte_table_hash_params *p = params;\n \tstruct rte_table_hash *t;\n-\tuint32_t total_size, table_meta_sz;\n-\tuint32_t bucket_sz, bucket_ext_sz, key_sz;\n-\tuint32_t key_stack_sz, bkt_ext_stack_sz, data_sz;\n-\tuint32_t bucket_offset, bucket_ext_offset, key_offset;\n-\tuint32_t key_stack_offset, bkt_ext_stack_offset, data_offset;\n-\tuint32_t i;\n+\tuint64_t table_meta_sz, key_mask_sz, bucket_sz, bucket_ext_sz, key_sz;\n+\tuint64_t key_stack_sz, bkt_ext_stack_sz, data_sz, total_size;\n+\tuint64_t key_mask_offset, bucket_offset, bucket_ext_offset, key_offset;\n+\tuint64_t key_stack_offset, bkt_ext_stack_offset, data_offset;\n+\tuint32_t n_buckets_ext, i;\n \n \t/* Check input parameters */\n \tif ((check_params_create(p) != 0) ||\n@@ -188,38 +210,66 @@ rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)\n \t\t(sizeof(struct bucket) != (RTE_CACHE_LINE_SIZE / 2)))\n \t\treturn NULL;\n \n+\t/*\n+\t * Table dimensioning\n+\t *\n+\t * Objective: Pick the number of bucket extensions (n_buckets_ext) so that\n+\t * it is guaranteed that n_keys keys can be stored in the table at any time.\n+\t *\n+\t * The worst case scenario takes place when all the n_keys keys fall into\n+\t * the same bucket. Actually, due to the KEYS_PER_BUCKET scheme, the worst\n+\t * case takes place when (n_keys - KEYS_PER_BUCKET + 1) keys fall into the\n+\t * same bucket, while the remaining (KEYS_PER_BUCKET - 1) keys each fall\n+\t * into a different bucket. This case defeats the purpose of the hash table.\n+\t * It indicates unsuitable f_hash or n_keys to n_buckets ratio.\n+\t *\n+\t * n_buckets_ext = n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1\n+\t */\n+\tn_buckets_ext = p->n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1;\n+\n \t/* Memory allocation */\n \ttable_meta_sz = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_table_hash));\n+\tkey_mask_sz = RTE_CACHE_LINE_ROUNDUP(p->key_size);\n \tbucket_sz = RTE_CACHE_LINE_ROUNDUP(p->n_buckets * sizeof(struct bucket));\n \tbucket_ext_sz =\n-\t\tRTE_CACHE_LINE_ROUNDUP(p->n_buckets_ext * sizeof(struct bucket));\n+\t\tRTE_CACHE_LINE_ROUNDUP(n_buckets_ext * sizeof(struct bucket));\n \tkey_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * p->key_size);\n \tkey_stack_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * sizeof(uint32_t));\n \tbkt_ext_stack_sz =\n-\t\tRTE_CACHE_LINE_ROUNDUP(p->n_buckets_ext * sizeof(uint32_t));\n+\t\tRTE_CACHE_LINE_ROUNDUP(n_buckets_ext * sizeof(uint32_t));\n \tdata_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * entry_size);\n-\ttotal_size = table_meta_sz + bucket_sz + bucket_ext_sz + key_sz +\n-\t\tkey_stack_sz + bkt_ext_stack_sz + data_sz;\n+\ttotal_size = table_meta_sz + key_mask_sz + bucket_sz + bucket_ext_sz +\n+\t\tkey_sz + key_stack_sz + bkt_ext_stack_sz + data_sz;\n \n-\tt = rte_zmalloc_socket(\"TABLE\", total_size, RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (total_size > SIZE_MAX) {\n+\t\tRTE_LOG(ERR, TABLE, \"%s: Cannot allocate %\" PRIu64 \" bytes\"\n+\t\t\t\" for hash table %s\\n\",\n+\t\t\t__func__, total_size, p->name);\n+\t\treturn NULL;\n+\t}\n+\n+\tt = rte_zmalloc_socket(p->name,\n+\t\t(size_t)total_size,\n+\t\tRTE_CACHE_LINE_SIZE,\n+\t\tsocket_id);\n \tif (t == NULL) {\n-\t\tRTE_LOG(ERR, TABLE,\n-\t\t\t\"%s: Cannot allocate %u bytes for hash table\\n\",\n-\t\t\t__func__, total_size);\n+\t\tRTE_LOG(ERR, TABLE, \"%s: Cannot allocate %\" PRIu64 \" bytes\"\n+\t\t\t\" for hash table %s\\n\",\n+\t\t\t__func__, total_size, p->name);\n \t\treturn NULL;\n \t}\n-\tRTE_LOG(INFO, TABLE, \"%s (%u-byte key): Hash table memory footprint is \"\n-\t\t\"%u bytes\\n\", __func__, p->key_size, total_size);\n+\tRTE_LOG(INFO, TABLE, \"%s (%u-byte key): Hash table %s memory \"\n+\t\t\"footprint is %\" PRIu64 \" bytes\\n\",\n+\t\t__func__, p->key_size, p->name, total_size);\n \n \t/* Memory initialization */\n \tt->key_size = p->key_size;\n \tt->entry_size = entry_size;\n \tt->n_keys = p->n_keys;\n \tt->n_buckets = p->n_buckets;\n-\tt->n_buckets_ext = p->n_buckets_ext;\n+\tt->n_buckets_ext = n_buckets_ext;\n \tt->f_hash = p->f_hash;\n \tt->seed = p->seed;\n-\tt->signature_offset = p->signature_offset;\n \tt->key_offset = p->key_offset;\n \n \t/* Internal */\n@@ -228,13 +278,15 @@ rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)\n \tt->data_size_shl = __builtin_ctzl(entry_size);\n \n \t/* Tables */\n-\tbucket_offset = 0;\n+\tkey_mask_offset = 0;\n+\tbucket_offset = key_mask_offset + key_mask_sz;\n \tbucket_ext_offset = bucket_offset + bucket_sz;\n \tkey_offset = bucket_ext_offset + bucket_ext_sz;\n \tkey_stack_offset = key_offset + key_sz;\n \tbkt_ext_stack_offset = key_stack_offset + key_stack_sz;\n \tdata_offset = bkt_ext_stack_offset + bkt_ext_stack_sz;\n \n+\tt->key_mask = (uint64_t *) &t->memory[key_mask_offset];\n \tt->buckets = (struct bucket *) &t->memory[bucket_offset];\n \tt->buckets_ext = (struct bucket *) &t->memory[bucket_ext_offset];\n \tt->key_mem = &t->memory[key_offset];\n@@ -242,6 +294,12 @@ rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)\n \tt->bkt_ext_stack = (uint32_t *) &t->memory[bkt_ext_stack_offset];\n \tt->data_mem = &t->memory[data_offset];\n \n+\t/* Key mask */\n+\tif (p->key_mask == NULL)\n+\t\tmemset(t->key_mask, 0xFF, p->key_size);\n+\telse\n+\t\tmemcpy(t->key_mask, p->key_mask, p->key_size);\n+\n \t/* Key stack */\n \tfor (i = 0; i < t->n_keys; i++)\n \t\tt->key_stack[i] = t->n_keys - 1 - i;\n@@ -277,7 +335,7 @@ rte_table_hash_ext_entry_add(void *table, void *key, void *entry,\n \tuint64_t sig;\n \tuint32_t bkt_index, i;\n \n-\tsig = t->f_hash(key, t->key_size, t->seed);\n+\tsig = t->f_hash(key, t->key_mask, t->key_size, t->seed);\n \tbkt_index = sig & t->bucket_mask;\n \tbkt0 = &t->buckets[bkt_index];\n \tsig = (sig >> 16) | 1LLU;\n@@ -290,7 +348,7 @@ rte_table_hash_ext_entry_add(void *table, void *key, void *entry,\n \t\t\tuint8_t *bkt_key =\n \t\t\t\t&t->key_mem[bkt_key_index << t->key_size_shl];\n \n-\t\t\tif ((sig == bkt_sig) && (memcmp(key, bkt_key,\n+\t\t\tif ((sig == bkt_sig) && (keycmp(bkt_key, key, t->key_mask,\n \t\t\t\tt->key_size) == 0)) {\n \t\t\t\tuint8_t *data = &t->data_mem[bkt_key_index <<\n \t\t\t\t\tt->data_size_shl];\n@@ -327,7 +385,7 @@ rte_table_hash_ext_entry_add(void *table, void *key, void *entry,\n \n \t\t\t\tbkt->sig[i] = (uint16_t) sig;\n \t\t\t\tbkt->key_pos[i] = bkt_key_index;\n-\t\t\t\tmemcpy(bkt_key, key, t->key_size);\n+\t\t\t\tkeycpy(bkt_key, key, t->key_mask, t->key_size);\n \t\t\t\tmemcpy(data, entry, t->entry_size);\n \n \t\t\t\t*key_found = 0;\n@@ -358,7 +416,7 @@ rte_table_hash_ext_entry_add(void *table, void *key, void *entry,\n \t\t/* Install new key into bucket */\n \t\tbkt->sig[0] = (uint16_t) sig;\n \t\tbkt->key_pos[0] = bkt_key_index;\n-\t\tmemcpy(bkt_key, key, t->key_size);\n+\t\tkeycpy(bkt_key, key, t->key_mask, t->key_size);\n \t\tmemcpy(data, entry, t->entry_size);\n \n \t\t*key_found = 0;\n@@ -378,7 +436,7 @@ void *entry)\n \tuint64_t sig;\n \tuint32_t bkt_index, i;\n \n-\tsig = t->f_hash(key, t->key_size, t->seed);\n+\tsig = t->f_hash(key, t->key_mask, t->key_size, t->seed);\n \tbkt_index = sig & t->bucket_mask;\n \tbkt0 = &t->buckets[bkt_index];\n \tsig = (sig >> 16) | 1LLU;\n@@ -392,7 +450,7 @@ void *entry)\n \t\t\tuint8_t *bkt_key = &t->key_mem[bkt_key_index <<\n \t\t\t\tt->key_size_shl];\n \n-\t\t\tif ((sig == bkt_sig) && (memcmp(key, bkt_key,\n+\t\t\tif ((sig == bkt_sig) && (keycmp(bkt_key, key, t->key_mask,\n \t\t\t\tt->key_size) == 0)) {\n \t\t\t\tuint8_t *data = &t->data_mem[bkt_key_index <<\n \t\t\t\t\tt->data_size_shl];\n@@ -457,7 +515,7 @@ static int rte_table_hash_ext_lookup_unoptimized(\n \n \t\tpkt = pkts[pkt_index];\n \t\tkey = RTE_MBUF_METADATA_UINT8_PTR(pkt, t->key_offset);\n-\t\tsig = (uint64_t) t->f_hash(key, t->key_size, t->seed);\n+\t\tsig = (uint64_t) t->f_hash(key, t->key_mask, t->key_size, t->seed);\n \n \t\tbkt_index = sig & t->bucket_mask;\n \t\tbkt0 = &t->buckets[bkt_index];\n@@ -471,8 +529,8 @@ static int rte_table_hash_ext_lookup_unoptimized(\n \t\t\t\tuint8_t *bkt_key = &t->key_mem[bkt_key_index <<\n \t\t\t\t\tt->key_size_shl];\n \n-\t\t\t\tif ((sig == bkt_sig) && (memcmp(key, bkt_key,\n-\t\t\t\t\tt->key_size) == 0)) {\n+\t\t\t\tif ((sig == bkt_sig) && (keycmp(bkt_key, key,\n+\t\t\t\t\tt->key_mask, t->key_size) == 0)) {\n \t\t\t\t\tuint8_t *data = &t->data_mem[\n \t\t\t\t\tbkt_key_index << t->data_size_shl];\n \n@@ -571,11 +629,12 @@ static int rte_table_hash_ext_lookup_unoptimized(\n {\t\t\t\t\t\t\t\t\t\\\n \tuint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(mbuf, f->key_offset);\\\n \tuint64_t *bkt_key = (uint64_t *) key;\t\t\t\t\\\n+\tuint64_t *key_mask = f->key_mask;\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n \tswitch (f->key_size) {\t\t\t\t\t\t\\\n \tcase 8:\t\t\t\t\t\t\t\t\\\n \t{\t\t\t\t\t\t\t\t\\\n-\t\tuint64_t xor = pkt_key[0] ^ bkt_key[0];\t\t\t\\\n+\t\tuint64_t xor = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];\t\\\n \t\tmatch_key = 0;\t\t\t\t\t\t\\\n \t\tif (xor == 0)\t\t\t\t\t\t\\\n \t\t\tmatch_key = 1;\t\t\t\t\t\\\n@@ -586,8 +645,8 @@ static int rte_table_hash_ext_lookup_unoptimized(\n \t{\t\t\t\t\t\t\t\t\\\n \t\tuint64_t xor[2], or;\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n-\t\txor[0] = pkt_key[0] ^ bkt_key[0];\t\t\t\\\n-\t\txor[1] = pkt_key[1] ^ bkt_key[1];\t\t\t\\\n+\t\txor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];\t\t\\\n+\t\txor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];\t\t\\\n \t\tor = xor[0] | xor[1];\t\t\t\t\t\\\n \t\tmatch_key = 0;\t\t\t\t\t\t\\\n \t\tif (or == 0)\t\t\t\t\t\t\\\n@@ -599,10 +658,10 @@ static int rte_table_hash_ext_lookup_unoptimized(\n \t{\t\t\t\t\t\t\t\t\\\n \t\tuint64_t xor[4], or;\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n-\t\txor[0] = pkt_key[0] ^ bkt_key[0];\t\t\t\\\n-\t\txor[1] = pkt_key[1] ^ bkt_key[1];\t\t\t\\\n-\t\txor[2] = pkt_key[2] ^ bkt_key[2];\t\t\t\\\n-\t\txor[3] = pkt_key[3] ^ bkt_key[3];\t\t\t\\\n+\t\txor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];\t\t\\\n+\t\txor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];\t\t\\\n+\t\txor[2] = (pkt_key[2] & key_mask[2]) ^ bkt_key[2];\t\t\\\n+\t\txor[3] = (pkt_key[3] & key_mask[3]) ^ bkt_key[3];\t\t\\\n \t\tor = xor[0] | xor[1] | xor[2] | xor[3];\t\t\t\\\n \t\tmatch_key = 0;\t\t\t\t\t\t\\\n \t\tif (or == 0)\t\t\t\t\t\t\\\n@@ -614,14 +673,14 @@ static int rte_table_hash_ext_lookup_unoptimized(\n \t{\t\t\t\t\t\t\t\t\\\n \t\tuint64_t xor[8], or;\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n-\t\txor[0] = pkt_key[0] ^ bkt_key[0];\t\t\t\\\n-\t\txor[1] = pkt_key[1] ^ bkt_key[1];\t\t\t\\\n-\t\txor[2] = pkt_key[2] ^ bkt_key[2];\t\t\t\\\n-\t\txor[3] = pkt_key[3] ^ bkt_key[3];\t\t\t\\\n-\t\txor[4] = pkt_key[4] ^ bkt_key[4];\t\t\t\\\n-\t\txor[5] = pkt_key[5] ^ bkt_key[5];\t\t\t\\\n-\t\txor[6] = pkt_key[6] ^ bkt_key[6];\t\t\t\\\n-\t\txor[7] = pkt_key[7] ^ bkt_key[7];\t\t\t\\\n+\t\txor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];\t\t\\\n+\t\txor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];\t\t\\\n+\t\txor[2] = (pkt_key[2] & key_mask[2]) ^ bkt_key[2];\t\t\\\n+\t\txor[3] = (pkt_key[3] & key_mask[3]) ^ bkt_key[3];\t\t\\\n+\t\txor[4] = (pkt_key[4] & key_mask[4]) ^ bkt_key[4];\t\t\\\n+\t\txor[5] = (pkt_key[5] & key_mask[5]) ^ bkt_key[5];\t\t\\\n+\t\txor[6] = (pkt_key[6] & key_mask[6]) ^ bkt_key[6];\t\t\\\n+\t\txor[7] = (pkt_key[7] & key_mask[7]) ^ bkt_key[7];\t\t\\\n \t\tor = xor[0] | xor[1] | xor[2] | xor[3] |\t\t\\\n \t\t\txor[4] | xor[5] | xor[6] | xor[7];\t\t\\\n \t\tmatch_key = 0;\t\t\t\t\t\t\\\n@@ -632,7 +691,7 @@ static int rte_table_hash_ext_lookup_unoptimized(\n \t\t\t\t\t\t\t\t\t\\\n \tdefault:\t\t\t\t\t\t\t\\\n \t\tmatch_key = 0;\t\t\t\t\t\t\\\n-\t\tif (memcmp(pkt_key, bkt_key, f->key_size) == 0)\t\t\\\n+\t\tif (keycmp(bkt_key, pkt_key, key_mask, f->key_size) == 0)\t\\\n \t\t\tmatch_key = 1;\t\t\t\t\t\\\n \t}\t\t\t\t\t\t\t\t\\\n }\n@@ -688,20 +747,20 @@ static int rte_table_hash_ext_lookup_unoptimized(\n \tstruct bucket *bkt10, *bkt11, *buckets = t->buckets;\t\t\\\n \tuint8_t *key10, *key11;\t\t\t\t\t\t\\\n \tuint64_t bucket_mask = t->bucket_mask;\t\t\t\t\\\n-\trte_table_hash_op_hash_nomask f_hash = t->f_hash;\t\t\t\\\n+\trte_table_hash_op_hash f_hash = t->f_hash;\t\t\t\\\n \tuint64_t seed = t->seed;\t\t\t\t\t\\\n \tuint32_t key_size = t->key_size;\t\t\t\t\\\n \tuint32_t key_offset = t->key_offset;\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n \tmbuf10 = pkts[pkt10_index];\t\t\t\t\t\\\n \tkey10 = RTE_MBUF_METADATA_UINT8_PTR(mbuf10, key_offset);\t\\\n-\tsig10 = (uint64_t) f_hash(key10, key_size, seed);\t\t\\\n+\tsig10 = (uint64_t) f_hash(key10, t->key_mask, key_size, seed);\t\\\n \tbkt10_index = sig10 & bucket_mask;\t\t\t\t\\\n \tbkt10 = &buckets[bkt10_index];\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n \tmbuf11 = pkts[pkt11_index];\t\t\t\t\t\\\n \tkey11 = RTE_MBUF_METADATA_UINT8_PTR(mbuf11, key_offset);\t\\\n-\tsig11 = (uint64_t) f_hash(key11, key_size, seed);\t\t\\\n+\tsig11 = (uint64_t) f_hash(key11, t->key_mask, key_size, seed);\t\\\n \tbkt11_index = sig11 & bucket_mask;\t\t\t\t\\\n \tbkt11 = &buckets[bkt11_index];\t\t\t\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n@@ -969,7 +1028,7 @@ rte_table_hash_ext_stats_read(void *table, struct rte_table_stats *stats, int cl\n \treturn 0;\n }\n \n-struct rte_table_ops rte_table_hash_ext_ops  = {\n+struct rte_table_ops rte_table_hash_ext_ops\t = {\n \t.f_create = rte_table_hash_ext_create,\n \t.f_free = rte_table_hash_ext_free,\n \t.f_add = rte_table_hash_ext_entry_add,\ndiff --git a/test/test-pipeline/pipeline_hash.c b/test/test-pipeline/pipeline_hash.c\nold mode 100644\nnew mode 100755\nindex 2f8c625..13d309d\n--- a/test/test-pipeline/pipeline_hash.c\n+++ b/test/test-pipeline/pipeline_hash.c\n@@ -175,15 +175,15 @@ app_main_loop_worker_pipeline_hash(void) {\n \tcase e_APP_PIPELINE_HASH_KEY16_EXT:\n \tcase e_APP_PIPELINE_HASH_KEY32_EXT:\n \t{\n-\t\tstruct rte_table_hash_ext_params table_hash_params = {\n+\t\tstruct rte_table_hash_params table_hash_params = {\n+\t\t\t.name = \"TABLE\",\n \t\t\t.key_size = key_size,\n+\t\t\t.key_offset = APP_METADATA_OFFSET(32),\n+\t\t\t.key_mask = NULL,\n \t\t\t.n_keys = 1 << 24,\n \t\t\t.n_buckets = 1 << 22,\n-\t\t\t.n_buckets_ext = 1 << 21,\n-\t\t\t.f_hash = test_hash,\n+\t\t\t.f_hash = (rte_table_hash_op_hash)test_hash,\n \t\t\t.seed = 0,\n-\t\t\t.signature_offset = APP_METADATA_OFFSET(0),\n-\t\t\t.key_offset = APP_METADATA_OFFSET(32),\n \t\t};\n \n \t\tstruct rte_pipeline_table_params table_params = {\n",
    "prefixes": [
        "dpdk-dev",
        "v3",
        "08/18"
    ]
}