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