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 : 529134 : 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 : 529134 : return 3 | (3 << 16);
99 : : }
100 : :
101 [ - + ]: 251 : 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 to create two hashes with identical names
1124 : : * in this case, trying to create a second one will not
1125 : : * fail but will simply return pointer to the existing
1126 : : * hash with that name. sort of like a "find hash by name" :-)
1127 : : */
1128 : 1 : struct rte_fbk_hash_params invalid_params_same_name_1 = {
1129 : : .name = "same_name", /* hash with identical name */
1130 : : .entries = 4,
1131 : : .entries_per_bucket = 2,
1132 : : .socket_id = 0,
1133 : : };
1134 : :
1135 : : /* trying to create this hash should return a pointer to an existing hash */
1136 : 1 : struct rte_fbk_hash_params invalid_params_same_name_2 = {
1137 : : .name = "same_name", /* hash with identical name */
1138 : : .entries = RTE_FBK_HASH_ENTRIES_MAX,
1139 : : .entries_per_bucket = 4,
1140 : : .socket_id = 0,
1141 : : };
1142 : :
1143 : : /* this is a sanity check for "same name" test
1144 : : * creating this hash will check if we are actually able to create
1145 : : * multiple hashes with different names (instead of having just one).
1146 : : */
1147 : 1 : struct rte_fbk_hash_params different_name = {
1148 : : .name = "different_name", /* different name */
1149 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1150 : : .entries_per_bucket = 4,
1151 : : .socket_id = 0,
1152 : : };
1153 : :
1154 : 1 : struct rte_fbk_hash_params params_jhash = {
1155 : : .name = "valid",
1156 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1157 : : .entries_per_bucket = 4,
1158 : : .socket_id = 0,
1159 : : .hash_func = rte_jhash_1word, /* Tests for different hash_func */
1160 : : .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1161 : : };
1162 : :
1163 : 1 : struct rte_fbk_hash_params params_nohash = {
1164 : : .name = "valid nohash",
1165 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1166 : : .entries_per_bucket = 4,
1167 : : .socket_id = 0,
1168 : : .hash_func = NULL, /* Tests for null hash_func */
1169 : : .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1170 : : };
1171 : :
1172 : : struct rte_fbk_hash_table *handle, *tmp;
1173 : 1 : uint32_t keys[5] =
1174 : : {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
1175 : 1 : uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
1176 : : int status;
1177 : : unsigned i;
1178 : : double used_entries;
1179 : :
1180 : : /* Try creating hashes with invalid parameters */
1181 : : printf("# Testing hash creation with invalid parameters "
1182 : : "- expect error msgs\n");
1183 : 1 : handle = rte_fbk_hash_create(&invalid_params_1);
1184 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1185 : :
1186 : 1 : handle = rte_fbk_hash_create(&invalid_params_2);
1187 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1188 : :
1189 : 1 : handle = rte_fbk_hash_create(&invalid_params_3);
1190 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1191 : :
1192 : 1 : handle = rte_fbk_hash_create(&invalid_params_4);
1193 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1194 : :
1195 : 1 : handle = rte_fbk_hash_create(&invalid_params_5);
1196 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1197 : :
1198 : 1 : handle = rte_fbk_hash_create(&invalid_params_6);
1199 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1200 : :
1201 : 1 : handle = rte_fbk_hash_create(&invalid_params_7);
1202 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1203 : :
1204 [ - + ]: 1 : if (rte_eal_has_hugepages()) {
1205 : 0 : handle = rte_fbk_hash_create(&invalid_params_8);
1206 [ # # ]: 0 : RETURN_IF_ERROR_FBK(handle != NULL,
1207 : : "fbk hash creation should have failed");
1208 : : }
1209 : :
1210 : 1 : handle = rte_fbk_hash_create(&invalid_params_same_name_1);
1211 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
1212 : :
1213 : 1 : tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
1214 : 1 : rte_fbk_hash_free(tmp);
1215 [ - + ]: 1 : RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed");
1216 : :
1217 : : /* we are not freeing handle here because we need a hash list
1218 : : * to be not empty for the next test */
1219 : :
1220 : : /* create a hash in non-empty list - good for coverage */
1221 : 1 : tmp = rte_fbk_hash_create(&different_name);
1222 [ - + ]: 1 : RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
1223 : :
1224 : : /* free both hashes */
1225 : 1 : rte_fbk_hash_free(handle);
1226 : 1 : rte_fbk_hash_free(tmp);
1227 : :
1228 : : /* Create empty jhash hash. */
1229 : 1 : handle = rte_fbk_hash_create(¶ms_jhash);
1230 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
1231 : :
1232 : : /* Cleanup. */
1233 : 1 : rte_fbk_hash_free(handle);
1234 : :
1235 : : /* Create empty jhash hash. */
1236 : 1 : handle = rte_fbk_hash_create(¶ms_nohash);
1237 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
1238 : :
1239 : : /* Cleanup. */
1240 : 1 : rte_fbk_hash_free(handle);
1241 : :
1242 : : /* Create empty hash. */
1243 : 1 : handle = rte_fbk_hash_create(¶ms);
1244 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1245 : :
1246 : 1 : used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1247 [ - + ]: 1 : RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1248 : : "load factor right after creation is not zero but it should be");
1249 : : /* Add keys. */
1250 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1251 : 5 : status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1252 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1253 : : }
1254 : :
1255 : 1 : used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1256 [ - + ]: 1 : RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
1257 : : "load factor now is not as expected");
1258 : : /* Find value of added keys. */
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 != vals[i],
1262 : : "fbk hash lookup failed");
1263 : : }
1264 : :
1265 : : /* Change value of added keys. */
1266 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1267 : 5 : status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
1268 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
1269 : : }
1270 : :
1271 : : /* Find new values. */
1272 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1273 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1274 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != vals[4-i],
1275 : : "fbk hash lookup failed");
1276 : : }
1277 : :
1278 : : /* Delete keys individually. */
1279 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1280 : 5 : status = rte_fbk_hash_delete_key(handle, keys[i]);
1281 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
1282 : : }
1283 : :
1284 : 1 : used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1285 [ - + ]: 1 : RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1286 : : "load factor right after deletion is not zero but it should be");
1287 : : /* Lookup should now fail. */
1288 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1289 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1290 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status == 0,
1291 : : "fbk hash lookup should have failed");
1292 : : }
1293 : :
1294 : : /* Add keys again. */
1295 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1296 : 5 : status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1297 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1298 : : }
1299 : :
1300 : : /* Make sure they were added. */
1301 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1302 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1303 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status != vals[i],
1304 : : "fbk hash lookup failed");
1305 : : }
1306 : :
1307 : : /* Clear all entries. */
1308 : : rte_fbk_hash_clear_all(handle);
1309 : :
1310 : : /* Lookup should fail. */
1311 [ + + ]: 6 : for (i = 0; i < 5; i++) {
1312 : 5 : status = rte_fbk_hash_lookup(handle, keys[i]);
1313 [ - + ]: 5 : RETURN_IF_ERROR_FBK(status == 0,
1314 : : "fbk hash lookup should have failed");
1315 : : }
1316 : :
1317 : : /* coverage */
1318 : :
1319 : : /* fill up the hash_table */
1320 [ + + ]: 1048578 : for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
1321 : 1048577 : rte_fbk_hash_add_key(handle, i, (uint16_t) i);
1322 : :
1323 : : /* Find non-existent key in a full hashtable */
1324 : 1 : status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1325 [ - + ]: 1 : RETURN_IF_ERROR_FBK(status != -ENOENT,
1326 : : "fbk hash lookup succeeded");
1327 : :
1328 : : /* Delete non-existent key in a full hashtable */
1329 : 1 : status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1330 [ - + ]: 1 : RETURN_IF_ERROR_FBK(status != -ENOENT,
1331 : : "fbk hash delete succeeded");
1332 : :
1333 : : /* Delete one key from a full hashtable */
1334 : 1 : status = rte_fbk_hash_delete_key(handle, 1);
1335 [ - + ]: 1 : RETURN_IF_ERROR_FBK(status != 0,
1336 : : "fbk hash delete failed");
1337 : :
1338 : : /* Clear all entries. */
1339 : : rte_fbk_hash_clear_all(handle);
1340 : :
1341 : : /* Cleanup. */
1342 : 1 : rte_fbk_hash_free(handle);
1343 : :
1344 : : /* Cover the NULL case. */
1345 : 1 : rte_fbk_hash_free(0);
1346 : :
1347 : 1 : return 0;
1348 : : }
1349 : :
1350 : : /*
1351 : : * Sequence of operations for find existing fbk hash table
1352 : : *
1353 : : * - create table
1354 : : * - find existing table: hit
1355 : : * - find non-existing table: miss
1356 : : *
1357 : : */
1358 : 1 : static int test_fbk_hash_find_existing(void)
1359 : : {
1360 : 1 : struct rte_fbk_hash_params params = {
1361 : : .name = "fbk_hash_find_existing",
1362 : : .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1363 : : .entries_per_bucket = 4,
1364 : : .socket_id = 0,
1365 : : };
1366 : : struct rte_fbk_hash_table *handle = NULL, *result = NULL;
1367 : :
1368 : : /* Create hash table. */
1369 : 1 : handle = rte_fbk_hash_create(¶ms);
1370 [ - + ]: 1 : RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1371 : :
1372 : : /* Try to find existing fbk hash table */
1373 : 1 : result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
1374 [ - + ]: 1 : RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
1375 : :
1376 : : /* Try to find non-existing fbk hash table */
1377 : 1 : result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
1378 [ - + ]: 1 : RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
1379 : :
1380 : : /* Cleanup. */
1381 : 1 : rte_fbk_hash_free(handle);
1382 : :
1383 : 1 : return 0;
1384 : : }
1385 : :
1386 : : #define BUCKET_ENTRIES 4
1387 : : /*
1388 : : * Do tests for hash creation with bad parameters.
1389 : : */
1390 : 1 : static int test_hash_creation_with_bad_parameters(void)
1391 : : {
1392 : : struct rte_hash *handle, *tmp;
1393 : : struct rte_hash_parameters params;
1394 : :
1395 : 1 : handle = rte_hash_create(NULL);
1396 [ - + ]: 1 : if (handle != NULL) {
1397 : 0 : rte_hash_free(handle);
1398 : : printf("Impossible creating hash successfully without any parameter\n");
1399 : 0 : return -1;
1400 : : }
1401 : :
1402 : : memcpy(¶ms, &ut_params, sizeof(params));
1403 : 1 : params.name = "creation_with_bad_parameters_0";
1404 : 1 : params.entries = RTE_HASH_ENTRIES_MAX + 1;
1405 : 1 : handle = rte_hash_create(¶ms);
1406 [ - + ]: 1 : if (handle != NULL) {
1407 : 0 : rte_hash_free(handle);
1408 : : printf("Impossible creating hash successfully with entries in parameter exceeded\n");
1409 : 0 : return -1;
1410 : : }
1411 : :
1412 : : memcpy(¶ms, &ut_params, sizeof(params));
1413 : 1 : params.name = "creation_with_bad_parameters_2";
1414 : 1 : params.entries = BUCKET_ENTRIES - 1;
1415 : 1 : handle = rte_hash_create(¶ms);
1416 [ - + ]: 1 : if (handle != NULL) {
1417 : 0 : rte_hash_free(handle);
1418 : : printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n");
1419 : 0 : return -1;
1420 : : }
1421 : :
1422 : : memcpy(¶ms, &ut_params, sizeof(params));
1423 : 1 : params.name = "creation_with_bad_parameters_3";
1424 : 1 : params.key_len = 0;
1425 : 1 : handle = rte_hash_create(¶ms);
1426 [ - + ]: 1 : if (handle != NULL) {
1427 : 0 : rte_hash_free(handle);
1428 : : printf("Impossible creating hash successfully if key_len in parameter is zero\n");
1429 : 0 : return -1;
1430 : : }
1431 : :
1432 : : memcpy(¶ms, &ut_params, sizeof(params));
1433 : 1 : params.name = "creation_with_bad_parameters_4";
1434 : 1 : params.socket_id = RTE_MAX_NUMA_NODES + 1;
1435 : 1 : handle = rte_hash_create(¶ms);
1436 [ - + ]: 1 : if (handle != NULL) {
1437 : 0 : rte_hash_free(handle);
1438 : : printf("Impossible creating hash successfully with invalid socket\n");
1439 : 0 : return -1;
1440 : : }
1441 : :
1442 : : /* test with same name should fail */
1443 : : memcpy(¶ms, &ut_params, sizeof(params));
1444 : 1 : params.name = "same_name";
1445 : 1 : handle = rte_hash_create(¶ms);
1446 [ - + ]: 1 : if (handle == NULL) {
1447 : : printf("Cannot create first hash table with 'same_name'\n");
1448 : 0 : return -1;
1449 : : }
1450 : 1 : tmp = rte_hash_create(¶ms);
1451 [ - + ]: 1 : if (tmp != NULL) {
1452 : : printf("Creation of hash table with same name should fail\n");
1453 : 0 : rte_hash_free(handle);
1454 : 0 : rte_hash_free(tmp);
1455 : 0 : return -1;
1456 : : }
1457 : 1 : rte_hash_free(handle);
1458 : :
1459 : : printf("# Test successful. No more errors expected\n");
1460 : :
1461 : 1 : return 0;
1462 : : }
1463 : :
1464 : : /*
1465 : : * Do tests for hash creation with parameters that look incorrect
1466 : : * but are actually valid.
1467 : : */
1468 : : static int
1469 : 1 : test_hash_creation_with_good_parameters(void)
1470 : : {
1471 : : struct rte_hash *handle;
1472 : : struct rte_hash_parameters params;
1473 : :
1474 : : /* create with null hash function - should choose DEFAULT_HASH_FUNC */
1475 : : memcpy(¶ms, &ut_params, sizeof(params));
1476 : 1 : params.name = "name";
1477 : 1 : params.hash_func = NULL;
1478 : 1 : handle = rte_hash_create(¶ms);
1479 [ - + ]: 1 : if (handle == NULL) {
1480 : : printf("Creating hash with null hash_func failed\n");
1481 : 0 : return -1;
1482 : : }
1483 : :
1484 : 1 : rte_hash_free(handle);
1485 : :
1486 : 1 : return 0;
1487 : : }
1488 : :
1489 : : #define ITERATIONS 3
1490 : : /*
1491 : : * Test to see the average table utilization (entries added/max entries)
1492 : : * before hitting a random entry that cannot be added
1493 : : */
1494 : 2 : static int test_average_table_utilization(uint32_t ext_table)
1495 : : {
1496 : : struct rte_hash *handle;
1497 : : uint8_t simple_key[MAX_KEYSIZE];
1498 : : unsigned i, j;
1499 : : unsigned added_keys, average_keys_added = 0;
1500 : : int ret;
1501 : : unsigned int cnt;
1502 : :
1503 : : printf("\n# Running test to determine average utilization"
1504 : : "\n before adding elements begins to fail\n");
1505 [ + + ]: 2 : if (ext_table)
1506 : : printf("ext table is enabled\n");
1507 : : else
1508 : : printf("ext table is disabled\n");
1509 : :
1510 : : printf("Measuring performance, please wait");
1511 : 2 : fflush(stdout);
1512 : 2 : ut_params.entries = 1 << 16;
1513 : 2 : ut_params.name = "test_average_utilization";
1514 : 2 : ut_params.hash_func = rte_jhash;
1515 [ + + ]: 2 : if (ext_table)
1516 : 1 : ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1517 : : else
1518 : 1 : ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1519 : :
1520 : 2 : handle = rte_hash_create(&ut_params);
1521 : :
1522 [ - + ]: 2 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1523 : :
1524 [ + + ]: 8 : for (j = 0; j < ITERATIONS; j++) {
1525 : : ret = 0;
1526 : : /* Add random entries until key cannot be added */
1527 : 389938 : for (added_keys = 0; ret >= 0; added_keys++) {
1528 [ + + ]: 6629048 : for (i = 0; i < ut_params.key_len; i++)
1529 : 6239104 : simple_key[i] = rte_rand() % 255;
1530 : 389944 : ret = rte_hash_add_key(handle, simple_key);
1531 [ + + ]: 389944 : if (ret < 0)
1532 : : break;
1533 : : }
1534 : :
1535 [ - + ]: 6 : if (ret != -ENOSPC) {
1536 : : printf("Unexpected error when adding keys\n");
1537 : 0 : rte_hash_free(handle);
1538 : 0 : return -1;
1539 : : }
1540 : :
1541 : 6 : cnt = rte_hash_count(handle);
1542 [ - + ]: 6 : if (cnt != added_keys) {
1543 : : printf("rte_hash_count returned wrong value %u, %u,"
1544 : : "%u\n", j, added_keys, cnt);
1545 : 0 : rte_hash_free(handle);
1546 : 0 : return -1;
1547 : : }
1548 [ + + ]: 6 : if (ext_table) {
1549 [ - + ]: 3 : if (cnt != ut_params.entries) {
1550 : : printf("rte_hash_count returned wrong value "
1551 : : "%u, %u, %u\n", j, added_keys, cnt);
1552 : 0 : rte_hash_free(handle);
1553 : 0 : return -1;
1554 : : }
1555 : : }
1556 : :
1557 : 6 : average_keys_added += added_keys;
1558 : :
1559 : : /* Reset the table */
1560 : 6 : rte_hash_reset(handle);
1561 : :
1562 : : /* Print a dot to show progress on operations */
1563 : : printf(".");
1564 : 6 : fflush(stdout);
1565 : : }
1566 : :
1567 : 2 : average_keys_added /= ITERATIONS;
1568 : :
1569 : 2 : printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
1570 : 2 : ((double) average_keys_added / ut_params.entries * 100),
1571 : : average_keys_added, ut_params.entries);
1572 : 2 : rte_hash_free(handle);
1573 : :
1574 : 2 : return 0;
1575 : : }
1576 : :
1577 : : #define NUM_ENTRIES 256
1578 : 2 : static int test_hash_iteration(uint32_t ext_table)
1579 : : {
1580 : : struct rte_hash *handle;
1581 : : unsigned i;
1582 : : uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE];
1583 : : const void *next_key;
1584 : : void *next_data;
1585 : : void *data[NUM_ENTRIES];
1586 : : unsigned added_keys;
1587 : 2 : uint32_t iter = 0;
1588 : : int ret = 0;
1589 : :
1590 : 2 : ut_params.entries = NUM_ENTRIES;
1591 : 2 : ut_params.name = "test_hash_iteration";
1592 : 2 : ut_params.hash_func = rte_jhash;
1593 : 2 : ut_params.key_len = 16;
1594 [ + + ]: 2 : if (ext_table)
1595 : 1 : ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1596 : : else
1597 : 1 : ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1598 : :
1599 : 2 : handle = rte_hash_create(&ut_params);
1600 [ - + ]: 2 : RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1601 : :
1602 : : /* Add random entries until key cannot be added */
1603 [ + + ]: 511 : for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) {
1604 : 510 : data[added_keys] = (void *) ((uintptr_t) rte_rand());
1605 [ + + ]: 8670 : for (i = 0; i < ut_params.key_len; i++)
1606 : 8160 : keys[added_keys][i] = rte_rand() % 255;
1607 : 510 : ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]);
1608 [ + + ]: 510 : if (ret < 0) {
1609 [ - + ]: 1 : if (ext_table) {
1610 : : printf("Insertion failed for ext table\n");
1611 : 0 : goto err;
1612 : : }
1613 : : break;
1614 : : }
1615 : : }
1616 : :
1617 : : /* Iterate through the hash table */
1618 [ + + ]: 511 : while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
1619 : : /* Search for the key in the list of keys added */
1620 [ + - ]: 65027 : for (i = 0; i < NUM_ENTRIES; i++) {
1621 [ + + ]: 65027 : if (memcmp(next_key, keys[i], ut_params.key_len) == 0) {
1622 [ - + ]: 509 : if (next_data != data[i]) {
1623 : : printf("Data found in the hash table is"
1624 : : "not the data added with the key\n");
1625 : 0 : goto err;
1626 : : }
1627 : 509 : added_keys--;
1628 : 509 : break;
1629 : : }
1630 : : }
1631 [ - + ]: 509 : if (i == NUM_ENTRIES) {
1632 : : printf("Key found in the hash table was not added\n");
1633 : 0 : goto err;
1634 : : }
1635 : : }
1636 : :
1637 : : /* Check if all keys have been iterated */
1638 [ - + ]: 2 : if (added_keys != 0) {
1639 : : printf("There were still %u keys to iterate\n", added_keys);
1640 : 0 : goto err;
1641 : : }
1642 : :
1643 : 2 : rte_hash_free(handle);
1644 : 2 : return 0;
1645 : :
1646 : 0 : err:
1647 : 0 : rte_hash_free(handle);
1648 : 0 : return -1;
1649 : : }
1650 : :
1651 : : static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
1652 : : 0x04, 0x05, 0x06, 0x07,
1653 : : 0x08, 0x09, 0x0a, 0x0b,
1654 : : 0x0c, 0x0d, 0x0e, 0x0f};
1655 : : static struct rte_hash_parameters hash_params_ex = {
1656 : : .name = NULL,
1657 : : .entries = 64,
1658 : : .key_len = 0,
1659 : : .hash_func = NULL,
1660 : : .hash_func_init_val = 0,
1661 : : .socket_id = 0,
1662 : : };
1663 : :
1664 : : /*
1665 : : * Wrapper function around rte_jhash_32b.
1666 : : * It is required because rte_jhash_32b() accepts the length
1667 : : * as size of 4-byte units.
1668 : : */
1669 : : static inline uint32_t
1670 : 4 : test_jhash_32b(const void *k, uint32_t length, uint32_t initval)
1671 : : {
1672 : 4 : return rte_jhash_32b(k, length >> 2, initval);
1673 : : }
1674 : :
1675 : : /*
1676 : : * add/delete key with jhash2
1677 : : */
1678 : : static int
1679 : 1 : test_hash_add_delete_jhash2(void)
1680 : : {
1681 : : int ret = -1;
1682 : : struct rte_hash *handle;
1683 : : int32_t pos1, pos2;
1684 : :
1685 : 1 : hash_params_ex.name = "hash_test_jhash2";
1686 : 1 : hash_params_ex.key_len = 4;
1687 : 1 : hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b;
1688 : :
1689 : 1 : handle = rte_hash_create(&hash_params_ex);
1690 [ - + ]: 1 : if (handle == NULL) {
1691 : : printf("test_hash_add_delete_jhash2 fail to create hash\n");
1692 : 0 : goto fail_jhash2;
1693 : : }
1694 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1695 [ - + ]: 1 : if (pos1 < 0) {
1696 : : printf("test_hash_add_delete_jhash2 fail to add hash key\n");
1697 : 0 : goto fail_jhash2;
1698 : : }
1699 : :
1700 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1701 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2) {
1702 : : printf("test_hash_add_delete_jhash2 delete different key from being added\n");
1703 : 0 : goto fail_jhash2;
1704 : : }
1705 : : ret = 0;
1706 : :
1707 : 1 : fail_jhash2:
1708 : 1 : rte_hash_free(handle);
1709 : :
1710 : 1 : return ret;
1711 : : }
1712 : :
1713 : : /*
1714 : : * add/delete (2) key with jhash2
1715 : : */
1716 : : static int
1717 : 1 : test_hash_add_delete_2_jhash2(void)
1718 : : {
1719 : : int ret = -1;
1720 : : struct rte_hash *handle;
1721 : : int32_t pos1, pos2;
1722 : :
1723 : 1 : hash_params_ex.name = "hash_test_2_jhash2";
1724 : 1 : hash_params_ex.key_len = 8;
1725 : 1 : hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b;
1726 : :
1727 : 1 : handle = rte_hash_create(&hash_params_ex);
1728 [ - + ]: 1 : if (handle == NULL)
1729 : 0 : goto fail_2_jhash2;
1730 : :
1731 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1732 [ - + ]: 1 : if (pos1 < 0)
1733 : 0 : goto fail_2_jhash2;
1734 : :
1735 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1736 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2)
1737 : 0 : goto fail_2_jhash2;
1738 : :
1739 : : ret = 0;
1740 : :
1741 : 1 : fail_2_jhash2:
1742 : 1 : rte_hash_free(handle);
1743 : :
1744 : 1 : return ret;
1745 : : }
1746 : :
1747 : : static uint32_t
1748 : 2 : test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval)
1749 : : {
1750 : : const uint32_t *k = key;
1751 : :
1752 : : RTE_SET_USED(length);
1753 : :
1754 : 2 : return rte_jhash_1word(k[0], initval);
1755 : : }
1756 : :
1757 : : static uint32_t
1758 : 2 : test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval)
1759 : : {
1760 : : const uint32_t *k = key;
1761 : :
1762 : : RTE_SET_USED(length);
1763 : :
1764 : 2 : return rte_jhash_2words(k[0], k[1], initval);
1765 : : }
1766 : :
1767 : : static uint32_t
1768 : 2 : test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval)
1769 : : {
1770 : : const uint32_t *k = key;
1771 : :
1772 : : RTE_SET_USED(length);
1773 : :
1774 : 2 : return rte_jhash_3words(k[0], k[1], k[2], initval);
1775 : : }
1776 : :
1777 : : /*
1778 : : * add/delete key with jhash 1word
1779 : : */
1780 : : static int
1781 : 1 : test_hash_add_delete_jhash_1word(void)
1782 : : {
1783 : : int ret = -1;
1784 : : struct rte_hash *handle;
1785 : : int32_t pos1, pos2;
1786 : :
1787 : 1 : hash_params_ex.name = "hash_test_jhash_1word";
1788 : 1 : hash_params_ex.key_len = 4;
1789 : 1 : hash_params_ex.hash_func = test_hash_jhash_1word;
1790 : :
1791 : 1 : handle = rte_hash_create(&hash_params_ex);
1792 [ - + ]: 1 : if (handle == NULL)
1793 : 0 : goto fail_jhash_1word;
1794 : :
1795 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1796 [ - + ]: 1 : if (pos1 < 0)
1797 : 0 : goto fail_jhash_1word;
1798 : :
1799 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1800 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2)
1801 : 0 : goto fail_jhash_1word;
1802 : :
1803 : : ret = 0;
1804 : :
1805 : 1 : fail_jhash_1word:
1806 : 1 : rte_hash_free(handle);
1807 : :
1808 : 1 : return ret;
1809 : : }
1810 : :
1811 : : /*
1812 : : * add/delete key with jhash 2word
1813 : : */
1814 : : static int
1815 : 1 : test_hash_add_delete_jhash_2word(void)
1816 : : {
1817 : : int ret = -1;
1818 : : struct rte_hash *handle;
1819 : : int32_t pos1, pos2;
1820 : :
1821 : 1 : hash_params_ex.name = "hash_test_jhash_2word";
1822 : 1 : hash_params_ex.key_len = 8;
1823 : 1 : hash_params_ex.hash_func = test_hash_jhash_2word;
1824 : :
1825 : 1 : handle = rte_hash_create(&hash_params_ex);
1826 [ - + ]: 1 : if (handle == NULL)
1827 : 0 : goto fail_jhash_2word;
1828 : :
1829 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1830 [ - + ]: 1 : if (pos1 < 0)
1831 : 0 : goto fail_jhash_2word;
1832 : :
1833 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1834 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2)
1835 : 0 : goto fail_jhash_2word;
1836 : :
1837 : : ret = 0;
1838 : :
1839 : 1 : fail_jhash_2word:
1840 : 1 : rte_hash_free(handle);
1841 : :
1842 : 1 : return ret;
1843 : : }
1844 : :
1845 : : /*
1846 : : * add/delete key with jhash 3word
1847 : : */
1848 : : static int
1849 : 1 : test_hash_add_delete_jhash_3word(void)
1850 : : {
1851 : : int ret = -1;
1852 : : struct rte_hash *handle;
1853 : : int32_t pos1, pos2;
1854 : :
1855 : 1 : hash_params_ex.name = "hash_test_jhash_3word";
1856 : 1 : hash_params_ex.key_len = 12;
1857 : 1 : hash_params_ex.hash_func = test_hash_jhash_3word;
1858 : :
1859 : 1 : handle = rte_hash_create(&hash_params_ex);
1860 [ - + ]: 1 : if (handle == NULL)
1861 : 0 : goto fail_jhash_3word;
1862 : :
1863 : 1 : pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1864 [ - + ]: 1 : if (pos1 < 0)
1865 : 0 : goto fail_jhash_3word;
1866 : :
1867 : 1 : pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1868 [ - + ]: 1 : if (pos2 < 0 || pos1 != pos2)
1869 : 0 : goto fail_jhash_3word;
1870 : :
1871 : : ret = 0;
1872 : :
1873 : 1 : fail_jhash_3word:
1874 : 1 : rte_hash_free(handle);
1875 : :
1876 : 1 : return ret;
1877 : : }
1878 : :
1879 : : static struct rte_hash *g_handle;
1880 : : static struct rte_rcu_qsbr *g_qsv;
1881 : : static volatile uint8_t writer_done;
1882 : : struct flow_key g_rand_keys[9];
1883 : :
1884 : : /*
1885 : : * rte_hash_rcu_qsbr_add positive and negative tests.
1886 : : * - Add RCU QSBR variable to Hash
1887 : : * - Add another RCU QSBR variable to Hash
1888 : : * - Check returns
1889 : : */
1890 : : static int
1891 : 1 : test_hash_rcu_qsbr_add(void)
1892 : : {
1893 : : size_t sz;
1894 : : struct rte_rcu_qsbr *qsv2 = NULL;
1895 : : int32_t status;
1896 : 1 : struct rte_hash_rcu_config rcu_cfg = {0};
1897 : : struct rte_hash_parameters params;
1898 : :
1899 : : printf("\n# Running RCU QSBR add tests\n");
1900 : : memcpy(¶ms, &ut_params, sizeof(params));
1901 : 1 : params.name = "test_hash_rcu_qsbr_add";
1902 : 1 : params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
1903 : : RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
1904 : 1 : g_handle = rte_hash_create(¶ms);
1905 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
1906 : :
1907 : : /* Create RCU QSBR variable */
1908 : 1 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
1909 : 1 : g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
1910 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
1911 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
1912 : : "RCU QSBR variable creation failed");
1913 : :
1914 : 1 : status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
1915 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
1916 : : "RCU QSBR variable initialization failed");
1917 : :
1918 : 1 : rcu_cfg.v = g_qsv;
1919 : : /* Invalid QSBR mode */
1920 : 1 : rcu_cfg.mode = 0xff;
1921 : 1 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1922 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status == 0, "Invalid QSBR mode test failed");
1923 : :
1924 : 1 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
1925 : : /* Attach RCU QSBR to hash table */
1926 : 1 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1927 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
1928 : : "Attach RCU QSBR to hash table failed");
1929 : :
1930 : : /* Create and attach another RCU QSBR to hash table */
1931 : 1 : qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
1932 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
1933 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(qsv2 == NULL,
1934 : : "RCU QSBR variable creation failed");
1935 : :
1936 : 1 : rcu_cfg.v = qsv2;
1937 : 1 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
1938 : 1 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1939 : 1 : rte_free(qsv2);
1940 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status == 0,
1941 : : "Attach RCU QSBR to hash table succeeded where failure"
1942 : : " is expected");
1943 : :
1944 : 1 : rte_hash_free(g_handle);
1945 : 1 : rte_free(g_qsv);
1946 : :
1947 : 1 : return 0;
1948 : : }
1949 : :
1950 : : /*
1951 : : * rte_hash_rcu_qsbr_add DQ mode functional test.
1952 : : * Reader and writer are in the same thread in this test.
1953 : : * - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
1954 : : * - Add RCU QSBR variable to hash
1955 : : * - Add 8 hash entries and fill the bucket
1956 : : * - If ext bkt is enabled, add 1 extra entry that is available in the ext bkt
1957 : : * - Register a reader thread (not a real thread)
1958 : : * - Reader lookup existing entry
1959 : : * - Writer deletes the entry
1960 : : * - Reader lookup the entry
1961 : : * - Writer re-add the entry (no available free index)
1962 : : * - Reader report quiescent state and unregister
1963 : : * - Writer re-add the entry
1964 : : * - Reader lookup the entry
1965 : : */
1966 : : static int
1967 : 2 : test_hash_rcu_qsbr_dq_mode(uint8_t ext_bkt)
1968 : 2 : {
1969 [ + + ]: 2 : uint32_t total_entries = (ext_bkt == 0) ? 8 : 9;
1970 : :
1971 : : uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
1972 : :
1973 [ + + ]: 2 : if (ext_bkt)
1974 : : hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1975 : :
1976 : 2 : struct rte_hash_parameters params_pseudo_hash = {
1977 : : .name = "test_hash_rcu_qsbr_dq_mode",
1978 : : .entries = total_entries,
1979 : : .key_len = sizeof(struct flow_key),
1980 : : .hash_func = pseudo_hash,
1981 : : .hash_func_init_val = 0,
1982 : : .socket_id = 0,
1983 : : .extra_flag = hash_extra_flag,
1984 : : };
1985 : 2 : int pos[total_entries];
1986 : 2 : int expected_pos[total_entries];
1987 : : unsigned int i;
1988 : : size_t sz;
1989 : : int32_t status;
1990 : 2 : struct rte_hash_rcu_config rcu_cfg = {0};
1991 : :
1992 : 2 : g_qsv = NULL;
1993 : 2 : g_handle = NULL;
1994 : :
1995 [ + + ]: 19 : for (i = 0; i < total_entries; i++) {
1996 : 17 : g_rand_keys[i].port_dst = i;
1997 : 17 : g_rand_keys[i].port_src = i+1;
1998 : : }
1999 : :
2000 [ + + ]: 2 : if (ext_bkt)
2001 : : printf("\n# Running RCU QSBR DQ mode functional test with"
2002 : : " ext bkt\n");
2003 : : else
2004 : : printf("\n# Running RCU QSBR DQ mode functional test\n");
2005 : :
2006 : 2 : g_handle = rte_hash_create(¶ms_pseudo_hash);
2007 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2008 : :
2009 : : /* Create RCU QSBR variable */
2010 : 2 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2011 : 2 : g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2012 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2013 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
2014 : : "RCU QSBR variable creation failed");
2015 : :
2016 : 2 : status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2017 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2018 : : "RCU QSBR variable initialization failed");
2019 : :
2020 : 2 : rcu_cfg.v = g_qsv;
2021 : 2 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
2022 : : /* Attach RCU QSBR to hash table */
2023 : 2 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2024 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2025 : : "Attach RCU QSBR to hash table failed");
2026 : :
2027 : : /* Fill bucket */
2028 [ + + ]: 19 : for (i = 0; i < total_entries; i++) {
2029 : 17 : pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
2030 : 17 : print_key_info("Add", &g_rand_keys[i], pos[i]);
2031 [ - + - - ]: 17 : RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
2032 : : "failed to add key (pos[%u]=%d)", i,
2033 : : pos[i]);
2034 : 17 : expected_pos[i] = pos[i];
2035 : : }
2036 : :
2037 : : /* Register pseudo reader */
2038 : 2 : status = rte_rcu_qsbr_thread_register(g_qsv, 0);
2039 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2040 : : "RCU QSBR thread registration failed");
2041 : 2 : rte_rcu_qsbr_thread_online(g_qsv, 0);
2042 : :
2043 : : /* Lookup */
2044 : 2 : pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2045 : 2 : print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2046 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2047 : : "failed to find correct key (pos[%u]=%d)", 0,
2048 : : pos[0]);
2049 : :
2050 : : /* Writer update */
2051 : 2 : pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
2052 : 2 : print_key_info("Del", &g_rand_keys[0], pos[0]);
2053 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2054 : : "failed to del correct key (pos[%u]=%d)", 0,
2055 : : pos[0]);
2056 : :
2057 : : /* Lookup */
2058 : 2 : pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2059 : 2 : print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2060 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOENT,
2061 : : "found deleted key (pos[%u]=%d)", 0, pos[0]);
2062 : :
2063 : : /* Fill bucket */
2064 : 2 : pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2065 : 2 : print_key_info("Add", &g_rand_keys[0], pos[0]);
2066 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOSPC,
2067 : : "Added key successfully (pos[%u]=%d)", 0, pos[0]);
2068 : :
2069 : : /* Reader quiescent */
2070 [ + - ]: 2 : rte_rcu_qsbr_quiescent(g_qsv, 0);
2071 : :
2072 : : /* Fill bucket */
2073 : 2 : pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2074 : 2 : print_key_info("Add", &g_rand_keys[0], pos[0]);
2075 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
2076 : : "failed to add key (pos[%u]=%d)", 0, pos[0]);
2077 : 2 : expected_pos[0] = pos[0];
2078 : :
2079 : 2 : rte_rcu_qsbr_thread_offline(g_qsv, 0);
2080 : 2 : (void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
2081 : :
2082 : : /* Lookup */
2083 : 2 : pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2084 : 2 : print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2085 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2086 : : "failed to find correct key (pos[%u]=%d)", 0,
2087 : : pos[0]);
2088 : :
2089 : 2 : rte_hash_free(g_handle);
2090 : 2 : rte_free(g_qsv);
2091 : 2 : return 0;
2092 : :
2093 : : }
2094 : :
2095 : : /* Report quiescent state interval every 1024 lookups. Larger critical
2096 : : * sections in reader will result in writer polling multiple times.
2097 : : */
2098 : : #define QSBR_REPORTING_INTERVAL 1024
2099 : : #define WRITER_ITERATIONS 512
2100 : :
2101 : : /*
2102 : : * Reader thread using rte_hash data structure with RCU.
2103 : : */
2104 : : static int
2105 : 2 : test_hash_rcu_qsbr_reader(void *arg)
2106 : : {
2107 : : int i;
2108 : :
2109 : : RTE_SET_USED(arg);
2110 : : /* Register this thread to report quiescent state */
2111 : 2 : (void)rte_rcu_qsbr_thread_register(g_qsv, 0);
2112 : 2 : rte_rcu_qsbr_thread_online(g_qsv, 0);
2113 : :
2114 : : do {
2115 [ + + ]: 527875 : for (i = 0; i < QSBR_REPORTING_INTERVAL; i++)
2116 : 527360 : rte_hash_lookup(g_handle, &g_rand_keys[0]);
2117 : :
2118 : : /* Update quiescent state */
2119 [ + + ]: 515 : rte_rcu_qsbr_quiescent(g_qsv, 0);
2120 [ + + ]: 515 : } while (!writer_done);
2121 : :
2122 : 2 : rte_rcu_qsbr_thread_offline(g_qsv, 0);
2123 : 2 : (void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
2124 : :
2125 : 2 : return 0;
2126 : : }
2127 : :
2128 : : /*
2129 : : * rte_hash_rcu_qsbr_add sync mode functional test.
2130 : : * 1 Reader and 1 writer. They cannot be in the same thread in this test.
2131 : : * - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
2132 : : * - Add RCU QSBR variable to hash
2133 : : * - Register a reader thread. Reader keeps looking up a specific key.
2134 : : * - Writer keeps adding and deleting a specific key.
2135 : : */
2136 : : static int
2137 : 2 : test_hash_rcu_qsbr_sync_mode(uint8_t ext_bkt)
2138 : 2 : {
2139 [ + + ]: 2 : uint32_t total_entries = (ext_bkt == 0) ? 8 : 9;
2140 : :
2141 : : uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2142 : :
2143 [ + + ]: 2 : if (ext_bkt)
2144 : : hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
2145 : :
2146 : 2 : struct rte_hash_parameters params_pseudo_hash = {
2147 : : .name = "test_hash_rcu_qsbr_sync_mode",
2148 : : .entries = total_entries,
2149 : : .key_len = sizeof(struct flow_key),
2150 : : .hash_func = pseudo_hash,
2151 : : .hash_func_init_val = 0,
2152 : : .socket_id = 0,
2153 : : .extra_flag = hash_extra_flag,
2154 : : };
2155 : 2 : int pos[total_entries];
2156 : 2 : int expected_pos[total_entries];
2157 : : unsigned int i;
2158 : : size_t sz;
2159 : : int32_t status;
2160 : 2 : struct rte_hash_rcu_config rcu_cfg = {0};
2161 : :
2162 : 2 : g_qsv = NULL;
2163 : 2 : g_handle = NULL;
2164 : :
2165 [ + + ]: 19 : for (i = 0; i < total_entries; i++) {
2166 : 17 : g_rand_keys[i].port_dst = i;
2167 : 17 : g_rand_keys[i].port_src = i+1;
2168 : : }
2169 : :
2170 [ + + ]: 2 : if (ext_bkt)
2171 : : printf("\n# Running RCU QSBR sync mode functional test with"
2172 : : " ext bkt\n");
2173 : : else
2174 : : printf("\n# Running RCU QSBR sync mode functional test\n");
2175 : :
2176 : 2 : g_handle = rte_hash_create(¶ms_pseudo_hash);
2177 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2178 : :
2179 : : /* Create RCU QSBR variable */
2180 : 2 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2181 : 2 : g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2182 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2183 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
2184 : : "RCU QSBR variable creation failed");
2185 : :
2186 : 2 : status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2187 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2188 : : "RCU QSBR variable initialization failed");
2189 : :
2190 : 2 : rcu_cfg.v = g_qsv;
2191 : 2 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
2192 : : /* Attach RCU QSBR to hash table */
2193 : 2 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2194 [ - + - - ]: 2 : RETURN_IF_ERROR_RCU_QSBR(status != 0,
2195 : : "Attach RCU QSBR to hash table failed");
2196 : :
2197 : : /* Launch reader thread */
2198 : 2 : rte_eal_remote_launch(test_hash_rcu_qsbr_reader, NULL,
2199 : : rte_get_next_lcore(-1, 1, 0));
2200 : :
2201 : : /* Fill bucket */
2202 [ + + ]: 19 : for (i = 0; i < total_entries; i++) {
2203 : 17 : pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
2204 : 17 : print_key_info("Add", &g_rand_keys[i], pos[i]);
2205 [ - + - - ]: 17 : RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
2206 : : "failed to add key (pos[%u]=%d)", i, pos[i]);
2207 : 17 : expected_pos[i] = pos[i];
2208 : : }
2209 : 2 : writer_done = 0;
2210 : :
2211 : : /* Writer Update */
2212 [ + + ]: 1026 : for (i = 0; i < WRITER_ITERATIONS; i++) {
2213 : 1024 : expected_pos[0] = pos[0];
2214 : 1024 : pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
2215 : 1024 : print_key_info("Del", &g_rand_keys[0], status);
2216 [ - + - - ]: 1024 : RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2217 : : "failed to del correct key (pos[%u]=%d)"
2218 : : , 0, pos[0]);
2219 : :
2220 : 1024 : pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2221 : 1024 : print_key_info("Add", &g_rand_keys[0], pos[0]);
2222 [ - + - - ]: 1024 : RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
2223 : : "failed to add key (pos[%u]=%d)", 0,
2224 : : pos[0]);
2225 : : }
2226 : :
2227 : 2 : writer_done = 1;
2228 : : /* Wait until reader exited. */
2229 : 2 : rte_eal_mp_wait_lcore();
2230 : :
2231 : 2 : rte_hash_free(g_handle);
2232 : 2 : rte_free(g_qsv);
2233 : :
2234 : 2 : return 0;
2235 : :
2236 : : }
2237 : :
2238 : : /*
2239 : : * rte_hash_rcu_qsbr_dq_reclaim unit test.
2240 : : */
2241 : : static int
2242 : 1 : test_hash_rcu_qsbr_dq_reclaim(void)
2243 : : {
2244 : : size_t sz;
2245 : : int32_t status;
2246 : : unsigned int total_entries = 8;
2247 : : unsigned int freed, pending, available;
2248 : 1 : uint32_t reclaim_keys[8] = {10, 11, 12, 13, 14, 15, 16, 17};
2249 : 1 : struct rte_hash_rcu_config rcu_cfg = {0};
2250 : 1 : struct rte_hash_parameters hash_params = {
2251 : : .name = "test_hash_rcu_qsbr_dq_reclaim",
2252 : : .entries = total_entries,
2253 : : .key_len = sizeof(uint32_t),
2254 : : .hash_func = NULL,
2255 : : .hash_func_init_val = 0,
2256 : : .socket_id = 0,
2257 : : };
2258 : :
2259 : 1 : hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2260 : :
2261 : 1 : g_qsv = NULL;
2262 : 1 : g_handle = NULL;
2263 : :
2264 : : printf("\n# Running RCU QSBR DQ mode, reclaim defer queue functional test\n");
2265 : :
2266 : 1 : g_handle = rte_hash_create(&hash_params);
2267 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2268 : :
2269 : : /* Create RCU QSBR variable */
2270 : 1 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2271 : 1 : g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(
2272 : : NULL, sz, RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2273 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL, "RCU QSBR variable creation failed");
2274 : :
2275 : 1 : status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2276 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR variable initialization failed");
2277 : :
2278 : 1 : rcu_cfg.v = g_qsv;
2279 : 1 : rcu_cfg.dq_size = total_entries;
2280 : 1 : rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
2281 : :
2282 : : /* Attach RCU QSBR to hash table */
2283 : 1 : status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2284 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0, "Attach RCU QSBR to hash table failed");
2285 : :
2286 : : /* Register pseudo reader */
2287 : 1 : status = rte_rcu_qsbr_thread_register(g_qsv, 0);
2288 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR thread registration failed");
2289 : 1 : rte_rcu_qsbr_thread_online(g_qsv, 0);
2290 : :
2291 : : /* Fill half of the hash table */
2292 [ + + ]: 5 : for (size_t i = 0; i < total_entries / 2; i++)
2293 : 4 : status = rte_hash_add_key(g_handle, &reclaim_keys[i]);
2294 : :
2295 : : /* Try to put these elements into the defer queue*/
2296 [ + + ]: 5 : for (size_t i = 0; i < total_entries / 2; i++)
2297 : 4 : rte_hash_del_key(g_handle, &reclaim_keys[i]);
2298 : :
2299 : : /* Reader quiescent */
2300 [ + - ]: 1 : rte_rcu_qsbr_quiescent(g_qsv, 0);
2301 : :
2302 : 1 : status = rte_hash_add_key(g_handle, &reclaim_keys[0]);
2303 [ - + - - ]: 1 : RETURN_IF_ERROR_RCU_QSBR(status < 0, "failed to add key (pos[%u]=%d)", 0, status);
2304 : :
2305 : : /* This should be (total_entries / 2) + 1 (last add) */
2306 : 1 : unsigned int hash_size = rte_hash_count(g_handle);
2307 : :
2308 : : /* Freed size should be (total_entries / 2) */
2309 : 1 : rte_hash_rcu_qsbr_dq_reclaim(g_handle, &freed, &pending, &available);
2310 : :
2311 : 1 : rte_hash_free(g_handle);
2312 : 1 : rte_free(g_qsv);
2313 : :
2314 [ + - - + ]: 1 : if (hash_size != (total_entries / 2 + 1) || freed != (total_entries / 2)) {
2315 : : printf("Failed to reclaim defer queue\n");
2316 : 0 : return -1;
2317 : : }
2318 : :
2319 : : return 0;
2320 : : }
2321 : :
2322 : : /*
2323 : : * Do all unit and performance tests.
2324 : : */
2325 : : static int
2326 : 1 : test_hash(void)
2327 : : {
2328 : : RTE_BUILD_BUG_ON(sizeof(struct flow_key) % sizeof(uint32_t) != 0);
2329 : :
2330 [ + - ]: 1 : if (test_add_delete() < 0)
2331 : : return -1;
2332 [ + - ]: 1 : if (test_hash_add_delete_jhash2() < 0)
2333 : : return -1;
2334 [ + - ]: 1 : if (test_hash_add_delete_2_jhash2() < 0)
2335 : : return -1;
2336 [ + - ]: 1 : if (test_hash_add_delete_jhash_1word() < 0)
2337 : : return -1;
2338 [ + - ]: 1 : if (test_hash_add_delete_jhash_2word() < 0)
2339 : : return -1;
2340 [ + - ]: 1 : if (test_hash_add_delete_jhash_3word() < 0)
2341 : : return -1;
2342 [ + - ]: 1 : if (test_hash_get_key_with_position() < 0)
2343 : : return -1;
2344 [ + - ]: 1 : if (test_hash_find_existing() < 0)
2345 : : return -1;
2346 [ + - ]: 1 : if (test_add_update_delete() < 0)
2347 : : return -1;
2348 [ + - ]: 1 : if (test_add_update_delete_free() < 0)
2349 : : return -1;
2350 [ + - ]: 1 : if (test_add_delete_free_lf() < 0)
2351 : : return -1;
2352 [ + - ]: 1 : if (test_five_keys() < 0)
2353 : : return -1;
2354 [ + - ]: 1 : if (test_full_bucket() < 0)
2355 : : return -1;
2356 [ + - ]: 1 : if (test_extendable_bucket() < 0)
2357 : : return -1;
2358 : :
2359 [ + - ]: 1 : if (test_fbk_hash_find_existing() < 0)
2360 : : return -1;
2361 [ + - ]: 1 : if (fbk_hash_unit_test() < 0)
2362 : : return -1;
2363 [ + - ]: 1 : if (test_hash_creation_with_bad_parameters() < 0)
2364 : : return -1;
2365 [ + - ]: 1 : if (test_hash_creation_with_good_parameters() < 0)
2366 : : return -1;
2367 : :
2368 : : /* ext table disabled */
2369 [ + - ]: 1 : if (test_average_table_utilization(0) < 0)
2370 : : return -1;
2371 [ + - ]: 1 : if (test_hash_iteration(0) < 0)
2372 : : return -1;
2373 : :
2374 : : /* ext table enabled */
2375 [ + - ]: 1 : if (test_average_table_utilization(1) < 0)
2376 : : return -1;
2377 [ + - ]: 1 : if (test_hash_iteration(1) < 0)
2378 : : return -1;
2379 : :
2380 : 1 : run_hash_func_tests();
2381 : :
2382 [ + - ]: 1 : if (test_crc32_hash_alg_equiv() < 0)
2383 : : return -1;
2384 : :
2385 [ + - ]: 1 : if (test_hash_rcu_qsbr_add() < 0)
2386 : : return -1;
2387 : :
2388 [ + - ]: 1 : if (test_hash_rcu_qsbr_dq_mode(0) < 0)
2389 : : return -1;
2390 : :
2391 [ + - ]: 1 : if (test_hash_rcu_qsbr_dq_mode(1) < 0)
2392 : : return -1;
2393 : :
2394 [ + - ]: 1 : if (test_hash_rcu_qsbr_sync_mode(0) < 0)
2395 : : return -1;
2396 : :
2397 [ + - ]: 1 : if (test_hash_rcu_qsbr_sync_mode(1) < 0)
2398 : : return -1;
2399 : :
2400 [ - + ]: 1 : if (test_hash_rcu_qsbr_dq_reclaim() < 0)
2401 : 0 : return -1;
2402 : :
2403 : : return 0;
2404 : : }
2405 : :
2406 : 251 : REGISTER_FAST_TEST(hash_autotest, true, true, test_hash);
|