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