xref: /dpdk/lib/efd/rte_efd.c (revision 1887f919549de2821b0eeabe808a5f2b76370c34)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2016-2017 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson #include <stdio.h>
599a2dd95SBruce Richardson #include <string.h>
699a2dd95SBruce Richardson #include <stdint.h>
772b452c5SDmitry Kozlyuk #include <stdlib.h>
899a2dd95SBruce Richardson #include <inttypes.h>
999a2dd95SBruce Richardson #include <errno.h>
1099a2dd95SBruce Richardson #include <sys/queue.h>
1199a2dd95SBruce Richardson 
128f9c9288SStephen Hemminger #include <rte_cpuflags.h>
1399a2dd95SBruce Richardson #include <rte_string_fns.h>
1499a2dd95SBruce Richardson #include <rte_log.h>
1599a2dd95SBruce Richardson #include <rte_eal_memconfig.h>
1699a2dd95SBruce Richardson #include <rte_errno.h>
1799a2dd95SBruce Richardson #include <rte_malloc.h>
1899a2dd95SBruce Richardson #include <rte_prefetch.h>
1999a2dd95SBruce Richardson #include <rte_branch_prediction.h>
2099a2dd95SBruce Richardson #include <rte_memcpy.h>
2199a2dd95SBruce Richardson #include <rte_ring.h>
2299a2dd95SBruce Richardson #include <rte_jhash.h>
2399a2dd95SBruce Richardson #include <rte_hash_crc.h>
2499a2dd95SBruce Richardson #include <rte_tailq.h>
2599a2dd95SBruce Richardson 
2699a2dd95SBruce Richardson #include "rte_efd.h"
2799a2dd95SBruce Richardson #if defined(RTE_ARCH_X86)
2899a2dd95SBruce Richardson #elif defined(RTE_ARCH_ARM64)
2999a2dd95SBruce Richardson #include "rte_efd_arm64.h"
3099a2dd95SBruce Richardson #endif
3199a2dd95SBruce Richardson 
32de863b4eSStephen Hemminger RTE_LOG_REGISTER_DEFAULT(efd_logtype, INFO);
33de863b4eSStephen Hemminger #define RTE_LOGTYPE_EFD	efd_logtype
3497433132SDavid Marchand #define EFD_LOG(level, ...) \
3597433132SDavid Marchand 	RTE_LOG_LINE(level, EFD, "" __VA_ARGS__)
36de863b4eSStephen Hemminger 
3799a2dd95SBruce Richardson #define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len))
3899a2dd95SBruce Richardson /** Hash function used to determine chunk_id and bin_id for a group */
3999a2dd95SBruce Richardson #define EFD_HASH(key, table) \
4099a2dd95SBruce Richardson 	(uint32_t)(rte_jhash(key, table->key_len, 0xbc9f1d34))
4199a2dd95SBruce Richardson /** Hash function used as constant component of perfect hash search */
4299a2dd95SBruce Richardson #define EFD_HASHFUNCA(key, table) \
4399a2dd95SBruce Richardson 	(uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d35))
4499a2dd95SBruce Richardson /** Hash function used as multiplicative component of perfect hash search */
4599a2dd95SBruce Richardson #define EFD_HASHFUNCB(key, table) \
4699a2dd95SBruce Richardson 	(uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d36))
4799a2dd95SBruce Richardson 
4899a2dd95SBruce Richardson /*************************************************************************
4999a2dd95SBruce Richardson  * Fixed constants
5099a2dd95SBruce Richardson  *************************************************************************/
5199a2dd95SBruce Richardson 
5299a2dd95SBruce Richardson /* These parameters are fixed by the efd_bin_to_group balancing table */
5399a2dd95SBruce Richardson #define EFD_CHUNK_NUM_GROUPS (64)
5499a2dd95SBruce Richardson #define EFD_CHUNK_NUM_BINS   (256)
5599a2dd95SBruce Richardson #define EFD_CHUNK_NUM_BIN_TO_GROUP_SETS \
5699a2dd95SBruce Richardson 	(EFD_CHUNK_NUM_BINS / EFD_CHUNK_NUM_GROUPS)
5799a2dd95SBruce Richardson 
5899a2dd95SBruce Richardson /*
5999a2dd95SBruce Richardson  * Target number of rules that each chunk is created to handle.
6099a2dd95SBruce Richardson  * Used when initially allocating the table
6199a2dd95SBruce Richardson  */
6299a2dd95SBruce Richardson #define EFD_TARGET_CHUNK_NUM_RULES  \
6399a2dd95SBruce Richardson 	(EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES)
6499a2dd95SBruce Richardson /*
6599a2dd95SBruce Richardson  * Max number of rules that each chunk is created to handle.
6699a2dd95SBruce Richardson  * Used when initially allocating the table
6799a2dd95SBruce Richardson  */
6899a2dd95SBruce Richardson #define EFD_TARGET_CHUNK_MAX_NUM_RULES  \
6999a2dd95SBruce Richardson 	(EFD_CHUNK_NUM_GROUPS * EFD_MAX_GROUP_NUM_RULES)
7099a2dd95SBruce Richardson 
7199a2dd95SBruce Richardson /** This is fixed based on the bin_to_group permutation array */
7299a2dd95SBruce Richardson #define EFD_MAX_GROUP_NUM_BINS (16)
7399a2dd95SBruce Richardson 
7499a2dd95SBruce Richardson /**
7599a2dd95SBruce Richardson  * The end of the chunks array needs some extra padding to ensure
7699a2dd95SBruce Richardson  * that vectorization over-reads on the last online chunk stay within
7799a2dd95SBruce Richardson allocated memory
7899a2dd95SBruce Richardson  */
7999a2dd95SBruce Richardson #define EFD_NUM_CHUNK_PADDING_BYTES (256)
8099a2dd95SBruce Richardson 
8199a2dd95SBruce Richardson /* All different internal lookup functions */
8299a2dd95SBruce Richardson enum efd_lookup_internal_function {
8399a2dd95SBruce Richardson 	EFD_LOOKUP_SCALAR = 0,
8499a2dd95SBruce Richardson 	EFD_LOOKUP_AVX2,
8599a2dd95SBruce Richardson 	EFD_LOOKUP_NEON,
8699a2dd95SBruce Richardson 	EFD_LOOKUP_NUM
8799a2dd95SBruce Richardson };
8899a2dd95SBruce Richardson 
8999a2dd95SBruce Richardson TAILQ_HEAD(rte_efd_list, rte_tailq_entry);
9099a2dd95SBruce Richardson 
9199a2dd95SBruce Richardson static struct rte_tailq_elem rte_efd_tailq = {
9299a2dd95SBruce Richardson 	.name = "RTE_EFD",
9399a2dd95SBruce Richardson };
9499a2dd95SBruce Richardson EAL_REGISTER_TAILQ(rte_efd_tailq);
9599a2dd95SBruce Richardson 
9699a2dd95SBruce Richardson /** Internal permutation array used to shuffle bins into pseudorandom groups */
9799a2dd95SBruce Richardson const uint32_t efd_bin_to_group[EFD_CHUNK_NUM_BIN_TO_GROUP_SETS][EFD_CHUNK_NUM_BINS] = {
9899a2dd95SBruce Richardson 	{
9999a2dd95SBruce Richardson 		0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
10099a2dd95SBruce Richardson 		4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
10199a2dd95SBruce Richardson 		8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
10299a2dd95SBruce Richardson 		12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
10399a2dd95SBruce Richardson 		16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
10499a2dd95SBruce Richardson 		20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
10599a2dd95SBruce Richardson 		24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
10699a2dd95SBruce Richardson 		28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
10799a2dd95SBruce Richardson 		32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
10899a2dd95SBruce Richardson 		36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
10999a2dd95SBruce Richardson 		40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
11099a2dd95SBruce Richardson 		44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
11199a2dd95SBruce Richardson 		48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
11299a2dd95SBruce Richardson 		52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
11399a2dd95SBruce Richardson 		56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
11499a2dd95SBruce Richardson 		60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63
11599a2dd95SBruce Richardson 	},
11699a2dd95SBruce Richardson 	{
11799a2dd95SBruce Richardson 		34, 33, 48, 59, 0, 21, 36, 18, 9, 49, 54, 38, 51, 23, 31, 5,
11899a2dd95SBruce Richardson 		44, 23, 37, 52, 11, 4, 58, 20, 38, 40, 38, 22, 26, 28, 42, 6,
11999a2dd95SBruce Richardson 		46, 16, 31, 28, 46, 14, 60, 0, 35, 53, 16, 58, 16, 29, 39, 7,
12099a2dd95SBruce Richardson 		1, 54, 15, 11, 48, 3, 62, 9, 58, 5, 30, 43, 17, 7, 36, 34,
12199a2dd95SBruce Richardson 		6, 36, 2, 14, 10, 1, 47, 47, 20, 45, 62, 56, 34, 25, 39, 18,
12299a2dd95SBruce Richardson 		51, 41, 61, 25, 56, 40, 41, 37, 52, 35, 30, 57, 11, 42, 37, 27,
12399a2dd95SBruce Richardson 		54, 19, 26, 13, 48, 31, 46, 15, 12, 10, 16, 20, 43, 17, 12, 55,
12499a2dd95SBruce Richardson 		45, 18, 8, 41, 7, 31, 42, 63, 12, 14, 21, 57, 24, 40, 5, 41,
12599a2dd95SBruce Richardson 		13, 44, 23, 59, 25, 57, 52, 50, 62, 1, 2, 49, 32, 57, 26, 43,
12699a2dd95SBruce Richardson 		56, 60, 55, 5, 49, 6, 3, 50, 46, 39, 27, 33, 17, 4, 53, 13,
12799a2dd95SBruce Richardson 		2, 19, 36, 51, 63, 0, 22, 33, 59, 28, 29, 23, 45, 33, 53, 27,
12899a2dd95SBruce Richardson 		22, 21, 40, 56, 4, 18, 44, 47, 28, 17, 4, 50, 21, 62, 8, 39,
12999a2dd95SBruce Richardson 		0, 8, 15, 24, 29, 24, 9, 11, 48, 61, 35, 55, 43, 1, 54, 42,
13099a2dd95SBruce Richardson 		53, 60, 22, 3, 32, 52, 25, 8, 15, 60, 7, 55, 27, 63, 19, 10,
13199a2dd95SBruce Richardson 		63, 24, 61, 19, 12, 38, 6, 29, 13, 37, 10, 3, 45, 32, 32, 30,
13299a2dd95SBruce Richardson 		49, 61, 44, 14, 20, 58, 35, 30, 2, 26, 34, 51, 9, 59, 47, 50
13399a2dd95SBruce Richardson 	},
13499a2dd95SBruce Richardson 	{
13599a2dd95SBruce Richardson 		32, 35, 32, 34, 55, 5, 6, 23, 49, 11, 6, 23, 52, 37, 29, 54,
13699a2dd95SBruce Richardson 		55, 40, 63, 50, 29, 52, 61, 25, 12, 56, 39, 38, 29, 11, 46, 1,
13799a2dd95SBruce Richardson 		40, 11, 19, 56, 7, 28, 51, 16, 15, 48, 21, 51, 60, 31, 14, 22,
13899a2dd95SBruce Richardson 		41, 47, 59, 56, 53, 28, 58, 26, 43, 27, 41, 33, 24, 52, 44, 38,
13999a2dd95SBruce Richardson 		13, 59, 48, 51, 60, 15, 3, 30, 15, 0, 10, 62, 44, 14, 28, 51,
14099a2dd95SBruce Richardson 		38, 2, 41, 26, 25, 49, 10, 12, 55, 57, 27, 35, 19, 33, 0, 30,
14199a2dd95SBruce Richardson 		5, 36, 47, 53, 5, 53, 20, 43, 34, 37, 52, 41, 21, 63, 59, 9,
14299a2dd95SBruce Richardson 		24, 1, 45, 24, 39, 44, 45, 16, 9, 17, 7, 50, 57, 22, 18, 28,
14399a2dd95SBruce Richardson 		25, 45, 2, 40, 58, 15, 17, 3, 1, 27, 61, 39, 19, 0, 19, 21,
14499a2dd95SBruce Richardson 		57, 62, 54, 60, 54, 40, 48, 33, 36, 37, 4, 42, 1, 43, 58, 8,
14599a2dd95SBruce Richardson 		13, 42, 10, 56, 35, 22, 48, 61, 63, 10, 49, 9, 24, 9, 25, 57,
14699a2dd95SBruce Richardson 		33, 18, 13, 31, 42, 36, 36, 55, 30, 37, 53, 34, 59, 4, 4, 23,
14799a2dd95SBruce Richardson 		8, 16, 58, 14, 30, 11, 12, 63, 49, 62, 2, 39, 47, 22, 2, 60,
14899a2dd95SBruce Richardson 		18, 8, 46, 31, 6, 20, 32, 29, 46, 42, 20, 31, 32, 61, 34, 4,
14999a2dd95SBruce Richardson 		47, 26, 20, 43, 26, 21, 7, 3, 16, 35, 18, 44, 27, 62, 13, 23,
15099a2dd95SBruce Richardson 		6, 50, 12, 8, 45, 17, 3, 46, 50, 7, 14, 5, 17, 54, 38, 0
15199a2dd95SBruce Richardson 	},
15299a2dd95SBruce Richardson 	{
15399a2dd95SBruce Richardson 		29, 56, 5, 7, 54, 48, 23, 37, 35, 44, 52, 40, 33, 49, 60, 0,
15499a2dd95SBruce Richardson 		59, 51, 28, 12, 41, 26, 2, 23, 34, 5, 59, 40, 3, 19, 6, 26,
15599a2dd95SBruce Richardson 		35, 53, 45, 49, 29, 57, 28, 62, 58, 59, 19, 53, 59, 62, 6, 54,
15699a2dd95SBruce Richardson 		13, 15, 48, 50, 45, 21, 41, 12, 34, 40, 24, 56, 19, 21, 35, 18,
15799a2dd95SBruce Richardson 		55, 45, 9, 61, 47, 61, 19, 15, 16, 39, 17, 31, 3, 51, 21, 50,
15899a2dd95SBruce Richardson 		17, 25, 25, 11, 44, 16, 18, 28, 14, 2, 37, 61, 58, 27, 62, 4,
15999a2dd95SBruce Richardson 		14, 17, 1, 9, 46, 28, 37, 0, 53, 43, 57, 7, 57, 46, 21, 41,
16099a2dd95SBruce Richardson 		39, 14, 52, 60, 44, 53, 49, 60, 49, 63, 13, 11, 29, 1, 55, 47,
16199a2dd95SBruce Richardson 		55, 12, 60, 43, 54, 37, 13, 6, 42, 10, 36, 13, 9, 8, 34, 51,
16299a2dd95SBruce Richardson 		31, 32, 12, 7, 57, 2, 26, 14, 3, 30, 63, 3, 32, 1, 5, 11,
16399a2dd95SBruce Richardson 		27, 24, 26, 44, 31, 23, 56, 38, 62, 0, 40, 30, 6, 23, 38, 2,
16499a2dd95SBruce Richardson 		47, 5, 15, 27, 16, 10, 31, 25, 22, 63, 30, 25, 20, 33, 32, 50,
16599a2dd95SBruce Richardson 		29, 43, 55, 10, 50, 45, 56, 20, 4, 7, 27, 46, 11, 16, 22, 52,
16699a2dd95SBruce Richardson 		35, 20, 41, 54, 46, 33, 42, 18, 63, 8, 22, 58, 36, 4, 51, 42,
16799a2dd95SBruce Richardson 		38, 32, 38, 22, 17, 0, 47, 8, 48, 8, 48, 1, 61, 36, 33, 20,
16899a2dd95SBruce Richardson 		24, 39, 39, 18, 30, 36, 9, 43, 42, 24, 10, 58, 4, 15, 34, 52
16999a2dd95SBruce Richardson 	},
17099a2dd95SBruce Richardson };
17199a2dd95SBruce Richardson 
17299a2dd95SBruce Richardson /*************************************************************************
17399a2dd95SBruce Richardson  * Offline region structures
17499a2dd95SBruce Richardson  *************************************************************************/
17599a2dd95SBruce Richardson 
17699a2dd95SBruce Richardson /** Online group containing number of rules, values, keys and their bins
17799a2dd95SBruce Richardson  * for EFD_MAX_GROUP_NUM_RULES rules.
17899a2dd95SBruce Richardson  */
17999a2dd95SBruce Richardson struct efd_offline_group_rules {
18099a2dd95SBruce Richardson 	uint32_t num_rules;
18199a2dd95SBruce Richardson 	/**< Sum of the number of rules in all bins assigned to this group. */
18299a2dd95SBruce Richardson 
18399a2dd95SBruce Richardson 	uint32_t key_idx[EFD_MAX_GROUP_NUM_RULES];
18499a2dd95SBruce Richardson 	/**< Array with all keys of the group. */
18599a2dd95SBruce Richardson 	efd_value_t value[EFD_MAX_GROUP_NUM_RULES];
18699a2dd95SBruce Richardson 	/**< Array with all values of the keys of the group. */
18799a2dd95SBruce Richardson 
18899a2dd95SBruce Richardson 	uint8_t bin_id[EFD_MAX_GROUP_NUM_RULES];
18999a2dd95SBruce Richardson 	/**< Stores the bin for each corresponding key to
19099a2dd95SBruce Richardson 	 * avoid having to recompute it
19199a2dd95SBruce Richardson 	 */
19299a2dd95SBruce Richardson };
19399a2dd95SBruce Richardson 
19499a2dd95SBruce Richardson /** Offline chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
19599a2dd95SBruce Richardson  * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
19699a2dd95SBruce Richardson  */
19799a2dd95SBruce Richardson struct efd_offline_chunk_rules {
19899a2dd95SBruce Richardson 	uint16_t num_rules;
19999a2dd95SBruce Richardson 	/**< Number of rules in the entire chunk;
20099a2dd95SBruce Richardson 	 * used to detect unbalanced groups
20199a2dd95SBruce Richardson 	 */
20299a2dd95SBruce Richardson 
20399a2dd95SBruce Richardson 	struct efd_offline_group_rules group_rules[EFD_CHUNK_NUM_GROUPS];
20499a2dd95SBruce Richardson 	/**< Array of all groups in the chunk. */
20599a2dd95SBruce Richardson };
20699a2dd95SBruce Richardson 
20799a2dd95SBruce Richardson /*************************************************************************
20899a2dd95SBruce Richardson  * Online region structures
20999a2dd95SBruce Richardson  *************************************************************************/
21099a2dd95SBruce Richardson 
21199a2dd95SBruce Richardson /** Online group containing values for EFD_MAX_GROUP_NUM_RULES rules. */
21299a2dd95SBruce Richardson struct efd_online_group_entry {
21399a2dd95SBruce Richardson 	efd_hashfunc_t hash_idx[RTE_EFD_VALUE_NUM_BITS];
21499a2dd95SBruce Richardson 	efd_lookuptbl_t lookup_table[RTE_EFD_VALUE_NUM_BITS];
215*1887f919SBruce Richardson };
21699a2dd95SBruce Richardson 
21799a2dd95SBruce Richardson /**
21899a2dd95SBruce Richardson  * A single chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
21999a2dd95SBruce Richardson  * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
22099a2dd95SBruce Richardson  */
22199a2dd95SBruce Richardson struct efd_online_chunk {
22299a2dd95SBruce Richardson 	uint8_t bin_choice_list[(EFD_CHUNK_NUM_BINS * 2 + 7) / 8];
22399a2dd95SBruce Richardson 	/**< This is a packed indirection index into the 'groups' array.
22499a2dd95SBruce Richardson 	 * Each byte contains four two-bit values which index into
22599a2dd95SBruce Richardson 	 * the efd_bin_to_group array.
22699a2dd95SBruce Richardson 	 * The efd_bin_to_group array returns the index into the groups array
22799a2dd95SBruce Richardson 	 */
22899a2dd95SBruce Richardson 
22999a2dd95SBruce Richardson 	struct efd_online_group_entry groups[EFD_CHUNK_NUM_GROUPS];
23099a2dd95SBruce Richardson 	/**< Array of all the groups in the chunk. */
231*1887f919SBruce Richardson };
23299a2dd95SBruce Richardson 
23399a2dd95SBruce Richardson /**
23499a2dd95SBruce Richardson  * EFD table structure
23599a2dd95SBruce Richardson  */
23699a2dd95SBruce Richardson struct rte_efd_table {
23799a2dd95SBruce Richardson 	char name[RTE_EFD_NAMESIZE]; /**< Name of the efd table. */
23899a2dd95SBruce Richardson 
23999a2dd95SBruce Richardson 	uint32_t key_len; /**< Length of the key stored offline */
24099a2dd95SBruce Richardson 
24199a2dd95SBruce Richardson 	uint32_t max_num_rules;
24299a2dd95SBruce Richardson 	/**< Static maximum number of entries the table was constructed to hold. */
24399a2dd95SBruce Richardson 
24499a2dd95SBruce Richardson 	uint32_t num_rules;
24599a2dd95SBruce Richardson 	/**< Number of entries currently in the table . */
24699a2dd95SBruce Richardson 
24799a2dd95SBruce Richardson 	uint32_t num_chunks;
24899a2dd95SBruce Richardson 	/**< Number of chunks in the table needed to support num_rules. */
24999a2dd95SBruce Richardson 
25099a2dd95SBruce Richardson 	uint32_t num_chunks_shift;
25199a2dd95SBruce Richardson 	/**< Bits to shift to get chunk id, instead of dividing by num_chunk. */
25299a2dd95SBruce Richardson 
25399a2dd95SBruce Richardson 	enum efd_lookup_internal_function lookup_fn;
25499a2dd95SBruce Richardson 	/**< Indicates which lookup function to use. */
25599a2dd95SBruce Richardson 
25699a2dd95SBruce Richardson 	struct efd_online_chunk *chunks[RTE_MAX_NUMA_NODES];
25799a2dd95SBruce Richardson 	/**< Dynamic array of size num_chunks of chunk records. */
25899a2dd95SBruce Richardson 
25999a2dd95SBruce Richardson 	struct efd_offline_chunk_rules *offline_chunks;
26099a2dd95SBruce Richardson 	/**< Dynamic array of size num_chunks of key-value pairs. */
26199a2dd95SBruce Richardson 
26299a2dd95SBruce Richardson 	struct rte_ring *free_slots;
26399a2dd95SBruce Richardson 	/**< Ring that stores all indexes of the free slots in the key table */
26499a2dd95SBruce Richardson 
26599a2dd95SBruce Richardson 	uint8_t *keys; /**< Dynamic array of size max_num_rules of keys */
26699a2dd95SBruce Richardson };
26799a2dd95SBruce Richardson 
26899a2dd95SBruce Richardson /**
26999a2dd95SBruce Richardson  * Computes the chunk ID for a given key hash
27099a2dd95SBruce Richardson  *
27199a2dd95SBruce Richardson  * @param table
27299a2dd95SBruce Richardson  *   EFD table to reference
27399a2dd95SBruce Richardson  * @param hashed_key
27499a2dd95SBruce Richardson  *   32-bit key hash returned by EFD_HASH
27599a2dd95SBruce Richardson  *
27699a2dd95SBruce Richardson  * @return
27799a2dd95SBruce Richardson  *   chunk ID containing this key hash
27899a2dd95SBruce Richardson  */
27999a2dd95SBruce Richardson static inline uint32_t
28099a2dd95SBruce Richardson efd_get_chunk_id(const struct rte_efd_table * const table,
28199a2dd95SBruce Richardson 		const uint32_t hashed_key)
28299a2dd95SBruce Richardson {
28399a2dd95SBruce Richardson 	return hashed_key & (table->num_chunks - 1);
28499a2dd95SBruce Richardson }
28599a2dd95SBruce Richardson 
28699a2dd95SBruce Richardson /**
28799a2dd95SBruce Richardson  * Computes the bin ID for a given key hash
28899a2dd95SBruce Richardson  *
28999a2dd95SBruce Richardson  * @param table
29099a2dd95SBruce Richardson  *   EFD table to reference
29199a2dd95SBruce Richardson  * @param hashed_key
29299a2dd95SBruce Richardson  *   32-bit key hash returned by EFD_HASH
29399a2dd95SBruce Richardson  *
29499a2dd95SBruce Richardson  * @return bin ID containing this key hash
29599a2dd95SBruce Richardson  */
29699a2dd95SBruce Richardson static inline uint32_t
29799a2dd95SBruce Richardson efd_get_bin_id(const struct rte_efd_table * const table,
29899a2dd95SBruce Richardson 		const uint32_t hashed_key)
29999a2dd95SBruce Richardson {
30099a2dd95SBruce Richardson 	return (hashed_key >> table->num_chunks_shift) & (EFD_CHUNK_NUM_BINS - 1);
30199a2dd95SBruce Richardson }
30299a2dd95SBruce Richardson 
30399a2dd95SBruce Richardson /**
30499a2dd95SBruce Richardson  * Looks up the current permutation choice for a particular bin in the online table
30599a2dd95SBruce Richardson  *
30699a2dd95SBruce Richardson  * @param table
30799a2dd95SBruce Richardson  *  EFD table to reference
30899a2dd95SBruce Richardson  * @param socket_id
30999a2dd95SBruce Richardson  *   Socket ID to use to look up existing values (ideally caller's socket id)
31099a2dd95SBruce Richardson  * @param chunk_id
31199a2dd95SBruce Richardson  *   Chunk ID of bin to look up
31299a2dd95SBruce Richardson  * @param bin_id
31399a2dd95SBruce Richardson  *   Bin ID to look up
31499a2dd95SBruce Richardson  *
31599a2dd95SBruce Richardson  * @return
31699a2dd95SBruce Richardson  *   Currently active permutation choice in the online table
31799a2dd95SBruce Richardson  */
31899a2dd95SBruce Richardson static inline uint8_t
31999a2dd95SBruce Richardson efd_get_choice(const struct rte_efd_table * const table,
32099a2dd95SBruce Richardson 		const unsigned int socket_id, const uint32_t chunk_id,
32199a2dd95SBruce Richardson 		const uint32_t bin_id)
32299a2dd95SBruce Richardson {
32399a2dd95SBruce Richardson 	struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
32499a2dd95SBruce Richardson 
32599a2dd95SBruce Richardson 	/*
32699a2dd95SBruce Richardson 	 * Grab the chunk (byte) that contains the choices
32799a2dd95SBruce Richardson 	 * for four neighboring bins.
32899a2dd95SBruce Richardson 	 */
32999a2dd95SBruce Richardson 	uint8_t choice_chunk =
33099a2dd95SBruce Richardson 			chunk->bin_choice_list[bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS];
33199a2dd95SBruce Richardson 
33299a2dd95SBruce Richardson 	/*
33399a2dd95SBruce Richardson 	 * Compute the offset into the chunk that contains
33499a2dd95SBruce Richardson 	 * the group_id lookup position
33599a2dd95SBruce Richardson 	 */
33699a2dd95SBruce Richardson 	int offset = (bin_id & 0x3) * 2;
33799a2dd95SBruce Richardson 
33899a2dd95SBruce Richardson 	/* Extract from the byte just the desired lookup position */
33999a2dd95SBruce Richardson 	return (uint8_t) ((choice_chunk >> offset) & 0x3);
34099a2dd95SBruce Richardson }
34199a2dd95SBruce Richardson 
34299a2dd95SBruce Richardson /**
34399a2dd95SBruce Richardson  * Compute the chunk_id and bin_id for a given key
34499a2dd95SBruce Richardson  *
34599a2dd95SBruce Richardson  * @param table
34699a2dd95SBruce Richardson  *   EFD table to reference
34799a2dd95SBruce Richardson  * @param key
34899a2dd95SBruce Richardson  *   Key to hash and find location of
34999a2dd95SBruce Richardson  * @param chunk_id
35099a2dd95SBruce Richardson  *   Computed chunk ID
35199a2dd95SBruce Richardson  * @param bin_id
35299a2dd95SBruce Richardson  *   Computed bin ID
35399a2dd95SBruce Richardson  */
35499a2dd95SBruce Richardson static inline void
35599a2dd95SBruce Richardson efd_compute_ids(const struct rte_efd_table * const table,
35699a2dd95SBruce Richardson 		const void *key, uint32_t * const chunk_id, uint32_t * const bin_id)
35799a2dd95SBruce Richardson {
35899a2dd95SBruce Richardson 	/* Compute the position of the entry in the hash table */
35999a2dd95SBruce Richardson 	uint32_t h = EFD_HASH(key, table);
36099a2dd95SBruce Richardson 
36199a2dd95SBruce Richardson 	/* Compute the chunk_id where that entry can be found */
36299a2dd95SBruce Richardson 	*chunk_id = efd_get_chunk_id(table, h);
36399a2dd95SBruce Richardson 
36499a2dd95SBruce Richardson 	/*
36599a2dd95SBruce Richardson 	 * Compute the bin within that chunk where the entry
36699a2dd95SBruce Richardson 	 * can be found (0 - 255)
36799a2dd95SBruce Richardson 	 */
36899a2dd95SBruce Richardson 	*bin_id = efd_get_bin_id(table, h);
36999a2dd95SBruce Richardson }
37099a2dd95SBruce Richardson 
37199a2dd95SBruce Richardson /**
37299a2dd95SBruce Richardson  * Search for a hash function for a group that satisfies all group results
37399a2dd95SBruce Richardson  */
37499a2dd95SBruce Richardson static inline int
37599a2dd95SBruce Richardson efd_search_hash(struct rte_efd_table * const table,
37699a2dd95SBruce Richardson 		const struct efd_offline_group_rules * const off_group,
37799a2dd95SBruce Richardson 		struct efd_online_group_entry * const on_group)
37899a2dd95SBruce Richardson {
37999a2dd95SBruce Richardson 	efd_hashfunc_t hash_idx;
38099a2dd95SBruce Richardson 	efd_hashfunc_t start_hash_idx[RTE_EFD_VALUE_NUM_BITS];
38199a2dd95SBruce Richardson 	efd_lookuptbl_t start_lookup_table[RTE_EFD_VALUE_NUM_BITS];
38299a2dd95SBruce Richardson 
38399a2dd95SBruce Richardson 	uint32_t i, j, rule_id;
38499a2dd95SBruce Richardson 	uint32_t hash_val_a[EFD_MAX_GROUP_NUM_RULES];
38599a2dd95SBruce Richardson 	uint32_t hash_val_b[EFD_MAX_GROUP_NUM_RULES];
38699a2dd95SBruce Richardson 	uint32_t hash_val[EFD_MAX_GROUP_NUM_RULES];
38799a2dd95SBruce Richardson 
38899a2dd95SBruce Richardson 
38999a2dd95SBruce Richardson 	rte_prefetch0(off_group->value);
39099a2dd95SBruce Richardson 
39199a2dd95SBruce Richardson 	/*
39299a2dd95SBruce Richardson 	 * Prepopulate the hash_val tables by running the two hash functions
39399a2dd95SBruce Richardson 	 * for each provided rule
39499a2dd95SBruce Richardson 	 */
39599a2dd95SBruce Richardson 	for (i = 0; i < off_group->num_rules; i++) {
39699a2dd95SBruce Richardson 		void *key_stored = EFD_KEY(off_group->key_idx[i], table);
39799a2dd95SBruce Richardson 		hash_val_b[i] = EFD_HASHFUNCB(key_stored, table);
39899a2dd95SBruce Richardson 		hash_val_a[i] = EFD_HASHFUNCA(key_stored, table);
39999a2dd95SBruce Richardson 	}
40099a2dd95SBruce Richardson 
40199a2dd95SBruce Richardson 	for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
40299a2dd95SBruce Richardson 		hash_idx = on_group->hash_idx[i];
40399a2dd95SBruce Richardson 		start_hash_idx[i] = hash_idx;
40499a2dd95SBruce Richardson 		start_lookup_table[i] = on_group->lookup_table[i];
40599a2dd95SBruce Richardson 
40699a2dd95SBruce Richardson 		do {
40799a2dd95SBruce Richardson 			efd_lookuptbl_t lookup_table = 0;
40899a2dd95SBruce Richardson 			efd_lookuptbl_t lookup_table_complement = 0;
40999a2dd95SBruce Richardson 
41099a2dd95SBruce Richardson 			for (rule_id = 0; rule_id < off_group->num_rules; rule_id++)
41199a2dd95SBruce Richardson 				hash_val[rule_id] = hash_val_a[rule_id] + (hash_idx *
41299a2dd95SBruce Richardson 					hash_val_b[rule_id]);
41399a2dd95SBruce Richardson 
41499a2dd95SBruce Richardson 			/*
41599a2dd95SBruce Richardson 			 * The goal here is to find a hash function for this
41699a2dd95SBruce Richardson 			 * particular bit entry that meets the following criteria:
41799a2dd95SBruce Richardson 			 * The most significant bits of the hash result define a
41899a2dd95SBruce Richardson 			 * shift into the lookup table where the bit will be stored
41999a2dd95SBruce Richardson 			 */
42099a2dd95SBruce Richardson 
42199a2dd95SBruce Richardson 			/* Iterate over each provided rule */
42299a2dd95SBruce Richardson 			for (rule_id = 0; rule_id < off_group->num_rules;
42399a2dd95SBruce Richardson 					rule_id++) {
42499a2dd95SBruce Richardson 				/*
42599a2dd95SBruce Richardson 				 * Use the few most significant bits (number based on
42699a2dd95SBruce Richardson 				 * EFD_LOOKUPTBL_SIZE) to see what position the
42799a2dd95SBruce Richardson 				 * expected bit should be set in the lookup_table
42899a2dd95SBruce Richardson 				 */
42999a2dd95SBruce Richardson 				uint32_t bucket_idx = hash_val[rule_id] >>
43099a2dd95SBruce Richardson 						EFD_LOOKUPTBL_SHIFT;
43199a2dd95SBruce Richardson 
43299a2dd95SBruce Richardson 				/*
43399a2dd95SBruce Richardson 				 * Get the current bit of interest.
43499a2dd95SBruce Richardson 				 * This only find an appropriate hash function
43599a2dd95SBruce Richardson 				 * for one bit at a time of the rule
43699a2dd95SBruce Richardson 				 */
43799a2dd95SBruce Richardson 				efd_lookuptbl_t expected =
43899a2dd95SBruce Richardson 						(off_group->value[rule_id] >> i) & 0x1;
43999a2dd95SBruce Richardson 
44099a2dd95SBruce Richardson 				/*
44199a2dd95SBruce Richardson 				 * Add the expected bit (if set) to a map
44299a2dd95SBruce Richardson 				 * (lookup_table). Also set its complement
44399a2dd95SBruce Richardson 				 * in lookup_table_complement
44499a2dd95SBruce Richardson 				 */
44599a2dd95SBruce Richardson 				lookup_table |= expected << bucket_idx;
44699a2dd95SBruce Richardson 				lookup_table_complement |= (1 - expected)
44799a2dd95SBruce Richardson 						<< bucket_idx;
44899a2dd95SBruce Richardson 
44999a2dd95SBruce Richardson 				/*
45099a2dd95SBruce Richardson 				 * If ever the hash function of two different
45199a2dd95SBruce Richardson 				 * elements result in different values at the
45299a2dd95SBruce Richardson 				 * same location in the lookup_table,
45399a2dd95SBruce Richardson 				 * the current hash_idx is not valid.
45499a2dd95SBruce Richardson 				 */
45599a2dd95SBruce Richardson 				if (lookup_table & lookup_table_complement)
45699a2dd95SBruce Richardson 					break;
45799a2dd95SBruce Richardson 			}
45899a2dd95SBruce Richardson 
45999a2dd95SBruce Richardson 			/*
46099a2dd95SBruce Richardson 			 * Check if the previous loop completed without
46199a2dd95SBruce Richardson 			 * breaking early
46299a2dd95SBruce Richardson 			 */
46399a2dd95SBruce Richardson 			if (rule_id == off_group->num_rules) {
46499a2dd95SBruce Richardson 				/*
46599a2dd95SBruce Richardson 				 * Current hash function worked, store it
46699a2dd95SBruce Richardson 				 * for the current group
46799a2dd95SBruce Richardson 				 */
46899a2dd95SBruce Richardson 				on_group->hash_idx[i] = hash_idx;
46999a2dd95SBruce Richardson 				on_group->lookup_table[i] = lookup_table;
47099a2dd95SBruce Richardson 
47199a2dd95SBruce Richardson 				/*
47299a2dd95SBruce Richardson 				 * Make sure that the hash function has changed
47399a2dd95SBruce Richardson 				 * from the starting value
47499a2dd95SBruce Richardson 				 */
47599a2dd95SBruce Richardson 				hash_idx = start_hash_idx[i] + 1;
47699a2dd95SBruce Richardson 				break;
47799a2dd95SBruce Richardson 			}
47899a2dd95SBruce Richardson 			hash_idx++;
47999a2dd95SBruce Richardson 
48099a2dd95SBruce Richardson 		} while (hash_idx != start_hash_idx[i]);
48199a2dd95SBruce Richardson 
48299a2dd95SBruce Richardson 		/* Failed to find perfect hash for this group */
48399a2dd95SBruce Richardson 		if (hash_idx == start_hash_idx[i]) {
48499a2dd95SBruce Richardson 			/*
48599a2dd95SBruce Richardson 			 * Restore previous hash_idx and lookup_table
48699a2dd95SBruce Richardson 			 * for all value bits
48799a2dd95SBruce Richardson 			 */
48899a2dd95SBruce Richardson 			for (j = 0; j < i; j++) {
48999a2dd95SBruce Richardson 				on_group->hash_idx[j] = start_hash_idx[j];
49099a2dd95SBruce Richardson 				on_group->lookup_table[j] = start_lookup_table[j];
49199a2dd95SBruce Richardson 			}
49299a2dd95SBruce Richardson 			return 1;
49399a2dd95SBruce Richardson 		}
49499a2dd95SBruce Richardson 	}
49599a2dd95SBruce Richardson 
49699a2dd95SBruce Richardson 	return 0;
49799a2dd95SBruce Richardson }
49899a2dd95SBruce Richardson 
49999a2dd95SBruce Richardson struct rte_efd_table *
50099a2dd95SBruce Richardson rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len,
5018751a7e9SPablo de Lara 		uint64_t online_cpu_socket_bitmask, uint8_t offline_cpu_socket)
50299a2dd95SBruce Richardson {
50399a2dd95SBruce Richardson 	struct rte_efd_table *table = NULL;
50499a2dd95SBruce Richardson 	uint8_t *key_array = NULL;
50599a2dd95SBruce Richardson 	uint32_t num_chunks, num_chunks_shift;
50699a2dd95SBruce Richardson 	uint8_t socket_id;
50799a2dd95SBruce Richardson 	struct rte_efd_list *efd_list = NULL;
50899a2dd95SBruce Richardson 	struct rte_tailq_entry *te;
50999a2dd95SBruce Richardson 	uint64_t offline_table_size;
51099a2dd95SBruce Richardson 	char ring_name[RTE_RING_NAMESIZE];
51199a2dd95SBruce Richardson 	struct rte_ring *r = NULL;
51299a2dd95SBruce Richardson 	unsigned int i;
51399a2dd95SBruce Richardson 
51499a2dd95SBruce Richardson 	efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
51599a2dd95SBruce Richardson 
51699a2dd95SBruce Richardson 	if (online_cpu_socket_bitmask == 0) {
517ae67895bSDavid Marchand 		EFD_LOG(ERR, "At least one CPU socket must be enabled "
518ae67895bSDavid Marchand 				"in the bitmask");
51999a2dd95SBruce Richardson 		return NULL;
52099a2dd95SBruce Richardson 	}
52199a2dd95SBruce Richardson 
52299a2dd95SBruce Richardson 	if (max_num_rules == 0) {
523ae67895bSDavid Marchand 		EFD_LOG(ERR, "Max num rules must be higher than 0");
52499a2dd95SBruce Richardson 		return NULL;
52599a2dd95SBruce Richardson 	}
52699a2dd95SBruce Richardson 
52799a2dd95SBruce Richardson 	/*
52899a2dd95SBruce Richardson 	 * Compute the minimum number of chunks (smallest power of 2)
52999a2dd95SBruce Richardson 	 * that can hold all of the rules
53099a2dd95SBruce Richardson 	 */
53199a2dd95SBruce Richardson 	if (max_num_rules % EFD_TARGET_CHUNK_NUM_RULES == 0)
53299a2dd95SBruce Richardson 		num_chunks = rte_align32pow2(max_num_rules /
53399a2dd95SBruce Richardson 			EFD_TARGET_CHUNK_NUM_RULES);
53499a2dd95SBruce Richardson 	else
53599a2dd95SBruce Richardson 		num_chunks = rte_align32pow2((max_num_rules /
53699a2dd95SBruce Richardson 			EFD_TARGET_CHUNK_NUM_RULES) + 1);
53799a2dd95SBruce Richardson 
53899a2dd95SBruce Richardson 	num_chunks_shift = rte_bsf32(num_chunks);
53999a2dd95SBruce Richardson 
54099a2dd95SBruce Richardson 	rte_mcfg_tailq_write_lock();
54199a2dd95SBruce Richardson 
54299a2dd95SBruce Richardson 	/*
54399a2dd95SBruce Richardson 	 * Guarantee there's no existing: this is normally already checked
54499a2dd95SBruce Richardson 	 * by ring creation above
54599a2dd95SBruce Richardson 	 */
54699a2dd95SBruce Richardson 	TAILQ_FOREACH(te, efd_list, next)
54799a2dd95SBruce Richardson 	{
54899a2dd95SBruce Richardson 		table = (struct rte_efd_table *) te->data;
54999a2dd95SBruce Richardson 		if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
55099a2dd95SBruce Richardson 			break;
55199a2dd95SBruce Richardson 	}
55299a2dd95SBruce Richardson 
55399a2dd95SBruce Richardson 	table = NULL;
55499a2dd95SBruce Richardson 	if (te != NULL) {
55599a2dd95SBruce Richardson 		rte_errno = EEXIST;
55699a2dd95SBruce Richardson 		te = NULL;
55799a2dd95SBruce Richardson 		goto error_unlock_exit;
55899a2dd95SBruce Richardson 	}
55999a2dd95SBruce Richardson 
56099a2dd95SBruce Richardson 	te = rte_zmalloc("EFD_TAILQ_ENTRY", sizeof(*te), 0);
56199a2dd95SBruce Richardson 	if (te == NULL) {
562ae67895bSDavid Marchand 		EFD_LOG(ERR, "tailq entry allocation failed");
56399a2dd95SBruce Richardson 		goto error_unlock_exit;
56499a2dd95SBruce Richardson 	}
56599a2dd95SBruce Richardson 
56699a2dd95SBruce Richardson 	/* Create a new EFD table management structure */
56799a2dd95SBruce Richardson 	table = rte_zmalloc_socket(NULL,
56899a2dd95SBruce Richardson 			sizeof(struct rte_efd_table),
56999a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE,
57099a2dd95SBruce Richardson 			offline_cpu_socket);
57199a2dd95SBruce Richardson 	if (table == NULL) {
572ae67895bSDavid Marchand 		EFD_LOG(ERR, "Allocating EFD table management structure"
573ae67895bSDavid Marchand 				" on socket %u failed",
57499a2dd95SBruce Richardson 				offline_cpu_socket);
57599a2dd95SBruce Richardson 		goto error_unlock_exit;
57699a2dd95SBruce Richardson 	}
57799a2dd95SBruce Richardson 
57899a2dd95SBruce Richardson 
579ae67895bSDavid Marchand 	EFD_LOG(DEBUG, "Allocated EFD table management structure "
580ae67895bSDavid Marchand 			"on socket %u", offline_cpu_socket);
58199a2dd95SBruce Richardson 
58299a2dd95SBruce Richardson 	table->max_num_rules = num_chunks * EFD_TARGET_CHUNK_MAX_NUM_RULES;
58399a2dd95SBruce Richardson 	table->num_rules = 0;
58499a2dd95SBruce Richardson 	table->num_chunks = num_chunks;
58599a2dd95SBruce Richardson 	table->num_chunks_shift = num_chunks_shift;
58699a2dd95SBruce Richardson 	table->key_len = key_len;
58799a2dd95SBruce Richardson 
58899a2dd95SBruce Richardson 	/* key_array */
58999a2dd95SBruce Richardson 	key_array = rte_zmalloc_socket(NULL,
59099a2dd95SBruce Richardson 			table->max_num_rules * table->key_len,
59199a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE,
59299a2dd95SBruce Richardson 			offline_cpu_socket);
59399a2dd95SBruce Richardson 	if (key_array == NULL) {
594ae67895bSDavid Marchand 		EFD_LOG(ERR, "Allocating key array"
595ae67895bSDavid Marchand 				" on socket %u failed",
59699a2dd95SBruce Richardson 				offline_cpu_socket);
59799a2dd95SBruce Richardson 		goto error_unlock_exit;
59899a2dd95SBruce Richardson 	}
59999a2dd95SBruce Richardson 	table->keys = key_array;
60099a2dd95SBruce Richardson 	strlcpy(table->name, name, sizeof(table->name));
60199a2dd95SBruce Richardson 
602ae67895bSDavid Marchand 	EFD_LOG(DEBUG, "Creating an EFD table with %u chunks,"
603ae67895bSDavid Marchand 			" which potentially supports %u entries",
60499a2dd95SBruce Richardson 			num_chunks, table->max_num_rules);
60599a2dd95SBruce Richardson 
60699a2dd95SBruce Richardson 	/* Make sure all the allocatable table pointers are NULL initially */
60799a2dd95SBruce Richardson 	for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
60899a2dd95SBruce Richardson 		table->chunks[socket_id] = NULL;
60999a2dd95SBruce Richardson 	table->offline_chunks = NULL;
61099a2dd95SBruce Richardson 
61199a2dd95SBruce Richardson 	/*
61299a2dd95SBruce Richardson 	 * Allocate one online table per socket specified
61399a2dd95SBruce Richardson 	 * in the user-supplied bitmask
61499a2dd95SBruce Richardson 	 */
61599a2dd95SBruce Richardson 	uint64_t online_table_size = num_chunks * sizeof(struct efd_online_chunk) +
61699a2dd95SBruce Richardson 			EFD_NUM_CHUNK_PADDING_BYTES;
61799a2dd95SBruce Richardson 
61899a2dd95SBruce Richardson 	for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) {
61999a2dd95SBruce Richardson 		if ((online_cpu_socket_bitmask >> socket_id) & 0x01) {
62099a2dd95SBruce Richardson 			/*
62199a2dd95SBruce Richardson 			 * Allocate all of the EFD table chunks (the online portion)
62299a2dd95SBruce Richardson 			 * as a continuous block
62399a2dd95SBruce Richardson 			 */
62499a2dd95SBruce Richardson 			table->chunks[socket_id] =
62599a2dd95SBruce Richardson 				rte_zmalloc_socket(
62699a2dd95SBruce Richardson 				NULL,
62799a2dd95SBruce Richardson 				online_table_size,
62899a2dd95SBruce Richardson 				RTE_CACHE_LINE_SIZE,
62999a2dd95SBruce Richardson 				socket_id);
63099a2dd95SBruce Richardson 			if (table->chunks[socket_id] == NULL) {
631ae67895bSDavid Marchand 				EFD_LOG(ERR,
63299a2dd95SBruce Richardson 						"Allocating EFD online table on "
633ae67895bSDavid Marchand 						"socket %u failed",
63499a2dd95SBruce Richardson 						socket_id);
63599a2dd95SBruce Richardson 				goto error_unlock_exit;
63699a2dd95SBruce Richardson 			}
637ae67895bSDavid Marchand 			EFD_LOG(DEBUG,
63899a2dd95SBruce Richardson 					"Allocated EFD online table of size "
639ae67895bSDavid Marchand 					"%"PRIu64" bytes (%.2f MB) on socket %u",
64099a2dd95SBruce Richardson 					online_table_size,
64199a2dd95SBruce Richardson 					(float) online_table_size /
64299a2dd95SBruce Richardson 						(1024.0F * 1024.0F),
64399a2dd95SBruce Richardson 					socket_id);
64499a2dd95SBruce Richardson 		}
64599a2dd95SBruce Richardson 	}
64699a2dd95SBruce Richardson 
64799a2dd95SBruce Richardson #if defined(RTE_ARCH_X86)
64899a2dd95SBruce Richardson 	/*
64999a2dd95SBruce Richardson 	 * For less than 4 bits, scalar function performs better
65099a2dd95SBruce Richardson 	 * than vectorised version
65199a2dd95SBruce Richardson 	 */
65299a2dd95SBruce Richardson 	if (RTE_EFD_VALUE_NUM_BITS > 3
65399a2dd95SBruce Richardson 			&& rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2)
65499a2dd95SBruce Richardson 			&& rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256)
65599a2dd95SBruce Richardson 		table->lookup_fn = EFD_LOOKUP_AVX2;
65699a2dd95SBruce Richardson 	else
65799a2dd95SBruce Richardson #endif
65899a2dd95SBruce Richardson #if defined(RTE_ARCH_ARM64)
65999a2dd95SBruce Richardson 	/*
66099a2dd95SBruce Richardson 	 * For less than or equal to 16 bits, scalar function performs better
66199a2dd95SBruce Richardson 	 * than vectorised version
66299a2dd95SBruce Richardson 	 */
66399a2dd95SBruce Richardson 	if (RTE_EFD_VALUE_NUM_BITS > 16 &&
66499a2dd95SBruce Richardson 	    rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON) &&
66599a2dd95SBruce Richardson 			rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
66699a2dd95SBruce Richardson 		table->lookup_fn = EFD_LOOKUP_NEON;
66799a2dd95SBruce Richardson 	else
66899a2dd95SBruce Richardson #endif
66999a2dd95SBruce Richardson 		table->lookup_fn = EFD_LOOKUP_SCALAR;
67099a2dd95SBruce Richardson 
67199a2dd95SBruce Richardson 	/*
67299a2dd95SBruce Richardson 	 * Allocate the EFD table offline portion (with the actual rules
67399a2dd95SBruce Richardson 	 * mapping keys to values) as a continuous block.
67499a2dd95SBruce Richardson 	 * This could be several gigabytes of memory.
67599a2dd95SBruce Richardson 	 */
67699a2dd95SBruce Richardson 	offline_table_size = num_chunks * sizeof(struct efd_offline_chunk_rules);
67799a2dd95SBruce Richardson 	table->offline_chunks =
67899a2dd95SBruce Richardson 			rte_zmalloc_socket(NULL,
67999a2dd95SBruce Richardson 			offline_table_size,
68099a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE,
68199a2dd95SBruce Richardson 			offline_cpu_socket);
68299a2dd95SBruce Richardson 	if (table->offline_chunks == NULL) {
683ae67895bSDavid Marchand 		EFD_LOG(ERR, "Allocating EFD offline table on socket %u "
684ae67895bSDavid Marchand 				"failed", offline_cpu_socket);
68599a2dd95SBruce Richardson 		goto error_unlock_exit;
68699a2dd95SBruce Richardson 	}
68799a2dd95SBruce Richardson 
688ae67895bSDavid Marchand 	EFD_LOG(DEBUG,
68999a2dd95SBruce Richardson 			"Allocated EFD offline table of size %"PRIu64" bytes "
690ae67895bSDavid Marchand 			" (%.2f MB) on socket %u", offline_table_size,
69199a2dd95SBruce Richardson 			(float) offline_table_size / (1024.0F * 1024.0F),
69299a2dd95SBruce Richardson 			offline_cpu_socket);
69399a2dd95SBruce Richardson 
69499a2dd95SBruce Richardson 	te->data = (void *) table;
69599a2dd95SBruce Richardson 	TAILQ_INSERT_TAIL(efd_list, te, next);
69699a2dd95SBruce Richardson 	rte_mcfg_tailq_write_unlock();
69799a2dd95SBruce Richardson 
69899a2dd95SBruce Richardson 	snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name);
69999a2dd95SBruce Richardson 	/* Create ring (Dummy slot index is not enqueued) */
70099a2dd95SBruce Richardson 	r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules),
70199a2dd95SBruce Richardson 			offline_cpu_socket, 0);
70299a2dd95SBruce Richardson 	if (r == NULL) {
703ae67895bSDavid Marchand 		EFD_LOG(ERR, "memory allocation failed");
70499a2dd95SBruce Richardson 		rte_efd_free(table);
70599a2dd95SBruce Richardson 		return NULL;
70699a2dd95SBruce Richardson 	}
70799a2dd95SBruce Richardson 
70899a2dd95SBruce Richardson 	/* Populate free slots ring. Entry zero is reserved for key misses. */
70999a2dd95SBruce Richardson 	for (i = 0; i < table->max_num_rules; i++)
71099a2dd95SBruce Richardson 		rte_ring_sp_enqueue(r, (void *) ((uintptr_t) i));
71199a2dd95SBruce Richardson 
71299a2dd95SBruce Richardson 	table->free_slots = r;
71399a2dd95SBruce Richardson 	return table;
71499a2dd95SBruce Richardson 
71599a2dd95SBruce Richardson error_unlock_exit:
71699a2dd95SBruce Richardson 	rte_mcfg_tailq_write_unlock();
71799a2dd95SBruce Richardson 	rte_free(te);
71899a2dd95SBruce Richardson 	rte_efd_free(table);
71999a2dd95SBruce Richardson 
72099a2dd95SBruce Richardson 	return NULL;
72199a2dd95SBruce Richardson }
72299a2dd95SBruce Richardson 
72399a2dd95SBruce Richardson struct rte_efd_table *
72499a2dd95SBruce Richardson rte_efd_find_existing(const char *name)
72599a2dd95SBruce Richardson {
72699a2dd95SBruce Richardson 	struct rte_efd_table *table = NULL;
72799a2dd95SBruce Richardson 	struct rte_tailq_entry *te;
72899a2dd95SBruce Richardson 	struct rte_efd_list *efd_list;
72999a2dd95SBruce Richardson 
73099a2dd95SBruce Richardson 	efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
73199a2dd95SBruce Richardson 
73299a2dd95SBruce Richardson 	rte_mcfg_tailq_read_lock();
73399a2dd95SBruce Richardson 
73499a2dd95SBruce Richardson 	TAILQ_FOREACH(te, efd_list, next)
73599a2dd95SBruce Richardson 	{
73699a2dd95SBruce Richardson 		table = (struct rte_efd_table *) te->data;
73799a2dd95SBruce Richardson 		if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
73899a2dd95SBruce Richardson 			break;
73999a2dd95SBruce Richardson 	}
74099a2dd95SBruce Richardson 	rte_mcfg_tailq_read_unlock();
74199a2dd95SBruce Richardson 
74299a2dd95SBruce Richardson 	if (te == NULL) {
74399a2dd95SBruce Richardson 		rte_errno = ENOENT;
74499a2dd95SBruce Richardson 		return NULL;
74599a2dd95SBruce Richardson 	}
74699a2dd95SBruce Richardson 	return table;
74799a2dd95SBruce Richardson }
74899a2dd95SBruce Richardson 
74999a2dd95SBruce Richardson void
75099a2dd95SBruce Richardson rte_efd_free(struct rte_efd_table *table)
75199a2dd95SBruce Richardson {
75299a2dd95SBruce Richardson 	uint8_t socket_id;
75399a2dd95SBruce Richardson 	struct rte_efd_list *efd_list;
75499a2dd95SBruce Richardson 	struct rte_tailq_entry *te, *temp;
75599a2dd95SBruce Richardson 
75699a2dd95SBruce Richardson 	if (table == NULL)
75799a2dd95SBruce Richardson 		return;
75899a2dd95SBruce Richardson 
75999a2dd95SBruce Richardson 	for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
76099a2dd95SBruce Richardson 		rte_free(table->chunks[socket_id]);
76199a2dd95SBruce Richardson 
76299a2dd95SBruce Richardson 	efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
76399a2dd95SBruce Richardson 	rte_mcfg_tailq_write_lock();
76499a2dd95SBruce Richardson 
765f1f6ebc0SWilliam Tu 	RTE_TAILQ_FOREACH_SAFE(te, efd_list, next, temp) {
76699a2dd95SBruce Richardson 		if (te->data == (void *) table) {
76799a2dd95SBruce Richardson 			TAILQ_REMOVE(efd_list, te, next);
76899a2dd95SBruce Richardson 			rte_free(te);
76999a2dd95SBruce Richardson 			break;
77099a2dd95SBruce Richardson 		}
77199a2dd95SBruce Richardson 	}
77299a2dd95SBruce Richardson 
77399a2dd95SBruce Richardson 	rte_mcfg_tailq_write_unlock();
77499a2dd95SBruce Richardson 	rte_ring_free(table->free_slots);
77599a2dd95SBruce Richardson 	rte_free(table->offline_chunks);
77699a2dd95SBruce Richardson 	rte_free(table->keys);
77799a2dd95SBruce Richardson 	rte_free(table);
77899a2dd95SBruce Richardson }
77999a2dd95SBruce Richardson 
78099a2dd95SBruce Richardson /**
78199a2dd95SBruce Richardson  * Applies a previously computed table entry to the specified table for all
78299a2dd95SBruce Richardson  * socket-local copies of the online table.
78399a2dd95SBruce Richardson  * Intended to apply an update for only a single change
78499a2dd95SBruce Richardson  * to a key/value pair at a time
78599a2dd95SBruce Richardson  *
78699a2dd95SBruce Richardson  * @param table
78799a2dd95SBruce Richardson  *   EFD table to reference
78899a2dd95SBruce Richardson  * @param socket_id
78999a2dd95SBruce Richardson  *   Socket ID to use to lookup existing values (ideally caller's socket id)
79099a2dd95SBruce Richardson  * @param chunk_id
79199a2dd95SBruce Richardson  *   Chunk index to update
79299a2dd95SBruce Richardson  * @param group_id
79399a2dd95SBruce Richardson  *   Group index to update
79499a2dd95SBruce Richardson  * @param bin_id
79599a2dd95SBruce Richardson  *   Bin within the group that this update affects
79699a2dd95SBruce Richardson  * @param new_bin_choice
79799a2dd95SBruce Richardson  *   Newly chosen permutation which this bin should use - only lower 2 bits
79899a2dd95SBruce Richardson  * @param new_group_entry
79999a2dd95SBruce Richardson  *   Previously computed updated chunk/group entry
80099a2dd95SBruce Richardson  */
80199a2dd95SBruce Richardson static inline void
80299a2dd95SBruce Richardson efd_apply_update(struct rte_efd_table * const table, const unsigned int socket_id,
80399a2dd95SBruce Richardson 		const uint32_t chunk_id, const uint32_t group_id,
80499a2dd95SBruce Richardson 		const uint32_t bin_id, const uint8_t new_bin_choice,
80599a2dd95SBruce Richardson 		const struct efd_online_group_entry * const new_group_entry)
80699a2dd95SBruce Richardson {
80799a2dd95SBruce Richardson 	int i;
80899a2dd95SBruce Richardson 	struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
80999a2dd95SBruce Richardson 	uint8_t bin_index = bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
81099a2dd95SBruce Richardson 
81199a2dd95SBruce Richardson 	/*
81299a2dd95SBruce Richardson 	 * Grab the current byte that contains the choices
81399a2dd95SBruce Richardson 	 * for four neighboring bins
81499a2dd95SBruce Richardson 	 */
81599a2dd95SBruce Richardson 	uint8_t choice_chunk =
81699a2dd95SBruce Richardson 			chunk->bin_choice_list[bin_index];
81799a2dd95SBruce Richardson 
81899a2dd95SBruce Richardson 
81999a2dd95SBruce Richardson 	/* Compute the offset into the chunk that needs to be updated */
82099a2dd95SBruce Richardson 	int offset = (bin_id & 0x3) * 2;
82199a2dd95SBruce Richardson 
82299a2dd95SBruce Richardson 	/* Zero the two bits of interest and set them to new_bin_choice */
82399a2dd95SBruce Richardson 	choice_chunk = (choice_chunk & (~(0x03 << offset)))
82499a2dd95SBruce Richardson 			| ((new_bin_choice & 0x03) << offset);
82599a2dd95SBruce Richardson 
82699a2dd95SBruce Richardson 	/* Update the online table with the new data across all sockets */
82799a2dd95SBruce Richardson 	for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
82899a2dd95SBruce Richardson 		if (table->chunks[i] != NULL) {
82999a2dd95SBruce Richardson 			memcpy(&(table->chunks[i][chunk_id].groups[group_id]),
83099a2dd95SBruce Richardson 					new_group_entry,
83199a2dd95SBruce Richardson 					sizeof(struct efd_online_group_entry));
83299a2dd95SBruce Richardson 			table->chunks[i][chunk_id].bin_choice_list[bin_index] =
83399a2dd95SBruce Richardson 					choice_chunk;
83499a2dd95SBruce Richardson 		}
83599a2dd95SBruce Richardson 	}
83699a2dd95SBruce Richardson }
83799a2dd95SBruce Richardson 
83899a2dd95SBruce Richardson /*
83999a2dd95SBruce Richardson  * Move the bin from prev group to the new group
84099a2dd95SBruce Richardson  */
84199a2dd95SBruce Richardson static inline void
84299a2dd95SBruce Richardson move_groups(uint32_t bin_id, uint8_t bin_size,
84399a2dd95SBruce Richardson 		struct efd_offline_group_rules *new_group,
84499a2dd95SBruce Richardson 		struct efd_offline_group_rules * const current_group)
84599a2dd95SBruce Richardson {
84699a2dd95SBruce Richardson 
84799a2dd95SBruce Richardson 	uint8_t empty_idx = 0;
84899a2dd95SBruce Richardson 	unsigned int i;
84999a2dd95SBruce Richardson 
85099a2dd95SBruce Richardson 	if (new_group == current_group)
85199a2dd95SBruce Richardson 		return;
85299a2dd95SBruce Richardson 
85399a2dd95SBruce Richardson 	for (i = 0; i < current_group->num_rules; i++) {
85499a2dd95SBruce Richardson 		/*
85599a2dd95SBruce Richardson 		 * Move keys that belong to the same bin
85699a2dd95SBruce Richardson 		 * to the new group
85799a2dd95SBruce Richardson 		 */
85899a2dd95SBruce Richardson 		if (current_group->bin_id[i] == bin_id) {
85999a2dd95SBruce Richardson 			new_group->key_idx[new_group->num_rules] =
86099a2dd95SBruce Richardson 					current_group->key_idx[i];
86199a2dd95SBruce Richardson 			new_group->value[new_group->num_rules] =
86299a2dd95SBruce Richardson 					current_group->value[i];
86399a2dd95SBruce Richardson 			new_group->bin_id[new_group->num_rules] =
86499a2dd95SBruce Richardson 					current_group->bin_id[i];
86599a2dd95SBruce Richardson 			new_group->num_rules++;
86699a2dd95SBruce Richardson 		} else {
86799a2dd95SBruce Richardson 			if (i != empty_idx) {
86899a2dd95SBruce Richardson 				/*
86999a2dd95SBruce Richardson 				 * Need to move this key towards
87099a2dd95SBruce Richardson 				 * the top of the array
87199a2dd95SBruce Richardson 				 */
87299a2dd95SBruce Richardson 				current_group->key_idx[empty_idx] =
87399a2dd95SBruce Richardson 						current_group->key_idx[i];
87499a2dd95SBruce Richardson 				current_group->value[empty_idx] =
87599a2dd95SBruce Richardson 						current_group->value[i];
87699a2dd95SBruce Richardson 				current_group->bin_id[empty_idx] =
87799a2dd95SBruce Richardson 						current_group->bin_id[i];
87899a2dd95SBruce Richardson 			}
87999a2dd95SBruce Richardson 			empty_idx++;
88099a2dd95SBruce Richardson 		}
88199a2dd95SBruce Richardson 
88299a2dd95SBruce Richardson 	}
88399a2dd95SBruce Richardson 	current_group->num_rules -= bin_size;
88499a2dd95SBruce Richardson }
88599a2dd95SBruce Richardson 
88699a2dd95SBruce Richardson /*
88799a2dd95SBruce Richardson  * Revert group/s to their previous state before
88899a2dd95SBruce Richardson  * trying to insert/add a new key
88999a2dd95SBruce Richardson  */
89099a2dd95SBruce Richardson static inline void
89199a2dd95SBruce Richardson revert_groups(struct efd_offline_group_rules *previous_group,
89299a2dd95SBruce Richardson 		struct efd_offline_group_rules *current_group, uint8_t bin_size)
89399a2dd95SBruce Richardson {
89499a2dd95SBruce Richardson 	unsigned int i;
89599a2dd95SBruce Richardson 
89699a2dd95SBruce Richardson 	if (current_group == previous_group)
89799a2dd95SBruce Richardson 		return;
89899a2dd95SBruce Richardson 
89999a2dd95SBruce Richardson 	/* Move keys back to previous group */
90099a2dd95SBruce Richardson 	for (i = current_group->num_rules - bin_size;
90199a2dd95SBruce Richardson 			i < current_group->num_rules; i++) {
90299a2dd95SBruce Richardson 		previous_group->key_idx[previous_group->num_rules] =
90399a2dd95SBruce Richardson 				current_group->key_idx[i];
90499a2dd95SBruce Richardson 		previous_group->value[previous_group->num_rules] =
90599a2dd95SBruce Richardson 				current_group->value[i];
90699a2dd95SBruce Richardson 		previous_group->bin_id[previous_group->num_rules] =
90799a2dd95SBruce Richardson 				current_group->bin_id[i];
90899a2dd95SBruce Richardson 		previous_group->num_rules++;
90999a2dd95SBruce Richardson 	}
91099a2dd95SBruce Richardson 
91199a2dd95SBruce Richardson 	/*
91299a2dd95SBruce Richardson 	 * Decrease number of rules after the move
91399a2dd95SBruce Richardson 	 * in the new group
91499a2dd95SBruce Richardson 	 */
91599a2dd95SBruce Richardson 	current_group->num_rules -= bin_size;
91699a2dd95SBruce Richardson }
91799a2dd95SBruce Richardson 
91899a2dd95SBruce Richardson /**
91999a2dd95SBruce Richardson  * Computes an updated table entry where the supplied key points to a new host.
92099a2dd95SBruce Richardson  * If no entry exists, one is inserted.
92199a2dd95SBruce Richardson  *
92299a2dd95SBruce Richardson  * This function does NOT modify the online table(s)
92399a2dd95SBruce Richardson  * This function DOES modify the offline table
92499a2dd95SBruce Richardson  *
92599a2dd95SBruce Richardson  * @param table
92699a2dd95SBruce Richardson  *   EFD table to reference
92799a2dd95SBruce Richardson  * @param socket_id
92899a2dd95SBruce Richardson  *   Socket ID to use to lookup existing values (ideally caller's socket id)
92999a2dd95SBruce Richardson  * @param key
93099a2dd95SBruce Richardson  *   Key to insert
93199a2dd95SBruce Richardson  * @param value
93299a2dd95SBruce Richardson  *   Value to associate with key
93399a2dd95SBruce Richardson  * @param chunk_id
93499a2dd95SBruce Richardson  *   Chunk ID of the chunk that was modified
93599a2dd95SBruce Richardson  * @param group_id
93699a2dd95SBruce Richardson  *   Group ID of the group that was modified
93799a2dd95SBruce Richardson  * @param bin_id
93899a2dd95SBruce Richardson  *   Bin ID that was modified
93999a2dd95SBruce Richardson  * @param new_bin_choice
94099a2dd95SBruce Richardson  *   Newly chosen permutation which this bin will use
94199a2dd95SBruce Richardson  * @param entry
94299a2dd95SBruce Richardson  *   Newly computed online entry to apply later with efd_apply_update
94399a2dd95SBruce Richardson  *
94499a2dd95SBruce Richardson  * @return
94599a2dd95SBruce Richardson  *   RTE_EFD_UPDATE_WARN_GROUP_FULL
94699a2dd95SBruce Richardson  *     Operation is insert, and the last available space in the
94799a2dd95SBruce Richardson  *     key's group was just used. Future inserts may fail as groups fill up.
94899a2dd95SBruce Richardson  *     This operation was still successful, and entry contains a valid update
94999a2dd95SBruce Richardson  *   RTE_EFD_UPDATE_FAILED
95099a2dd95SBruce Richardson  *     Either the EFD failed to find a suitable perfect hash or the group was full
95199a2dd95SBruce Richardson  *     This is a fatal error, and the table is now in an indeterminate state
95299a2dd95SBruce Richardson  *   RTE_EFD_UPDATE_NO_CHANGE
95399a2dd95SBruce Richardson  *     Operation resulted in no change to the table (same value already exists)
95499a2dd95SBruce Richardson  *   0
95599a2dd95SBruce Richardson  *     Insert or update was successful, and the new efd_online_group_entry
95699a2dd95SBruce Richardson  *     is stored in *entry
95799a2dd95SBruce Richardson  *
95899a2dd95SBruce Richardson  * @warning
95999a2dd95SBruce Richardson  *   Note that entry will be UNCHANGED if the update has no effect, and thus any
96099a2dd95SBruce Richardson  *   subsequent use of the entry content will likely be invalid
96199a2dd95SBruce Richardson  */
96299a2dd95SBruce Richardson static inline int
96399a2dd95SBruce Richardson efd_compute_update(struct rte_efd_table * const table,
96499a2dd95SBruce Richardson 		const unsigned int socket_id, const void *key,
96599a2dd95SBruce Richardson 		const efd_value_t value, uint32_t * const chunk_id,
96699a2dd95SBruce Richardson 		uint32_t * const group_id, uint32_t * const bin_id,
96799a2dd95SBruce Richardson 		uint8_t * const new_bin_choice,
96899a2dd95SBruce Richardson 		struct efd_online_group_entry * const entry)
96999a2dd95SBruce Richardson {
97099a2dd95SBruce Richardson 	unsigned int i;
97199a2dd95SBruce Richardson 	int ret;
97299a2dd95SBruce Richardson 	uint32_t new_idx;
97399a2dd95SBruce Richardson 	void *new_k, *slot_id = NULL;
97499a2dd95SBruce Richardson 	int status = EXIT_SUCCESS;
97599a2dd95SBruce Richardson 	unsigned int found = 0;
97699a2dd95SBruce Richardson 
97799a2dd95SBruce Richardson 	efd_compute_ids(table, key, chunk_id, bin_id);
97899a2dd95SBruce Richardson 
97999a2dd95SBruce Richardson 	struct efd_offline_chunk_rules * const chunk =
98099a2dd95SBruce Richardson 			&table->offline_chunks[*chunk_id];
98199a2dd95SBruce Richardson 	struct efd_offline_group_rules *new_group;
98299a2dd95SBruce Richardson 
98399a2dd95SBruce Richardson 	uint8_t current_choice = efd_get_choice(table, socket_id,
98499a2dd95SBruce Richardson 			*chunk_id, *bin_id);
98599a2dd95SBruce Richardson 	uint32_t current_group_id = efd_bin_to_group[current_choice][*bin_id];
98699a2dd95SBruce Richardson 	struct efd_offline_group_rules * const current_group =
98799a2dd95SBruce Richardson 			&chunk->group_rules[current_group_id];
98899a2dd95SBruce Richardson 	uint8_t bin_size = 0;
98999a2dd95SBruce Richardson 	uint8_t key_changed_index = 0;
99099a2dd95SBruce Richardson 	efd_value_t key_changed_previous_value = 0;
99199a2dd95SBruce Richardson 	uint32_t key_idx_previous = 0;
99299a2dd95SBruce Richardson 
99399a2dd95SBruce Richardson 	/* Scan the current group and see if the key is already present */
99499a2dd95SBruce Richardson 	for (i = 0; i < current_group->num_rules; i++) {
99599a2dd95SBruce Richardson 		if (current_group->bin_id[i] == *bin_id)
99699a2dd95SBruce Richardson 			bin_size++;
99799a2dd95SBruce Richardson 		else
99899a2dd95SBruce Richardson 			continue;
99999a2dd95SBruce Richardson 
100099a2dd95SBruce Richardson 		void *key_stored = EFD_KEY(current_group->key_idx[i], table);
100199a2dd95SBruce Richardson 		if (found == 0 && unlikely(memcmp(key_stored, key,
100299a2dd95SBruce Richardson 				table->key_len) == 0)) {
100399a2dd95SBruce Richardson 			/* Key is already present */
100499a2dd95SBruce Richardson 
100599a2dd95SBruce Richardson 			/*
100699a2dd95SBruce Richardson 			 * If previous value is same as new value,
100799a2dd95SBruce Richardson 			 * no additional work is required
100899a2dd95SBruce Richardson 			 */
100999a2dd95SBruce Richardson 			if (current_group->value[i] == value)
101099a2dd95SBruce Richardson 				return RTE_EFD_UPDATE_NO_CHANGE;
101199a2dd95SBruce Richardson 
101299a2dd95SBruce Richardson 			key_idx_previous = current_group->key_idx[i];
101399a2dd95SBruce Richardson 			key_changed_previous_value = current_group->value[i];
101499a2dd95SBruce Richardson 			key_changed_index = i;
101599a2dd95SBruce Richardson 			current_group->value[i] = value;
101699a2dd95SBruce Richardson 			found = 1;
101799a2dd95SBruce Richardson 		}
101899a2dd95SBruce Richardson 	}
101999a2dd95SBruce Richardson 
102099a2dd95SBruce Richardson 	if (found == 0) {
102199a2dd95SBruce Richardson 		/* Key does not exist. Insert the rule into the bin/group */
102299a2dd95SBruce Richardson 		if (unlikely(current_group->num_rules >= EFD_MAX_GROUP_NUM_RULES)) {
1023ae67895bSDavid Marchand 			EFD_LOG(ERR,
102499a2dd95SBruce Richardson 					"Fatal: No room remaining for insert into "
1025ae67895bSDavid Marchand 					"chunk %u group %u bin %u",
102699a2dd95SBruce Richardson 					*chunk_id,
102799a2dd95SBruce Richardson 					current_group_id, *bin_id);
102899a2dd95SBruce Richardson 			return RTE_EFD_UPDATE_FAILED;
102999a2dd95SBruce Richardson 		}
103099a2dd95SBruce Richardson 
103199a2dd95SBruce Richardson 		if (unlikely(current_group->num_rules ==
103299a2dd95SBruce Richardson 				(EFD_MAX_GROUP_NUM_RULES - 1))) {
1033ae67895bSDavid Marchand 			EFD_LOG(INFO, "Warn: Insert into last "
103499a2dd95SBruce Richardson 					"available slot in chunk %u "
1035ae67895bSDavid Marchand 					"group %u bin %u", *chunk_id,
103699a2dd95SBruce Richardson 					current_group_id, *bin_id);
103799a2dd95SBruce Richardson 			status = RTE_EFD_UPDATE_WARN_GROUP_FULL;
103899a2dd95SBruce Richardson 		}
103999a2dd95SBruce Richardson 
104099a2dd95SBruce Richardson 		if (rte_ring_sc_dequeue(table->free_slots, &slot_id) != 0)
104199a2dd95SBruce Richardson 			return RTE_EFD_UPDATE_FAILED;
104299a2dd95SBruce Richardson 
104399a2dd95SBruce Richardson 		new_k = RTE_PTR_ADD(table->keys, (uintptr_t) slot_id *
104499a2dd95SBruce Richardson 					table->key_len);
104599a2dd95SBruce Richardson 		rte_prefetch0(new_k);
104699a2dd95SBruce Richardson 		new_idx = (uint32_t) ((uintptr_t) slot_id);
104799a2dd95SBruce Richardson 
104899a2dd95SBruce Richardson 		rte_memcpy(EFD_KEY(new_idx, table), key, table->key_len);
104999a2dd95SBruce Richardson 		current_group->key_idx[current_group->num_rules] = new_idx;
105099a2dd95SBruce Richardson 		current_group->value[current_group->num_rules] = value;
105199a2dd95SBruce Richardson 		current_group->bin_id[current_group->num_rules] = *bin_id;
105299a2dd95SBruce Richardson 		current_group->num_rules++;
105399a2dd95SBruce Richardson 		table->num_rules++;
105499a2dd95SBruce Richardson 		bin_size++;
105599a2dd95SBruce Richardson 	} else {
105699a2dd95SBruce Richardson 		uint32_t last = current_group->num_rules - 1;
105799a2dd95SBruce Richardson 		/* Swap the key with the last key inserted*/
105899a2dd95SBruce Richardson 		current_group->key_idx[key_changed_index] =
105999a2dd95SBruce Richardson 				current_group->key_idx[last];
106099a2dd95SBruce Richardson 		current_group->value[key_changed_index] =
106199a2dd95SBruce Richardson 				current_group->value[last];
106299a2dd95SBruce Richardson 		current_group->bin_id[key_changed_index] =
106399a2dd95SBruce Richardson 				current_group->bin_id[last];
106499a2dd95SBruce Richardson 
106599a2dd95SBruce Richardson 		/*
106699a2dd95SBruce Richardson 		 * Key to be updated will always be available
106799a2dd95SBruce Richardson 		 * at the end of the group
106899a2dd95SBruce Richardson 		 */
106999a2dd95SBruce Richardson 		current_group->key_idx[last] = key_idx_previous;
107099a2dd95SBruce Richardson 		current_group->value[last] = value;
107199a2dd95SBruce Richardson 		current_group->bin_id[last] = *bin_id;
107299a2dd95SBruce Richardson 	}
107399a2dd95SBruce Richardson 
107499a2dd95SBruce Richardson 	*new_bin_choice = current_choice;
107599a2dd95SBruce Richardson 	*group_id = current_group_id;
107699a2dd95SBruce Richardson 	new_group = current_group;
107799a2dd95SBruce Richardson 
107899a2dd95SBruce Richardson 	/* Group need to be rebalanced when it starts to get loaded */
107999a2dd95SBruce Richardson 	if (current_group->num_rules > EFD_MIN_BALANCED_NUM_RULES) {
108099a2dd95SBruce Richardson 
108199a2dd95SBruce Richardson 		/*
108299a2dd95SBruce Richardson 		 * Subtract the number of entries in the bin from
108399a2dd95SBruce Richardson 		 * the original group
108499a2dd95SBruce Richardson 		 */
108599a2dd95SBruce Richardson 		current_group->num_rules -= bin_size;
108699a2dd95SBruce Richardson 
108799a2dd95SBruce Richardson 		/*
108899a2dd95SBruce Richardson 		 * Figure out which of the available groups that this bin
108999a2dd95SBruce Richardson 		 * can map to is the smallest (using the current group
109099a2dd95SBruce Richardson 		 * as baseline)
109199a2dd95SBruce Richardson 		 */
109299a2dd95SBruce Richardson 		uint8_t smallest_choice = current_choice;
109399a2dd95SBruce Richardson 		uint8_t smallest_size = current_group->num_rules;
109499a2dd95SBruce Richardson 		uint32_t smallest_group_id = current_group_id;
109599a2dd95SBruce Richardson 		unsigned char choice;
109699a2dd95SBruce Richardson 
109799a2dd95SBruce Richardson 		for (choice = 0; choice < EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
109899a2dd95SBruce Richardson 				choice++) {
109999a2dd95SBruce Richardson 			uint32_t test_group_id =
110099a2dd95SBruce Richardson 					efd_bin_to_group[choice][*bin_id];
110199a2dd95SBruce Richardson 			uint32_t num_rules =
110299a2dd95SBruce Richardson 					chunk->group_rules[test_group_id].num_rules;
110399a2dd95SBruce Richardson 			if (num_rules < smallest_size) {
110499a2dd95SBruce Richardson 				smallest_choice = choice;
110599a2dd95SBruce Richardson 				smallest_size = num_rules;
110699a2dd95SBruce Richardson 				smallest_group_id = test_group_id;
110799a2dd95SBruce Richardson 			}
110899a2dd95SBruce Richardson 		}
110999a2dd95SBruce Richardson 
111099a2dd95SBruce Richardson 		*new_bin_choice = smallest_choice;
111199a2dd95SBruce Richardson 		*group_id = smallest_group_id;
111299a2dd95SBruce Richardson 		new_group = &chunk->group_rules[smallest_group_id];
111399a2dd95SBruce Richardson 		current_group->num_rules += bin_size;
111499a2dd95SBruce Richardson 
111599a2dd95SBruce Richardson 	}
111699a2dd95SBruce Richardson 
111799a2dd95SBruce Richardson 	uint8_t choice = 0;
111899a2dd95SBruce Richardson 	for (;;) {
111999a2dd95SBruce Richardson 		if (current_group != new_group &&
112099a2dd95SBruce Richardson 				new_group->num_rules + bin_size >
112199a2dd95SBruce Richardson 					EFD_MAX_GROUP_NUM_RULES) {
1122ae67895bSDavid Marchand 			EFD_LOG(DEBUG,
112399a2dd95SBruce Richardson 					"Unable to move_groups to dest group "
112499a2dd95SBruce Richardson 					"containing %u entries."
1125ae67895bSDavid Marchand 					"bin_size:%u choice:%02x",
112699a2dd95SBruce Richardson 					new_group->num_rules, bin_size,
112799a2dd95SBruce Richardson 					choice - 1);
112899a2dd95SBruce Richardson 			goto next_choice;
112999a2dd95SBruce Richardson 		}
113099a2dd95SBruce Richardson 		move_groups(*bin_id, bin_size, new_group, current_group);
113199a2dd95SBruce Richardson 		/*
113299a2dd95SBruce Richardson 		 * Recompute the hash function for the modified group,
113399a2dd95SBruce Richardson 		 * and return it to the caller
113499a2dd95SBruce Richardson 		 */
113599a2dd95SBruce Richardson 		ret = efd_search_hash(table, new_group, entry);
113699a2dd95SBruce Richardson 
113799a2dd95SBruce Richardson 		if (!ret)
113899a2dd95SBruce Richardson 			return status;
113999a2dd95SBruce Richardson 
1140ae67895bSDavid Marchand 		EFD_LOG(DEBUG,
114199a2dd95SBruce Richardson 				"Failed to find perfect hash for group "
1142ae67895bSDavid Marchand 				"containing %u entries. bin_size:%u choice:%02x",
114399a2dd95SBruce Richardson 				new_group->num_rules, bin_size, choice - 1);
114499a2dd95SBruce Richardson 		/* Restore groups modified to their previous state */
114599a2dd95SBruce Richardson 		revert_groups(current_group, new_group, bin_size);
114699a2dd95SBruce Richardson 
114799a2dd95SBruce Richardson next_choice:
114899a2dd95SBruce Richardson 		if (choice == EFD_CHUNK_NUM_BIN_TO_GROUP_SETS)
114999a2dd95SBruce Richardson 			break;
115099a2dd95SBruce Richardson 		*new_bin_choice = choice;
115199a2dd95SBruce Richardson 		*group_id = efd_bin_to_group[choice][*bin_id];
115299a2dd95SBruce Richardson 		new_group = &chunk->group_rules[*group_id];
115399a2dd95SBruce Richardson 		choice++;
115499a2dd95SBruce Richardson 	}
115599a2dd95SBruce Richardson 
115699a2dd95SBruce Richardson 	if (!found) {
115799a2dd95SBruce Richardson 		current_group->num_rules--;
115899a2dd95SBruce Richardson 		table->num_rules--;
115999a2dd95SBruce Richardson 	} else
116099a2dd95SBruce Richardson 		current_group->value[current_group->num_rules - 1] =
116199a2dd95SBruce Richardson 			key_changed_previous_value;
116299a2dd95SBruce Richardson 	return RTE_EFD_UPDATE_FAILED;
116399a2dd95SBruce Richardson }
116499a2dd95SBruce Richardson 
116599a2dd95SBruce Richardson int
116699a2dd95SBruce Richardson rte_efd_update(struct rte_efd_table * const table, const unsigned int socket_id,
116799a2dd95SBruce Richardson 		const void *key, const efd_value_t value)
116899a2dd95SBruce Richardson {
116999a2dd95SBruce Richardson 	uint32_t chunk_id = 0, group_id = 0, bin_id = 0;
117099a2dd95SBruce Richardson 	uint8_t new_bin_choice = 0;
1171ecda2c40SPablo de Lara 	struct efd_online_group_entry entry = {{0}};
117299a2dd95SBruce Richardson 
117399a2dd95SBruce Richardson 	int status = efd_compute_update(table, socket_id, key, value,
117499a2dd95SBruce Richardson 			&chunk_id, &group_id, &bin_id,
117599a2dd95SBruce Richardson 			&new_bin_choice, &entry);
117699a2dd95SBruce Richardson 
117799a2dd95SBruce Richardson 	if (status == RTE_EFD_UPDATE_NO_CHANGE)
117899a2dd95SBruce Richardson 		return EXIT_SUCCESS;
117999a2dd95SBruce Richardson 
118099a2dd95SBruce Richardson 	if (status == RTE_EFD_UPDATE_FAILED)
118199a2dd95SBruce Richardson 		return status;
118299a2dd95SBruce Richardson 
118399a2dd95SBruce Richardson 	efd_apply_update(table, socket_id, chunk_id, group_id, bin_id,
118499a2dd95SBruce Richardson 			new_bin_choice, &entry);
118599a2dd95SBruce Richardson 	return status;
118699a2dd95SBruce Richardson }
118799a2dd95SBruce Richardson 
118899a2dd95SBruce Richardson int
118999a2dd95SBruce Richardson rte_efd_delete(struct rte_efd_table * const table, const unsigned int socket_id,
119099a2dd95SBruce Richardson 		const void *key, efd_value_t * const prev_value)
119199a2dd95SBruce Richardson {
119299a2dd95SBruce Richardson 	unsigned int i;
119399a2dd95SBruce Richardson 	uint32_t chunk_id, bin_id;
119499a2dd95SBruce Richardson 	uint8_t not_found = 1;
119599a2dd95SBruce Richardson 
119699a2dd95SBruce Richardson 	efd_compute_ids(table, key, &chunk_id, &bin_id);
119799a2dd95SBruce Richardson 
119899a2dd95SBruce Richardson 	struct efd_offline_chunk_rules * const chunk =
119999a2dd95SBruce Richardson 			&table->offline_chunks[chunk_id];
120099a2dd95SBruce Richardson 
120199a2dd95SBruce Richardson 	uint8_t current_choice = efd_get_choice(table, socket_id,
120299a2dd95SBruce Richardson 			chunk_id, bin_id);
120399a2dd95SBruce Richardson 	uint32_t current_group_id = efd_bin_to_group[current_choice][bin_id];
120499a2dd95SBruce Richardson 	struct efd_offline_group_rules * const current_group =
120599a2dd95SBruce Richardson 			&chunk->group_rules[current_group_id];
120699a2dd95SBruce Richardson 
120799a2dd95SBruce Richardson 	/*
120899a2dd95SBruce Richardson 	 * Search the current group for the specified key.
120999a2dd95SBruce Richardson 	 * If it exists, remove it and re-pack the other values
121099a2dd95SBruce Richardson 	 */
121199a2dd95SBruce Richardson 	for (i = 0; i < current_group->num_rules; i++) {
121299a2dd95SBruce Richardson 		if (not_found) {
121399a2dd95SBruce Richardson 			/* Found key that needs to be removed */
121499a2dd95SBruce Richardson 			if (memcmp(EFD_KEY(current_group->key_idx[i], table),
121599a2dd95SBruce Richardson 					key, table->key_len) == 0) {
121699a2dd95SBruce Richardson 				/* Store previous value if requested by caller */
121799a2dd95SBruce Richardson 				if (prev_value != NULL)
121899a2dd95SBruce Richardson 					*prev_value = current_group->value[i];
121999a2dd95SBruce Richardson 
122099a2dd95SBruce Richardson 				not_found = 0;
122199a2dd95SBruce Richardson 				rte_ring_sp_enqueue(table->free_slots,
122299a2dd95SBruce Richardson 					(void *)((uintptr_t)current_group->key_idx[i]));
122399a2dd95SBruce Richardson 			}
122499a2dd95SBruce Richardson 		} else {
122599a2dd95SBruce Richardson 			/*
122699a2dd95SBruce Richardson 			 * If the desired key has been found,
122799a2dd95SBruce Richardson 			 * need to shift other values up one
122899a2dd95SBruce Richardson 			 */
122999a2dd95SBruce Richardson 
123099a2dd95SBruce Richardson 			/* Need to shift this entry back up one index */
123199a2dd95SBruce Richardson 			current_group->key_idx[i - 1] = current_group->key_idx[i];
123299a2dd95SBruce Richardson 			current_group->value[i - 1] = current_group->value[i];
123399a2dd95SBruce Richardson 			current_group->bin_id[i - 1] = current_group->bin_id[i];
123499a2dd95SBruce Richardson 		}
123599a2dd95SBruce Richardson 	}
123699a2dd95SBruce Richardson 
123799a2dd95SBruce Richardson 	if (not_found == 0) {
123899a2dd95SBruce Richardson 		table->num_rules--;
123999a2dd95SBruce Richardson 		current_group->num_rules--;
124099a2dd95SBruce Richardson 	}
124199a2dd95SBruce Richardson 
124299a2dd95SBruce Richardson 	return not_found;
124399a2dd95SBruce Richardson }
124499a2dd95SBruce Richardson 
124599a2dd95SBruce Richardson static inline efd_value_t
124699a2dd95SBruce Richardson efd_lookup_internal_scalar(const efd_hashfunc_t *group_hash_idx,
124799a2dd95SBruce Richardson 		const efd_lookuptbl_t *group_lookup_table,
124899a2dd95SBruce Richardson 		const uint32_t hash_val_a, const uint32_t hash_val_b)
124999a2dd95SBruce Richardson {
125099a2dd95SBruce Richardson 	efd_value_t value = 0;
125199a2dd95SBruce Richardson 	uint32_t i;
125299a2dd95SBruce Richardson 
125399a2dd95SBruce Richardson 	for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
125499a2dd95SBruce Richardson 		value <<= 1;
125599a2dd95SBruce Richardson 		uint32_t h = hash_val_a + (hash_val_b *
125699a2dd95SBruce Richardson 			group_hash_idx[RTE_EFD_VALUE_NUM_BITS - i - 1]);
125799a2dd95SBruce Richardson 		uint16_t bucket_idx = h >> EFD_LOOKUPTBL_SHIFT;
125899a2dd95SBruce Richardson 		value |= (group_lookup_table[
125999a2dd95SBruce Richardson 				RTE_EFD_VALUE_NUM_BITS - i - 1] >>
126099a2dd95SBruce Richardson 				bucket_idx) & 0x1;
126199a2dd95SBruce Richardson 	}
126299a2dd95SBruce Richardson 
126399a2dd95SBruce Richardson 	return value;
126499a2dd95SBruce Richardson }
126599a2dd95SBruce Richardson 
126699a2dd95SBruce Richardson 
126799a2dd95SBruce Richardson static inline efd_value_t
126899a2dd95SBruce Richardson efd_lookup_internal(const struct efd_online_group_entry * const group,
126999a2dd95SBruce Richardson 		const uint32_t hash_val_a, const uint32_t hash_val_b,
127099a2dd95SBruce Richardson 		enum efd_lookup_internal_function lookup_fn)
127199a2dd95SBruce Richardson {
127299a2dd95SBruce Richardson 	efd_value_t value = 0;
127399a2dd95SBruce Richardson 
127499a2dd95SBruce Richardson 	switch (lookup_fn) {
127599a2dd95SBruce Richardson 
127699a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) && defined(CC_SUPPORT_AVX2)
127799a2dd95SBruce Richardson 	case EFD_LOOKUP_AVX2:
127899a2dd95SBruce Richardson 		return efd_lookup_internal_avx2(group->hash_idx,
127999a2dd95SBruce Richardson 					group->lookup_table,
128099a2dd95SBruce Richardson 					hash_val_a,
128199a2dd95SBruce Richardson 					hash_val_b);
128299a2dd95SBruce Richardson 		break;
128399a2dd95SBruce Richardson #endif
128499a2dd95SBruce Richardson #if defined(RTE_ARCH_ARM64)
128599a2dd95SBruce Richardson 	case EFD_LOOKUP_NEON:
128699a2dd95SBruce Richardson 		return efd_lookup_internal_neon(group->hash_idx,
128799a2dd95SBruce Richardson 					group->lookup_table,
128899a2dd95SBruce Richardson 					hash_val_a,
128999a2dd95SBruce Richardson 					hash_val_b);
129099a2dd95SBruce Richardson 		break;
129199a2dd95SBruce Richardson #endif
129299a2dd95SBruce Richardson 	case EFD_LOOKUP_SCALAR:
129399a2dd95SBruce Richardson 	/* Fall-through */
129499a2dd95SBruce Richardson 	default:
129599a2dd95SBruce Richardson 		return efd_lookup_internal_scalar(group->hash_idx,
129699a2dd95SBruce Richardson 					group->lookup_table,
129799a2dd95SBruce Richardson 					hash_val_a,
129899a2dd95SBruce Richardson 					hash_val_b);
129999a2dd95SBruce Richardson 	}
130099a2dd95SBruce Richardson 
130199a2dd95SBruce Richardson 	return value;
130299a2dd95SBruce Richardson }
130399a2dd95SBruce Richardson 
130499a2dd95SBruce Richardson efd_value_t
130599a2dd95SBruce Richardson rte_efd_lookup(const struct rte_efd_table * const table,
130699a2dd95SBruce Richardson 		const unsigned int socket_id, const void *key)
130799a2dd95SBruce Richardson {
130899a2dd95SBruce Richardson 	uint32_t chunk_id, group_id, bin_id;
130999a2dd95SBruce Richardson 	uint8_t bin_choice;
131099a2dd95SBruce Richardson 	const struct efd_online_group_entry *group;
131199a2dd95SBruce Richardson 	const struct efd_online_chunk * const chunks = table->chunks[socket_id];
131299a2dd95SBruce Richardson 
131399a2dd95SBruce Richardson 	/* Determine the chunk and group location for the given key */
131499a2dd95SBruce Richardson 	efd_compute_ids(table, key, &chunk_id, &bin_id);
131599a2dd95SBruce Richardson 	bin_choice = efd_get_choice(table, socket_id, chunk_id, bin_id);
131699a2dd95SBruce Richardson 	group_id = efd_bin_to_group[bin_choice][bin_id];
131799a2dd95SBruce Richardson 	group = &chunks[chunk_id].groups[group_id];
131899a2dd95SBruce Richardson 
131999a2dd95SBruce Richardson 	return efd_lookup_internal(group,
132099a2dd95SBruce Richardson 			EFD_HASHFUNCA(key, table),
132199a2dd95SBruce Richardson 			EFD_HASHFUNCB(key, table),
132299a2dd95SBruce Richardson 			table->lookup_fn);
132399a2dd95SBruce Richardson }
132499a2dd95SBruce Richardson 
132599a2dd95SBruce Richardson void rte_efd_lookup_bulk(const struct rte_efd_table * const table,
132699a2dd95SBruce Richardson 		const unsigned int socket_id, const int num_keys,
132799a2dd95SBruce Richardson 		const void **key_list, efd_value_t * const value_list)
132899a2dd95SBruce Richardson {
132999a2dd95SBruce Richardson 	int i;
133099a2dd95SBruce Richardson 	uint32_t chunk_id_list[RTE_EFD_BURST_MAX];
133199a2dd95SBruce Richardson 	uint32_t bin_id_list[RTE_EFD_BURST_MAX];
133299a2dd95SBruce Richardson 	uint8_t bin_choice_list[RTE_EFD_BURST_MAX];
133399a2dd95SBruce Richardson 	uint32_t group_id_list[RTE_EFD_BURST_MAX];
133499a2dd95SBruce Richardson 	struct efd_online_group_entry *group;
133599a2dd95SBruce Richardson 
133699a2dd95SBruce Richardson 	struct efd_online_chunk *chunks = table->chunks[socket_id];
133799a2dd95SBruce Richardson 
133899a2dd95SBruce Richardson 	for (i = 0; i < num_keys; i++) {
133999a2dd95SBruce Richardson 		efd_compute_ids(table, key_list[i], &chunk_id_list[i],
134099a2dd95SBruce Richardson 				&bin_id_list[i]);
134199a2dd95SBruce Richardson 		rte_prefetch0(&chunks[chunk_id_list[i]].bin_choice_list);
134299a2dd95SBruce Richardson 	}
134399a2dd95SBruce Richardson 
134499a2dd95SBruce Richardson 	for (i = 0; i < num_keys; i++) {
134599a2dd95SBruce Richardson 		bin_choice_list[i] = efd_get_choice(table, socket_id,
134699a2dd95SBruce Richardson 				chunk_id_list[i], bin_id_list[i]);
134799a2dd95SBruce Richardson 		group_id_list[i] =
134899a2dd95SBruce Richardson 				efd_bin_to_group[bin_choice_list[i]][bin_id_list[i]];
134999a2dd95SBruce Richardson 		group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
135099a2dd95SBruce Richardson 		rte_prefetch0(group);
135199a2dd95SBruce Richardson 	}
135299a2dd95SBruce Richardson 
135399a2dd95SBruce Richardson 	for (i = 0; i < num_keys; i++) {
135499a2dd95SBruce Richardson 		group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
135599a2dd95SBruce Richardson 		value_list[i] = efd_lookup_internal(group,
135699a2dd95SBruce Richardson 				EFD_HASHFUNCA(key_list[i], table),
135799a2dd95SBruce Richardson 				EFD_HASHFUNCB(key_list[i], table),
135899a2dd95SBruce Richardson 				table->lookup_fn);
135999a2dd95SBruce Richardson 	}
136099a2dd95SBruce Richardson }
1361