All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo de Lara <pablo.de.lara.guarch@intel.com>
To: dev@dpdk.org
Cc: bruce.richardson@intel.com,
	Pablo de Lara <pablo.de.lara.guarch@intel.com>
Subject: [PATCH v2] hash: fix to support multi process
Date: Wed, 30 Mar 2016 18:34:57 +0100	[thread overview]
Message-ID: <1459359297-31549-1-git-send-email-pablo.de.lara.guarch@intel.com> (raw)
In-Reply-To: <1458827804-25496-1-git-send-email-pablo.de.lara.guarch@intel.com>

Hash library used a function pointer to choose a different
key compare function, depending on the key size.
As a result, multiple processes could not use the same hash table,
as the function addresses vary from one process to another.

Instead, a jump table is used, so each process has its own
function addresses, accessing this table with an index stored
in the hash table (note that using a custom key compare function
is not supported in multi-process mode).

Fixes: 48a399119619 ("hash: replace with cuckoo hash implementation")

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---

Changes in v2:
- Added missing const
- Added extra info in documentation

 doc/guides/prog_guide/hash_lib.rst     |  8 ++++
 doc/guides/rel_notes/release_16_04.rst |  8 ++++
 lib/librte_hash/rte_cuckoo_hash.c      | 85 ++++++++++++++++++++++++++--------
 3 files changed, 82 insertions(+), 19 deletions(-)

diff --git a/doc/guides/prog_guide/hash_lib.rst b/doc/guides/prog_guide/hash_lib.rst
index 8f2cdbf..7944640 100644
--- a/doc/guides/prog_guide/hash_lib.rst
+++ b/doc/guides/prog_guide/hash_lib.rst
@@ -87,6 +87,14 @@ or stored in the hash table itself.
 The example hash tables in the L2/L3 Forwarding sample applications defines which port to forward a packet to based on a packet flow identified by the five-tuple lookup.
 However, this table could also be used for more sophisticated features and provide many other functions and actions that could be performed on the packets and flows.
 
+Multi-process support
+---------------------
+
+The hash library can be used in a multi-process environment, minding that only lookups are thread-safe.
+The only function that can only be used in single-process mode is rte_hash_set_cmp_func(), which sets up
+a custom compare function, which is assigned to a function pointer (therefore, it is not supported in
+multi-process mode).
+
 Implementation Details
 ----------------------
 
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 79d76e1..e6cc34d 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -404,6 +404,14 @@ Libraries
   Fix crc32c hash functions to return a valid crc32c value for data lengths
   not multiple of 4 bytes.
 
+* **hash: Fixed hash library to support multi-process mode.**
+
+  Fix hash library to support multi-process mode, using a jump table,
+  instead of storing a function pointer to the key compare function.
+  Multi-process mode only works with the built-in compare functions,
+  however a custom compare function (not in the jump table) can only
+  be used in single-process mode.
+
 * **librte_port: Fixed segmentation fault for ring and ethdev writer nodrop.**
 
   Fixed core dump issue on txq and swq when dropless is set to yes.
diff --git a/lib/librte_hash/rte_cuckoo_hash.c b/lib/librte_hash/rte_cuckoo_hash.c
index 71b5b76..bdba557 100644
--- a/lib/librte_hash/rte_cuckoo_hash.c
+++ b/lib/librte_hash/rte_cuckoo_hash.c
@@ -102,6 +102,41 @@ EAL_REGISTER_TAILQ(rte_hash_tailq)
 
 #define LCORE_CACHE_SIZE		8
 
