xref: /dpdk/lib/member/rte_member_ht.c (revision 33f5b0dcb11580be8091f3b589845e512008e2f0)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2017 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <rte_errno.h>
699a2dd95SBruce Richardson #include <rte_malloc.h>
799a2dd95SBruce Richardson #include <rte_prefetch.h>
899a2dd95SBruce Richardson #include <rte_random.h>
999a2dd95SBruce Richardson #include <rte_log.h>
1099a2dd95SBruce Richardson #include <rte_vect.h>
1199a2dd95SBruce Richardson 
120e21c7c0SDavid Marchand #include "member.h"
1399a2dd95SBruce Richardson #include "rte_member.h"
1499a2dd95SBruce Richardson #include "rte_member_ht.h"
1599a2dd95SBruce Richardson 
1699a2dd95SBruce Richardson #if defined(RTE_ARCH_X86)
1799a2dd95SBruce Richardson #include "rte_member_x86.h"
1899a2dd95SBruce Richardson #endif
1999a2dd95SBruce Richardson 
2099a2dd95SBruce Richardson /* Search bucket for entry with tmp_sig and update set_id */
2199a2dd95SBruce Richardson static inline int
2299a2dd95SBruce Richardson update_entry_search(uint32_t bucket_id, member_sig_t tmp_sig,
2399a2dd95SBruce Richardson 		struct member_ht_bucket *buckets,
2499a2dd95SBruce Richardson 		member_set_t set_id)
2599a2dd95SBruce Richardson {
2699a2dd95SBruce Richardson 	uint32_t i;
2799a2dd95SBruce Richardson 
2899a2dd95SBruce Richardson 	for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
2999a2dd95SBruce Richardson 		if (buckets[bucket_id].sigs[i] == tmp_sig) {
3099a2dd95SBruce Richardson 			buckets[bucket_id].sets[i] = set_id;
3199a2dd95SBruce Richardson 			return 1;
3299a2dd95SBruce Richardson 		}
3399a2dd95SBruce Richardson 	}
3499a2dd95SBruce Richardson 	return 0;
3599a2dd95SBruce Richardson }
3699a2dd95SBruce Richardson 
3799a2dd95SBruce Richardson static inline int
3899a2dd95SBruce Richardson search_bucket_single(uint32_t bucket_id, member_sig_t tmp_sig,
3999a2dd95SBruce Richardson 		struct member_ht_bucket *buckets,
4099a2dd95SBruce Richardson 		member_set_t *set_id)
4199a2dd95SBruce Richardson {
4299a2dd95SBruce Richardson 	uint32_t iter;
4399a2dd95SBruce Richardson 
4499a2dd95SBruce Richardson 	for (iter = 0; iter < RTE_MEMBER_BUCKET_ENTRIES; iter++) {
4599a2dd95SBruce Richardson 		if (tmp_sig == buckets[bucket_id].sigs[iter] &&
4699a2dd95SBruce Richardson 				buckets[bucket_id].sets[iter] !=
4799a2dd95SBruce Richardson 				RTE_MEMBER_NO_MATCH) {
4899a2dd95SBruce Richardson 			*set_id = buckets[bucket_id].sets[iter];
4999a2dd95SBruce Richardson 			return 1;
5099a2dd95SBruce Richardson 		}
5199a2dd95SBruce Richardson 	}
5299a2dd95SBruce Richardson 	return 0;
5399a2dd95SBruce Richardson }
5499a2dd95SBruce Richardson 
5599a2dd95SBruce Richardson static inline void
5699a2dd95SBruce Richardson search_bucket_multi(uint32_t bucket_id, member_sig_t tmp_sig,
5799a2dd95SBruce Richardson 		struct member_ht_bucket *buckets,
5899a2dd95SBruce Richardson 		uint32_t *counter,
5999a2dd95SBruce Richardson 		uint32_t matches_per_key,
6099a2dd95SBruce Richardson 		member_set_t *set_id)
6199a2dd95SBruce Richardson {
6299a2dd95SBruce Richardson 	uint32_t iter;
6399a2dd95SBruce Richardson 
6499a2dd95SBruce Richardson 	for (iter = 0; iter < RTE_MEMBER_BUCKET_ENTRIES; iter++) {
6599a2dd95SBruce Richardson 		if (tmp_sig == buckets[bucket_id].sigs[iter] &&
6699a2dd95SBruce Richardson 				buckets[bucket_id].sets[iter] !=
6799a2dd95SBruce Richardson 				RTE_MEMBER_NO_MATCH) {
6899a2dd95SBruce Richardson 			set_id[*counter] = buckets[bucket_id].sets[iter];
6999a2dd95SBruce Richardson 			(*counter)++;
7099a2dd95SBruce Richardson 			if (*counter >= matches_per_key)
7199a2dd95SBruce Richardson 				return;
7299a2dd95SBruce Richardson 		}
7399a2dd95SBruce Richardson 	}
7499a2dd95SBruce Richardson }
7599a2dd95SBruce Richardson 
7699a2dd95SBruce Richardson int
7799a2dd95SBruce Richardson rte_member_create_ht(struct rte_member_setsum *ss,
7899a2dd95SBruce Richardson 		const struct rte_member_parameters *params)
7999a2dd95SBruce Richardson {
8099a2dd95SBruce Richardson 	uint32_t i, j;
8199a2dd95SBruce Richardson 	uint32_t size_bucket_t;
8299a2dd95SBruce Richardson 	uint32_t num_entries = rte_align32pow2(params->num_keys);
8399a2dd95SBruce Richardson 
8499a2dd95SBruce Richardson 	if ((num_entries > RTE_MEMBER_ENTRIES_MAX) ||
8599a2dd95SBruce Richardson 			!rte_is_power_of_2(RTE_MEMBER_BUCKET_ENTRIES) ||
8699a2dd95SBruce Richardson 			num_entries < RTE_MEMBER_BUCKET_ENTRIES) {
8799a2dd95SBruce Richardson 		rte_errno = EINVAL;
880e21c7c0SDavid Marchand 		MEMBER_LOG(ERR,
890e21c7c0SDavid Marchand 			"Membership HT create with invalid parameters");
9099a2dd95SBruce Richardson 		return -EINVAL;
9199a2dd95SBruce Richardson 	}
9299a2dd95SBruce Richardson 
9399a2dd95SBruce Richardson 	uint32_t num_buckets = num_entries / RTE_MEMBER_BUCKET_ENTRIES;
9499a2dd95SBruce Richardson 
9599a2dd95SBruce Richardson 	size_bucket_t = sizeof(struct member_ht_bucket);
9699a2dd95SBruce Richardson 
9799a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = rte_zmalloc_socket(NULL,
9899a2dd95SBruce Richardson 			num_buckets * size_bucket_t,
9999a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE, ss->socket_id);
10099a2dd95SBruce Richardson 
10199a2dd95SBruce Richardson 	if (buckets == NULL) {
1020e21c7c0SDavid Marchand 		MEMBER_LOG(ERR, "memory allocation failed for HT "
1030e21c7c0SDavid Marchand 						"setsummary");
10499a2dd95SBruce Richardson 		return -ENOMEM;
10599a2dd95SBruce Richardson 	}
10699a2dd95SBruce Richardson 
10799a2dd95SBruce Richardson 	ss->table = buckets;
10899a2dd95SBruce Richardson 	ss->bucket_cnt = num_buckets;
10999a2dd95SBruce Richardson 	ss->bucket_mask = num_buckets - 1;
11099a2dd95SBruce Richardson 	ss->cache = params->is_cache;
11199a2dd95SBruce Richardson 
11299a2dd95SBruce Richardson 	for (i = 0; i < num_buckets; i++) {
11399a2dd95SBruce Richardson 		for (j = 0; j < RTE_MEMBER_BUCKET_ENTRIES; j++)
11499a2dd95SBruce Richardson 			buckets[i].sets[j] = RTE_MEMBER_NO_MATCH;
11599a2dd95SBruce Richardson 	}
11699a2dd95SBruce Richardson #if defined(RTE_ARCH_X86)
11799a2dd95SBruce Richardson 	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2) &&
11899a2dd95SBruce Richardson 			RTE_MEMBER_BUCKET_ENTRIES == 16 &&
11999a2dd95SBruce Richardson 			rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256)
12099a2dd95SBruce Richardson 		ss->sig_cmp_fn = RTE_MEMBER_COMPARE_AVX2;
12199a2dd95SBruce Richardson 	else
12299a2dd95SBruce Richardson #endif
12399a2dd95SBruce Richardson 		ss->sig_cmp_fn = RTE_MEMBER_COMPARE_SCALAR;
12499a2dd95SBruce Richardson 
1250e21c7c0SDavid Marchand 	MEMBER_LOG(DEBUG, "Hash table based filter created, "
1260e21c7c0SDavid Marchand 			"the table has %u entries, %u buckets",
12799a2dd95SBruce Richardson 			num_entries, num_buckets);
12899a2dd95SBruce Richardson 	return 0;
12999a2dd95SBruce Richardson }
13099a2dd95SBruce Richardson 
13199a2dd95SBruce Richardson static inline void
13299a2dd95SBruce Richardson get_buckets_index(const struct rte_member_setsum *ss, const void *key,
13399a2dd95SBruce Richardson 		uint32_t *prim_bkt, uint32_t *sec_bkt, member_sig_t *sig)
13499a2dd95SBruce Richardson {
13599a2dd95SBruce Richardson 	uint32_t first_hash = MEMBER_HASH_FUNC(key, ss->key_len,
13699a2dd95SBruce Richardson 						ss->prim_hash_seed);
13799a2dd95SBruce Richardson 	uint32_t sec_hash = MEMBER_HASH_FUNC(&first_hash, sizeof(uint32_t),
13899a2dd95SBruce Richardson 						ss->sec_hash_seed);
13999a2dd95SBruce Richardson 	/*
14099a2dd95SBruce Richardson 	 * We use the first hash value for the signature, and the second hash
14199a2dd95SBruce Richardson 	 * value to derive the primary and secondary bucket locations.
14299a2dd95SBruce Richardson 	 *
14399a2dd95SBruce Richardson 	 * For non-cache mode, we use the lower bits for the primary bucket
14499a2dd95SBruce Richardson 	 * location. Then we xor primary bucket location and the signature
14599a2dd95SBruce Richardson 	 * to get the secondary bucket location. This is called "partial-key
14699a2dd95SBruce Richardson 	 * cuckoo hashing" proposed by B. Fan, et al's paper
14799a2dd95SBruce Richardson 	 * "Cuckoo Filter: Practically Better Than Bloom". The benefit to use
14899a2dd95SBruce Richardson 	 * xor is that one could derive the alternative bucket location
14999a2dd95SBruce Richardson 	 * by only using the current bucket location and the signature. This is
15099a2dd95SBruce Richardson 	 * generally required by non-cache mode's eviction and deletion
15199a2dd95SBruce Richardson 	 * process without the need to store alternative hash value nor the full
15299a2dd95SBruce Richardson 	 * key.
15399a2dd95SBruce Richardson 	 *
15499a2dd95SBruce Richardson 	 * For cache mode, we use the lower bits for the primary bucket
15599a2dd95SBruce Richardson 	 * location and the higher bits for the secondary bucket location. In
15699a2dd95SBruce Richardson 	 * cache mode, keys are simply overwritten if bucket is full. We do not
15799a2dd95SBruce Richardson 	 * use xor since lower/higher bits are more independent hash values thus
15899a2dd95SBruce Richardson 	 * should provide slightly better table load.
15999a2dd95SBruce Richardson 	 */
16099a2dd95SBruce Richardson 	*sig = first_hash;
16199a2dd95SBruce Richardson 	if (ss->cache) {
16299a2dd95SBruce Richardson 		*prim_bkt = sec_hash & ss->bucket_mask;
16399a2dd95SBruce Richardson 		*sec_bkt =  (sec_hash >> 16) & ss->bucket_mask;
16499a2dd95SBruce Richardson 	} else {
16599a2dd95SBruce Richardson 		*prim_bkt = sec_hash & ss->bucket_mask;
16699a2dd95SBruce Richardson 		*sec_bkt =  (*prim_bkt ^ *sig) & ss->bucket_mask;
16799a2dd95SBruce Richardson 	}
16899a2dd95SBruce Richardson }
16999a2dd95SBruce Richardson 
17099a2dd95SBruce Richardson int
17199a2dd95SBruce Richardson rte_member_lookup_ht(const struct rte_member_setsum *ss,
17299a2dd95SBruce Richardson 		const void *key, member_set_t *set_id)
17399a2dd95SBruce Richardson {
17499a2dd95SBruce Richardson 	uint32_t prim_bucket, sec_bucket;
17599a2dd95SBruce Richardson 	member_sig_t tmp_sig;
17699a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = ss->table;
17799a2dd95SBruce Richardson 
17899a2dd95SBruce Richardson 	*set_id = RTE_MEMBER_NO_MATCH;
17999a2dd95SBruce Richardson 	get_buckets_index(ss, key, &prim_bucket, &sec_bucket, &tmp_sig);
18099a2dd95SBruce Richardson 
18199a2dd95SBruce Richardson 	switch (ss->sig_cmp_fn) {
18299a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) && defined(__AVX2__)
18399a2dd95SBruce Richardson 	case RTE_MEMBER_COMPARE_AVX2:
18499a2dd95SBruce Richardson 		if (search_bucket_single_avx(prim_bucket, tmp_sig, buckets,
18599a2dd95SBruce Richardson 				set_id) ||
18699a2dd95SBruce Richardson 				search_bucket_single_avx(sec_bucket, tmp_sig,
18799a2dd95SBruce Richardson 					buckets, set_id))
18899a2dd95SBruce Richardson 			return 1;
18999a2dd95SBruce Richardson 		break;
19099a2dd95SBruce Richardson #endif
19199a2dd95SBruce Richardson 	default:
19299a2dd95SBruce Richardson 		if (search_bucket_single(prim_bucket, tmp_sig, buckets,
19399a2dd95SBruce Richardson 				set_id) ||
19499a2dd95SBruce Richardson 				search_bucket_single(sec_bucket, tmp_sig,
19599a2dd95SBruce Richardson 					buckets, set_id))
19699a2dd95SBruce Richardson 			return 1;
19799a2dd95SBruce Richardson 	}
19899a2dd95SBruce Richardson 
19999a2dd95SBruce Richardson 	return 0;
20099a2dd95SBruce Richardson }
20199a2dd95SBruce Richardson 
20299a2dd95SBruce Richardson uint32_t
20399a2dd95SBruce Richardson rte_member_lookup_bulk_ht(const struct rte_member_setsum *ss,
20499a2dd95SBruce Richardson 		const void **keys, uint32_t num_keys, member_set_t *set_id)
20599a2dd95SBruce Richardson {
20699a2dd95SBruce Richardson 	uint32_t i;
20799a2dd95SBruce Richardson 	uint32_t num_matches = 0;
20899a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = ss->table;
20999a2dd95SBruce Richardson 	member_sig_t tmp_sig[RTE_MEMBER_LOOKUP_BULK_MAX];
21099a2dd95SBruce Richardson 	uint32_t prim_buckets[RTE_MEMBER_LOOKUP_BULK_MAX];
21199a2dd95SBruce Richardson 	uint32_t sec_buckets[RTE_MEMBER_LOOKUP_BULK_MAX];
21299a2dd95SBruce Richardson 
21399a2dd95SBruce Richardson 	for (i = 0; i < num_keys; i++) {
21499a2dd95SBruce Richardson 		get_buckets_index(ss, keys[i], &prim_buckets[i],
21599a2dd95SBruce Richardson 				&sec_buckets[i], &tmp_sig[i]);
21699a2dd95SBruce Richardson 		rte_prefetch0(&buckets[prim_buckets[i]]);
21799a2dd95SBruce Richardson 		rte_prefetch0(&buckets[sec_buckets[i]]);
21899a2dd95SBruce Richardson 	}
21999a2dd95SBruce Richardson 
22099a2dd95SBruce Richardson 	for (i = 0; i < num_keys; i++) {
22199a2dd95SBruce Richardson 		switch (ss->sig_cmp_fn) {
22299a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) && defined(__AVX2__)
22399a2dd95SBruce Richardson 		case RTE_MEMBER_COMPARE_AVX2:
22499a2dd95SBruce Richardson 			if (search_bucket_single_avx(prim_buckets[i],
22599a2dd95SBruce Richardson 					tmp_sig[i], buckets, &set_id[i]) ||
22699a2dd95SBruce Richardson 				search_bucket_single_avx(sec_buckets[i],
22799a2dd95SBruce Richardson 					tmp_sig[i], buckets, &set_id[i]))
22899a2dd95SBruce Richardson 				num_matches++;
22999a2dd95SBruce Richardson 			else
23099a2dd95SBruce Richardson 				set_id[i] = RTE_MEMBER_NO_MATCH;
23199a2dd95SBruce Richardson 			break;
23299a2dd95SBruce Richardson #endif
23399a2dd95SBruce Richardson 		default:
23499a2dd95SBruce Richardson 			if (search_bucket_single(prim_buckets[i], tmp_sig[i],
23599a2dd95SBruce Richardson 					buckets, &set_id[i]) ||
23699a2dd95SBruce Richardson 					search_bucket_single(sec_buckets[i],
23799a2dd95SBruce Richardson 					tmp_sig[i], buckets, &set_id[i]))
23899a2dd95SBruce Richardson 				num_matches++;
23999a2dd95SBruce Richardson 			else
24099a2dd95SBruce Richardson 				set_id[i] = RTE_MEMBER_NO_MATCH;
24199a2dd95SBruce Richardson 		}
24299a2dd95SBruce Richardson 	}
24399a2dd95SBruce Richardson 	return num_matches;
24499a2dd95SBruce Richardson }
24599a2dd95SBruce Richardson 
24699a2dd95SBruce Richardson uint32_t
24799a2dd95SBruce Richardson rte_member_lookup_multi_ht(const struct rte_member_setsum *ss,
24899a2dd95SBruce Richardson 		const void *key, uint32_t match_per_key,
24999a2dd95SBruce Richardson 		member_set_t *set_id)
25099a2dd95SBruce Richardson {
25199a2dd95SBruce Richardson 	uint32_t num_matches = 0;
25299a2dd95SBruce Richardson 	uint32_t prim_bucket, sec_bucket;
25399a2dd95SBruce Richardson 	member_sig_t tmp_sig;
25499a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = ss->table;
25599a2dd95SBruce Richardson 
25699a2dd95SBruce Richardson 	get_buckets_index(ss, key, &prim_bucket, &sec_bucket, &tmp_sig);
25799a2dd95SBruce Richardson 
25899a2dd95SBruce Richardson 	switch (ss->sig_cmp_fn) {
25999a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) && defined(__AVX2__)
26099a2dd95SBruce Richardson 	case RTE_MEMBER_COMPARE_AVX2:
26199a2dd95SBruce Richardson 		search_bucket_multi_avx(prim_bucket, tmp_sig, buckets,
26299a2dd95SBruce Richardson 			&num_matches, match_per_key, set_id);
26399a2dd95SBruce Richardson 		if (num_matches < match_per_key)
26499a2dd95SBruce Richardson 			search_bucket_multi_avx(sec_bucket, tmp_sig,
26599a2dd95SBruce Richardson 				buckets, &num_matches, match_per_key, set_id);
26699a2dd95SBruce Richardson 		return num_matches;
26799a2dd95SBruce Richardson #endif
26899a2dd95SBruce Richardson 	default:
26999a2dd95SBruce Richardson 		search_bucket_multi(prim_bucket, tmp_sig, buckets, &num_matches,
27099a2dd95SBruce Richardson 				 match_per_key, set_id);
27199a2dd95SBruce Richardson 		if (num_matches < match_per_key)
27299a2dd95SBruce Richardson 			search_bucket_multi(sec_bucket, tmp_sig,
27399a2dd95SBruce Richardson 				buckets, &num_matches, match_per_key, set_id);
27499a2dd95SBruce Richardson 		return num_matches;
27599a2dd95SBruce Richardson 	}
27699a2dd95SBruce Richardson }
27799a2dd95SBruce Richardson 
27899a2dd95SBruce Richardson uint32_t
27999a2dd95SBruce Richardson rte_member_lookup_multi_bulk_ht(const struct rte_member_setsum *ss,
28099a2dd95SBruce Richardson 		const void **keys, uint32_t num_keys, uint32_t match_per_key,
28199a2dd95SBruce Richardson 		uint32_t *match_count,
28299a2dd95SBruce Richardson 		member_set_t *set_ids)
28399a2dd95SBruce Richardson {
28499a2dd95SBruce Richardson 	uint32_t i;
28599a2dd95SBruce Richardson 	uint32_t num_matches = 0;
28699a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = ss->table;
28799a2dd95SBruce Richardson 	uint32_t match_cnt_tmp;
28899a2dd95SBruce Richardson 	member_sig_t tmp_sig[RTE_MEMBER_LOOKUP_BULK_MAX];
28999a2dd95SBruce Richardson 	uint32_t prim_buckets[RTE_MEMBER_LOOKUP_BULK_MAX];
29099a2dd95SBruce Richardson 	uint32_t sec_buckets[RTE_MEMBER_LOOKUP_BULK_MAX];
29199a2dd95SBruce Richardson 
29299a2dd95SBruce Richardson 	for (i = 0; i < num_keys; i++) {
29399a2dd95SBruce Richardson 		get_buckets_index(ss, keys[i], &prim_buckets[i],
29499a2dd95SBruce Richardson 				&sec_buckets[i], &tmp_sig[i]);
29599a2dd95SBruce Richardson 		rte_prefetch0(&buckets[prim_buckets[i]]);
29699a2dd95SBruce Richardson 		rte_prefetch0(&buckets[sec_buckets[i]]);
29799a2dd95SBruce Richardson 	}
29899a2dd95SBruce Richardson 	for (i = 0; i < num_keys; i++) {
29999a2dd95SBruce Richardson 		match_cnt_tmp = 0;
30099a2dd95SBruce Richardson 
30199a2dd95SBruce Richardson 		switch (ss->sig_cmp_fn) {
30299a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) && defined(__AVX2__)
30399a2dd95SBruce Richardson 		case RTE_MEMBER_COMPARE_AVX2:
30499a2dd95SBruce Richardson 			search_bucket_multi_avx(prim_buckets[i], tmp_sig[i],
30599a2dd95SBruce Richardson 				buckets, &match_cnt_tmp, match_per_key,
30699a2dd95SBruce Richardson 				&set_ids[i*match_per_key]);
30799a2dd95SBruce Richardson 			if (match_cnt_tmp < match_per_key)
30899a2dd95SBruce Richardson 				search_bucket_multi_avx(sec_buckets[i],
30999a2dd95SBruce Richardson 					tmp_sig[i], buckets, &match_cnt_tmp,
31099a2dd95SBruce Richardson 					match_per_key,
31199a2dd95SBruce Richardson 					&set_ids[i*match_per_key]);
31299a2dd95SBruce Richardson 			match_count[i] = match_cnt_tmp;
31399a2dd95SBruce Richardson 			if (match_cnt_tmp != 0)
31499a2dd95SBruce Richardson 				num_matches++;
31599a2dd95SBruce Richardson 			break;
31699a2dd95SBruce Richardson #endif
31799a2dd95SBruce Richardson 		default:
31899a2dd95SBruce Richardson 			search_bucket_multi(prim_buckets[i], tmp_sig[i],
31999a2dd95SBruce Richardson 				buckets, &match_cnt_tmp, match_per_key,
32099a2dd95SBruce Richardson 				&set_ids[i*match_per_key]);
32199a2dd95SBruce Richardson 			if (match_cnt_tmp < match_per_key)
32299a2dd95SBruce Richardson 				search_bucket_multi(sec_buckets[i], tmp_sig[i],
32399a2dd95SBruce Richardson 					buckets, &match_cnt_tmp, match_per_key,
32499a2dd95SBruce Richardson 					&set_ids[i*match_per_key]);
32599a2dd95SBruce Richardson 			match_count[i] = match_cnt_tmp;
32699a2dd95SBruce Richardson 			if (match_cnt_tmp != 0)
32799a2dd95SBruce Richardson 				num_matches++;
32899a2dd95SBruce Richardson 		}
32999a2dd95SBruce Richardson 	}
33099a2dd95SBruce Richardson 	return num_matches;
33199a2dd95SBruce Richardson }
33299a2dd95SBruce Richardson 
33399a2dd95SBruce Richardson static inline int
33499a2dd95SBruce Richardson try_insert(struct member_ht_bucket *buckets, uint32_t prim, uint32_t sec,
33599a2dd95SBruce Richardson 		member_sig_t sig, member_set_t set_id)
33699a2dd95SBruce Richardson {
33799a2dd95SBruce Richardson 	int i;
33899a2dd95SBruce Richardson 	/* If not full then insert into one slot */
33999a2dd95SBruce Richardson 	for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
34099a2dd95SBruce Richardson 		if (buckets[prim].sets[i] == RTE_MEMBER_NO_MATCH) {
34199a2dd95SBruce Richardson 			buckets[prim].sigs[i] = sig;
34299a2dd95SBruce Richardson 			buckets[prim].sets[i] = set_id;
34399a2dd95SBruce Richardson 			return 0;
34499a2dd95SBruce Richardson 		}
34599a2dd95SBruce Richardson 	}
34699a2dd95SBruce Richardson 	/* If prim failed, we need to access second bucket */
34799a2dd95SBruce Richardson 	for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
34899a2dd95SBruce Richardson 		if (buckets[sec].sets[i] == RTE_MEMBER_NO_MATCH) {
34999a2dd95SBruce Richardson 			buckets[sec].sigs[i] = sig;
35099a2dd95SBruce Richardson 			buckets[sec].sets[i] = set_id;
35199a2dd95SBruce Richardson 			return 0;
35299a2dd95SBruce Richardson 		}
35399a2dd95SBruce Richardson 	}
35499a2dd95SBruce Richardson 	return -1;
35599a2dd95SBruce Richardson }
35699a2dd95SBruce Richardson 
35799a2dd95SBruce Richardson static inline int
35899a2dd95SBruce Richardson try_update(struct member_ht_bucket *buckets, uint32_t prim, uint32_t sec,
35999a2dd95SBruce Richardson 		member_sig_t sig, member_set_t set_id,
36099a2dd95SBruce Richardson 		enum rte_member_sig_compare_function cmp_fn)
36199a2dd95SBruce Richardson {
36299a2dd95SBruce Richardson 	switch (cmp_fn) {
36399a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) && defined(__AVX2__)
36499a2dd95SBruce Richardson 	case RTE_MEMBER_COMPARE_AVX2:
36599a2dd95SBruce Richardson 		if (update_entry_search_avx(prim, sig, buckets, set_id) ||
36699a2dd95SBruce Richardson 				update_entry_search_avx(sec, sig, buckets,
36799a2dd95SBruce Richardson 					set_id))
36899a2dd95SBruce Richardson 			return 0;
36999a2dd95SBruce Richardson 		break;
37099a2dd95SBruce Richardson #endif
37199a2dd95SBruce Richardson 	default:
37299a2dd95SBruce Richardson 		if (update_entry_search(prim, sig, buckets, set_id) ||
37399a2dd95SBruce Richardson 				update_entry_search(sec, sig, buckets,
37499a2dd95SBruce Richardson 					set_id))
37599a2dd95SBruce Richardson 			return 0;
37699a2dd95SBruce Richardson 	}
37799a2dd95SBruce Richardson 	return -1;
37899a2dd95SBruce Richardson }
37999a2dd95SBruce Richardson 
38099a2dd95SBruce Richardson static inline int
38199a2dd95SBruce Richardson evict_from_bucket(void)
38299a2dd95SBruce Richardson {
38399a2dd95SBruce Richardson 	/* For now, we randomly pick one entry to evict */
38499a2dd95SBruce Richardson 	return rte_rand() & (RTE_MEMBER_BUCKET_ENTRIES - 1);
38599a2dd95SBruce Richardson }
38699a2dd95SBruce Richardson 
38799a2dd95SBruce Richardson /*
38899a2dd95SBruce Richardson  * This function is similar to the cuckoo hash make_space function in hash
38999a2dd95SBruce Richardson  * library
39099a2dd95SBruce Richardson  */
39199a2dd95SBruce Richardson static inline int
39299a2dd95SBruce Richardson make_space_bucket(const struct rte_member_setsum *ss, uint32_t bkt_idx,
39399a2dd95SBruce Richardson 			unsigned int *nr_pushes)
39499a2dd95SBruce Richardson {
39599a2dd95SBruce Richardson 	unsigned int i, j;
39699a2dd95SBruce Richardson 	int ret;
39799a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = ss->table;
39899a2dd95SBruce Richardson 	uint32_t next_bucket_idx;
39999a2dd95SBruce Richardson 	struct member_ht_bucket *next_bkt[RTE_MEMBER_BUCKET_ENTRIES];
40099a2dd95SBruce Richardson 	struct member_ht_bucket *bkt = &buckets[bkt_idx];
40199a2dd95SBruce Richardson 	/* MSB is set to indicate if an entry has been already pushed */
40299a2dd95SBruce Richardson 	member_set_t flag_mask = 1U << (sizeof(member_set_t) * 8 - 1);
40399a2dd95SBruce Richardson 
40499a2dd95SBruce Richardson 	/*
40599a2dd95SBruce Richardson 	 * Push existing item (search for bucket with space in
40699a2dd95SBruce Richardson 	 * alternative locations) to its alternative location
40799a2dd95SBruce Richardson 	 */
40899a2dd95SBruce Richardson 	for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
40999a2dd95SBruce Richardson 		/* Search for space in alternative locations */
41099a2dd95SBruce Richardson 		next_bucket_idx = (bkt->sigs[i] ^ bkt_idx) & ss->bucket_mask;
41199a2dd95SBruce Richardson 		next_bkt[i] = &buckets[next_bucket_idx];
41299a2dd95SBruce Richardson 		for (j = 0; j < RTE_MEMBER_BUCKET_ENTRIES; j++) {
41399a2dd95SBruce Richardson 			if (next_bkt[i]->sets[j] == RTE_MEMBER_NO_MATCH)
41499a2dd95SBruce Richardson 				break;
41599a2dd95SBruce Richardson 		}
41699a2dd95SBruce Richardson 
41799a2dd95SBruce Richardson 		if (j != RTE_MEMBER_BUCKET_ENTRIES)
41899a2dd95SBruce Richardson 			break;
41999a2dd95SBruce Richardson 	}
42099a2dd95SBruce Richardson 
42199a2dd95SBruce Richardson 	/* Alternative location has spare room (end of recursive function) */
42299a2dd95SBruce Richardson 	if (i != RTE_MEMBER_BUCKET_ENTRIES) {
42399a2dd95SBruce Richardson 		next_bkt[i]->sigs[j] = bkt->sigs[i];
42499a2dd95SBruce Richardson 		next_bkt[i]->sets[j] = bkt->sets[i];
42599a2dd95SBruce Richardson 		return i;
42699a2dd95SBruce Richardson 	}
42799a2dd95SBruce Richardson 
42899a2dd95SBruce Richardson 	/* Pick entry that has not been pushed yet */
42999a2dd95SBruce Richardson 	for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++)
43099a2dd95SBruce Richardson 		if ((bkt->sets[i] & flag_mask) == 0)
43199a2dd95SBruce Richardson 			break;
43299a2dd95SBruce Richardson 
43399a2dd95SBruce Richardson 	/* All entries have been pushed, so entry cannot be added */
43499a2dd95SBruce Richardson 	if (i == RTE_MEMBER_BUCKET_ENTRIES ||
43599a2dd95SBruce Richardson 			++(*nr_pushes) > RTE_MEMBER_MAX_PUSHES)
43699a2dd95SBruce Richardson 		return -ENOSPC;
43799a2dd95SBruce Richardson 
43899a2dd95SBruce Richardson 	next_bucket_idx = (bkt->sigs[i] ^ bkt_idx) & ss->bucket_mask;
43999a2dd95SBruce Richardson 	/* Set flag to indicate that this entry is going to be pushed */
44099a2dd95SBruce Richardson 	bkt->sets[i] |= flag_mask;
44199a2dd95SBruce Richardson 
44299a2dd95SBruce Richardson 	/* Need room in alternative bucket to insert the pushed entry */
44399a2dd95SBruce Richardson 	ret = make_space_bucket(ss, next_bucket_idx, nr_pushes);
44499a2dd95SBruce Richardson 	/*
44599a2dd95SBruce Richardson 	 * After recursive function.
44699a2dd95SBruce Richardson 	 * Clear flags and insert the pushed entry
44799a2dd95SBruce Richardson 	 * in its alternative location if successful,
44899a2dd95SBruce Richardson 	 * or return error
44999a2dd95SBruce Richardson 	 */
45099a2dd95SBruce Richardson 	bkt->sets[i] &= ~flag_mask;
45199a2dd95SBruce Richardson 	if (ret >= 0) {
45299a2dd95SBruce Richardson 		next_bkt[i]->sigs[ret] = bkt->sigs[i];
45399a2dd95SBruce Richardson 		next_bkt[i]->sets[ret] = bkt->sets[i];
45499a2dd95SBruce Richardson 		return i;
45599a2dd95SBruce Richardson 	} else
45699a2dd95SBruce Richardson 		return ret;
45799a2dd95SBruce Richardson }
45899a2dd95SBruce Richardson 
45999a2dd95SBruce Richardson int
46099a2dd95SBruce Richardson rte_member_add_ht(const struct rte_member_setsum *ss,
46199a2dd95SBruce Richardson 		const void *key, member_set_t set_id)
46299a2dd95SBruce Richardson {
46399a2dd95SBruce Richardson 	int ret;
46499a2dd95SBruce Richardson 	unsigned int nr_pushes = 0;
46599a2dd95SBruce Richardson 	uint32_t prim_bucket, sec_bucket;
46699a2dd95SBruce Richardson 	member_sig_t tmp_sig;
46799a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = ss->table;
46899a2dd95SBruce Richardson 	member_set_t flag_mask = 1U << (sizeof(member_set_t) * 8 - 1);
46999a2dd95SBruce Richardson 
47099a2dd95SBruce Richardson 	if (set_id == RTE_MEMBER_NO_MATCH || (set_id & flag_mask) != 0)
47199a2dd95SBruce Richardson 		return -EINVAL;
47299a2dd95SBruce Richardson 
47399a2dd95SBruce Richardson 	get_buckets_index(ss, key, &prim_bucket, &sec_bucket, &tmp_sig);
47499a2dd95SBruce Richardson 
47599a2dd95SBruce Richardson 	/*
47699a2dd95SBruce Richardson 	 * If it is cache based setsummary, we try overwriting (updating)
47799a2dd95SBruce Richardson 	 * existing entry with the same signature first. In cache mode, we allow
47899a2dd95SBruce Richardson 	 * false negatives and only cache the most recent keys.
47999a2dd95SBruce Richardson 	 *
48099a2dd95SBruce Richardson 	 * For non-cache mode, we do not update existing entry with the same
48199a2dd95SBruce Richardson 	 * signature. This is because if two keys with same signature update
48299a2dd95SBruce Richardson 	 * each other, false negative may happen, which is not the expected
48399a2dd95SBruce Richardson 	 * behavior for non-cache setsummary.
48499a2dd95SBruce Richardson 	 */
48599a2dd95SBruce Richardson 	if (ss->cache) {
48699a2dd95SBruce Richardson 		ret = try_update(buckets, prim_bucket, sec_bucket, tmp_sig,
48799a2dd95SBruce Richardson 					set_id, ss->sig_cmp_fn);
48899a2dd95SBruce Richardson 		if (ret != -1)
48999a2dd95SBruce Richardson 			return ret;
49099a2dd95SBruce Richardson 	}
49199a2dd95SBruce Richardson 	/* If not full then insert into one slot */
49299a2dd95SBruce Richardson 	ret = try_insert(buckets, prim_bucket, sec_bucket, tmp_sig, set_id);
49399a2dd95SBruce Richardson 	if (ret != -1)
49499a2dd95SBruce Richardson 		return ret;
49599a2dd95SBruce Richardson 
49699a2dd95SBruce Richardson 	/* Random pick prim or sec for recursive displacement */
497*33f5b0dcSStephen Hemminger 	uint32_t select_bucket = (tmp_sig & 1U) ? prim_bucket : sec_bucket;
49899a2dd95SBruce Richardson 	if (ss->cache) {
49999a2dd95SBruce Richardson 		ret = evict_from_bucket();
50099a2dd95SBruce Richardson 		buckets[select_bucket].sigs[ret] = tmp_sig;
50199a2dd95SBruce Richardson 		buckets[select_bucket].sets[ret] = set_id;
50299a2dd95SBruce Richardson 		return 1;
50399a2dd95SBruce Richardson 	}
50499a2dd95SBruce Richardson 
50599a2dd95SBruce Richardson 	ret = make_space_bucket(ss, select_bucket, &nr_pushes);
50699a2dd95SBruce Richardson 	if (ret >= 0) {
50799a2dd95SBruce Richardson 		buckets[select_bucket].sigs[ret] = tmp_sig;
50899a2dd95SBruce Richardson 		buckets[select_bucket].sets[ret] = set_id;
50999a2dd95SBruce Richardson 		ret = 1;
51099a2dd95SBruce Richardson 	}
51199a2dd95SBruce Richardson 
51299a2dd95SBruce Richardson 	return ret;
51399a2dd95SBruce Richardson }
51499a2dd95SBruce Richardson 
51599a2dd95SBruce Richardson void
51699a2dd95SBruce Richardson rte_member_free_ht(struct rte_member_setsum *ss)
51799a2dd95SBruce Richardson {
51899a2dd95SBruce Richardson 	rte_free(ss->table);
51999a2dd95SBruce Richardson }
52099a2dd95SBruce Richardson 
52199a2dd95SBruce Richardson int
52299a2dd95SBruce Richardson rte_member_delete_ht(const struct rte_member_setsum *ss, const void *key,
52399a2dd95SBruce Richardson 		member_set_t set_id)
52499a2dd95SBruce Richardson {
52599a2dd95SBruce Richardson 	int i;
52699a2dd95SBruce Richardson 	uint32_t prim_bucket, sec_bucket;
52799a2dd95SBruce Richardson 	member_sig_t tmp_sig;
52899a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = ss->table;
52999a2dd95SBruce Richardson 
53099a2dd95SBruce Richardson 	get_buckets_index(ss, key, &prim_bucket, &sec_bucket, &tmp_sig);
53199a2dd95SBruce Richardson 
53299a2dd95SBruce Richardson 	for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
53399a2dd95SBruce Richardson 		if (tmp_sig == buckets[prim_bucket].sigs[i] &&
53499a2dd95SBruce Richardson 				set_id == buckets[prim_bucket].sets[i]) {
53599a2dd95SBruce Richardson 			buckets[prim_bucket].sets[i] = RTE_MEMBER_NO_MATCH;
53699a2dd95SBruce Richardson 			return 0;
53799a2dd95SBruce Richardson 		}
53899a2dd95SBruce Richardson 	}
53999a2dd95SBruce Richardson 
54099a2dd95SBruce Richardson 	for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
54199a2dd95SBruce Richardson 		if (tmp_sig == buckets[sec_bucket].sigs[i] &&
54299a2dd95SBruce Richardson 				set_id == buckets[sec_bucket].sets[i]) {
54399a2dd95SBruce Richardson 			buckets[sec_bucket].sets[i] = RTE_MEMBER_NO_MATCH;
54499a2dd95SBruce Richardson 			return 0;
54599a2dd95SBruce Richardson 		}
54699a2dd95SBruce Richardson 	}
54799a2dd95SBruce Richardson 	return -ENOENT;
54899a2dd95SBruce Richardson }
54999a2dd95SBruce Richardson 
55099a2dd95SBruce Richardson void
55199a2dd95SBruce Richardson rte_member_reset_ht(const struct rte_member_setsum *ss)
55299a2dd95SBruce Richardson {
55399a2dd95SBruce Richardson 	uint32_t i, j;
55499a2dd95SBruce Richardson 	struct member_ht_bucket *buckets = ss->table;
55599a2dd95SBruce Richardson 
55699a2dd95SBruce Richardson 	for (i = 0; i < ss->bucket_cnt; i++) {
55799a2dd95SBruce Richardson 		for (j = 0; j < RTE_MEMBER_BUCKET_ENTRIES; j++)
55899a2dd95SBruce Richardson 			buckets[i].sets[j] = RTE_MEMBER_NO_MATCH;
55999a2dd95SBruce Richardson 	}
56099a2dd95SBruce Richardson }
561