1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2015 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdint.h> 7 #include <string.h> 8 #include <stdlib.h> 9 #include <stdarg.h> 10 #include <errno.h> 11 #include <sys/queue.h> 12 13 #include <rte_common.h> 14 #include <rte_malloc.h> 15 #include <rte_cycles.h> 16 #include <rte_random.h> 17 #include <rte_memory.h> 18 #include <rte_eal.h> 19 #include <rte_ip.h> 20 #include <rte_string_fns.h> 21 22 #include "test.h" 23 24 #include <rte_hash.h> 25 #include <rte_fbk_hash.h> 26 #include <rte_jhash.h> 27 #include <rte_hash_crc.h> 28 29 /******************************************************************************* 30 * Hash function performance test configuration section. Each performance test 31 * will be performed HASHTEST_ITERATIONS times. 32 * 33 * The five arrays below control what tests are performed. Every combination 34 * from the array entries is tested. 35 */ 36 static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc}; 37 static uint32_t hashtest_initvals[] = {0}; 38 static uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64}; 39 #define MAX_KEYSIZE 64 40 /******************************************************************************/ 41 #define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15) 42 43 /* 44 * Check condition and return an error if true. Assumes that "handle" is the 45 * name of the hash structure pointer to be freed. 46 */ 47 #define RETURN_IF_ERROR(cond, str, ...) do { \ 48 if (cond) { \ 49 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \ 50 if (handle) rte_hash_free(handle); \ 51 return -1; \ 52 } \ 53 } while(0) 54 55 #define RETURN_IF_ERROR_FBK(cond, str, ...) do { \ 56 if (cond) { \ 57 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \ 58 if (handle) rte_fbk_hash_free(handle); \ 59 return -1; \ 60 } \ 61 } while(0) 62 63 #define RETURN_IF_ERROR_RCU_QSBR(cond, str, ...) do { \ 64 if (cond) { \ 65 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \ 66 if (rcu_cfg.mode == RTE_HASH_QSBR_MODE_SYNC) { \ 67 writer_done = 1; \ 68 /* Wait until reader exited. */ \ 69 rte_eal_mp_wait_lcore(); \ 70 } \ 71 rte_hash_free(g_handle); \ 72 rte_free(g_qsv); \ 73 return -1; \ 74 } \ 75 } while (0) 76 77 /* 78 * 5-tuple key type. 79 * Should be packed to avoid holes with potentially 80 * undefined content in the middle. 81 */ 82 struct __rte_packed_begin flow_key { 83 uint32_t ip_src; 84 uint32_t ip_dst; 85 uint16_t port_src; 86 uint16_t port_dst; 87 uint32_t proto; 88 } __rte_packed_end; 89 90 /* 91 * Hash function that always returns the same value, to easily test what 92 * happens when a bucket is full. 93 */ 94 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 return 3 | (3 << 16); 99 } 100 101 RTE_LOG_REGISTER(hash_logtype_test, test.hash, INFO); 102 103 /* 104 * Print out result of unit test hash operation. 105 */ 106 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 rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%s key:0x", msg); 113 for (i = 0; i < sizeof(struct flow_key); i++) 114 rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%02X", p[i]); 115 rte_log(RTE_LOG_DEBUG, hash_logtype_test, " @ pos %d\n", pos); 116 } 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 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 for (i = 0; i < CRC32_ITERATIONS; i++) { 202 /* Randomizing data_len of data set */ 203 data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1); 204 init_val = (uint32_t) rte_rand(); 205 206 /* Fill the data set */ 207 for (j = 0; j < CRC32_DWORDS; j++) 208 data64[j] = rte_rand(); 209 210 /* Calculate software CRC32 */ 211 rte_hash_crc_set_alg(CRC32_SW); 212 hash_val = rte_hash_crc(data64, data_len, init_val); 213 214 /* Check against 4-byte-operand sse4.2 CRC32 if available */ 215 rte_hash_crc_set_alg(CRC32_SSE42); 216 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 rte_hash_crc_set_alg(CRC32_SSE42_x64); 223 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 rte_hash_crc_set_alg(CRC32_ARM64); 230 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 rte_hash_crc_set_alg(CRC32_SSE42_x64); 238 239 if (i == CRC32_ITERATIONS) 240 return 0; 241 242 printf("Failed test data (hex, %zu bytes total):\n", data_len); 243 for (j = 0; j < data_len; j++) 244 printf("%02X%c", ((uint8_t *)data64)[j], 245 ((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' '); 246 247 return -1; 248 } 249 250 /* 251 * Test a hash function. 252 */ 253 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 for (i = 0; i < key_len; i++) 261 key[i] = (uint8_t) rte_rand(); 262 263 /* just to be on the safe side */ 264 if (!f) 265 return; 266 267 f(key, key_len, init_val); 268 } 269 270 /* 271 * Test all hash functions. 272 */ 273 static void run_hash_func_tests(void) 274 { 275 unsigned i, j, k; 276 277 for (i = 0; i < RTE_DIM(hashtest_funcs); i++) { 278 for (j = 0; j < RTE_DIM(hashtest_initvals); j++) { 279 for (k = 0; k < RTE_DIM(hashtest_key_lens); k++) { 280 run_hash_func_test(hashtest_funcs[i], 281 hashtest_initvals[j], 282 hashtest_key_lens[k]); 283 } 284 } 285 } 286 } 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 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 ut_params.name = "test1"; 309 handle = rte_hash_create(&ut_params); 310 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 311 312 pos0 = rte_hash_add_key(handle, &keys[0]); 313 print_key_info("Add", &keys[0], pos0); 314 RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0); 315 expectedPos0 = pos0; 316 317 pos0 = rte_hash_lookup(handle, &keys[0]); 318 print_key_info("Lkp", &keys[0], pos0); 319 RETURN_IF_ERROR(pos0 != expectedPos0, 320 "failed to find key (pos0=%d)", pos0); 321 322 pos0 = rte_hash_del_key(handle, &keys[0]); 323 print_key_info("Del", &keys[0], pos0); 324 RETURN_IF_ERROR(pos0 != expectedPos0, 325 "failed to delete key (pos0=%d)", pos0); 326 327 pos0 = rte_hash_lookup(handle, &keys[0]); 328 print_key_info("Lkp", &keys[0], pos0); 329 RETURN_IF_ERROR(pos0 != -ENOENT, 330 "fail: found key after deleting! (pos0=%d)", pos0); 331 332 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 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL; 339 handle = rte_hash_create(&ut_params); 340 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 341 ut_params.extra_flag = 0; 342 343 hash_value = rte_hash_hash(handle, &keys[0]); 344 pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value); 345 print_key_info("Add", &keys[0], pos1); 346 RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1); 347 expectedPos1 = pos1; 348 349 pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value); 350 print_key_info("Lkp", &keys[0], pos1); 351 RETURN_IF_ERROR(pos1 != expectedPos1, 352 "failed to find key (pos1=%d)", pos1); 353 354 pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value); 355 print_key_info("Del", &keys[0], pos1); 356 RETURN_IF_ERROR(pos1 != expectedPos1, 357 "failed to delete key (pos1=%d)", pos1); 358 delPos1 = pos1; 359 360 pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value); 361 print_key_info("Lkp", &keys[0], pos1); 362 RETURN_IF_ERROR(pos1 != -ENOENT, 363 "fail: found key after deleting! (pos1=%d)", pos1); 364 365 pos1 = rte_hash_free_key_with_position(handle, delPos1); 366 print_key_info("Free", &keys[0], delPos1); 367 RETURN_IF_ERROR(pos1 != 0, 368 "failed to free key (pos1=%d)", delPos1); 369 370 rte_hash_free(handle); 371 372 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 static int test_add_update_delete(void) 387 { 388 struct rte_hash *handle; 389 int pos0, expectedPos0; 390 391 ut_params.name = "test2"; 392 handle = rte_hash_create(&ut_params); 393 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 394 395 pos0 = rte_hash_del_key(handle, &keys[0]); 396 print_key_info("Del", &keys[0], pos0); 397 RETURN_IF_ERROR(pos0 != -ENOENT, 398 "fail: found non-existent key (pos0=%d)", pos0); 399 400 pos0 = rte_hash_add_key(handle, &keys[0]); 401 print_key_info("Add", &keys[0], pos0); 402 RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0); 403 expectedPos0 = pos0; 404 405 pos0 = rte_hash_lookup(handle, &keys[0]); 406 print_key_info("Lkp", &keys[0], pos0); 407 RETURN_IF_ERROR(pos0 != expectedPos0, 408 "failed to find key (pos0=%d)", pos0); 409 410 pos0 = rte_hash_add_key(handle, &keys[0]); 411 print_key_info("Add", &keys[0], pos0); 412 RETURN_IF_ERROR(pos0 != expectedPos0, 413 "failed to re-add key (pos0=%d)", pos0); 414 415 pos0 = rte_hash_lookup(handle, &keys[0]); 416 print_key_info("Lkp", &keys[0], pos0); 417 RETURN_IF_ERROR(pos0 != expectedPos0, 418 "failed to find key (pos0=%d)", pos0); 419 420 pos0 = rte_hash_del_key(handle, &keys[0]); 421 print_key_info("Del", &keys[0], pos0); 422 RETURN_IF_ERROR(pos0 != expectedPos0, 423 "failed to delete key (pos0=%d)", pos0); 424 425 pos0 = rte_hash_del_key(handle, &keys[0]); 426 print_key_info("Del", &keys[0], pos0); 427 RETURN_IF_ERROR(pos0 != -ENOENT, 428 "fail: deleted already deleted key (pos0=%d)", pos0); 429 430 pos0 = rte_hash_lookup(handle, &keys[0]); 431 print_key_info("Lkp", &keys[0], pos0); 432 RETURN_IF_ERROR(pos0 != -ENOENT, 433 "fail: found key after deleting! (pos0=%d)", pos0); 434 435 rte_hash_free(handle); 436 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 static int test_add_update_delete_free(void) 453 { 454 struct rte_hash *handle; 455 int pos0, expectedPos0, delPos0, result; 456 457 ut_params.name = "test2"; 458 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL; 459 handle = rte_hash_create(&ut_params); 460 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 461 ut_params.extra_flag = 0; 462 463 pos0 = rte_hash_del_key(handle, &keys[0]); 464 print_key_info("Del", &keys[0], pos0); 465 RETURN_IF_ERROR(pos0 != -ENOENT, 466 "fail: found non-existent key (pos0=%d)", pos0); 467 468 pos0 = rte_hash_add_key(handle, &keys[0]); 469 print_key_info("Add", &keys[0], pos0); 470 RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0); 471 expectedPos0 = pos0; 472 473 pos0 = rte_hash_lookup(handle, &keys[0]); 474 print_key_info("Lkp", &keys[0], pos0); 475 RETURN_IF_ERROR(pos0 != expectedPos0, 476 "failed to find key (pos0=%d)", pos0); 477 478 pos0 = rte_hash_add_key(handle, &keys[0]); 479 print_key_info("Add", &keys[0], pos0); 480 RETURN_IF_ERROR(pos0 != expectedPos0, 481 "failed to re-add key (pos0=%d)", pos0); 482 483 pos0 = rte_hash_lookup(handle, &keys[0]); 484 print_key_info("Lkp", &keys[0], pos0); 485 RETURN_IF_ERROR(pos0 != expectedPos0, 486 "failed to find key (pos0=%d)", pos0); 487 488 delPos0 = rte_hash_del_key(handle, &keys[0]); 489 print_key_info("Del", &keys[0], delPos0); 490 RETURN_IF_ERROR(delPos0 != expectedPos0, 491 "failed to delete key (pos0=%d)", delPos0); 492 493 pos0 = rte_hash_del_key(handle, &keys[0]); 494 print_key_info("Del", &keys[0], pos0); 495 RETURN_IF_ERROR(pos0 != -ENOENT, 496 "fail: deleted already deleted key (pos0=%d)", pos0); 497 498 pos0 = rte_hash_lookup(handle, &keys[0]); 499 print_key_info("Lkp", &keys[0], pos0); 500 RETURN_IF_ERROR(pos0 != -ENOENT, 501 "fail: found key after deleting! (pos0=%d)", pos0); 502 503 result = rte_hash_free_key_with_position(handle, delPos0); 504 print_key_info("Free", &keys[0], delPos0); 505 RETURN_IF_ERROR(result != 0, 506 "failed to free key (pos1=%d)", delPos0); 507 508 pos0 = rte_hash_lookup(handle, &keys[0]); 509 print_key_info("Lkp", &keys[0], pos0); 510 RETURN_IF_ERROR(pos0 != -ENOENT, 511 "fail: found key after deleting! (pos0=%d)", pos0); 512 513 rte_hash_free(handle); 514 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 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 extra_flag = ut_params.extra_flag; 538 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF; 539 handle = rte_hash_create(&ut_params); 540 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 541 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 for (i = 0; i < ut_params.entries + 1; i++) { 549 hash_value = rte_hash_hash(handle, &keys[0]); 550 pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value); 551 print_key_info("Add", &keys[0], pos); 552 RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos); 553 expectedPos = pos; 554 555 pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value); 556 print_key_info("Del", &keys[0], pos); 557 RETURN_IF_ERROR(pos != expectedPos, 558 "failed to delete key (pos=%d)", pos); 559 delPos = pos; 560 561 pos = rte_hash_free_key_with_position(handle, delPos); 562 print_key_info("Free", &keys[0], delPos); 563 RETURN_IF_ERROR(pos != 0, 564 "failed to free key (pos=%d)", delPos); 565 } 566 567 rte_hash_free(handle); 568 569 extra_flag = ut_params.extra_flag; 570 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF | 571 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD; 572 handle = rte_hash_create(&ut_params); 573 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 574 ut_params.extra_flag = extra_flag; 575 576 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 for (i = 0; i < ut_params.entries + (RTE_MAX_LCORE - 1) * 583 (LCORE_CACHE_SIZE - 1) + 1; i++) { 584 keys[0].ip_src++; 585 hash_value = rte_hash_hash(handle, &keys[0]); 586 pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value); 587 print_key_info("Add", &keys[0], pos); 588 RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos); 589 expectedPos = pos; 590 591 pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value); 592 print_key_info("Del", &keys[0], pos); 593 RETURN_IF_ERROR(pos != expectedPos, 594 "failed to delete key (pos=%d)", pos); 595 delPos = pos; 596 597 pos = rte_hash_free_key_with_position(handle, delPos); 598 print_key_info("Free", &keys[0], delPos); 599 RETURN_IF_ERROR(pos != 0, 600 "failed to free key (pos=%d)", delPos); 601 } 602 keys[0].ip_src = ip_src; 603 604 rte_hash_free(handle); 605 606 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 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 ut_params.name = "hash_get_key_w_pos"; 635 handle = rte_hash_create(&ut_params); 636 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 637 638 pos = rte_hash_add_key(handle, &keys[0]); 639 print_key_info("Add", &keys[0], pos); 640 RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos); 641 expectedPos = pos; 642 643 result = rte_hash_get_key_with_position(handle, pos, &key); 644 RETURN_IF_ERROR(result != 0, "error retrieving a key"); 645 646 pos = rte_hash_del_key(handle, &keys[0]); 647 print_key_info("Del", &keys[0], pos); 648 RETURN_IF_ERROR(pos != expectedPos, 649 "failed to delete key (pos0=%d)", pos); 650 651 result = rte_hash_get_key_with_position(handle, pos, &key); 652 RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved"); 653 654 rte_hash_free(handle); 655 656 ut_params.name = "hash_get_key_w_pos"; 657 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL; 658 handle = rte_hash_create(&ut_params); 659 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 660 ut_params.extra_flag = 0; 661 662 pos = rte_hash_add_key(handle, &keys[0]); 663 print_key_info("Add", &keys[0], pos); 664 RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos); 665 expectedPos = pos; 666 667 result = rte_hash_get_key_with_position(handle, pos, &key); 668 RETURN_IF_ERROR(result != 0, "error retrieving a key"); 669 670 delPos = rte_hash_del_key(handle, &keys[0]); 671 print_key_info("Del", &keys[0], delPos); 672 RETURN_IF_ERROR(delPos != expectedPos, 673 "failed to delete key (pos0=%d)", delPos); 674 675 result = rte_hash_get_key_with_position(handle, delPos, &key); 676 RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved"); 677 678 result = rte_hash_free_key_with_position(handle, delPos); 679 print_key_info("Free", &keys[0], delPos); 680 RETURN_IF_ERROR(result != 0, 681 "failed to free key (pos1=%d)", delPos); 682 683 result = rte_hash_get_key_with_position(handle, delPos, &key); 684 RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved"); 685 686 rte_hash_free(handle); 687 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 static int test_hash_find_existing(void) 699 { 700 struct rte_hash *handle = NULL, *result = NULL; 701 702 /* Create hash table. */ 703 ut_params.name = "hash_find_existing"; 704 handle = rte_hash_create(&ut_params); 705 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 706 707 /* Try to find existing hash table */ 708 result = rte_hash_find_existing("hash_find_existing"); 709 RETURN_IF_ERROR(result != handle, "could not find existing hash table"); 710 711 /* Try to find non-existing hash table */ 712 result = rte_hash_find_existing("hash_find_non_existing"); 713 RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist"); 714 715 /* Cleanup. */ 716 rte_hash_free(handle); 717 718 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 static int test_five_keys(void) 731 { 732 struct rte_hash *handle; 733 const void *key_array[5] = {0}; 734 int pos[5]; 735 int expected_pos[5]; 736 unsigned i; 737 int ret; 738 739 ut_params.name = "test3"; 740 handle = rte_hash_create(&ut_params); 741 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 742 743 /* Add */ 744 for (i = 0; i < 5; i++) { 745 pos[i] = rte_hash_add_key(handle, &keys[i]); 746 print_key_info("Add", &keys[i], pos[i]); 747 RETURN_IF_ERROR(pos[i] < 0, 748 "failed to add key (pos[%u]=%d)", i, pos[i]); 749 expected_pos[i] = pos[i]; 750 } 751 752 /* Lookup */ 753 for(i = 0; i < 5; i++) 754 key_array[i] = &keys[i]; 755 756 ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos); 757 if(ret == 0) 758 for(i = 0; i < 5; i++) { 759 print_key_info("Lkp", key_array[i], pos[i]); 760 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 for (i = 0; i < 5; i++) { 766 pos[i] = rte_hash_add_key(handle, &keys[i]); 767 print_key_info("Add", &keys[i], pos[i]); 768 RETURN_IF_ERROR(pos[i] != expected_pos[i], 769 "failed to add key (pos[%u]=%d)", i, pos[i]); 770 } 771 772 /* Lookup */ 773 for (i = 0; i < 5; i++) { 774 pos[i] = rte_hash_lookup(handle, &keys[i]); 775 print_key_info("Lkp", &keys[i], pos[i]); 776 RETURN_IF_ERROR(pos[i] != expected_pos[i], 777 "failed to find key (pos[%u]=%d)", i, pos[i]); 778 } 779 780 /* Delete */ 781 for (i = 0; i < 5; i++) { 782 pos[i] = rte_hash_del_key(handle, &keys[i]); 783 print_key_info("Del", &keys[i], pos[i]); 784 RETURN_IF_ERROR(pos[i] != expected_pos[i], 785 "failed to delete key (pos[%u]=%d)", i, pos[i]); 786 } 787 788 /* Lookup */ 789 for (i = 0; i < 5; i++) { 790 pos[i] = rte_hash_lookup(handle, &keys[i]); 791 print_key_info("Lkp", &keys[i], pos[i]); 792 RETURN_IF_ERROR(pos[i] != -ENOENT, 793 "found non-existent key (pos[%u]=%d)", i, pos[i]); 794 } 795 796 /* Lookup multi */ 797 ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos); 798 if (ret == 0) 799 for (i = 0; i < 5; i++) { 800 print_key_info("Lkp", key_array[i], pos[i]); 801 RETURN_IF_ERROR(pos[i] != -ENOENT, 802 "found not-existent key (pos[%u]=%d)", i, pos[i]); 803 } 804 805 rte_hash_free(handle); 806 807 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 static int test_full_bucket(void) 823 { 824 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 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 handle = rte_hash_create(¶ms_pseudo_hash); 839 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 840 841 /* Fill bucket */ 842 for (i = 0; i < KEY_PER_BUCKET; i++) { 843 pos[i] = rte_hash_add_key(handle, &keys[i]); 844 print_key_info("Add", &keys[i], pos[i]); 845 RETURN_IF_ERROR(pos[i] < 0, 846 "failed to add key (pos[%u]=%d)", i, pos[i]); 847 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 pos[KEY_PER_BUCKET] = rte_hash_add_key(handle, &keys[KEY_PER_BUCKET]); 854 print_key_info("Add", &keys[KEY_PER_BUCKET], pos[KEY_PER_BUCKET]); 855 RETURN_IF_ERROR(pos[KEY_PER_BUCKET] < 0, 856 "failed to add key (pos[%d]=%d)", KEY_PER_BUCKET, pos[KEY_PER_BUCKET]); 857 expected_pos[KEY_PER_BUCKET] = pos[KEY_PER_BUCKET]; 858 859 /* Lookup */ 860 for (i = 0; i < KEY_PER_BUCKET+1; i++) { 861 pos[i] = rte_hash_lookup(handle, &keys[i]); 862 print_key_info("Lkp", &keys[i], pos[i]); 863 RETURN_IF_ERROR(pos[i] != expected_pos[i], 864 "failed to find key (pos[%u]=%d)", i, pos[i]); 865 } 866 867 for (i = 0; i < KEY_PER_BUCKET+1; i++) 868 key_array[i] = &keys[i]; 869 870 /*Bulk lookup after add with same hash*/ 871 ret = rte_hash_lookup_bulk(handle, key_array, KEY_PER_BUCKET+1, (int32_t *)pos); 872 RETURN_IF_ERROR(ret, "rte_hash_lookup_bulk returned an error: %d\n", ret); 873 for (i = 0; i < KEY_PER_BUCKET+1; i++) { 874 print_key_info("Blk_Lkp", key_array[i], pos[i]); 875 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 for (i = 0; i < KEY_PER_BUCKET+1; i++) { 883 pos[i] = rte_hash_add_key(handle, &keys[i]); 884 print_key_info("Add", &keys[i], pos[i]); 885 RETURN_IF_ERROR(pos[i] != expected_pos[i], 886 "failed to add key (pos[%u]=%d)", i, pos[i]); 887 } 888 889 /* Lookup */ 890 for (i = 0; i < KEY_PER_BUCKET+1; i++) { 891 pos[i] = rte_hash_lookup(handle, &keys[i]); 892 print_key_info("Lkp", &keys[i], pos[i]); 893 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 pos[1] = rte_hash_del_key(handle, &keys[1]); 899 print_key_info("Del", &keys[1], pos[1]); 900 RETURN_IF_ERROR(pos[1] != expected_pos[1], 901 "failed to delete key (pos[1]=%d)", pos[1]); 902 pos[3] = rte_hash_lookup(handle, &keys[3]); 903 print_key_info("Lkp", &keys[3], pos[3]); 904 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 pos[1] = rte_hash_add_key(handle, &keys[1]); 910 print_key_info("Add", &keys[1], pos[1]); 911 expected_pos[1] = pos[1]; 912 RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]); 913 914 /* Delete */ 915 for (i = 0; i < KEY_PER_BUCKET+1; i++) { 916 pos[i] = rte_hash_del_key(handle, &keys[i]); 917 print_key_info("Del", &keys[i], pos[i]); 918 RETURN_IF_ERROR(pos[i] != expected_pos[i], 919 "failed to delete key (pos[%u]=%d)", i, pos[i]); 920 } 921 922 /* Lookup */ 923 for (i = 0; i < KEY_PER_BUCKET+1; i++) { 924 pos[i] = rte_hash_lookup(handle, &keys[i]); 925 print_key_info("Lkp", &keys[i], pos[i]); 926 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 ret = rte_hash_lookup_bulk(handle, &key_array[0], KEY_PER_BUCKET+1, (int32_t *)pos); 932 RETURN_IF_ERROR(ret, "rte_hash_lookup_bulk returned an error: %d\n", ret); 933 for (i = 0; i < KEY_PER_BUCKET+1; i++) { 934 print_key_info("Blk_Lkp", key_array[i], pos[i]); 935 RETURN_IF_ERROR(pos[i] != -ENOENT, 936 "failed to find key (pos[%u]=%d)", i, pos[i]); 937 } 938 939 rte_hash_free(handle); 940 941 /* Cover the NULL case. */ 942 rte_hash_free(0); 943 return 0; 944 } 945 946 /* 947 * Similar to the test above (full bucket test), but for extendable buckets. 948 */ 949 static int test_extendable_bucket(void) 950 { 951 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 for (i = 0; i < 64; i++) { 967 rand_keys[i].port_dst = i; 968 rand_keys[i].port_src = i+1; 969 } 970 971 handle = rte_hash_create(¶ms_pseudo_hash); 972 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 973 974 /* Fill bucket */ 975 for (i = 0; i < 64; i++) { 976 pos[i] = rte_hash_add_key(handle, &rand_keys[i]); 977 print_key_info("Add", &rand_keys[i], pos[i]); 978 RETURN_IF_ERROR(pos[i] < 0, 979 "failed to add key (pos[%u]=%d)", i, pos[i]); 980 expected_pos[i] = pos[i]; 981 } 982 983 /* Lookup */ 984 for (i = 0; i < 64; i++) { 985 pos[i] = rte_hash_lookup(handle, &rand_keys[i]); 986 print_key_info("Lkp", &rand_keys[i], pos[i]); 987 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 for (i = 0; i < 64; i++) { 993 pos[i] = rte_hash_add_key(handle, &rand_keys[i]); 994 print_key_info("Add", &rand_keys[i], pos[i]); 995 RETURN_IF_ERROR(pos[i] != expected_pos[i], 996 "failed to add key (pos[%u]=%d)", i, pos[i]); 997 } 998 999 /* Lookup */ 1000 for (i = 0; i < 64; i++) { 1001 pos[i] = rte_hash_lookup(handle, &rand_keys[i]); 1002 print_key_info("Lkp", &rand_keys[i], pos[i]); 1003 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 pos[35] = rte_hash_del_key(handle, &rand_keys[35]); 1009 print_key_info("Del", &rand_keys[35], pos[35]); 1010 RETURN_IF_ERROR(pos[35] != expected_pos[35], 1011 "failed to delete key (pos[1]=%d)", pos[35]); 1012 pos[20] = rte_hash_lookup(handle, &rand_keys[20]); 1013 print_key_info("Lkp", &rand_keys[20], pos[20]); 1014 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 pos[35] = rte_hash_add_key(handle, &rand_keys[35]); 1020 print_key_info("Add", &rand_keys[35], pos[35]); 1021 expected_pos[35] = pos[35]; 1022 RETURN_IF_ERROR(pos[35] < 0, "failed to add key (pos[1]=%d)", pos[35]); 1023 1024 /* Delete */ 1025 for (i = 0; i < 64; i++) { 1026 pos[i] = rte_hash_del_key(handle, &rand_keys[i]); 1027 print_key_info("Del", &rand_keys[i], pos[i]); 1028 RETURN_IF_ERROR(pos[i] != expected_pos[i], 1029 "failed to delete key (pos[%u]=%d)", i, pos[i]); 1030 } 1031 1032 /* Lookup */ 1033 for (i = 0; i < 64; i++) { 1034 pos[i] = rte_hash_lookup(handle, &rand_keys[i]); 1035 print_key_info("Lkp", &rand_keys[i], pos[i]); 1036 RETURN_IF_ERROR(pos[i] != -ENOENT, 1037 "fail: found non-existent key (pos[%u]=%d)", i, pos[i]); 1038 } 1039 1040 /* Add again */ 1041 for (i = 0; i < 64; i++) { 1042 pos[i] = rte_hash_add_key(handle, &rand_keys[i]); 1043 print_key_info("Add", &rand_keys[i], pos[i]); 1044 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 rte_hash_free(handle); 1050 1051 /* Cover the NULL case. */ 1052 rte_hash_free(0); 1053 return 0; 1054 } 1055 1056 /******************************************************************************/ 1057 static int 1058 fbk_hash_unit_test(void) 1059 { 1060 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 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 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 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 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 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 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 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 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 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 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 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 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 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 uint32_t keys[5] = 1174 {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9}; 1175 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 handle = rte_fbk_hash_create(&invalid_params_1); 1184 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 1185 1186 handle = rte_fbk_hash_create(&invalid_params_2); 1187 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 1188 1189 handle = rte_fbk_hash_create(&invalid_params_3); 1190 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 1191 1192 handle = rte_fbk_hash_create(&invalid_params_4); 1193 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 1194 1195 handle = rte_fbk_hash_create(&invalid_params_5); 1196 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 1197 1198 handle = rte_fbk_hash_create(&invalid_params_6); 1199 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 1200 1201 handle = rte_fbk_hash_create(&invalid_params_7); 1202 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 1203 1204 if (rte_eal_has_hugepages()) { 1205 handle = rte_fbk_hash_create(&invalid_params_8); 1206 RETURN_IF_ERROR_FBK(handle != NULL, 1207 "fbk hash creation should have failed"); 1208 } 1209 1210 handle = rte_fbk_hash_create(&invalid_params_same_name_1); 1211 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded"); 1212 1213 tmp = rte_fbk_hash_create(&invalid_params_same_name_2); 1214 rte_fbk_hash_free(tmp); 1215 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 tmp = rte_fbk_hash_create(&different_name); 1222 RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded"); 1223 1224 /* free both hashes */ 1225 rte_fbk_hash_free(handle); 1226 rte_fbk_hash_free(tmp); 1227 1228 /* Create empty jhash hash. */ 1229 handle = rte_fbk_hash_create(¶ms_jhash); 1230 RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed"); 1231 1232 /* Cleanup. */ 1233 rte_fbk_hash_free(handle); 1234 1235 /* Create empty jhash hash. */ 1236 handle = rte_fbk_hash_create(¶ms_nohash); 1237 RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed"); 1238 1239 /* Cleanup. */ 1240 rte_fbk_hash_free(handle); 1241 1242 /* Create empty hash. */ 1243 handle = rte_fbk_hash_create(¶ms); 1244 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed"); 1245 1246 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; 1247 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 for (i = 0; i < 5; i++) { 1251 status = rte_fbk_hash_add_key(handle, keys[i], vals[i]); 1252 RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed"); 1253 } 1254 1255 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; 1256 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 for (i = 0; i < 5; i++) { 1260 status = rte_fbk_hash_lookup(handle, keys[i]); 1261 RETURN_IF_ERROR_FBK(status != vals[i], 1262 "fbk hash lookup failed"); 1263 } 1264 1265 /* Change value of added keys. */ 1266 for (i = 0; i < 5; i++) { 1267 status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]); 1268 RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed"); 1269 } 1270 1271 /* Find new values. */ 1272 for (i = 0; i < 5; i++) { 1273 status = rte_fbk_hash_lookup(handle, keys[i]); 1274 RETURN_IF_ERROR_FBK(status != vals[4-i], 1275 "fbk hash lookup failed"); 1276 } 1277 1278 /* Delete keys individually. */ 1279 for (i = 0; i < 5; i++) { 1280 status = rte_fbk_hash_delete_key(handle, keys[i]); 1281 RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed"); 1282 } 1283 1284 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; 1285 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 for (i = 0; i < 5; i++) { 1289 status = rte_fbk_hash_lookup(handle, keys[i]); 1290 RETURN_IF_ERROR_FBK(status == 0, 1291 "fbk hash lookup should have failed"); 1292 } 1293 1294 /* Add keys again. */ 1295 for (i = 0; i < 5; i++) { 1296 status = rte_fbk_hash_add_key(handle, keys[i], vals[i]); 1297 RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed"); 1298 } 1299 1300 /* Make sure they were added. */ 1301 for (i = 0; i < 5; i++) { 1302 status = rte_fbk_hash_lookup(handle, keys[i]); 1303 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 for (i = 0; i < 5; i++) { 1312 status = rte_fbk_hash_lookup(handle, keys[i]); 1313 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 for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++) 1321 rte_fbk_hash_add_key(handle, i, (uint16_t) i); 1322 1323 /* Find non-existent key in a full hashtable */ 1324 status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1); 1325 RETURN_IF_ERROR_FBK(status != -ENOENT, 1326 "fbk hash lookup succeeded"); 1327 1328 /* Delete non-existent key in a full hashtable */ 1329 status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1); 1330 RETURN_IF_ERROR_FBK(status != -ENOENT, 1331 "fbk hash delete succeeded"); 1332 1333 /* Delete one key from a full hashtable */ 1334 status = rte_fbk_hash_delete_key(handle, 1); 1335 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 rte_fbk_hash_free(handle); 1343 1344 /* Cover the NULL case. */ 1345 rte_fbk_hash_free(0); 1346 1347 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 static int test_fbk_hash_find_existing(void) 1359 { 1360 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 handle = rte_fbk_hash_create(¶ms); 1370 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed"); 1371 1372 /* Try to find existing fbk hash table */ 1373 result = rte_fbk_hash_find_existing("fbk_hash_find_existing"); 1374 RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table"); 1375 1376 /* Try to find non-existing fbk hash table */ 1377 result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing"); 1378 RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist"); 1379 1380 /* Cleanup. */ 1381 rte_fbk_hash_free(handle); 1382 1383 return 0; 1384 } 1385 1386 #define BUCKET_ENTRIES 4 1387 /* 1388 * Do tests for hash creation with bad parameters. 1389 */ 1390 static int test_hash_creation_with_bad_parameters(void) 1391 { 1392 struct rte_hash *handle, *tmp; 1393 struct rte_hash_parameters params; 1394 1395 handle = rte_hash_create(NULL); 1396 if (handle != NULL) { 1397 rte_hash_free(handle); 1398 printf("Impossible creating hash successfully without any parameter\n"); 1399 return -1; 1400 } 1401 1402 memcpy(¶ms, &ut_params, sizeof(params)); 1403 params.name = "creation_with_bad_parameters_0"; 1404 params.entries = RTE_HASH_ENTRIES_MAX + 1; 1405 handle = rte_hash_create(¶ms); 1406 if (handle != NULL) { 1407 rte_hash_free(handle); 1408 printf("Impossible creating hash successfully with entries in parameter exceeded\n"); 1409 return -1; 1410 } 1411 1412 memcpy(¶ms, &ut_params, sizeof(params)); 1413 params.name = "creation_with_bad_parameters_2"; 1414 params.entries = BUCKET_ENTRIES - 1; 1415 handle = rte_hash_create(¶ms); 1416 if (handle != NULL) { 1417 rte_hash_free(handle); 1418 printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n"); 1419 return -1; 1420 } 1421 1422 memcpy(¶ms, &ut_params, sizeof(params)); 1423 params.name = "creation_with_bad_parameters_3"; 1424 params.key_len = 0; 1425 handle = rte_hash_create(¶ms); 1426 if (handle != NULL) { 1427 rte_hash_free(handle); 1428 printf("Impossible creating hash successfully if key_len in parameter is zero\n"); 1429 return -1; 1430 } 1431 1432 memcpy(¶ms, &ut_params, sizeof(params)); 1433 params.name = "creation_with_bad_parameters_4"; 1434 params.socket_id = RTE_MAX_NUMA_NODES + 1; 1435 handle = rte_hash_create(¶ms); 1436 if (handle != NULL) { 1437 rte_hash_free(handle); 1438 printf("Impossible creating hash successfully with invalid socket\n"); 1439 return -1; 1440 } 1441 1442 /* test with same name should fail */ 1443 memcpy(¶ms, &ut_params, sizeof(params)); 1444 params.name = "same_name"; 1445 handle = rte_hash_create(¶ms); 1446 if (handle == NULL) { 1447 printf("Cannot create first hash table with 'same_name'\n"); 1448 return -1; 1449 } 1450 tmp = rte_hash_create(¶ms); 1451 if (tmp != NULL) { 1452 printf("Creation of hash table with same name should fail\n"); 1453 rte_hash_free(handle); 1454 rte_hash_free(tmp); 1455 return -1; 1456 } 1457 rte_hash_free(handle); 1458 1459 printf("# Test successful. No more errors expected\n"); 1460 1461 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 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 params.name = "name"; 1477 params.hash_func = NULL; 1478 handle = rte_hash_create(¶ms); 1479 if (handle == NULL) { 1480 printf("Creating hash with null hash_func failed\n"); 1481 return -1; 1482 } 1483 1484 rte_hash_free(handle); 1485 1486 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 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 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 fflush(stdout); 1512 ut_params.entries = 1 << 16; 1513 ut_params.name = "test_average_utilization"; 1514 ut_params.hash_func = rte_jhash; 1515 if (ext_table) 1516 ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE; 1517 else 1518 ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE; 1519 1520 handle = rte_hash_create(&ut_params); 1521 1522 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 1523 1524 for (j = 0; j < ITERATIONS; j++) { 1525 ret = 0; 1526 /* Add random entries until key cannot be added */ 1527 for (added_keys = 0; ret >= 0; added_keys++) { 1528 for (i = 0; i < ut_params.key_len; i++) 1529 simple_key[i] = rte_rand() % 255; 1530 ret = rte_hash_add_key(handle, simple_key); 1531 if (ret < 0) 1532 break; 1533 } 1534 1535 if (ret != -ENOSPC) { 1536 printf("Unexpected error when adding keys\n"); 1537 rte_hash_free(handle); 1538 return -1; 1539 } 1540 1541 cnt = rte_hash_count(handle); 1542 if (cnt != added_keys) { 1543 printf("rte_hash_count returned wrong value %u, %u," 1544 "%u\n", j, added_keys, cnt); 1545 rte_hash_free(handle); 1546 return -1; 1547 } 1548 if (ext_table) { 1549 if (cnt != ut_params.entries) { 1550 printf("rte_hash_count returned wrong value " 1551 "%u, %u, %u\n", j, added_keys, cnt); 1552 rte_hash_free(handle); 1553 return -1; 1554 } 1555 } 1556 1557 average_keys_added += added_keys; 1558 1559 /* Reset the table */ 1560 rte_hash_reset(handle); 1561 1562 /* Print a dot to show progress on operations */ 1563 printf("."); 1564 fflush(stdout); 1565 } 1566 1567 average_keys_added /= ITERATIONS; 1568 1569 printf("\nAverage table utilization = %.2f%% (%u/%u)\n", 1570 ((double) average_keys_added / ut_params.entries * 100), 1571 average_keys_added, ut_params.entries); 1572 rte_hash_free(handle); 1573 1574 return 0; 1575 } 1576 1577 #define NUM_ENTRIES 256 1578 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 uint32_t iter = 0; 1588 int ret = 0; 1589 1590 ut_params.entries = NUM_ENTRIES; 1591 ut_params.name = "test_hash_iteration"; 1592 ut_params.hash_func = rte_jhash; 1593 ut_params.key_len = 16; 1594 if (ext_table) 1595 ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE; 1596 else 1597 ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE; 1598 1599 handle = rte_hash_create(&ut_params); 1600 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 1601 1602 /* Add random entries until key cannot be added */ 1603 for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) { 1604 data[added_keys] = (void *) ((uintptr_t) rte_rand()); 1605 for (i = 0; i < ut_params.key_len; i++) 1606 keys[added_keys][i] = rte_rand() % 255; 1607 ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]); 1608 if (ret < 0) { 1609 if (ext_table) { 1610 printf("Insertion failed for ext table\n"); 1611 goto err; 1612 } 1613 break; 1614 } 1615 } 1616 1617 /* Iterate through the hash table */ 1618 while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) { 1619 /* Search for the key in the list of keys added */ 1620 for (i = 0; i < NUM_ENTRIES; i++) { 1621 if (memcmp(next_key, keys[i], ut_params.key_len) == 0) { 1622 if (next_data != data[i]) { 1623 printf("Data found in the hash table is" 1624 "not the data added with the key\n"); 1625 goto err; 1626 } 1627 added_keys--; 1628 break; 1629 } 1630 } 1631 if (i == NUM_ENTRIES) { 1632 printf("Key found in the hash table was not added\n"); 1633 goto err; 1634 } 1635 } 1636 1637 /* Check if all keys have been iterated */ 1638 if (added_keys != 0) { 1639 printf("There were still %u keys to iterate\n", added_keys); 1640 goto err; 1641 } 1642 1643 rte_hash_free(handle); 1644 return 0; 1645 1646 err: 1647 rte_hash_free(handle); 1648 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 test_jhash_32b(const void *k, uint32_t length, uint32_t initval) 1671 { 1672 return rte_jhash_32b(k, length >> 2, initval); 1673 } 1674 1675 /* 1676 * add/delete key with jhash2 1677 */ 1678 static int 1679 test_hash_add_delete_jhash2(void) 1680 { 1681 int ret = -1; 1682 struct rte_hash *handle; 1683 int32_t pos1, pos2; 1684 1685 hash_params_ex.name = "hash_test_jhash2"; 1686 hash_params_ex.key_len = 4; 1687 hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b; 1688 1689 handle = rte_hash_create(&hash_params_ex); 1690 if (handle == NULL) { 1691 printf("test_hash_add_delete_jhash2 fail to create hash\n"); 1692 goto fail_jhash2; 1693 } 1694 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1695 if (pos1 < 0) { 1696 printf("test_hash_add_delete_jhash2 fail to add hash key\n"); 1697 goto fail_jhash2; 1698 } 1699 1700 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1701 if (pos2 < 0 || pos1 != pos2) { 1702 printf("test_hash_add_delete_jhash2 delete different key from being added\n"); 1703 goto fail_jhash2; 1704 } 1705 ret = 0; 1706 1707 fail_jhash2: 1708 rte_hash_free(handle); 1709 1710 return ret; 1711 } 1712 1713 /* 1714 * add/delete (2) key with jhash2 1715 */ 1716 static int 1717 test_hash_add_delete_2_jhash2(void) 1718 { 1719 int ret = -1; 1720 struct rte_hash *handle; 1721 int32_t pos1, pos2; 1722 1723 hash_params_ex.name = "hash_test_2_jhash2"; 1724 hash_params_ex.key_len = 8; 1725 hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b; 1726 1727 handle = rte_hash_create(&hash_params_ex); 1728 if (handle == NULL) 1729 goto fail_2_jhash2; 1730 1731 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1732 if (pos1 < 0) 1733 goto fail_2_jhash2; 1734 1735 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1736 if (pos2 < 0 || pos1 != pos2) 1737 goto fail_2_jhash2; 1738 1739 ret = 0; 1740 1741 fail_2_jhash2: 1742 rte_hash_free(handle); 1743 1744 return ret; 1745 } 1746 1747 static uint32_t 1748 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 return rte_jhash_1word(k[0], initval); 1755 } 1756 1757 static uint32_t 1758 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 return rte_jhash_2words(k[0], k[1], initval); 1765 } 1766 1767 static uint32_t 1768 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 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 test_hash_add_delete_jhash_1word(void) 1782 { 1783 int ret = -1; 1784 struct rte_hash *handle; 1785 int32_t pos1, pos2; 1786 1787 hash_params_ex.name = "hash_test_jhash_1word"; 1788 hash_params_ex.key_len = 4; 1789 hash_params_ex.hash_func = test_hash_jhash_1word; 1790 1791 handle = rte_hash_create(&hash_params_ex); 1792 if (handle == NULL) 1793 goto fail_jhash_1word; 1794 1795 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1796 if (pos1 < 0) 1797 goto fail_jhash_1word; 1798 1799 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1800 if (pos2 < 0 || pos1 != pos2) 1801 goto fail_jhash_1word; 1802 1803 ret = 0; 1804 1805 fail_jhash_1word: 1806 rte_hash_free(handle); 1807 1808 return ret; 1809 } 1810 1811 /* 1812 * add/delete key with jhash 2word 1813 */ 1814 static int 1815 test_hash_add_delete_jhash_2word(void) 1816 { 1817 int ret = -1; 1818 struct rte_hash *handle; 1819 int32_t pos1, pos2; 1820 1821 hash_params_ex.name = "hash_test_jhash_2word"; 1822 hash_params_ex.key_len = 8; 1823 hash_params_ex.hash_func = test_hash_jhash_2word; 1824 1825 handle = rte_hash_create(&hash_params_ex); 1826 if (handle == NULL) 1827 goto fail_jhash_2word; 1828 1829 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1830 if (pos1 < 0) 1831 goto fail_jhash_2word; 1832 1833 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1834 if (pos2 < 0 || pos1 != pos2) 1835 goto fail_jhash_2word; 1836 1837 ret = 0; 1838 1839 fail_jhash_2word: 1840 rte_hash_free(handle); 1841 1842 return ret; 1843 } 1844 1845 /* 1846 * add/delete key with jhash 3word 1847 */ 1848 static int 1849 test_hash_add_delete_jhash_3word(void) 1850 { 1851 int ret = -1; 1852 struct rte_hash *handle; 1853 int32_t pos1, pos2; 1854 1855 hash_params_ex.name = "hash_test_jhash_3word"; 1856 hash_params_ex.key_len = 12; 1857 hash_params_ex.hash_func = test_hash_jhash_3word; 1858 1859 handle = rte_hash_create(&hash_params_ex); 1860 if (handle == NULL) 1861 goto fail_jhash_3word; 1862 1863 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1864 if (pos1 < 0) 1865 goto fail_jhash_3word; 1866 1867 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1868 if (pos2 < 0 || pos1 != pos2) 1869 goto fail_jhash_3word; 1870 1871 ret = 0; 1872 1873 fail_jhash_3word: 1874 rte_hash_free(handle); 1875 1876 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 test_hash_rcu_qsbr_add(void) 1892 { 1893 size_t sz; 1894 struct rte_rcu_qsbr *qsv2 = NULL; 1895 int32_t status; 1896 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 params.name = "test_hash_rcu_qsbr_add"; 1902 params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF | 1903 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD; 1904 g_handle = rte_hash_create(¶ms); 1905 RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed"); 1906 1907 /* Create RCU QSBR variable */ 1908 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE); 1909 g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, 1910 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 1911 RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL, 1912 "RCU QSBR variable creation failed"); 1913 1914 status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE); 1915 RETURN_IF_ERROR_RCU_QSBR(status != 0, 1916 "RCU QSBR variable initialization failed"); 1917 1918 rcu_cfg.v = g_qsv; 1919 /* Invalid QSBR mode */ 1920 rcu_cfg.mode = 0xff; 1921 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg); 1922 RETURN_IF_ERROR_RCU_QSBR(status == 0, "Invalid QSBR mode test failed"); 1923 1924 rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ; 1925 /* Attach RCU QSBR to hash table */ 1926 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg); 1927 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 qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, 1932 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 1933 RETURN_IF_ERROR_RCU_QSBR(qsv2 == NULL, 1934 "RCU QSBR variable creation failed"); 1935 1936 rcu_cfg.v = qsv2; 1937 rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC; 1938 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg); 1939 rte_free(qsv2); 1940 RETURN_IF_ERROR_RCU_QSBR(status == 0, 1941 "Attach RCU QSBR to hash table succeeded where failure" 1942 " is expected"); 1943 1944 rte_hash_free(g_handle); 1945 rte_free(g_qsv); 1946 1947 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 test_hash_rcu_qsbr_dq_mode(uint8_t ext_bkt) 1968 { 1969 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 if (ext_bkt) 1974 hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE; 1975 1976 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 int pos[total_entries]; 1986 int expected_pos[total_entries]; 1987 unsigned int i; 1988 size_t sz; 1989 int32_t status; 1990 struct rte_hash_rcu_config rcu_cfg = {0}; 1991 1992 g_qsv = NULL; 1993 g_handle = NULL; 1994 1995 for (i = 0; i < total_entries; i++) { 1996 g_rand_keys[i].port_dst = i; 1997 g_rand_keys[i].port_src = i+1; 1998 } 1999 2000 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 g_handle = rte_hash_create(¶ms_pseudo_hash); 2007 RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed"); 2008 2009 /* Create RCU QSBR variable */ 2010 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE); 2011 g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, 2012 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 2013 RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL, 2014 "RCU QSBR variable creation failed"); 2015 2016 status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE); 2017 RETURN_IF_ERROR_RCU_QSBR(status != 0, 2018 "RCU QSBR variable initialization failed"); 2019 2020 rcu_cfg.v = g_qsv; 2021 rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ; 2022 /* Attach RCU QSBR to hash table */ 2023 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg); 2024 RETURN_IF_ERROR_RCU_QSBR(status != 0, 2025 "Attach RCU QSBR to hash table failed"); 2026 2027 /* Fill bucket */ 2028 for (i = 0; i < total_entries; i++) { 2029 pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]); 2030 print_key_info("Add", &g_rand_keys[i], pos[i]); 2031 RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0, 2032 "failed to add key (pos[%u]=%d)", i, 2033 pos[i]); 2034 expected_pos[i] = pos[i]; 2035 } 2036 2037 /* Register pseudo reader */ 2038 status = rte_rcu_qsbr_thread_register(g_qsv, 0); 2039 RETURN_IF_ERROR_RCU_QSBR(status != 0, 2040 "RCU QSBR thread registration failed"); 2041 rte_rcu_qsbr_thread_online(g_qsv, 0); 2042 2043 /* Lookup */ 2044 pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]); 2045 print_key_info("Lkp", &g_rand_keys[0], pos[0]); 2046 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 pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]); 2052 print_key_info("Del", &g_rand_keys[0], pos[0]); 2053 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 pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]); 2059 print_key_info("Lkp", &g_rand_keys[0], pos[0]); 2060 RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOENT, 2061 "found deleted key (pos[%u]=%d)", 0, pos[0]); 2062 2063 /* Fill bucket */ 2064 pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]); 2065 print_key_info("Add", &g_rand_keys[0], pos[0]); 2066 RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOSPC, 2067 "Added key successfully (pos[%u]=%d)", 0, pos[0]); 2068 2069 /* Reader quiescent */ 2070 rte_rcu_qsbr_quiescent(g_qsv, 0); 2071 2072 /* Fill bucket */ 2073 pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]); 2074 print_key_info("Add", &g_rand_keys[0], pos[0]); 2075 RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0, 2076 "failed to add key (pos[%u]=%d)", 0, pos[0]); 2077 expected_pos[0] = pos[0]; 2078 2079 rte_rcu_qsbr_thread_offline(g_qsv, 0); 2080 (void)rte_rcu_qsbr_thread_unregister(g_qsv, 0); 2081 2082 /* Lookup */ 2083 pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]); 2084 print_key_info("Lkp", &g_rand_keys[0], pos[0]); 2085 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 rte_hash_free(g_handle); 2090 rte_free(g_qsv); 2091 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 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 (void)rte_rcu_qsbr_thread_register(g_qsv, 0); 2112 rte_rcu_qsbr_thread_online(g_qsv, 0); 2113 2114 do { 2115 for (i = 0; i < QSBR_REPORTING_INTERVAL; i++) 2116 rte_hash_lookup(g_handle, &g_rand_keys[0]); 2117 2118 /* Update quiescent state */ 2119 rte_rcu_qsbr_quiescent(g_qsv, 0); 2120 } while (!writer_done); 2121 2122 rte_rcu_qsbr_thread_offline(g_qsv, 0); 2123 (void)rte_rcu_qsbr_thread_unregister(g_qsv, 0); 2124 2125 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 test_hash_rcu_qsbr_sync_mode(uint8_t ext_bkt) 2138 { 2139 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 if (ext_bkt) 2144 hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE; 2145 2146 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 int pos[total_entries]; 2156 int expected_pos[total_entries]; 2157 unsigned int i; 2158 size_t sz; 2159 int32_t status; 2160 struct rte_hash_rcu_config rcu_cfg = {0}; 2161 2162 g_qsv = NULL; 2163 g_handle = NULL; 2164 2165 for (i = 0; i < total_entries; i++) { 2166 g_rand_keys[i].port_dst = i; 2167 g_rand_keys[i].port_src = i+1; 2168 } 2169 2170 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 g_handle = rte_hash_create(¶ms_pseudo_hash); 2177 RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed"); 2178 2179 /* Create RCU QSBR variable */ 2180 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE); 2181 g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, 2182 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 2183 RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL, 2184 "RCU QSBR variable creation failed"); 2185 2186 status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE); 2187 RETURN_IF_ERROR_RCU_QSBR(status != 0, 2188 "RCU QSBR variable initialization failed"); 2189 2190 rcu_cfg.v = g_qsv; 2191 rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC; 2192 /* Attach RCU QSBR to hash table */ 2193 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg); 2194 RETURN_IF_ERROR_RCU_QSBR(status != 0, 2195 "Attach RCU QSBR to hash table failed"); 2196 2197 /* Launch reader thread */ 2198 rte_eal_remote_launch(test_hash_rcu_qsbr_reader, NULL, 2199 rte_get_next_lcore(-1, 1, 0)); 2200 2201 /* Fill bucket */ 2202 for (i = 0; i < total_entries; i++) { 2203 pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]); 2204 print_key_info("Add", &g_rand_keys[i], pos[i]); 2205 RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0, 2206 "failed to add key (pos[%u]=%d)", i, pos[i]); 2207 expected_pos[i] = pos[i]; 2208 } 2209 writer_done = 0; 2210 2211 /* Writer Update */ 2212 for (i = 0; i < WRITER_ITERATIONS; i++) { 2213 expected_pos[0] = pos[0]; 2214 pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]); 2215 print_key_info("Del", &g_rand_keys[0], status); 2216 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 pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]); 2221 print_key_info("Add", &g_rand_keys[0], pos[0]); 2222 RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0, 2223 "failed to add key (pos[%u]=%d)", 0, 2224 pos[0]); 2225 } 2226 2227 writer_done = 1; 2228 /* Wait until reader exited. */ 2229 rte_eal_mp_wait_lcore(); 2230 2231 rte_hash_free(g_handle); 2232 rte_free(g_qsv); 2233 2234 return 0; 2235 2236 } 2237 2238 /* 2239 * rte_hash_rcu_qsbr_dq_reclaim unit test. 2240 */ 2241 static int 2242 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 uint32_t reclaim_keys[8] = {10, 11, 12, 13, 14, 15, 16, 17}; 2249 struct rte_hash_rcu_config rcu_cfg = {0}; 2250 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 hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF; 2260 2261 g_qsv = NULL; 2262 g_handle = NULL; 2263 2264 printf("\n# Running RCU QSBR DQ mode, reclaim defer queue functional test\n"); 2265 2266 g_handle = rte_hash_create(&hash_params); 2267 RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed"); 2268 2269 /* Create RCU QSBR variable */ 2270 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE); 2271 g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket( 2272 NULL, sz, RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 2273 RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL, "RCU QSBR variable creation failed"); 2274 2275 status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE); 2276 RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR variable initialization failed"); 2277 2278 rcu_cfg.v = g_qsv; 2279 rcu_cfg.dq_size = total_entries; 2280 rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ; 2281 2282 /* Attach RCU QSBR to hash table */ 2283 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg); 2284 RETURN_IF_ERROR_RCU_QSBR(status != 0, "Attach RCU QSBR to hash table failed"); 2285 2286 /* Register pseudo reader */ 2287 status = rte_rcu_qsbr_thread_register(g_qsv, 0); 2288 RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR thread registration failed"); 2289 rte_rcu_qsbr_thread_online(g_qsv, 0); 2290 2291 /* Fill half of the hash table */ 2292 for (size_t i = 0; i < total_entries / 2; i++) 2293 status = rte_hash_add_key(g_handle, &reclaim_keys[i]); 2294 2295 /* Try to put these elements into the defer queue*/ 2296 for (size_t i = 0; i < total_entries / 2; i++) 2297 rte_hash_del_key(g_handle, &reclaim_keys[i]); 2298 2299 /* Reader quiescent */ 2300 rte_rcu_qsbr_quiescent(g_qsv, 0); 2301 2302 status = rte_hash_add_key(g_handle, &reclaim_keys[0]); 2303 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 unsigned int hash_size = rte_hash_count(g_handle); 2307 2308 /* Freed size should be (total_entries / 2) */ 2309 rte_hash_rcu_qsbr_dq_reclaim(g_handle, &freed, &pending, &available); 2310 2311 rte_hash_free(g_handle); 2312 rte_free(g_qsv); 2313 2314 if (hash_size != (total_entries / 2 + 1) || freed != (total_entries / 2)) { 2315 printf("Failed to reclaim defer queue\n"); 2316 return -1; 2317 } 2318 2319 return 0; 2320 } 2321 2322 /* 2323 * Do all unit and performance tests. 2324 */ 2325 static int 2326 test_hash(void) 2327 { 2328 RTE_BUILD_BUG_ON(sizeof(struct flow_key) % sizeof(uint32_t) != 0); 2329 2330 if (test_add_delete() < 0) 2331 return -1; 2332 if (test_hash_add_delete_jhash2() < 0) 2333 return -1; 2334 if (test_hash_add_delete_2_jhash2() < 0) 2335 return -1; 2336 if (test_hash_add_delete_jhash_1word() < 0) 2337 return -1; 2338 if (test_hash_add_delete_jhash_2word() < 0) 2339 return -1; 2340 if (test_hash_add_delete_jhash_3word() < 0) 2341 return -1; 2342 if (test_hash_get_key_with_position() < 0) 2343 return -1; 2344 if (test_hash_find_existing() < 0) 2345 return -1; 2346 if (test_add_update_delete() < 0) 2347 return -1; 2348 if (test_add_update_delete_free() < 0) 2349 return -1; 2350 if (test_add_delete_free_lf() < 0) 2351 return -1; 2352 if (test_five_keys() < 0) 2353 return -1; 2354 if (test_full_bucket() < 0) 2355 return -1; 2356 if (test_extendable_bucket() < 0) 2357 return -1; 2358 2359 if (test_fbk_hash_find_existing() < 0) 2360 return -1; 2361 if (fbk_hash_unit_test() < 0) 2362 return -1; 2363 if (test_hash_creation_with_bad_parameters() < 0) 2364 return -1; 2365 if (test_hash_creation_with_good_parameters() < 0) 2366 return -1; 2367 2368 /* ext table disabled */ 2369 if (test_average_table_utilization(0) < 0) 2370 return -1; 2371 if (test_hash_iteration(0) < 0) 2372 return -1; 2373 2374 /* ext table enabled */ 2375 if (test_average_table_utilization(1) < 0) 2376 return -1; 2377 if (test_hash_iteration(1) < 0) 2378 return -1; 2379 2380 run_hash_func_tests(); 2381 2382 if (test_crc32_hash_alg_equiv() < 0) 2383 return -1; 2384 2385 if (test_hash_rcu_qsbr_add() < 0) 2386 return -1; 2387 2388 if (test_hash_rcu_qsbr_dq_mode(0) < 0) 2389 return -1; 2390 2391 if (test_hash_rcu_qsbr_dq_mode(1) < 0) 2392 return -1; 2393 2394 if (test_hash_rcu_qsbr_sync_mode(0) < 0) 2395 return -1; 2396 2397 if (test_hash_rcu_qsbr_sync_mode(1) < 0) 2398 return -1; 2399 2400 if (test_hash_rcu_qsbr_dq_reclaim() < 0) 2401 return -1; 2402 2403 return 0; 2404 } 2405 2406 REGISTER_FAST_TEST(hash_autotest, true, true, test_hash); 2407