+/*
+ * All different options to select a key compare function,
+ * based on the key size and custom function.
+ */
+enum cmp_jump_table_case {
+	KEY_CUSTOM = 0,
+	KEY_16_BYTES,
+	KEY_32_BYTES,
+	KEY_48_BYTES,
+	KEY_64_BYTES,
+	KEY_80_BYTES,
+	KEY_96_BYTES,
+	KEY_112_BYTES,
+	KEY_128_BYTES,
+	KEY_OTHER_BYTES,
+	NUM_KEY_CMP_CASES,
+};
+
+/*
+ * Table storing all different key compare functions
+ * (multi-process supported)
+ */
+const rte_hash_cmp_eq_t cmp_jump_table[NUM_KEY_CMP_CASES] = {
+	NULL,
+	rte_hash_k16_cmp_eq,
+	rte_hash_k32_cmp_eq,
+	rte_hash_k48_cmp_eq,
+	rte_hash_k64_cmp_eq,
+	rte_hash_k80_cmp_eq,
+	rte_hash_k96_cmp_eq,
+	rte_hash_k112_cmp_eq,
+	rte_hash_k128_cmp_eq,
+	memcmp
+};
+
 struct lcore_cache {
 	unsigned len; /**< Cache len */
 	void *objs[LCORE_CACHE_SIZE]; /**< Cache objects */
@@ -115,7 +150,10 @@ struct rte_hash {
 	uint32_t key_len;               /**< Length of hash key. */
 	rte_hash_function hash_func;    /**< Function used to calculate hash. */
 	uint32_t hash_func_init_val;    /**< Init value used by hash_func. */
-	rte_hash_cmp_eq_t rte_hash_cmp_eq; /**< Function used to compare keys. */
+	rte_hash_cmp_eq_t rte_hash_custom_cmp_eq;
+	/**< Custom function used to compare keys. */
+	enum cmp_jump_table_case cmp_jump_table_idx;
+	/**< Indicates which compare function to use. */
 	uint32_t bucket_bitmask;        /**< Bitmask for getting bucket index
 						from hash signature. */
 	uint32_t key_entry_size;         /**< Size of each key entry. */
@@ -187,7 +225,16 @@ rte_hash_find_existing(const char *name)
 
 void rte_hash_set_cmp_func(struct rte_hash *h, rte_hash_cmp_eq_t func)
 {
-	h->rte_hash_cmp_eq = func;
+	h->rte_hash_custom_cmp_eq = func;
+}
+
+static inline int
+rte_hash_cmp_eq(const void *key1, const void *key2, const struct rte_hash *h)
+{
+	if (h->cmp_jump_table_idx == KEY_CUSTOM)
+		return h->rte_hash_custom_cmp_eq(key1, key2, h->key_len);
+	else
+		return cmp_jump_table[h->cmp_jump_table_idx](key1, key2, h->key_len);
 }
 
 struct rte_hash *
@@ -292,35 +339,35 @@ rte_hash_create(const struct rte_hash_parameters *params)
 	/* Select function to compare keys */
 	switch (params->key_len) {
 	case 16:
-		h->rte_hash_cmp_eq = rte_hash_k16_cmp_eq;
+		h->cmp_jump_table_idx = KEY_16_BYTES;
 		break;
 	case 32:
-		h->rte_hash_cmp_eq = rte_hash_k32_cmp_eq;
+		h->cmp_jump_table_idx = KEY_32_BYTES;
 		break;
 	case 48:
-		h->rte_hash_cmp_eq = rte_hash_k48_cmp_eq;
+		h->cmp_jump_table_idx = KEY_48_BYTES;
 		break;
 	case 64:
-		h->rte_hash_cmp_eq = rte_hash_k64_cmp_eq;
+		h->cmp_jump_table_idx = KEY_64_BYTES;
 		break;
 	case 80:
-		h->rte_hash_cmp_eq = rte_hash_k80_cmp_eq;
+		h->cmp_jump_table_idx = KEY_80_BYTES;
 		break;
 	case 96:
-		h->rte_hash_cmp_eq = rte_hash_k96_cmp_eq;
+		h->cmp_jump_table_idx = KEY_96_BYTES;
 		break;
 	case 112:
-		h->rte_hash_cmp_eq = rte_hash_k112_cmp_eq;
+		h->cmp_jump_table_idx = KEY_112_BYTES;
 		break;
 	case 128:
-		h->rte_hash_cmp_eq = rte_hash_k128_cmp_eq;
+		h->cmp_jump_table_idx = KEY_128_BYTES;
 		break;
 	default:
 		/* If key is not multiple of 16, use generic memcmp */
-		h->rte_hash_cmp_eq = memcmp;
+		h->cmp_jump_table_idx = KEY_OTHER_BYTES;
 	}
 #else
-	h->rte_hash_cmp_eq = memcmp;
+	h->cmp_jump_table_idx = KEY_OTHER_BYTES;
 #endif
 
 	snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name);
@@ -594,7 +641,7 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,
 				prim_bkt->signatures[i].alt == alt_hash) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					prim_bkt->key_idx[i] * h->key_entry_size);
