1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2016-2017 Intel Corporation
10 #include <sys/queue.h>
12 #include <rte_string_fns.h>
14 #include <rte_eal_memconfig.h>
15 #include <rte_errno.h>
16 #include <rte_malloc.h>
17 #include <rte_prefetch.h>
18 #include <rte_branch_prediction.h>
19 #include <rte_memcpy.h>
21 #include <rte_jhash.h>
22 #include <rte_hash_crc.h>
23 #include <rte_tailq.h>
26 #if defined(RTE_ARCH_X86)
27 #include "rte_efd_x86.h"
28 #elif defined(RTE_ARCH_ARM64)
29 #include "rte_efd_arm64.h"
32 #define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len))
33 /** Hash function used to determine chunk_id and bin_id for a group */
34 #define EFD_HASH(key, table) \
35 (uint32_t)(rte_jhash(key, table->key_len, 0xbc9f1d34))
36 /** Hash function used as constant component of perfect hash search */
37 #define EFD_HASHFUNCA(key, table) \
38 (uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d35))
39 /** Hash function used as multiplicative component of perfect hash search */
40 #define EFD_HASHFUNCB(key, table) \
41 (uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d36))
43 /*************************************************************************
45 *************************************************************************/
47 /* These parameters are fixed by the efd_bin_to_group balancing table */
48 #define EFD_CHUNK_NUM_GROUPS (64)
49 #define EFD_CHUNK_NUM_BINS (256)
50 #define EFD_CHUNK_NUM_BIN_TO_GROUP_SETS \
51 (EFD_CHUNK_NUM_BINS / EFD_CHUNK_NUM_GROUPS)
54 * Target number of rules that each chunk is created to handle.
55 * Used when initially allocating the table
57 #define EFD_TARGET_CHUNK_NUM_RULES \
58 (EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES)
60 * Max number of rules that each chunk is created to handle.
61 * Used when initially allocating the table
63 #define EFD_TARGET_CHUNK_MAX_NUM_RULES \
64 (EFD_CHUNK_NUM_GROUPS * EFD_MAX_GROUP_NUM_RULES)
66 /** This is fixed based on the bin_to_group permutation array */
67 #define EFD_MAX_GROUP_NUM_BINS (16)
70 * The end of the chunks array needs some extra padding to ensure
71 * that vectorization over-reads on the last online chunk stay within
74 #define EFD_NUM_CHUNK_PADDING_BYTES (256)
76 /* All different internal lookup functions */
77 enum efd_lookup_internal_function {
78 EFD_LOOKUP_SCALAR = 0,
84 TAILQ_HEAD(rte_efd_list, rte_tailq_entry);
86 static struct rte_tailq_elem rte_efd_tailq = {
89 EAL_REGISTER_TAILQ(rte_efd_tailq);
91 /** Internal permutation array used to shuffle bins into pseudorandom groups */
92 const uint32_t efd_bin_to_group[EFD_CHUNK_NUM_BIN_TO_GROUP_SETS][EFD_CHUNK_NUM_BINS] = {
94 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
95 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
96 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
97 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
98 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
99 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
100 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
101 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
102 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
103 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
104 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
105 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
106 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
107 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
108 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
109 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63
112 34, 33, 48, 59, 0, 21, 36, 18, 9, 49, 54, 38, 51, 23, 31, 5,
113 44, 23, 37, 52, 11, 4, 58, 20, 38, 40, 38, 22, 26, 28, 42, 6,
114 46, 16, 31, 28, 46, 14, 60, 0, 35, 53, 16, 58, 16, 29, 39, 7,
115 1, 54, 15, 11, 48, 3, 62, 9, 58, 5, 30, 43, 17, 7, 36, 34,
116 6, 36, 2, 14, 10, 1, 47, 47, 20, 45, 62, 56, 34, 25, 39, 18,
117 51, 41, 61, 25, 56, 40, 41, 37, 52, 35, 30, 57, 11, 42, 37, 27,
118 54, 19, 26, 13, 48, 31, 46, 15, 12, 10, 16, 20, 43, 17, 12, 55,
119 45, 18, 8, 41, 7, 31, 42, 63, 12, 14, 21, 57, 24, 40, 5, 41,
120 13, 44, 23, 59, 25, 57, 52, 50, 62, 1, 2, 49, 32, 57, 26, 43,
121 56, 60, 55, 5, 49, 6, 3, 50, 46, 39, 27, 33, 17, 4, 53, 13,
122 2, 19, 36, 51, 63, 0, 22, 33, 59, 28, 29, 23, 45, 33, 53, 27,
123 22, 21, 40, 56, 4, 18, 44, 47, 28, 17, 4, 50, 21, 62, 8, 39,
124 0, 8, 15, 24, 29, 24, 9, 11, 48, 61, 35, 55, 43, 1, 54, 42,
125 53, 60, 22, 3, 32, 52, 25, 8, 15, 60, 7, 55, 27, 63, 19, 10,
126 63, 24, 61, 19, 12, 38, 6, 29, 13, 37, 10, 3, 45, 32, 32, 30,
127 49, 61, 44, 14, 20, 58, 35, 30, 2, 26, 34, 51, 9, 59, 47, 50
130 32, 35, 32, 34, 55, 5, 6, 23, 49, 11, 6, 23, 52, 37, 29, 54,
131 55, 40, 63, 50, 29, 52, 61, 25, 12, 56, 39, 38, 29, 11, 46, 1,
132 40, 11, 19, 56, 7, 28, 51, 16, 15, 48, 21, 51, 60, 31, 14, 22,
133 41, 47, 59, 56, 53, 28, 58, 26, 43, 27, 41, 33, 24, 52, 44, 38,
134 13, 59, 48, 51, 60, 15, 3, 30, 15, 0, 10, 62, 44, 14, 28, 51,
135 38, 2, 41, 26, 25, 49, 10, 12, 55, 57, 27, 35, 19, 33, 0, 30,
136 5, 36, 47, 53, 5, 53, 20, 43, 34, 37, 52, 41, 21, 63, 59, 9,
137 24, 1, 45, 24, 39, 44, 45, 16, 9, 17, 7, 50, 57, 22, 18, 28,
138 25, 45, 2, 40, 58, 15, 17, 3, 1, 27, 61, 39, 19, 0, 19, 21,
139 57, 62, 54, 60, 54, 40, 48, 33, 36, 37, 4, 42, 1, 43, 58, 8,
140 13, 42, 10, 56, 35, 22, 48, 61, 63, 10, 49, 9, 24, 9, 25, 57,
141 33, 18, 13, 31, 42, 36, 36, 55, 30, 37, 53, 34, 59, 4, 4, 23,
142 8, 16, 58, 14, 30, 11, 12, 63, 49, 62, 2, 39, 47, 22, 2, 60,
143 18, 8, 46, 31, 6, 20, 32, 29, 46, 42, 20, 31, 32, 61, 34, 4,
144 47, 26, 20, 43, 26, 21, 7, 3, 16, 35, 18, 44, 27, 62, 13, 23,
145 6, 50, 12, 8, 45, 17, 3, 46, 50, 7, 14, 5, 17, 54, 38, 0
148 29, 56, 5, 7, 54, 48, 23, 37, 35, 44, 52, 40, 33, 49, 60, 0,
149 59, 51, 28, 12, 41, 26, 2, 23, 34, 5, 59, 40, 3, 19, 6, 26,
150 35, 53, 45, 49, 29, 57, 28, 62, 58, 59, 19, 53, 59, 62, 6, 54,
151 13, 15, 48, 50, 45, 21, 41, 12, 34, 40, 24, 56, 19, 21, 35, 18,
152 55, 45, 9, 61, 47, 61, 19, 15, 16, 39, 17, 31, 3, 51, 21, 50,
153 17, 25, 25, 11, 44, 16, 18, 28, 14, 2, 37, 61, 58, 27, 62, 4,
154 14, 17, 1, 9, 46, 28, 37, 0, 53, 43, 57, 7, 57, 46, 21, 41,
155 39, 14, 52, 60, 44, 53, 49, 60, 49, 63, 13, 11, 29, 1, 55, 47,
156 55, 12, 60, 43, 54, 37, 13, 6, 42, 10, 36, 13, 9, 8, 34, 51,
157 31, 32, 12, 7, 57, 2, 26, 14, 3, 30, 63, 3, 32, 1, 5, 11,
158 27, 24, 26, 44, 31, 23, 56, 38, 62, 0, 40, 30, 6, 23, 38, 2,
159 47, 5, 15, 27, 16, 10, 31, 25, 22, 63, 30, 25, 20, 33, 32, 50,
160 29, 43, 55, 10, 50, 45, 56, 20, 4, 7, 27, 46, 11, 16, 22, 52,
161 35, 20, 41, 54, 46, 33, 42, 18, 63, 8, 22, 58, 36, 4, 51, 42,
162 38, 32, 38, 22, 17, 0, 47, 8, 48, 8, 48, 1, 61, 36, 33, 20,
163 24, 39, 39, 18, 30, 36, 9, 43, 42, 24, 10, 58, 4, 15, 34, 52
167 /*************************************************************************
168 * Offline region structures
169 *************************************************************************/
171 /** Online group containing number of rules, values, keys and their bins
172 * for EFD_MAX_GROUP_NUM_RULES rules.
174 struct efd_offline_group_rules {
176 /**< Sum of the number of rules in all bins assigned to this group. */
178 uint32_t key_idx[EFD_MAX_GROUP_NUM_RULES];
179 /**< Array with all keys of the group. */
180 efd_value_t value[EFD_MAX_GROUP_NUM_RULES];
181 /**< Array with all values of the keys of the group. */
183 uint8_t bin_id[EFD_MAX_GROUP_NUM_RULES];
184 /**< Stores the bin for each corresponding key to
185 * avoid having to recompute it
189 /** Offline chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
190 * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
192 struct efd_offline_chunk_rules {
194 /**< Number of rules in the entire chunk;
195 * used to detect unbalanced groups
198 struct efd_offline_group_rules group_rules[EFD_CHUNK_NUM_GROUPS];
199 /**< Array of all groups in the chunk. */
202 /*************************************************************************
203 * Online region structures
204 *************************************************************************/
206 /** Online group containing values for EFD_MAX_GROUP_NUM_RULES rules. */
207 struct efd_online_group_entry {
208 efd_hashfunc_t hash_idx[RTE_EFD_VALUE_NUM_BITS];
209 efd_lookuptbl_t lookup_table[RTE_EFD_VALUE_NUM_BITS];
213 * A single chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
214 * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
216 struct efd_online_chunk {
217 uint8_t bin_choice_list[(EFD_CHUNK_NUM_BINS * 2 + 7) / 8];
218 /**< This is a packed indirection index into the 'groups' array.
219 * Each byte contains four two-bit values which index into
220 * the efd_bin_to_group array.
221 * The efd_bin_to_group array returns the index into the groups array
224 struct efd_online_group_entry groups[EFD_CHUNK_NUM_GROUPS];
225 /**< Array of all the groups in the chunk. */
229 * EFD table structure
231 struct rte_efd_table {
232 char name[RTE_EFD_NAMESIZE]; /**< Name of the efd table. */
234 uint32_t key_len; /**< Length of the key stored offline */
236 uint32_t max_num_rules;
237 /**< Static maximum number of entries the table was constructed to hold. */
240 /**< Number of entries currently in the table . */
243 /**< Number of chunks in the table needed to support num_rules. */
245 uint32_t num_chunks_shift;
246 /**< Bits to shift to get chunk id, instead of dividing by num_chunk. */
248 enum efd_lookup_internal_function lookup_fn;
249 /**< Indicates which lookup function to use. */
251 struct efd_online_chunk *chunks[RTE_MAX_NUMA_NODES];
252 /**< Dynamic array of size num_chunks of chunk records. */
254 struct efd_offline_chunk_rules *offline_chunks;
255 /**< Dynamic array of size num_chunks of key-value pairs. */
257 struct rte_ring *free_slots;
258 /**< Ring that stores all indexes of the free slots in the key table */
260 uint8_t *keys; /**< Dynamic array of size max_num_rules of keys */
264 * Computes the chunk ID for a given key hash
267 * EFD table to reference
269 * 32-bit key hash returned by EFD_HASH
272 * chunk ID containing this key hash
274 static inline uint32_t
275 efd_get_chunk_id(const struct rte_efd_table * const table,
276 const uint32_t hashed_key)
278 return hashed_key & (table->num_chunks - 1);
282 * Computes the bin ID for a given key hash
285 * EFD table to reference
287 * 32-bit key hash returned by EFD_HASH
289 * @return bin ID containing this key hash
291 static inline uint32_t
292 efd_get_bin_id(const struct rte_efd_table * const table,
293 const uint32_t hashed_key)
295 return (hashed_key >> table->num_chunks_shift) & (EFD_CHUNK_NUM_BINS - 1);
299 * Looks up the current permutation choice for a particular bin in the online table
302 * EFD table to reference
304 * Socket ID to use to look up existing values (ideally caller's socket id)
306 * Chunk ID of bin to look up
311 * Currently active permutation choice in the online table
313 static inline uint8_t
314 efd_get_choice(const struct rte_efd_table * const table,
315 const unsigned int socket_id, const uint32_t chunk_id,
316 const uint32_t bin_id)
318 struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
321 * Grab the chunk (byte) that contains the choices
322 * for four neighboring bins.
324 uint8_t choice_chunk =
325 chunk->bin_choice_list[bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS];
328 * Compute the offset into the chunk that contains
329 * the group_id lookup position
331 int offset = (bin_id & 0x3) * 2;
333 /* Extract from the byte just the desired lookup position */
334 return (uint8_t) ((choice_chunk >> offset) & 0x3);
338 * Compute the chunk_id and bin_id for a given key
341 * EFD table to reference
343 * Key to hash and find location of
351 efd_compute_ids(const struct rte_efd_table * const table,
352 const void *key, uint32_t * const chunk_id, uint32_t * const bin_id)
354 /* Compute the position of the entry in the hash table */
355 uint32_t h = EFD_HASH(key, table);
357 /* Compute the chunk_id where that entry can be found */
358 *chunk_id = efd_get_chunk_id(table, h);
361 * Compute the bin within that chunk where the entry
362 * can be found (0 - 255)
364 *bin_id = efd_get_bin_id(table, h);
368 * Search for a hash function for a group that satisfies all group results
371 efd_search_hash(struct rte_efd_table * const table,
372 const struct efd_offline_group_rules * const off_group,
373 struct efd_online_group_entry * const on_group)
375 efd_hashfunc_t hash_idx;
376 efd_hashfunc_t start_hash_idx[RTE_EFD_VALUE_NUM_BITS];
377 efd_lookuptbl_t start_lookup_table[RTE_EFD_VALUE_NUM_BITS];
379 uint32_t i, j, rule_id;
380 uint32_t hash_val_a[EFD_MAX_GROUP_NUM_RULES];
381 uint32_t hash_val_b[EFD_MAX_GROUP_NUM_RULES];
382 uint32_t hash_val[EFD_MAX_GROUP_NUM_RULES];
385 rte_prefetch0(off_group->value);
388 * Prepopulate the hash_val tables by running the two hash functions
389 * for each provided rule
391 for (i = 0; i < off_group->num_rules; i++) {
392 void *key_stored = EFD_KEY(off_group->key_idx[i], table);
393 hash_val_b[i] = EFD_HASHFUNCB(key_stored, table);
394 hash_val_a[i] = EFD_HASHFUNCA(key_stored, table);
397 for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
398 hash_idx = on_group->hash_idx[i];
399 start_hash_idx[i] = hash_idx;
400 start_lookup_table[i] = on_group->lookup_table[i];
403 efd_lookuptbl_t lookup_table = 0;
404 efd_lookuptbl_t lookup_table_complement = 0;
406 for (rule_id = 0; rule_id < off_group->num_rules; rule_id++)
407 hash_val[rule_id] = hash_val_a[rule_id] + (hash_idx *
408 hash_val_b[rule_id]);
411 * The goal here is to find a hash function for this
412 * particular bit entry that meets the following criteria:
413 * The most significant bits of the hash result define a
414 * shift into the lookup table where the bit will be stored
417 /* Iterate over each provided rule */
418 for (rule_id = 0; rule_id < off_group->num_rules;
421 * Use the few most significant bits (number based on
422 * EFD_LOOKUPTBL_SIZE) to see what position the
423 * expected bit should be set in the lookup_table
425 uint32_t bucket_idx = hash_val[rule_id] >>
429 * Get the current bit of interest.
430 * This only find an appropriate hash function
431 * for one bit at a time of the rule
433 efd_lookuptbl_t expected =
434 (off_group->value[rule_id] >> i) & 0x1;
437 * Add the expected bit (if set) to a map
438 * (lookup_table). Also set its complement
439 * in lookup_table_complement
441 lookup_table |= expected << bucket_idx;
442 lookup_table_complement |= (1 - expected)
446 * If ever the hash function of two different
447 * elements result in different values at the
448 * same location in the lookup_table,
449 * the current hash_idx is not valid.
451 if (lookup_table & lookup_table_complement)
456 * Check if the previous loop completed without
459 if (rule_id == off_group->num_rules) {
461 * Current hash function worked, store it
462 * for the current group
464 on_group->hash_idx[i] = hash_idx;
465 on_group->lookup_table[i] = lookup_table;
468 * Make sure that the hash function has changed
469 * from the starting value
471 hash_idx = start_hash_idx[i] + 1;
476 } while (hash_idx != start_hash_idx[i]);
478 /* Failed to find perfect hash for this group */
479 if (hash_idx == start_hash_idx[i]) {
481 * Restore previous hash_idx and lookup_table
484 for (j = 0; j < i; j++) {
485 on_group->hash_idx[j] = start_hash_idx[j];
486 on_group->lookup_table[j] = start_lookup_table[j];
495 struct rte_efd_table *
496 rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len,
497 uint8_t online_cpu_socket_bitmask, uint8_t offline_cpu_socket)
499 struct rte_efd_table *table = NULL;
500 uint8_t *key_array = NULL;
501 uint32_t num_chunks, num_chunks_shift;
503 struct rte_efd_list *efd_list = NULL;
504 struct rte_tailq_entry *te;
505 uint64_t offline_table_size;
506 char ring_name[RTE_RING_NAMESIZE];
507 struct rte_ring *r = NULL;
510 efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
512 if (online_cpu_socket_bitmask == 0) {
513 RTE_LOG(ERR, EFD, "At least one CPU socket must be enabled "
518 if (max_num_rules == 0) {
519 RTE_LOG(ERR, EFD, "Max num rules must be higher than 0\n");
524 * Compute the minimum number of chunks (smallest power of 2)
525 * that can hold all of the rules
527 if (max_num_rules % EFD_TARGET_CHUNK_NUM_RULES == 0)
528 num_chunks = rte_align32pow2(max_num_rules /
529 EFD_TARGET_CHUNK_NUM_RULES);
531 num_chunks = rte_align32pow2((max_num_rules /
532 EFD_TARGET_CHUNK_NUM_RULES) + 1);
534 num_chunks_shift = rte_bsf32(num_chunks);
536 rte_mcfg_tailq_write_lock();
539 * Guarantee there's no existing: this is normally already checked
540 * by ring creation above
542 TAILQ_FOREACH(te, efd_list, next)
544 table = (struct rte_efd_table *) te->data;
545 if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
553 goto error_unlock_exit;
556 te = rte_zmalloc("EFD_TAILQ_ENTRY", sizeof(*te), 0);
558 RTE_LOG(ERR, EFD, "tailq entry allocation failed\n");
559 goto error_unlock_exit;
562 /* Create a new EFD table management structure */
563 table = rte_zmalloc_socket(NULL,
564 sizeof(struct rte_efd_table),
568 RTE_LOG(ERR, EFD, "Allocating EFD table management structure"
569 " on socket %u failed\n",
571 goto error_unlock_exit;
575 RTE_LOG(DEBUG, EFD, "Allocated EFD table management structure "
576 "on socket %u\n", offline_cpu_socket);
578 table->max_num_rules = num_chunks * EFD_TARGET_CHUNK_MAX_NUM_RULES;
579 table->num_rules = 0;
580 table->num_chunks = num_chunks;
581 table->num_chunks_shift = num_chunks_shift;
582 table->key_len = key_len;
585 key_array = rte_zmalloc_socket(NULL,
586 table->max_num_rules * table->key_len,
589 if (key_array == NULL) {
590 RTE_LOG(ERR, EFD, "Allocating key array"
591 " on socket %u failed\n",
593 goto error_unlock_exit;
595 table->keys = key_array;
596 strlcpy(table->name, name, sizeof(table->name));
598 RTE_LOG(DEBUG, EFD, "Creating an EFD table with %u chunks,"
599 " which potentially supports %u entries\n",
600 num_chunks, table->max_num_rules);
602 /* Make sure all the allocatable table pointers are NULL initially */
603 for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
604 table->chunks[socket_id] = NULL;
605 table->offline_chunks = NULL;
608 * Allocate one online table per socket specified
609 * in the user-supplied bitmask
611 uint64_t online_table_size = num_chunks * sizeof(struct efd_online_chunk) +
612 EFD_NUM_CHUNK_PADDING_BYTES;
614 for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) {
615 if ((online_cpu_socket_bitmask >> socket_id) & 0x01) {
617 * Allocate all of the EFD table chunks (the online portion)
618 * as a continuous block
620 table->chunks[socket_id] =
626 if (table->chunks[socket_id] == NULL) {
628 "Allocating EFD online table on "
629 "socket %u failed\n",
631 goto error_unlock_exit;
634 "Allocated EFD online table of size "
635 "%"PRIu64" bytes (%.2f MB) on socket %u\n",
637 (float) online_table_size /
643 #if defined(RTE_ARCH_X86)
645 * For less than 4 bits, scalar function performs better
646 * than vectorised version
648 if (RTE_EFD_VALUE_NUM_BITS > 3 && rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
649 table->lookup_fn = EFD_LOOKUP_AVX2;
652 #if defined(RTE_ARCH_ARM64)
654 * For less than or equal to 16 bits, scalar function performs better
655 * than vectorised version
657 if (RTE_EFD_VALUE_NUM_BITS > 16 &&
658 rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON))
659 table->lookup_fn = EFD_LOOKUP_NEON;
662 table->lookup_fn = EFD_LOOKUP_SCALAR;
665 * Allocate the EFD table offline portion (with the actual rules
666 * mapping keys to values) as a continuous block.
667 * This could be several gigabytes of memory.
669 offline_table_size = num_chunks * sizeof(struct efd_offline_chunk_rules);
670 table->offline_chunks =
671 rte_zmalloc_socket(NULL,
675 if (table->offline_chunks == NULL) {
676 RTE_LOG(ERR, EFD, "Allocating EFD offline table on socket %u "
677 "failed\n", offline_cpu_socket);
678 goto error_unlock_exit;
682 "Allocated EFD offline table of size %"PRIu64" bytes "
683 " (%.2f MB) on socket %u\n", offline_table_size,
684 (float) offline_table_size / (1024.0F * 1024.0F),
687 te->data = (void *) table;
688 TAILQ_INSERT_TAIL(efd_list, te, next);
689 rte_mcfg_tailq_write_unlock();
691 snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name);
692 /* Create ring (Dummy slot index is not enqueued) */
693 r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules),
694 offline_cpu_socket, 0);
696 RTE_LOG(ERR, EFD, "memory allocation failed\n");
701 /* Populate free slots ring. Entry zero is reserved for key misses. */
702 for (i = 0; i < table->max_num_rules; i++)
703 rte_ring_sp_enqueue(r, (void *) ((uintptr_t) i));
705 table->free_slots = r;
709 rte_mcfg_tailq_write_unlock();
715 struct rte_efd_table *
716 rte_efd_find_existing(const char *name)
718 struct rte_efd_table *table = NULL;
719 struct rte_tailq_entry *te;
720 struct rte_efd_list *efd_list;
722 efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
724 rte_mcfg_tailq_read_lock();
726 TAILQ_FOREACH(te, efd_list, next)
728 table = (struct rte_efd_table *) te->data;
729 if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
732 rte_mcfg_tailq_read_unlock();
742 rte_efd_free(struct rte_efd_table *table)
745 struct rte_efd_list *efd_list;
746 struct rte_tailq_entry *te, *temp;
751 for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
752 rte_free(table->chunks[socket_id]);
754 efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
755 rte_mcfg_tailq_write_lock();
757 TAILQ_FOREACH_SAFE(te, efd_list, next, temp) {
758 if (te->data == (void *) table) {
759 TAILQ_REMOVE(efd_list, te, next);
765 rte_mcfg_tailq_write_unlock();
766 rte_ring_free(table->free_slots);
767 rte_free(table->offline_chunks);
768 rte_free(table->keys);
773 * Applies a previously computed table entry to the specified table for all
774 * socket-local copies of the online table.
775 * Intended to apply an update for only a single change
776 * to a key/value pair at a time
779 * EFD table to reference
781 * Socket ID to use to lookup existing values (ideally caller's socket id)
783 * Chunk index to update
785 * Group index to update
787 * Bin within the group that this update affects
788 * @param new_bin_choice
789 * Newly chosen permutation which this bin should use - only lower 2 bits
790 * @param new_group_entry
791 * Previously computed updated chunk/group entry
794 efd_apply_update(struct rte_efd_table * const table, const unsigned int socket_id,
795 const uint32_t chunk_id, const uint32_t group_id,
796 const uint32_t bin_id, const uint8_t new_bin_choice,
797 const struct efd_online_group_entry * const new_group_entry)
800 struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
801 uint8_t bin_index = bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
804 * Grab the current byte that contains the choices
805 * for four neighboring bins
807 uint8_t choice_chunk =
808 chunk->bin_choice_list[bin_index];
811 /* Compute the offset into the chunk that needs to be updated */
812 int offset = (bin_id & 0x3) * 2;
814 /* Zero the two bits of interest and set them to new_bin_choice */
815 choice_chunk = (choice_chunk & (~(0x03 << offset)))
816 | ((new_bin_choice & 0x03) << offset);
818 /* Update the online table with the new data across all sockets */
819 for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
820 if (table->chunks[i] != NULL) {
821 memcpy(&(table->chunks[i][chunk_id].groups[group_id]),
823 sizeof(struct efd_online_group_entry));
824 table->chunks[i][chunk_id].bin_choice_list[bin_index] =
831 * Move the bin from prev group to the new group
834 move_groups(uint32_t bin_id, uint8_t bin_size,
835 struct efd_offline_group_rules *new_group,
836 struct efd_offline_group_rules * const current_group)
839 uint8_t empty_idx = 0;
842 if (new_group == current_group)
845 for (i = 0; i < current_group->num_rules; i++) {
847 * Move keys that belong to the same bin
850 if (current_group->bin_id[i] == bin_id) {
851 new_group->key_idx[new_group->num_rules] =
852 current_group->key_idx[i];
853 new_group->value[new_group->num_rules] =
854 current_group->value[i];
855 new_group->bin_id[new_group->num_rules] =
856 current_group->bin_id[i];
857 new_group->num_rules++;
859 if (i != empty_idx) {
861 * Need to move this key towards
862 * the top of the array
864 current_group->key_idx[empty_idx] =
865 current_group->key_idx[i];
866 current_group->value[empty_idx] =
867 current_group->value[i];
868 current_group->bin_id[empty_idx] =
869 current_group->bin_id[i];
875 current_group->num_rules -= bin_size;
879 * Revert group/s to their previous state before
880 * trying to insert/add a new key
883 revert_groups(struct efd_offline_group_rules *previous_group,
884 struct efd_offline_group_rules *current_group, uint8_t bin_size)
888 if (current_group == previous_group)
891 /* Move keys back to previous group */
892 for (i = current_group->num_rules - bin_size;
893 i < current_group->num_rules; i++) {
894 previous_group->key_idx[previous_group->num_rules] =
895 current_group->key_idx[i];
896 previous_group->value[previous_group->num_rules] =
897 current_group->value[i];
898 previous_group->bin_id[previous_group->num_rules] =
899 current_group->bin_id[i];
900 previous_group->num_rules++;
904 * Decrease number of rules after the move
907 current_group->num_rules -= bin_size;
911 * Computes an updated table entry where the supplied key points to a new host.
912 * If no entry exists, one is inserted.
914 * This function does NOT modify the online table(s)
915 * This function DOES modify the offline table
918 * EFD table to reference
920 * Socket ID to use to lookup existing values (ideally caller's socket id)
924 * Value to associate with key
926 * Chunk ID of the chunk that was modified
928 * Group ID of the group that was modified
930 * Bin ID that was modified
931 * @param new_bin_choice
932 * Newly chosen permutation which this bin will use
934 * Newly computed online entry to apply later with efd_apply_update
937 * RTE_EFD_UPDATE_WARN_GROUP_FULL
938 * Operation is insert, and the last available space in the
939 * key's group was just used. Future inserts may fail as groups fill up.
940 * This operation was still successful, and entry contains a valid update
941 * RTE_EFD_UPDATE_FAILED
942 * Either the EFD failed to find a suitable perfect hash or the group was full
943 * This is a fatal error, and the table is now in an indeterminate state
944 * RTE_EFD_UPDATE_NO_CHANGE
945 * Operation resulted in no change to the table (same value already exists)
947 * Insert or update was successful, and the new efd_online_group_entry
948 * is stored in *entry
951 * Note that entry will be UNCHANGED if the update has no effect, and thus any
952 * subsequent use of the entry content will likely be invalid
955 efd_compute_update(struct rte_efd_table * const table,
956 const unsigned int socket_id, const void *key,
957 const efd_value_t value, uint32_t * const chunk_id,
958 uint32_t * const group_id, uint32_t * const bin_id,
959 uint8_t * const new_bin_choice,
960 struct efd_online_group_entry * const entry)
965 void *new_k, *slot_id = NULL;
966 int status = EXIT_SUCCESS;
967 unsigned int found = 0;
969 efd_compute_ids(table, key, chunk_id, bin_id);
971 struct efd_offline_chunk_rules * const chunk =
972 &table->offline_chunks[*chunk_id];
973 struct efd_offline_group_rules *new_group;
975 uint8_t current_choice = efd_get_choice(table, socket_id,
977 uint32_t current_group_id = efd_bin_to_group[current_choice][*bin_id];
978 struct efd_offline_group_rules * const current_group =
979 &chunk->group_rules[current_group_id];
980 uint8_t bin_size = 0;
981 uint8_t key_changed_index = 0;
982 efd_value_t key_changed_previous_value = 0;
983 uint32_t key_idx_previous = 0;
985 /* Scan the current group and see if the key is already present */
986 for (i = 0; i < current_group->num_rules; i++) {
987 if (current_group->bin_id[i] == *bin_id)
992 void *key_stored = EFD_KEY(current_group->key_idx[i], table);
993 if (found == 0 && unlikely(memcmp(key_stored, key,
994 table->key_len) == 0)) {
995 /* Key is already present */
998 * If previous value is same as new value,
999 * no additional work is required
1001 if (current_group->value[i] == value)
1002 return RTE_EFD_UPDATE_NO_CHANGE;
1004 key_idx_previous = current_group->key_idx[i];
1005 key_changed_previous_value = current_group->value[i];
1006 key_changed_index = i;
1007 current_group->value[i] = value;
1013 /* Key does not exist. Insert the rule into the bin/group */
1014 if (unlikely(current_group->num_rules >= EFD_MAX_GROUP_NUM_RULES)) {
1016 "Fatal: No room remaining for insert into "
1017 "chunk %u group %u bin %u\n",
1019 current_group_id, *bin_id);
1020 return RTE_EFD_UPDATE_FAILED;
1023 if (unlikely(current_group->num_rules ==
1024 (EFD_MAX_GROUP_NUM_RULES - 1))) {
1025 RTE_LOG(INFO, EFD, "Warn: Insert into last "
1026 "available slot in chunk %u "
1027 "group %u bin %u\n", *chunk_id,
1028 current_group_id, *bin_id);
1029 status = RTE_EFD_UPDATE_WARN_GROUP_FULL;
1032 if (rte_ring_sc_dequeue(table->free_slots, &slot_id) != 0)
1033 return RTE_EFD_UPDATE_FAILED;
1035 new_k = RTE_PTR_ADD(table->keys, (uintptr_t) slot_id *
1037 rte_prefetch0(new_k);
1038 new_idx = (uint32_t) ((uintptr_t) slot_id);
1040 rte_memcpy(EFD_KEY(new_idx, table), key, table->key_len);
1041 current_group->key_idx[current_group->num_rules] = new_idx;
1042 current_group->value[current_group->num_rules] = value;
1043 current_group->bin_id[current_group->num_rules] = *bin_id;
1044 current_group->num_rules++;
1048 uint32_t last = current_group->num_rules - 1;
1049 /* Swap the key with the last key inserted*/
1050 current_group->key_idx[key_changed_index] =
1051 current_group->key_idx[last];
1052 current_group->value[key_changed_index] =
1053 current_group->value[last];
1054 current_group->bin_id[key_changed_index] =
1055 current_group->bin_id[last];
1058 * Key to be updated will always be available
1059 * at the end of the group
1061 current_group->key_idx[last] = key_idx_previous;
1062 current_group->value[last] = value;
1063 current_group->bin_id[last] = *bin_id;
1066 *new_bin_choice = current_choice;
1067 *group_id = current_group_id;
1068 new_group = current_group;
1070 /* Group need to be rebalanced when it starts to get loaded */
1071 if (current_group->num_rules > EFD_MIN_BALANCED_NUM_RULES) {
1074 * Subtract the number of entries in the bin from
1075 * the original group
1077 current_group->num_rules -= bin_size;
1080 * Figure out which of the available groups that this bin
1081 * can map to is the smallest (using the current group
1084 uint8_t smallest_choice = current_choice;
1085 uint8_t smallest_size = current_group->num_rules;
1086 uint32_t smallest_group_id = current_group_id;
1087 unsigned char choice;
1089 for (choice = 0; choice < EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
1091 uint32_t test_group_id =
1092 efd_bin_to_group[choice][*bin_id];
1093 uint32_t num_rules =
1094 chunk->group_rules[test_group_id].num_rules;
1095 if (num_rules < smallest_size) {
1096 smallest_choice = choice;
1097 smallest_size = num_rules;
1098 smallest_group_id = test_group_id;
1102 *new_bin_choice = smallest_choice;
1103 *group_id = smallest_group_id;
1104 new_group = &chunk->group_rules[smallest_group_id];
1105 current_group->num_rules += bin_size;
1111 if (current_group != new_group &&
1112 new_group->num_rules + bin_size >
1113 EFD_MAX_GROUP_NUM_RULES) {
1115 "Unable to move_groups to dest group "
1116 "containing %u entries."
1117 "bin_size:%u choice:%02x\n",
1118 new_group->num_rules, bin_size,
1122 move_groups(*bin_id, bin_size, new_group, current_group);
1124 * Recompute the hash function for the modified group,
1125 * and return it to the caller
1127 ret = efd_search_hash(table, new_group, entry);
1133 "Failed to find perfect hash for group "
1134 "containing %u entries. bin_size:%u choice:%02x\n",
1135 new_group->num_rules, bin_size, choice - 1);
1136 /* Restore groups modified to their previous state */
1137 revert_groups(current_group, new_group, bin_size);
1140 if (choice == EFD_CHUNK_NUM_BIN_TO_GROUP_SETS)
1142 *new_bin_choice = choice;
1143 *group_id = efd_bin_to_group[choice][*bin_id];
1144 new_group = &chunk->group_rules[*group_id];
1149 current_group->num_rules--;
1152 current_group->value[current_group->num_rules - 1] =
1153 key_changed_previous_value;
1154 return RTE_EFD_UPDATE_FAILED;
1158 rte_efd_update(struct rte_efd_table * const table, const unsigned int socket_id,
1159 const void *key, const efd_value_t value)
1161 uint32_t chunk_id = 0, group_id = 0, bin_id = 0;
1162 uint8_t new_bin_choice = 0;
1163 struct efd_online_group_entry entry;
1165 int status = efd_compute_update(table, socket_id, key, value,
1166 &chunk_id, &group_id, &bin_id,
1167 &new_bin_choice, &entry);
1169 if (status == RTE_EFD_UPDATE_NO_CHANGE)
1170 return EXIT_SUCCESS;
1172 if (status == RTE_EFD_UPDATE_FAILED)
1175 efd_apply_update(table, socket_id, chunk_id, group_id, bin_id,
1176 new_bin_choice, &entry);
1181 rte_efd_delete(struct rte_efd_table * const table, const unsigned int socket_id,
1182 const void *key, efd_value_t * const prev_value)
1185 uint32_t chunk_id, bin_id;
1186 uint8_t not_found = 1;
1188 efd_compute_ids(table, key, &chunk_id, &bin_id);
1190 struct efd_offline_chunk_rules * const chunk =
1191 &table->offline_chunks[chunk_id];
1193 uint8_t current_choice = efd_get_choice(table, socket_id,
1195 uint32_t current_group_id = efd_bin_to_group[current_choice][bin_id];
1196 struct efd_offline_group_rules * const current_group =
1197 &chunk->group_rules[current_group_id];
1200 * Search the current group for the specified key.
1201 * If it exists, remove it and re-pack the other values
1203 for (i = 0; i < current_group->num_rules; i++) {
1205 /* Found key that needs to be removed */
1206 if (memcmp(EFD_KEY(current_group->key_idx[i], table),
1207 key, table->key_len) == 0) {
1208 /* Store previous value if requested by caller */
1209 if (prev_value != NULL)
1210 *prev_value = current_group->value[i];
1213 rte_ring_sp_enqueue(table->free_slots,
1214 (void *)((uintptr_t)current_group->key_idx[i]));
1218 * If the desired key has been found,
1219 * need to shift other values up one
1222 /* Need to shift this entry back up one index */
1223 current_group->key_idx[i - 1] = current_group->key_idx[i];
1224 current_group->value[i - 1] = current_group->value[i];
1225 current_group->bin_id[i - 1] = current_group->bin_id[i];
1229 if (not_found == 0) {
1231 current_group->num_rules--;
1237 static inline efd_value_t
1238 efd_lookup_internal_scalar(const efd_hashfunc_t *group_hash_idx,
1239 const efd_lookuptbl_t *group_lookup_table,
1240 const uint32_t hash_val_a, const uint32_t hash_val_b)
1242 efd_value_t value = 0;
1245 for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
1247 uint32_t h = hash_val_a + (hash_val_b *
1248 group_hash_idx[RTE_EFD_VALUE_NUM_BITS - i - 1]);
1249 uint16_t bucket_idx = h >> EFD_LOOKUPTBL_SHIFT;
1250 value |= (group_lookup_table[
1251 RTE_EFD_VALUE_NUM_BITS - i - 1] >>
1259 static inline efd_value_t
1260 efd_lookup_internal(const struct efd_online_group_entry * const group,
1261 const uint32_t hash_val_a, const uint32_t hash_val_b,
1262 enum efd_lookup_internal_function lookup_fn)
1264 efd_value_t value = 0;
1266 switch (lookup_fn) {
1268 #if defined(RTE_ARCH_X86) && defined(CC_SUPPORT_AVX2)
1269 case EFD_LOOKUP_AVX2:
1270 return efd_lookup_internal_avx2(group->hash_idx,
1271 group->lookup_table,
1276 #if defined(RTE_ARCH_ARM64)
1277 case EFD_LOOKUP_NEON:
1278 return efd_lookup_internal_neon(group->hash_idx,
1279 group->lookup_table,
1284 case EFD_LOOKUP_SCALAR:
1287 return efd_lookup_internal_scalar(group->hash_idx,
1288 group->lookup_table,
1297 rte_efd_lookup(const struct rte_efd_table * const table,
1298 const unsigned int socket_id, const void *key)
1300 uint32_t chunk_id, group_id, bin_id;
1302 const struct efd_online_group_entry *group;
1303 const struct efd_online_chunk * const chunks = table->chunks[socket_id];
1305 /* Determine the chunk and group location for the given key */
1306 efd_compute_ids(table, key, &chunk_id, &bin_id);
1307 bin_choice = efd_get_choice(table, socket_id, chunk_id, bin_id);
1308 group_id = efd_bin_to_group[bin_choice][bin_id];
1309 group = &chunks[chunk_id].groups[group_id];
1311 return efd_lookup_internal(group,
1312 EFD_HASHFUNCA(key, table),
1313 EFD_HASHFUNCB(key, table),
1317 void rte_efd_lookup_bulk(const struct rte_efd_table * const table,
1318 const unsigned int socket_id, const int num_keys,
1319 const void **key_list, efd_value_t * const value_list)
1322 uint32_t chunk_id_list[RTE_EFD_BURST_MAX];
1323 uint32_t bin_id_list[RTE_EFD_BURST_MAX];
1324 uint8_t bin_choice_list[RTE_EFD_BURST_MAX];
1325 uint32_t group_id_list[RTE_EFD_BURST_MAX];
1326 struct efd_online_group_entry *group;
1328 struct efd_online_chunk *chunks = table->chunks[socket_id];
1330 for (i = 0; i < num_keys; i++) {
1331 efd_compute_ids(table, key_list[i], &chunk_id_list[i],
1333 rte_prefetch0(&chunks[chunk_id_list[i]].bin_choice_list);
1336 for (i = 0; i < num_keys; i++) {
1337 bin_choice_list[i] = efd_get_choice(table, socket_id,
1338 chunk_id_list[i], bin_id_list[i]);
1340 efd_bin_to_group[bin_choice_list[i]][bin_id_list[i]];
1341 group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
1342 rte_prefetch0(group);
1345 for (i = 0; i < num_keys; i++) {
1346 group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
1347 value_list[i] = efd_lookup_internal(group,
1348 EFD_HASHFUNCA(key_list[i], table),
1349 EFD_HASHFUNCB(key_list[i], table),