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: *;
+};
