[dpdk-dev] [PATCH V2 1/5] table: add key mask for hash tables

Cristian Dumitrescu cristian.dumitrescu at intel.com
Tue Oct 10 13:18:57 CEST 2017


Main changes:

1. The key_mask parameter is added to all the hash tables that were
   previously missing it, as well to the hash compute function. This was
   first started in DPDK 2.0, but was only implemented for a couple of
   hash tables. The benefit of this approach is that it allows for better
   performance for large keys (bigger than 16 bytes), while it preserves
   the same performance for small keys [Q&A1].

2. The precomputed key signature (i.e. non-"do-sig") versions have been
   removed for all the hash tables, so now the key signature is always
   computed on every lookup. Note that this approach also allows for the
   precomputed key signature scheme [Q&A2].

3. API cleanup: single parameter structure common for all hash tables.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu at intel.com>
---
Changes in V2:
- Removed unnecessary constraints and improved checks for input params
- Fixed potential overflow issues for large tables
- Fixed map file
- Fixed minor style issues

 lib/librte_table/rte_table_hash.h        | 306 +------------
 lib/librte_table/rte_table_hash_cuckoo.c | 205 ++++-----
 lib/librte_table/rte_table_hash_ext.c    | 417 ++++++-----------
 lib/librte_table/rte_table_hash_key16.c  | 749 +++++++++----------------------
 lib/librte_table/rte_table_hash_key32.c  | 435 +++++++++++-------
 lib/librte_table/rte_table_hash_key8.c   | 715 +++++++++--------------------
 lib/librte_table/rte_table_hash_lru.c    | 513 +++++++++------------
 lib/librte_table/rte_table_version.map   |  23 +-
 8 files changed, 1160 insertions(+), 2203 deletions(-)

