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