1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2016-2017 Intel Corporation
3 */
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdint.h>
7 #include <inttypes.h>
8 #include <errno.h>
9 #include <sys/queue.h>
10
11 #include <rte_string_fns.h>
12 #include <rte_log.h>
13 #include <rte_eal_memconfig.h>
14 #include <rte_errno.h>
15 #include <rte_malloc.h>
16 #include <rte_prefetch.h>
17 #include <rte_branch_prediction.h>
18 #include <rte_memcpy.h>
19 #include <rte_ring.h>
20 #include <rte_jhash.h>
21 #include <rte_hash_crc.h>
22 #include <rte_tailq.h>
23
24 #include "rte_efd.h"
25 #if defined(RTE_ARCH_X86)
26 #elif defined(RTE_ARCH_ARM64)
27 #include "rte_efd_arm64.h"
28 #endif
29
30 #define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len))
31 /** Hash function used to determine chunk_id and bin_id for a group */
32 #define EFD_HASH(key, table) \
33 (uint32_t)(rte_jhash(key, table->key_len, 0xbc9f1d34))
34 /** Hash function used as constant component of perfect hash search */
35 #define EFD_HASHFUNCA(key, table) \
36 (uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d35))
37 /** Hash function used as multiplicative component of perfect hash search */
38 #define EFD_HASHFUNCB(key, table) \
39 (uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d36))
40
41 /*************************************************************************
42 * Fixed constants
43 *************************************************************************/
44
45 /* These parameters are fixed by the efd_bin_to_group balancing table */
46 #define EFD_CHUNK_NUM_GROUPS (64)
47 #define EFD_CHUNK_NUM_BINS (256)
48 #define EFD_CHUNK_NUM_BIN_TO_GROUP_SETS \
49 (EFD_CHUNK_NUM_BINS / EFD_CHUNK_NUM_GROUPS)
50
51 /*
52 * Target number of rules that each chunk is created to handle.
53 * Used when initially allocating the table
54 */
55 #define EFD_TARGET_CHUNK_NUM_RULES \
56 (EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES)
57 /*
58 * Max number of rules that each chunk is created to handle.
59 * Used when initially allocating the table
60 */
61 #define EFD_TARGET_CHUNK_MAX_NUM_RULES \
62 (EFD_CHUNK_NUM_GROUPS * EFD_MAX_GROUP_NUM_RULES)
63
64 /** This is fixed based on the bin_to_group permutation array */
65 #define EFD_MAX_GROUP_NUM_BINS (16)
66
67 /**
68 * The end of the chunks array needs some extra padding to ensure
69 * that vectorization over-reads on the last online chunk stay within
70 allocated memory
71 */
72 #define EFD_NUM_CHUNK_PADDING_BYTES (256)
73
74 /* All different internal lookup functions */
75 enum efd_lookup_internal_function {
76 EFD_LOOKUP_SCALAR = 0,
77 EFD_LOOKUP_AVX2,
78 EFD_LOOKUP_NEON,
79 EFD_LOOKUP_NUM
80 };
81
82 TAILQ_HEAD(rte_efd_list, rte_tailq_entry);
83
84 static struct rte_tailq_elem rte_efd_tailq = {
85 .name = "RTE_EFD",
86 };
87 EAL_REGISTER_TAILQ(rte_efd_tailq);
88
89 /** Internal permutation array used to shuffle bins into pseudorandom groups */
90 const uint32_t efd_bin_to_group[EFD_CHUNK_NUM_BIN_TO_GROUP_SETS][EFD_CHUNK_NUM_BINS] = {
91 {
92 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
93 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
94 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
95 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
96 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
97 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
98 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
99 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
100 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
101 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
102 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
103 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
104 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
105 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
106 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
107 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63
108 },
109 {
110 34, 33, 48, 59, 0, 21, 36, 18, 9, 49, 54, 38, 51, 23, 31, 5,
111 44, 23, 37, 52, 11, 4, 58, 20, 38, 40, 38, 22, 26, 28, 42, 6,
112 46, 16, 31, 28, 46, 14, 60, 0, 35, 53, 16, 58, 16, 29, 39, 7,
113 1, 54, 15, 11, 48, 3, 62, 9, 58, 5, 30, 43, 17, 7, 36, 34,
114 6, 36, 2, 14, 10, 1, 47, 47, 20, 45, 62, 56, 34, 25, 39, 18,
115 51, 41, 61, 25, 56, 40, 41, 37, 52, 35, 30, 57, 11, 42, 37, 27,
116 54, 19, 26, 13, 48, 31, 46, 15, 12, 10, 16, 20, 43, 17, 12, 55,
117 45, 18, 8, 41, 7, 31, 42, 63, 12, 14, 21, 57, 24, 40, 5, 41,
118 13, 44, 23, 59, 25, 57, 52, 50, 62, 1, 2, 49, 32, 57, 26, 43,
119 56, 60, 55, 5, 49, 6, 3, 50, 46, 39, 27, 33, 17, 4, 53, 13,
120 2, 19, 36, 51, 63, 0, 22, 33, 59, 28, 29, 23, 45, 33, 53, 27,
121 22, 21, 40, 56, 4, 18, 44, 47, 28, 17, 4, 50, 21, 62, 8, 39,
122 0, 8, 15, 24, 29, 24, 9, 11, 48, 61, 35, 55, 43, 1, 54, 42,
123 53, 60, 22, 3, 32, 52, 25, 8, 15, 60, 7, 55, 27, 63, 19, 10,
124 63, 24, 61, 19, 12, 38, 6, 29, 13, 37, 10, 3, 45, 32, 32, 30,
125 49, 61, 44, 14, 20, 58, 35, 30, 2, 26, 34, 51, 9, 59, 47, 50
126 },
127 {
128 32, 35, 32, 34, 55, 5, 6, 23, 49, 11, 6, 23, 52, 37, 29, 54,
129 55, 40, 63, 50, 29, 52, 61, 25, 12, 56, 39, 38, 29, 11, 46, 1,
130 40, 11, 19, 56, 7, 28, 51, 16, 15, 48, 21, 51, 60, 31, 14, 22,
131 41, 47, 59, 56, 53, 28, 58, 26, 43, 27, 41, 33, 24, 52, 44, 38,
132 13, 59, 48, 51, 60, 15, 3, 30, 15, 0, 10, 62, 44, 14, 28, 51,
133 38, 2, 41, 26, 25, 49, 10, 12, 55, 57, 27, 35, 19, 33, 0, 30,
134 5, 36, 47, 53, 5, 53, 20, 43, 34, 37, 52, 41, 21, 63, 59, 9,
135 24, 1, 45, 24, 39, 44, 45, 16, 9, 17, 7, 50, 57, 22, 18, 28,
136 25, 45, 2, 40, 58, 15, 17, 3, 1, 27, 61, 39, 19, 0, 19, 21,
137 57, 62, 54, 60, 54, 40, 48, 33, 36, 37, 4, 42, 1, 43, 58, 8,
138 13, 42, 10, 56, 35, 22, 48, 61, 63, 10, 49, 9, 24, 9, 25, 57,
139 33, 18, 13, 31, 42, 36, 36, 55, 30, 37, 53, 34, 59, 4, 4, 23,
140 8, 16, 58, 14, 30, 11, 12, 63, 49, 62, 2, 39, 47, 22, 2, 60,
141 18, 8, 46, 31, 6, 20, 32, 29, 46, 42, 20, 31, 32, 61, 34, 4,
142 47, 26, 20, 43, 26, 21, 7, 3, 16, 35, 18, 44, 27, 62, 13, 23,
143 6, 50, 12, 8, 45, 17, 3, 46, 50, 7, 14, 5, 17, 54, 38, 0
144 },
145 {
146 29, 56, 5, 7, 54, 48, 23, 37, 35, 44, 52, 40, 33, 49, 60, 0,
147 59, 51, 28, 12, 41, 26, 2, 23, 34, 5, 59, 40, 3, 19, 6, 26,
148 35, 53, 45, 49, 29, 57, 28, 62, 58, 59, 19, 53, 59, 62, 6, 54,
149 13, 15, 48, 50, 45, 21, 41, 12, 34, 40, 24, 56, 19, 21, 35, 18,
150 55, 45, 9, 61, 47, 61, 19, 15, 16, 39, 17, 31, 3, 51, 21, 50,
151 17, 25, 25, 11, 44, 16, 18, 28, 14, 2, 37, 61, 58, 27, 62, 4,
152 14, 17, 1, 9, 46, 28, 37, 0, 53, 43, 57, 7, 57, 46, 21, 41,
153 39, 14, 52, 60, 44, 53, 49, 60, 49, 63, 13, 11, 29, 1, 55, 47,
154 55, 12, 60, 43, 54, 37, 13, 6, 42, 10, 36, 13, 9, 8, 34, 51,
155 31, 32, 12, 7, 57, 2, 26, 14, 3, 30, 63, 3, 32, 1, 5, 11,
156 27, 24, 26, 44, 31, 23, 56, 38, 62, 0, 40, 30, 6, 23, 38, 2,
157 47, 5, 15, 27, 16, 10, 31, 25, 22, 63, 30, 25, 20, 33, 32, 50,
158 29, 43, 55, 10, 50, 45, 56, 20, 4, 7, 27, 46, 11, 16, 22, 52,
159 35, 20, 41, 54, 46, 33, 42, 18, 63, 8, 22, 58, 36, 4, 51, 42,
160 38, 32, 38, 22, 17, 0, 47, 8, 48, 8, 48, 1, 61, 36, 33, 20,
161 24, 39, 39, 18, 30, 36, 9, 43, 42, 24, 10, 58, 4, 15, 34, 52
162 },
163 };
164
165 /*************************************************************************
166 * Offline region structures
167 *************************************************************************/
168
169 /** Online group containing number of rules, values, keys and their bins
170 * for EFD_MAX_GROUP_NUM_RULES rules.
171 */
172 struct efd_offline_group_rules {
173 uint32_t num_rules;
174 /**< Sum of the number of rules in all bins assigned to this group. */
175
176 uint32_t key_idx[EFD_MAX_GROUP_NUM_RULES];
177 /**< Array with all keys of the group. */
178 efd_value_t value[EFD_MAX_GROUP_NUM_RULES];
179 /**< Array with all values of the keys of the group. */
180
181 uint8_t bin_id[EFD_MAX_GROUP_NUM_RULES];
182 /**< Stores the bin for each corresponding key to
183 * avoid having to recompute it
184 */
185 };
186
187 /** Offline chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
188 * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
189 */
190 struct efd_offline_chunk_rules {
191 uint16_t num_rules;
192 /**< Number of rules in the entire chunk;
193 * used to detect unbalanced groups
194 */
195
196 struct efd_offline_group_rules group_rules[EFD_CHUNK_NUM_GROUPS];
197 /**< Array of all groups in the chunk. */
198 };
199
200 /*************************************************************************
201 * Online region structures
202 *************************************************************************/
203
204 /** Online group containing values for EFD_MAX_GROUP_NUM_RULES rules. */
205 struct efd_online_group_entry {
206 efd_hashfunc_t hash_idx[RTE_EFD_VALUE_NUM_BITS];
207 efd_lookuptbl_t lookup_table[RTE_EFD_VALUE_NUM_BITS];
208 } __rte_packed;
209
210 /**
211 * A single chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
212 * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
213 */
214 struct efd_online_chunk {
215 uint8_t bin_choice_list[(EFD_CHUNK_NUM_BINS * 2 + 7) / 8];
216 /**< This is a packed indirection index into the 'groups' array.
217 * Each byte contains four two-bit values which index into
218 * the efd_bin_to_group array.
219 * The efd_bin_to_group array returns the index into the groups array
220 */
221
222 struct efd_online_group_entry groups[EFD_CHUNK_NUM_GROUPS];
223 /**< Array of all the groups in the chunk. */
224 } __rte_packed;
225
226 /**
227 * EFD table structure
228 */
229 struct rte_efd_table {
230 char name[RTE_EFD_NAMESIZE]; /**< Name of the efd table. */
231
232 uint32_t key_len; /**< Length of the key stored offline */
233
234 uint32_t max_num_rules;
235 /**< Static maximum number of entries the table was constructed to hold. */
236
237 uint32_t num_rules;
238 /**< Number of entries currently in the table . */
239
240 uint32_t num_chunks;
241 /**< Number of chunks in the table needed to support num_rules. */
242
243 uint32_t num_chunks_shift;
244 /**< Bits to shift to get chunk id, instead of dividing by num_chunk. */
245
246 enum efd_lookup_internal_function lookup_fn;
247 /**< Indicates which lookup function to use. */
248
249 struct efd_online_chunk *chunks[RTE_MAX_NUMA_NODES];
250 /**< Dynamic array of size num_chunks of chunk records. */
251
252 struct efd_offline_chunk_rules *offline_chunks;
253 /**< Dynamic array of size num_chunks of key-value pairs. */
254
255 struct rte_ring *free_slots;
256 /**< Ring that stores all indexes of the free slots in the key table */
257
258 uint8_t *keys; /**< Dynamic array of size max_num_rules of keys */
259 };
260
261 /**
262 * Computes the chunk ID for a given key hash
263 *
264 * @param table
265 * EFD table to reference
266 * @param hashed_key
267 * 32-bit key hash returned by EFD_HASH
268 *
269 * @return
270 * chunk ID containing this key hash
271 */
272 static inline uint32_t
efd_get_chunk_id(const struct rte_efd_table * const table,const uint32_t hashed_key)273 efd_get_chunk_id(const struct rte_efd_table * const table,
274 const uint32_t hashed_key)
275 {
276 return hashed_key & (table->num_chunks - 1);
277 }
278
279 /**
280 * Computes the bin ID for a given key hash
281 *
282 * @param table
283 * EFD table to reference
284 * @param hashed_key
285 * 32-bit key hash returned by EFD_HASH
286 *
287 * @return bin ID containing this key hash
288 */
289 static inline uint32_t
efd_get_bin_id(const struct rte_efd_table * const table,const uint32_t hashed_key)290 efd_get_bin_id(const struct rte_efd_table * const table,
291 const uint32_t hashed_key)
292 {
293 return (hashed_key >> table->num_chunks_shift) & (EFD_CHUNK_NUM_BINS - 1);
294 }
295
296 /**
297 * Looks up the current permutation choice for a particular bin in the online table
298 *
299 * @param table
300 * EFD table to reference
301 * @param socket_id
302 * Socket ID to use to look up existing values (ideally caller's socket id)
303 * @param chunk_id
304 * Chunk ID of bin to look up
305 * @param bin_id
306 * Bin ID to look up
307 *
308 * @return
309 * Currently active permutation choice in the online table
310 */
311 static inline uint8_t
efd_get_choice(const struct rte_efd_table * const table,const unsigned int socket_id,const uint32_t chunk_id,const uint32_t bin_id)312 efd_get_choice(const struct rte_efd_table * const table,
313 const unsigned int socket_id, const uint32_t chunk_id,
314 const uint32_t bin_id)
315 {
316 struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
317
318 /*
319 * Grab the chunk (byte) that contains the choices
320 * for four neighboring bins.
321 */
322 uint8_t choice_chunk =
323 chunk->bin_choice_list[bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS];
324
325 /*
326 * Compute the offset into the chunk that contains
327 * the group_id lookup position
328 */
329 int offset = (bin_id & 0x3) * 2;
330
331 /* Extract from the byte just the desired lookup position */
332 return (uint8_t) ((choice_chunk >> offset) & 0x3);
333 }
334
335 /**
336 * Compute the chunk_id and bin_id for a given key
337 *
338 * @param table
339 * EFD table to reference
340 * @param key
341 * Key to hash and find location of
342 * @param chunk_id
343 * Computed chunk ID
344 * @param bin_id
345 * Computed bin ID
346 *
347 */
348 static inline void
efd_compute_ids(const struct rte_efd_table * const table,const void * key,uint32_t * const chunk_id,uint32_t * const bin_id)349 efd_compute_ids(const struct rte_efd_table * const table,
350 const void *key, uint32_t * const chunk_id, uint32_t * const bin_id)
351 {
352 /* Compute the position of the entry in the hash table */
353 uint32_t h = EFD_HASH(key, table);
354
355 /* Compute the chunk_id where that entry can be found */
356 *chunk_id = efd_get_chunk_id(table, h);
357
358 /*
359 * Compute the bin within that chunk where the entry
360 * can be found (0 - 255)
361 */
362 *bin_id = efd_get_bin_id(table, h);
363 }
364
365 /**
366 * Search for a hash function for a group that satisfies all group results
367 */
368 static inline int
efd_search_hash(struct rte_efd_table * const table,const struct efd_offline_group_rules * const off_group,struct efd_online_group_entry * const on_group)369 efd_search_hash(struct rte_efd_table * const table,
370 const struct efd_offline_group_rules * const off_group,
371 struct efd_online_group_entry * const on_group)
372 {
373 efd_hashfunc_t hash_idx;
374 efd_hashfunc_t start_hash_idx[RTE_EFD_VALUE_NUM_BITS];
375 efd_lookuptbl_t start_lookup_table[RTE_EFD_VALUE_NUM_BITS];
376
377 uint32_t i, j, rule_id;
378 uint32_t hash_val_a[EFD_MAX_GROUP_NUM_RULES];
379 uint32_t hash_val_b[EFD_MAX_GROUP_NUM_RULES];
380 uint32_t hash_val[EFD_MAX_GROUP_NUM_RULES];
381
382
383 rte_prefetch0(off_group->value);
384
385 /*
386 * Prepopulate the hash_val tables by running the two hash functions
387 * for each provided rule
388 */
389 for (i = 0; i < off_group->num_rules; i++) {
390 void *key_stored = EFD_KEY(off_group->key_idx[i], table);
391 hash_val_b[i] = EFD_HASHFUNCB(key_stored, table);
392 hash_val_a[i] = EFD_HASHFUNCA(key_stored, table);
393 }
394
395 for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
396 hash_idx = on_group->hash_idx[i];
397 start_hash_idx[i] = hash_idx;
398 start_lookup_table[i] = on_group->lookup_table[i];
399
400 do {
401 efd_lookuptbl_t lookup_table = 0;
402 efd_lookuptbl_t lookup_table_complement = 0;
403
404 for (rule_id = 0; rule_id < off_group->num_rules; rule_id++)
405 hash_val[rule_id] = hash_val_a[rule_id] + (hash_idx *
406 hash_val_b[rule_id]);
407
408 /*
409 * The goal here is to find a hash function for this
410 * particular bit entry that meets the following criteria:
411 * The most significant bits of the hash result define a
412 * shift into the lookup table where the bit will be stored
413 */
414
415 /* Iterate over each provided rule */
416 for (rule_id = 0; rule_id < off_group->num_rules;
417 rule_id++) {
418 /*
419 * Use the few most significant bits (number based on
420 * EFD_LOOKUPTBL_SIZE) to see what position the
421 * expected bit should be set in the lookup_table
422 */
423 uint32_t bucket_idx = hash_val[rule_id] >>
424 EFD_LOOKUPTBL_SHIFT;
425
426 /*
427 * Get the current bit of interest.
428 * This only find an appropriate hash function
429 * for one bit at a time of the rule
430 */
431 efd_lookuptbl_t expected =
432 (off_group->value[rule_id] >> i) & 0x1;
433
434 /*
435 * Add the expected bit (if set) to a map
436 * (lookup_table). Also set its complement
437 * in lookup_table_complement
438 */
439 lookup_table |= expected << bucket_idx;
440 lookup_table_complement |= (1 - expected)
441 << bucket_idx;
442
443 /*
444 * If ever the hash function of two different
445 * elements result in different values at the
446 * same location in the lookup_table,
447 * the current hash_idx is not valid.
448 */
449 if (lookup_table & lookup_table_complement)
450 break;
451 }
452
453 /*
454 * Check if the previous loop completed without
455 * breaking early
456 */
457 if (rule_id == off_group->num_rules) {
458 /*
459 * Current hash function worked, store it
460 * for the current group
461 */
462 on_group->hash_idx[i] = hash_idx;
463 on_group->lookup_table[i] = lookup_table;
464
465 /*
466 * Make sure that the hash function has changed
467 * from the starting value
468 */
469 hash_idx = start_hash_idx[i] + 1;
470 break;
471 }
472 hash_idx++;
473
474 } while (hash_idx != start_hash_idx[i]);
475
476 /* Failed to find perfect hash for this group */
477 if (hash_idx == start_hash_idx[i]) {
478 /*
479 * Restore previous hash_idx and lookup_table
480 * for all value bits
481 */
482 for (j = 0; j < i; j++) {
483 on_group->hash_idx[j] = start_hash_idx[j];
484 on_group->lookup_table[j] = start_lookup_table[j];
485 }
486 return 1;
487 }
488 }
489
490 return 0;
491 }
492
493 struct rte_efd_table *
rte_efd_create(const char * name,uint32_t max_num_rules,uint32_t key_len,uint64_t online_cpu_socket_bitmask,uint8_t offline_cpu_socket)494 rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len,
495 uint64_t online_cpu_socket_bitmask, uint8_t offline_cpu_socket)
496 {
497 struct rte_efd_table *table = NULL;
498 uint8_t *key_array = NULL;
499 uint32_t num_chunks, num_chunks_shift;
500 uint8_t socket_id;
501 struct rte_efd_list *efd_list = NULL;
502 struct rte_tailq_entry *te;
503 uint64_t offline_table_size;
504 char ring_name[RTE_RING_NAMESIZE];
505 struct rte_ring *r = NULL;
506 unsigned int i;
507
508 efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
509
510 if (online_cpu_socket_bitmask == 0) {
511 RTE_LOG(ERR, EFD, "At least one CPU socket must be enabled "
512 "in the bitmask\n");
513 return NULL;
514 }
515
516 if (max_num_rules == 0) {
517 RTE_LOG(ERR, EFD, "Max num rules must be higher than 0\n");
518 return NULL;
519 }
520
521 /*
522 * Compute the minimum number of chunks (smallest power of 2)
523 * that can hold all of the rules
524 */
525 if (max_num_rules % EFD_TARGET_CHUNK_NUM_RULES == 0)
526 num_chunks = rte_align32pow2(max_num_rules /
527 EFD_TARGET_CHUNK_NUM_RULES);
528 else
529 num_chunks = rte_align32pow2((max_num_rules /
530 EFD_TARGET_CHUNK_NUM_RULES) + 1);
531
532 num_chunks_shift = rte_bsf32(num_chunks);
533
534 rte_mcfg_tailq_write_lock();
535
536 /*
537 * Guarantee there's no existing: this is normally already checked
538 * by ring creation above
539 */
540 TAILQ_FOREACH(te, efd_list, next)
541 {
542 table = (struct rte_efd_table *) te->data;
543 if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
544 break;
545 }
546
547 table = NULL;
548 if (te != NULL) {
549 rte_errno = EEXIST;
550 te = NULL;
551 goto error_unlock_exit;
552 }
553
554 te = rte_zmalloc("EFD_TAILQ_ENTRY", sizeof(*te), 0);
555 if (te == NULL) {
556 RTE_LOG(ERR, EFD, "tailq entry allocation failed\n");
557 goto error_unlock_exit;
558 }
559
560 /* Create a new EFD table management structure */
561 table = rte_zmalloc_socket(NULL,
562 sizeof(struct rte_efd_table),
563 RTE_CACHE_LINE_SIZE,
564 offline_cpu_socket);
565 if (table == NULL) {
566 RTE_LOG(ERR, EFD, "Allocating EFD table management structure"
567 " on socket %u failed\n",
568 offline_cpu_socket);
569 goto error_unlock_exit;
570 }
571
572
573 RTE_LOG(DEBUG, EFD, "Allocated EFD table management structure "
574 "on socket %u\n", offline_cpu_socket);
575
576 table->max_num_rules = num_chunks * EFD_TARGET_CHUNK_MAX_NUM_RULES;
577 table->num_rules = 0;
578 table->num_chunks = num_chunks;
579 table->num_chunks_shift = num_chunks_shift;
580 table->key_len = key_len;
581
582 /* key_array */
583 key_array = rte_zmalloc_socket(NULL,
584 table->max_num_rules * table->key_len,
585 RTE_CACHE_LINE_SIZE,
586 offline_cpu_socket);
587 if (key_array == NULL) {
588 RTE_LOG(ERR, EFD, "Allocating key array"
589 " on socket %u failed\n",
590 offline_cpu_socket);
591 goto error_unlock_exit;
592 }
593 table->keys = key_array;
594 strlcpy(table->name, name, sizeof(table->name));
595
596 RTE_LOG(DEBUG, EFD, "Creating an EFD table with %u chunks,"
597 " which potentially supports %u entries\n",
598 num_chunks, table->max_num_rules);
599
600 /* Make sure all the allocatable table pointers are NULL initially */
601 for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
602 table->chunks[socket_id] = NULL;
603 table->offline_chunks = NULL;
604
605 /*
606 * Allocate one online table per socket specified
607 * in the user-supplied bitmask
608 */
609 uint64_t online_table_size = num_chunks * sizeof(struct efd_online_chunk) +
610 EFD_NUM_CHUNK_PADDING_BYTES;
611
612 for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) {
613 if ((online_cpu_socket_bitmask >> socket_id) & 0x01) {
614 /*
615 * Allocate all of the EFD table chunks (the online portion)
616 * as a continuous block
617 */
618 table->chunks[socket_id] =
619 rte_zmalloc_socket(
620 NULL,
621 online_table_size,
622 RTE_CACHE_LINE_SIZE,
623 socket_id);
624 if (table->chunks[socket_id] == NULL) {
625 RTE_LOG(ERR, EFD,
626 "Allocating EFD online table on "
627 "socket %u failed\n",
628 socket_id);
629 goto error_unlock_exit;
630 }
631 RTE_LOG(DEBUG, EFD,
632 "Allocated EFD online table of size "
633 "%"PRIu64" bytes (%.2f MB) on socket %u\n",
634 online_table_size,
635 (float) online_table_size /
636 (1024.0F * 1024.0F),
637 socket_id);
638 }
639 }
640
641 #if defined(RTE_ARCH_X86)
642 /*
643 * For less than 4 bits, scalar function performs better
644 * than vectorised version
645 */
646 if (RTE_EFD_VALUE_NUM_BITS > 3
647 && rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2)
648 && rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256)
649 table->lookup_fn = EFD_LOOKUP_AVX2;
650 else
651 #endif
652 #if defined(RTE_ARCH_ARM64)
653 /*
654 * For less than or equal to 16 bits, scalar function performs better
655 * than vectorised version
656 */
657 if (RTE_EFD_VALUE_NUM_BITS > 16 &&
658 rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON) &&
659 rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
660 table->lookup_fn = EFD_LOOKUP_NEON;
661 else
662 #endif
663 table->lookup_fn = EFD_LOOKUP_SCALAR;
664
665 /*
666 * Allocate the EFD table offline portion (with the actual rules
667 * mapping keys to values) as a continuous block.
668 * This could be several gigabytes of memory.
669 */
670 offline_table_size = num_chunks * sizeof(struct efd_offline_chunk_rules);
671 table->offline_chunks =
672 rte_zmalloc_socket(NULL,
673 offline_table_size,
674 RTE_CACHE_LINE_SIZE,
675 offline_cpu_socket);
676 if (table->offline_chunks == NULL) {
677 RTE_LOG(ERR, EFD, "Allocating EFD offline table on socket %u "
678 "failed\n", offline_cpu_socket);
679 goto error_unlock_exit;
680 }
681
682 RTE_LOG(DEBUG, EFD,
683 "Allocated EFD offline table of size %"PRIu64" bytes "
684 " (%.2f MB) on socket %u\n", offline_table_size,
685 (float) offline_table_size / (1024.0F * 1024.0F),
686 offline_cpu_socket);
687
688 te->data = (void *) table;
689 TAILQ_INSERT_TAIL(efd_list, te, next);
690 rte_mcfg_tailq_write_unlock();
691
692 snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name);
693 /* Create ring (Dummy slot index is not enqueued) */
694 r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules),
695 offline_cpu_socket, 0);
696 if (r == NULL) {
697 RTE_LOG(ERR, EFD, "memory allocation failed\n");
698 rte_efd_free(table);
699 return NULL;
700 }
701
702 /* Populate free slots ring. Entry zero is reserved for key misses. */
703 for (i = 0; i < table->max_num_rules; i++)
704 rte_ring_sp_enqueue(r, (void *) ((uintptr_t) i));
705
706 table->free_slots = r;
707 return table;
708
709 error_unlock_exit:
710 rte_mcfg_tailq_write_unlock();
711 rte_free(te);
712 rte_efd_free(table);
713
714 return NULL;
715 }
716
717 struct rte_efd_table *
rte_efd_find_existing(const char * name)718 rte_efd_find_existing(const char *name)
719 {
720 struct rte_efd_table *table = NULL;
721 struct rte_tailq_entry *te;
722 struct rte_efd_list *efd_list;
723
724 efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
725
726 rte_mcfg_tailq_read_lock();
727
728 TAILQ_FOREACH(te, efd_list, next)
729 {
730 table = (struct rte_efd_table *) te->data;
731 if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
732 break;
733 }
734 rte_mcfg_tailq_read_unlock();
735
736 if (te == NULL) {
737 rte_errno = ENOENT;
738 return NULL;
739 }
740 return table;
741 }
742
743 void
rte_efd_free(struct rte_efd_table * table)744 rte_efd_free(struct rte_efd_table *table)
745 {
746 uint8_t socket_id;
747 struct rte_efd_list *efd_list;
748 struct rte_tailq_entry *te, *temp;
749
750 if (table == NULL)
751 return;
752
753 for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
754 rte_free(table->chunks[socket_id]);
755
756 efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
757 rte_mcfg_tailq_write_lock();
758
759 RTE_TAILQ_FOREACH_SAFE(te, efd_list, next, temp) {
760 if (te->data == (void *) table) {
761 TAILQ_REMOVE(efd_list, te, next);
762 rte_free(te);
763 break;
764 }
765 }
766
767 rte_mcfg_tailq_write_unlock();
768 rte_ring_free(table->free_slots);
769 rte_free(table->offline_chunks);
770 rte_free(table->keys);
771 rte_free(table);
772 }
773
774 /**
775 * Applies a previously computed table entry to the specified table for all
776 * socket-local copies of the online table.
777 * Intended to apply an update for only a single change
778 * to a key/value pair at a time
779 *
780 * @param table
781 * EFD table to reference
782 * @param socket_id
783 * Socket ID to use to lookup existing values (ideally caller's socket id)
784 * @param chunk_id
785 * Chunk index to update
786 * @param group_id
787 * Group index to update
788 * @param bin_id
789 * Bin within the group that this update affects
790 * @param new_bin_choice
791 * Newly chosen permutation which this bin should use - only lower 2 bits
792 * @param new_group_entry
793 * Previously computed updated chunk/group entry
794 */
795 static inline void
efd_apply_update(struct rte_efd_table * const table,const unsigned int socket_id,const uint32_t chunk_id,const uint32_t group_id,const uint32_t bin_id,const uint8_t new_bin_choice,const struct efd_online_group_entry * const new_group_entry)796 efd_apply_update(struct rte_efd_table * const table, const unsigned int socket_id,
797 const uint32_t chunk_id, const uint32_t group_id,
798 const uint32_t bin_id, const uint8_t new_bin_choice,
799 const struct efd_online_group_entry * const new_group_entry)
800 {
801 int i;
802 struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
803 uint8_t bin_index = bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
804
805 /*
806 * Grab the current byte that contains the choices
807 * for four neighboring bins
808 */
809 uint8_t choice_chunk =
810 chunk->bin_choice_list[bin_index];
811
812
813 /* Compute the offset into the chunk that needs to be updated */
814 int offset = (bin_id & 0x3) * 2;
815
816 /* Zero the two bits of interest and set them to new_bin_choice */
817 choice_chunk = (choice_chunk & (~(0x03 << offset)))
818 | ((new_bin_choice & 0x03) << offset);
819
820 /* Update the online table with the new data across all sockets */
821 for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
822 if (table->chunks[i] != NULL) {
823 memcpy(&(table->chunks[i][chunk_id].groups[group_id]),
824 new_group_entry,
825 sizeof(struct efd_online_group_entry));
826 table->chunks[i][chunk_id].bin_choice_list[bin_index] =
827 choice_chunk;
828 }
829 }
830 }
831
832 /*
833 * Move the bin from prev group to the new group
834 */
835 static inline void
move_groups(uint32_t bin_id,uint8_t bin_size,struct efd_offline_group_rules * new_group,struct efd_offline_group_rules * const current_group)836 move_groups(uint32_t bin_id, uint8_t bin_size,
837 struct efd_offline_group_rules *new_group,
838 struct efd_offline_group_rules * const current_group)
839 {
840
841 uint8_t empty_idx = 0;
842 unsigned int i;
843
844 if (new_group == current_group)
845 return;
846
847 for (i = 0; i < current_group->num_rules; i++) {
848 /*
849 * Move keys that belong to the same bin
850 * to the new group
851 */
852 if (current_group->bin_id[i] == bin_id) {
853 new_group->key_idx[new_group->num_rules] =
854 current_group->key_idx[i];
855 new_group->value[new_group->num_rules] =
856 current_group->value[i];
857 new_group->bin_id[new_group->num_rules] =
858 current_group->bin_id[i];
859 new_group->num_rules++;
860 } else {
861 if (i != empty_idx) {
862 /*
863 * Need to move this key towards
864 * the top of the array
865 */
866 current_group->key_idx[empty_idx] =
867 current_group->key_idx[i];
868 current_group->value[empty_idx] =
869 current_group->value[i];
870 current_group->bin_id[empty_idx] =
871 current_group->bin_id[i];
872 }
873 empty_idx++;
874 }
875
876 }
877 current_group->num_rules -= bin_size;
878 }
879
880 /*
881 * Revert group/s to their previous state before
882 * trying to insert/add a new key
883 */
884 static inline void
revert_groups(struct efd_offline_group_rules * previous_group,struct efd_offline_group_rules * current_group,uint8_t bin_size)885 revert_groups(struct efd_offline_group_rules *previous_group,
886 struct efd_offline_group_rules *current_group, uint8_t bin_size)
887 {
888 unsigned int i;
889
890 if (current_group == previous_group)
891 return;
892
893 /* Move keys back to previous group */
894 for (i = current_group->num_rules - bin_size;
895 i < current_group->num_rules; i++) {
896 previous_group->key_idx[previous_group->num_rules] =
897 current_group->key_idx[i];
898 previous_group->value[previous_group->num_rules] =
899 current_group->value[i];
900 previous_group->bin_id[previous_group->num_rules] =
901 current_group->bin_id[i];
902 previous_group->num_rules++;
903 }
904
905 /*
906 * Decrease number of rules after the move
907 * in the new group
908 */
909 current_group->num_rules -= bin_size;
910 }
911
912 /**
913 * Computes an updated table entry where the supplied key points to a new host.
914 * If no entry exists, one is inserted.
915 *
916 * This function does NOT modify the online table(s)
917 * This function DOES modify the offline table
918 *
919 * @param table
920 * EFD table to reference
921 * @param socket_id
922 * Socket ID to use to lookup existing values (ideally caller's socket id)
923 * @param key
924 * Key to insert
925 * @param value
926 * Value to associate with key
927 * @param chunk_id
928 * Chunk ID of the chunk that was modified
929 * @param group_id
930 * Group ID of the group that was modified
931 * @param bin_id
932 * Bin ID that was modified
933 * @param new_bin_choice
934 * Newly chosen permutation which this bin will use
935 * @param entry
936 * Newly computed online entry to apply later with efd_apply_update
937 *
938 * @return
939 * RTE_EFD_UPDATE_WARN_GROUP_FULL
940 * Operation is insert, and the last available space in the
941 * key's group was just used. Future inserts may fail as groups fill up.
942 * This operation was still successful, and entry contains a valid update
943 * RTE_EFD_UPDATE_FAILED
944 * Either the EFD failed to find a suitable perfect hash or the group was full
945 * This is a fatal error, and the table is now in an indeterminate state
946 * RTE_EFD_UPDATE_NO_CHANGE
947 * Operation resulted in no change to the table (same value already exists)
948 * 0
949 * Insert or update was successful, and the new efd_online_group_entry
950 * is stored in *entry
951 *
952 * @warning
953 * Note that entry will be UNCHANGED if the update has no effect, and thus any
954 * subsequent use of the entry content will likely be invalid
955 */
956 static inline int
efd_compute_update(struct rte_efd_table * const table,const unsigned int socket_id,const void * key,const efd_value_t value,uint32_t * const chunk_id,uint32_t * const group_id,uint32_t * const bin_id,uint8_t * const new_bin_choice,struct efd_online_group_entry * const entry)957 efd_compute_update(struct rte_efd_table * const table,
958 const unsigned int socket_id, const void *key,
959 const efd_value_t value, uint32_t * const chunk_id,
960 uint32_t * const group_id, uint32_t * const bin_id,
961 uint8_t * const new_bin_choice,
962 struct efd_online_group_entry * const entry)
963 {
964 unsigned int i;
965 int ret;
966 uint32_t new_idx;
967 void *new_k, *slot_id = NULL;
968 int status = EXIT_SUCCESS;
969 unsigned int found = 0;
970
971 efd_compute_ids(table, key, chunk_id, bin_id);
972
973 struct efd_offline_chunk_rules * const chunk =
974 &table->offline_chunks[*chunk_id];
975 struct efd_offline_group_rules *new_group;
976
977 uint8_t current_choice = efd_get_choice(table, socket_id,
978 *chunk_id, *bin_id);
979 uint32_t current_group_id = efd_bin_to_group[current_choice][*bin_id];
980 struct efd_offline_group_rules * const current_group =
981 &chunk->group_rules[current_group_id];
982 uint8_t bin_size = 0;
983 uint8_t key_changed_index = 0;
984 efd_value_t key_changed_previous_value = 0;
985 uint32_t key_idx_previous = 0;
986
987 /* Scan the current group and see if the key is already present */
988 for (i = 0; i < current_group->num_rules; i++) {
989 if (current_group->bin_id[i] == *bin_id)
990 bin_size++;
991 else
992 continue;
993
994 void *key_stored = EFD_KEY(current_group->key_idx[i], table);
995 if (found == 0 && unlikely(memcmp(key_stored, key,
996 table->key_len) == 0)) {
997 /* Key is already present */
998
999 /*
1000 * If previous value is same as new value,
1001 * no additional work is required
1002 */
1003 if (current_group->value[i] == value)
1004 return RTE_EFD_UPDATE_NO_CHANGE;
1005
1006 key_idx_previous = current_group->key_idx[i];
1007 key_changed_previous_value = current_group->value[i];
1008 key_changed_index = i;
1009 current_group->value[i] = value;
1010 found = 1;
1011 }
1012 }
1013
1014 if (found == 0) {
1015 /* Key does not exist. Insert the rule into the bin/group */
1016 if (unlikely(current_group->num_rules >= EFD_MAX_GROUP_NUM_RULES)) {
1017 RTE_LOG(ERR, EFD,
1018 "Fatal: No room remaining for insert into "
1019 "chunk %u group %u bin %u\n",
1020 *chunk_id,
1021 current_group_id, *bin_id);
1022 return RTE_EFD_UPDATE_FAILED;
1023 }
1024
1025 if (unlikely(current_group->num_rules ==
1026 (EFD_MAX_GROUP_NUM_RULES - 1))) {
1027 RTE_LOG(INFO, EFD, "Warn: Insert into last "
1028 "available slot in chunk %u "
1029 "group %u bin %u\n", *chunk_id,
1030 current_group_id, *bin_id);
1031 status = RTE_EFD_UPDATE_WARN_GROUP_FULL;
1032 }
1033
1034 if (rte_ring_sc_dequeue(table->free_slots, &slot_id) != 0)
1035 return RTE_EFD_UPDATE_FAILED;
1036
1037 new_k = RTE_PTR_ADD(table->keys, (uintptr_t) slot_id *
1038 table->key_len);
1039 rte_prefetch0(new_k);
1040 new_idx = (uint32_t) ((uintptr_t) slot_id);
1041
1042 rte_memcpy(EFD_KEY(new_idx, table), key, table->key_len);
1043 current_group->key_idx[current_group->num_rules] = new_idx;
1044 current_group->value[current_group->num_rules] = value;
1045 current_group->bin_id[current_group->num_rules] = *bin_id;
1046 current_group->num_rules++;
1047 table->num_rules++;
1048 bin_size++;
1049 } else {
1050 uint32_t last = current_group->num_rules - 1;
1051 /* Swap the key with the last key inserted*/
1052 current_group->key_idx[key_changed_index] =
1053 current_group->key_idx[last];
1054 current_group->value[key_changed_index] =
1055 current_group->value[last];
1056 current_group->bin_id[key_changed_index] =
1057 current_group->bin_id[last];
1058
1059 /*
1060 * Key to be updated will always be available
1061 * at the end of the group
1062 */
1063 current_group->key_idx[last] = key_idx_previous;
1064 current_group->value[last] = value;
1065 current_group->bin_id[last] = *bin_id;
1066 }
1067
1068 *new_bin_choice = current_choice;
1069 *group_id = current_group_id;
1070 new_group = current_group;
1071
1072 /* Group need to be rebalanced when it starts to get loaded */
1073 if (current_group->num_rules > EFD_MIN_BALANCED_NUM_RULES) {
1074
1075 /*
1076 * Subtract the number of entries in the bin from
1077 * the original group
1078 */
1079 current_group->num_rules -= bin_size;
1080
1081 /*
1082 * Figure out which of the available groups that this bin
1083 * can map to is the smallest (using the current group
1084 * as baseline)
1085 */
1086 uint8_t smallest_choice = current_choice;
1087 uint8_t smallest_size = current_group->num_rules;
1088 uint32_t smallest_group_id = current_group_id;
1089 unsigned char choice;
1090
1091 for (choice = 0; choice < EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
1092 choice++) {
1093 uint32_t test_group_id =
1094 efd_bin_to_group[choice][*bin_id];
1095 uint32_t num_rules =
1096 chunk->group_rules[test_group_id].num_rules;
1097 if (num_rules < smallest_size) {
1098 smallest_choice = choice;
1099 smallest_size = num_rules;
1100 smallest_group_id = test_group_id;
1101 }
1102 }
1103
1104 *new_bin_choice = smallest_choice;
1105 *group_id = smallest_group_id;
1106 new_group = &chunk->group_rules[smallest_group_id];
1107 current_group->num_rules += bin_size;
1108
1109 }
1110
1111 uint8_t choice = 0;
1112 for (;;) {
1113 if (current_group != new_group &&
1114 new_group->num_rules + bin_size >
1115 EFD_MAX_GROUP_NUM_RULES) {
1116 RTE_LOG(DEBUG, EFD,
1117 "Unable to move_groups to dest group "
1118 "containing %u entries."
1119 "bin_size:%u choice:%02x\n",
1120 new_group->num_rules, bin_size,
1121 choice - 1);
1122 goto next_choice;
1123 }
1124 move_groups(*bin_id, bin_size, new_group, current_group);
1125 /*
1126 * Recompute the hash function for the modified group,
1127 * and return it to the caller
1128 */
1129 ret = efd_search_hash(table, new_group, entry);
1130
1131 if (!ret)
1132 return status;
1133
1134 RTE_LOG(DEBUG, EFD,
1135 "Failed to find perfect hash for group "
1136 "containing %u entries. bin_size:%u choice:%02x\n",
1137 new_group->num_rules, bin_size, choice - 1);
1138 /* Restore groups modified to their previous state */
1139 revert_groups(current_group, new_group, bin_size);
1140
1141 next_choice:
1142 if (choice == EFD_CHUNK_NUM_BIN_TO_GROUP_SETS)
1143 break;
1144 *new_bin_choice = choice;
1145 *group_id = efd_bin_to_group[choice][*bin_id];
1146 new_group = &chunk->group_rules[*group_id];
1147 choice++;
1148 }
1149
1150 if (!found) {
1151 current_group->num_rules--;
1152 table->num_rules--;
1153 } else
1154 current_group->value[current_group->num_rules - 1] =
1155 key_changed_previous_value;
1156 return RTE_EFD_UPDATE_FAILED;
1157 }
1158
1159 int
rte_efd_update(struct rte_efd_table * const table,const unsigned int socket_id,const void * key,const efd_value_t value)1160 rte_efd_update(struct rte_efd_table * const table, const unsigned int socket_id,
1161 const void *key, const efd_value_t value)
1162 {
1163 uint32_t chunk_id = 0, group_id = 0, bin_id = 0;
1164 uint8_t new_bin_choice = 0;
1165 struct efd_online_group_entry entry = {{0}};
1166
1167 int status = efd_compute_update(table, socket_id, key, value,
1168 &chunk_id, &group_id, &bin_id,
1169 &new_bin_choice, &entry);
1170
1171 if (status == RTE_EFD_UPDATE_NO_CHANGE)
1172 return EXIT_SUCCESS;
1173
1174 if (status == RTE_EFD_UPDATE_FAILED)
1175 return status;
1176
1177 efd_apply_update(table, socket_id, chunk_id, group_id, bin_id,
1178 new_bin_choice, &entry);
1179 return status;
1180 }
1181
1182 int
rte_efd_delete(struct rte_efd_table * const table,const unsigned int socket_id,const void * key,efd_value_t * const prev_value)1183 rte_efd_delete(struct rte_efd_table * const table, const unsigned int socket_id,
1184 const void *key, efd_value_t * const prev_value)
1185 {
1186 unsigned int i;
1187 uint32_t chunk_id, bin_id;
1188 uint8_t not_found = 1;
1189
1190 efd_compute_ids(table, key, &chunk_id, &bin_id);
1191
1192 struct efd_offline_chunk_rules * const chunk =
1193 &table->offline_chunks[chunk_id];
1194
1195 uint8_t current_choice = efd_get_choice(table, socket_id,
1196 chunk_id, bin_id);
1197 uint32_t current_group_id = efd_bin_to_group[current_choice][bin_id];
1198 struct efd_offline_group_rules * const current_group =
1199 &chunk->group_rules[current_group_id];
1200
1201 /*
1202 * Search the current group for the specified key.
1203 * If it exists, remove it and re-pack the other values
1204 */
1205 for (i = 0; i < current_group->num_rules; i++) {
1206 if (not_found) {
1207 /* Found key that needs to be removed */
1208 if (memcmp(EFD_KEY(current_group->key_idx[i], table),
1209 key, table->key_len) == 0) {
1210 /* Store previous value if requested by caller */
1211 if (prev_value != NULL)
1212 *prev_value = current_group->value[i];
1213
1214 not_found = 0;
1215 rte_ring_sp_enqueue(table->free_slots,
1216 (void *)((uintptr_t)current_group->key_idx[i]));
1217 }
1218 } else {
1219 /*
1220 * If the desired key has been found,
1221 * need to shift other values up one
1222 */
1223
1224 /* Need to shift this entry back up one index */
1225 current_group->key_idx[i - 1] = current_group->key_idx[i];
1226 current_group->value[i - 1] = current_group->value[i];
1227 current_group->bin_id[i - 1] = current_group->bin_id[i];
1228 }
1229 }
1230
1231 if (not_found == 0) {
1232 table->num_rules--;
1233 current_group->num_rules--;
1234 }
1235
1236 return not_found;
1237 }
1238
1239 static inline efd_value_t
efd_lookup_internal_scalar(const efd_hashfunc_t * group_hash_idx,const efd_lookuptbl_t * group_lookup_table,const uint32_t hash_val_a,const uint32_t hash_val_b)1240 efd_lookup_internal_scalar(const efd_hashfunc_t *group_hash_idx,
1241 const efd_lookuptbl_t *group_lookup_table,
1242 const uint32_t hash_val_a, const uint32_t hash_val_b)
1243 {
1244 efd_value_t value = 0;
1245 uint32_t i;
1246
1247 for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
1248 value <<= 1;
1249 uint32_t h = hash_val_a + (hash_val_b *
1250 group_hash_idx[RTE_EFD_VALUE_NUM_BITS - i - 1]);
1251 uint16_t bucket_idx = h >> EFD_LOOKUPTBL_SHIFT;
1252 value |= (group_lookup_table[
1253 RTE_EFD_VALUE_NUM_BITS - i - 1] >>
1254 bucket_idx) & 0x1;
1255 }
1256
1257 return value;
1258 }
1259
1260
1261 static inline efd_value_t
efd_lookup_internal(const struct efd_online_group_entry * const group,const uint32_t hash_val_a,const uint32_t hash_val_b,enum efd_lookup_internal_function lookup_fn)1262 efd_lookup_internal(const struct efd_online_group_entry * const group,
1263 const uint32_t hash_val_a, const uint32_t hash_val_b,
1264 enum efd_lookup_internal_function lookup_fn)
1265 {
1266 efd_value_t value = 0;
1267
1268 switch (lookup_fn) {
1269
1270 #if defined(RTE_ARCH_X86) && defined(CC_SUPPORT_AVX2)
1271 case EFD_LOOKUP_AVX2:
1272 return efd_lookup_internal_avx2(group->hash_idx,
1273 group->lookup_table,
1274 hash_val_a,
1275 hash_val_b);
1276 break;
1277 #endif
1278 #if defined(RTE_ARCH_ARM64)
1279 case EFD_LOOKUP_NEON:
1280 return efd_lookup_internal_neon(group->hash_idx,
1281 group->lookup_table,
1282 hash_val_a,
1283 hash_val_b);
1284 break;
1285 #endif
1286 case EFD_LOOKUP_SCALAR:
1287 /* Fall-through */
1288 default:
1289 return efd_lookup_internal_scalar(group->hash_idx,
1290 group->lookup_table,
1291 hash_val_a,
1292 hash_val_b);
1293 }
1294
1295 return value;
1296 }
1297
1298 efd_value_t
rte_efd_lookup(const struct rte_efd_table * const table,const unsigned int socket_id,const void * key)1299 rte_efd_lookup(const struct rte_efd_table * const table,
1300 const unsigned int socket_id, const void *key)
1301 {
1302 uint32_t chunk_id, group_id, bin_id;
1303 uint8_t bin_choice;
1304 const struct efd_online_group_entry *group;
1305 const struct efd_online_chunk * const chunks = table->chunks[socket_id];
1306
1307 /* Determine the chunk and group location for the given key */
1308 efd_compute_ids(table, key, &chunk_id, &bin_id);
1309 bin_choice = efd_get_choice(table, socket_id, chunk_id, bin_id);
1310 group_id = efd_bin_to_group[bin_choice][bin_id];
1311 group = &chunks[chunk_id].groups[group_id];
1312
1313 return efd_lookup_internal(group,
1314 EFD_HASHFUNCA(key, table),
1315 EFD_HASHFUNCB(key, table),
1316 table->lookup_fn);
1317 }
1318
rte_efd_lookup_bulk(const struct rte_efd_table * const table,const unsigned int socket_id,const int num_keys,const void ** key_list,efd_value_t * const value_list)1319 void rte_efd_lookup_bulk(const struct rte_efd_table * const table,
1320 const unsigned int socket_id, const int num_keys,
1321 const void **key_list, efd_value_t * const value_list)
1322 {
1323 int i;
1324 uint32_t chunk_id_list[RTE_EFD_BURST_MAX];
1325 uint32_t bin_id_list[RTE_EFD_BURST_MAX];
1326 uint8_t bin_choice_list[RTE_EFD_BURST_MAX];
1327 uint32_t group_id_list[RTE_EFD_BURST_MAX];
1328 struct efd_online_group_entry *group;
1329
1330 struct efd_online_chunk *chunks = table->chunks[socket_id];
1331
1332 for (i = 0; i < num_keys; i++) {
1333 efd_compute_ids(table, key_list[i], &chunk_id_list[i],
1334 &bin_id_list[i]);
1335 rte_prefetch0(&chunks[chunk_id_list[i]].bin_choice_list);
1336 }
1337
1338 for (i = 0; i < num_keys; i++) {
1339 bin_choice_list[i] = efd_get_choice(table, socket_id,
1340 chunk_id_list[i], bin_id_list[i]);
1341 group_id_list[i] =
1342 efd_bin_to_group[bin_choice_list[i]][bin_id_list[i]];
1343 group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
1344 rte_prefetch0(group);
1345 }
1346
1347 for (i = 0; i < num_keys; i++) {
1348 group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
1349 value_list[i] = efd_lookup_internal(group,
1350 EFD_HASHFUNCA(key_list[i], table),
1351 EFD_HASHFUNCB(key_list[i], table),
1352 table->lookup_fn);
1353 }
1354 }
1355