diff --git a/lib/librte_table/rte_table_hash.h b/lib/librte_table/rte_table_hash.h
index 57505a6..4ee6984 100644
--- a/lib/librte_table/rte_table_hash.h
+++ b/lib/librte_table/rte_table_hash.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -45,8 +45,6 @@ extern "C" {
  * These tables use the exact match criterion to uniquely associate data to
  * lookup keys.
  *
- * Use-cases: Flow classification table, Address Resolution Protocol (ARP) table
- *
  * Hash table types:
  * 1. Entry add strategy on bucket full:
  *     a. Least Recently Used (LRU): One of the existing keys in the bucket is
@@ -59,7 +57,7 @@ extern "C" {
  *        to the bucket, it also becomes the new MRU key. When a key needs to
  *        be picked and dropped, the most likely candidate for drop, i.e. the
  *        current LRU key, is always picked. The LRU logic requires maintaining
- *        specific data structures per each bucket.
+ *        specific data structures per each bucket. Use-cases: flow cache, etc.
  *     b. Extendible bucket (ext): The bucket is extended with space for 4 more
  *        keys. This is done by allocating additional memory at table init time,
  *        which is used to create a pool of free keys (the size of this pool is
@@ -73,20 +71,8 @@ extern "C" {
  *        first group of 4 keys, the search continues beyond the first group of
  *        4 keys, potentially until all keys in this bucket are examined. The
  *        extendible bucket logic requires maintaining specific data structures
- *        per table and per each bucket.
- * 2. Key signature computation:
- *     a. Pre-computed key signature: The key lookup operation is split between
- *        two CPU cores. The first CPU core (typically the CPU core performing
- *        packet RX) extracts the key from the input packet, computes the key
- *        signature and saves both the key and the key signature in the packet
- *        buffer as packet meta-data. The second CPU core reads both the key and
- *        the key signature from the packet meta-data and performs the bucket
- *        search step of the key lookup operation.
- *     b. Key signature computed on lookup (do-sig): The same CPU core reads
- *        the key from the packet meta-data, uses it to compute the key
- *        signature and also performs the bucket search step of the key lookup
- *        operation.
- * 3. Key size:
+ *        per table and per each bucket. Use-cases: flow table, etc.
+ * 2. Key size:
  *     a. Configurable key size
  *     b. Single key size (8-byte, 16-byte or 32-byte key size)
  *
@@ -98,59 +84,28 @@ extern "C" {
 /** Hash function */
 typedef uint64_t (*rte_table_hash_op_hash)(
 	void *key,
+	void *key_mask,
 	uint32_t key_size,
 	uint64_t seed);
 
-/**
- * Hash tables with configurable key size
- *
- */
-/** Extendible bucket hash table parameters */
-struct rte_table_hash_ext_params {
+/** Hash table parameters */
+struct rte_table_hash_params {
+	/** Name */
+	const char *name;
+
 	/** Key size (number of bytes) */
 	uint32_t key_size;
 
-	/** Maximum number of keys */
-	uint32_t n_keys;
-
-	/** Number of hash table buckets. Each bucket stores up to 4 keys. */
-	uint32_t n_buckets;
-
-	/** Number of hash table bucket extensions. Each bucket extension has
-	space for 4 keys and each bucket can have 0, 1 or more extensions. */
-	uint32_t n_buckets_ext;
-
-	/** Hash function */
-	rte_table_hash_op_hash f_hash;
-
-	/** Seed value for the hash function */
-	uint64_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
 	/** Byte offset within packet meta-data where the key is located */
 	uint32_t key_offset;
-};
 
-/** Extendible bucket hash table operations for pre-computed key signature */
-extern struct rte_table_ops rte_table_hash_ext_ops;
-
-/** Extendible bucket hash table operations for key signature computed on
-	lookup ("do-sig") */
-extern struct rte_table_ops rte_table_hash_ext_dosig_ops;
-
-/** LRU hash table parameters */
-struct rte_table_hash_lru_params {
-	/** Key size (number of bytes) */
-	uint32_t key_size;
+	/** Key mask */
+	uint8_t *key_mask;
 
-	/** Maximum number of keys */
+	/** Number of keys */
 	uint32_t n_keys;
 
-	/** Number of hash table buckets. Each bucket stores up to 4 keys. */
+	/** Number of buckets */
 	uint32_t n_buckets;
 
 	/** Hash function */
@@ -158,239 +113,22 @@ struct rte_table_hash_lru_params {
 
 	/** Seed value for the hash function */
 	uint64_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
-	/** Byte offset within packet meta-data where the key is located */
-	uint32_t key_offset;
 };
 
-/** LRU hash table operations for pre-computed key signature */
-extern struct rte_table_ops rte_table_hash_lru_ops;
-
-/** LRU hash table operations for key signature computed on lookup ("do-sig") */
-extern struct rte_table_ops rte_table_hash_lru_dosig_ops;
-
-/**
- * 8-byte key hash tables
- *
- */
-/** LRU hash table parameters */
-struct rte_table_hash_key8_lru_params {
-	/** Maximum number of entries (and keys) in the table */
-	uint32_t n_entries;
-
-	/** Hash function */
-	rte_table_hash_op_hash f_hash;
-
-	/** Seed for the hash function */
-	uint64_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
-	/** Byte offset within packet meta-data where the key is located */
-	uint32_t key_offset;
-
-	/** Bit-mask to be AND-ed to the key on lookup */
-	uint8_t *key_mask;
-};
-
-/** LRU hash table operations for pre-computed key signature */
-extern struct rte_table_ops rte_table_hash_key8_lru_ops;
-
-/** LRU hash table operations for key signature computed on lookup ("do-sig") */
-extern struct rte_table_ops rte_table_hash_key8_lru_dosig_ops;
-
-/** Extendible bucket hash table parameters */
-struct rte_table_hash_key8_ext_params {
-	/** Maximum number of entries (and keys) in the table */
-	uint32_t n_entries;
-
-	/** Number of entries (and keys) for hash table bucket extensions. Each
-		bucket is extended in increments of 4 keys. */
-	uint32_t n_entries_ext;
-
-	/** Hash function */
-	rte_table_hash_op_hash f_hash;
-
-	/** Seed for the hash function */
-	uint64_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
-	/** Byte offset within packet meta-data where the key is located */
-	uint32_t key_offset;
-
-	/** Bit-mask to be AND-ed to the key on lookup */
-	uint8_t *key_mask;
-};
-
-/** Extendible bucket hash table operations for pre-computed key signature */
+/** Extendible bucket hash table operations */
+extern struct rte_table_ops rte_table_hash_ext_ops;
 extern struct rte_table_ops rte_table_hash_key8_ext_ops;
-
-/** Extendible bucket hash table operations for key signature computed on
-    lookup ("do-sig") */
-extern struct rte_table_ops rte_table_hash_key8_ext_dosig_ops;
-
-/**
- * 16-byte key hash tables
- *
- */
-/** LRU hash table parameters */
-struct rte_table_hash_key16_lru_params {
-	/** Maximum number of entries (and keys) in the table */
-	uint32_t n_entries;
-
-	/** Hash function */
-	rte_table_hash_op_hash f_hash;
-
-	/** Seed for the hash function */
-	uint64_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
-	/** Byte offset within packet meta-data where the key is located */
-	uint32_t key_offset;
-
-	/** Bit-mask to be AND-ed to the key on lookup */
-	uint8_t *key_mask;
-};
-
-/** LRU hash table operations for pre-computed key signature */
-extern struct rte_table_ops rte_table_hash_key16_lru_ops;
-
-/** LRU hash table operations for key signature computed on lookup
-    ("do-sig") */
-extern struct rte_table_ops rte_table_hash_key16_lru_dosig_ops;
-
-/** Extendible bucket hash table parameters */
-struct rte_table_hash_key16_ext_params {
-	/** Maximum number of entries (and keys) in the table */
-	uint32_t n_entries;
-
-	/** Number of entries (and keys) for hash table bucket extensions. Each
-	bucket is extended in increments of 4 keys. */
-	uint32_t n_entries_ext;
-
-	/** Hash function */
-	rte_table_hash_op_hash f_hash;
-
-	/** Seed for the hash function */
-	uint64_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
-	/** Byte offset within packet meta-data where the key is located */
-	uint32_t key_offset;
-
-	/** Bit-mask to be AND-ed to the key on lookup */
-	uint8_t *key_mask;
-};
-
-/** Extendible bucket operations for pre-computed key signature */
 extern struct rte_table_ops rte_table_hash_key16_ext_ops;
-
-/** Extendible bucket hash table operations for key signature computed on
-    lookup ("do-sig") */
-extern struct rte_table_ops rte_table_hash_key16_ext_dosig_ops;
-
-/**
- * 32-byte key hash tables
- *
- */
-/** LRU hash table parameters */
-struct rte_table_hash_key32_lru_params {
-	/** Maximum number of entries (and keys) in the table */
-	uint32_t n_entries;
-
-	/** Hash function */
-	rte_table_hash_op_hash f_hash;
-
-	/** Seed for the hash function */
-	uint64_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
-	/** Byte offset within packet meta-data where the key is located */
-	uint32_t key_offset;
-};
-
-/** LRU hash table operations for pre-computed key signature */
-extern struct rte_table_ops rte_table_hash_key32_lru_ops;
-
-/** Extendible bucket hash table parameters */
-struct rte_table_hash_key32_ext_params {
-	/** Maximum number of entries (and keys) in the table */
-	uint32_t n_entries;
-
-	/** Number of entries (and keys) for hash table bucket extensions. Each
-		bucket is extended in increments of 4 keys. */
-	uint32_t n_entries_ext;
-
-	/** Hash function */
-	rte_table_hash_op_hash f_hash;
-
-	/** Seed for the hash function */
-	uint64_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
-	/** Byte offset within packet meta-data where the key is located */
-	uint32_t key_offset;
-};
-
-/** Extendible bucket hash table operations */
 extern struct rte_table_ops rte_table_hash_key32_ext_ops;
 
-/** Cuckoo hash table parameters */
-struct rte_table_hash_cuckoo_params {
-    /** Key size (number of bytes */
-		uint32_t key_size;
-
-	/** Maximum number of hash table entries */
-	uint32_t n_keys;
-
-	/** Hash function used to calculate hash */
-	rte_table_hash_op_hash f_hash;
-
-	/** Seed value or Init value used by f_hash */
-	uint32_t seed;
-
-	/** Byte offset within packet meta-data where the 4-byte key signature
-	is located. Valid for pre-computed key signature tables, ignored for
-	do-sig tables. */
-	uint32_t signature_offset;
-
-	/** Byte offset within packet meta-data where the key is located */
-	uint32_t key_offset;
-
-	/** Hash table name */
-	const char *name;
-};
+/** LRU hash table operations */
+extern struct rte_table_ops rte_table_hash_lru_ops;
+extern struct rte_table_ops rte_table_hash_key8_lru_ops;
+extern struct rte_table_ops rte_table_hash_key16_lru_ops;
+extern struct rte_table_ops rte_table_hash_key32_lru_ops;
 
 /** Cuckoo hash table operations */
-extern struct rte_table_ops rte_table_hash_cuckoo_dosig_ops;
+extern struct rte_table_ops rte_table_hash_cuckoo_ops;
 
 #ifdef __cplusplus
 }
diff --git a/lib/librte_table/rte_table_hash_cuckoo.c b/lib/librte_table/rte_table_hash_cuckoo.c
index da1597f..f3845c7 100644
--- a/lib/librte_table/rte_table_hash_cuckoo.c
+++ b/lib/librte_table/rte_table_hash_cuckoo.c
@@ -1,34 +1,34 @@
 /*-
- *	 BSD LICENSE
+ *   BSD LICENSE
  *
- *	 Copyright(c) 2016 Intel Corporation. All rights reserved.
- *	 All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
  *
- *	 Redistribution and use in source and binary forms, with or without
- *	 modification, are permitted provided that the following conditions
- *	 are met:
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
  *
- *	* Redistributions of source code must retain the above copyright
- *		 notice, this list of conditions and the following disclaimer.
- *	* Redistributions in binary form must reproduce the above copyright
- *		 notice, this list of conditions and the following disclaimer in
- *		 the documentation and/or other materials provided with the
- *		 distribution.
- *	* Neither the name of Intel Corporation nor the names of its
- *		 contributors may be used to endorse or promote products derived
- *		 from this software without specific prior written permission.
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
  *
- *	 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *	 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *	 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *	 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *	 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *	 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *	 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *	 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *	 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *	 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *	 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <string.h>
 #include <stdio.h>
@@ -66,25 +66,28 @@ struct rte_table_hash {
 	uint32_t n_keys;
 	rte_table_hash_op_hash f_hash;
 	uint32_t seed;
-	uint32_t signature_offset;
 	uint32_t key_offset;
-	const char *name;
 
 	/* cuckoo hash table object */
 	struct rte_hash *h_table;
 
 	/* Lookup table */
-	uint8_t memory[0] __rte_cache_aligned; };
+	uint8_t memory[0] __rte_cache_aligned;
+};
 
 static int
-check_params_create_hash_cuckoo(const struct
-rte_table_hash_cuckoo_params *params) {
-	/* Check for valid parameters */
+check_params_create_hash_cuckoo(struct rte_table_hash_params *params)
+{
 	if (params == NULL) {
 		RTE_LOG(ERR, TABLE, "NULL Input Parameters.\n");
 		return -EINVAL;
 	}
 
+	if (params->name == NULL) {
+		RTE_LOG(ERR, TABLE, "Table name is NULL.\n");
+		return -EINVAL;
+	}
+
 	if (params->key_size == 0) {
 		RTE_LOG(ERR, TABLE, "Invalid key_size.\n");
 		return -EINVAL;
@@ -100,11 +103,6 @@ rte_table_hash_cuckoo_params *params) {
 		return -EINVAL;
 	}
 
-	if (params->name == NULL) {
-		RTE_LOG(ERR, TABLE, "Table name is NULL.\n");
-		return -EINVAL;
-	}
-
 	return 0;
 }
 
@@ -113,34 +111,24 @@ rte_table_hash_cuckoo_create(void *params,
 			int socket_id,
 			uint32_t entry_size)
 {
-	struct rte_hash *rte_hash_handle;
+	struct rte_table_hash_params *p = params;
+	struct rte_hash *h_table;
 	struct rte_table_hash *t;
-	uint32_t total_size, total_cl_size;
+	uint32_t total_size;
 
 	/* Check input parameters */
-	struct rte_table_hash_cuckoo_params *p =
-		(struct rte_table_hash_cuckoo_params *) params;
-
 	if (check_params_create_hash_cuckoo(params))
 		return NULL;
 
 	/* Memory allocation */
-	total_cl_size =
-		(sizeof(struct rte_table_hash) +
-		 RTE_CACHE_LINE_SIZE) / RTE_CACHE_LINE_SIZE;
-	total_cl_size += (p->n_keys * entry_size +
-			RTE_CACHE_LINE_SIZE) / RTE_CACHE_LINE_SIZE;
-	total_size = total_cl_size * RTE_CACHE_LINE_SIZE;
-
-	t = rte_zmalloc_socket("TABLE",
-			total_size,
-			RTE_CACHE_LINE_SIZE,
-			socket_id);
+	total_size = sizeof(struct rte_table_hash) +
+		RTE_CACHE_LINE_ROUNDUP(p->n_keys * entry_size);
+
+	t = rte_zmalloc_socket(p->name, total_size, RTE_CACHE_LINE_SIZE, socket_id);
 	if (t == NULL) {
 		RTE_LOG(ERR, TABLE,
-			"%s: Cannot allocate %u bytes for Cuckoo hash table\n",
-			__func__,
-			(uint32_t)sizeof(struct rte_table_hash));
+			"%s: Cannot allocate %u bytes for cuckoo hash table %s\n",
+			__func__, total_size, p->name);
 		return NULL;
 	}
 
@@ -154,13 +142,13 @@ rte_table_hash_cuckoo_create(void *params,
 		.name = p->name
 	};
 
-	rte_hash_handle = rte_hash_find_existing(p->name);
-	if (rte_hash_handle == NULL) {
-		rte_hash_handle = rte_hash_create(&hash_cuckoo_params);
-		if (NULL == rte_hash_handle) {
+	h_table = rte_hash_find_existing(p->name);
+	if (h_table == NULL) {
+		h_table = rte_hash_create(&hash_cuckoo_params);
+		if (h_table == NULL) {
 			RTE_LOG(ERR, TABLE,
-				"%s: failed to create cuckoo hash table. keysize: %u",
-				__func__, hash_cuckoo_params.key_len);
+				"%s: failed to create cuckoo hash table %s\n",
+				__func__, p->name);
 			rte_free(t);
 			return NULL;
 		}
@@ -172,26 +160,22 @@ rte_table_hash_cuckoo_create(void *params,
 	t->n_keys = p->n_keys;
 	t->f_hash = p->f_hash;
 	t->seed = p->seed;
-	t->signature_offset = p->signature_offset;
 	t->key_offset = p->key_offset;
-	t->name = p->name;
-	t->h_table = rte_hash_handle;
+	t->h_table = h_table;
 
 	RTE_LOG(INFO, TABLE,
-		"%s: Cuckoo Hash table memory footprint is %u bytes\n",
-		__func__, total_size);
+		"%s: Cuckoo hash table %s memory footprint is %u bytes\n",
+		__func__, p->name, total_size);
 	return t;
 }
 
 static int
 rte_table_hash_cuckoo_free(void *table) {
-	if (table == NULL) {
-		RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
-		return -EINVAL;
-	}
-
 	struct rte_table_hash *t = table;
 
+	if (table == NULL)
+		return -EINVAL;
+
 	rte_hash_free(t->h_table);
 	rte_free(t);
 
@@ -200,25 +184,18 @@ rte_table_hash_cuckoo_free(void *table) {
 
 static int
 rte_table_hash_cuckoo_entry_add(void *table, void *key, void *entry,
-		int *key_found, void **entry_ptr) {
+	int *key_found, void **entry_ptr)
+{
+	struct rte_table_hash *t = table;
 	int pos = 0;
 
-	if (table == NULL) {
-		RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
-		return -EINVAL;
-	}
-
-	if (key == NULL) {
-		RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
-		return -EINVAL;
-	}
-
-	if (entry == NULL) {
-		RTE_LOG(ERR, TABLE, "%s: entry parameter is NULL\n", __func__);
+	/* Check input parameters */
+	if ((table == NULL) ||
+		(key == NULL) ||
+		(entry == NULL) ||
+		(key_found == NULL) ||
+		(entry_ptr == NULL))
 		return -EINVAL;
-	}
-
-	struct rte_table_hash *t = table;
 
 	/*  Find Existing entries */
 	pos = rte_hash_lookup(t->h_table, key);
@@ -231,17 +208,15 @@ rte_table_hash_cuckoo_entry_add(void *table, void *key, void *entry,
 		*entry_ptr = existing_entry;
 
 		return 0;
-} else if (pos == -ENOENT) {
-	/* Entry not found. Adding new entry */
+	}
+
+	if (pos == -ENOENT) {
+		/* Entry not found. Adding new entry */
 		uint8_t *new_entry;
 
 		pos = rte_hash_add_key(t->h_table, key);
-		if (pos < 0) {
-			RTE_LOG(ERR, TABLE,
-				"%s: Entry not added, status : %u\n",
-				__func__, pos);
+		if (pos < 0)
 			return pos;
-		}
 
 		new_entry = &t->memory[pos * t->entry_size];
 		memcpy(new_entry, entry, t->entry_size);
@@ -250,25 +225,22 @@ rte_table_hash_cuckoo_entry_add(void *table, void *key, void *entry,
 		*entry_ptr = new_entry;
 		return 0;
 	}
+
 	return pos;
 }
 
 static int
 rte_table_hash_cuckoo_entry_delete(void *table, void *key,
-		int *key_found, __rte_unused void *entry) {
+	int *key_found, void *entry)
+{
+	struct rte_table_hash *t = table;
 	int pos = 0;
 
-	if (table == NULL) {
-		RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
-		return -EINVAL;
-	}
-
-	if (key == NULL) {
-		RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
+	/* Check input parameters */
+	if ((table == NULL) ||
+		(key == NULL) ||
+		(key_found == NULL))
 		return -EINVAL;
-	}
-
-	struct rte_table_hash *t = table;
 
 	pos = rte_hash_del_key(t->h_table, key);
 	if (pos >= 0) {
@@ -279,20 +251,21 @@ rte_table_hash_cuckoo_entry_delete(void *table, void *key,
 			memcpy(entry, entry_ptr, t->entry_size);
 
 		memset(&t->memory[pos * t->entry_size], 0, t->entry_size);
+		return 0;
 	}
 
+	*key_found = 0;
 	return pos;
 }
 
-
 static int
-rte_table_hash_cuckoo_lookup_dosig(void *table,
+rte_table_hash_cuckoo_lookup(void *table,
 	struct rte_mbuf **pkts,
 	uint64_t pkts_mask,
 	uint64_t *lookup_hit_mask,
 	void **entries)
 {
-	struct rte_table_hash *t = (struct rte_table_hash *)table;
+	struct rte_table_hash *t = table;
 	uint64_t pkts_mask_out = 0;
 	uint32_t i;
 
@@ -301,20 +274,19 @@ rte_table_hash_cuckoo_lookup_dosig(void *table,
 	RTE_TABLE_HASH_CUCKOO_STATS_PKTS_IN_ADD(t, n_pkts_in);
 
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
-		const uint8_t *keys[64];
-		int32_t positions[64], status;
+		const uint8_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
+		int32_t positions[RTE_PORT_IN_BURST_SIZE_MAX], status;
 
 		/* Keys for bulk lookup */
 		for (i = 0; i < n_pkts_in; i++)
 			keys[i] = RTE_MBUF_METADATA_UINT8_PTR(pkts[i],
-					t->key_offset);
+				t->key_offset);
 
 		/* Bulk Lookup */
 		status = rte_hash_lookup_bulk(t->h_table,
 				(const void **) keys,
 				n_pkts_in,
 				positions);
-
 		if (status == 0) {
 			for (i = 0; i < n_pkts_in; i++) {
 				if (likely(positions[i] >= 0)) {
@@ -326,7 +298,7 @@ rte_table_hash_cuckoo_lookup_dosig(void *table,
 				}
 			}
 		}
-	} else {
+	} else
 		for (i = 0; i < (uint32_t)(RTE_PORT_IN_BURST_SIZE_MAX
 					- __builtin_clzll(pkts_mask)); i++) {
 			uint64_t pkt_mask = 1LLU << i;
@@ -345,7 +317,6 @@ rte_table_hash_cuckoo_lookup_dosig(void *table,
 				}
 			}
 		}
-	}
 
 	*lookup_hit_mask = pkts_mask_out;
 	RTE_TABLE_HASH_CUCKOO_STATS_PKTS_LOOKUP_MISS(t,
@@ -370,13 +341,13 @@ rte_table_hash_cuckoo_stats_read(void *table, struct rte_table_stats *stats,
 	return 0;
 }
 
-struct rte_table_ops rte_table_hash_cuckoo_dosig_ops = {
+struct rte_table_ops rte_table_hash_cuckoo_ops = {
 	.f_create = rte_table_hash_cuckoo_create,
 	.f_free = rte_table_hash_cuckoo_free,
 	.f_add = rte_table_hash_cuckoo_entry_add,
 	.f_delete = rte_table_hash_cuckoo_entry_delete,
 	.f_add_bulk = NULL,
 	.f_delete_bulk = NULL,
-	.f_lookup = rte_table_hash_cuckoo_lookup_dosig,
+	.f_lookup = rte_table_hash_cuckoo_lookup,
 	.f_stats = rte_table_hash_cuckoo_stats_read,
 };
diff --git a/lib/librte_table/rte_table_hash_ext.c b/lib/librte_table/rte_table_hash_ext.c
index e718102..3af1bca 100644
--- a/lib/librte_table/rte_table_hash_ext.c
+++ b/lib/librte_table/rte_table_hash_ext.c
@@ -1,34 +1,34 @@
 /*-
- *	 BSD LICENSE
+ *   BSD LICENSE
  *
- *	 Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *	 All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
  *
- *	 Redistribution and use in source and binary forms, with or without
- *	 modification, are permitted provided that the following conditions
- *	 are met:
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
  *
- *	* Redistributions of source code must retain the above copyright
- *		 notice, this list of conditions and the following disclaimer.
- *	* Redistributions in binary form must reproduce the above copyright
- *		 notice, this list of conditions and the following disclaimer in
- *		 the documentation and/or other materials provided with the
- *		 distribution.
- *	* Neither the name of Intel Corporation nor the names of its
- *		 contributors may be used to endorse or promote products derived
- *		 from this software without specific prior written permission.
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
  *
- *	 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *	 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *	 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *	 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *	 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *	 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *	 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *	 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *	 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *	 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *	 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <string.h>
@@ -106,7 +106,6 @@ struct rte_table_hash {
 	uint32_t n_buckets_ext;
 	rte_table_hash_op_hash f_hash;
 	uint64_t seed;
-	uint32_t signature_offset;
 	uint32_t key_offset;
 
 	/* Internal */
@@ -120,6 +119,7 @@ struct rte_table_hash {
 	struct grinder grinders[RTE_PORT_IN_BURST_SIZE_MAX];
 
 	/* Tables */
+	uint64_t *key_mask;
 	struct bucket *buckets;
 	struct bucket *buckets_ext;
 	uint8_t *key_mem;
@@ -132,29 +132,53 @@ struct rte_table_hash {
 };
 
 static int
-check_params_create(struct rte_table_hash_ext_params *params)
+keycmp(void *a, void *b, void *b_mask, uint32_t n_bytes)
 {
-	uint32_t n_buckets_min;
+	uint64_t *a64 = a, *b64 = b, *b_mask64 = b_mask;
+	uint32_t i;
+
+	for (i = 0; i < n_bytes / sizeof(uint64_t); i++)
+		if (a64[i] != (b64[i] & b_mask64[i]))
+			return 1;
+
+	return 0;
+}
+
+static void
+keycpy(void *dst, void *src, void *src_mask, uint32_t n_bytes)
+{
+	uint64_t *dst64 = dst, *src64 = src, *src_mask64 = src_mask;
+	uint32_t i;
+
+	for (i = 0; i < n_bytes / sizeof(uint64_t); i++)
+		dst64[i] = src64[i] & src_mask64[i];
+}
+
+static int
+check_params_create(struct rte_table_hash_params *params)
+{
+	/* name */
+	if (params->name == NULL) {
+		RTE_LOG(ERR, TABLE, "%s: name invalid value\n", __func__);
+		return -EINVAL;
+	}
 
 	/* key_size */
-	if ((params->key_size == 0) ||
+	if ((params->key_size < sizeof(uint64_t)) ||
 		(!rte_is_power_of_2(params->key_size))) {
 		RTE_LOG(ERR, TABLE, "%s: key_size invalid value\n", __func__);
 		return -EINVAL;
 	}
 
 	/* n_keys */
-	if ((params->n_keys == 0) ||
-		(!rte_is_power_of_2(params->n_keys))) {
+	if (params->n_keys == 0) {
 		RTE_LOG(ERR, TABLE, "%s: n_keys invalid value\n", __func__);
 		return -EINVAL;
 	}
 
 	/* n_buckets */
-	n_buckets_min = (params->n_keys + KEYS_PER_BUCKET - 1) / params->n_keys;
 	if ((params->n_buckets == 0) ||
-		(!rte_is_power_of_2(params->n_keys)) ||
-		(params->n_buckets < n_buckets_min)) {
+		(!rte_is_power_of_2(params->n_buckets))) {
 		RTE_LOG(ERR, TABLE, "%s: n_buckets invalid value\n", __func__);
 		return -EINVAL;
 	}
@@ -171,15 +195,13 @@ check_params_create(struct rte_table_hash_ext_params *params)
 static void *
 rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)
 {
-	struct rte_table_hash_ext_params *p =
-		params;
+	struct rte_table_hash_params *p = params;
 	struct rte_table_hash *t;
-	uint32_t total_size, table_meta_sz;
-	uint32_t bucket_sz, bucket_ext_sz, key_sz;
-	uint32_t key_stack_sz, bkt_ext_stack_sz, data_sz;
-	uint32_t bucket_offset, bucket_ext_offset, key_offset;
-	uint32_t key_stack_offset, bkt_ext_stack_offset, data_offset;
-	uint32_t i;
+	uint64_t table_meta_sz, key_mask_sz, bucket_sz, bucket_ext_sz, key_sz;
+	uint64_t key_stack_sz, bkt_ext_stack_sz, data_sz, total_size;
+	uint64_t key_mask_offset, bucket_offset, bucket_ext_offset, key_offset;
+	uint64_t key_stack_offset, bkt_ext_stack_offset, data_offset;
+	uint32_t n_buckets_ext, i;
 
 	/* Check input parameters */
 	if ((check_params_create(p) != 0) ||
@@ -188,38 +210,66 @@ rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)
 		(sizeof(struct bucket) != (RTE_CACHE_LINE_SIZE / 2)))
 		return NULL;
 
+	/*
+	 * Table dimensioning
+	 *
+	 * Objective: Pick the number of bucket extensions (n_buckets_ext) so that
+	 * it is guaranteed that n_keys keys can be stored in the table at any time.
+	 *
+	 * The worst case scenario takes place when all the n_keys keys fall into
+	 * the same bucket. Actually, due to the KEYS_PER_BUCKET scheme, the worst
+	 * case takes place when (n_keys - KEYS_PER_BUCKET + 1) keys fall into the
+	 * same bucket, while the remaining (KEYS_PER_BUCKET - 1) keys each fall
+	 * into a different bucket. This case defeats the purpose of the hash table.
+	 * It indicates unsuitable f_hash or n_keys to n_buckets ratio.
+	 *
+	 * n_buckets_ext = n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1
+	 */
+	n_buckets_ext = p->n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1;
+
 	/* Memory allocation */
 	table_meta_sz = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_table_hash));
+	key_mask_sz = RTE_CACHE_LINE_ROUNDUP(p->key_size);
 	bucket_sz = RTE_CACHE_LINE_ROUNDUP(p->n_buckets * sizeof(struct bucket));
 	bucket_ext_sz =
-		RTE_CACHE_LINE_ROUNDUP(p->n_buckets_ext * sizeof(struct bucket));
+		RTE_CACHE_LINE_ROUNDUP(n_buckets_ext * sizeof(struct bucket));
 	key_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * p->key_size);
 	key_stack_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * sizeof(uint32_t));
 	bkt_ext_stack_sz =
-		RTE_CACHE_LINE_ROUNDUP(p->n_buckets_ext * sizeof(uint32_t));
+		RTE_CACHE_LINE_ROUNDUP(n_buckets_ext * sizeof(uint32_t));
 	data_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * entry_size);
-	total_size = table_meta_sz + bucket_sz + bucket_ext_sz + key_sz +
-		key_stack_sz + bkt_ext_stack_sz + data_sz;
+	total_size = table_meta_sz + key_mask_sz + bucket_sz + bucket_ext_sz +
+		key_sz + key_stack_sz + bkt_ext_stack_sz + data_sz;
 
-	t = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
+	if (total_size > SIZE_MAX) {
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes"
+			" for hash table %s\n",
+			__func__, total_size, p->name);
+		return NULL;
+	}
+
+	t = rte_zmalloc_socket(p->name,
+		(size_t)total_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (t == NULL) {
-		RTE_LOG(ERR, TABLE,
-			"%s: Cannot allocate %u bytes for hash table\n",
-			__func__, total_size);
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes"
+			" for hash table %s\n",
+			__func__, total_size, p->name);
 		return NULL;
 	}
-	RTE_LOG(INFO, TABLE, "%s (%u-byte key): Hash table memory footprint is "
-		"%u bytes\n", __func__, p->key_size, total_size);
+	RTE_LOG(INFO, TABLE, "%s (%u-byte key): Hash table %s memory "
+		"footprint is %" PRIu64 " bytes\n",
+		__func__, p->key_size, p->name, total_size);
 
 	/* Memory initialization */
 	t->key_size = p->key_size;
 	t->entry_size = entry_size;
 	t->n_keys = p->n_keys;
 	t->n_buckets = p->n_buckets;
-	t->n_buckets_ext = p->n_buckets_ext;
+	t->n_buckets_ext = n_buckets_ext;
 	t->f_hash = p->f_hash;
 	t->seed = p->seed;
-	t->signature_offset = p->signature_offset;
 	t->key_offset = p->key_offset;
 
 	/* Internal */
@@ -228,13 +278,15 @@ rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)
 	t->data_size_shl = __builtin_ctzl(entry_size);
 
 	/* Tables */
-	bucket_offset = 0;
+	key_mask_offset = 0;
+	bucket_offset = key_mask_offset + key_mask_sz;
 	bucket_ext_offset = bucket_offset + bucket_sz;
 	key_offset = bucket_ext_offset + bucket_ext_sz;
 	key_stack_offset = key_offset + key_sz;
 	bkt_ext_stack_offset = key_stack_offset + key_stack_sz;
 	data_offset = bkt_ext_stack_offset + bkt_ext_stack_sz;
 
+	t->key_mask = (uint64_t *) &t->memory[key_mask_offset];
 	t->buckets = (struct bucket *) &t->memory[bucket_offset];
 	t->buckets_ext = (struct bucket *) &t->memory[bucket_ext_offset];
 	t->key_mem = &t->memory[key_offset];
@@ -242,6 +294,12 @@ rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)
 	t->bkt_ext_stack = (uint32_t *) &t->memory[bkt_ext_stack_offset];
 	t->data_mem = &t->memory[data_offset];
 
+	/* Key mask */
+	if (p->key_mask == NULL)
+		memset(t->key_mask, 0xFF, p->key_size);
+	else
+		memcpy(t->key_mask, p->key_mask, p->key_size);
+
 	/* Key stack */
 	for (i = 0; i < t->n_keys; i++)
 		t->key_stack[i] = t->n_keys - 1 - i;
@@ -277,7 +335,7 @@ rte_table_hash_ext_entry_add(void *table, void *key, void *entry,
 	uint64_t sig;
 	uint32_t bkt_index, i;
 
-	sig = t->f_hash(key, t->key_size, t->seed);
+	sig = t->f_hash(key, t->key_mask, t->key_size, t->seed);
 	bkt_index = sig & t->bucket_mask;
 	bkt0 = &t->buckets[bkt_index];
 	sig = (sig >> 16) | 1LLU;
@@ -290,7 +348,7 @@ rte_table_hash_ext_entry_add(void *table, void *key, void *entry,
 			uint8_t *bkt_key =
 				&t->key_mem[bkt_key_index << t->key_size_shl];
 
-			if ((sig == bkt_sig) && (memcmp(key, bkt_key,
+			if ((sig == bkt_sig) && (keycmp(bkt_key, key, t->key_mask,
 				t->key_size) == 0)) {
 				uint8_t *data = &t->data_mem[bkt_key_index <<
 					t->data_size_shl];
@@ -327,7 +385,7 @@ rte_table_hash_ext_entry_add(void *table, void *key, void *entry,
 
 				bkt->sig[i] = (uint16_t) sig;
 				bkt->key_pos[i] = bkt_key_index;
-				memcpy(bkt_key, key, t->key_size);
+				keycpy(bkt_key, key, t->key_mask, t->key_size);
 				memcpy(data, entry, t->entry_size);
 
 				*key_found = 0;
@@ -358,7 +416,7 @@ rte_table_hash_ext_entry_add(void *table, void *key, void *entry,
 		/* Install new key into bucket */
 		bkt->sig[0] = (uint16_t) sig;
 		bkt->key_pos[0] = bkt_key_index;
-		memcpy(bkt_key, key, t->key_size);
+		keycpy(bkt_key, key, t->key_mask, t->key_size);
 		memcpy(data, entry, t->entry_size);
 
 		*key_found = 0;
@@ -378,7 +436,7 @@ void *entry)
 	uint64_t sig;
 	uint32_t bkt_index, i;
 
-	sig = t->f_hash(key, t->key_size, t->seed);
+	sig = t->f_hash(key, t->key_mask, t->key_size, t->seed);
 	bkt_index = sig & t->bucket_mask;
 	bkt0 = &t->buckets[bkt_index];
 	sig = (sig >> 16) | 1LLU;
@@ -392,7 +450,7 @@ void *entry)
 			uint8_t *bkt_key = &t->key_mem[bkt_key_index <<
 				t->key_size_shl];
 
-			if ((sig == bkt_sig) && (memcmp(key, bkt_key,
+			if ((sig == bkt_sig) && (keycmp(bkt_key, key, t->key_mask,
 				t->key_size) == 0)) {
 				uint8_t *data = &t->data_mem[bkt_key_index <<
 					t->data_size_shl];
@@ -437,8 +495,7 @@ static int rte_table_hash_ext_lookup_unoptimized(
 	struct rte_mbuf **pkts,
 	uint64_t pkts_mask,
 	uint64_t *lookup_hit_mask,
-	void **entries,
-	int dosig)
+	void **entries)
 {
 	struct rte_table_hash *t = (struct rte_table_hash *) table;
 	uint64_t pkts_mask_out = 0;
@@ -458,11 +515,7 @@ static int rte_table_hash_ext_lookup_unoptimized(
 
 		pkt = pkts[pkt_index];
 		key = RTE_MBUF_METADATA_UINT8_PTR(pkt, t->key_offset);
-		if (dosig)
-			sig = (uint64_t) t->f_hash(key, t->key_size, t->seed);
-		else
-			sig = RTE_MBUF_METADATA_UINT32(pkt,
-				t->signature_offset);
+		sig = (uint64_t) t->f_hash(key, t->key_mask, t->key_size, t->seed);
 
 		bkt_index = sig & t->bucket_mask;
 		bkt0 = &t->buckets[bkt_index];
@@ -476,8 +529,8 @@ static int rte_table_hash_ext_lookup_unoptimized(
 				uint8_t *bkt_key = &t->key_mem[bkt_key_index <<
 					t->key_size_shl];
 
-				if ((sig == bkt_sig) && (memcmp(key, bkt_key,
-					t->key_size) == 0)) {
+				if ((sig == bkt_sig) && (keycmp(bkt_key, key,
+					t->key_mask, t->key_size) == 0)) {
 					uint8_t *data = &t->data_mem[
 					bkt_key_index << t->data_size_shl];
 
@@ -576,11 +629,12 @@ static int rte_table_hash_ext_lookup_unoptimized(
 {									\
 	uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(mbuf, f->key_offset);\
 	uint64_t *bkt_key = (uint64_t *) key;				\
+	uint64_t *key_mask = f->key_mask;					\
 									\
 	switch (f->key_size) {						\
 	case 8:								\
 	{								\
-		uint64_t xor = pkt_key[0] ^ bkt_key[0];			\
+		uint64_t xor = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];	\
 		match_key = 0;						\
 		if (xor == 0)						\
 			match_key = 1;					\
@@ -591,8 +645,8 @@ static int rte_table_hash_ext_lookup_unoptimized(
 	{								\
 		uint64_t xor[2], or;					\
 									\
-		xor[0] = pkt_key[0] ^ bkt_key[0];			\
-		xor[1] = pkt_key[1] ^ bkt_key[1];			\
+		xor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];		\
+		xor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];		\
 		or = xor[0] | xor[1];					\
 		match_key = 0;						\
 		if (or == 0)						\
@@ -604,10 +658,10 @@ static int rte_table_hash_ext_lookup_unoptimized(
 	{								\
 		uint64_t xor[4], or;					\
 									\
-		xor[0] = pkt_key[0] ^ bkt_key[0];			\
-		xor[1] = pkt_key[1] ^ bkt_key[1];			\
-		xor[2] = pkt_key[2] ^ bkt_key[2];			\
-		xor[3] = pkt_key[3] ^ bkt_key[3];			\
+		xor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];		\
+		xor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];		\
+		xor[2] = (pkt_key[2] & key_mask[2]) ^ bkt_key[2];		\
+		xor[3] = (pkt_key[3] & key_mask[3]) ^ bkt_key[3];		\
 		or = xor[0] | xor[1] | xor[2] | xor[3];			\
 		match_key = 0;						\
 		if (or == 0)						\
@@ -619,14 +673,14 @@ static int rte_table_hash_ext_lookup_unoptimized(
 	{								\
 		uint64_t xor[8], or;					\
 									\
-		xor[0] = pkt_key[0] ^ bkt_key[0];			\
-		xor[1] = pkt_key[1] ^ bkt_key[1];			\
-		xor[2] = pkt_key[2] ^ bkt_key[2];			\
-		xor[3] = pkt_key[3] ^ bkt_key[3];			\
-		xor[4] = pkt_key[4] ^ bkt_key[4];			\
-		xor[5] = pkt_key[5] ^ bkt_key[5];			\
-		xor[6] = pkt_key[6] ^ bkt_key[6];			\
-		xor[7] = pkt_key[7] ^ bkt_key[7];			\
+		xor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];		\
+		xor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];		\
+		xor[2] = (pkt_key[2] & key_mask[2]) ^ bkt_key[2];		\
+		xor[3] = (pkt_key[3] & key_mask[3]) ^ bkt_key[3];		\
+		xor[4] = (pkt_key[4] & key_mask[4]) ^ bkt_key[4];		\
+		xor[5] = (pkt_key[5] & key_mask[5]) ^ bkt_key[5];		\
+		xor[6] = (pkt_key[6] & key_mask[6]) ^ bkt_key[6];		\
+		xor[7] = (pkt_key[7] & key_mask[7]) ^ bkt_key[7];		\
 		or = xor[0] | xor[1] | xor[2] | xor[3] |		\
 			xor[4] | xor[5] | xor[6] | xor[7];		\
 		match_key = 0;						\
@@ -637,7 +691,7 @@ static int rte_table_hash_ext_lookup_unoptimized(
 									\
 	default:							\
 		match_key = 0;						\
-		if (memcmp(pkt_key, bkt_key, f->key_size) == 0)		\
+		if (keycmp(bkt_key, pkt_key, key_mask, f->key_size) == 0)	\
 			match_key = 1;					\
 	}								\
 }
@@ -685,38 +739,7 @@ static int rte_table_hash_ext_lookup_unoptimized(
 	rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset));\
 }
 
-#define lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index)		\
-{									\
-	struct grinder *g10, *g11;					\
-	uint64_t sig10, sig11, bkt10_index, bkt11_index;		\
-	struct rte_mbuf *mbuf10, *mbuf11;				\
-	struct bucket *bkt10, *bkt11, *buckets = t->buckets;		\
-	uint64_t bucket_mask = t->bucket_mask;				\
-	uint32_t signature_offset = t->signature_offset;		\
-									\
-	mbuf10 = pkts[pkt10_index];					\
-	sig10 = (uint64_t) RTE_MBUF_METADATA_UINT32(mbuf10, signature_offset);\
-	bkt10_index = sig10 & bucket_mask;				\
-	bkt10 = &buckets[bkt10_index];					\
-									\
-	mbuf11 = pkts[pkt11_index];					\
-	sig11 = (uint64_t) RTE_MBUF_METADATA_UINT32(mbuf11, signature_offset);\
-	bkt11_index = sig11 & bucket_mask;				\
-	bkt11 = &buckets[bkt11_index];					\
-									\
-	rte_prefetch0(bkt10);						\
-	rte_prefetch0(bkt11);						\
-									\
-	g10 = &g[pkt10_index];						\
-	g10->sig = sig10;						\
-	g10->bkt = bkt10;						\
-									\
-	g11 = &g[pkt11_index];						\
-	g11->sig = sig11;						\
-	g11->bkt = bkt11;						\
-}
-
-#define lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index)	\
+#define lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index)	\
 {									\
 	struct grinder *g10, *g11;					\
 	uint64_t sig10, sig11, bkt10_index, bkt11_index;		\
@@ -731,13 +754,13 @@ static int rte_table_hash_ext_lookup_unoptimized(
 									\
 	mbuf10 = pkts[pkt10_index];					\
 	key10 = RTE_MBUF_METADATA_UINT8_PTR(mbuf10, key_offset);	\
-	sig10 = (uint64_t) f_hash(key10, key_size, seed);		\
+	sig10 = (uint64_t) f_hash(key10, t->key_mask, key_size, seed);	\
 	bkt10_index = sig10 & bucket_mask;				\
 	bkt10 = &buckets[bkt10_index];					\
 									\
 	mbuf11 = pkts[pkt11_index];					\
 	key11 = RTE_MBUF_METADATA_UINT8_PTR(mbuf11, key_offset);	\
-	sig11 = (uint64_t) f_hash(key11, key_size, seed);		\
+	sig11 = (uint64_t) f_hash(key11, t->key_mask, key_size, seed);	\
 	bkt11_index = sig11 & bucket_mask;				\
 	bkt11 = &buckets[bkt11_index];					\
 									\
@@ -874,7 +897,7 @@ static int rte_table_hash_ext_lookup(
 	/* Cannot run the pipeline with less than 7 packets */
 	if (__builtin_popcountll(pkts_mask) < 7) {
 		status = rte_table_hash_ext_lookup_unoptimized(table, pkts,
-			pkts_mask, lookup_hit_mask, entries, 0);
+			pkts_mask, lookup_hit_mask, entries);
 		RTE_TABLE_HASH_EXT_STATS_PKTS_LOOKUP_MISS(t, n_pkts_in -
 				__builtin_popcountll(*lookup_hit_mask));
 		return status;
@@ -982,144 +1005,7 @@ static int rte_table_hash_ext_lookup(
 		uint64_t pkts_mask_out_slow = 0;
 
 		status = rte_table_hash_ext_lookup_unoptimized(table, pkts,
-			pkts_mask_match_many, &pkts_mask_out_slow, entries, 0);
-		pkts_mask_out |= pkts_mask_out_slow;
-	}
-
-	*lookup_hit_mask = pkts_mask_out;
-	RTE_TABLE_HASH_EXT_STATS_PKTS_LOOKUP_MISS(t, n_pkts_in - __builtin_popcountll(pkts_mask_out));
-	return status;
-}
-
-static int rte_table_hash_ext_lookup_dosig(
-	void *table,
-	struct rte_mbuf **pkts,
-	uint64_t pkts_mask,
-	uint64_t *lookup_hit_mask,
-	void **entries)
-{
-	struct rte_table_hash *t = (struct rte_table_hash *) table;
-	struct grinder *g = t->grinders;
-	uint64_t pkt00_index, pkt01_index, pkt10_index, pkt11_index;
-	uint64_t pkt20_index, pkt21_index, pkt30_index, pkt31_index;
-	uint64_t pkts_mask_out = 0, pkts_mask_match_many = 0;
-	int status = 0;
-
-	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
-	RTE_TABLE_HASH_EXT_STATS_PKTS_IN_ADD(t, n_pkts_in);
-
-	/* Cannot run the pipeline with less than 7 packets */
-	if (__builtin_popcountll(pkts_mask) < 7) {
-		status = rte_table_hash_ext_lookup_unoptimized(table, pkts,
-			pkts_mask, lookup_hit_mask, entries, 1);
-		RTE_TABLE_HASH_EXT_STATS_PKTS_LOOKUP_MISS(t, n_pkts_in -
-				__builtin_popcountll(*lookup_hit_mask));
-		return status;
-	}
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
-
-	/* Pipeline feed */
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
-
-	/* Pipeline feed */
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
-
-	/* Pipeline stage 2 */
-	lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
-
-	/*
-	* Pipeline run
-	*
-	*/
-	for ( ; pkts_mask; ) {
-		/* Pipeline feed */
-		pkt30_index = pkt20_index;
-		pkt31_index = pkt21_index;
-		pkt20_index = pkt10_index;
-		pkt21_index = pkt11_index;
-		pkt10_index = pkt00_index;
-		pkt11_index = pkt01_index;
-
-		/* Pipeline stage 0 */
-		lookup2_stage0_with_odd_support(t, g, pkts, pkts_mask,
-			pkt00_index, pkt01_index);
-
-		/* Pipeline stage 1 */
-		lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
-
-		/* Pipeline stage 2 */
-		lookup2_stage2(t, g, pkt20_index, pkt21_index,
-			pkts_mask_match_many);
-
-		/* Pipeline stage 3 */
-		lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index,
-			pkts_mask_out, entries);
-	}
-
-	/* Pipeline feed */
-	pkt30_index = pkt20_index;
-	pkt31_index = pkt21_index;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
-
-	/* Pipeline stage 2 */
-	lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
-
-	/* Pipeline stage 3 */
-	lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
-		entries);
-
-	/* Pipeline feed */
-	pkt30_index = pkt20_index;
-	pkt31_index = pkt21_index;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-
-	/* Pipeline stage 2 */
-	lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
-
-	/* Pipeline stage 3 */
-	lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
-		entries);
-
-	/* Pipeline feed */
-	pkt30_index = pkt20_index;
-	pkt31_index = pkt21_index;
-
-	/* Pipeline stage 3 */
-	lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
-		entries);
-
-	/* Slow path */
-	pkts_mask_match_many &= ~pkts_mask_out;
-	if (pkts_mask_match_many) {
-		uint64_t pkts_mask_out_slow = 0;
-
-		status = rte_table_hash_ext_lookup_unoptimized(table, pkts,
-			pkts_mask_match_many, &pkts_mask_out_slow, entries, 1);
+			pkts_mask_match_many, &pkts_mask_out_slow, entries);
 		pkts_mask_out |= pkts_mask_out_slow;
 	}
 
@@ -1152,14 +1038,3 @@ struct rte_table_ops rte_table_hash_ext_ops	 = {
 	.f_lookup = rte_table_hash_ext_lookup,
 	.f_stats = rte_table_hash_ext_stats_read,
 };
-
-struct rte_table_ops rte_table_hash_ext_dosig_ops  = {
-	.f_create = rte_table_hash_ext_create,
-	.f_free = rte_table_hash_ext_free,
-	.f_add = rte_table_hash_ext_entry_add,
-	.f_delete = rte_table_hash_ext_entry_delete,
-	.f_add_bulk = NULL,
-	.f_delete_bulk = NULL,
-	.f_lookup = rte_table_hash_ext_lookup_dosig,
-	.f_stats = rte_table_hash_ext_stats_read,
-};
diff --git a/lib/librte_table/rte_table_hash_key16.c b/lib/librte_table/rte_table_hash_key16.c
index ce057b7..e6e7d98 100644
--- a/lib/librte_table/rte_table_hash_key16.c
+++ b/lib/librte_table/rte_table_hash_key16.c
@@ -1,34 +1,34 @@
 /*-
- *	 BSD LICENSE
+ *   BSD LICENSE
  *
- *	 Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *	 All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
  *
- *	 Redistribution and use in source and binary forms, with or without
- *	 modification, are permitted provided that the following conditions
- *	 are met:
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
  *
- *	* Redistributions of source code must retain the above copyright
- *		 notice, this list of conditions and the following disclaimer.
- *	* Redistributions in binary form must reproduce the above copyright
- *		 notice, this list of conditions and the following disclaimer in
- *		 the documentation and/or other materials provided with the
- *		 distribution.
- *	* Neither the name of Intel Corporation nor the names of its
- *		 contributors may be used to endorse or promote products derived
- *		 from this software without specific prior written permission.
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
  *
- *	 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *	 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *	 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *	 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *	 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *	 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *	 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *	 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *	 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *	 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *	 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <string.h>
 #include <stdio.h>
@@ -42,7 +42,9 @@
 #include "rte_table_hash.h"
 #include "rte_lru.h"
 
-#define RTE_TABLE_HASH_KEY_SIZE						16
+#define KEY_SIZE						16
+
+#define KEYS_PER_BUCKET					4
 
 #define RTE_BUCKET_ENTRY_VALID						0x1LLU
 
@@ -79,11 +81,9 @@ struct rte_table_hash {
 
 	/* Input parameters */
 	uint32_t n_buckets;
-	uint32_t n_entries_per_bucket;
 	uint32_t key_size;
 	uint32_t entry_size;
 	uint32_t bucket_size;
-	uint32_t signature_offset;
 	uint32_t key_offset;
 	uint64_t key_mask[2];
 	rte_table_hash_op_hash f_hash;
@@ -99,17 +99,54 @@ struct rte_table_hash {
 };
 
 static int
-check_params_create_lru(struct rte_table_hash_key16_lru_params *params) {
-	/* n_entries */
-	if (params->n_entries == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries is zero\n", __func__);
+keycmp(void *a, void *b, void *b_mask)
+{
+	uint64_t *a64 = a, *b64 = b, *b_mask64 = b_mask;
+
+	return (a64[0] != (b64[0] & b_mask64[0])) ||
+		(a64[1] != (b64[1] & b_mask64[1]));
+}
+
+static void
+keycpy(void *dst, void *src, void *src_mask)
+{
+	uint64_t *dst64 = dst, *src64 = src, *src_mask64 = src_mask;
+
+	dst64[0] = src64[0] & src_mask64[0];
+	dst64[1] = src64[1] & src_mask64[1];
+}
+
+static int
+check_params_create(struct rte_table_hash_params *params) {
+	/* name */
+	if (params->name == NULL) {
+		RTE_LOG(ERR, TABLE, "%s: name invalid value\n", __func__);
+		return -EINVAL;
+	}
+
+	/* key_size */
+	if (params->key_size != KEY_SIZE) {
+		RTE_LOG(ERR, TABLE, "%s: key_size invalid value\n", __func__);
+		return -EINVAL;
+	}
+
+	/* n_keys */
+	if (params->n_keys == 0) {
+		RTE_LOG(ERR, TABLE, "%s: n_keys is zero\n", __func__);
+		return -EINVAL;
+	}
+
+	/* n_buckets */
+	if ((params->n_buckets == 0) ||
+		(!rte_is_power_of_2(params->n_buckets))) {
+		RTE_LOG(ERR, TABLE, "%s: n_buckets invalid value\n", __func__);
 		return -EINVAL;
 	}
 
 	/* f_hash */
 	if (params->f_hash == NULL) {
-		RTE_LOG(ERR, TABLE,
-			"%s: f_hash function pointer is NULL\n", __func__);
+		RTE_LOG(ERR, TABLE, "%s: f_hash function pointer is NULL\n",
+			__func__);
 		return -EINVAL;
 	}
 
@@ -121,46 +158,67 @@ rte_table_hash_create_key16_lru(void *params,
 		int socket_id,
 		uint32_t entry_size)
 {
-	struct rte_table_hash_key16_lru_params *p =
-			(struct rte_table_hash_key16_lru_params *) params;
+	struct rte_table_hash_params *p = params;
 	struct rte_table_hash *f;
-	uint32_t n_buckets, n_entries_per_bucket,
-			key_size, bucket_size_cl, total_size, i;
+	uint64_t bucket_size, total_size;
+	uint32_t n_buckets, i;
 
 	/* Check input parameters */
-	if ((check_params_create_lru(p) != 0) ||
+	if ((check_params_create(p) != 0) ||
 		((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
 		((sizeof(struct rte_bucket_4_16) % 64) != 0))
 		return NULL;
-	n_entries_per_bucket = 4;
-	key_size = 16;
+
+	/*
+	 * Table dimensioning
+	 *
+	 * Objective: Pick the number of buckets (n_buckets) so that there a chance
+	 * to store n_keys keys in the table.
+	 *
+	 * Note: Since the buckets do not get extended, it is not possible to
+	 * guarantee that n_keys keys can be stored in the table at any time. In the
+	 * worst case scenario when all the n_keys fall into the same bucket, only
+	 * a maximum of KEYS_PER_BUCKET keys will be stored in the table. This case
+	 * defeats the purpose of the hash table. It indicates unsuitable f_hash or
+	 * n_keys to n_buckets ratio.
+	 *
+	 * MIN(n_buckets) = (n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET
+	 */
+	n_buckets = rte_align32pow2(
+		(p->n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET);
+	n_buckets = RTE_MAX(n_buckets, p->n_buckets);
 
 	/* Memory allocation */
-	n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
-		n_entries_per_bucket);
-	bucket_size_cl = (sizeof(struct rte_bucket_4_16) + n_entries_per_bucket
-		* entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
-	total_size = sizeof(struct rte_table_hash) + n_buckets *
-		bucket_size_cl * RTE_CACHE_LINE_SIZE;
-
-	f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
+	bucket_size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_bucket_4_16) +
+		KEYS_PER_BUCKET * entry_size);
+	total_size = sizeof(struct rte_table_hash) + n_buckets * bucket_size;
+
+	if (total_size > SIZE_MAX) {
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+		"for hash table %s\n",
+		__func__, total_size, p->name);
+		return NULL;
+	}
+
+	f = rte_zmalloc_socket(p->name,
+		(size_t)total_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (f == NULL) {
-		RTE_LOG(ERR, TABLE,
-		"%s: Cannot allocate %u bytes for hash table\n",
-		__func__, total_size);
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+		"for hash table %s\n",
+		__func__, total_size, p->name);
 		return NULL;
 	}
-	RTE_LOG(INFO, TABLE,
-		"%s: Hash table memory footprint is %u bytes\n",
-		__func__, total_size);
+	RTE_LOG(INFO, TABLE, "%s: Hash table %s memory footprint "
+		"is %" PRIu64 " bytes\n",
+		__func__, p->name, total_size);
 
 	/* Memory initialization */
 	f->n_buckets = n_buckets;
-	f->n_entries_per_bucket = n_entries_per_bucket;
-	f->key_size = key_size;
+	f->key_size = KEY_SIZE;
 	f->entry_size = entry_size;
-	f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
-	f->signature_offset = p->signature_offset;
+	f->bucket_size = bucket_size;
 	f->key_offset = p->key_offset;
 	f->f_hash = p->f_hash;
 	f->seed = p->seed;
@@ -212,19 +270,19 @@ rte_table_hash_entry_add_key16_lru(
 	uint64_t signature, pos;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket = (struct rte_bucket_4_16 *)
-			&f->memory[bucket_index * f->bucket_size];
+		&f->memory[bucket_index * f->bucket_size];
 	signature |= RTE_BUCKET_ENTRY_VALID;
 
 	/* Key is present in the bucket */
 	for (i = 0; i < 4; i++) {
 		uint64_t bucket_signature = bucket->signature[i];
-		uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+		uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 		if ((bucket_signature == signature) &&
-				(memcmp(key, bucket_key, f->key_size) == 0)) {
+			(keycmp(bucket_key, key, f->key_mask) == 0)) {
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			memcpy(bucket_data, entry, f->entry_size);
@@ -238,13 +296,13 @@ rte_table_hash_entry_add_key16_lru(
 	/* Key is not present in the bucket */
 	for (i = 0; i < 4; i++) {
 		uint64_t bucket_signature = bucket->signature[i];
-		uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+		uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 		if (bucket_signature == 0) {
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			bucket->signature[i] = signature;
-			memcpy(bucket_key, key, f->key_size);
+			keycpy(bucket_key, key, f->key_mask);
 			memcpy(bucket_data, entry, f->entry_size);
 			lru_update(bucket, i);
 			*key_found = 0;
@@ -257,7 +315,7 @@ rte_table_hash_entry_add_key16_lru(
 	/* Bucket full: replace LRU entry */
 	pos = lru_pos(bucket);
 	bucket->signature[pos] = signature;
-	memcpy(bucket->key[pos], key, f->key_size);
+	keycpy(&bucket->key[pos], key, f->key_mask);
 	memcpy(&bucket->data[pos * f->entry_size], entry, f->entry_size);
 	lru_update(bucket, pos);
 	*key_found = 0;
@@ -278,19 +336,19 @@ rte_table_hash_entry_delete_key16_lru(
 	uint64_t signature;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket = (struct rte_bucket_4_16 *)
-			&f->memory[bucket_index * f->bucket_size];
+		&f->memory[bucket_index * f->bucket_size];
 	signature |= RTE_BUCKET_ENTRY_VALID;
 
 	/* Key is present in the bucket */
 	for (i = 0; i < 4; i++) {
 		uint64_t bucket_signature = bucket->signature[i];
-		uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+		uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 		if ((bucket_signature == signature) &&
-				(memcmp(key, bucket_key, f->key_size) == 0)) {
+			(keycmp(bucket_key, key, f->key_mask) == 0)) {
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			bucket->signature[i] = 0;
@@ -306,81 +364,71 @@ rte_table_hash_entry_delete_key16_lru(
 	return 0;
 }
 
-static int
-check_params_create_ext(struct rte_table_hash_key16_ext_params *params) {
-	/* n_entries */
-	if (params->n_entries == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries is zero\n", __func__);
-		return -EINVAL;
-	}
-
-	/* n_entries_ext */
-	if (params->n_entries_ext == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries_ext is zero\n", __func__);
-		return -EINVAL;
-	}
-
-	/* f_hash */
-	if (params->f_hash == NULL) {
-		RTE_LOG(ERR, TABLE,
-			"%s: f_hash function pointer is NULL\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static void *
 rte_table_hash_create_key16_ext(void *params,
 		int socket_id,
 		uint32_t entry_size)
 {
-	struct rte_table_hash_key16_ext_params *p =
-			(struct rte_table_hash_key16_ext_params *) params;
+	struct rte_table_hash_params *p = params;
 	struct rte_table_hash *f;
-	uint32_t n_buckets, n_buckets_ext, n_entries_per_bucket, key_size,
-			bucket_size_cl, stack_size_cl, total_size, i;
+	uint64_t bucket_size, stack_size, total_size;
+	uint32_t n_buckets_ext, i;
 
 	/* Check input parameters */
-	if ((check_params_create_ext(p) != 0) ||
+	if ((check_params_create(p) != 0) ||
 		((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
 		((sizeof(struct rte_bucket_4_16) % 64) != 0))
 		return NULL;
 
-	n_entries_per_bucket = 4;
-	key_size = 16;
+	/*
+	 * Table dimensioning
+	 *
+	 * Objective: Pick the number of bucket extensions (n_buckets_ext) so that
+	 * it is guaranteed that n_keys keys can be stored in the table at any time.
+	 *
+	 * The worst case scenario takes place when all the n_keys keys fall into
+	 * the same bucket. Actually, due to the KEYS_PER_BUCKET scheme, the worst
+	 * case takes place when (n_keys - KEYS_PER_BUCKET + 1) keys fall into the
+	 * same bucket, while the remaining (KEYS_PER_BUCKET - 1) keys each fall
+	 * into a different bucket. This case defeats the purpose of the hash table.
+	 * It indicates unsuitable f_hash or n_keys to n_buckets ratio.
+	 *
+	 * n_buckets_ext = n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1
+	 */
+	n_buckets_ext = p->n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1;
 
 	/* Memory allocation */
-	n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
-		n_entries_per_bucket);
-	n_buckets_ext = (p->n_entries_ext + n_entries_per_bucket - 1) /
-		n_entries_per_bucket;
-	bucket_size_cl = (sizeof(struct rte_bucket_4_16) + n_entries_per_bucket
-		* entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
-	stack_size_cl = (n_buckets_ext * sizeof(uint32_t) + RTE_CACHE_LINE_SIZE - 1)
-		/ RTE_CACHE_LINE_SIZE;
+	bucket_size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_bucket_4_16) +
+		KEYS_PER_BUCKET * entry_size);
+	stack_size = RTE_CACHE_LINE_ROUNDUP(n_buckets_ext * sizeof(uint32_t));
 	total_size = sizeof(struct rte_table_hash) +
-		((n_buckets + n_buckets_ext) * bucket_size_cl + stack_size_cl) *
-		RTE_CACHE_LINE_SIZE;
+		(p->n_buckets + n_buckets_ext) * bucket_size + stack_size;
+	if (total_size > SIZE_MAX) {
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+			"for hash table %s\n",
+			__func__, total_size, p->name);
+		return NULL;
+	}
 
-	f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
+	f = rte_zmalloc_socket(p->name,
+		(size_t)total_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (f == NULL) {
-		RTE_LOG(ERR, TABLE,
-			"%s: Cannot allocate %u bytes for hash table\n",
-			__func__, total_size);
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+			"for hash table %s\n",
+			__func__, total_size, p->name);
 		return NULL;
 	}
-	RTE_LOG(INFO, TABLE,
-		"%s: Hash table memory footprint is %u bytes\n",
-		__func__, total_size);
+	RTE_LOG(INFO, TABLE, "%s: Hash table %s memory footprint "
+		"is %" PRIu64 " bytes\n",
+		__func__, p->name, total_size);
 
 	/* Memory initialization */
-	f->n_buckets = n_buckets;
-	f->n_entries_per_bucket = n_entries_per_bucket;
-	f->key_size = key_size;
+	f->n_buckets = p->n_buckets;
+	f->key_size = KEY_SIZE;
 	f->entry_size = entry_size;
-	f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
-	f->signature_offset = p->signature_offset;
+	f->bucket_size = bucket_size;
 	f->key_offset = p->key_offset;
 	f->f_hash = p->f_hash;
 	f->seed = p->seed;
@@ -388,10 +436,7 @@ rte_table_hash_create_key16_ext(void *params,
 	f->n_buckets_ext = n_buckets_ext;
 	f->stack_pos = n_buckets_ext;
 	f->stack = (uint32_t *)
-		&f->memory[(n_buckets + n_buckets_ext) * f->bucket_size];
-
-	for (i = 0; i < n_buckets_ext; i++)
-		f->stack[i] = i;
+		&f->memory[(p->n_buckets + n_buckets_ext) * f->bucket_size];
 
 	if (p->key_mask != NULL) {
 		f->key_mask[0] = (((uint64_t *)p->key_mask)[0]);
@@ -401,6 +446,9 @@ rte_table_hash_create_key16_ext(void *params,
 		f->key_mask[1] = 0xFFFFFFFFFFFFFFFFLLU;
 	}
 
+	for (i = 0; i < n_buckets_ext; i++)
+		f->stack[i] = i;
+
 	return f;
 }
 
@@ -432,20 +480,20 @@ rte_table_hash_entry_add_key16_ext(
 	uint64_t signature;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket0 = (struct rte_bucket_4_16 *)
-			&f->memory[bucket_index * f->bucket_size];
+		&f->memory[bucket_index * f->bucket_size];
 	signature |= RTE_BUCKET_ENTRY_VALID;
 
 	/* Key is present in the bucket */
 	for (bucket = bucket0; bucket != NULL; bucket = bucket->next)
 		for (i = 0; i < 4; i++) {
 			uint64_t bucket_signature = bucket->signature[i];
-			uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+			uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 			if ((bucket_signature == signature) &&
-				(memcmp(key, bucket_key, f->key_size) == 0)) {
+				(keycmp(bucket_key, key, f->key_mask) == 0)) {
 				uint8_t *bucket_data = &bucket->data[i *
 					f->entry_size];
 
@@ -458,17 +506,17 @@ rte_table_hash_entry_add_key16_ext(
 
 	/* Key is not present in the bucket */
 	for (bucket_prev = NULL, bucket = bucket0; bucket != NULL;
-			 bucket_prev = bucket, bucket = bucket->next)
+		bucket_prev = bucket, bucket = bucket->next)
 		for (i = 0; i < 4; i++) {
 			uint64_t bucket_signature = bucket->signature[i];
-			uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+			uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 			if (bucket_signature == 0) {
 				uint8_t *bucket_data = &bucket->data[i *
 					f->entry_size];
 
 				bucket->signature[i] = signature;
-				memcpy(bucket_key, key, f->key_size);
+				keycpy(bucket_key, key, f->key_mask);
 				memcpy(bucket_data, entry, f->entry_size);
 				*key_found = 0;
 				*entry_ptr = (void *) bucket_data;
@@ -487,7 +535,7 @@ rte_table_hash_entry_add_key16_ext(
 		bucket_prev->next_valid = 1;
 
 		bucket->signature[0] = signature;
-		memcpy(bucket->key[0], key, f->key_size);
+		keycpy(&bucket->key[0], key, f->key_mask);
 		memcpy(&bucket->data[0], entry, f->entry_size);
 		*key_found = 0;
 		*entry_ptr = (void *) &bucket->data[0];
@@ -509,7 +557,7 @@ rte_table_hash_entry_delete_key16_ext(
 	uint64_t signature;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket0 = (struct rte_bucket_4_16 *)
 		&f->memory[bucket_index * f->bucket_size];
@@ -520,18 +568,17 @@ rte_table_hash_entry_delete_key16_ext(
 		bucket_prev = bucket, bucket = bucket->next)
 		for (i = 0; i < 4; i++) {
 			uint64_t bucket_signature = bucket->signature[i];
-			uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+			uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 			if ((bucket_signature == signature) &&
-				(memcmp(key, bucket_key, f->key_size) == 0)) {
+				(keycmp(bucket_key, key, f->key_mask) == 0)) {
 				uint8_t *bucket_data = &bucket->data[i *
 					f->entry_size];
 
 				bucket->signature[i] = 0;
 				*key_found = 1;
 				if (entry)
-					memcpy(entry, bucket_data,
-					f->entry_size);
+					memcpy(entry, bucket_data, f->entry_size);
 
 				if ((bucket->signature[0] == 0) &&
 					(bucket->signature[1] == 0) &&
@@ -558,26 +605,28 @@ rte_table_hash_entry_delete_key16_ext(
 	return 0;
 }
 
-#define lookup_key16_cmp(key_in, bucket, pos)			\
+#define lookup_key16_cmp(key_in, bucket, pos, f)			\
 {								\
-	uint64_t xor[4][2], or[4], signature[4];		\
+	uint64_t xor[4][2], or[4], signature[4], k[2];		\
 								\
+	k[0] = key_in[0] & f->key_mask[0];				\
+	k[1] = key_in[1] & f->key_mask[1];				\
 	signature[0] = (~bucket->signature[0]) & 1;		\
 	signature[1] = (~bucket->signature[1]) & 1;		\
 	signature[2] = (~bucket->signature[2]) & 1;		\
 	signature[3] = (~bucket->signature[3]) & 1;		\
 								\
-	xor[0][0] = key_in[0] ^	 bucket->key[0][0];		\
-	xor[0][1] = key_in[1] ^	 bucket->key[0][1];		\
+	xor[0][0] = k[0] ^ bucket->key[0][0];			\
+	xor[0][1] = k[1] ^ bucket->key[0][1];			\
 								\
-	xor[1][0] = key_in[0] ^	 bucket->key[1][0];		\
-	xor[1][1] = key_in[1] ^	 bucket->key[1][1];		\
+	xor[1][0] = k[0] ^ bucket->key[1][0];			\
+	xor[1][1] = k[1] ^ bucket->key[1][1];			\
 								\
-	xor[2][0] = key_in[0] ^	 bucket->key[2][0];		\
-	xor[2][1] = key_in[1] ^	 bucket->key[2][1];		\
+	xor[2][0] = k[0] ^ bucket->key[2][0];			\
+	xor[2][1] = k[1] ^ bucket->key[2][1];			\
 								\
-	xor[3][0] = key_in[0] ^	 bucket->key[3][0];		\
-	xor[3][1] = key_in[1] ^	 bucket->key[3][1];		\
+	xor[3][0] = k[0] ^ bucket->key[3][0];			\
+	xor[3][1] = k[1] ^ bucket->key[3][1];			\
 								\
 	or[0] = xor[0][0] | xor[0][1] | signature[0];		\
 	or[1] = xor[1][0] | xor[1][1] | signature[1];		\
@@ -610,30 +659,12 @@ rte_table_hash_entry_delete_key16_ext(
 
 #define lookup1_stage1(mbuf1, bucket1, f)			\
 {								\
-	uint64_t signature;					\
-	uint32_t bucket_index;					\
-								\
-	signature = RTE_MBUF_METADATA_UINT32(mbuf1, f->signature_offset);\
-	bucket_index = signature & (f->n_buckets - 1);		\
-	bucket1 = (struct rte_bucket_4_16 *)			\
-		&f->memory[bucket_index * f->bucket_size];	\
-	rte_prefetch0(bucket1);					\
-	rte_prefetch0((void *)(((uintptr_t) bucket1) + RTE_CACHE_LINE_SIZE));\
-}
-
-#define lookup1_stage1_dosig(mbuf1, bucket1, f)			\
-{								\
 	uint64_t *key;						\
 	uint64_t signature = 0;				\
 	uint32_t bucket_index;				\
-	uint64_t hash_key_buffer[2];		\
 								\
 	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf1, f->key_offset);\
-								\
-	hash_key_buffer[0] = key[0] & f->key_mask[0];	\
-	hash_key_buffer[1] = key[1] & f->key_mask[1];	\
-	signature = f->f_hash(hash_key_buffer,			\
-			RTE_TABLE_HASH_KEY_SIZE, f->seed);		\
+	signature = f->f_hash(key, f->key_mask, KEY_SIZE, f->seed);	\
 								\
 	bucket_index = signature & (f->n_buckets - 1);		\
 	bucket1 = (struct rte_bucket_4_16 *)			\
@@ -648,14 +679,10 @@ rte_table_hash_entry_delete_key16_ext(
 	void *a;						\
 	uint64_t pkt_mask;					\
 	uint64_t *key;						\
-	uint64_t hash_key_buffer[2];		\
 	uint32_t pos;						\
 								\
 	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
-	hash_key_buffer[0] = key[0] & f->key_mask[0];	\
-	hash_key_buffer[1] = key[1] & f->key_mask[1];	\
-								\
-	lookup_key16_cmp(hash_key_buffer, bucket2, pos);	\
+	lookup_key16_cmp(key, bucket2, pos, f);			\
 								\
 	pkt_mask = (bucket2->signature[pos] & 1LLU) << pkt2_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -673,14 +700,10 @@ rte_table_hash_entry_delete_key16_ext(
 	void *a;						\
 	uint64_t pkt_mask, bucket_mask;				\
 	uint64_t *key;						\
-	uint64_t hash_key_buffer[2];		\
 	uint32_t pos;						\
 								\
 	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
-	hash_key_buffer[0] = key[0] & f->key_mask[0];	\
-	hash_key_buffer[1] = key[1] & f->key_mask[1];	\
-								\
-	lookup_key16_cmp(hash_key_buffer, bucket2, pos);	\
+	lookup_key16_cmp(key, bucket2, pos, f);			\
 								\
 	pkt_mask = (bucket2->signature[pos] & 1LLU) << pkt2_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -703,15 +726,11 @@ rte_table_hash_entry_delete_key16_ext(
 	void *a;						\
 	uint64_t pkt_mask, bucket_mask;				\
 	uint64_t *key;						\
-	uint64_t hash_key_buffer[2];		\
 	uint32_t pos;						\
 								\
 	bucket = buckets[pkt_index];				\
 	key = keys[pkt_index];					\
-	hash_key_buffer[0] = key[0] & f->key_mask[0];	\
-	hash_key_buffer[1] = key[1] & f->key_mask[1];	\
-								\
-	lookup_key16_cmp(hash_key_buffer, bucket, pos);	\
+	lookup_key16_cmp(key, bucket, pos, f);			\
 								\
 	pkt_mask = (bucket->signature[pos] & 1LLU) << pkt_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -775,36 +794,12 @@ rte_table_hash_entry_delete_key16_ext(
 
 #define lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f)	\
 {								\
-	uint64_t signature10, signature11;			\
-	uint32_t bucket10_index, bucket11_index;		\
-								\
-	signature10 = RTE_MBUF_METADATA_UINT32(mbuf10, f->signature_offset);\
-	bucket10_index = signature10 & (f->n_buckets - 1);	\
-	bucket10 = (struct rte_bucket_4_16 *)			\
-		&f->memory[bucket10_index * f->bucket_size];	\
-	rte_prefetch0(bucket10);				\
-	rte_prefetch0((void *)(((uintptr_t) bucket10) + RTE_CACHE_LINE_SIZE));\
-								\
-	signature11 = RTE_MBUF_METADATA_UINT32(mbuf11, f->signature_offset);\
-	bucket11_index = signature11 & (f->n_buckets - 1);	\
-	bucket11 = (struct rte_bucket_4_16 *)			\
-		&f->memory[bucket11_index * f->bucket_size];	\
-	rte_prefetch0(bucket11);				\
-	rte_prefetch0((void *)(((uintptr_t) bucket11) + RTE_CACHE_LINE_SIZE));\
-}
-
-#define lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f)	\
-{								\
 	uint64_t *key10, *key11;					\
-	uint64_t hash_offset_buffer[2];				\
 	uint64_t signature10, signature11;			\
 	uint32_t bucket10_index, bucket11_index;	\
 								\
 	key10 = RTE_MBUF_METADATA_UINT64_PTR(mbuf10, f->key_offset);\
-	hash_offset_buffer[0] = key10[0] & f->key_mask[0];	\
-	hash_offset_buffer[1] = key10[1] & f->key_mask[1];	\
-	signature10 = f->f_hash(hash_offset_buffer,			\
-			RTE_TABLE_HASH_KEY_SIZE, f->seed);\
+	signature10 = f->f_hash(key10, f->key_mask,	 KEY_SIZE, f->seed);\
 	bucket10_index = signature10 & (f->n_buckets - 1);	\
 	bucket10 = (struct rte_bucket_4_16 *)				\
 		&f->memory[bucket10_index * f->bucket_size];	\
@@ -812,10 +807,7 @@ rte_table_hash_entry_delete_key16_ext(
 	rte_prefetch0((void *)(((uintptr_t) bucket10) + RTE_CACHE_LINE_SIZE));\
 								\
 	key11 = RTE_MBUF_METADATA_UINT64_PTR(mbuf11, f->key_offset);\
-	hash_offset_buffer[0] = key11[0] & f->key_mask[0];	\
-	hash_offset_buffer[1] = key11[1] & f->key_mask[1];	\
-	signature11 = f->f_hash(hash_offset_buffer,			\
-			RTE_TABLE_HASH_KEY_SIZE, f->seed);\
+	signature11 = f->f_hash(key11, f->key_mask,	 KEY_SIZE, f->seed);\
 	bucket11_index = signature11 & (f->n_buckets - 1);	\
 	bucket11 = (struct rte_bucket_4_16 *)			\
 		&f->memory[bucket11_index * f->bucket_size];	\
@@ -829,19 +821,13 @@ rte_table_hash_entry_delete_key16_ext(
 	void *a20, *a21;					\
 	uint64_t pkt20_mask, pkt21_mask;			\
 	uint64_t *key20, *key21;				\
-	uint64_t hash_key_buffer20[2];			\
-	uint64_t hash_key_buffer21[2];			\
 	uint32_t pos20, pos21;					\
 								\
 	key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
 	key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
-	hash_key_buffer20[0] = key20[0] & f->key_mask[0];	\
-	hash_key_buffer20[1] = key20[1] & f->key_mask[1];	\
-	hash_key_buffer21[0] = key21[0] & f->key_mask[0];	\
-	hash_key_buffer21[1] = key21[1] & f->key_mask[1];	\
 								\
-	lookup_key16_cmp(hash_key_buffer20, bucket20, pos20);	\
-	lookup_key16_cmp(hash_key_buffer21, bucket21, pos21);	\
+	lookup_key16_cmp(key20, bucket20, pos20, f);		\
+	lookup_key16_cmp(key21, bucket21, pos21, f);		\
 								\
 	pkt20_mask = (bucket20->signature[pos20] & 1LLU) << pkt20_index;\
 	pkt21_mask = (bucket21->signature[pos21] & 1LLU) << pkt21_index;\
@@ -864,19 +850,13 @@ rte_table_hash_entry_delete_key16_ext(
 	void *a20, *a21;					\
 	uint64_t pkt20_mask, pkt21_mask, bucket20_mask, bucket21_mask;\
 	uint64_t *key20, *key21;				\
-	uint64_t hash_key_buffer20[2];			\
-	uint64_t hash_key_buffer21[2];			\
 	uint32_t pos20, pos21;					\
 								\
 	key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
 	key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
-	hash_key_buffer20[0] = key20[0] & f->key_mask[0];	\
-	hash_key_buffer20[1] = key20[1] & f->key_mask[1];	\
-	hash_key_buffer21[0] = key21[0] & f->key_mask[0];	\
-	hash_key_buffer21[1] = key21[1] & f->key_mask[1];	\
 								\
-	lookup_key16_cmp(hash_key_buffer20, bucket20, pos20);	\
-	lookup_key16_cmp(hash_key_buffer21, bucket21, pos21);	\
+	lookup_key16_cmp(key20, bucket20, pos20, f);	\
+	lookup_key16_cmp(key21, bucket21, pos21, f);	\
 								\
 	pkt20_mask = (bucket20->signature[pos20] & 1LLU) << pkt20_index;\
 	pkt21_mask = (bucket21->signature[pos21] & 1LLU) << pkt21_index;\
@@ -916,6 +896,7 @@ rte_table_hash_lookup_key16_lru(
 	uint64_t pkts_mask_out = 0;
 
 	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
+
 	RTE_TABLE_HASH_KEY16_STATS_PKTS_IN_ADD(f, n_pkts_in);
 
 	/* Cannot run the pipeline with less than 5 packets */
@@ -932,8 +913,8 @@ rte_table_hash_lookup_key16_lru(
 		}
 
 		*lookup_hit_mask = pkts_mask_out;
-		RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f,
-			n_pkts_in - __builtin_popcountll(pkts_mask_out));
+		RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
+			__builtin_popcountll(pkts_mask_out));
 		return 0;
 	}
 
@@ -1026,136 +1007,7 @@ rte_table_hash_lookup_key16_lru(
 	RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
 		__builtin_popcountll(pkts_mask_out));
 	return 0;
-} /* rte_table_hash_lookup_key16_lru() */
-
-static int
-rte_table_hash_lookup_key16_lru_dosig(
-	void *table,
-	struct rte_mbuf **pkts,
-	uint64_t pkts_mask,
-	uint64_t *lookup_hit_mask,
-	void **entries)
-{
-	struct rte_table_hash *f = (struct rte_table_hash *) table;
-	struct rte_bucket_4_16 *bucket10, *bucket11, *bucket20, *bucket21;
-	struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
-	uint32_t pkt00_index, pkt01_index, pkt10_index;
-	uint32_t pkt11_index, pkt20_index, pkt21_index;
-	uint64_t pkts_mask_out = 0;
-
-	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
-
-	RTE_TABLE_HASH_KEY16_STATS_PKTS_IN_ADD(f, n_pkts_in);
-
-	/* Cannot run the pipeline with less than 5 packets */
-	if (__builtin_popcountll(pkts_mask) < 5) {
-		for ( ; pkts_mask; ) {
-			struct rte_bucket_4_16 *bucket;
-			struct rte_mbuf *mbuf;
-			uint32_t pkt_index;
-
-			lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
-			lookup1_stage1_dosig(mbuf, bucket, f);
-			lookup1_stage2_lru(pkt_index, mbuf, bucket,
-				pkts_mask_out, entries, f);
-		}
-
-		*lookup_hit_mask = pkts_mask_out;
-		RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
-			__builtin_popcountll(pkts_mask_out));
-		return 0;
-	}
-
-	/*
-	 * Pipeline fill
-	 *
-	 */
-	/* Pipeline stage 0 */
-	lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-		pkts_mask, f);
-
-	/* Pipeline feed */
-	mbuf10 = mbuf00;
-	mbuf11 = mbuf01;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-		pkts_mask, f);
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-	/*
-	 * Pipeline run
-	 *
-	 */
-	for ( ; pkts_mask; ) {
-		/* Pipeline feed */
-		bucket20 = bucket10;
-		bucket21 = bucket11;
-		mbuf20 = mbuf10;
-		mbuf21 = mbuf11;
-		mbuf10 = mbuf00;
-		mbuf11 = mbuf01;
-		pkt20_index = pkt10_index;
-		pkt21_index = pkt11_index;
-		pkt10_index = pkt00_index;
-		pkt11_index = pkt01_index;
-
-		/* Pipeline stage 0 */
-		lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
-			mbuf00, mbuf01, pkts, pkts_mask, f);
-
-		/* Pipeline stage 1 */
-		lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-		/* Pipeline stage 2 */
-		lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
-			bucket20, bucket21, pkts_mask_out, entries, f);
-	}
-
-	/*
-	 * Pipeline flush
-	 *
-	 */
-	/* Pipeline feed */
-	bucket20 = bucket10;
-	bucket21 = bucket11;
-	mbuf20 = mbuf10;
-	mbuf21 = mbuf11;
-	mbuf10 = mbuf00;
-	mbuf11 = mbuf01;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-	/* Pipeline stage 2 */
-	lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
-		bucket20, bucket21, pkts_mask_out, entries, f);
-
-	/* Pipeline feed */
-	bucket20 = bucket10;
-	bucket21 = bucket11;
-	mbuf20 = mbuf10;
-	mbuf21 = mbuf11;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-
-	/* Pipeline stage 2 */
-	lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
-		bucket20, bucket21, pkts_mask_out, entries, f);
-
-	*lookup_hit_mask = pkts_mask_out;
-	RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
-		__builtin_popcountll(pkts_mask_out));
-	return 0;
-} /* rte_table_hash_lookup_key16_lru_dosig() */
+} /* lookup LRU */
 
 static int
 rte_table_hash_lookup_key16_ext(
@@ -1175,6 +1027,7 @@ rte_table_hash_lookup_key16_ext(
 	uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
 
 	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
+
 	RTE_TABLE_HASH_KEY16_STATS_PKTS_IN_ADD(f, n_pkts_in);
 
 	/* Cannot run the pipeline with less than 5 packets */
@@ -1306,159 +1159,7 @@ rte_table_hash_lookup_key16_ext(
 	RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
 		__builtin_popcountll(pkts_mask_out));
 	return 0;
-} /* rte_table_hash_lookup_key16_ext() */
-
-static int
-rte_table_hash_lookup_key16_ext_dosig(
-	void *table,
-	struct rte_mbuf **pkts,
-	uint64_t pkts_mask,
-	uint64_t *lookup_hit_mask,
-	void **entries)
-{
-	struct rte_table_hash *f = (struct rte_table_hash *) table;
-	struct rte_bucket_4_16 *bucket10, *bucket11, *bucket20, *bucket21;
-	struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
-	uint32_t pkt00_index, pkt01_index, pkt10_index;
-	uint32_t pkt11_index, pkt20_index, pkt21_index;
-	uint64_t pkts_mask_out = 0, buckets_mask = 0;
-	struct rte_bucket_4_16 *buckets[RTE_PORT_IN_BURST_SIZE_MAX];
-	uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
-
-	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
-
-	RTE_TABLE_HASH_KEY16_STATS_PKTS_IN_ADD(f, n_pkts_in);
-
-	/* Cannot run the pipeline with less than 5 packets */
-	if (__builtin_popcountll(pkts_mask) < 5) {
-		for ( ; pkts_mask; ) {
-			struct rte_bucket_4_16 *bucket;
-			struct rte_mbuf *mbuf;
-			uint32_t pkt_index;
-
-			lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
-			lookup1_stage1_dosig(mbuf, bucket, f);
-			lookup1_stage2_ext(pkt_index, mbuf, bucket,
-				pkts_mask_out, entries, buckets_mask,
-				buckets, keys, f);
-		}
-
-		goto grind_next_buckets;
-	}
-
-	/*
-	 * Pipeline fill
-	 *
-	 */
-	/* Pipeline stage 0 */
-	lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-		pkts_mask, f);
-
-	/* Pipeline feed */
-	mbuf10 = mbuf00;
-	mbuf11 = mbuf01;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-		pkts_mask, f);
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-	/*
-	 * Pipeline run
-	 *
-	 */
-	for ( ; pkts_mask; ) {
-		/* Pipeline feed */
-		bucket20 = bucket10;
-		bucket21 = bucket11;
-		mbuf20 = mbuf10;
-		mbuf21 = mbuf11;
-		mbuf10 = mbuf00;
-		mbuf11 = mbuf01;
-		pkt20_index = pkt10_index;
-		pkt21_index = pkt11_index;
-		pkt10_index = pkt00_index;
-		pkt11_index = pkt01_index;
-
-		/* Pipeline stage 0 */
-		lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
-			mbuf00, mbuf01, pkts, pkts_mask, f);
-
-		/* Pipeline stage 1 */
-		lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-		/* Pipeline stage 2 */
-		lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
-			bucket20, bucket21, pkts_mask_out, entries,
-			buckets_mask, buckets, keys, f);
-	}
-
-	/*
-	 * Pipeline flush
-	 *
-	 */
-	/* Pipeline feed */
-	bucket20 = bucket10;
-	bucket21 = bucket11;
-	mbuf20 = mbuf10;
-	mbuf21 = mbuf11;
-	mbuf10 = mbuf00;
-	mbuf11 = mbuf01;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-	/* Pipeline stage 2 */
-	lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
-		bucket20, bucket21, pkts_mask_out, entries,
-		buckets_mask, buckets, keys, f);
-
-	/* Pipeline feed */
-	bucket20 = bucket10;
-	bucket21 = bucket11;
-	mbuf20 = mbuf10;
-	mbuf21 = mbuf11;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-
-	/* Pipeline stage 2 */
-	lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
-		bucket20, bucket21, pkts_mask_out, entries,
-		buckets_mask, buckets, keys, f);
-
-grind_next_buckets:
-	/* Grind next buckets */
-	for ( ; buckets_mask; ) {
-		uint64_t buckets_mask_next = 0;
-
-		for ( ; buckets_mask; ) {
-			uint64_t pkt_mask;
-			uint32_t pkt_index;
-
-			pkt_index = __builtin_ctzll(buckets_mask);
-			pkt_mask = 1LLU << pkt_index;
-			buckets_mask &= ~pkt_mask;
-
-			lookup_grinder(pkt_index, buckets, keys, pkts_mask_out,
-				entries, buckets_mask_next, f);
-		}
-
-		buckets_mask = buckets_mask_next;
-	}
-
-	*lookup_hit_mask = pkts_mask_out;
-	RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
-		__builtin_popcountll(pkts_mask_out));
-	return 0;
-} /* rte_table_hash_lookup_key16_ext_dosig() */
+} /* lookup EXT */
 
 static int
 rte_table_hash_key16_stats_read(void *table, struct rte_table_stats *stats, int clear)
@@ -1485,15 +1186,6 @@ struct rte_table_ops rte_table_hash_key16_lru_ops = {
 	.f_stats = rte_table_hash_key16_stats_read,
 };
 
-struct rte_table_ops rte_table_hash_key16_lru_dosig_ops = {
-	.f_create = rte_table_hash_create_key16_lru,
-	.f_free = rte_table_hash_free_key16_lru,
-	.f_add = rte_table_hash_entry_add_key16_lru,
-	.f_delete = rte_table_hash_entry_delete_key16_lru,
-	.f_lookup = rte_table_hash_lookup_key16_lru_dosig,
-	.f_stats = rte_table_hash_key16_stats_read,
-};
-
 struct rte_table_ops rte_table_hash_key16_ext_ops = {
 	.f_create = rte_table_hash_create_key16_ext,
 	.f_free = rte_table_hash_free_key16_ext,
@@ -1504,12 +1196,3 @@ struct rte_table_ops rte_table_hash_key16_ext_ops = {
 	.f_lookup = rte_table_hash_lookup_key16_ext,
 	.f_stats = rte_table_hash_key16_stats_read,
 };
-
-struct rte_table_ops rte_table_hash_key16_ext_dosig_ops = {
-	.f_create = rte_table_hash_create_key16_ext,
-	.f_free = rte_table_hash_free_key16_ext,
-	.f_add = rte_table_hash_entry_add_key16_ext,
-	.f_delete = rte_table_hash_entry_delete_key16_ext,
-	.f_lookup = rte_table_hash_lookup_key16_ext_dosig,
-	.f_stats = rte_table_hash_key16_stats_read,
-};
diff --git a/lib/librte_table/rte_table_hash_key32.c b/lib/librte_table/rte_table_hash_key32.c
index 31fe6fd..0664aa4 100644
--- a/lib/librte_table/rte_table_hash_key32.c
+++ b/lib/librte_table/rte_table_hash_key32.c
@@ -1,34 +1,34 @@
 /*-
- *	 BSD LICENSE
+ *   BSD LICENSE
  *
- *	 Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *	 All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
  *
- *	 Redistribution and use in source and binary forms, with or without
- *	 modification, are permitted provided that the following conditions
- *	 are met:
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
  *
- *	* Redistributions of source code must retain the above copyright
- *		 notice, this list of conditions and the following disclaimer.
- *	* Redistributions in binary form must reproduce the above copyright
- *		 notice, this list of conditions and the following disclaimer in
- *		 the documentation and/or other materials provided with the
- *		 distribution.
- *	* Neither the name of Intel Corporation nor the names of its
- *		 contributors may be used to endorse or promote products derived
- *		 from this software without specific prior written permission.
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
  *
- *	 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *	 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *	 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *	 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *	 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *	 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *	 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *	 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *	 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *	 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *	 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <string.h>
 #include <stdio.h>
@@ -42,7 +42,9 @@
 #include "rte_table_hash.h"
 #include "rte_lru.h"
 
-#define RTE_TABLE_HASH_KEY_SIZE						32
+#define KEY_SIZE						32
+
+#define KEYS_PER_BUCKET					4
 
 #define RTE_BUCKET_ENTRY_VALID						0x1LLU
 
@@ -79,12 +81,11 @@ struct rte_table_hash {
 
 	/* Input parameters */
 	uint32_t n_buckets;
-	uint32_t n_entries_per_bucket;
 	uint32_t key_size;
 	uint32_t entry_size;
 	uint32_t bucket_size;
-	uint32_t signature_offset;
 	uint32_t key_offset;
+	uint64_t key_mask[4];
 	rte_table_hash_op_hash f_hash;
 	uint64_t seed;
 
@@ -98,10 +99,51 @@ struct rte_table_hash {
 };
 
 static int
-check_params_create_lru(struct rte_table_hash_key32_lru_params *params) {
-	/* n_entries */
-	if (params->n_entries == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries is zero\n", __func__);
+keycmp(void *a, void *b, void *b_mask)
+{
+	uint64_t *a64 = a, *b64 = b, *b_mask64 = b_mask;
+
+	return (a64[0] != (b64[0] & b_mask64[0])) ||
+		(a64[1] != (b64[1] & b_mask64[1])) ||
+		(a64[2] != (b64[2] & b_mask64[2])) ||
+		(a64[3] != (b64[3] & b_mask64[3]));
+}
+
+static void
+keycpy(void *dst, void *src, void *src_mask)
+{
+	uint64_t *dst64 = dst, *src64 = src, *src_mask64 = src_mask;
+
+	dst64[0] = src64[0] & src_mask64[0];
+	dst64[1] = src64[1] & src_mask64[1];
+	dst64[2] = src64[2] & src_mask64[2];
+	dst64[3] = src64[3] & src_mask64[3];
+}
+
+static int
+check_params_create(struct rte_table_hash_params *params) {
+	/* name */
+	if (params->name == NULL) {
+		RTE_LOG(ERR, TABLE, "%s: name invalid value\n", __func__);
+		return -EINVAL;
+	}
+
+	/* key_size */
+	if (params->key_size != KEY_SIZE) {
+		RTE_LOG(ERR, TABLE, "%s: key_size invalid value\n", __func__);
+		return -EINVAL;
+	}
+
+	/* n_keys */
+	if (params->n_keys == 0) {
+		RTE_LOG(ERR, TABLE, "%s: n_keys is zero\n", __func__);
+		return -EINVAL;
+	}
+
+	/* n_buckets */
+	if ((params->n_buckets == 0) ||
+		(!rte_is_power_of_2(params->n_buckets))) {
+		RTE_LOG(ERR, TABLE, "%s: n_buckets invalid value\n", __func__);
 		return -EINVAL;
 	}
 
@@ -120,51 +162,83 @@ rte_table_hash_create_key32_lru(void *params,
 		int socket_id,
 		uint32_t entry_size)
 {
-	struct rte_table_hash_key32_lru_params *p =
-		(struct rte_table_hash_key32_lru_params *) params;
+	struct rte_table_hash_params *p = params;
 	struct rte_table_hash *f;
-	uint32_t n_buckets, n_entries_per_bucket, key_size, bucket_size_cl;
-	uint32_t total_size, i;
+	uint64_t bucket_size, total_size;
+	uint32_t n_buckets, i;
 
 	/* Check input parameters */
-	if ((check_params_create_lru(p) != 0) ||
+	if ((check_params_create(p) != 0) ||
 		((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
-		((sizeof(struct rte_bucket_4_32) % 64) != 0)) {
+		((sizeof(struct rte_bucket_4_32) % 64) != 0))
 		return NULL;
-	}
-	n_entries_per_bucket = 4;
-	key_size = 32;
+
+	/*
+	 * Table dimensioning
+	 *
+	 * Objective: Pick the number of buckets (n_buckets) so that there a chance
+	 * to store n_keys keys in the table.
+	 *
+	 * Note: Since the buckets do not get extended, it is not possible to
+	 * guarantee that n_keys keys can be stored in the table at any time. In the
+	 * worst case scenario when all the n_keys fall into the same bucket, only
+	 * a maximum of KEYS_PER_BUCKET keys will be stored in the table. This case
+	 * defeats the purpose of the hash table. It indicates unsuitable f_hash or
+	 * n_keys to n_buckets ratio.
+	 *
+	 * MIN(n_buckets) = (n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET
+	 */
+	n_buckets = rte_align32pow2(
+		(p->n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET);
+	n_buckets = RTE_MAX(n_buckets, p->n_buckets);
 
 	/* Memory allocation */
-	n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
-		n_entries_per_bucket);
-	bucket_size_cl = (sizeof(struct rte_bucket_4_32) + n_entries_per_bucket
-		* entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
-	total_size = sizeof(struct rte_table_hash) + n_buckets *
-		bucket_size_cl * RTE_CACHE_LINE_SIZE;
-
-	f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
+	bucket_size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_bucket_4_32) +
+		KEYS_PER_BUCKET * entry_size);
+	total_size = sizeof(struct rte_table_hash) + n_buckets * bucket_size;
+	if (total_size > SIZE_MAX) {
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+			"for hash table %s\n",
+			__func__, total_size, p->name);
+		return NULL;
+	}
+
+	f = rte_zmalloc_socket(p->name,
+		(size_t)total_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (f == NULL) {
-		RTE_LOG(ERR, TABLE,
-			"%s: Cannot allocate %u bytes for hash table\n",
-			__func__, total_size);
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+			"for hash table %s\n",
+			__func__, total_size, p->name);
 		return NULL;
 	}
 	RTE_LOG(INFO, TABLE,
-		"%s: Hash table memory footprint is %u bytes\n", __func__,
-		total_size);
+		"%s: Hash table %s memory footprint "
+		"is %" PRIu64 " bytes\n",
+		__func__, p->name, total_size);
 
 	/* Memory initialization */
 	f->n_buckets = n_buckets;
-	f->n_entries_per_bucket = n_entries_per_bucket;
-	f->key_size = key_size;
+	f->key_size = KEY_SIZE;
 	f->entry_size = entry_size;
-	f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
-	f->signature_offset = p->signature_offset;
+	f->bucket_size = bucket_size;
 	f->key_offset = p->key_offset;
 	f->f_hash = p->f_hash;
 	f->seed = p->seed;
 
+	if (p->key_mask != NULL) {
+		f->key_mask[0] = ((uint64_t *)p->key_mask)[0];
+		f->key_mask[1] = ((uint64_t *)p->key_mask)[1];
+		f->key_mask[2] = ((uint64_t *)p->key_mask)[2];
+		f->key_mask[3] = ((uint64_t *)p->key_mask)[3];
+	} else {
+		f->key_mask[0] = 0xFFFFFFFFFFFFFFFFLLU;
+		f->key_mask[1] = 0xFFFFFFFFFFFFFFFFLLU;
+		f->key_mask[2] = 0xFFFFFFFFFFFFFFFFLLU;
+		f->key_mask[3] = 0xFFFFFFFFFFFFFFFFLLU;
+	}
+
 	for (i = 0; i < n_buckets; i++) {
 		struct rte_bucket_4_32 *bucket;
 
@@ -204,7 +278,7 @@ rte_table_hash_entry_add_key32_lru(
 	uint64_t signature, pos;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket = (struct rte_bucket_4_32 *)
 		&f->memory[bucket_index * f->bucket_size];
@@ -213,10 +287,10 @@ rte_table_hash_entry_add_key32_lru(
 	/* Key is present in the bucket */
 	for (i = 0; i < 4; i++) {
 		uint64_t bucket_signature = bucket->signature[i];
-		uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+		uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 		if ((bucket_signature == signature) &&
-			(memcmp(key, bucket_key, f->key_size) == 0)) {
+			(keycmp(bucket_key, key, f->key_mask) == 0)) {
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			memcpy(bucket_data, entry, f->entry_size);
@@ -230,13 +304,13 @@ rte_table_hash_entry_add_key32_lru(
 	/* Key is not present in the bucket */
 	for (i = 0; i < 4; i++) {
 		uint64_t bucket_signature = bucket->signature[i];
-		uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+		uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 		if (bucket_signature == 0) {
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			bucket->signature[i] = signature;
-			memcpy(bucket_key, key, f->key_size);
+			keycpy(bucket_key, key, f->key_mask);
 			memcpy(bucket_data, entry, f->entry_size);
 			lru_update(bucket, i);
 			*key_found = 0;
@@ -249,10 +323,10 @@ rte_table_hash_entry_add_key32_lru(
 	/* Bucket full: replace LRU entry */
 	pos = lru_pos(bucket);
 	bucket->signature[pos] = signature;
-	memcpy(bucket->key[pos], key, f->key_size);
+	keycpy(&bucket->key[pos], key, f->key_mask);
 	memcpy(&bucket->data[pos * f->entry_size], entry, f->entry_size);
 	lru_update(bucket, pos);
-	*key_found	= 0;
+	*key_found = 0;
 	*entry_ptr = (void *) &bucket->data[pos * f->entry_size];
 
 	return 0;
@@ -270,7 +344,7 @@ rte_table_hash_entry_delete_key32_lru(
 	uint64_t signature;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket = (struct rte_bucket_4_32 *)
 		&f->memory[bucket_index * f->bucket_size];
@@ -279,10 +353,10 @@ rte_table_hash_entry_delete_key32_lru(
 	/* Key is present in the bucket */
 	for (i = 0; i < 4; i++) {
 		uint64_t bucket_signature = bucket->signature[i];
-		uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+		uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 		if ((bucket_signature == signature) &&
-			(memcmp(key, bucket_key, f->key_size) == 0)) {
+			(keycmp(bucket_key, key, f->key_mask) == 0)) {
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			bucket->signature[i] = 0;
@@ -299,81 +373,72 @@ rte_table_hash_entry_delete_key32_lru(
 	return 0;
 }
 
-static int
-check_params_create_ext(struct rte_table_hash_key32_ext_params *params) {
-	/* n_entries */
-	if (params->n_entries == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries is zero\n", __func__);
-		return -EINVAL;
-	}
-
-	/* n_entries_ext */
-	if (params->n_entries_ext == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries_ext is zero\n", __func__);
-		return -EINVAL;
-	}
-
-	/* f_hash */
-	if (params->f_hash == NULL) {
-		RTE_LOG(ERR, TABLE, "%s: f_hash function pointer is NULL\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static void *
 rte_table_hash_create_key32_ext(void *params,
 	int socket_id,
 	uint32_t entry_size)
 {
-	struct rte_table_hash_key32_ext_params *p =
-			params;
+	struct rte_table_hash_params *p = params;
 	struct rte_table_hash *f;
-	uint32_t n_buckets, n_buckets_ext, n_entries_per_bucket;
-	uint32_t key_size, bucket_size_cl, stack_size_cl, total_size, i;
+	uint64_t bucket_size, stack_size, total_size;
+	uint32_t n_buckets_ext, i;
 
 	/* Check input parameters */
-	if ((check_params_create_ext(p) != 0) ||
+	if ((check_params_create(p) != 0) ||
 		((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
 		((sizeof(struct rte_bucket_4_32) % 64) != 0))
 		return NULL;
 
-	n_entries_per_bucket = 4;
-	key_size = 32;
+	/*
+	 * Table dimensioning
+	 *
+	 * Objective: Pick the number of bucket extensions (n_buckets_ext) so that
+	 * it is guaranteed that n_keys keys can be stored in the table at any time.
+	 *
+	 * The worst case scenario takes place when all the n_keys keys fall into
+	 * the same bucket. Actually, due to the KEYS_PER_BUCKET scheme, the worst
+	 * case takes place when (n_keys - KEYS_PER_BUCKET + 1) keys fall into the
+	 * same bucket, while the remaining (KEYS_PER_BUCKET - 1) keys each fall
+	 * into a different bucket. This case defeats the purpose of the hash table.
+	 * It indicates unsuitable f_hash or n_keys to n_buckets ratio.
+	 *
+	 * n_buckets_ext = n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1
+	 */
+	n_buckets_ext = p->n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1;
 
 	/* Memory allocation */
-	n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
-		n_entries_per_bucket);
-	n_buckets_ext = (p->n_entries_ext + n_entries_per_bucket - 1) /
-		n_entries_per_bucket;
-	bucket_size_cl = (sizeof(struct rte_bucket_4_32) + n_entries_per_bucket
-		* entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
-	stack_size_cl = (n_buckets_ext * sizeof(uint32_t) + RTE_CACHE_LINE_SIZE - 1)
-		/ RTE_CACHE_LINE_SIZE;
+	bucket_size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_bucket_4_32) +
+		KEYS_PER_BUCKET * entry_size);
+	stack_size = RTE_CACHE_LINE_ROUNDUP(n_buckets_ext * sizeof(uint32_t));
 	total_size = sizeof(struct rte_table_hash) +
-		((n_buckets + n_buckets_ext) * bucket_size_cl + stack_size_cl) *
-		RTE_CACHE_LINE_SIZE;
+		(p->n_buckets + n_buckets_ext) * bucket_size + stack_size;
+	if (total_size > SIZE_MAX) {
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+			"for hash table %s\n",
+			__func__, total_size, p->name);
+		return NULL;
+	}
 
-	f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
+	f = rte_zmalloc_socket(p->name,
+		(size_t)total_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (f == NULL) {
-		RTE_LOG(ERR, TABLE,
-			"%s: Cannot allocate %u bytes for hash table\n",
-			__func__, total_size);
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+			"for hash table %s\n",
+			__func__, total_size, p->name);
 		return NULL;
 	}
 	RTE_LOG(INFO, TABLE,
-		"%s: Hash table memory footprint is %u bytes\n", __func__,
-		total_size);
+		"%s: Hash table %s memory footprint "
+		"is %" PRIu64" bytes\n",
+		__func__, p->name, total_size);
 
 	/* Memory initialization */
-	f->n_buckets = n_buckets;
-	f->n_entries_per_bucket = n_entries_per_bucket;
-	f->key_size = key_size;
+	f->n_buckets = p->n_buckets;
+	f->key_size = KEY_SIZE;
 	f->entry_size = entry_size;
-	f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
-	f->signature_offset = p->signature_offset;
+	f->bucket_size = bucket_size;
 	f->key_offset = p->key_offset;
 	f->f_hash = p->f_hash;
 	f->seed = p->seed;
@@ -381,7 +446,19 @@ rte_table_hash_create_key32_ext(void *params,
 	f->n_buckets_ext = n_buckets_ext;
 	f->stack_pos = n_buckets_ext;
 	f->stack = (uint32_t *)
-		&f->memory[(n_buckets + n_buckets_ext) * f->bucket_size];
+		&f->memory[(p->n_buckets + n_buckets_ext) * f->bucket_size];
+
+	if (p->key_mask != NULL) {
+		f->key_mask[0] = (((uint64_t *)p->key_mask)[0]);
+		f->key_mask[1] = (((uint64_t *)p->key_mask)[1]);
+		f->key_mask[2] = (((uint64_t *)p->key_mask)[2]);
+		f->key_mask[3] = (((uint64_t *)p->key_mask)[3]);
+	} else {
+		f->key_mask[0] = 0xFFFFFFFFFFFFFFFFLLU;
+		f->key_mask[1] = 0xFFFFFFFFFFFFFFFFLLU;
+		f->key_mask[2] = 0xFFFFFFFFFFFFFFFFLLU;
+		f->key_mask[3] = 0xFFFFFFFFFFFFFFFFLLU;
+	}
 
 	for (i = 0; i < n_buckets_ext; i++)
 		f->stack[i] = i;
@@ -417,7 +494,7 @@ rte_table_hash_entry_add_key32_ext(
 	uint64_t signature;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket0 = (struct rte_bucket_4_32 *)
 			&f->memory[bucket_index * f->bucket_size];
@@ -427,10 +504,10 @@ rte_table_hash_entry_add_key32_ext(
 	for (bucket = bucket0; bucket != NULL; bucket = bucket->next) {
 		for (i = 0; i < 4; i++) {
 			uint64_t bucket_signature = bucket->signature[i];
-			uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+			uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 			if ((bucket_signature == signature) &&
-				(memcmp(key, bucket_key, f->key_size) == 0)) {
+				(keycmp(bucket_key, key, f->key_mask) == 0)) {
 				uint8_t *bucket_data = &bucket->data[i *
 					f->entry_size];
 
@@ -448,14 +525,14 @@ rte_table_hash_entry_add_key32_ext(
 		bucket_prev = bucket, bucket = bucket->next)
 		for (i = 0; i < 4; i++) {
 			uint64_t bucket_signature = bucket->signature[i];
-			uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+			uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 			if (bucket_signature == 0) {
 				uint8_t *bucket_data = &bucket->data[i *
 					f->entry_size];
 
 				bucket->signature[i] = signature;
-				memcpy(bucket_key, key, f->key_size);
+				keycpy(bucket_key, key, f->key_mask);
 				memcpy(bucket_data, entry, f->entry_size);
 				*key_found = 0;
 				*entry_ptr = (void *) bucket_data;
@@ -475,7 +552,7 @@ rte_table_hash_entry_add_key32_ext(
 		bucket_prev->next_valid = 1;
 
 		bucket->signature[0] = signature;
-		memcpy(bucket->key[0], key, f->key_size);
+		keycpy(&bucket->key[0], key, f->key_mask);
 		memcpy(&bucket->data[0], entry, f->entry_size);
 		*key_found = 0;
 		*entry_ptr = (void *) &bucket->data[0];
@@ -497,7 +574,7 @@ rte_table_hash_entry_delete_key32_ext(
 	uint64_t signature;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket0 = (struct rte_bucket_4_32 *)
 		&f->memory[bucket_index * f->bucket_size];
@@ -508,24 +585,23 @@ rte_table_hash_entry_delete_key32_ext(
 		bucket_prev = bucket, bucket = bucket->next)
 		for (i = 0; i < 4; i++) {
 			uint64_t bucket_signature = bucket->signature[i];
-			uint8_t *bucket_key = (uint8_t *) bucket->key[i];
+			uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
 
 			if ((bucket_signature == signature) &&
-				(memcmp(key, bucket_key, f->key_size) == 0)) {
+				(keycmp(bucket_key, key, f->key_mask) == 0)) {
 				uint8_t *bucket_data = &bucket->data[i *
 					f->entry_size];
 
 				bucket->signature[i] = 0;
 				*key_found = 1;
 				if (entry)
-					memcpy(entry, bucket_data,
-						f->entry_size);
+					memcpy(entry, bucket_data, f->entry_size);
 
 				if ((bucket->signature[0] == 0) &&
-						(bucket->signature[1] == 0) &&
-						(bucket->signature[2] == 0) &&
-						(bucket->signature[3] == 0) &&
-						(bucket_prev != NULL)) {
+					(bucket->signature[1] == 0) &&
+					(bucket->signature[2] == 0) &&
+					(bucket->signature[3] == 0) &&
+					(bucket_prev != NULL)) {
 					bucket_prev->next = bucket->next;
 					bucket_prev->next_valid =
 						bucket->next_valid;
@@ -546,34 +622,39 @@ rte_table_hash_entry_delete_key32_ext(
 	return 0;
 }
 
-#define lookup_key32_cmp(key_in, bucket, pos)			\
+#define lookup_key32_cmp(key_in, bucket, pos, f)			\
 {								\
-	uint64_t xor[4][4], or[4], signature[4];		\
+	uint64_t xor[4][4], or[4], signature[4], k[4];		\
+								\
+	k[0] = key_in[0] & f->key_mask[0];				\
+	k[1] = key_in[1] & f->key_mask[1];				\
+	k[2] = key_in[2] & f->key_mask[2];				\
+	k[3] = key_in[3] & f->key_mask[3];				\
 								\
 	signature[0] = ((~bucket->signature[0]) & 1);		\
 	signature[1] = ((~bucket->signature[1]) & 1);		\
 	signature[2] = ((~bucket->signature[2]) & 1);		\
 	signature[3] = ((~bucket->signature[3]) & 1);		\
 								\
-	xor[0][0] = key_in[0] ^	 bucket->key[0][0];		\
-	xor[0][1] = key_in[1] ^	 bucket->key[0][1];		\
-	xor[0][2] = key_in[2] ^	 bucket->key[0][2];		\
-	xor[0][3] = key_in[3] ^	 bucket->key[0][3];		\
+	xor[0][0] = k[0] ^ bucket->key[0][0];			\
+	xor[0][1] = k[1] ^ bucket->key[0][1];			\
+	xor[0][2] = k[2] ^ bucket->key[0][2];			\
+	xor[0][3] = k[3] ^ bucket->key[0][3];			\
 								\
-	xor[1][0] = key_in[0] ^	 bucket->key[1][0];		\
-	xor[1][1] = key_in[1] ^	 bucket->key[1][1];		\
-	xor[1][2] = key_in[2] ^	 bucket->key[1][2];		\
-	xor[1][3] = key_in[3] ^	 bucket->key[1][3];		\
+	xor[1][0] = k[0] ^ bucket->key[1][0];			\
+	xor[1][1] = k[1] ^ bucket->key[1][1];			\
+	xor[1][2] = k[2] ^ bucket->key[1][2];			\
+	xor[1][3] = k[3] ^ bucket->key[1][3];			\
 								\
-	xor[2][0] = key_in[0] ^	 bucket->key[2][0];		\
-	xor[2][1] = key_in[1] ^	 bucket->key[2][1];		\
-	xor[2][2] = key_in[2] ^	 bucket->key[2][2];		\
-	xor[2][3] = key_in[3] ^	 bucket->key[2][3];		\
+	xor[2][0] = k[0] ^ bucket->key[2][0];			\
+	xor[2][1] = k[1] ^ bucket->key[2][1];			\
+	xor[2][2] = k[2] ^ bucket->key[2][2];			\
+	xor[2][3] = k[3] ^ bucket->key[2][3];			\
 								\
-	xor[3][0] = key_in[0] ^	 bucket->key[3][0];		\
-	xor[3][1] = key_in[1] ^	 bucket->key[3][1];		\
-	xor[3][2] = key_in[2] ^	 bucket->key[3][2];		\
-	xor[3][3] = key_in[3] ^	 bucket->key[3][3];		\
+	xor[3][0] = k[0] ^ bucket->key[3][0];			\
+	xor[3][1] = k[1] ^ bucket->key[3][1];			\
+	xor[3][2] = k[2] ^ bucket->key[3][2];			\
+	xor[3][3] = k[3] ^ bucket->key[3][3];			\
 								\
 	or[0] = xor[0][0] | xor[0][1] | xor[0][2] | xor[0][3] | signature[0];\
 	or[1] = xor[1][0] | xor[1][1] | xor[1][2] | xor[1][3] | signature[1];\
@@ -604,12 +685,15 @@ rte_table_hash_entry_delete_key32_ext(
 	rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf0, key_offset));\
 }
 
-#define lookup1_stage1(mbuf1, bucket1, f)			\
+#define lookup1_stage1(mbuf1, bucket1, f)				\
 {								\
+	uint64_t *key;						\
 	uint64_t signature;					\
 	uint32_t bucket_index;					\
 								\
-	signature = RTE_MBUF_METADATA_UINT32(mbuf1, f->signature_offset);\
+	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf1, f->key_offset);	\
+	signature = f->f_hash(key, f->key_mask, KEY_SIZE, f->seed);	\
+								\
 	bucket_index = signature & (f->n_buckets - 1);		\
 	bucket1 = (struct rte_bucket_4_32 *)			\
 		&f->memory[bucket_index * f->bucket_size];	\
@@ -627,8 +711,7 @@ rte_table_hash_entry_delete_key32_ext(
 	uint32_t pos;						\
 								\
 	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
-								\
-	lookup_key32_cmp(key, bucket2, pos);			\
+	lookup_key32_cmp(key, bucket2, pos, f);			\
 								\
 	pkt_mask = (bucket2->signature[pos] & 1LLU) << pkt2_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -649,8 +732,7 @@ rte_table_hash_entry_delete_key32_ext(
 	uint32_t pos;						\
 								\
 	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
-								\
-	lookup_key32_cmp(key, bucket2, pos);			\
+	lookup_key32_cmp(key, bucket2, pos, f);			\
 								\
 	pkt_mask = (bucket2->signature[pos] & 1LLU) << pkt2_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -678,7 +760,7 @@ rte_table_hash_entry_delete_key32_ext(
 	bucket = buckets[pkt_index];				\
 	key = keys[pkt_index];					\
 								\
-	lookup_key32_cmp(key, bucket, pos);			\
+	lookup_key32_cmp(key, bucket, pos, f);			\
 								\
 	pkt_mask = (bucket->signature[pos] & 1LLU) << pkt_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -745,22 +827,27 @@ rte_table_hash_entry_delete_key32_ext(
 
 #define lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f)	\
 {								\
-	uint64_t signature10, signature11;			\
-	uint32_t bucket10_index, bucket11_index;		\
+	uint64_t *key10, *key11;					\
+	uint64_t signature10, signature11;				\
+	uint32_t bucket10_index, bucket11_index;			\
 								\
-	signature10 = RTE_MBUF_METADATA_UINT32(mbuf10, f->signature_offset);\
-	bucket10_index = signature10 & (f->n_buckets - 1);	\
+	key10 = RTE_MBUF_METADATA_UINT64_PTR(mbuf10, f->key_offset);	\
+	signature10 = f->f_hash(key10, f->key_mask,	 KEY_SIZE, f->seed); \
+								\
+	bucket10_index = signature10 & (f->n_buckets - 1);		\
 	bucket10 = (struct rte_bucket_4_32 *)			\
 		&f->memory[bucket10_index * f->bucket_size];	\
-	rte_prefetch0(bucket10);				\
+	rte_prefetch0(bucket10);					\
 	rte_prefetch0((void *)(((uintptr_t) bucket10) + RTE_CACHE_LINE_SIZE));\
 	rte_prefetch0((void *)(((uintptr_t) bucket10) + 2 * RTE_CACHE_LINE_SIZE));\
 								\
-	signature11 = RTE_MBUF_METADATA_UINT32(mbuf11, f->signature_offset);\
-	bucket11_index = signature11 & (f->n_buckets - 1);	\
+	key11 = RTE_MBUF_METADATA_UINT64_PTR(mbuf11, f->key_offset);	\
+	signature11 = f->f_hash(key11, f->key_mask, KEY_SIZE, f->seed);\
+								\
+	bucket11_index = signature11 & (f->n_buckets - 1);		\
 	bucket11 = (struct rte_bucket_4_32 *)			\
 		&f->memory[bucket11_index * f->bucket_size];	\
-	rte_prefetch0(bucket11);				\
+	rte_prefetch0(bucket11);					\
 	rte_prefetch0((void *)(((uintptr_t) bucket11) + RTE_CACHE_LINE_SIZE));\
 	rte_prefetch0((void *)(((uintptr_t) bucket11) + 2 * RTE_CACHE_LINE_SIZE));\
 }
@@ -776,8 +863,8 @@ rte_table_hash_entry_delete_key32_ext(
 	key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
 	key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
 								\
-	lookup_key32_cmp(key20, bucket20, pos20);		\
-	lookup_key32_cmp(key21, bucket21, pos21);		\
+	lookup_key32_cmp(key20, bucket20, pos20, f);		\
+	lookup_key32_cmp(key21, bucket21, pos21, f);		\
 								\
 	pkt20_mask = (bucket20->signature[pos20] & 1LLU) << pkt20_index;\
 	pkt21_mask = (bucket21->signature[pos21] & 1LLU) << pkt21_index;\
@@ -805,8 +892,8 @@ rte_table_hash_entry_delete_key32_ext(
 	key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
 	key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
 								\
-	lookup_key32_cmp(key20, bucket20, pos20);		\
-	lookup_key32_cmp(key21, bucket21, pos21);		\
+	lookup_key32_cmp(key20, bucket20, pos20, f);		\
+	lookup_key32_cmp(key21, bucket21, pos21, f);		\
 								\
 	pkt20_mask = (bucket20->signature[pos20] & 1LLU) << pkt20_index;\
 	pkt21_mask = (bucket21->signature[pos21] & 1LLU) << pkt21_index;\
diff --git a/lib/librte_table/rte_table_hash_key8.c b/lib/librte_table/rte_table_hash_key8.c
index 5f0c656..68a9a95 100644
--- a/lib/librte_table/rte_table_hash_key8.c
+++ b/lib/librte_table/rte_table_hash_key8.c
@@ -1,34 +1,34 @@
 /*-
- *	 BSD LICENSE
+ *   BSD LICENSE
  *
- *	 Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *	 All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
  *
- *	 Redistribution and use in source and binary forms, with or without
- *	 modification, are permitted provided that the following conditions
- *	 are met:
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
  *
- *	* Redistributions of source code must retain the above copyright
- *		 notice, this list of conditions and the following disclaimer.
- *	* Redistributions in binary form must reproduce the above copyright
- *		 notice, this list of conditions and the following disclaimer in
- *		 the documentation and/or other materials provided with the
- *		 distribution.
- *	* Neither the name of Intel Corporation nor the names of its
- *		 contributors may be used to endorse or promote products derived
- *		 from this software without specific prior written permission.
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
  *
- *	 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *	 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *	 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *	 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *	 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *	 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *	 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *	 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *	 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *	 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *	 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <string.h>
 #include <stdio.h>
@@ -42,7 +42,9 @@
 #include "rte_table_hash.h"
 #include "rte_lru.h"
 
-#define RTE_TABLE_HASH_KEY_SIZE						8
+#define KEY_SIZE						8
+
+#define KEYS_PER_BUCKET					4
 
 #ifdef RTE_TABLE_STATS_COLLECT
 
@@ -76,11 +78,9 @@ struct rte_table_hash {
 
 	/* Input parameters */
 	uint32_t n_buckets;
-	uint32_t n_entries_per_bucket;
 	uint32_t key_size;
 	uint32_t entry_size;
 	uint32_t bucket_size;
-	uint32_t signature_offset;
 	uint32_t key_offset;
 	uint64_t key_mask;
 	rte_table_hash_op_hash f_hash;
@@ -96,10 +96,45 @@ struct rte_table_hash {
 };
 
 static int
-check_params_create_lru(struct rte_table_hash_key8_lru_params *params) {
-	/* n_entries */
-	if (params->n_entries == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries is zero\n", __func__);
+keycmp(void *a, void *b, void *b_mask)
+{
+	uint64_t *a64 = a, *b64 = b, *b_mask64 = b_mask;
+
+	return a64[0] != (b64[0] & b_mask64[0]);
+}
+
+static void
+keycpy(void *dst, void *src, void *src_mask)
+{
+	uint64_t *dst64 = dst, *src64 = src, *src_mask64 = src_mask;
+
+	dst64[0] = src64[0] & src_mask64[0];
+}
+
+static int
+check_params_create(struct rte_table_hash_params *params) {
+	/* name */
+	if (params->name == NULL) {
+		RTE_LOG(ERR, TABLE, "%s: name invalid value\n", __func__);
+		return -EINVAL;
+	}
+
+	/* key_size */
+	if (params->key_size != KEY_SIZE) {
+		RTE_LOG(ERR, TABLE, "%s: key_size invalid value\n", __func__);
+		return -EINVAL;
+	}
+
+	/* n_keys */
+	if (params->n_keys == 0) {
+		RTE_LOG(ERR, TABLE, "%s: n_keys is zero\n", __func__);
+		return -EINVAL;
+	}
+
+	/* n_buckets */
+	if ((params->n_buckets == 0) ||
+		(!rte_is_power_of_2(params->n_buckets))) {
+		RTE_LOG(ERR, TABLE, "%s: n_buckets invalid value\n", __func__);
 		return -EINVAL;
 	}
 
@@ -116,47 +151,68 @@ check_params_create_lru(struct rte_table_hash_key8_lru_params *params) {
 static void *
 rte_table_hash_create_key8_lru(void *params, int socket_id, uint32_t entry_size)
 {
-	struct rte_table_hash_key8_lru_params *p =
-		(struct rte_table_hash_key8_lru_params *) params;
+	struct rte_table_hash_params *p = params;
 	struct rte_table_hash *f;
-	uint32_t n_buckets, n_entries_per_bucket, key_size, bucket_size_cl;
-	uint32_t total_size, i;
+	uint64_t bucket_size, total_size;
+	uint32_t n_buckets, i;
 
 	/* Check input parameters */
-	if ((check_params_create_lru(p) != 0) ||
+	if ((check_params_create(p) != 0) ||
 		((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
-		((sizeof(struct rte_bucket_4_8) % 64) != 0)) {
+		((sizeof(struct rte_bucket_4_8) % 64) != 0))
 		return NULL;
-	}
-	n_entries_per_bucket = 4;
-	key_size = 8;
+
+	/*
+	 * Table dimensioning
+	 *
+	 * Objective: Pick the number of buckets (n_buckets) so that there a chance
+	 * to store n_keys keys in the table.
+	 *
+	 * Note: Since the buckets do not get extended, it is not possible to
+	 * guarantee that n_keys keys can be stored in the table at any time. In the
+	 * worst case scenario when all the n_keys fall into the same bucket, only
+	 * a maximum of KEYS_PER_BUCKET keys will be stored in the table. This case
+	 * defeats the purpose of the hash table. It indicates unsuitable f_hash or
+	 * n_keys to n_buckets ratio.
+	 *
+	 * MIN(n_buckets) = (n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET
+	 */
+	n_buckets = rte_align32pow2(
+		(p->n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET);
+	n_buckets = RTE_MAX(n_buckets, p->n_buckets);
 
 	/* Memory allocation */
-	n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
-		n_entries_per_bucket);
-	bucket_size_cl = (sizeof(struct rte_bucket_4_8) + n_entries_per_bucket *
-		entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
-	total_size = sizeof(struct rte_table_hash) + n_buckets *
-		bucket_size_cl * RTE_CACHE_LINE_SIZE;
-
-	f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
+	bucket_size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_bucket_4_8) +
+		KEYS_PER_BUCKET * entry_size);
+	total_size = sizeof(struct rte_table_hash) + n_buckets * bucket_size;
+
+	if (total_size > SIZE_MAX) {
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes"
+			" for hash table %s\n",
+			__func__, total_size, p->name);
+		return NULL;
+	}
+
+	f = rte_zmalloc_socket(p->name,
+		(size_t)total_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (f == NULL) {
-		RTE_LOG(ERR, TABLE,
-			"%s: Cannot allocate %u bytes for hash table\n",
-			__func__, total_size);
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes"
+			" for hash table %s\n",
+			__func__, total_size, p->name);
 		return NULL;
 	}
-	RTE_LOG(INFO, TABLE,
-		"%s: Hash table memory footprint is %u bytes\n",
-		__func__, total_size);
+
+	RTE_LOG(INFO, TABLE, "%s: Hash table %s memory footprint "
+		"is %" PRIu64 " bytes\n",
+		__func__, p->name, total_size);
 
 	/* Memory initialization */
 	f->n_buckets = n_buckets;
-	f->n_entries_per_bucket = n_entries_per_bucket;
-	f->key_size = key_size;
+	f->key_size = KEY_SIZE;
 	f->entry_size = entry_size;
-	f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
-	f->signature_offset = p->signature_offset;
+	f->bucket_size = bucket_size;
 	f->key_offset = p->key_offset;
 	f->f_hash = p->f_hash;
 	f->seed = p->seed;
@@ -205,7 +261,7 @@ rte_table_hash_entry_add_key8_lru(
 	uint64_t signature, mask, pos;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, &f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket = (struct rte_bucket_4_8 *)
 		&f->memory[bucket_index * f->bucket_size];
@@ -213,10 +269,10 @@ rte_table_hash_entry_add_key8_lru(
 	/* Key is present in the bucket */
 	for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
 		uint64_t bucket_signature = bucket->signature;
-		uint64_t bucket_key = bucket->key[i];
+		uint64_t *bucket_key = &bucket->key[i];
 
 		if ((bucket_signature & mask) &&
-		    (*((uint64_t *) key) == bucket_key)) {
+			(keycmp(bucket_key, key, &f->key_mask) == 0)) {
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			memcpy(bucket_data, entry, f->entry_size);
@@ -235,7 +291,7 @@ rte_table_hash_entry_add_key8_lru(
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			bucket->signature |= mask;
-			bucket->key[i] = *((uint64_t *) key);
+			keycpy(&bucket->key[i], key, &f->key_mask);
 			memcpy(bucket_data, entry, f->entry_size);
 			lru_update(bucket, i);
 			*key_found = 0;
@@ -247,10 +303,10 @@ rte_table_hash_entry_add_key8_lru(
 
 	/* Bucket full: replace LRU entry */
 	pos = lru_pos(bucket);
-	bucket->key[pos] = *((uint64_t *) key);
+	keycpy(&bucket->key[pos], key, &f->key_mask);
 	memcpy(&bucket->data[pos * f->entry_size], entry, f->entry_size);
 	lru_update(bucket, pos);
-	*key_found	= 0;
+	*key_found = 0;
 	*entry_ptr = (void *) &bucket->data[pos * f->entry_size];
 
 	return 0;
@@ -268,7 +324,7 @@ rte_table_hash_entry_delete_key8_lru(
 	uint64_t signature, mask;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, &f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket = (struct rte_bucket_4_8 *)
 		&f->memory[bucket_index * f->bucket_size];
@@ -276,10 +332,10 @@ rte_table_hash_entry_delete_key8_lru(
 	/* Key is present in the bucket */
 	for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
 		uint64_t bucket_signature = bucket->signature;
-		uint64_t bucket_key = bucket->key[i];
+		uint64_t *bucket_key = &bucket->key[i];
 
 		if ((bucket_signature & mask) &&
-		    (*((uint64_t *) key) == bucket_key)) {
+			(keycmp(bucket_key, key, &f->key_mask) == 0)) {
 			uint8_t *bucket_data = &bucket->data[i * f->entry_size];
 
 			bucket->signature &= ~mask;
@@ -296,79 +352,71 @@ rte_table_hash_entry_delete_key8_lru(
 	return 0;
 }
 
-static int
-check_params_create_ext(struct rte_table_hash_key8_ext_params *params) {
-	/* n_entries */
-	if (params->n_entries == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries is zero\n", __func__);
-		return -EINVAL;
-	}
-
-	/* n_entries_ext */
-	if (params->n_entries_ext == 0) {
-		RTE_LOG(ERR, TABLE, "%s: n_entries_ext is zero\n", __func__);
-		return -EINVAL;
-	}
-
-	/* f_hash */
-	if (params->f_hash == NULL) {
-		RTE_LOG(ERR, TABLE, "%s: f_hash function pointer is NULL\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static void *
 rte_table_hash_create_key8_ext(void *params, int socket_id, uint32_t entry_size)
 {
-	struct rte_table_hash_key8_ext_params *p =
-		(struct rte_table_hash_key8_ext_params *) params;
+	struct rte_table_hash_params *p = params;
 	struct rte_table_hash *f;
-	uint32_t n_buckets, n_buckets_ext, n_entries_per_bucket, key_size;
-	uint32_t bucket_size_cl, stack_size_cl, total_size, i;
+	uint64_t bucket_size, stack_size, total_size;
+	uint32_t n_buckets_ext, i;
 
 	/* Check input parameters */
-	if ((check_params_create_ext(p) != 0) ||
+	if ((check_params_create(p) != 0) ||
 		((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
 		((sizeof(struct rte_bucket_4_8) % 64) != 0))
 		return NULL;
 
-	n_entries_per_bucket = 4;
-	key_size = 8;
+	/*
+	 * Table dimensioning
+	 *
+	 * Objective: Pick the number of bucket extensions (n_buckets_ext) so that
+	 * it is guaranteed that n_keys keys can be stored in the table at any time.
+	 *
+	 * The worst case scenario takes place when all the n_keys keys fall into
+	 * the same bucket. Actually, due to the KEYS_PER_BUCKET scheme, the worst
+	 * case takes place when (n_keys - KEYS_PER_BUCKET + 1) keys fall into the
+	 * same bucket, while the remaining (KEYS_PER_BUCKET - 1) keys each fall
+	 * into a different bucket. This case defeats the purpose of the hash table.
+	 * It indicates unsuitable f_hash or n_keys to n_buckets ratio.
+	 *
+	 * n_buckets_ext = n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1
+	 */
+	n_buckets_ext = p->n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1;
 
 	/* Memory allocation */
-	n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
-		n_entries_per_bucket);
-	n_buckets_ext = (p->n_entries_ext + n_entries_per_bucket - 1) /
-		n_entries_per_bucket;
-	bucket_size_cl = (sizeof(struct rte_bucket_4_8) + n_entries_per_bucket *
-		entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
-	stack_size_cl = (n_buckets_ext * sizeof(uint32_t) + RTE_CACHE_LINE_SIZE - 1)
-		/ RTE_CACHE_LINE_SIZE;
-	total_size = sizeof(struct rte_table_hash) + ((n_buckets +
-		n_buckets_ext) * bucket_size_cl + stack_size_cl) *
-		RTE_CACHE_LINE_SIZE;
-
-	f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
+	bucket_size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_bucket_4_8) +
+		KEYS_PER_BUCKET * entry_size);
+	stack_size = RTE_CACHE_LINE_ROUNDUP(n_buckets_ext * sizeof(uint32_t));
+	total_size = sizeof(struct rte_table_hash) +
+		(p->n_buckets + n_buckets_ext) * bucket_size + stack_size;
+
+	if (total_size > SIZE_MAX) {
+		RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
+			"for hash table %s\n",
+			__func__, total_size, p->name);
+		return NULL;
+	}
+
+	f = rte_zmalloc_socket(p->name,
+		(size_t)total_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (f == NULL) {
 		RTE_LOG(ERR, TABLE,
-			"%s: Cannot allocate %u bytes for hash table\n",
-			__func__, total_size);
+			"%s: Cannot allocate %" PRIu64 " bytes "
+			"for hash table %s\n",
+			__func__, total_size, p->name);
 		return NULL;
 	}
-	RTE_LOG(INFO, TABLE,
-		"%s: Hash table memory footprint is %u bytes\n",
-		__func__, total_size);
+	RTE_LOG(INFO, TABLE, "%s: Hash table %s memory footprint "
+		"is %" PRIu64 " bytes\n",
+		__func__, p->name, total_size);
 
 	/* Memory initialization */
-	f->n_buckets = n_buckets;
-	f->n_entries_per_bucket = n_entries_per_bucket;
-	f->key_size = key_size;
+	f->n_buckets = p->n_buckets;
+	f->key_size = KEY_SIZE;
 	f->entry_size = entry_size;
-	f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
-	f->signature_offset = p->signature_offset;
+	f->bucket_size = bucket_size;
 	f->key_offset = p->key_offset;
 	f->f_hash = p->f_hash;
 	f->seed = p->seed;
@@ -376,7 +424,7 @@ rte_table_hash_create_key8_ext(void *params, int socket_id, uint32_t entry_size)
 	f->n_buckets_ext = n_buckets_ext;
 	f->stack_pos = n_buckets_ext;
 	f->stack = (uint32_t *)
-		&f->memory[(n_buckets + n_buckets_ext) * f->bucket_size];
+		&f->memory[(p->n_buckets + n_buckets_ext) * f->bucket_size];
 
 	if (p->key_mask != NULL)
 		f->key_mask = ((uint64_t *)p->key_mask)[0];
@@ -417,7 +465,7 @@ rte_table_hash_entry_add_key8_ext(
 	uint64_t signature;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, &f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket0 = (struct rte_bucket_4_8 *)
 		&f->memory[bucket_index * f->bucket_size];
@@ -428,10 +476,10 @@ rte_table_hash_entry_add_key8_ext(
 
 		for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
 			uint64_t bucket_signature = bucket->signature;
-			uint64_t bucket_key = bucket->key[i];
+			uint64_t *bucket_key = &bucket->key[i];
 
 			if ((bucket_signature & mask) &&
-					(*((uint64_t *) key) == bucket_key)) {
+				(keycmp(bucket_key, key, &f->key_mask) == 0)) {
 				uint8_t *bucket_data = &bucket->data[i *
 					f->entry_size];
 
@@ -456,7 +504,7 @@ rte_table_hash_entry_add_key8_ext(
 					f->entry_size];
 
 				bucket->signature |= mask;
-				bucket->key[i] = *((uint64_t *) key);
+				keycpy(&bucket->key[i], key, &f->key_mask);
 				memcpy(bucket_data, entry, f->entry_size);
 				*key_found = 0;
 				*entry_ptr = (void *) bucket_data;
@@ -476,7 +524,7 @@ rte_table_hash_entry_add_key8_ext(
 		bucket_prev->next_valid = 1;
 
 		bucket->signature = 1;
-		bucket->key[0] = *((uint64_t *) key);
+		keycpy(&bucket->key[0], key, &f->key_mask);
 		memcpy(&bucket->data[0], entry, f->entry_size);
 		*key_found = 0;
 		*entry_ptr = (void *) &bucket->data[0];
@@ -498,7 +546,7 @@ rte_table_hash_entry_delete_key8_ext(
 	uint64_t signature;
 	uint32_t bucket_index, i;
 
-	signature = f->f_hash(key, f->key_size, f->seed);
+	signature = f->f_hash(key, &f->key_mask, f->key_size, f->seed);
 	bucket_index = signature & (f->n_buckets - 1);
 	bucket0 = (struct rte_bucket_4_8 *)
 		&f->memory[bucket_index * f->bucket_size];
@@ -510,10 +558,10 @@ rte_table_hash_entry_delete_key8_ext(
 
 		for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
 			uint64_t bucket_signature = bucket->signature;
-			uint64_t bucket_key = bucket->key[i];
+			uint64_t *bucket_key = &bucket->key[i];
 
 			if ((bucket_signature & mask) &&
-				(*((uint64_t *) key) == bucket_key)) {
+				(keycmp(bucket_key, key, &f->key_mask) == 0)) {
 				uint8_t *bucket_data = &bucket->data[i *
 					f->entry_size];
 
@@ -546,16 +594,17 @@ rte_table_hash_entry_delete_key8_ext(
 	return 0;
 }
 
-#define lookup_key8_cmp(key_in, bucket, pos)			\
+#define lookup_key8_cmp(key_in, bucket, pos, f)			\
 {								\
-	uint64_t xor[4], signature;				\
+	uint64_t xor[4], signature, k;				\
 								\
 	signature = ~bucket->signature;				\
 								\
-	xor[0] = (key_in[0] ^	 bucket->key[0]) | (signature & 1);\
-	xor[1] = (key_in[0] ^	 bucket->key[1]) | (signature & 2);\
-	xor[2] = (key_in[0] ^	 bucket->key[2]) | (signature & 4);\
-	xor[3] = (key_in[0] ^	 bucket->key[3]) | (signature & 8);\
+	k = key_in[0] & f->key_mask;				\
+	xor[0] = (k ^ bucket->key[0]) | (signature & 1);		\
+	xor[1] = (k ^ bucket->key[1]) | (signature & 2);		\
+	xor[2] = (k ^ bucket->key[2]) | (signature & 4);		\
+	xor[3] = (k ^ bucket->key[3]) | (signature & 8);		\
 								\
 	pos = 4;						\
 	if (xor[0] == 0)					\
@@ -583,27 +632,12 @@ rte_table_hash_entry_delete_key8_ext(
 
 #define lookup1_stage1(mbuf1, bucket1, f)			\
 {								\
-	uint64_t signature;					\
-	uint32_t bucket_index;					\
-								\
-	signature = RTE_MBUF_METADATA_UINT32(mbuf1, f->signature_offset);\
-	bucket_index = signature & (f->n_buckets - 1);		\
-	bucket1 = (struct rte_bucket_4_8 *)			\
-		&f->memory[bucket_index * f->bucket_size];	\
-	rte_prefetch0(bucket1);					\
-}
-
-#define lookup1_stage1_dosig(mbuf1, bucket1, f)			\
-{								\
 	uint64_t *key;						\
 	uint64_t signature;					\
 	uint32_t bucket_index;					\
-	uint64_t hash_key_buffer;				\
 								\
 	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf1, f->key_offset);\
-	hash_key_buffer = *key & f->key_mask;			\
-	signature = f->f_hash(&hash_key_buffer,			\
-		RTE_TABLE_HASH_KEY_SIZE, f->seed);		\
+	signature = f->f_hash(key, &f->key_mask, KEY_SIZE, f->seed);	\
 	bucket_index = signature & (f->n_buckets - 1);		\
 	bucket1 = (struct rte_bucket_4_8 *)			\
 		&f->memory[bucket_index * f->bucket_size];	\
@@ -617,12 +651,9 @@ rte_table_hash_entry_delete_key8_ext(
 	uint64_t pkt_mask;					\
 	uint64_t *key;						\
 	uint32_t pos;						\
-	uint64_t hash_key_buffer;				\
 								\
 	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
-	hash_key_buffer = key[0] & f->key_mask;			\
-								\
-	lookup_key8_cmp((&hash_key_buffer), bucket2, pos);	\
+	lookup_key8_cmp(key, bucket2, pos, f);	\
 								\
 	pkt_mask = ((bucket2->signature >> pos) & 1LLU) << pkt2_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -641,12 +672,9 @@ rte_table_hash_entry_delete_key8_ext(
 	uint64_t pkt_mask, bucket_mask;				\
 	uint64_t *key;						\
 	uint32_t pos;						\
-	uint64_t hash_key_buffer;				\
 								\
 	key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
-	hash_key_buffer = *key & f->key_mask;			\
-								\
-	lookup_key8_cmp((&hash_key_buffer), bucket2, pos);	\
+	lookup_key8_cmp(key, bucket2, pos, f);	\
 								\
 	pkt_mask = ((bucket2->signature >> pos) & 1LLU) << pkt2_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -670,13 +698,10 @@ rte_table_hash_entry_delete_key8_ext(
 	uint64_t pkt_mask, bucket_mask;				\
 	uint64_t *key;						\
 	uint32_t pos;						\
-	uint64_t hash_key_buffer;				\
 								\
 	bucket = buckets[pkt_index];				\
 	key = keys[pkt_index];					\
-	hash_key_buffer = (*key) & f->key_mask;			\
-								\
-	lookup_key8_cmp((&hash_key_buffer), bucket, pos);	\
+	lookup_key8_cmp(key, bucket, pos, f);			\
 								\
 	pkt_mask = ((bucket->signature >> pos) & 1LLU) << pkt_index;\
 	pkts_mask_out |= pkt_mask;				\
@@ -738,29 +763,9 @@ rte_table_hash_entry_delete_key8_ext(
 	rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset));\
 }
 
-#define lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f)	\
-{								\
-	uint64_t signature10, signature11;			\
-	uint32_t bucket10_index, bucket11_index;		\
-								\
-	signature10 = RTE_MBUF_METADATA_UINT32(mbuf10, f->signature_offset);\
-	bucket10_index = signature10 & (f->n_buckets - 1);	\
-	bucket10 = (struct rte_bucket_4_8 *)			\
-		&f->memory[bucket10_index * f->bucket_size];	\
-	rte_prefetch0(bucket10);				\
-								\
-	signature11 = RTE_MBUF_METADATA_UINT32(mbuf11, f->signature_offset);\
-	bucket11_index = signature11 & (f->n_buckets - 1);	\
-	bucket11 = (struct rte_bucket_4_8 *)			\
-		&f->memory[bucket11_index * f->bucket_size];	\
-	rte_prefetch0(bucket11);				\
-}
-
-#define lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f)\
+#define lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f)\
 {								\
 	uint64_t *key10, *key11;				\
-	uint64_t hash_offset_buffer10;				\
-	uint64_t hash_offset_buffer11;				\
 	uint64_t signature10, signature11;			\
 	uint32_t bucket10_index, bucket11_index;		\
 	rte_table_hash_op_hash f_hash = f->f_hash;		\
@@ -769,18 +774,14 @@ rte_table_hash_entry_delete_key8_ext(
 								\
 	key10 = RTE_MBUF_METADATA_UINT64_PTR(mbuf10, key_offset);\
 	key11 = RTE_MBUF_METADATA_UINT64_PTR(mbuf11, key_offset);\
-	hash_offset_buffer10 = *key10 & f->key_mask;		\
-	hash_offset_buffer11 = *key11 & f->key_mask;		\
 								\
-	signature10 = f_hash(&hash_offset_buffer10,		\
-		RTE_TABLE_HASH_KEY_SIZE, seed);			\
+	signature10 = f_hash(key10, &f->key_mask, KEY_SIZE, seed);	\
 	bucket10_index = signature10 & (f->n_buckets - 1);	\
 	bucket10 = (struct rte_bucket_4_8 *)			\
 		&f->memory[bucket10_index * f->bucket_size];	\
 	rte_prefetch0(bucket10);				\
 								\
-	signature11 = f_hash(&hash_offset_buffer11,		\
-		RTE_TABLE_HASH_KEY_SIZE, seed);			\
+	signature11 = f_hash(key11, &f->key_mask, KEY_SIZE, seed);	\
 	bucket11_index = signature11 & (f->n_buckets - 1);	\
 	bucket11 = (struct rte_bucket_4_8 *)			\
 		&f->memory[bucket11_index * f->bucket_size];	\
@@ -793,17 +794,13 @@ rte_table_hash_entry_delete_key8_ext(
 	void *a20, *a21;					\
 	uint64_t pkt20_mask, pkt21_mask;			\
 	uint64_t *key20, *key21;				\
-	uint64_t hash_offset_buffer20;				\
-	uint64_t hash_offset_buffer21;				\
 	uint32_t pos20, pos21;					\
 								\
 	key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
 	key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
-	hash_offset_buffer20 = *key20 & f->key_mask;		\
-	hash_offset_buffer21 = *key21 & f->key_mask;		\
 								\
-	lookup_key8_cmp((&hash_offset_buffer20), bucket20, pos20);\
-	lookup_key8_cmp((&hash_offset_buffer21), bucket21, pos21);\
+	lookup_key8_cmp(key20, bucket20, pos20, f);			\
+	lookup_key8_cmp(key21, bucket21, pos21, f);			\
 								\
 	pkt20_mask = ((bucket20->signature >> pos20) & 1LLU) << pkt20_index;\
 	pkt21_mask = ((bucket21->signature >> pos21) & 1LLU) << pkt21_index;\
@@ -826,17 +823,13 @@ rte_table_hash_entry_delete_key8_ext(
 	void *a20, *a21;					\
 	uint64_t pkt20_mask, pkt21_mask, bucket20_mask, bucket21_mask;\
 	uint64_t *key20, *key21;				\
-	uint64_t hash_offset_buffer20;				\
-	uint64_t hash_offset_buffer21;				\
 	uint32_t pos20, pos21;					\
 								\
 	key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
 	key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
-	hash_offset_buffer20 = *key20 & f->key_mask;		\
-	hash_offset_buffer21 = *key21 & f->key_mask;		\
 								\
-	lookup_key8_cmp((&hash_offset_buffer20), bucket20, pos20);\
-	lookup_key8_cmp((&hash_offset_buffer21), bucket21, pos21);\
+	lookup_key8_cmp(key20, bucket20, pos20, f);			\
+	lookup_key8_cmp(key21, bucket21, pos21, f);			\
 								\
 	pkt20_mask = ((bucket20->signature >> pos20) & 1LLU) << pkt20_index;\
 	pkt21_mask = ((bucket21->signature >> pos21) & 1LLU) << pkt21_index;\
@@ -871,8 +864,8 @@ rte_table_hash_lookup_key8_lru(
 	struct rte_table_hash *f = (struct rte_table_hash *) table;
 	struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
 	struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
-	uint32_t pkt00_index, pkt01_index, pkt10_index,
-			pkt11_index, pkt20_index, pkt21_index;
+	uint32_t pkt00_index, pkt01_index, pkt10_index;
+	uint32_t pkt11_index, pkt20_index, pkt21_index;
 	uint64_t pkts_mask_out = 0;
 
 	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
@@ -888,7 +881,7 @@ rte_table_hash_lookup_key8_lru(
 			lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
 			lookup1_stage1(mbuf, bucket, f);
 			lookup1_stage2_lru(pkt_index, mbuf, bucket,
-					pkts_mask_out, entries, f);
+				pkts_mask_out, entries, f);
 		}
 
 		*lookup_hit_mask = pkts_mask_out;
@@ -984,133 +977,7 @@ rte_table_hash_lookup_key8_lru(
 	*lookup_hit_mask = pkts_mask_out;
 	RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
 	return 0;
-} /* rte_table_hash_lookup_key8_lru() */
-
-static int
-rte_table_hash_lookup_key8_lru_dosig(
-	void *table,
-	struct rte_mbuf **pkts,
-	uint64_t pkts_mask,
-	uint64_t *lookup_hit_mask,
-	void **entries)
-{
-	struct rte_table_hash *f = (struct rte_table_hash *) table;
-	struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
-	struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
-	uint32_t pkt00_index, pkt01_index, pkt10_index;
-	uint32_t pkt11_index, pkt20_index, pkt21_index;
-	uint64_t pkts_mask_out = 0;
-
-	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
-	RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
-
-	/* Cannot run the pipeline with less than 5 packets */
-	if (__builtin_popcountll(pkts_mask) < 5) {
-		for ( ; pkts_mask; ) {
-			struct rte_bucket_4_8 *bucket;
-			struct rte_mbuf *mbuf;
-			uint32_t pkt_index;
-
-			lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
-			lookup1_stage1_dosig(mbuf, bucket, f);
-			lookup1_stage2_lru(pkt_index, mbuf, bucket,
-				pkts_mask_out, entries, f);
-		}
-
-		*lookup_hit_mask = pkts_mask_out;
-		RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
-		return 0;
-	}
-
-	/*
-	 * Pipeline fill
-	 *
-	 */
-	/* Pipeline stage 0 */
-	lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-		pkts_mask, f);
-
-	/* Pipeline feed */
-	mbuf10 = mbuf00;
-	mbuf11 = mbuf01;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-		pkts_mask, f);
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-	/*
-	 * Pipeline run
-	 *
-	 */
-	for ( ; pkts_mask; ) {
-		/* Pipeline feed */
-		bucket20 = bucket10;
-		bucket21 = bucket11;
-		mbuf20 = mbuf10;
-		mbuf21 = mbuf11;
-		mbuf10 = mbuf00;
-		mbuf11 = mbuf01;
-		pkt20_index = pkt10_index;
-		pkt21_index = pkt11_index;
-		pkt10_index = pkt00_index;
-		pkt11_index = pkt01_index;
-
-		/* Pipeline stage 0 */
-		lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
-			mbuf00, mbuf01, pkts, pkts_mask, f);
-
-		/* Pipeline stage 1 */
-		lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-		/* Pipeline stage 2 */
-		lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
-			bucket20, bucket21, pkts_mask_out, entries, f);
-	}
-
-	/*
-	 * Pipeline flush
-	 *
-	 */
-	/* Pipeline feed */
-	bucket20 = bucket10;
-	bucket21 = bucket11;
-	mbuf20 = mbuf10;
-	mbuf21 = mbuf11;
-	mbuf10 = mbuf00;
-	mbuf11 = mbuf01;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-	/* Pipeline stage 2 */
-	lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
-		bucket20, bucket21, pkts_mask_out, entries, f);
-
-	/* Pipeline feed */
-	bucket20 = bucket10;
-	bucket21 = bucket11;
-	mbuf20 = mbuf10;
-	mbuf21 = mbuf11;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-
-	/* Pipeline stage 2 */
-	lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
-		bucket20, bucket21, pkts_mask_out, entries, f);
-
-	*lookup_hit_mask = pkts_mask_out;
-	RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
-	return 0;
-} /* rte_table_hash_lookup_key8_lru_dosig() */
+} /* lookup LRU */
 
 static int
 rte_table_hash_lookup_key8_ext(
@@ -1142,8 +1009,8 @@ rte_table_hash_lookup_key8_ext(
 			lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
 			lookup1_stage1(mbuf, bucket, f);
 			lookup1_stage2_ext(pkt_index, mbuf, bucket,
-				pkts_mask_out, entries, buckets_mask, buckets,
-				keys, f);
+				pkts_mask_out, entries, buckets_mask,
+				buckets, keys, f);
 		}
 
 		goto grind_next_buckets;
@@ -1260,157 +1127,7 @@ rte_table_hash_lookup_key8_ext(
 	*lookup_hit_mask = pkts_mask_out;
 	RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
 	return 0;
-} /* rte_table_hash_lookup_key8_ext() */
-
-static int
-rte_table_hash_lookup_key8_ext_dosig(
-	void *table,
-	struct rte_mbuf **pkts,
-	uint64_t pkts_mask,
-	uint64_t *lookup_hit_mask,
-	void **entries)
-{
-	struct rte_table_hash *f = (struct rte_table_hash *) table;
-	struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
-	struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
-	uint32_t pkt00_index, pkt01_index, pkt10_index;
-	uint32_t pkt11_index, pkt20_index, pkt21_index;
-	uint64_t pkts_mask_out = 0, buckets_mask = 0;
-	struct rte_bucket_4_8 *buckets[RTE_PORT_IN_BURST_SIZE_MAX];
-	uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
-
-	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
-	RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
-
-	/* Cannot run the pipeline with less than 5 packets */
-	if (__builtin_popcountll(pkts_mask) < 5) {
-		for ( ; pkts_mask; ) {
-			struct rte_bucket_4_8 *bucket;
-			struct rte_mbuf *mbuf;
-			uint32_t pkt_index;
-
-			lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
-			lookup1_stage1_dosig(mbuf, bucket, f);
-			lookup1_stage2_ext(pkt_index, mbuf, bucket,
-				pkts_mask_out, entries, buckets_mask,
-				buckets, keys, f);
-		}
-
-		goto grind_next_buckets;
-	}
-
-	/*
-	 * Pipeline fill
-	 *
-	 */
-	/* Pipeline stage 0 */
-	lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-		pkts_mask, f);
-
-	/* Pipeline feed */
-	mbuf10 = mbuf00;
-	mbuf11 = mbuf01;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-		pkts_mask, f);
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-	/*
-	 * Pipeline run
-	 *
-	 */
-	for ( ; pkts_mask; ) {
-		/* Pipeline feed */
-		bucket20 = bucket10;
-		bucket21 = bucket11;
-		mbuf20 = mbuf10;
-		mbuf21 = mbuf11;
-		mbuf10 = mbuf00;
-		mbuf11 = mbuf01;
-		pkt20_index = pkt10_index;
-		pkt21_index = pkt11_index;
-		pkt10_index = pkt00_index;
-		pkt11_index = pkt01_index;
-
-		/* Pipeline stage 0 */
-		lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
-			mbuf00, mbuf01, pkts, pkts_mask, f);
-
-		/* Pipeline stage 1 */
-		lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-		/* Pipeline stage 2 */
-		lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
-			bucket20, bucket21, pkts_mask_out, entries,
-			buckets_mask, buckets, keys, f);
-	}
-
-	/*
-	 * Pipeline flush
-	 *
-	 */
-	/* Pipeline feed */
-	bucket20 = bucket10;
-	bucket21 = bucket11;
-	mbuf20 = mbuf10;
-	mbuf21 = mbuf11;
-	mbuf10 = mbuf00;
-	mbuf11 = mbuf01;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
-
-	/* Pipeline stage 2 */
-	lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
-		bucket20, bucket21, pkts_mask_out, entries,
-		buckets_mask, buckets, keys, f);
-
-	/* Pipeline feed */
-	bucket20 = bucket10;
-	bucket21 = bucket11;
-	mbuf20 = mbuf10;
-	mbuf21 = mbuf11;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-
-	/* Pipeline stage 2 */
-	lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
-		bucket20, bucket21, pkts_mask_out, entries,
-		buckets_mask, buckets, keys, f);
-
-grind_next_buckets:
-	/* Grind next buckets */
-	for ( ; buckets_mask; ) {
-		uint64_t buckets_mask_next = 0;
-
-		for ( ; buckets_mask; ) {
-			uint64_t pkt_mask;
-			uint32_t pkt_index;
-
-			pkt_index = __builtin_ctzll(buckets_mask);
-			pkt_mask = 1LLU << pkt_index;
-			buckets_mask &= ~pkt_mask;
-
-			lookup_grinder(pkt_index, buckets, keys, pkts_mask_out,
-				entries, buckets_mask_next, f);
-		}
-
-		buckets_mask = buckets_mask_next;
-	}
-
-	*lookup_hit_mask = pkts_mask_out;
-	RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
-	return 0;
-} /* rte_table_hash_lookup_key8_dosig_ext() */
+} /* lookup EXT */
 
 static int
 rte_table_hash_key8_stats_read(void *table, struct rte_table_stats *stats, int clear)
@@ -1437,17 +1154,6 @@ struct rte_table_ops rte_table_hash_key8_lru_ops = {
 	.f_stats = rte_table_hash_key8_stats_read,
 };
 
-struct rte_table_ops rte_table_hash_key8_lru_dosig_ops = {
-	.f_create = rte_table_hash_create_key8_lru,
-	.f_free = rte_table_hash_free_key8_lru,
-	.f_add = rte_table_hash_entry_add_key8_lru,
-	.f_delete = rte_table_hash_entry_delete_key8_lru,
-	.f_add_bulk = NULL,
-	.f_delete_bulk = NULL,
-	.f_lookup = rte_table_hash_lookup_key8_lru_dosig,
-	.f_stats = rte_table_hash_key8_stats_read,
-};
-
 struct rte_table_ops rte_table_hash_key8_ext_ops = {
 	.f_create = rte_table_hash_create_key8_ext,
 	.f_free = rte_table_hash_free_key8_ext,
@@ -1458,14 +1164,3 @@ struct rte_table_ops rte_table_hash_key8_ext_ops = {
 	.f_lookup = rte_table_hash_lookup_key8_ext,
 	.f_stats = rte_table_hash_key8_stats_read,
 };
-
-struct rte_table_ops rte_table_hash_key8_ext_dosig_ops = {
-	.f_create = rte_table_hash_create_key8_ext,
-	.f_free = rte_table_hash_free_key8_ext,
-	.f_add = rte_table_hash_entry_add_key8_ext,
-	.f_delete = rte_table_hash_entry_delete_key8_ext,
-	.f_add_bulk = NULL,
-	.f_delete_bulk = NULL,
-	.f_lookup = rte_table_hash_lookup_key8_ext_dosig,
-	.f_stats = rte_table_hash_key8_stats_read,
-};
diff --git a/lib/librte_table/rte_table_hash_lru.c b/lib/librte_table/rte_table_hash_lru.c
index 5a4864e..139b8fb 100644
--- a/lib/librte_table/rte_table_hash_lru.c
+++ b/lib/librte_table/rte_table_hash_lru.c
@@ -1,34 +1,34 @@
 /*-
- *	 BSD LICENSE
+ *   BSD LICENSE
  *
- *	 Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *	 All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
  *
- *	 Redistribution and use in source and binary forms, with or without
- *	 modification, are permitted provided that the following conditions
- *	 are met:
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
  *
- *	* Redistributions of source code must retain the above copyright
- *		 notice, this list of conditions and the following disclaimer.
- *	* Redistributions in binary form must reproduce the above copyright
- *		 notice, this list of conditions and the following disclaimer in
- *		 the documentation and/or other materials provided with the
- *		 distribution.
- *	* Neither the name of Intel Corporation nor the names of its
- *		 contributors may be used to endorse or promote products derived
- *		 from this software without specific prior written permission.
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
  *
- *	 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *	 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *	 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *	 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *	 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *	 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *	 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *	 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *	 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *	 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *	 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <string.h>
@@ -86,7 +86,6 @@ struct rte_table_hash {
 	uint32_t n_buckets;
 	rte_table_hash_op_hash f_hash;
 	uint64_t seed;
-	uint32_t signature_offset;
 	uint32_t key_offset;
 
 	/* Internal */
@@ -99,6 +98,7 @@ struct rte_table_hash {
 	struct grinder grinders[RTE_PORT_IN_BURST_SIZE_MAX];
 
 	/* Tables */
+	uint64_t *key_mask;
 	struct bucket *buckets;
 	uint8_t *key_mem;
 	uint8_t *data_mem;
@@ -109,12 +109,39 @@ struct rte_table_hash {
 };
 
 static int
-check_params_create(struct rte_table_hash_lru_params *params)
+keycmp(void *a, void *b, void *b_mask, uint32_t n_bytes)
 {
-	uint32_t n_buckets_min;
+	uint64_t *a64 = a, *b64 = b, *b_mask64 = b_mask;
+	uint32_t i;
+
+	for (i = 0; i < n_bytes / sizeof(uint64_t); i++)
+		if (a64[i] != (b64[i] & b_mask64[i]))
+			return 1;
+
+	return 0;
+}
+
+static void
+keycpy(void *dst, void *src, void *src_mask, uint32_t n_bytes)
+{
+	uint64_t *dst64 = dst, *src64 = src, *src_mask64 = src_mask;
+	uint32_t i;
+
+	for (i = 0; i < n_bytes / sizeof(uint64_t); i++)
+		dst64[i] = src64[i] & src_mask64[i];
+}
+
+static int
+check_params_create(struct rte_table_hash_params *params)
+{
+	/* name */
+	if (params->name == NULL) {
+		RTE_LOG(ERR, TABLE, "%s: name invalid value\n", __func__);
+		return -EINVAL;
+	}
 
 	/* key_size */
-	if ((params->key_size == 0) ||
+	if ((params->key_size < sizeof(uint64_t)) ||
 		(!rte_is_power_of_2(params->key_size))) {
 		RTE_LOG(ERR, TABLE, "%s: key_size invalid value\n", __func__);
 		return -EINVAL;
@@ -128,10 +155,8 @@ check_params_create(struct rte_table_hash_lru_params *params)
 	}
 
 	/* n_buckets */
-	n_buckets_min = (params->n_keys + KEYS_PER_BUCKET - 1) / params->n_keys;
 	if ((params->n_buckets == 0) ||
-		(!rte_is_power_of_2(params->n_keys)) ||
-		(params->n_buckets < n_buckets_min)) {
+		(!rte_is_power_of_2(params->n_keys))) {
 		RTE_LOG(ERR, TABLE, "%s: n_buckets invalid value\n", __func__);
 		return -EINVAL;
 	}
@@ -148,13 +173,13 @@ check_params_create(struct rte_table_hash_lru_params *params)
 static void *
 rte_table_hash_lru_create(void *params, int socket_id, uint32_t entry_size)
 {
-	struct rte_table_hash_lru_params *p =
-		params;
+	struct rte_table_hash_params *p = params;
 	struct rte_table_hash *t;
-	uint32_t total_size, table_meta_sz;
-	uint32_t bucket_sz, key_sz, key_stack_sz, data_sz;
-	uint32_t bucket_offset, key_offset, key_stack_offset, data_offset;
-	uint32_t i;
+	uint64_t table_meta_sz, key_mask_sz, bucket_sz, key_sz, key_stack_sz;
+	uint64_t data_sz, total_size;
+	uint64_t key_mask_offset, bucket_offset, key_offset, key_stack_offset;
+	uint64_t data_offset;
+	uint32_t n_buckets, i;
 
 	/* Check input parameters */
 	if ((check_params_create(p) != 0) ||
@@ -164,33 +189,65 @@ rte_table_hash_lru_create(void *params, int socket_id, uint32_t entry_size)
 		return NULL;
 	}
 
+	/*
+	 * Table dimensioning
+	 *
+	 * Objective: Pick the number of buckets (n_buckets) so that there a chance
+	 * to store n_keys keys in the table.
+	 *
+	 * Note: Since the buckets do not get extended, it is not possible to
+	 * guarantee that n_keys keys can be stored in the table at any time. In the
+	 * worst case scenario when all the n_keys fall into the same bucket, only
+	 * a maximum of KEYS_PER_BUCKET keys will be stored in the table. This case
+	 * defeats the purpose of the hash table. It indicates unsuitable f_hash or
+	 * n_keys to n_buckets ratio.
+	 *
+	 * MIN(n_buckets) = (n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET
+	 */
+	n_buckets = rte_align32pow2(
+		(p->n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET);
+	n_buckets = RTE_MAX(n_buckets, p->n_buckets);
+
 	/* Memory allocation */
 	table_meta_sz = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_table_hash));
-	bucket_sz = RTE_CACHE_LINE_ROUNDUP(p->n_buckets * sizeof(struct bucket));
+	key_mask_sz = RTE_CACHE_LINE_ROUNDUP(p->key_size);
+	bucket_sz = RTE_CACHE_LINE_ROUNDUP(n_buckets * sizeof(struct bucket));
 	key_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * p->key_size);
 	key_stack_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * sizeof(uint32_t));
 	data_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * entry_size);
-	total_size = table_meta_sz + bucket_sz + key_sz + key_stack_sz +
-		data_sz;
+	total_size = table_meta_sz + key_mask_sz + bucket_sz + key_sz +
+		key_stack_sz + data_sz;
 
-	t = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
+	if (total_size > SIZE_MAX) {
+		RTE_LOG(ERR, TABLE,
+			"%s: Cannot allocate %" PRIu64 " bytes for hash "
+			"table %s\n",
+			__func__, total_size, p->name);
+		return NULL;
+	}
+
+	t = rte_zmalloc_socket(p->name,
+		(size_t)total_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (t == NULL) {
 		RTE_LOG(ERR, TABLE,
-			"%s: Cannot allocate %u bytes for hash table\n",
-			__func__, total_size);
+			"%s: Cannot allocate %" PRIu64 " bytes for hash "
+			"table %s\n",
+			__func__, total_size, p->name);
 		return NULL;
 	}
-	RTE_LOG(INFO, TABLE, "%s (%u-byte key): Hash table memory footprint is "
-		"%u bytes\n", __func__, p->key_size, total_size);
+	RTE_LOG(INFO, TABLE, "%s (%u-byte key): Hash table %s memory footprint"
+		" is %" PRIu64 " bytes\n",
+		__func__, p->key_size, p->name, total_size);
 
 	/* Memory initialization */
 	t->key_size = p->key_size;
 	t->entry_size = entry_size;
 	t->n_keys = p->n_keys;
-	t->n_buckets = p->n_buckets;
+	t->n_buckets = n_buckets;
 	t->f_hash = p->f_hash;
 	t->seed = p->seed;
-	t->signature_offset = p->signature_offset;
 	t->key_offset = p->key_offset;
 
 	/* Internal */
@@ -199,16 +256,24 @@ rte_table_hash_lru_create(void *params, int socket_id, uint32_t entry_size)
 	t->data_size_shl = __builtin_ctzl(entry_size);
 
 	/* Tables */
-	bucket_offset = 0;
+	key_mask_offset = 0;
+	bucket_offset = key_mask_offset + key_mask_sz;
 	key_offset = bucket_offset + bucket_sz;
 	key_stack_offset = key_offset + key_sz;
 	data_offset = key_stack_offset + key_stack_sz;
 
+	t->key_mask = (uint64_t *) &t->memory[key_mask_offset];
 	t->buckets = (struct bucket *) &t->memory[bucket_offset];
 	t->key_mem = &t->memory[key_offset];
 	t->key_stack = (uint32_t *) &t->memory[key_stack_offset];
 	t->data_mem = &t->memory[data_offset];
 
+	/* Key mask */
+	if (p->key_mask == NULL)
+		memset(t->key_mask, 0xFF, p->key_size);
+	else
+		memcpy(t->key_mask, p->key_mask, p->key_size);
+
 	/* Key stack */
 	for (i = 0; i < t->n_keys; i++)
 		t->key_stack[i] = t->n_keys - 1 - i;
@@ -246,7 +311,7 @@ rte_table_hash_lru_entry_add(void *table, void *key, void *entry,
 	uint64_t sig;
 	uint32_t bkt_index, i;
 
-	sig = t->f_hash(key, t->key_size, t->seed);
+	sig = t->f_hash(key, t->key_mask, t->key_size, t->seed);
 	bkt_index = sig & t->bucket_mask;
 	bkt = &t->buckets[bkt_index];
 	sig = (sig >> 16) | 1LLU;
@@ -258,8 +323,8 @@ rte_table_hash_lru_entry_add(void *table, void *key, void *entry,
 		uint8_t *bkt_key = &t->key_mem[bkt_key_index <<
 			t->key_size_shl];
 
-		if ((sig == bkt_sig) && (memcmp(key, bkt_key, t->key_size)
-			== 0)) {
+		if ((sig == bkt_sig) && (keycmp(bkt_key, key, t->key_mask,
+			t->key_size) == 0)) {
 			uint8_t *data = &t->data_mem[bkt_key_index <<
 				t->data_size_shl];
 
@@ -292,7 +357,7 @@ rte_table_hash_lru_entry_add(void *table, void *key, void *entry,
 
 			bkt->sig[i] = (uint16_t) sig;
 			bkt->key_pos[i] = bkt_key_index;
-			memcpy(bkt_key, key, t->key_size);
+			keycpy(bkt_key, key, t->key_mask, t->key_size);
 			memcpy(data, entry, t->entry_size);
 			lru_update(bkt, i);
 
@@ -311,7 +376,7 @@ rte_table_hash_lru_entry_add(void *table, void *key, void *entry,
 		uint8_t *data = &t->data_mem[bkt_key_index << t->data_size_shl];
 
 		bkt->sig[pos] = (uint16_t) sig;
-		memcpy(bkt_key, key, t->key_size);
+		keycpy(bkt_key, key, t->key_mask, t->key_size);
 		memcpy(data, entry, t->entry_size);
 		lru_update(bkt, pos);
 
@@ -330,7 +395,7 @@ rte_table_hash_lru_entry_delete(void *table, void *key, int *key_found,
 	uint64_t sig;
 	uint32_t bkt_index, i;
 
-	sig = t->f_hash(key, t->key_size, t->seed);
+	sig = t->f_hash(key, t->key_mask, t->key_size, t->seed);
 	bkt_index = sig & t->bucket_mask;
 	bkt = &t->buckets[bkt_index];
 	sig = (sig >> 16) | 1LLU;
@@ -343,14 +408,15 @@ rte_table_hash_lru_entry_delete(void *table, void *key, int *key_found,
 			t->key_size_shl];
 
 		if ((sig == bkt_sig) &&
-			(memcmp(key, bkt_key, t->key_size) == 0)) {
+			(keycmp(bkt_key, key, t->key_mask, t->key_size) == 0)) {
 			uint8_t *data = &t->data_mem[bkt_key_index <<
 				t->data_size_shl];
 
 			bkt->sig[i] = 0;
 			t->key_stack[t->key_stack_tos++] = bkt_key_index;
 			*key_found = 1;
-			memcpy(entry, data, t->entry_size);
+			if (entry)
+				memcpy(entry, data, t->entry_size);
 			return 0;
 		}
 	}
@@ -365,8 +431,7 @@ static int rte_table_hash_lru_lookup_unoptimized(
 	struct rte_mbuf **pkts,
 	uint64_t pkts_mask,
 	uint64_t *lookup_hit_mask,
-	void **entries,
-	int dosig)
+	void **entries)
 {
 	struct rte_table_hash *t = (struct rte_table_hash *) table;
 	uint64_t pkts_mask_out = 0;
@@ -387,11 +452,7 @@ static int rte_table_hash_lru_lookup_unoptimized(
 
 		pkt = pkts[pkt_index];
 		key = RTE_MBUF_METADATA_UINT8_PTR(pkt, t->key_offset);
-		if (dosig)
-			sig = (uint64_t) t->f_hash(key, t->key_size, t->seed);
-		else
-			sig = RTE_MBUF_METADATA_UINT32(pkt,
-				t->signature_offset);
+		sig = (uint64_t) t->f_hash(key, t->key_mask, t->key_size, t->seed);
 
 		bkt_index = sig & t->bucket_mask;
 		bkt = &t->buckets[bkt_index];
@@ -404,7 +465,7 @@ static int rte_table_hash_lru_lookup_unoptimized(
 			uint8_t *bkt_key = &t->key_mem[bkt_key_index <<
 				t->key_size_shl];
 
-			if ((sig == bkt_sig) && (memcmp(key, bkt_key,
+			if ((sig == bkt_sig) && (keycmp(bkt_key, key, t->key_mask,
 				t->key_size) == 0)) {
 				uint8_t *data = &t->data_mem[bkt_key_index <<
 					t->data_size_shl];
@@ -502,74 +563,75 @@ static int rte_table_hash_lru_lookup_unoptimized(
 	match_pos = (LUT_MATCH_POS >> (mask_all << 1)) & 3;	\
 }
 
-#define lookup_cmp_key(mbuf, key, match_key, f)			\
-{								\
+#define lookup_cmp_key(mbuf, key, match_key, f)				\
+{									\
 	uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(mbuf, f->key_offset);\
-	uint64_t *bkt_key = (uint64_t *) key;			\
-								\
-	switch (f->key_size) {					\
-	case 8:							\
-	{							\
-		uint64_t xor = pkt_key[0] ^ bkt_key[0];		\
-		match_key = 0;					\
-		if (xor == 0)					\
-			match_key = 1;				\
-	}							\
-	break;							\
-								\
-	case 16:						\
-	{							\
-		uint64_t xor[2], or;				\
-								\
-		xor[0] = pkt_key[0] ^ bkt_key[0];		\
-		xor[1] = pkt_key[1] ^ bkt_key[1];		\
-		or = xor[0] | xor[1];				\
-		match_key = 0;					\
-		if (or == 0)					\
-			match_key = 1;				\
-	}							\
-	break;							\
-								\
-	case 32:						\
-	{							\
-		uint64_t xor[4], or;				\
-								\
-		xor[0] = pkt_key[0] ^ bkt_key[0];		\
-		xor[1] = pkt_key[1] ^ bkt_key[1];		\
-		xor[2] = pkt_key[2] ^ bkt_key[2];		\
-		xor[3] = pkt_key[3] ^ bkt_key[3];		\
-		or = xor[0] | xor[1] | xor[2] | xor[3];		\
-		match_key = 0;					\
-		if (or == 0)					\
-			match_key = 1;				\
-	}							\
-	break;							\
-								\
-	case 64:						\
-	{							\
-		uint64_t xor[8], or;				\
-								\
-		xor[0] = pkt_key[0] ^ bkt_key[0];		\
-		xor[1] = pkt_key[1] ^ bkt_key[1];		\
-		xor[2] = pkt_key[2] ^ bkt_key[2];		\
-		xor[3] = pkt_key[3] ^ bkt_key[3];		\
-		xor[4] = pkt_key[4] ^ bkt_key[4];		\
-		xor[5] = pkt_key[5] ^ bkt_key[5];		\
-		xor[6] = pkt_key[6] ^ bkt_key[6];		\
-		xor[7] = pkt_key[7] ^ bkt_key[7];		\
-		or = xor[0] | xor[1] | xor[2] | xor[3] |	\
-			xor[4] | xor[5] | xor[6] | xor[7];	\
-		match_key = 0;					\
-		if (or == 0)					\
-			match_key = 1;				\
-	}							\
-	break;							\
-								\
-	default:						\
-		match_key = 0;					\
-		if (memcmp(pkt_key, bkt_key, f->key_size) == 0)	\
-			match_key = 1;				\
-	}							\
+	uint64_t *bkt_key = (uint64_t *) key;				\
+	uint64_t *key_mask = f->key_mask;					\
+									\
+	switch (f->key_size) {						\
+	case 8:								\
+	{								\
+		uint64_t xor = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];	\
+		match_key = 0;						\
+		if (xor == 0)						\
+			match_key = 1;					\
+	}								\
+	break;								\
+									\
+	case 16:							\
+	{								\
+		uint64_t xor[2], or;					\
+									\
+		xor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];		\
+		xor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];		\
+		or = xor[0] | xor[1];					\
+		match_key = 0;						\
+		if (or == 0)						\
+			match_key = 1;					\
+	}								\
+	break;								\
+									\
+	case 32:							\
+	{								\
+		uint64_t xor[4], or;					\
+									\
+		xor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];		\
+		xor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];		\
+		xor[2] = (pkt_key[2] & key_mask[2]) ^ bkt_key[2];		\
+		xor[3] = (pkt_key[3] & key_mask[3]) ^ bkt_key[3];		\
+		or = xor[0] | xor[1] | xor[2] | xor[3];			\
+		match_key = 0;						\
+		if (or == 0)						\
+			match_key = 1;					\
+	}								\
+	break;								\
+									\
+	case 64:							\
+	{								\
+		uint64_t xor[8], or;					\
+									\
+		xor[0] = (pkt_key[0] & key_mask[0]) ^ bkt_key[0];		\
+		xor[1] = (pkt_key[1] & key_mask[1]) ^ bkt_key[1];		\
+		xor[2] = (pkt_key[2] & key_mask[2]) ^ bkt_key[2];		\
+		xor[3] = (pkt_key[3] & key_mask[3]) ^ bkt_key[3];		\
+		xor[4] = (pkt_key[4] & key_mask[4]) ^ bkt_key[4];		\
+		xor[5] = (pkt_key[5] & key_mask[5]) ^ bkt_key[5];		\
+		xor[6] = (pkt_key[6] & key_mask[6]) ^ bkt_key[6];		\
+		xor[7] = (pkt_key[7] & key_mask[7]) ^ bkt_key[7];		\
+		or = xor[0] | xor[1] | xor[2] | xor[3] |		\
+			xor[4] | xor[5] | xor[6] | xor[7];		\
+		match_key = 0;						\
+		if (or == 0)						\
+			match_key = 1;					\
+	}								\
+	break;								\
+									\
+	default:							\
+		match_key = 0;						\
+		if (keycmp(bkt_key, pkt_key, key_mask, f->key_size) == 0)	\
+			match_key = 1;					\
+	}								\
 }
 
 #define lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index)\
@@ -616,38 +678,7 @@ static int rte_table_hash_lru_lookup_unoptimized(
 	rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset));\
 }
 
-#define lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index)	\
-{								\
-	struct grinder *g10, *g11;				\
-	uint64_t sig10, sig11, bkt10_index, bkt11_index;	\
-	struct rte_mbuf *mbuf10, *mbuf11;			\
-	struct bucket *bkt10, *bkt11, *buckets = t->buckets;	\
-	uint64_t bucket_mask = t->bucket_mask;			\
-	uint32_t signature_offset = t->signature_offset;	\
-								\
-	mbuf10 = pkts[pkt10_index];				\
-	sig10 = (uint64_t) RTE_MBUF_METADATA_UINT32(mbuf10, signature_offset);\
-	bkt10_index = sig10 & bucket_mask;			\
-	bkt10 = &buckets[bkt10_index];				\
-								\
-	mbuf11 = pkts[pkt11_index];				\
-	sig11 = (uint64_t) RTE_MBUF_METADATA_UINT32(mbuf11, signature_offset);\
-	bkt11_index = sig11 & bucket_mask;			\
-	bkt11 = &buckets[bkt11_index];				\
-								\
-	rte_prefetch0(bkt10);					\
-	rte_prefetch0(bkt11);					\
-								\
-	g10 = &g[pkt10_index];					\
-	g10->sig = sig10;					\
-	g10->bkt = bkt10;					\
-								\
-	g11 = &g[pkt11_index];					\
-	g11->sig = sig11;					\
-	g11->bkt = bkt11;					\
-}
-
-#define lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index)\
+#define lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index)\
 {								\
 	struct grinder *g10, *g11;				\
 	uint64_t sig10, sig11, bkt10_index, bkt11_index;	\
@@ -662,13 +693,13 @@ static int rte_table_hash_lru_lookup_unoptimized(
 								\
 	mbuf10 = pkts[pkt10_index];				\
 	key10 = RTE_MBUF_METADATA_UINT8_PTR(mbuf10, key_offset);\
-	sig10 = (uint64_t) f_hash(key10, key_size, seed);	\
+	sig10 = (uint64_t) f_hash(key10, t->key_mask, key_size, seed);\
 	bkt10_index = sig10 & bucket_mask;			\
 	bkt10 = &buckets[bkt10_index];				\
 								\
 	mbuf11 = pkts[pkt11_index];				\
 	key11 = RTE_MBUF_METADATA_UINT8_PTR(mbuf11, key_offset);\
-	sig11 = (uint64_t) f_hash(key11, key_size, seed);	\
+	sig11 = (uint64_t) f_hash(key11, t->key_mask, key_size, seed);\
 	bkt11_index = sig11 & bucket_mask;			\
 	bkt11 = &buckets[bkt11_index];				\
 								\
@@ -819,7 +850,7 @@ static int rte_table_hash_lru_lookup(
 	/* Cannot run the pipeline with less than 7 packets */
 	if (__builtin_popcountll(pkts_mask) < 7)
 		return rte_table_hash_lru_lookup_unoptimized(table, pkts,
-			pkts_mask, lookup_hit_mask, entries, 0);
+			pkts_mask, lookup_hit_mask, entries);
 
 	/* Pipeline stage 0 */
 	lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
@@ -923,140 +954,7 @@ static int rte_table_hash_lru_lookup(
 		uint64_t pkts_mask_out_slow = 0;
 
 		status = rte_table_hash_lru_lookup_unoptimized(table, pkts,
-			pkts_mask_match_many, &pkts_mask_out_slow, entries, 0);
-		pkts_mask_out |= pkts_mask_out_slow;
-	}
-
-	*lookup_hit_mask = pkts_mask_out;
-	RTE_TABLE_HASH_LRU_STATS_PKTS_LOOKUP_MISS(t, n_pkts_in - __builtin_popcountll(pkts_mask_out));
-	return status;
-}
-
-static int rte_table_hash_lru_lookup_dosig(
-	void *table,
-	struct rte_mbuf **pkts,
-	uint64_t pkts_mask,
-	uint64_t *lookup_hit_mask,
-	void **entries)
-{
-	struct rte_table_hash *t = (struct rte_table_hash *) table;
-	struct grinder *g = t->grinders;
-	uint64_t pkt00_index, pkt01_index, pkt10_index, pkt11_index;
-	uint64_t pkt20_index, pkt21_index, pkt30_index, pkt31_index;
-	uint64_t pkts_mask_out = 0, pkts_mask_match_many = 0;
-	int status = 0;
-
-	__rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
-	RTE_TABLE_HASH_LRU_STATS_PKTS_IN_ADD(t, n_pkts_in);
-
-	/* Cannot run the pipeline with less than 7 packets */
-	if (__builtin_popcountll(pkts_mask) < 7)
-		return rte_table_hash_lru_lookup_unoptimized(table, pkts,
-			pkts_mask, lookup_hit_mask, entries, 1);
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
-
-	/* Pipeline feed */
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
-
-	/* Pipeline feed */
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 0 */
-	lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
-
-	/* Pipeline stage 2 */
-	lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
-
-	/*
-	* Pipeline run
-	*
-	*/
-	for ( ; pkts_mask; ) {
-		/* Pipeline feed */
-		pkt30_index = pkt20_index;
-		pkt31_index = pkt21_index;
-		pkt20_index = pkt10_index;
-		pkt21_index = pkt11_index;
-		pkt10_index = pkt00_index;
-		pkt11_index = pkt01_index;
-
-		/* Pipeline stage 0 */
-		lookup2_stage0_with_odd_support(t, g, pkts, pkts_mask,
-			pkt00_index, pkt01_index);
-
-		/* Pipeline stage 1 */
-		lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
-
-		/* Pipeline stage 2 */
-		lookup2_stage2(t, g, pkt20_index, pkt21_index,
-			pkts_mask_match_many);
-
-		/* Pipeline stage 3 */
-		lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index,
-			pkts_mask_out, entries);
-	}
-
-	/* Pipeline feed */
-	pkt30_index = pkt20_index;
-	pkt31_index = pkt21_index;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-	pkt10_index = pkt00_index;
-	pkt11_index = pkt01_index;
-
-	/* Pipeline stage 1 */
-	lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
-
-	/* Pipeline stage 2 */
-	lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
-
-	/* Pipeline stage 3 */
-	lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
-		entries);
-
-	/* Pipeline feed */
-	pkt30_index = pkt20_index;
-	pkt31_index = pkt21_index;
-	pkt20_index = pkt10_index;
-	pkt21_index = pkt11_index;
-
-	/* Pipeline stage 2 */
-	lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
-
-	/* Pipeline stage 3 */
-	lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
-		entries);
-
-	/* Pipeline feed */
-	pkt30_index = pkt20_index;
-	pkt31_index = pkt21_index;
-
-	/* Pipeline stage 3 */
-	lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
-		entries);
-
-	/* Slow path */
-	pkts_mask_match_many &= ~pkts_mask_out;
-	if (pkts_mask_match_many) {
-		uint64_t pkts_mask_out_slow = 0;
-
-		status = rte_table_hash_lru_lookup_unoptimized(table, pkts,
-			pkts_mask_match_many, &pkts_mask_out_slow, entries, 1);
+			pkts_mask_match_many, &pkts_mask_out_slow, entries);
 		pkts_mask_out |= pkts_mask_out_slow;
 	}
 
@@ -1089,14 +987,3 @@ struct rte_table_ops rte_table_hash_lru_ops = {
 	.f_lookup = rte_table_hash_lru_lookup,
 	.f_stats = rte_table_hash_lru_stats_read,
 };
-
-struct rte_table_ops rte_table_hash_lru_dosig_ops = {
-	.f_create = rte_table_hash_lru_create,
-	.f_free = rte_table_hash_lru_free,
-	.f_add = rte_table_hash_lru_entry_add,
-	.f_delete = rte_table_hash_lru_entry_delete,
-	.f_add_bulk = NULL,
-	.f_delete_bulk = NULL,
-	.f_lookup = rte_table_hash_lru_lookup_dosig,
-	.f_stats = rte_table_hash_lru_stats_read,
-};
diff --git a/lib/librte_table/rte_table_version.map b/lib/librte_table/rte_table_version.map
index e1eaa27..f03fc3f 100644
--- a/lib/librte_table/rte_table_version.map
+++ b/lib/librte_table/rte_table_version.map
@@ -28,7 +28,7 @@ DPDK_2.2 {
 	rte_table_hash_key16_ext_dosig_ops;
 	rte_table_hash_key16_lru_dosig_ops;
 
-};
+} DPDK_2.0;
 
 DPDK_16.07 {
        global:
@@ -36,3 +36,24 @@ DPDK_16.07 {
        rte_table_hash_cuckoo_dosig_ops;
 
 } DPDK_2.0;
+
+DPDK_17.11 {
+	global:
+
+	rte_table_acl_ops;
+	rte_table_array_ops;
+	rte_table_hash_ext_ops;
+	rte_table_hash_key8_ext_ops;
+	rte_table_hash_key16_ext_ops;
+	rte_table_hash_key32_ext_ops;
+	rte_table_hash_lru_ops;
+	rte_table_hash_key8_lru_ops;
+	rte_table_hash_key16_lru_ops;
+	rte_table_hash_key32_lru_ops;
+	rte_table_hash_cuckoo_ops;
+	rte_table_lpm_ipv6_ops;
+	rte_table_lpm_ops;
+	rte_table_stub_ops;
+
+	local: *;
+};
-- 
2.7.4



More information about the dev mailing list