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