Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2015 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <stdint.h>
7 : : #include <string.h>
8 : : #include <stdlib.h>
9 : : #include <stdarg.h>
10 : : #include <errno.h>
11 : : #include <sys/queue.h>
12 : :
13 : : #include <rte_common.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_cycles.h>
16 : : #include <rte_random.h>
17 : : #include <rte_memory.h>
18 : : #include <rte_eal.h>
19 : : #include <rte_ip.h>
20 : : #include <rte_string_fns.h>
21 : :
22 : : #include "test.h"
23 : :
24 : : #include <rte_hash.h>
25 : : #include <rte_fbk_hash.h>
26 : : #include <rte_jhash.h>
27 : : #include <rte_hash_crc.h>
28 : :
29 : : /*******************************************************************************
30 : : * Hash function performance test configuration section. Each performance test
31 : : * will be performed HASHTEST_ITERATIONS times.
32 : : *
33 : : * The five arrays below control what tests are performed. Every combination
34 : : * from the array entries is tested.
35 : : */
36 : : static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc};
37 : : static uint32_t hashtest_initvals[] = {0};
38 : :
39 : : /*
40 : : * Test common hash key lengths. Make sure and cover all the special cases
41 : : * in the cmp_jump_table.
42 : : */
43 : : static uint32_t hashtest_key_lens[] = {
44 : : 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18, 20,
45 : : 21, 31, 32, 33, 36, 48, 63, 64, 80, 96, 112, 128, 254
46 : : };
47 : : #define MAX_KEYSIZE 256
48 : : /******************************************************************************/
49 : : #define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15)
50 : :
51 : : /*
52 : : * Check condition and return an error if true. Assumes that "handle" is the
53 : : * name of the hash structure pointer to be freed.
54 : : */
55 : : #define RETURN_IF_ERROR(cond, str, ...) do { \
56 : : if (cond) { \
57 : : printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
58 : : if (handle) rte_hash_free(handle); \
59 : : return -1; \
60 : : } \
61 : : } while(0)
62 : :
63 : : #define RETURN_IF_ERROR_FBK(cond, str, ...) do { \
64 : : if (cond) { \
65 : : printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
66 : : if (handle) rte_fbk_hash_free(handle); \
67 : : return -1; \
68 : : } \
69 : : } while(0)
70 : :
71 : : #define RETURN_IF_ERROR_RCU_QSBR(cond, str, ...) do { \
72 : : if (cond) { \
73 : : printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
74 : : if (rcu_cfg.mode == RTE_HASH_QSBR_MODE_SYNC) { \
75 : : writer_done = 1; \
76 : : /* Wait until reader exited. */ \
77 : : rte_eal_mp_wait_lcore(); \
78 : : } \
79 : : rte_hash_free(g_handle); \
80 : : rte_free(g_qsv); \
81 : : return -1; \
82 : : } \
83 : : } while (0)
84 : :
85 : : /*
86 : : * 5-tuple key type.
87 : : * Should be packed to avoid holes with potentially
88 : : * undefined content in the middle.
89 : : */
90 : : struct __rte_packed_begin flow_key {
91 : : uint32_t ip_src;
92 : : uint32_t ip_dst;
93 : : uint16_t port_src;
94 : : uint16_t port_dst;
95 : : uint32_t proto;
96 : : } __rte_packed_end;
97 : :
98 : : /*
99 : : * Hash function that always returns the same value, to easily test what
100 : : * happens when a bucket is full.
101 : : */
102 : 1051540 : static uint32_t pseudo_hash(__rte_unused const void *keys,
103 : : __rte_unused uint32_t key_len,
104 : : __rte_unused uint32_t init_val)
105 : : {
106 : 1051540 : return 3 | (3 << 16);
107 : : }
108 : :
109 [ - + ]: 301 : RTE_LOG_REGISTER(hash_logtype_test, test.hash, INFO);
110 : :
111 : : /*
112 : : * Print out result of unit test hash operation.
113 : : */
114 : 27080 : static void print_key_info(const char *msg, const struct flow_key *key,
115 : : int32_t pos)
116 : : {
117 : : const uint8_t *p = (const uint8_t *)key;
118 : : unsigned int i;
119 : :
120 : 27080 : rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%s key:0x", msg);
121 [ + + ]: 460360 : for (i = 0; i < sizeof(struct flow_key); i++)
122 : 433280 : rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%02X", p[i]);
123 : 27080 : rte_log(RTE_LOG_DEBUG, hash_logtype_test, " @ pos %d\n", pos);
124 : 27080 : }
125 : :
126 : : #define KEY_PER_BUCKET 8
127 : :
128 : : /* Keys used by unit test functions */
129 : : static struct flow_key keys[KEY_PER_BUCKET+1] = { {
130 : : .ip_src = RTE_IPV4(0x03, 0x02, 0x01, 0x00),
131 : : .ip_dst = RTE_IPV4(0x07, 0x06, 0x05, 0x04),
132 : : .port_src = 0x0908,
133 : : .port_dst = 0x0b0a,
134 : : .proto = 0x0c,
135 : : }, {
136 : : .ip_src = RTE_IPV4(0x13, 0x12, 0x11, 0x10),
137 : : .ip_dst = RTE_IPV4(0x17, 0x16, 0x15, 0x14),
138 : : .port_src = 0x1918,
139 : : .port_dst = 0x1b1a,
140 : : .proto = 0x1c,
141 : : }, {
142 : : .ip_src = RTE_IPV4(0x23, 0x22, 0x21, 0x20),
143 : : .ip_dst = RTE_IPV4(0x27, 0x26, 0x25, 0x24),
144 : : .port_src = 0x2928,
145 : : .port_dst = 0x2b2a,
146 : : .proto = 0x2c,
147 : : }, {
148 : : .ip_src = RTE_IPV4(0x33, 0x32, 0x31, 0x30),
149 : : .ip_dst = RTE_IPV4(0x37, 0x36, 0x35, 0x34),
150 : : .port_src = 0x3938,
151 : : .port_dst = 0x3b3a,
152 : : .proto = 0x3c,
153 : : }, {
154 : : .ip_src = RTE_IPV4(0x43, 0x42, 0x41, 0x40),
155 : : .ip_dst = RTE_IPV4(0x47, 0x46, 0x45, 0x44),
156 : : .port_src = 0x4948,
157 : : .port_dst = 0x4b4a,
158 : : .proto = 0x4c,
159 : : }, {
160 : : .ip_src = RTE_IPV4(0x53, 0x52, 0x51, 0x50),
161 : : .ip_dst = RTE_IPV4(0x57, 0x56, 0x55, 0x54),
162 : : .port_src = 0x5958,
163 : : .port_dst = 0x5b5a,
164 : : .proto = 0x5c,
165 : : }, {
166 : : .ip_src = RTE_IPV4(0x63, 0x62, 0x61, 0x60),
167 : : .ip_dst = RTE_IPV4(0x67, 0x66, 0x65, 0x64),
168 : : .port_src = 0x6968,
169 : : .port_dst = 0x6b6a,
170 : : .proto = 0x6c,
171 : : }, {
172 : : .ip_src = RTE_IPV4(0x73, 0x72, 0x71, 0x70),
173 : : .ip_dst = RTE_IPV4(0x77, 0x76, 0x75, 0x74),
174 : : .port_src = 0x7978,
175 : : .port_dst = 0x7b7a,
176 : : .proto = 0x7c,
177 : : }, {
178 : : .ip_src = RTE_IPV4(0x83, 0x82, 0x81, 0x80),
179 : : .ip_dst = RTE_IPV4(0x87, 0x86, 0x85, 0x84),
180 : : .port_src = 0x8988,
181 : : .port_dst = 0x8b8a,
182 : : .proto = 0x8c,
183 : : } };
184 : :
185 : : /* Parameters used for hash table in unit test functions. Name set later. */
186 : : static struct rte_hash_parameters ut_params = {
187 : : .entries = 64,
188 : : .key_len = sizeof(struct flow_key),
189 : : .hash_func = rte_jhash,
190 : : .hash_func_init_val = 0,
191 : : .socket_id = 0,
192 : : };
193 : :
194 : : #define CRC32_ITERATIONS (1U << 10)
195 : : #define CRC32_DWORDS (1U << 6)
196 : : /*
197 : : * Test if all CRC32 implementations yield the same hash value
198 : : */
199 : : static int
200 : 1 : test_crc32_hash_alg_equiv(void)
201 : : {
202 : : uint32_t hash_val;
203 : : uint32_t init_val;
204 : : uint64_t data64[CRC32_DWORDS];
205 : : unsigned i, j;
206 : : size_t data_len;
207 : :
208 : : printf("\n# CRC32 implementations equivalence test\n");
209 [ + + ]: 1025 : for (i = 0; i < CRC32_ITERATIONS; i++) {
210 : : /* Randomizing data_len of data set */
211 : 1024 : data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
212 : 1024 : init_val = (uint32_t) rte_rand();
213 : :
214 : : /* Fill the data set */
215 [ + + ]: 66560 : for (j = 0; j < CRC32_DWORDS; j++)
216 : 65536 : data64[j] = rte_rand();
217 : :
218 : : /* Calculate software CRC32 */
219 : 1024 : rte_hash_crc_set_alg(CRC32_SW);
220 : 1024 : hash_val = rte_hash_crc(data64, data_len, init_val);
221 : :
222 : : /* Check against 4-byte-operand sse4.2 CRC32 if available */
223 : 1024 : rte_hash_crc_set_alg(CRC32_SSE42);
224 [ - + ]: 1024 : if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
225 : : printf("Failed checking CRC32_SW against CRC32_SSE42\n");
226 : : break;
227 : : }
228 : :
229 : : /* Check against 8-byte-operand sse4.2 CRC32 if available */
230 : 1024 : rte_hash_crc_set_alg(CRC32_SSE42_x64);
231 [ - + ]: 1024 : if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
232 : : printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n");
233 : : break;
234 : : }
235 : :
236 : : /* Check against 8-byte-operand ARM64 CRC32 if available */
237 : 1024 : rte_hash_crc_set_alg(CRC32_ARM64);
238 [ - + ]: 1024 : if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
239 : : printf("Failed checking CRC32_SW against CRC32_ARM64\n");
240 : : break;
241 : : }
242 : : }
243 : :
244 : : /* Resetting to best available algorithm */
245 : 1 : rte_hash_crc_set_alg(CRC32_SSE42_x64);
246 : :
247 [ - + ]: 1 : if (i == CRC32_ITERATIONS)
248 : : return 0;
249 : :
250 : : printf("Failed test data (hex, %zu bytes total):\n", data_len);
251 [ # # ]: 0 : for (j = 0; j < data_len; j++)
252 : 0 : printf("%02X%c", ((uint8_t *)data64)[j],
253 [ # # # # ]: 0 : ((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' ');
254 : :
255 : : return -1;
256 : : }
257 : :
258 : : /*
259 : : * Test a hash function.
260 : : */
261 : 60 : static void run_hash_func_test(rte_hash_function f, uint32_t init_val,
262 : : uint32_t key_len)
263 : : {
264 : : static uint8_t key[MAX_KEYSIZE];
265 : : unsigned i;
266 : :
267 : :
268 [ + + ]: 2360 : for (i = 0; i < key_len; i++)
269 : 2300 : key[i] = (uint8_t) rte_rand();
270 : :
271 : : /* just to be on the safe side */
272 [ + - ]: 60 : if (!f)
273 : : return;
274 : :
275 : 60 : f(key, key_len, init_val);
276 : : }
277 : :
278 : : /*
279 : : * Test all hash functions.
280 : : */
281 : 1 : static void run_hash_func_tests(void)
282 : : {
283 : : unsigned i, j, k;
284 : :
285 [ + + ]: 3 : for (i = 0; i < RTE_DIM(hashtest_funcs); i++) {
286 [ + + ]: 4 : for (j = 0; j < RTE_DIM(hashtest_initvals); j++) {
287 [ + + ]: 62 : for (k = 0; k < RTE_DIM(hashtest_key_lens); k++) {
288 : 60 : run_hash_func_test(hashtest_funcs[i],
289 : : hashtest_initvals[j],
290 : : hashtest_key_lens[k]);
291 : : }
292 : : }
293 : : }
294 : 1 : }
295 : :
296 : : /*
297 : : * Basic sequence of operations for a single key:
298 : : * - add
299 : : * - lookup (hit)
300 : : * - delete
301 : : * - lookup (miss)
302 : : *
303 : : * Repeat the test case when 'free on delete' is disabled.
304 : : * - add
305 : : * - lookup (hit)
306 : : * - delete
307 : : * - lookup (miss)
308 : : * - free
309 : : */
310 : 1 : static int test_add_delete(void)
311 : : {
312 : : struct rte_hash *handle;
313 : : /* test with standard add/lookup/delete functions */
314 : : int pos0, expectedPos0;
315 : :
316 : 1 : ut_params.name = "test1";
317 : 1 : handle = rte_hash_create(&ut_params);
318 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
319 : :
320 : 1 : pos0 = rte_hash_add_key(handle, &keys[0]);
321 : 1 : print_key_info("Add", &keys[0], pos0);
322 [ - + ]: 1 : RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
323 : : expectedPos0 = pos0;
324 : :
325 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
326 : 1 : print_key_info("Lkp", &keys[0], pos0);
327 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
328 : : "failed to find key (pos0=%d)", pos0);
329 : :
330 : 1 : pos0 = rte_hash_del_key(handle, &keys[0]);
331 : 1 : print_key_info("Del", &keys[0], pos0);
332 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
333 : : "failed to delete key (pos0=%d)", pos0);
334 : :
335 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
336 : 1 : print_key_info("Lkp", &keys[0], pos0);
337 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != -ENOENT,
338 : : "fail: found key after deleting! (pos0=%d)", pos0);
339 : :
340 : 1 : rte_hash_free(handle);
341 : :
342 : : /* repeat test with precomputed hash functions */
343 : : hash_sig_t hash_value;
344 : : int pos1, expectedPos1, delPos1;
345 : :
346 : 1 : ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
347 : 1 : handle = rte_hash_create(&ut_params);
348 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
349 : 1 : ut_params.extra_flag = 0;
350 : :
351 : 1 : hash_value = rte_hash_hash(handle, &keys[0]);
352 : 1 : pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
353 : 1 : print_key_info("Add", &keys[0], pos1);
354 [ - + ]: 1 : RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
355 : : expectedPos1 = pos1;
356 : :
357 : 1 : pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
358 : 1 : print_key_info("Lkp", &keys[0], pos1);
359 [ - + ]: 1 : RETURN_IF_ERROR(pos1 != expectedPos1,
360 : : "failed to find key (pos1=%d)", pos1);
361 : :
362 : 1 : pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
363 : 1 : print_key_info("Del", &keys[0], pos1);
364 [ - + ]: 1 : RETURN_IF_ERROR(pos1 != expectedPos1,
365 : : "failed to delete key (pos1=%d)", pos1);
366 : : delPos1 = pos1;
367 : :
368 : 1 : pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
369 : 1 : print_key_info("Lkp", &keys[0], pos1);
370 [ - + ]: 1 : RETURN_IF_ERROR(pos1 != -ENOENT,
371 : : "fail: found key after deleting! (pos1=%d)", pos1);
372 : :
373 : 1 : pos1 = rte_hash_free_key_with_position(handle, delPos1);
374 : 1 : print_key_info("Free", &keys[0], delPos1);
375 [ - + ]: 1 : RETURN_IF_ERROR(pos1 != 0,
376 : : "failed to free key (pos1=%d)", delPos1);
377 : :
378 : 1 : rte_hash_free(handle);
379 : :
380 : 1 : return 0;
381 : : }
382 : :
383 : : /*
384 : : * Sequence of operations for a single key:
385 : : * - delete: miss
386 : : * - add
387 : : * - lookup: hit
388 : : * - add: update
389 : : * - lookup: hit (updated data)
390 : : * - delete: hit
391 : : * - delete: miss
392 : : * - lookup: miss
393 : : */
394 : 1 : static int test_add_update_delete(void)
395 : : {
396 : : struct rte_hash *handle;
397 : : int pos0, expectedPos0;
398 : :
399 : 1 : ut_params.name = "test2";
400 : 1 : handle = rte_hash_create(&ut_params);
401 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
402 : :
403 : 1 : pos0 = rte_hash_del_key(handle, &keys[0]);
404 : 1 : print_key_info("Del", &keys[0], pos0);
405 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != -ENOENT,
406 : : "fail: found non-existent key (pos0=%d)", pos0);
407 : :
408 : 1 : pos0 = rte_hash_add_key(handle, &keys[0]);
409 : 1 : print_key_info("Add", &keys[0], pos0);
410 [ - + ]: 1 : RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
411 : : expectedPos0 = pos0;
412 : :
413 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
414 : 1 : print_key_info("Lkp", &keys[0], pos0);
415 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
416 : : "failed to find key (pos0=%d)", pos0);
417 : :
418 : 1 : pos0 = rte_hash_add_key(handle, &keys[0]);
419 : 1 : print_key_info("Add", &keys[0], pos0);
420 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
421 : : "failed to re-add key (pos0=%d)", pos0);
422 : :
423 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
424 : 1 : print_key_info("Lkp", &keys[0], pos0);
425 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
426 : : "failed to find key (pos0=%d)", pos0);
427 : :
428 : 1 : pos0 = rte_hash_del_key(handle, &keys[0]);
429 : 1 : print_key_info("Del", &keys[0], pos0);
430 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
431 : : "failed to delete key (pos0=%d)", pos0);
432 : :
433 : 1 : pos0 = rte_hash_del_key(handle, &keys[0]);
434 : 1 : print_key_info("Del", &keys[0], pos0);
435 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != -ENOENT,
436 : : "fail: deleted already deleted key (pos0=%d)", pos0);
437 : :
438 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
439 : 1 : print_key_info("Lkp", &keys[0], pos0);
440 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != -ENOENT,
441 : : "fail: found key after deleting! (pos0=%d)", pos0);
442 : :
443 : 1 : rte_hash_free(handle);
444 : 1 : return 0;
445 : : }
446 : :
447 : : /*
448 : : * Sequence of operations for a single key with 'disable free on del' set:
449 : : * - delete: miss
450 : : * - add
451 : : * - lookup: hit
452 : : * - add: update
453 : : * - lookup: hit (updated data)
454 : : * - delete: hit
455 : : * - delete: miss
456 : : * - lookup: miss
457 : : * - free: hit
458 : : * - lookup: miss
459 : : */
460 : 1 : static int test_add_update_delete_free(void)
461 : : {
462 : : struct rte_hash *handle;
463 : : int pos0, expectedPos0, delPos0, result;
464 : :
465 : 1 : ut_params.name = "test2";
466 : 1 : ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
467 : 1 : handle = rte_hash_create(&ut_params);
468 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
469 : 1 : ut_params.extra_flag = 0;
470 : :
471 : 1 : pos0 = rte_hash_del_key(handle, &keys[0]);
472 : 1 : print_key_info("Del", &keys[0], pos0);
473 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != -ENOENT,
474 : : "fail: found non-existent key (pos0=%d)", pos0);
475 : :
476 : 1 : pos0 = rte_hash_add_key(handle, &keys[0]);
477 : 1 : print_key_info("Add", &keys[0], pos0);
478 [ - + ]: 1 : RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
479 : : expectedPos0 = pos0;
480 : :
481 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
482 : 1 : print_key_info("Lkp", &keys[0], pos0);
483 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
484 : : "failed to find key (pos0=%d)", pos0);
485 : :
486 : 1 : pos0 = rte_hash_add_key(handle, &keys[0]);
487 : 1 : print_key_info("Add", &keys[0], pos0);
488 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
489 : : "failed to re-add key (pos0=%d)", pos0);
490 : :
491 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
492 : 1 : print_key_info("Lkp", &keys[0], pos0);
493 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != expectedPos0,
494 : : "failed to find key (pos0=%d)", pos0);
495 : :
496 : 1 : delPos0 = rte_hash_del_key(handle, &keys[0]);
497 : 1 : print_key_info("Del", &keys[0], delPos0);
498 [ - + ]: 1 : RETURN_IF_ERROR(delPos0 != expectedPos0,
499 : : "failed to delete key (pos0=%d)", delPos0);
500 : :
501 : 1 : pos0 = rte_hash_del_key(handle, &keys[0]);
502 : 1 : print_key_info("Del", &keys[0], pos0);
503 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != -ENOENT,
504 : : "fail: deleted already deleted key (pos0=%d)", pos0);
505 : :
506 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
507 : 1 : print_key_info("Lkp", &keys[0], pos0);
508 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != -ENOENT,
509 : : "fail: found key after deleting! (pos0=%d)", pos0);
510 : :
511 : 1 : result = rte_hash_free_key_with_position(handle, delPos0);
512 : 1 : print_key_info("Free", &keys[0], delPos0);
513 [ - + ]: 1 : RETURN_IF_ERROR(result != 0,
514 : : "failed to free key (pos1=%d)", delPos0);
515 : :
516 : 1 : pos0 = rte_hash_lookup(handle, &keys[0]);
517 : 1 : print_key_info("Lkp", &keys[0], pos0);
518 [ - + ]: 1 : RETURN_IF_ERROR(pos0 != -ENOENT,
519 : : "fail: found key after deleting! (pos0=%d)", pos0);
520 : :
521 : 1 : rte_hash_free(handle);
522 : 1 : return 0;
523 : : }
524 : :
525 : : /*
526 : : * Sequence of operations for a single key with 'rw concurrency lock free' set:
527 : : * - add
528 : : * - delete: hit
529 : : * - free: hit
530 : : * Repeat the test case when 'multi writer add' is enabled.
531 : : * - add
532 : : * - delete: hit
533 : : * - free: hit
534 : : */
535 : 1 : static int test_add_delete_free_lf(void)
536 : : {
537 : : /* Should match the #define LCORE_CACHE_SIZE value in rte_cuckoo_hash.h */
538 : : #define LCORE_CACHE_SIZE 64
539 : : struct rte_hash *handle;
540 : : hash_sig_t hash_value;
541 : : int pos, expectedPos, delPos;
542 : : uint8_t extra_flag;
543 : : uint32_t i, ip_src;
544 : :
545 : 1 : extra_flag = ut_params.extra_flag;
546 : 1 : ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
547 : 1 : handle = rte_hash_create(&ut_params);
548 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
549 : 1 : ut_params.extra_flag = extra_flag;
550 : :
551 : : /*
552 : : * The number of iterations is at least the same as the number of slots
553 : : * rte_hash allocates internally. This is to reveal potential issues of
554 : : * not freeing keys successfully.
555 : : */
556 [ + + ]: 66 : for (i = 0; i < ut_params.entries + 1; i++) {
557 : 65 : hash_value = rte_hash_hash(handle, &keys[0]);
558 : 65 : pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
559 : 65 : print_key_info("Add", &keys[0], pos);
560 [ - + ]: 65 : RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
561 : : expectedPos = pos;
562 : :
563 : 65 : pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
564 : 65 : print_key_info("Del", &keys[0], pos);
565 [ - + ]: 65 : RETURN_IF_ERROR(pos != expectedPos,
566 : : "failed to delete key (pos=%d)", pos);
567 : : delPos = pos;
568 : :
569 : 65 : pos = rte_hash_free_key_with_position(handle, delPos);
570 : 65 : print_key_info("Free", &keys[0], delPos);
571 [ - + ]: 65 : RETURN_IF_ERROR(pos != 0,
572 : : "failed to free key (pos=%d)", delPos);
573 : : }
574 : :
575 : 1 : rte_hash_free(handle);
576 : :
577 : 1 : extra_flag = ut_params.extra_flag;
578 : 1 : ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
579 : : RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
580 : 1 : handle = rte_hash_create(&ut_params);
581 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
582 : 1 : ut_params.extra_flag = extra_flag;
583 : :
584 : 1 : ip_src = keys[0].ip_src;
585 : : /*
586 : : * The number of iterations is at least the same as the number of slots
587 : : * rte_hash allocates internally. This is to reveal potential issues of
588 : : * not freeing keys successfully.
589 : : */
590 : 1 : for (i = 0; i < ut_params.entries + (RTE_MAX_LCORE - 1) *
591 [ + + ]: 8067 : (LCORE_CACHE_SIZE - 1) + 1; i++) {
592 : 8066 : keys[0].ip_src++;
593 : 8066 : hash_value = rte_hash_hash(handle, &keys[0]);
594 : 8066 : pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
595 : 8066 : print_key_info("Add", &keys[0], pos);
596 [ - + ]: 8066 : RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
597 : : expectedPos = pos;
598 : :
599 : 8066 : pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
600 : 8066 : print_key_info("Del", &keys[0], pos);
601 [ - + ]: 8066 : RETURN_IF_ERROR(pos != expectedPos,
602 : : "failed to delete key (pos=%d)", pos);
603 : : delPos = pos;
604 : :
605 : 8066 : pos = rte_hash_free_key_with_position(handle, delPos);
606 : 8066 : print_key_info("Free", &keys[0], delPos);
607 [ - + ]: 8066 : RETURN_IF_ERROR(pos != 0,
608 : : "failed to free key (pos=%d)", delPos);
609 : : }
610 : 1 : keys[0].ip_src = ip_src;
611 : :
612 : 1 : rte_hash_free(handle);
613 : :
614 : 1 : return 0;
615 : : }
616 : :
617 : : /*
618 : : * Sequence of operations for retrieving a key with its position
619 : : *
620 : : * - create table
621 : : * - add key
622 : : * - get the key with its position: hit
623 : : * - delete key
624 : : * - try to get the deleted key: miss
625 : : *
626 : : * Repeat the test case when 'free on delete' is disabled.
627 : : * - create table
628 : : * - add key
629 : : * - get the key with its position: hit
630 : : * - delete key
631 : : * - try to get the deleted key: hit
632 : : * - free key
633 : : * - try to get the deleted key: miss
634 : : *
635 : : */
636 : 1 : static int test_hash_get_key_with_position(void)
637 : : {
638 : : struct rte_hash *handle = NULL;
639 : : int pos, expectedPos, delPos, result;
640 : : void *key;
641 : :
642 : 1 : ut_params.name = "hash_get_key_w_pos";
643 : 1 : handle = rte_hash_create(&ut_params);
644 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
645 : :
646 : 1 : pos = rte_hash_add_key(handle, &keys[0]);
647 : 1 : print_key_info("Add", &keys[0], pos);
648 [ - + ]: 1 : RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
649 : : expectedPos = pos;
650 : :
651 : 1 : result = rte_hash_get_key_with_position(handle, pos, &key);
652 [ - + ]: 1 : RETURN_IF_ERROR(result != 0, "error retrieving a key");
653 : :
654 : 1 : pos = rte_hash_del_key(handle, &keys[0]);
655 : 1 : print_key_info("Del", &keys[0], pos);
656 [ - + ]: 1 : RETURN_IF_ERROR(pos != expectedPos,
657 : : "failed to delete key (pos0=%d)", pos);
658 : :
659 : 1 : result = rte_hash_get_key_with_position(handle, pos, &key);
660 [ - + ]: 1 : RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
661 : :
662 : 1 : rte_hash_free(handle);
663 : :
664 : 1 : ut_params.name = "hash_get_key_w_pos";
665 : 1 : ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
666 : 1 : handle = rte_hash_create(&ut_params);
667 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
668 : 1 : ut_params.extra_flag = 0;
669 : :
670 : 1 : pos = rte_hash_add_key(handle, &keys[0]);
671 : 1 : print_key_info("Add", &keys[0], pos);
672 [ - + ]: 1 : RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
673 : : expectedPos = pos;
674 : :
675 : 1 : result = rte_hash_get_key_with_position(handle, pos, &key);
676 [ - + ]: 1 : RETURN_IF_ERROR(result != 0, "error retrieving a key");
677 : :
678 : 1 : delPos = rte_hash_del_key(handle, &keys[0]);
679 : 1 : print_key_info("Del", &keys[0], delPos);
680 [ - + ]: 1 : RETURN_IF_ERROR(delPos != expectedPos,
681 : : "failed to delete key (pos0=%d)", delPos);
682 : :
683 : 1 : result = rte_hash_get_key_with_position(handle, delPos, &key);
684 [ - + ]: 1 : RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
685 : :
686 : 1 : result = rte_hash_free_key_with_position(handle, delPos);
687 : 1 : print_key_info("Free", &keys[0], delPos);
688 [ - + ]: 1 : RETURN_IF_ERROR(result != 0,
689 : : "failed to free key (pos1=%d)", delPos);
690 : :
691 : 1 : result = rte_hash_get_key_with_position(handle, delPos, &key);
692 [ - + ]: 1 : RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
693 : :
694 : 1 : rte_hash_free(handle);
695 : 1 : return 0;
696 : : }
697 : :
698 : : /*
699 : : * Sequence of operations for find existing hash table
700 : : *
701 : : * - create table
702 : : * - find existing table: hit
703 : : * - find non-existing table: miss
704 : : *
705 : : */
706 : 1 : static int test_hash_find_existing(void)
707 : : {
708 : : struct rte_hash *handle = NULL, *result = NULL;
709 : :
710 : : /* Create hash table. */
711 : 1 : ut_params.name = "hash_find_existing";
712 : 1 : handle = rte_hash_create(&ut_params);
713 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
714 : :
715 : : /* Try to find existing hash table */
716 : 1 : result = rte_hash_find_existing("hash_find_existing");
717 [ - + ]: 1 : RETURN_IF_ERROR(result != handle, "could not find existing hash table");
718 : :
719 : : /* Try to find non-existing hash table */
720 : 1 : result = rte_hash_find_existing("hash_find_non_existing");
721 [ - + ]: 1 : RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
722 : :
723 : : /* Cleanup. */
724 : 1 : rte_hash_free(handle);
725 : :
726 : 1 : return 0;
727 : : }
728 : :
729 : : /*
730 : : * Sequence of operations for 5 keys
731 : : * - add keys
732 : : * - lookup keys: hit
733 : : * - add keys (update)
734 : : * - lookup keys: hit (updated data)
735 : : * - delete keys : hit
736 : : * - lookup keys: miss
737 : : */
738 : 1 : static int test_five_keys(void)
739 : : {
740 : : struct rte_hash *handle;
741 : 1 : const void *key_array[5] = {0};
742 : : int pos[5];
743 : : int expected_pos[5];
744 : : unsigned i;
745 : : int ret;
746 : :
747 : 1 : ut_params.name = "test3";
748 : 1 : handle = rte_hash_create(&ut_params);
749 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
750 : :
751 : : /* Add */
752 [ + + ]: 6 : for (i = 0; i < 5; i++) {
753 : 5 : pos[i] = rte_hash_add_key(handle, &keys[i]);
754 : 5 : print_key_info("Add", &keys[i], pos[i]);
755 [ - + ]: 5 : RETURN_IF_ERROR(pos[i] < 0,
756 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
757 : 5 : expected_pos[i] = pos[i];
758 : : }
759 : :
760 : : /* Lookup */
761 [ + + ]: 6 : for(i = 0; i < 5; i++)
762 : 5 : key_array[i] = &keys[i];
763 : :
764 : 1 : ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
765 [ + - ]: 1 : if(ret == 0)
766 [ + + ]: 6 : for(i = 0; i < 5; i++) {
767 : 5 : print_key_info("Lkp", key_array[i], pos[i]);
768 [ - + ]: 5 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
769 : : "failed to find key (pos[%u]=%d)", i, pos[i]);
770 : : }
771 : :
772 : : /* Add - update */
773 [ + + ]: 6 : for (i = 0; i < 5; i++) {
774 : 5 : pos[i] = rte_hash_add_key(handle, &keys[i]);
775 : 5 : print_key_info("Add", &keys[i], pos[i]);
776 [ - + ]: 5 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
777 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
778 : : }
779 : :
780 : : /* Lookup */
781 [ + + ]: 6 : for (i = 0; i < 5; i++) {
782 : 5 : pos[i] = rte_hash_lookup(handle, &keys[i]);
783 : 5 : print_key_info("Lkp", &keys[i], pos[i]);
784 [ - + ]: 5 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
785 : : "failed to find key (pos[%u]=%d)", i, pos[i]);
786 : : }
787 : :
788 : : /* Delete */
789 [ + + ]: 6 : for (i = 0; i < 5; i++) {
790 : 5 : pos[i] = rte_hash_del_key(handle, &keys[i]);
791 : 5 : print_key_info("Del", &keys[i], pos[i]);
792 [ - + ]: 5 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
793 : : "failed to delete key (pos[%u]=%d)", i, pos[i]);
794 : : }
795 : :
796 : : /* Lookup */
797 [ + + ]: 6 : for (i = 0; i < 5; i++) {
798 : 5 : pos[i] = rte_hash_lookup(handle, &keys[i]);
799 : 5 : print_key_info("Lkp", &keys[i], pos[i]);
800 [ - + ]: 5 : RETURN_IF_ERROR(pos[i] != -ENOENT,
801 : : "found non-existent key (pos[%u]=%d)", i, pos[i]);
802 : : }
803 : :
804 : : /* Lookup multi */
805 : 1 : ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
806 [ + - ]: 1 : if (ret == 0)
807 [ + + ]: 6 : for (i = 0; i < 5; i++) {
808 : 5 : print_key_info("Lkp", key_array[i], pos[i]);
809 [ - + ]: 5 : RETURN_IF_ERROR(pos[i] != -ENOENT,
810 : : "found not-existent key (pos[%u]=%d)", i, pos[i]);
811 : : }
812 : :
813 : 1 : rte_hash_free(handle);
814 : :
815 : 1 : return 0;
816 : : }
817 : :
818 : : /*
819 : : * Add keys to the same bucket until bucket full.
820 : : * - add 9 keys to the same bucket (hash created with 8 keys per bucket):
821 : : * first 8 successful, 9th successful, pushing existing item in bucket
822 : : * - lookup the 9 keys: 9 hits
823 : : * - bulk lookup for all the 9 keys: 9 hits
824 : : * - add the 9 keys again: 9 OK
825 : : * - lookup the 9 keys: 9 hits (updated data)
826 : : * - delete the 9 keys: 9 OK
827 : : * - lookup the 9 keys: 9 misses
828 : : * - bulk lookup for all the 9 keys: 9 misses
829 : : */
830 : 1 : static int test_full_bucket(void)
831 : : {
832 : 1 : struct rte_hash_parameters params_pseudo_hash = {
833 : : .name = "test4",
834 : : .entries = 64,
835 : : .key_len = sizeof(struct flow_key),
836 : : .hash_func = pseudo_hash,
837 : : .hash_func_init_val = 0,
838 : : .socket_id = 0,
839 : : };
840 : 1 : const void *key_array[KEY_PER_BUCKET+1] = {0};
841 : : struct rte_hash *handle;
842 : : int pos[KEY_PER_BUCKET+1];
843 : : int expected_pos[KEY_PER_BUCKET+1];
844 : : unsigned i;
845 : : int ret;
846 : 1 : handle = rte_hash_create(¶ms_pseudo_hash);
847 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
848 : :
849 : : /* Fill bucket */
850 [ + + ]: 9 : for (i = 0; i < KEY_PER_BUCKET; i++) {
851 : 8 : pos[i] = rte_hash_add_key(handle, &keys[i]);
852 : 8 : print_key_info("Add", &keys[i], pos[i]);
853 [ - + ]: 8 : RETURN_IF_ERROR(pos[i] < 0,
854 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
855 : 8 : expected_pos[i] = pos[i];
856 : : }
857 : : /*
858 : : * This should work and will push one of the items
859 : : * in the bucket because it is full
860 : : */
861 : 1 : pos[KEY_PER_BUCKET] = rte_hash_add_key(handle, &keys[KEY_PER_BUCKET]);
862 : 1 : print_key_info("Add", &keys[KEY_PER_BUCKET], pos[KEY_PER_BUCKET]);
863 [ - + ]: 1 : RETURN_IF_ERROR(pos[KEY_PER_BUCKET] < 0,
864 : : "failed to add key (pos[%d]=%d)", KEY_PER_BUCKET, pos[KEY_PER_BUCKET]);
865 : 1 : expected_pos[KEY_PER_BUCKET] = pos[KEY_PER_BUCKET];
866 : :
867 : : /* Lookup */
868 [ + + ]: 10 : for (i = 0; i < KEY_PER_BUCKET+1; i++) {
869 : 9 : pos[i] = rte_hash_lookup(handle, &keys[i]);
870 : 9 : print_key_info("Lkp", &keys[i], pos[i]);
871 [ - + ]: 9 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
872 : : "failed to find key (pos[%u]=%d)", i, pos[i]);
873 : : }
874 : :
875 [ + + ]: 10 : for (i = 0; i < KEY_PER_BUCKET+1; i++)
876 : 9 : key_array[i] = &keys[i];
877 : :
878 : : /*Bulk lookup after add with same hash*/
879 : 1 : ret = rte_hash_lookup_bulk(handle, key_array, KEY_PER_BUCKET+1, (int32_t *)pos);
880 [ - + ]: 1 : RETURN_IF_ERROR(ret, "rte_hash_lookup_bulk returned an error: %d\n", ret);
881 [ + + ]: 10 : for (i = 0; i < KEY_PER_BUCKET+1; i++) {
882 : 9 : print_key_info("Blk_Lkp", key_array[i], pos[i]);
883 [ - + ]: 9 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
884 : : "failed to find key (pos[%u]=%d)", i, pos[i]);
885 : : }
886 : :
887 : :
888 : :
889 : : /* Add - update */
890 [ + + ]: 10 : for (i = 0; i < KEY_PER_BUCKET+1; i++) {
891 : 9 : pos[i] = rte_hash_add_key(handle, &keys[i]);
892 : 9 : print_key_info("Add", &keys[i], pos[i]);
893 [ - + ]: 9 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
894 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
895 : : }
896 : :
897 : : /* Lookup */
898 [ + + ]: 10 : for (i = 0; i < KEY_PER_BUCKET+1; i++) {
899 : 9 : pos[i] = rte_hash_lookup(handle, &keys[i]);
900 : 9 : print_key_info("Lkp", &keys[i], pos[i]);
901 [ - + ]: 9 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
902 : : "failed to find key (pos[%u]=%d)", i, pos[i]);
903 : : }
904 : :
905 : : /* Delete 1 key, check other keys are still found */
906 : 1 : pos[1] = rte_hash_del_key(handle, &keys[1]);
907 : 1 : print_key_info("Del", &keys[1], pos[1]);
908 [ - + ]: 1 : RETURN_IF_ERROR(pos[1] != expected_pos[1],
909 : : "failed to delete key (pos[1]=%d)", pos[1]);
910 : 1 : pos[3] = rte_hash_lookup(handle, &keys[3]);
911 : 1 : print_key_info("Lkp", &keys[3], pos[3]);
912 [ - + ]: 1 : RETURN_IF_ERROR(pos[3] != expected_pos[3],
913 : : "failed lookup after deleting key from same bucket "
914 : : "(pos[3]=%d)", pos[3]);
915 : :
916 : : /* Go back to previous state */
917 : 1 : pos[1] = rte_hash_add_key(handle, &keys[1]);
918 : 1 : print_key_info("Add", &keys[1], pos[1]);
919 : 1 : expected_pos[1] = pos[1];
920 [ - + ]: 1 : RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]);
921 : :
922 : : /* Delete */
923 [ + + ]: 10 : for (i = 0; i < KEY_PER_BUCKET+1; i++) {
924 : 9 : pos[i] = rte_hash_del_key(handle, &keys[i]);
925 : 9 : print_key_info("Del", &keys[i], pos[i]);
926 [ - + ]: 9 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
927 : : "failed to delete key (pos[%u]=%d)", i, pos[i]);
928 : : }
929 : :
930 : : /* Lookup */
931 [ + + ]: 10 : for (i = 0; i < KEY_PER_BUCKET+1; i++) {
932 : 9 : pos[i] = rte_hash_lookup(handle, &keys[i]);
933 : 9 : print_key_info("Lkp", &keys[i], pos[i]);
934 [ - + ]: 9 : RETURN_IF_ERROR(pos[i] != -ENOENT,
935 : : "fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
936 : : }
937 : :
938 : : /* Bulk Lookup on empty table*/
939 : 1 : ret = rte_hash_lookup_bulk(handle, &key_array[0], KEY_PER_BUCKET+1, (int32_t *)pos);
940 [ - + ]: 1 : RETURN_IF_ERROR(ret, "rte_hash_lookup_bulk returned an error: %d\n", ret);
941 [ + + ]: 10 : for (i = 0; i < KEY_PER_BUCKET+1; i++) {
942 : 9 : print_key_info("Blk_Lkp", key_array[i], pos[i]);
943 [ - + ]: 9 : RETURN_IF_ERROR(pos[i] != -ENOENT,
944 : : "failed to find key (pos[%u]=%d)", i, pos[i]);
945 : : }
946 : :
947 : 1 : rte_hash_free(handle);
948 : :
949 : : /* Cover the NULL case. */
950 : 1 : rte_hash_free(0);
951 : 1 : return 0;
952 : : }
953 : :
954 : : /*
955 : : * Similar to the test above (full bucket test), but for extendable buckets.
956 : : */
957 : 1 : static int test_extendable_bucket(void)
958 : : {
959 : 1 : struct rte_hash_parameters params_pseudo_hash = {
960 : : .name = "test5",
961 : : .entries = 64,
962 : : .key_len = sizeof(struct flow_key),
963 : : .hash_func = pseudo_hash,
964 : : .hash_func_init_val = 0,
965 : : .socket_id = 0,
966 : : .extra_flag = RTE_HASH_EXTRA_FLAGS_EXT_TABLE
967 : : };
968 : : struct rte_hash *handle;
969 : : int pos[64];
970 : : int expected_pos[64];
971 : : unsigned int i;
972 : : struct flow_key rand_keys[64];
973 : :
974 [ + + ]: 65 : for (i = 0; i < 64; i++) {
975 : 64 : rand_keys[i].port_dst = i;
976 : 64 : rand_keys[i].port_src = i+1;
977 : : }
978 : :
979 : 1 : handle = rte_hash_create(¶ms_pseudo_hash);
980 [ - + ]: 1 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
981 : :
982 : : /* Fill bucket */
983 [ + + ]: 65 : for (i = 0; i < 64; i++) {
984 : 64 : pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
985 : 64 : print_key_info("Add", &rand_keys[i], pos[i]);
986 [ - + ]: 64 : RETURN_IF_ERROR(pos[i] < 0,
987 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
988 : 64 : expected_pos[i] = pos[i];
989 : : }
990 : :
991 : : /* Lookup */
992 [ + + ]: 65 : for (i = 0; i < 64; i++) {
993 : 64 : pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
994 : 64 : print_key_info("Lkp", &rand_keys[i], pos[i]);
995 [ - + ]: 64 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
996 : : "failed to find key (pos[%u]=%d)", i, pos[i]);
997 : : }
998 : :
999 : : /* Add - update */
1000 [ + + ]: 65 : for (i = 0; i < 64; i++) {
1001 : 64 : pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
1002 : 64 : print_key_info("Add", &rand_keys[i], pos[i]);
1003 [ - + ]: 64 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
1004 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
1005 : : }
1006 : :
1007 : : /* Lookup */
1008 [ + + ]: 65 : for (i = 0; i < 64; i++) {
1009 : 64 : pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
1010 : 64 : print_key_info("Lkp", &rand_keys[i], pos[i]);
1011 [ - + ]: 64 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
1012 : : "failed to find key (pos[%u]=%d)", i, pos[i]);
1013 : : }
1014 : :
1015 : : /* Delete 1 key, check other keys are still found */
1016 : 1 : pos[35] = rte_hash_del_key(handle, &rand_keys[35]);
1017 : 1 : print_key_info("Del", &rand_keys[35], pos[35]);
1018 [ - + ]: 1 : RETURN_IF_ERROR(pos[35] != expected_pos[35],
1019 : : "failed to delete key (pos[1]=%d)", pos[35]);
1020 : 1 : pos[20] = rte_hash_lookup(handle, &rand_keys[20]);
1021 : 1 : print_key_info("Lkp", &rand_keys[20], pos[20]);
1022 [ - + ]: 1 : RETURN_IF_ERROR(pos[20] != expected_pos[20],
1023 : : "failed lookup after deleting key from same bucket "
1024 : : "(pos[20]=%d)", pos[20]);
1025 : :
1026 : : /* Go back to previous state */
1027 : 1 : pos[35] = rte_hash_add_key(handle, &rand_keys[35]);
1028 : 1 : print_key_info("Add", &rand_keys[35], pos[35]);
1029 : 1 : expected_pos[35] = pos[35];
1030 [ - + ]: 1 : RETURN_IF_ERROR(pos[35] < 0, "failed to add key (pos[1]=%d)", pos[35]);
1031 : :
1032 : : /* Delete */
1033 [ + + ]: 65 : for (i = 0; i < 64; i++) {
1034 : 64 : pos[i] = rte_hash_del_key(handle, &rand_keys[i]);
1035 : 64 : print_key_info("Del", &rand_keys[i], pos[i]);
1036 [ - + ]: 64 : RETURN_IF_ERROR(pos[i] != expected_pos[i],
1037 : : "failed to delete key (pos[%u]=%d)", i, pos[i]);
1038 : : }
1039 : :
1040 : : /* Lookup */
1041 [ + + ]: 65 : for (i = 0; i < 64; i++) {
1042 : 64 : pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
1043 : 64 : print_key_info("Lkp", &rand_keys[i], pos[i]);
1044 [ - + ]: 64 : RETURN_IF_ERROR(pos[i] != -ENOENT,
1045 : : "fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
1046 : : }
1047 : :
1048 : : /* Add again */
1049 [ + + ]: 65 : for (i = 0; i < 64; i++) {
1050 : 64 : pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
1051 : 64 : print_key_info("Add", &rand_keys[i], pos[i]);
1052 [ - + ]: 64 : RETURN_IF_ERROR(pos[i] < 0,
1053 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
1054 : : expected_pos[i] = pos[i];
1055 : : }
1056 : :
1057 : 1 : rte_hash_free(handle);
1058 : :
1059 : : /* Cover the NULL case. */
1060 : 1 : rte_hash_free(0);
1061 : 1 : return 0;
1062 : : }
1063 : :
1064 : : /******************************************************************************/
1065 : : static int
1066 : 1 : fbk_hash_unit_test(void)
1067 : : {
1068 : 1 : struct rte_fbk_hash_params params = {
1069 : : .name = "fbk_hash_test",
1070 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1071 : : .entries_per_bucket = 4,
1072 : : .socket_id = 0,
1073 : : };
1074 : :
1075 : 1 : struct rte_fbk_hash_params invalid_params_1 = {
1076 : : .name = "invalid_1",
1077 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */
1078 : : .entries_per_bucket = 4,
1079 : : .socket_id = 0,
1080 : : };
1081 : :
1082 : 1 : struct rte_fbk_hash_params invalid_params_2 = {
1083 : : .name = "invalid_2",
1084 : : .entries = 4,
1085 : : .entries_per_bucket = 3, /* Not power of 2 */
1086 : : .socket_id = 0,
1087 : : };
1088 : :
1089 : 1 : struct rte_fbk_hash_params invalid_params_3 = {
1090 : : .name = "invalid_3",
1091 : : .entries = 0, /* Entries is 0 */
1092 : : .entries_per_bucket = 4,
1093 : : .socket_id = 0,
1094 : : };
1095 : :
1096 : 1 : struct rte_fbk_hash_params invalid_params_4 = {
1097 : : .name = "invalid_4",
1098 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1099 : : .entries_per_bucket = 0, /* Entries per bucket is 0 */
1100 : : .socket_id = 0,
1101 : : };
1102 : :
1103 : 1 : struct rte_fbk_hash_params invalid_params_5 = {
1104 : : .name = "invalid_5",
1105 : : .entries = 4,
1106 : : .entries_per_bucket = 8, /* Entries per bucket > entries */
1107 : : .socket_id = 0,
1108 : : };
1109 : :
1110 : 1 : struct rte_fbk_hash_params invalid_params_6 = {
1111 : : .name = "invalid_6",
1112 : : .entries = RTE_FBK_HASH_ENTRIES_MAX * 2, /* Entries > max allowed */
1113 : : .entries_per_bucket = 4,
1114 : : .socket_id = 0,
1115 : : };
1116 : :
1117 : 1 : struct rte_fbk_hash_params invalid_params_7 = {
1118 : : .name = "invalid_7",
1119 : : .entries = RTE_FBK_HASH_ENTRIES_MAX,
1120 : : .entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2, /* Entries > max allowed */
1121 : : .socket_id = 0,
1122 : : };
1123 : :
1124 : 1 : struct rte_fbk_hash_params invalid_params_8 = {
1125 : : .name = "invalid_7",
1126 : : .entries = RTE_FBK_HASH_ENTRIES_MAX,
1127 : : .entries_per_bucket = 4,
1128 : : .socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */
1129 : : };
1130 : :
1131 : : /* try and create hash with an excessively long name */
1132 : 1 : struct rte_fbk_hash_params invalid_params_long_name = {
1133 : : .name = "four_byte_key_hash_name_length_32",
1134 : : .entries = 4,
1135 : : .entries_per_bucket = 2,
1136 : : .socket_id = 0,
1137 : : };
1138 : :
1139 : : /* try to create two hashes with identical names
1140 : : * in this case, trying to create a second one will not
1141 : : * fail but will simply return pointer to the existing
1142 : : * hash with that name. sort of like a "find hash by name" :-)
1143 : : */
1144 : 1 : struct rte_fbk_hash_params invalid_params_same_name_1 = {
1145 : : .name = "same_name", /* hash with identical name */
1146 : : .entries = 4,
1147 : : .entries_per_bucket = 2,
1148 : : .socket_id = 0,
1149 : : };
1150 : :
1151 : : /* trying to create this hash should return a pointer to an existing hash */
1152 : 1 : struct rte_fbk_hash_params invalid_params_same_name_2 = {
1153 : : .name = "same_name", /* hash with identical name */
1154 : : .entries = RTE_FBK_HASH_ENTRIES_MAX,
1155 : : .entries_per_bucket = 4,
1156 : : .socket_id = 0,
1157 : : };
1158 : :
1159 : : /* this is a sanity check for "same name" test
1160 : : * creating this hash will check if we are actually able to create
1161 : : * multiple hashes with different names (instead of having just one).
1162 : : */
1163 : 1 : struct rte_fbk_hash_params different_name = {
1164 : : .name = "different_name", /* different name */
1165 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1166 : : .entries_per_bucket = 4,
1167 : : .socket_id = 0,
1168 : : };
1169 : :
1170 : 1 : struct rte_fbk_hash_params params_jhash = {
1171 : : .name = "valid",
1172 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1173 : : .entries_per_bucket = 4,
1174 : : .socket_id = 0,
1175 : : .hash_func = rte_jhash_1word, /* Tests for different hash_func */
1176 : : .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1177 : : };
1178 : :
1179 : 1 : struct rte_fbk_hash_params params_nohash = {
1180 : : .name = "valid nohash",
1181 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1182 : : .entries_per_bucket = 4,
1183 : : .socket_id = 0,
1184 : : .hash_func = NULL, /* Tests for null hash_func */
1185 : : .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1186 : : };
1187 : :
1188 : : struct rte_fbk_hash_table *handle, *tmp;
1189 : 1 : uint32_t keys[5] =
1190 : : {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
1191 : 1 : uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
1192 : : int status;
1193 : : unsigned i;
1194 : : double used_entries;
1195 : :
1196 : : /* Try creating hashes with invalid parameters */
1197 : : printf("# Testing hash creation with invalid parameters "
1198 : : "- expect error msgs\n");
1199 : 1 : handle = rte_fbk_hash_create(&invalid_params_1);
1200 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1201 : :
1202 : 1 : handle = rte_fbk_hash_create(&invalid_params_2);
1203 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1204 : :
1205 : 1 : handle = rte_fbk_hash_create(&invalid_params_3);
1206 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1207 : :
1208 : 1 : handle = rte_fbk_hash_create(&invalid_params_4);
1209 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1210 : :
1211 : 1 : handle = rte_fbk_hash_create(&invalid_params_5);
1212 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1213 : :
1214 : 1 : handle = rte_fbk_hash_create(&invalid_params_6);
1215 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1216 : :
1217 : 1 : handle = rte_fbk_hash_create(&invalid_params_7);
1218 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1219 : :
1220 : 1 : handle = rte_fbk_hash_create(&invalid_params_long_name);
1221 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1222 : :
1223 [ - + ]: 1 : if (rte_eal_has_hugepages()) {
1224 : 0 : handle = rte_fbk_hash_create(&invalid_params_8);
1225 [ # # ]: 0 : RETURN_IF_ERROR_FBK(handle != NULL,
1226 : : "fbk hash creation should have failed");
1227 : : }
1228 : :
1229 : 1 : handle = rte_fbk_hash_create(&invalid_params_same_name_1);
1230 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
1231 : :
1232 : 1 : tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
1233 : 1 : rte_fbk_hash_free(tmp);
1234 [ - + ]: 1 : RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed");
1235 : :
1236 : : /* we are not freeing handle here because we need a hash list
1237 : : * to be not empty for the next test */
1238 : :
1239 : : /* create a hash in non-empty list - good for coverage */
1240 : 1 : tmp = rte_fbk_hash_create(&different_name);
1241 [ - + ]: 1 : RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
1242 : :
1243 : : /* free both hashes */
1244 : 1 : rte_fbk_hash_free(handle);
1245 : 1 : rte_fbk_hash_free(tmp);
1246 : :
1247 : : /* Create empty jhash hash. */
1248 : 1 : handle = rte_fbk_hash_create(¶ms_jhash);
1249 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
1250 : :
1251 : : /* Cleanup. */
1252 : 1 : rte_fbk_hash_free(handle);
1253 : :
1254 : : /* Create empty jhash hash. */
1255 : 1 : handle = rte_fbk_hash_create(¶ms_nohash);
1256 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
1257 : :
1258 : : /* Cleanup. */
1259 : 1 : rte_fbk_hash_free(handle);
1260 : :
1261 : : /* Create empty hash. */
1262 : 1 : handle = rte_fbk_hash_create(¶ms);
1263 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1264 : :
1265 : 1 : used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1266 [ - + ]: 1 : RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1267 : : "load factor right after creation is not zero but it should be");
1268 : : /* Add keys. */
1269 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1270 : 5 : status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1271 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1272 : : }
1273 : :
1274 : 1 : used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1275 [ - + ]: 1 : RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
1276 : : "load factor now is not as expected");
1277 : : /* Find value of added keys. */
1278 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1279 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1280 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != vals[i],
1281 : : "fbk hash lookup failed");
1282 : : }
1283 : :
1284 : : /* Change value of added keys. */
1285 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1286 : 5 : status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
1287 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
1288 : : }
1289 : :
1290 : : /* Find new values. */
1291 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1292 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1293 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != vals[4-i],
1294 : : "fbk hash lookup failed");
1295 : : }
1296 : :
1297 : : /* Delete keys individually. */
1298 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1299 : 5 : status = rte_fbk_hash_delete_key(handle, keys[i]);
1300 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
1301 : : }
1302 : :
1303 : 1 : used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1304 [ - + ]: 1 : RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1305 : : "load factor right after deletion is not zero but it should be");
1306 : : /* Lookup should now fail. */
1307 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1308 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1309 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status == 0,
1310 : : "fbk hash lookup should have failed");
1311 : : }
1312 : :
1313 : : /* Add keys again. */
1314 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1315 : 5 : status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1316 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1317 : : }
1318 : :
1319 : : /* Make sure they were added. */
1320 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1321 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1322 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != vals[i],
1323 : : "fbk hash lookup failed");
1324 : : }
1325 : :
1326 : : /* Clear all entries. */
1327 : : rte_fbk_hash_clear_all(handle);
1328 : :
1329 : : /* Lookup should fail. */
1330 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1331 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1332 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status == 0,
1333 : : "fbk hash lookup should have failed");
1334 : : }
1335 : :
1336 : : /* coverage */
1337 : :
1338 : : /* fill up the hash_table */
1339 [ + + ]: 1048578 : for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
1340 : 1048577 : rte_fbk_hash_add_key(handle, i, (uint16_t) i);
1341 : :
1342 : : /* Find non-existent key in a full hashtable */
1343 : 1 : status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1344 [ - + ]: 1 : RETURN_IF_ERROR_FBK(status != -ENOENT,
1345 : : "fbk hash lookup succeeded");
1346 : :
1347 : : /* Delete non-existent key in a full hashtable */
1348 : 1 : status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1349 [ - + ]: 1 : RETURN_IF_ERROR_FBK(status != -ENOENT,
1350 : : "fbk hash delete succeeded");
1351 : :
1352 : : /* Delete one key from a full hashtable */
1353 : 1 : status = rte_fbk_hash_delete_key(handle, 1);
1354 [ - + ]: 1 : RETURN_IF_ERROR_FBK(status != 0,
1355 : : "fbk hash delete failed");
1356 : :
1357 : : /* Clear all entries. */
1358 : : rte_fbk_hash_clear_all(handle);
1359 : :
1360 : : /* Cleanup. */
1361 : 1 : rte_fbk_hash_free(handle);
1362 : :
1363 : : /* Cover the NULL case. */
1364 : 1 : rte_fbk_hash_free(0);
1365 : :
1366 : 1 : return 0;
1367 : : }
1368 : :
1369 : : /*
1370 : : * Sequence of operations for find existing fbk hash table
1371 : : *
1372 : : * - create table
1373 : : * - find existing table: hit
1374 : : * - find non-existing table: miss
1375 : : *
1376 : : */
1377 : 1 : static int test_fbk_hash_find_existing(void)
1378 : : {
1379 : 1 : struct rte_fbk_hash_params params = {
1380 : : .name = "fbk_hash_find_existing",
1381 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1382 : : .entries_per_bucket = 4,
1383 : : .socket_id = 0,
1384 : : };
1385 : : struct rte_fbk_hash_table *handle = NULL, *result = NULL;
1386 : :
1387 : : /* Create hash table. */
1388 : 1 : handle = rte_fbk_hash_create(¶ms);
1389 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1390 : :
1391 : : /* Try to find existing fbk hash table */
1392 : 1 : result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
1393 [ - + ]: 1 : RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
1394 : :
1395 : : /* Try to find non-existing fbk hash table */
1396 : 1 : result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
1397 [ - + ]: 1 : RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
1398 : :
1399 : : /* Cleanup. */
1400 : 1 : rte_fbk_hash_free(handle);
1401 : :
1402 : 1 : return 0;
1403 : : }
1404 : :
1405 : : #define BUCKET_ENTRIES 4
1406 : : /*
1407 : : * Do tests for hash creation with bad parameters.
1408 : : */
1409 : 1 : static int test_hash_creation_with_bad_parameters(void)
1410 : : {
1411 : : struct rte_hash *handle, *tmp;
1412 : : struct rte_hash_parameters params;
1413 : :
1414 : 1 : handle = rte_hash_create(NULL);
1415 [ - + ]: 1 : if (handle != NULL) {
1416 : 0 : rte_hash_free(handle);
1417 : : printf("Impossible creating hash successfully without any parameter\n");
1418 : 0 : return -1;
1419 : : }
1420 : :
1421 : : memcpy(¶ms, &ut_params, sizeof(params));
1422 : 1 : params.name = "creation_with_bad_parameters_0";
1423 : 1 : params.entries = RTE_HASH_ENTRIES_MAX + 1;
1424 : 1 : handle = rte_hash_create(¶ms);
1425 [ - + ]: 1 : if (handle != NULL) {
1426 : 0 : rte_hash_free(handle);
1427 : : printf("Impossible creating hash successfully with entries in parameter exceeded\n");
1428 : 0 : return -1;
1429 : : }
1430 : :
1431 : : memcpy(¶ms, &ut_params, sizeof(params));
1432 : 1 : params.name = "creation_with_bad_parameters_2";
1433 : 1 : params.entries = BUCKET_ENTRIES - 1;
1434 : 1 : handle = rte_hash_create(¶ms);
1435 [ - + ]: 1 : if (handle != NULL) {
1436 : 0 : rte_hash_free(handle);
1437 : : printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n");
1438 : 0 : return -1;
1439 : : }
1440 : :
1441 : : memcpy(¶ms, &ut_params, sizeof(params));
1442 : 1 : params.name = "creation_with_bad_parameters_3";
1443 : 1 : params.key_len = 0;
1444 : 1 : handle = rte_hash_create(¶ms);
1445 [ - + ]: 1 : if (handle != NULL) {
1446 : 0 : rte_hash_free(handle);
1447 : : printf("Impossible creating hash successfully if key_len in parameter is zero\n");
1448 : 0 : return -1;
1449 : : }
1450 : :
1451 : : memcpy(¶ms, &ut_params, sizeof(params));
1452 : 1 : params.name = "creation_with_bad_parameters_4";
1453 : 1 : params.socket_id = RTE_MAX_NUMA_NODES + 1;
1454 : 1 : handle = rte_hash_create(¶ms);
1455 [ - + ]: 1 : if (handle != NULL) {
1456 : 0 : rte_hash_free(handle);
1457 : : printf("Impossible creating hash successfully with invalid socket\n");
1458 : 0 : return -1;
1459 : : }
1460 : :
1461 : : memcpy(¶ms, &ut_params, sizeof(params));
1462 : 1 : params.name = "hash_creation_with_too_long_name";
1463 : 1 : params.socket_id = SOCKET_ID_ANY;
1464 : 1 : handle = rte_hash_create(¶ms);
1465 [ - + ]: 1 : if (handle != NULL) {
1466 : 0 : rte_hash_free(handle);
1467 : : printf("Impossible creating hash successfully with long name\n");
1468 : 0 : return -1;
1469 : : }
1470 : :
1471 : : /* test with same name should fail */
1472 : : memcpy(¶ms, &ut_params, sizeof(params));
1473 : 1 : params.name = "same_name";
1474 : 1 : handle = rte_hash_create(¶ms);
1475 [ - + ]: 1 : if (handle == NULL) {
1476 : : printf("Cannot create first hash table with 'same_name'\n");
1477 : 0 : return -1;
1478 : : }
1479 : 1 : tmp = rte_hash_create(¶ms);
1480 [ - + ]: 1 : if (tmp != NULL) {
1481 : : printf("Creation of hash table with same name should fail\n");
1482 : 0 : rte_hash_free(handle);
1483 : 0 : rte_hash_free(tmp);
1484 : 0 : return -1;
1485 : : }
1486 : 1 : rte_hash_free(handle);
1487 : :
1488 : : printf("# Test successful. No more errors expected\n");
1489 : :
1490 : 1 : return 0;
1491 : : }
1492 : :
1493 : : /*
1494 : : * Do tests for hash creation with parameters that look incorrect
1495 : : * but are actually valid.
1496 : : */
1497 : : static int
1498 : 1 : test_hash_creation_with_good_parameters(void)
1499 : : {
1500 : : struct rte_hash *handle;
1501 : : struct rte_hash_parameters params;
1502 : :
1503 : : /* create with null hash function - should choose DEFAULT_HASH_FUNC */
1504 : : memcpy(¶ms, &ut_params, sizeof(params));
1505 : 1 : params.name = "name";
1506 : 1 : params.hash_func = NULL;
1507 : 1 : handle = rte_hash_create(¶ms);
1508 [ - + ]: 1 : if (handle == NULL) {
1509 : : printf("Creating hash with null hash_func failed\n");
1510 : 0 : return -1;
1511 : : }
1512 : :
1513 : 1 : rte_hash_free(handle);
1514 : :
1515 : 1 : return 0;
1516 : : }
1517 : :
1518 : : /*
1519 : : * Test hash creation and key operations with various key lengths.
1520 : : * This exercises the key compare functions for different sizes.
1521 : : */
1522 : : static int
1523 : 1 : test_hash_creation_with_key_lengths(void)
1524 : : {
1525 : : struct rte_hash *handle;
1526 : : struct rte_hash_parameters params;
1527 : : uint8_t key[MAX_KEYSIZE];
1528 : : unsigned int i, j;
1529 : : int pos, expected_pos;
1530 : :
1531 [ + + ]: 31 : for (i = 0; i < RTE_DIM(hashtest_key_lens); i++) {
1532 : 30 : uint32_t key_len = hashtest_key_lens[i];
1533 : :
1534 : : /* key_len of 0 is invalid */
1535 [ + + ]: 30 : if (key_len == 0)
1536 : 1 : continue;
1537 : :
1538 : : memcpy(¶ms, &ut_params, sizeof(params));
1539 : 29 : params.name = "key_len_test";
1540 : 29 : params.key_len = key_len;
1541 : :
1542 : 29 : handle = rte_hash_create(¶ms);
1543 [ - + ]: 29 : if (handle == NULL) {
1544 : : printf("Creating hash with key_len %u failed\n", key_len);
1545 : 0 : return -1;
1546 : : }
1547 : :
1548 : : /* initialize key with pattern */
1549 [ + + ]: 1179 : for (j = 0; j < key_len; j++)
1550 : 1150 : key[j] = (uint8_t)j;
1551 : :
1552 : : /* add the key */
1553 : 29 : pos = rte_hash_add_key(handle, key);
1554 [ - + ]: 29 : if (pos < 0) {
1555 : : printf("Adding key with key_len %u failed\n", key_len);
1556 : 0 : rte_hash_free(handle);
1557 : 0 : return -1;
1558 : : }
1559 : : expected_pos = pos;
1560 : :
1561 : : /* lookup should find same key */
1562 : 29 : pos = rte_hash_lookup(handle, key);
1563 [ - + ]: 29 : if (pos != expected_pos) {
1564 : : printf("Lookup key with key_len %u failed: expected %d got %d\n",
1565 : : key_len, expected_pos, pos);
1566 : 0 : rte_hash_free(handle);
1567 : 0 : return -1;
1568 : : }
1569 : :
1570 : : /* modify one byte and lookup should fail */
1571 : 29 : key[key_len - 1] ^= 0xff;
1572 : 29 : pos = rte_hash_lookup(handle, key);
1573 [ - + ]: 29 : if (pos != -ENOENT) {
1574 : : printf("Lookup modified key with key_len %u should have failed\n",
1575 : : key_len);
1576 : 0 : rte_hash_free(handle);
1577 : 0 : return -1;
1578 : : }
1579 : :
1580 : : /* restore key and delete */
1581 : 29 : key[key_len - 1] ^= 0xff;
1582 : 29 : pos = rte_hash_del_key(handle, key);
1583 [ - + ]: 29 : if (pos != expected_pos) {
1584 : : printf("Delete key with key_len %u failed\n", key_len);
1585 : 0 : rte_hash_free(handle);
1586 : 0 : return -1;
1587 : : }
1588 : :
1589 : 29 : rte_hash_free(handle);
1590 : : }
1591 : :
1592 : : return 0;
1593 : : }
1594 : :
1595 : : #define ITERATIONS 3
1596 : : /*
1597 : : * Test to see the average table utilization (entries added/max entries)
1598 : : * before hitting a random entry that cannot be added
1599 : : */
1600 : 2 : static int test_average_table_utilization(uint32_t ext_table)
1601 : : {
1602 : : struct rte_hash *handle;
1603 : : uint8_t simple_key[MAX_KEYSIZE];
1604 : : unsigned i, j;
1605 : : unsigned added_keys, average_keys_added = 0;
1606 : : int ret;
1607 : : unsigned int cnt;
1608 : :
1609 : : printf("\n# Running test to determine average utilization"
1610 : : "\n before adding elements begins to fail\n");
1611 [ + + ]: 2 : if (ext_table)
1612 : : printf("ext table is enabled\n");
1613 : : else
1614 : : printf("ext table is disabled\n");
1615 : :
1616 : : printf("Measuring performance, please wait");
1617 : 2 : fflush(stdout);
1618 : 2 : ut_params.entries = 1 << 16;
1619 : 2 : ut_params.name = "test_average_utilization";
1620 : 2 : ut_params.hash_func = rte_jhash;
1621 [ + + ]: 2 : if (ext_table)
1622 : 1 : ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1623 : : else
1624 : 1 : ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1625 : :
1626 : 2 : handle = rte_hash_create(&ut_params);
1627 : :
1628 [ - + ]: 2 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1629 : :
1630 [ + + ]: 8 : for (j = 0; j < ITERATIONS; j++) {
1631 : : ret = 0;
1632 : : /* Add random entries until key cannot be added */
1633 : 390083 : for (added_keys = 0; ret >= 0; added_keys++) {
1634 [ + + ]: 6631513 : for (i = 0; i < ut_params.key_len; i++)
1635 : 6241424 : simple_key[i] = rte_rand() % 255;
1636 : 390089 : ret = rte_hash_add_key(handle, simple_key);
1637 [ + + ]: 390089 : if (ret < 0)
1638 : : break;
1639 : : }
1640 : :
1641 [ - + ]: 6 : if (ret != -ENOSPC) {
1642 : : printf("Unexpected error when adding keys\n");
1643 : 0 : rte_hash_free(handle);
1644 : 0 : return -1;
1645 : : }
1646 : :
1647 : 6 : cnt = rte_hash_count(handle);
1648 [ - + ]: 6 : if (cnt != added_keys) {
1649 : : printf("rte_hash_count returned wrong value %u, %u,"
1650 : : "%u\n", j, added_keys, cnt);
1651 : 0 : rte_hash_free(handle);
1652 : 0 : return -1;
1653 : : }
1654 [ + + ]: 6 : if (ext_table) {
1655 [ - + ]: 3 : if (cnt != ut_params.entries) {
1656 : : printf("rte_hash_count returned wrong value "
1657 : : "%u, %u, %u\n", j, added_keys, cnt);
1658 : 0 : rte_hash_free(handle);
1659 : 0 : return -1;
1660 : : }
1661 : : }
1662 : :
1663 : 6 : average_keys_added += added_keys;
1664 : :
1665 : : /* Reset the table */
1666 : 6 : rte_hash_reset(handle);
1667 : :
1668 : : /* Print a dot to show progress on operations */
1669 : : printf(".");
1670 : 6 : fflush(stdout);
1671 : : }
1672 : :
1673 : 2 : average_keys_added /= ITERATIONS;
1674 : :
1675 : 2 : printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
1676 : 2 : ((double) average_keys_added / ut_params.entries * 100),
1677 : : average_keys_added, ut_params.entries);
1678 : 2 : rte_hash_free(handle);
1679 : :
1680 : 2 : return 0;
1681 : : }
1682 : :
1683 : : #define NUM_ENTRIES 256
1684 : 2 : static int test_hash_iteration(uint32_t ext_table)
1685 : : {
1686 : : struct rte_hash *handle;
1687 : : unsigned i;
1688 : : uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE];
1689 : : const void *next_key;
1690 : : void *next_data;
1691 : : void *data[NUM_ENTRIES];
1692 : : unsigned added_keys;
1693 : 2 : uint32_t iter = 0;
1694 : : int ret = 0;
1695 : :
1696 : 2 : ut_params.entries = NUM_ENTRIES;
1697 : 2 : ut_params.name = "test_hash_iteration";
1698 : 2 : ut_params.hash_func = rte_jhash;
1699 : 2 : ut_params.key_len = 16;
1700 [ + + ]: 2 : if (ext_table)
1701 : 1 : ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1702 : : else
1703 : 1 : ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1704 : :
1705 : 2 : handle = rte_hash_create(&ut_params);
1706 [ - + ]: 2 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1707 : :
1708 : : /* Add random entries until key cannot be added */
1709 [ + + ]: 514 : for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) {
1710 : 512 : data[added_keys] = (void *) ((uintptr_t) rte_rand());
1711 [ + + ]: 8704 : for (i = 0; i < ut_params.key_len; i++)
1712 : 8192 : keys[added_keys][i] = rte_rand() % 255;
1713 : 512 : ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]);
1714 [ - + ]: 512 : if (ret < 0) {
1715 [ # # ]: 0 : if (ext_table) {
1716 : : printf("Insertion failed for ext table\n");
1717 : 0 : goto err;
1718 : : }
1719 : : break;
1720 : : }
1721 : : }
1722 : :
1723 : : /* Iterate through the hash table */
1724 [ + + ]: 514 : while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
1725 : : /* Search for the key in the list of keys added */
1726 [ + - ]: 65792 : for (i = 0; i < NUM_ENTRIES; i++) {
1727 [ + + ]: 65792 : if (memcmp(next_key, keys[i], ut_params.key_len) == 0) {
1728 [ - + ]: 512 : if (next_data != data[i]) {
1729 : : printf("Data found in the hash table is"
1730 : : "not the data added with the key\n");
1731 : 0 : goto err;
1732 : : }
1733 : 512 : added_keys--;
1734 : 512 : break;
1735 : : }
1736 : : }
1737 [ - + ]: 512 : if (i == NUM_ENTRIES) {
1738 : : printf("Key found in the hash table was not added\n");
1739 : 0 : goto err;
1740 : : }
1741 : : }
1742 : :
1743 : : /* Check if all keys have been iterated */
1744 [ - + ]: 2 : if (added_keys != 0) {
1745 : : printf("There were still %u keys to iterate\n", added_keys);
1746 : 0 : goto err;
1747 : : }
1748 : :
1749 : 2 : rte_hash_free(handle);
1750 : 2 : return 0;
1751 : :
1752 : 0 : err:
1753 : 0 : rte_hash_free(handle);
1754 : 0 : return -1;
1755 : : }
1756 : :
1757 : : static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
1758 : : 0x04, 0x05, 0x06, 0x07,
1759 : : 0x08, 0x09, 0x0a, 0x0b,
1760 : : 0x0c, 0x0d, 0x0e, 0x0f};
1761 : : static struct rte_hash_parameters hash_params_ex = {
1762 : : .name = NULL,
1763 : : .entries = 64,
1764 : : .key_len = 0,
1765 : : .hash_func = NULL,
1766 : : .hash_func_init_val = 0,
1767 : : .socket_id = 0,
1768 : : };
1769 : :
1770 : : /*
1771 : : * Wrapper function around rte_jhash_32b.
1772 : : * It is required because rte_jhash_32b() accepts the length
1773 : : * as size of 4-byte units.
1774 : : */
1775 : : static inline uint32_t
1776 : 4 : test_jhash_32b(const void *k, uint32_t length, uint32_t initval)
1777 : : {
1778 : 4 : return rte_jhash_32b(k, length >> 2, initval);
1779 : : }
1780 : :
1781 : : /*
1782 : : * add/delete key with jhash2
1783 : : */
1784 : : static int
1785 : 1 : test_hash_add_delete_jhash2(void)
1786 : : {
1787 : : int ret = -1;
1788 : : struct rte_hash *handle;
1789 : : int32_t pos1, pos2;
1790 : :
1791 : 1 : hash_params_ex.name = "hash_test_jhash2";
1792 : 1 : hash_params_ex.key_len = 4;
1793 : 1 : hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b;
1794 : :
1795 : 1 : handle = rte_hash_create(&hash_params_ex);
1796 [ - + ]: 1 : if (handle == NULL) {
1797 : : printf("test_hash_add_delete_jhash2 fail to create hash\n");
1798 : 0 : goto fail_jhash2;
1799 : : }
1800 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1801 [ - + ]: 1 : if (pos1 < 0) {
1802 : : printf("test_hash_add_delete_jhash2 fail to add hash key\n");
1803 : 0 : goto fail_jhash2;
1804 : : }
1805 : :
1806 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1807 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2) {
1808 : : printf("test_hash_add_delete_jhash2 delete different key from being added\n");
1809 : 0 : goto fail_jhash2;
1810 : : }
1811 : : ret = 0;
1812 : :
1813 : 1 : fail_jhash2:
1814 : 1 : rte_hash_free(handle);
1815 : :
1816 : 1 : return ret;
1817 : : }
1818 : :
1819 : : /*
1820 : : * add/delete (2) key with jhash2
1821 : : */
1822 : : static int
1823 : 1 : test_hash_add_delete_2_jhash2(void)
1824 : : {
1825 : : int ret = -1;
1826 : : struct rte_hash *handle;
1827 : : int32_t pos1, pos2;
1828 : :
1829 : 1 : hash_params_ex.name = "hash_test_2_jhash2";
1830 : 1 : hash_params_ex.key_len = 8;
1831 : 1 : hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b;
1832 : :
1833 : 1 : handle = rte_hash_create(&hash_params_ex);
1834 [ - + ]: 1 : if (handle == NULL)
1835 : 0 : goto fail_2_jhash2;
1836 : :
1837 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1838 [ - + ]: 1 : if (pos1 < 0)
1839 : 0 : goto fail_2_jhash2;
1840 : :
1841 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1842 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2)
1843 : 0 : goto fail_2_jhash2;
1844 : :
1845 : : ret = 0;
1846 : :
1847 : 1 : fail_2_jhash2:
1848 : 1 : rte_hash_free(handle);
1849 : :
1850 : 1 : return ret;
1851 : : }
1852 : :
1853 : : static uint32_t
1854 : 2 : test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval)
1855 : : {
1856 : : const uint32_t *k = key;
1857 : :
1858 : : RTE_SET_USED(length);
1859 : :
1860 : 2 : return rte_jhash_1word(k[0], initval);
1861 : : }
1862 : :
1863 : : static uint32_t
1864 : 2 : test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval)
1865 : : {
1866 : : const uint32_t *k = key;
1867 : :
1868 : : RTE_SET_USED(length);
1869 : :
1870 : 2 : return rte_jhash_2words(k[0], k[1], initval);
1871 : : }
1872 : :
1873 : : static uint32_t
1874 : 2 : test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval)
1875 : : {
1876 : : const uint32_t *k = key;
1877 : :
1878 : : RTE_SET_USED(length);
1879 : :
1880 : 2 : return rte_jhash_3words(k[0], k[1], k[2], initval);
1881 : : }
1882 : :
1883 : : /*
1884 : : * add/delete key with jhash 1word
1885 : : */
1886 : : static int
1887 : 1 : test_hash_add_delete_jhash_1word(void)
1888 : : {
1889 : : int ret = -1;
1890 : : struct rte_hash *handle;
1891 : : int32_t pos1, pos2;
1892 : :
1893 : 1 : hash_params_ex.name = "hash_test_jhash_1word";
1894 : 1 : hash_params_ex.key_len = 4;
1895 : 1 : hash_params_ex.hash_func = test_hash_jhash_1word;
1896 : :
1897 : 1 : handle = rte_hash_create(&hash_params_ex);
1898 [ - + ]: 1 : if (handle == NULL)
1899 : 0 : goto fail_jhash_1word;
1900 : :
1901 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1902 [ - + ]: 1 : if (pos1 < 0)
1903 : 0 : goto fail_jhash_1word;
1904 : :
1905 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1906 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2)
1907 : 0 : goto fail_jhash_1word;
1908 : :
1909 : : ret = 0;
1910 : :
1911 : 1 : fail_jhash_1word:
1912 : 1 : rte_hash_free(handle);
1913 : :
1914 : 1 : return ret;
1915 : : }
1916 : :
1917 : : /*
1918 : : * add/delete key with jhash 2word
1919 : : */
1920 : : static int
1921 : 1 : test_hash_add_delete_jhash_2word(void)
1922 : : {
1923 : : int ret = -1;
1924 : : struct rte_hash *handle;
1925 : : int32_t pos1, pos2;
1926 : :
1927 : 1 : hash_params_ex.name = "hash_test_jhash_2word";
1928 : 1 : hash_params_ex.key_len = 8;
1929 : 1 : hash_params_ex.hash_func = test_hash_jhash_2word;
1930 : :
1931 : 1 : handle = rte_hash_create(&hash_params_ex);
1932 [ - + ]: 1 : if (handle == NULL)
1933 : 0 : goto fail_jhash_2word;
1934 : :
1935 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1936 [ - + ]: 1 : if (pos1 < 0)
1937 : 0 : goto fail_jhash_2word;
1938 : :
1939 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1940 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2)
1941 : 0 : goto fail_jhash_2word;
1942 : :
1943 : : ret = 0;
1944 : :
1945 : 1 : fail_jhash_2word:
1946 : 1 : rte_hash_free(handle);
1947 : :
1948 : 1 : return ret;
1949 : : }
1950 : :
1951 : : /*
1952 : : * add/delete key with jhash 3word
1953 : : */
1954 : : static int
1955 : 1 : test_hash_add_delete_jhash_3word(void)
1956 : : {
1957 : : int ret = -1;
1958 : : struct rte_hash *handle;
1959 : : int32_t pos1, pos2;
1960 : :
1961 : 1 : hash_params_ex.name = "hash_test_jhash_3word";
1962 : 1 : hash_params_ex.key_len = 12;
1963 : 1 : hash_params_ex.hash_func = test_hash_jhash_3word;
1964 : :
1965 : 1 : handle = rte_hash_create(&hash_params_ex);
1966 [ - + ]: 1 : if (handle == NULL)
1967 : 0 : goto fail_jhash_3word;
1968 : :
1969 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1970 [ - + ]: 1 : if (pos1 < 0)
1971 : 0 : goto fail_jhash_3word;
1972 : :
1973 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1974 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2)
1975 : 0 : goto fail_jhash_3word;
1976 : :
1977 : : ret = 0;
1978 : :
1979 : 1 : fail_jhash_3word:
1980 : 1 : rte_hash_free(handle);
1981 : :
1982 : 1 : return ret;
1983 : : }
1984 : :
1985 : : static struct rte_hash *g_handle;
1986 : : static struct rte_rcu_qsbr *g_qsv;
1987 : : static volatile uint8_t writer_done;
1988 : : struct flow_key g_rand_keys[9];
1989 : :
1990 : : /*
1991 : : * rte_hash_rcu_qsbr_add positive and negative tests.
1992 : : * - Add RCU QSBR variable to Hash
1993 : : * - Add another RCU QSBR variable to Hash
1994 : : * - Check returns
1995 : : */
1996 : : static int
1997 : 1 : test_hash_rcu_qsbr_add(void)
1998 : : {
1999 : : size_t sz;
2000 : : struct rte_rcu_qsbr *qsv2 = NULL;
2001 : : int32_t status;
2002 : 1 : struct rte_hash_rcu_config rcu_cfg = {0};
2003 : : struct rte_hash_parameters params;
2004 : :
2005 : : printf("\n# Running RCU QSBR add tests\n");
2006 : : memcpy(¶ms, &ut_params, sizeof(params));
2007 : 1 : params.name = "test_hash_rcu_qsbr_add";
2008 : 1 : params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
2009 : : RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
2010 : 1 : g_handle = rte_hash_create(¶ms);
2011 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2012 : :
2013 : : /* Create RCU QSBR variable */
2014 : 1 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2015 : 1 : g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2016 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2017 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
2018 : : "RCU QSBR variable creation failed");
2019 : :
2020 : 1 : status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2021 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2022 : : "RCU QSBR variable initialization failed");
2023 : :
2024 : 1 : rcu_cfg.v = g_qsv;
2025 : : /* Invalid QSBR mode */
2026 : 1 : rcu_cfg.mode = 0xff;
2027 : 1 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2028 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status == 0, "Invalid QSBR mode test failed");
2029 : :
2030 : 1 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
2031 : : /* Attach RCU QSBR to hash table */
2032 : 1 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2033 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2034 : : "Attach RCU QSBR to hash table failed");
2035 : :
2036 : : /* Create and attach another RCU QSBR to hash table */
2037 : 1 : qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2038 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2039 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(qsv2 == NULL,
2040 : : "RCU QSBR variable creation failed");
2041 : :
2042 : 1 : rcu_cfg.v = qsv2;
2043 : 1 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
2044 : 1 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2045 : 1 : rte_free(qsv2);
2046 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status == 0,
2047 : : "Attach RCU QSBR to hash table succeeded where failure"
2048 : : " is expected");
2049 : :
2050 : 1 : rte_hash_free(g_handle);
2051 : 1 : rte_free(g_qsv);
2052 : :
2053 : 1 : return 0;
2054 : : }
2055 : :
2056 : : #define HASH_RCU_QSBR_MAX_TOTAL_ENTRIES 9
2057 : :
2058 : : /*
2059 : : * rte_hash_rcu_qsbr_add DQ mode functional test.
2060 : : * Reader and writer are in the same thread in this test.
2061 : : * - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
2062 : : * - Add RCU QSBR variable to hash
2063 : : * - Add 8 hash entries and fill the bucket
2064 : : * - If ext bkt is enabled, add 1 extra entry that is available in the ext bkt
2065 : : * - Register a reader thread (not a real thread)
2066 : : * - Reader lookup existing entry
2067 : : * - Writer deletes the entry
2068 : : * - Reader lookup the entry
2069 : : * - Writer re-add the entry (no available free index)
2070 : : * - Reader report quiescent state and unregister
2071 : : * - Writer re-add the entry
2072 : : * - Reader lookup the entry
2073 : : */
2074 : : static int
2075 : 2 : test_hash_rcu_qsbr_dq_mode(uint8_t ext_bkt)
2076 : : {
2077 [ + + ]: 2 : const uint32_t total_entries = (ext_bkt == 0) ? 8 : HASH_RCU_QSBR_MAX_TOTAL_ENTRIES;
2078 : :
2079 : : uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2080 : :
2081 [ + + ]: 2 : if (ext_bkt)
2082 : : hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
2083 : :
2084 : 2 : struct rte_hash_parameters params_pseudo_hash = {
2085 : : .name = "test_hash_rcu_qsbr_dq_mode",
2086 : : .entries = total_entries,
2087 : : .key_len = sizeof(struct flow_key),
2088 : : .hash_func = pseudo_hash,
2089 : : .hash_func_init_val = 0,
2090 : : .socket_id = 0,
2091 : : .extra_flag = hash_extra_flag,
2092 : : };
2093 : : int pos[HASH_RCU_QSBR_MAX_TOTAL_ENTRIES];
2094 : : int expected_pos[HASH_RCU_QSBR_MAX_TOTAL_ENTRIES];
2095 : : unsigned int i;
2096 : : size_t sz;
2097 : : int32_t status;
2098 : 2 : struct rte_hash_rcu_config rcu_cfg = {0};
2099 : :
2100 : 2 : g_qsv = NULL;
2101 : 2 : g_handle = NULL;
2102 : :
2103 [ + + ]: 19 : for (i = 0; i < total_entries; i++) {
2104 : 17 : g_rand_keys[i].port_dst = i;
2105 : 17 : g_rand_keys[i].port_src = i+1;
2106 : : }
2107 : :
2108 [ + + ]: 2 : if (ext_bkt)
2109 : : printf("\n# Running RCU QSBR DQ mode functional test with"
2110 : : " ext bkt\n");
2111 : : else
2112 : : printf("\n# Running RCU QSBR DQ mode functional test\n");
2113 : :
2114 : 2 : g_handle = rte_hash_create(¶ms_pseudo_hash);
2115 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2116 : :
2117 : : /* Create RCU QSBR variable */
2118 : 2 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2119 : 2 : g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2120 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2121 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
2122 : : "RCU QSBR variable creation failed");
2123 : :
2124 : 2 : status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2125 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2126 : : "RCU QSBR variable initialization failed");
2127 : :
2128 : 2 : rcu_cfg.v = g_qsv;
2129 : 2 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
2130 : : /* Attach RCU QSBR to hash table */
2131 : 2 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2132 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2133 : : "Attach RCU QSBR to hash table failed");
2134 : :
2135 : : /* Fill bucket */
2136 [ + + ]: 19 : for (i = 0; i < total_entries; i++) {
2137 : 17 : pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
2138 : 17 : print_key_info("Add", &g_rand_keys[i], pos[i]);
2139 [ - + - - ]: 17 : RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
2140 : : "failed to add key (pos[%u]=%d)", i,
2141 : : pos[i]);
2142 : 17 : expected_pos[i] = pos[i];
2143 : : }
2144 : :
2145 : : /* Register pseudo reader */
2146 : 2 : status = rte_rcu_qsbr_thread_register(g_qsv, 0);
2147 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2148 : : "RCU QSBR thread registration failed");
2149 : 2 : rte_rcu_qsbr_thread_online(g_qsv, 0);
2150 : :
2151 : : /* Lookup */
2152 : 2 : pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2153 : 2 : print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2154 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2155 : : "failed to find correct key (pos[%u]=%d)", 0,
2156 : : pos[0]);
2157 : :
2158 : : /* Writer update */
2159 : 2 : pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
2160 : 2 : print_key_info("Del", &g_rand_keys[0], pos[0]);
2161 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2162 : : "failed to del correct key (pos[%u]=%d)", 0,
2163 : : pos[0]);
2164 : :
2165 : : /* Lookup */
2166 : 2 : pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2167 : 2 : print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2168 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOENT,
2169 : : "found deleted key (pos[%u]=%d)", 0, pos[0]);
2170 : :
2171 : : /* Fill bucket */
2172 : 2 : pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2173 : 2 : print_key_info("Add", &g_rand_keys[0], pos[0]);
2174 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOSPC,
2175 : : "Added key successfully (pos[%u]=%d)", 0, pos[0]);
2176 : :
2177 : : /* Reader quiescent */
2178 [ + - ]: 2 : rte_rcu_qsbr_quiescent(g_qsv, 0);
2179 : :
2180 : : /* Fill bucket */
2181 : 2 : pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2182 : 2 : print_key_info("Add", &g_rand_keys[0], pos[0]);
2183 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
2184 : : "failed to add key (pos[%u]=%d)", 0, pos[0]);
2185 : : expected_pos[0] = pos[0];
2186 : :
2187 : 2 : rte_rcu_qsbr_thread_offline(g_qsv, 0);
2188 : 2 : (void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
2189 : :
2190 : : /* Lookup */
2191 : 2 : pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2192 : 2 : print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2193 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2194 : : "failed to find correct key (pos[%u]=%d)", 0,
2195 : : pos[0]);
2196 : :
2197 : 2 : rte_hash_free(g_handle);
2198 : 2 : rte_free(g_qsv);
2199 : 2 : return 0;
2200 : :
2201 : : }
2202 : :
2203 : : /* Report quiescent state interval every 1024 lookups. Larger critical
2204 : : * sections in reader will result in writer polling multiple times.
2205 : : */
2206 : : #define QSBR_REPORTING_INTERVAL 1024
2207 : : #define WRITER_ITERATIONS 512
2208 : :
2209 : : /*
2210 : : * Reader thread using rte_hash data structure with RCU.
2211 : : */
2212 : : static int
2213 : 2 : test_hash_rcu_qsbr_reader(void *arg)
2214 : : {
2215 : : int i;
2216 : :
2217 : : RTE_SET_USED(arg);
2218 : : /* Register this thread to report quiescent state */
2219 : 2 : (void)rte_rcu_qsbr_thread_register(g_qsv, 0);
2220 : 2 : rte_rcu_qsbr_thread_online(g_qsv, 0);
2221 : :
2222 : : do {
2223 [ + + ]: 1051650 : for (i = 0; i < QSBR_REPORTING_INTERVAL; i++)
2224 : 1050624 : rte_hash_lookup(g_handle, &g_rand_keys[0]);
2225 : :
2226 : : /* Update quiescent state */
2227 [ + + ]: 1026 : rte_rcu_qsbr_quiescent(g_qsv, 0);
2228 [ + + ]: 1026 : } while (!writer_done);
2229 : :
2230 : 2 : rte_rcu_qsbr_thread_offline(g_qsv, 0);
2231 : 2 : (void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
2232 : :
2233 : 2 : return 0;
2234 : : }
2235 : :
2236 : : /*
2237 : : * rte_hash_rcu_qsbr_add sync mode functional test.
2238 : : * 1 Reader and 1 writer. They cannot be in the same thread in this test.
2239 : : * - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
2240 : : * - Add RCU QSBR variable to hash
2241 : : * - Register a reader thread. Reader keeps looking up a specific key.
2242 : : * - Writer keeps adding and deleting a specific key.
2243 : : */
2244 : : static int
2245 : 2 : test_hash_rcu_qsbr_sync_mode(uint8_t ext_bkt)
2246 : : {
2247 [ + + ]: 2 : const uint32_t total_entries = (ext_bkt == 0) ? 8 : HASH_RCU_QSBR_MAX_TOTAL_ENTRIES;
2248 : :
2249 : : uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2250 : :
2251 [ + + ]: 2 : if (ext_bkt)
2252 : : hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
2253 : :
2254 : 2 : struct rte_hash_parameters params_pseudo_hash = {
2255 : : .name = "test_hash_rcu_qsbr_sync_mode",
2256 : : .entries = total_entries,
2257 : : .key_len = sizeof(struct flow_key),
2258 : : .hash_func = pseudo_hash,
2259 : : .hash_func_init_val = 0,
2260 : : .socket_id = 0,
2261 : : .extra_flag = hash_extra_flag,
2262 : : };
2263 : : int pos[HASH_RCU_QSBR_MAX_TOTAL_ENTRIES];
2264 : : int expected_pos[HASH_RCU_QSBR_MAX_TOTAL_ENTRIES];
2265 : : unsigned int i;
2266 : : size_t sz;
2267 : : int32_t status;
2268 : 2 : struct rte_hash_rcu_config rcu_cfg = {0};
2269 : :
2270 : 2 : g_qsv = NULL;
2271 : 2 : g_handle = NULL;
2272 : :
2273 [ + + ]: 19 : for (i = 0; i < total_entries; i++) {
2274 : 17 : g_rand_keys[i].port_dst = i;
2275 : 17 : g_rand_keys[i].port_src = i+1;
2276 : : }
2277 : :
2278 [ + + ]: 2 : if (ext_bkt)
2279 : : printf("\n# Running RCU QSBR sync mode functional test with"
2280 : : " ext bkt\n");
2281 : : else
2282 : : printf("\n# Running RCU QSBR sync mode functional test\n");
2283 : :
2284 : 2 : g_handle = rte_hash_create(¶ms_pseudo_hash);
2285 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2286 : :
2287 : : /* Create RCU QSBR variable */
2288 : 2 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2289 : 2 : g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2290 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2291 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
2292 : : "RCU QSBR variable creation failed");
2293 : :
2294 : 2 : status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2295 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2296 : : "RCU QSBR variable initialization failed");
2297 : :
2298 : 2 : rcu_cfg.v = g_qsv;
2299 : 2 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
2300 : : /* Attach RCU QSBR to hash table */
2301 : 2 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2302 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2303 : : "Attach RCU QSBR to hash table failed");
2304 : :
2305 : : /* Launch reader thread */
2306 : 2 : rte_eal_remote_launch(test_hash_rcu_qsbr_reader, NULL,
2307 : : rte_get_next_lcore(-1, 1, 0));
2308 : :
2309 : : /* Fill bucket */
2310 [ + + ]: 19 : for (i = 0; i < total_entries; i++) {
2311 : 17 : pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
2312 : 17 : print_key_info("Add", &g_rand_keys[i], pos[i]);
2313 [ - + - - ]: 17 : RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
2314 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
2315 : : expected_pos[i] = pos[i];
2316 : : }
2317 : 2 : writer_done = 0;
2318 : :
2319 : : /* Writer Update */
2320 [ + + ]: 1026 : for (i = 0; i < WRITER_ITERATIONS; i++) {
2321 : 1024 : expected_pos[0] = pos[0];
2322 : 1024 : pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
2323 : 1024 : print_key_info("Del", &g_rand_keys[0], status);
2324 [ - + - - ]: 1024 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2325 : : "failed to del correct key (pos[%u]=%d)"
2326 : : , 0, pos[0]);
2327 : :
2328 : 1024 : pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2329 : 1024 : print_key_info("Add", &g_rand_keys[0], pos[0]);
2330 [ - + - - ]: 1024 : RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
2331 : : "failed to add key (pos[%u]=%d)", 0,
2332 : : pos[0]);
2333 : : }
2334 : :
2335 : 2 : writer_done = 1;
2336 : : /* Wait until reader exited. */
2337 : 2 : rte_eal_mp_wait_lcore();
2338 : :
2339 : 2 : rte_hash_free(g_handle);
2340 : 2 : rte_free(g_qsv);
2341 : :
2342 : 2 : return 0;
2343 : :
2344 : : }
2345 : :
2346 : : /*
2347 : : * rte_hash_rcu_qsbr_dq_reclaim unit test.
2348 : : */
2349 : : static int
2350 : 1 : test_hash_rcu_qsbr_dq_reclaim(void)
2351 : : {
2352 : : size_t sz;
2353 : : int32_t status;
2354 : : unsigned int total_entries = 8;
2355 : : unsigned int freed, pending, available;
2356 : 1 : uint32_t reclaim_keys[8] = {10, 11, 12, 13, 14, 15, 16, 17};
2357 : 1 : struct rte_hash_rcu_config rcu_cfg = {0};
2358 : 1 : struct rte_hash_parameters hash_params = {
2359 : : .name = "test_hash_rcu_qsbr_dq_reclaim",
2360 : : .entries = total_entries,
2361 : : .key_len = sizeof(uint32_t),
2362 : : .hash_func = NULL,
2363 : : .hash_func_init_val = 0,
2364 : : .socket_id = 0,
2365 : : };
2366 : :
2367 : 1 : hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2368 : :
2369 : 1 : g_qsv = NULL;
2370 : 1 : g_handle = NULL;
2371 : :
2372 : : printf("\n# Running RCU QSBR DQ mode, reclaim defer queue functional test\n");
2373 : :
2374 : 1 : g_handle = rte_hash_create(&hash_params);
2375 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2376 : :
2377 : : /* Create RCU QSBR variable */
2378 : 1 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2379 : 1 : g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(
2380 : : NULL, sz, RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2381 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL, "RCU QSBR variable creation failed");
2382 : :
2383 : 1 : status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2384 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR variable initialization failed");
2385 : :
2386 : 1 : rcu_cfg.v = g_qsv;
2387 : 1 : rcu_cfg.dq_size = total_entries;
2388 : 1 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
2389 : :
2390 : : /* Attach RCU QSBR to hash table */
2391 : 1 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2392 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0, "Attach RCU QSBR to hash table failed");
2393 : :
2394 : : /* Register pseudo reader */
2395 : 1 : status = rte_rcu_qsbr_thread_register(g_qsv, 0);
2396 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR thread registration failed");
2397 : 1 : rte_rcu_qsbr_thread_online(g_qsv, 0);
2398 : :
2399 : : /* Fill half of the hash table */
2400 [ + + ]: 5 : for (size_t i = 0; i < total_entries / 2; i++)
2401 : 4 : status = rte_hash_add_key(g_handle, &reclaim_keys[i]);
2402 : :
2403 : : /* Try to put these elements into the defer queue*/
2404 [ + + ]: 5 : for (size_t i = 0; i < total_entries / 2; i++)
2405 : 4 : rte_hash_del_key(g_handle, &reclaim_keys[i]);
2406 : :
2407 : : /* Reader quiescent */
2408 [ + - ]: 1 : rte_rcu_qsbr_quiescent(g_qsv, 0);
2409 : :
2410 : 1 : status = rte_hash_add_key(g_handle, &reclaim_keys[0]);
2411 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status < 0, "failed to add key (pos[%u]=%d)", 0, status);
2412 : :
2413 : : /* This should be (total_entries / 2) + 1 (last add) */
2414 : 1 : unsigned int hash_size = rte_hash_count(g_handle);
2415 : :
2416 : : /* Freed size should be (total_entries / 2) */
2417 : 1 : rte_hash_rcu_qsbr_dq_reclaim(g_handle, &freed, &pending, &available);
2418 : :
2419 : 1 : rte_hash_free(g_handle);
2420 : 1 : rte_free(g_qsv);
2421 : :
2422 [ + - - + ]: 1 : if (hash_size != (total_entries / 2 + 1) || freed != (total_entries / 2)) {
2423 : : printf("Failed to reclaim defer queue\n");
2424 : 0 : return -1;
2425 : : }
2426 : :
2427 : : return 0;
2428 : : }
2429 : :
2430 : : static void *old_data;
2431 : :
2432 : : static void
2433 : 2 : test_hash_free_key_data_func(void *p __rte_unused, void *key_data)
2434 : : {
2435 : 2 : old_data = key_data;
2436 : 2 : }
2437 : :
2438 : : /*
2439 : : * Test automatic RCU free on overwrite via rte_hash_add_key_data.
2440 : : * - Create hash with RW_CONCURRENCY_LF and RCU QSBR in DQ mode
2441 : : * with a free_key_data_func callback that increments a counter.
2442 : : * - Register a pseudo reader thread.
2443 : : * - Add key with data (void *)1.
2444 : : * - Overwrite same key with data (void *)2 via rte_hash_add_key_data.
2445 : : * - Report quiescent state, trigger reclamation.
2446 : : * - Verify the free callback was called exactly once.
2447 : : * - Delete the key, report quiescent state, reclaim again.
2448 : : * - Verify the free callback was called a second time.
2449 : : */
2450 : : static int
2451 : 1 : test_hash_rcu_qsbr_replace_auto_free(void)
2452 : : {
2453 : 1 : struct rte_hash_rcu_config rcu = {
2454 : : .v = NULL,
2455 : : .mode = RTE_HASH_QSBR_MODE_DQ,
2456 : : .free_key_data_func = test_hash_free_key_data_func,
2457 : : .key_data_ptr = NULL,
2458 : : };
2459 : 1 : struct rte_hash_parameters params = {
2460 : : .name = "test_replace_auto_free",
2461 : : .entries = 16,
2462 : : .key_len = sizeof(uint32_t),
2463 : : .hash_func = NULL,
2464 : : .hash_func_init_val = 0,
2465 : : .socket_id = SOCKET_ID_ANY,
2466 : : .extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
2467 : : };
2468 : : struct rte_hash *hash = NULL;
2469 : 1 : uint32_t key = 55;
2470 : : int32_t status;
2471 : : int ret = -1;
2472 : : size_t sz;
2473 : :
2474 : : printf("\n# Running RCU replace auto-free test\n");
2475 : :
2476 : 1 : hash = rte_hash_create(¶ms);
2477 [ - + ]: 1 : if (hash == NULL) {
2478 : : printf("hash creation failed\n");
2479 : 0 : goto end;
2480 : : }
2481 : :
2482 : 1 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2483 : 1 : rcu.v = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
2484 [ - + ]: 1 : if (rcu.v == NULL) {
2485 : : printf("RCU QSBR alloc failed\n");
2486 : 0 : goto end;
2487 : : }
2488 : 1 : status = rte_rcu_qsbr_init(rcu.v, RTE_MAX_LCORE);
2489 [ - + ]: 1 : if (status != 0) {
2490 : : printf("RCU QSBR init failed\n");
2491 : 0 : goto end;
2492 : : }
2493 : :
2494 : 1 : status = rte_hash_rcu_qsbr_add(hash, &rcu);
2495 [ - + ]: 1 : if (status != 0) {
2496 : : printf("RCU QSBR add failed\n");
2497 : 0 : goto end;
2498 : : }
2499 : :
2500 : : /* Register pseudo reader */
2501 : 1 : status = rte_rcu_qsbr_thread_register(rcu.v, 0);
2502 [ - + ]: 1 : if (status != 0) {
2503 : : printf("RCU QSBR thread register failed\n");
2504 : 0 : goto end;
2505 : : }
2506 : 1 : rte_rcu_qsbr_thread_online(rcu.v, 0);
2507 : :
2508 : 1 : old_data = NULL;
2509 : :
2510 : : /* Add key with data = (void *)1 */
2511 : 1 : status = rte_hash_add_key_data(hash, &key, (void *)(uintptr_t)1);
2512 [ - + ]: 1 : if (status != 0) {
2513 : : printf("failed to add key (status=%d)\n", status);
2514 : 0 : goto end;
2515 : : }
2516 : :
2517 : : /* Overwrite same key with data = (void *)2 */
2518 : 1 : status = rte_hash_add_key_data(hash, &key, (void *)(uintptr_t)2);
2519 [ - + ]: 1 : if (status != 0) {
2520 : : printf("failed to overwrite key (status=%d)\n", status);
2521 : 0 : goto end;
2522 : : }
2523 : :
2524 : : /* Reader quiescent and reclaim */
2525 [ + - ]: 1 : rte_rcu_qsbr_quiescent(rcu.v, 0);
2526 : 1 : rte_hash_rcu_qsbr_dq_reclaim(hash, NULL, NULL, NULL);
2527 : :
2528 [ - + ]: 1 : if (old_data != (void *)(uintptr_t)1) {
2529 : : printf("old data should be 0x1 but is %p\n", old_data);
2530 : 0 : goto end;
2531 : : }
2532 : :
2533 : : /* Delete the key */
2534 : 1 : status = rte_hash_del_key(hash, &key);
2535 [ - + ]: 1 : if (status < 0) {
2536 : : printf("failed to delete key (status=%d)\n", status);
2537 : 0 : goto end;
2538 : : }
2539 : :
2540 : : /* Reader quiescent and reclaim again */
2541 [ + - ]: 1 : rte_rcu_qsbr_quiescent(rcu.v, 0);
2542 : 1 : rte_hash_rcu_qsbr_dq_reclaim(hash, NULL, NULL, NULL);
2543 : :
2544 [ - + ]: 1 : if (old_data != (void *)(uintptr_t)2) {
2545 : : printf("old data should be 2 but is %p\n", old_data);
2546 : 0 : goto end;
2547 : : }
2548 : :
2549 : : ret = 0;
2550 : 1 : end:
2551 [ + - ]: 1 : if (rcu.v != NULL) {
2552 : : rte_rcu_qsbr_thread_offline(rcu.v, 0);
2553 : 1 : rte_rcu_qsbr_thread_unregister(rcu.v, 0);
2554 : : }
2555 : 1 : rte_hash_free(hash);
2556 : 1 : rte_free(rcu.v);
2557 : :
2558 : 1 : return ret;
2559 : : }
2560 : :
2561 : : /*
2562 : : * Wrapper functions for tests that take parameters.
2563 : : */
2564 : : static int
2565 : 1 : test_average_table_utilization_no_ext(void)
2566 : : {
2567 : 1 : return test_average_table_utilization(0);
2568 : : }
2569 : :
2570 : : static int
2571 : 1 : test_average_table_utilization_ext(void)
2572 : : {
2573 : 1 : return test_average_table_utilization(1);
2574 : : }
2575 : :
2576 : : static int
2577 : 1 : test_hash_iteration_no_ext(void)
2578 : : {
2579 : 1 : return test_hash_iteration(0);
2580 : : }
2581 : :
2582 : : static int
2583 : 1 : test_hash_iteration_ext(void)
2584 : : {
2585 : 1 : return test_hash_iteration(1);
2586 : : }
2587 : :
2588 : : static int
2589 : 1 : test_hash_rcu_qsbr_dq_mode_no_ext(void)
2590 : : {
2591 : 1 : return test_hash_rcu_qsbr_dq_mode(0);
2592 : : }
2593 : :
2594 : : static int
2595 : 1 : test_hash_rcu_qsbr_dq_mode_ext(void)
2596 : : {
2597 : 1 : return test_hash_rcu_qsbr_dq_mode(1);
2598 : : }
2599 : :
2600 : : static int
2601 : 1 : test_hash_rcu_qsbr_sync_mode_no_ext(void)
2602 : : {
2603 : 1 : return test_hash_rcu_qsbr_sync_mode(0);
2604 : : }
2605 : :
2606 : : static int
2607 : 1 : test_hash_rcu_qsbr_sync_mode_ext(void)
2608 : : {
2609 : 1 : return test_hash_rcu_qsbr_sync_mode(1);
2610 : : }
2611 : :
2612 : : static int
2613 : 1 : test_hash_func_tests(void)
2614 : : {
2615 : 1 : run_hash_func_tests();
2616 : 1 : return TEST_SUCCESS;
2617 : : }
2618 : :
2619 : : static_assert(sizeof(struct flow_key) % sizeof(uint32_t) == 0,
2620 : : "flow_key size must be a multiple of 4 bytes");
2621 : :
2622 : : static struct unit_test_suite hash_test_suite = {
2623 : : .suite_name = "Hash Unit Test Suite",
2624 : : .unit_test_cases = {
2625 : : TEST_CASE(test_add_delete),
2626 : : TEST_CASE(test_hash_add_delete_jhash2),
2627 : : TEST_CASE(test_hash_add_delete_2_jhash2),
2628 : : TEST_CASE(test_hash_add_delete_jhash_1word),
2629 : : TEST_CASE(test_hash_add_delete_jhash_2word),
2630 : : TEST_CASE(test_hash_add_delete_jhash_3word),
2631 : : TEST_CASE(test_hash_get_key_with_position),
2632 : : TEST_CASE(test_hash_find_existing),
2633 : : TEST_CASE(test_add_update_delete),
2634 : : TEST_CASE(test_add_update_delete_free),
2635 : : TEST_CASE(test_add_delete_free_lf),
2636 : : TEST_CASE(test_five_keys),
2637 : : TEST_CASE(test_full_bucket),
2638 : : TEST_CASE(test_extendable_bucket),
2639 : : TEST_CASE(test_fbk_hash_find_existing),
2640 : : TEST_CASE(fbk_hash_unit_test),
2641 : : TEST_CASE(test_hash_creation_with_bad_parameters),
2642 : : TEST_CASE(test_hash_creation_with_good_parameters),
2643 : : TEST_CASE(test_hash_creation_with_key_lengths),
2644 : : TEST_CASE(test_average_table_utilization_no_ext),
2645 : : TEST_CASE(test_hash_iteration_no_ext),
2646 : : TEST_CASE(test_average_table_utilization_ext),
2647 : : TEST_CASE(test_hash_iteration_ext),
2648 : : TEST_CASE(test_hash_func_tests),
2649 : : TEST_CASE(test_crc32_hash_alg_equiv),
2650 : : TEST_CASE(test_hash_rcu_qsbr_add),
2651 : : TEST_CASE(test_hash_rcu_qsbr_dq_mode_no_ext),
2652 : : TEST_CASE(test_hash_rcu_qsbr_dq_mode_ext),
2653 : : TEST_CASE(test_hash_rcu_qsbr_sync_mode_no_ext),
2654 : : TEST_CASE(test_hash_rcu_qsbr_sync_mode_ext),
2655 : : TEST_CASE(test_hash_rcu_qsbr_dq_reclaim),
2656 : : TEST_CASE(test_hash_rcu_qsbr_replace_auto_free),
2657 : : TEST_CASES_END()
2658 : : }
2659 : : };
2660 : :
2661 : : /*
2662 : : * Do all unit and performance tests.
2663 : : */
2664 : : static int
2665 : 1 : test_hash(void)
2666 : : {
2667 : 1 : return unit_test_suite_runner(&hash_test_suite);
2668 : : }
2669 : :
2670 : 301 : REGISTER_FAST_TEST(hash_autotest, NOHUGE_OK, ASAN_OK, test_hash);
|