-			if (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {
+			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
 				/* Enqueue index of free slot back in the ring. */
 				enqueue_slot_back(h, cached_free_slots, slot_id);
 				/* Update data */
@@ -614,7 +661,7 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,
 				sec_bkt->signatures[i].current == alt_hash) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					sec_bkt->key_idx[i] * h->key_entry_size);
-			if (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {
+			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
 				/* Enqueue index of free slot back in the ring. */
 				enqueue_slot_back(h, cached_free_slots, slot_id);
 				/* Update data */
@@ -725,7 +772,7 @@ __rte_hash_lookup_with_hash(const struct rte_hash *h, const void *key,
 				bkt->signatures[i].sig != NULL_SIGNATURE) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					bkt->key_idx[i] * h->key_entry_size);
-			if (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {
+			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
 				if (data != NULL)
 					*data = k->pdata;
 				/*
@@ -748,7 +795,7 @@ __rte_hash_lookup_with_hash(const struct rte_hash *h, const void *key,
 				bkt->signatures[i].alt == sig) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					bkt->key_idx[i] * h->key_entry_size);
-			if (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {
+			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
 				if (data != NULL)
 					*data = k->pdata;
 				/*
@@ -840,7 +887,7 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,
 				bkt->signatures[i].sig != NULL_SIGNATURE) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					bkt->key_idx[i] * h->key_entry_size);
-			if (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {
+			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
 				remove_entry(h, bkt, i);
 
 				/*
@@ -863,7 +910,7 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,
 				bkt->signatures[i].sig != NULL_SIGNATURE) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					bkt->key_idx[i] * h->key_entry_size);
-			if (h->rte_hash_cmp_eq(key, k->key, h->key_len) == 0) {
+			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
 				remove_entry(h, bkt, i);
 
 				/*
@@ -980,7 +1027,7 @@ lookup_stage3(unsigned idx, const struct rte_hash_key *key_slot, const void * co
 	unsigned hit;
 	unsigned key_idx;
 
-	hit = !h->rte_hash_cmp_eq(key_slot->key, keys[idx], h->key_len);
+	hit = !rte_hash_cmp_eq(key_slot->key, keys[idx], h);
 	if (data != NULL)
 		data[idx] = key_slot->pdata;
 
-- 
2.5.5

  parent reply	other threads:[~2016-03-30 17:34 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-24 13:56 [PATCH] hash: fix to support multi process Pablo de Lara
2016-03-25 14:41 ` Bruce Richardson
2016-03-25 15:08   ` De Lara Guarch, Pablo
2016-03-30 17:34 ` Pablo de Lara [this message]
2016-04-01 13:07   ` [PATCH v2] " Thomas Monjalon
2016-04-01 14:08     ` De Lara Guarch, Pablo
2016-04-01 15:03   ` [PATCH v3 0/2] Multi-process support in hash library Pablo de Lara
2016-04-01 15:03     ` [PATCH v3 1/2] hash: use RTE_ARCH_X86 macro for X86 systems Pablo de Lara
2016-04-01 15:03     ` [PATCH v3 2/2] hash: fix to support multi process Pablo de Lara
2016-04-01 16:57     ` [PATCH v3 0/2] Multi-process support in hash library Thomas Monjalon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1459359297-31549-1-git-send-email-pablo.de.lara.guarch@intel.com \
    --to=pablo.de.lara.guarch@intel.com \
    --cc=bruce.richardson@intel.com \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.