1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stdio.h> 35 #include <stdint.h> 36 #include <string.h> 37 #include <stdlib.h> 38 #include <stdarg.h> 39 #include <errno.h> 40 #include <sys/queue.h> 41 42 #include <rte_common.h> 43 #include <rte_malloc.h> 44 #include <rte_cycles.h> 45 #include <rte_random.h> 46 #include <rte_memory.h> 47 #include <rte_memzone.h> 48 #include <rte_eal.h> 49 #include <rte_ip.h> 50 #include <rte_string_fns.h> 51 52 #include "test.h" 53 54 #include <rte_hash.h> 55 #include <rte_fbk_hash.h> 56 #include <rte_jhash.h> 57 #include <rte_hash_crc.h> 58 59 /******************************************************************************* 60 * Hash function performance test configuration section. Each performance test 61 * will be performed HASHTEST_ITERATIONS times. 62 * 63 * The five arrays below control what tests are performed. Every combination 64 * from the array entries is tested. 65 */ 66 static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc}; 67 static uint32_t hashtest_initvals[] = {0}; 68 static uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64}; 69 #define MAX_KEYSIZE 64 70 /******************************************************************************/ 71 #define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15) 72 73 /* 74 * Check condition and return an error if true. Assumes that "handle" is the 75 * name of the hash structure pointer to be freed. 76 */ 77 #define RETURN_IF_ERROR(cond, str, ...) do { \ 78 if (cond) { \ 79 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \ 80 if (handle) rte_hash_free(handle); \ 81 return -1; \ 82 } \ 83 } while(0) 84 85 #define RETURN_IF_ERROR_FBK(cond, str, ...) do { \ 86 if (cond) { \ 87 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \ 88 if (handle) rte_fbk_hash_free(handle); \ 89 return -1; \ 90 } \ 91 } while(0) 92 93 /* 5-tuple key type */ 94 struct flow_key { 95 uint32_t ip_src; 96 uint32_t ip_dst; 97 uint16_t port_src; 98 uint16_t port_dst; 99 uint8_t proto; 100 } __attribute__((packed)); 101 102 /* 103 * Hash function that always returns the same value, to easily test what 104 * happens when a bucket is full. 105 */ 106 static uint32_t pseudo_hash(__attribute__((unused)) const void *keys, 107 __attribute__((unused)) uint32_t key_len, 108 __attribute__((unused)) uint32_t init_val) 109 { 110 return 3; 111 } 112 113 /* 114 * Print out result of unit test hash operation. 115 */ 116 #if defined(UNIT_TEST_HASH_VERBOSE) 117 static void print_key_info(const char *msg, const struct flow_key *key, 118 int32_t pos) 119 { 120 uint8_t *p = (uint8_t *)key; 121 unsigned i; 122 123 printf("%s key:0x", msg); 124 for (i = 0; i < sizeof(struct flow_key); i++) { 125 printf("%02X", p[i]); 126 } 127 printf(" @ pos %d\n", pos); 128 } 129 #else 130 static void print_key_info(__attribute__((unused)) const char *msg, 131 __attribute__((unused)) const struct flow_key *key, 132 __attribute__((unused)) int32_t pos) 133 { 134 } 135 #endif 136 137 /* Keys used by unit test functions */ 138 static struct flow_key keys[5] = { { 139 .ip_src = IPv4(0x03, 0x02, 0x01, 0x00), 140 .ip_dst = IPv4(0x07, 0x06, 0x05, 0x04), 141 .port_src = 0x0908, 142 .port_dst = 0x0b0a, 143 .proto = 0x0c, 144 }, { 145 .ip_src = IPv4(0x13, 0x12, 0x11, 0x10), 146 .ip_dst = IPv4(0x17, 0x16, 0x15, 0x14), 147 .port_src = 0x1918, 148 .port_dst = 0x1b1a, 149 .proto = 0x1c, 150 }, { 151 .ip_src = IPv4(0x23, 0x22, 0x21, 0x20), 152 .ip_dst = IPv4(0x27, 0x26, 0x25, 0x24), 153 .port_src = 0x2928, 154 .port_dst = 0x2b2a, 155 .proto = 0x2c, 156 }, { 157 .ip_src = IPv4(0x33, 0x32, 0x31, 0x30), 158 .ip_dst = IPv4(0x37, 0x36, 0x35, 0x34), 159 .port_src = 0x3938, 160 .port_dst = 0x3b3a, 161 .proto = 0x3c, 162 }, { 163 .ip_src = IPv4(0x43, 0x42, 0x41, 0x40), 164 .ip_dst = IPv4(0x47, 0x46, 0x45, 0x44), 165 .port_src = 0x4948, 166 .port_dst = 0x4b4a, 167 .proto = 0x4c, 168 } }; 169 170 /* Parameters used for hash table in unit test functions. Name set later. */ 171 static struct rte_hash_parameters ut_params = { 172 .entries = 64, 173 .key_len = sizeof(struct flow_key), /* 13 */ 174 .hash_func = rte_jhash, 175 .hash_func_init_val = 0, 176 .socket_id = 0, 177 }; 178 179 #define CRC32_ITERATIONS (1U << 10) 180 #define CRC32_DWORDS (1U << 6) 181 /* 182 * Test if all CRC32 implementations yield the same hash value 183 */ 184 static int 185 test_crc32_hash_alg_equiv(void) 186 { 187 uint32_t hash_val; 188 uint32_t init_val; 189 uint64_t data64[CRC32_DWORDS]; 190 unsigned i, j; 191 size_t data_len; 192 193 printf("\n# CRC32 implementations equivalence test\n"); 194 for (i = 0; i < CRC32_ITERATIONS; i++) { 195 /* Randomizing data_len of data set */ 196 data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1); 197 init_val = (uint32_t) rte_rand(); 198 199 /* Fill the data set */ 200 for (j = 0; j < CRC32_DWORDS; j++) 201 data64[j] = rte_rand(); 202 203 /* Calculate software CRC32 */ 204 rte_hash_crc_set_alg(CRC32_SW); 205 hash_val = rte_hash_crc(data64, data_len, init_val); 206 207 /* Check against 4-byte-operand sse4.2 CRC32 if available */ 208 rte_hash_crc_set_alg(CRC32_SSE42); 209 if (hash_val != rte_hash_crc(data64, data_len, init_val)) { 210 printf("Failed checking CRC32_SW against CRC32_SSE42\n"); 211 break; 212 } 213 214 /* Check against 8-byte-operand sse4.2 CRC32 if available */ 215 rte_hash_crc_set_alg(CRC32_SSE42_x64); 216 if (hash_val != rte_hash_crc(data64, data_len, init_val)) { 217 printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n"); 218 break; 219 } 220 221 /* Check against 8-byte-operand ARM64 CRC32 if available */ 222 rte_hash_crc_set_alg(CRC32_ARM64); 223 if (hash_val != rte_hash_crc(data64, data_len, init_val)) { 224 printf("Failed checking CRC32_SW against CRC32_ARM64\n"); 225 break; 226 } 227 } 228 229 /* Resetting to best available algorithm */ 230 rte_hash_crc_set_alg(CRC32_SSE42_x64); 231 232 if (i == CRC32_ITERATIONS) 233 return 0; 234 235 printf("Failed test data (hex, %zu bytes total):\n", data_len); 236 for (j = 0; j < data_len; j++) 237 printf("%02X%c", ((uint8_t *)data64)[j], 238 ((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' '); 239 240 return -1; 241 } 242 243 /* 244 * Test a hash function. 245 */ 246 static void run_hash_func_test(rte_hash_function f, uint32_t init_val, 247 uint32_t key_len) 248 { 249 static uint8_t key[MAX_KEYSIZE]; 250 unsigned i; 251 252 253 for (i = 0; i < key_len; i++) 254 key[i] = (uint8_t) rte_rand(); 255 256 /* just to be on the safe side */ 257 if (!f) 258 return; 259 260 f(key, key_len, init_val); 261 } 262 263 /* 264 * Test all hash functions. 265 */ 266 static void run_hash_func_tests(void) 267 { 268 unsigned i, j, k; 269 270 for (i = 0; 271 i < sizeof(hashtest_funcs) / sizeof(rte_hash_function); 272 i++) { 273 for (j = 0; 274 j < sizeof(hashtest_initvals) / sizeof(uint32_t); 275 j++) { 276 for (k = 0; 277 k < sizeof(hashtest_key_lens) / sizeof(uint32_t); 278 k++) { 279 run_hash_func_test(hashtest_funcs[i], 280 hashtest_initvals[j], 281 hashtest_key_lens[k]); 282 } 283 } 284 } 285 } 286 287 /* 288 * Basic sequence of operations for a single key: 289 * - add 290 * - lookup (hit) 291 * - delete 292 * - lookup (miss) 293 */ 294 static int test_add_delete(void) 295 { 296 struct rte_hash *handle; 297 /* test with standard add/lookup/delete functions */ 298 int pos0, expectedPos0; 299 300 ut_params.name = "test1"; 301 handle = rte_hash_create(&ut_params); 302 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 303 304 pos0 = rte_hash_add_key(handle, &keys[0]); 305 print_key_info("Add", &keys[0], pos0); 306 RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0); 307 expectedPos0 = pos0; 308 309 pos0 = rte_hash_lookup(handle, &keys[0]); 310 print_key_info("Lkp", &keys[0], pos0); 311 RETURN_IF_ERROR(pos0 != expectedPos0, 312 "failed to find key (pos0=%d)", pos0); 313 314 pos0 = rte_hash_del_key(handle, &keys[0]); 315 print_key_info("Del", &keys[0], pos0); 316 RETURN_IF_ERROR(pos0 != expectedPos0, 317 "failed to delete key (pos0=%d)", pos0); 318 319 pos0 = rte_hash_lookup(handle, &keys[0]); 320 print_key_info("Lkp", &keys[0], pos0); 321 RETURN_IF_ERROR(pos0 != -ENOENT, 322 "fail: found key after deleting! (pos0=%d)", pos0); 323 324 rte_hash_free(handle); 325 326 /* repeat test with precomputed hash functions */ 327 hash_sig_t hash_value; 328 int pos1, expectedPos1; 329 330 handle = rte_hash_create(&ut_params); 331 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 332 333 hash_value = rte_hash_hash(handle, &keys[0]); 334 pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value); 335 print_key_info("Add", &keys[0], pos1); 336 RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1); 337 expectedPos1 = pos1; 338 339 pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value); 340 print_key_info("Lkp", &keys[0], pos1); 341 RETURN_IF_ERROR(pos1 != expectedPos1, 342 "failed to find key (pos1=%d)", pos1); 343 344 pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value); 345 print_key_info("Del", &keys[0], pos1); 346 RETURN_IF_ERROR(pos1 != expectedPos1, 347 "failed to delete key (pos1=%d)", 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 != -ENOENT, 352 "fail: found key after deleting! (pos1=%d)", pos1); 353 354 rte_hash_free(handle); 355 356 return 0; 357 } 358 359 /* 360 * Sequence of operations for a single key: 361 * - delete: miss 362 * - add 363 * - lookup: hit 364 * - add: update 365 * - lookup: hit (updated data) 366 * - delete: hit 367 * - delete: miss 368 * - lookup: miss 369 */ 370 static int test_add_update_delete(void) 371 { 372 struct rte_hash *handle; 373 int pos0, expectedPos0; 374 375 ut_params.name = "test2"; 376 handle = rte_hash_create(&ut_params); 377 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 378 379 pos0 = rte_hash_del_key(handle, &keys[0]); 380 print_key_info("Del", &keys[0], pos0); 381 RETURN_IF_ERROR(pos0 != -ENOENT, 382 "fail: found non-existent key (pos0=%d)", pos0); 383 384 pos0 = rte_hash_add_key(handle, &keys[0]); 385 print_key_info("Add", &keys[0], pos0); 386 RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0); 387 expectedPos0 = pos0; 388 389 pos0 = rte_hash_lookup(handle, &keys[0]); 390 print_key_info("Lkp", &keys[0], pos0); 391 RETURN_IF_ERROR(pos0 != expectedPos0, 392 "failed to find key (pos0=%d)", pos0); 393 394 pos0 = rte_hash_add_key(handle, &keys[0]); 395 print_key_info("Add", &keys[0], pos0); 396 RETURN_IF_ERROR(pos0 != expectedPos0, 397 "failed to re-add key (pos0=%d)", pos0); 398 399 pos0 = rte_hash_lookup(handle, &keys[0]); 400 print_key_info("Lkp", &keys[0], pos0); 401 RETURN_IF_ERROR(pos0 != expectedPos0, 402 "failed to find key (pos0=%d)", pos0); 403 404 pos0 = rte_hash_del_key(handle, &keys[0]); 405 print_key_info("Del", &keys[0], pos0); 406 RETURN_IF_ERROR(pos0 != expectedPos0, 407 "failed to delete key (pos0=%d)", pos0); 408 409 pos0 = rte_hash_del_key(handle, &keys[0]); 410 print_key_info("Del", &keys[0], pos0); 411 RETURN_IF_ERROR(pos0 != -ENOENT, 412 "fail: deleted already deleted key (pos0=%d)", pos0); 413 414 pos0 = rte_hash_lookup(handle, &keys[0]); 415 print_key_info("Lkp", &keys[0], pos0); 416 RETURN_IF_ERROR(pos0 != -ENOENT, 417 "fail: found key after deleting! (pos0=%d)", pos0); 418 419 rte_hash_free(handle); 420 return 0; 421 } 422 423 /* 424 * Sequence of operations for retrieving a key with its position 425 * 426 * - create table 427 * - add key 428 * - get the key with its position: hit 429 * - delete key 430 * - try to get the deleted key: miss 431 * 432 */ 433 static int test_hash_get_key_with_position(void) 434 { 435 struct rte_hash *handle = NULL; 436 int pos, expectedPos, result; 437 void *key; 438 439 ut_params.name = "hash_get_key_w_pos"; 440 handle = rte_hash_create(&ut_params); 441 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 442 443 pos = rte_hash_add_key(handle, &keys[0]); 444 print_key_info("Add", &keys[0], pos); 445 RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos); 446 expectedPos = pos; 447 448 result = rte_hash_get_key_with_position(handle, pos, &key); 449 RETURN_IF_ERROR(result != 0, "error retrieving a key"); 450 451 pos = rte_hash_del_key(handle, &keys[0]); 452 print_key_info("Del", &keys[0], pos); 453 RETURN_IF_ERROR(pos != expectedPos, 454 "failed to delete key (pos0=%d)", pos); 455 456 result = rte_hash_get_key_with_position(handle, pos, &key); 457 RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved"); 458 459 rte_hash_free(handle); 460 return 0; 461 } 462 463 /* 464 * Sequence of operations for find existing hash table 465 * 466 * - create table 467 * - find existing table: hit 468 * - find non-existing table: miss 469 * 470 */ 471 static int test_hash_find_existing(void) 472 { 473 struct rte_hash *handle = NULL, *result = NULL; 474 475 /* Create hash table. */ 476 ut_params.name = "hash_find_existing"; 477 handle = rte_hash_create(&ut_params); 478 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 479 480 /* Try to find existing hash table */ 481 result = rte_hash_find_existing("hash_find_existing"); 482 RETURN_IF_ERROR(result != handle, "could not find existing hash table"); 483 484 /* Try to find non-existing hash table */ 485 result = rte_hash_find_existing("hash_find_non_existing"); 486 RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist"); 487 488 /* Cleanup. */ 489 rte_hash_free(handle); 490 491 return 0; 492 } 493 494 /* 495 * Sequence of operations for 5 keys 496 * - add keys 497 * - lookup keys: hit 498 * - add keys (update) 499 * - lookup keys: hit (updated data) 500 * - delete keys : hit 501 * - lookup keys: miss 502 */ 503 static int test_five_keys(void) 504 { 505 struct rte_hash *handle; 506 const void *key_array[5] = {0}; 507 int pos[5]; 508 int expected_pos[5]; 509 unsigned i; 510 int ret; 511 512 ut_params.name = "test3"; 513 handle = rte_hash_create(&ut_params); 514 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 515 516 /* Add */ 517 for (i = 0; i < 5; i++) { 518 pos[i] = rte_hash_add_key(handle, &keys[i]); 519 print_key_info("Add", &keys[i], pos[i]); 520 RETURN_IF_ERROR(pos[i] < 0, 521 "failed to add key (pos[%u]=%d)", i, pos[i]); 522 expected_pos[i] = pos[i]; 523 } 524 525 /* Lookup */ 526 for(i = 0; i < 5; i++) 527 key_array[i] = &keys[i]; 528 529 ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos); 530 if(ret == 0) 531 for(i = 0; i < 5; i++) { 532 print_key_info("Lkp", key_array[i], pos[i]); 533 RETURN_IF_ERROR(pos[i] != expected_pos[i], 534 "failed to find key (pos[%u]=%d)", i, pos[i]); 535 } 536 537 /* Add - update */ 538 for (i = 0; i < 5; i++) { 539 pos[i] = rte_hash_add_key(handle, &keys[i]); 540 print_key_info("Add", &keys[i], pos[i]); 541 RETURN_IF_ERROR(pos[i] != expected_pos[i], 542 "failed to add key (pos[%u]=%d)", i, pos[i]); 543 } 544 545 /* Lookup */ 546 for (i = 0; i < 5; i++) { 547 pos[i] = rte_hash_lookup(handle, &keys[i]); 548 print_key_info("Lkp", &keys[i], pos[i]); 549 RETURN_IF_ERROR(pos[i] != expected_pos[i], 550 "failed to find key (pos[%u]=%d)", i, pos[i]); 551 } 552 553 /* Delete */ 554 for (i = 0; i < 5; i++) { 555 pos[i] = rte_hash_del_key(handle, &keys[i]); 556 print_key_info("Del", &keys[i], pos[i]); 557 RETURN_IF_ERROR(pos[i] != expected_pos[i], 558 "failed to delete key (pos[%u]=%d)", i, pos[i]); 559 } 560 561 /* Lookup */ 562 for (i = 0; i < 5; i++) { 563 pos[i] = rte_hash_lookup(handle, &keys[i]); 564 print_key_info("Lkp", &keys[i], pos[i]); 565 RETURN_IF_ERROR(pos[i] != -ENOENT, 566 "found non-existent key (pos[%u]=%d)", i, pos[i]); 567 } 568 569 /* Lookup multi */ 570 ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos); 571 if (ret == 0) 572 for (i = 0; i < 5; i++) { 573 print_key_info("Lkp", key_array[i], pos[i]); 574 RETURN_IF_ERROR(pos[i] != -ENOENT, 575 "found not-existent key (pos[%u]=%d)", i, pos[i]); 576 } 577 578 rte_hash_free(handle); 579 580 return 0; 581 } 582 583 /* 584 * Add keys to the same bucket until bucket full. 585 * - add 5 keys to the same bucket (hash created with 4 keys per bucket): 586 * first 4 successful, 5th successful, pushing existing item in bucket 587 * - lookup the 5 keys: 5 hits 588 * - add the 5 keys again: 5 OK 589 * - lookup the 5 keys: 5 hits (updated data) 590 * - delete the 5 keys: 5 OK 591 * - lookup the 5 keys: 5 misses 592 */ 593 static int test_full_bucket(void) 594 { 595 struct rte_hash_parameters params_pseudo_hash = { 596 .name = "test4", 597 .entries = 64, 598 .key_len = sizeof(struct flow_key), /* 13 */ 599 .hash_func = pseudo_hash, 600 .hash_func_init_val = 0, 601 .socket_id = 0, 602 }; 603 struct rte_hash *handle; 604 int pos[5]; 605 int expected_pos[5]; 606 unsigned i; 607 608 handle = rte_hash_create(¶ms_pseudo_hash); 609 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 610 611 /* Fill bucket */ 612 for (i = 0; i < 4; i++) { 613 pos[i] = rte_hash_add_key(handle, &keys[i]); 614 print_key_info("Add", &keys[i], pos[i]); 615 RETURN_IF_ERROR(pos[i] < 0, 616 "failed to add key (pos[%u]=%d)", i, pos[i]); 617 expected_pos[i] = pos[i]; 618 } 619 /* 620 * This should work and will push one of the items 621 * in the bucket because it is full 622 */ 623 pos[4] = rte_hash_add_key(handle, &keys[4]); 624 print_key_info("Add", &keys[4], pos[4]); 625 RETURN_IF_ERROR(pos[4] < 0, 626 "failed to add key (pos[4]=%d)", pos[4]); 627 expected_pos[4] = pos[4]; 628 629 /* Lookup */ 630 for (i = 0; i < 5; i++) { 631 pos[i] = rte_hash_lookup(handle, &keys[i]); 632 print_key_info("Lkp", &keys[i], pos[i]); 633 RETURN_IF_ERROR(pos[i] != expected_pos[i], 634 "failed to find key (pos[%u]=%d)", i, pos[i]); 635 } 636 637 /* Add - update */ 638 for (i = 0; i < 5; i++) { 639 pos[i] = rte_hash_add_key(handle, &keys[i]); 640 print_key_info("Add", &keys[i], pos[i]); 641 RETURN_IF_ERROR(pos[i] != expected_pos[i], 642 "failed to add key (pos[%u]=%d)", i, pos[i]); 643 } 644 645 /* Lookup */ 646 for (i = 0; i < 5; i++) { 647 pos[i] = rte_hash_lookup(handle, &keys[i]); 648 print_key_info("Lkp", &keys[i], pos[i]); 649 RETURN_IF_ERROR(pos[i] != expected_pos[i], 650 "failed to find key (pos[%u]=%d)", i, pos[i]); 651 } 652 653 /* Delete 1 key, check other keys are still found */ 654 pos[1] = rte_hash_del_key(handle, &keys[1]); 655 print_key_info("Del", &keys[1], pos[1]); 656 RETURN_IF_ERROR(pos[1] != expected_pos[1], 657 "failed to delete key (pos[1]=%d)", pos[1]); 658 pos[3] = rte_hash_lookup(handle, &keys[3]); 659 print_key_info("Lkp", &keys[3], pos[3]); 660 RETURN_IF_ERROR(pos[3] != expected_pos[3], 661 "failed lookup after deleting key from same bucket " 662 "(pos[3]=%d)", pos[3]); 663 664 /* Go back to previous state */ 665 pos[1] = rte_hash_add_key(handle, &keys[1]); 666 print_key_info("Add", &keys[1], pos[1]); 667 expected_pos[1] = pos[1]; 668 RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]); 669 670 /* Delete */ 671 for (i = 0; i < 5; i++) { 672 pos[i] = rte_hash_del_key(handle, &keys[i]); 673 print_key_info("Del", &keys[i], pos[i]); 674 RETURN_IF_ERROR(pos[i] != expected_pos[i], 675 "failed to delete key (pos[%u]=%d)", i, pos[i]); 676 } 677 678 /* Lookup */ 679 for (i = 0; i < 5; i++) { 680 pos[i] = rte_hash_lookup(handle, &keys[i]); 681 print_key_info("Lkp", &keys[i], pos[i]); 682 RETURN_IF_ERROR(pos[i] != -ENOENT, 683 "fail: found non-existent key (pos[%u]=%d)", i, pos[i]); 684 } 685 686 rte_hash_free(handle); 687 688 /* Cover the NULL case. */ 689 rte_hash_free(0); 690 return 0; 691 } 692 693 /******************************************************************************/ 694 static int 695 fbk_hash_unit_test(void) 696 { 697 struct rte_fbk_hash_params params = { 698 .name = "fbk_hash_test", 699 .entries = LOCAL_FBK_HASH_ENTRIES_MAX, 700 .entries_per_bucket = 4, 701 .socket_id = 0, 702 }; 703 704 struct rte_fbk_hash_params invalid_params_1 = { 705 .name = "invalid_1", 706 .entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */ 707 .entries_per_bucket = 4, 708 .socket_id = 0, 709 }; 710 711 struct rte_fbk_hash_params invalid_params_2 = { 712 .name = "invalid_2", 713 .entries = 4, 714 .entries_per_bucket = 3, /* Not power of 2 */ 715 .socket_id = 0, 716 }; 717 718 struct rte_fbk_hash_params invalid_params_3 = { 719 .name = "invalid_3", 720 .entries = 0, /* Entries is 0 */ 721 .entries_per_bucket = 4, 722 .socket_id = 0, 723 }; 724 725 struct rte_fbk_hash_params invalid_params_4 = { 726 .name = "invalid_4", 727 .entries = LOCAL_FBK_HASH_ENTRIES_MAX, 728 .entries_per_bucket = 0, /* Entries per bucket is 0 */ 729 .socket_id = 0, 730 }; 731 732 struct rte_fbk_hash_params invalid_params_5 = { 733 .name = "invalid_5", 734 .entries = 4, 735 .entries_per_bucket = 8, /* Entries per bucket > entries */ 736 .socket_id = 0, 737 }; 738 739 struct rte_fbk_hash_params invalid_params_6 = { 740 .name = "invalid_6", 741 .entries = RTE_FBK_HASH_ENTRIES_MAX * 2, /* Entries > max allowed */ 742 .entries_per_bucket = 4, 743 .socket_id = 0, 744 }; 745 746 struct rte_fbk_hash_params invalid_params_7 = { 747 .name = "invalid_7", 748 .entries = RTE_FBK_HASH_ENTRIES_MAX, 749 .entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2, /* Entries > max allowed */ 750 .socket_id = 0, 751 }; 752 753 struct rte_fbk_hash_params invalid_params_8 = { 754 .name = "invalid_7", 755 .entries = RTE_FBK_HASH_ENTRIES_MAX, 756 .entries_per_bucket = 4, 757 .socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */ 758 }; 759 760 /* try to create two hashes with identical names 761 * in this case, trying to create a second one will not 762 * fail but will simply return pointer to the existing 763 * hash with that name. sort of like a "find hash by name" :-) 764 */ 765 struct rte_fbk_hash_params invalid_params_same_name_1 = { 766 .name = "same_name", /* hash with identical name */ 767 .entries = 4, 768 .entries_per_bucket = 2, 769 .socket_id = 0, 770 }; 771 772 /* trying to create this hash should return a pointer to an existing hash */ 773 struct rte_fbk_hash_params invalid_params_same_name_2 = { 774 .name = "same_name", /* hash with identical name */ 775 .entries = RTE_FBK_HASH_ENTRIES_MAX, 776 .entries_per_bucket = 4, 777 .socket_id = 0, 778 }; 779 780 /* this is a sanity check for "same name" test 781 * creating this hash will check if we are actually able to create 782 * multiple hashes with different names (instead of having just one). 783 */ 784 struct rte_fbk_hash_params different_name = { 785 .name = "different_name", /* different name */ 786 .entries = LOCAL_FBK_HASH_ENTRIES_MAX, 787 .entries_per_bucket = 4, 788 .socket_id = 0, 789 }; 790 791 struct rte_fbk_hash_params params_jhash = { 792 .name = "valid", 793 .entries = LOCAL_FBK_HASH_ENTRIES_MAX, 794 .entries_per_bucket = 4, 795 .socket_id = 0, 796 .hash_func = rte_jhash_1word, /* Tests for different hash_func */ 797 .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT, 798 }; 799 800 struct rte_fbk_hash_params params_nohash = { 801 .name = "valid nohash", 802 .entries = LOCAL_FBK_HASH_ENTRIES_MAX, 803 .entries_per_bucket = 4, 804 .socket_id = 0, 805 .hash_func = NULL, /* Tests for null hash_func */ 806 .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT, 807 }; 808 809 struct rte_fbk_hash_table *handle, *tmp; 810 uint32_t keys[5] = 811 {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9}; 812 uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571}; 813 int status; 814 unsigned i; 815 double used_entries; 816 817 /* Try creating hashes with invalid parameters */ 818 printf("# Testing hash creation with invalid parameters " 819 "- expect error msgs\n"); 820 handle = rte_fbk_hash_create(&invalid_params_1); 821 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 822 823 handle = rte_fbk_hash_create(&invalid_params_2); 824 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 825 826 handle = rte_fbk_hash_create(&invalid_params_3); 827 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 828 829 handle = rte_fbk_hash_create(&invalid_params_4); 830 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 831 832 handle = rte_fbk_hash_create(&invalid_params_5); 833 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 834 835 handle = rte_fbk_hash_create(&invalid_params_6); 836 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 837 838 handle = rte_fbk_hash_create(&invalid_params_7); 839 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 840 841 handle = rte_fbk_hash_create(&invalid_params_8); 842 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); 843 844 handle = rte_fbk_hash_create(&invalid_params_same_name_1); 845 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded"); 846 847 tmp = rte_fbk_hash_create(&invalid_params_same_name_2); 848 if (tmp != NULL) 849 rte_fbk_hash_free(tmp); 850 RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed"); 851 852 /* we are not freeing handle here because we need a hash list 853 * to be not empty for the next test */ 854 855 /* create a hash in non-empty list - good for coverage */ 856 tmp = rte_fbk_hash_create(&different_name); 857 RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded"); 858 859 /* free both hashes */ 860 rte_fbk_hash_free(handle); 861 rte_fbk_hash_free(tmp); 862 863 /* Create empty jhash hash. */ 864 handle = rte_fbk_hash_create(¶ms_jhash); 865 RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed"); 866 867 /* Cleanup. */ 868 rte_fbk_hash_free(handle); 869 870 /* Create empty jhash hash. */ 871 handle = rte_fbk_hash_create(¶ms_nohash); 872 RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed"); 873 874 /* Cleanup. */ 875 rte_fbk_hash_free(handle); 876 877 /* Create empty hash. */ 878 handle = rte_fbk_hash_create(¶ms); 879 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed"); 880 881 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; 882 RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \ 883 "load factor right after creation is not zero but it should be"); 884 /* Add keys. */ 885 for (i = 0; i < 5; i++) { 886 status = rte_fbk_hash_add_key(handle, keys[i], vals[i]); 887 RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed"); 888 } 889 890 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; 891 RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \ 892 "load factor now is not as expected"); 893 /* Find value of added keys. */ 894 for (i = 0; i < 5; i++) { 895 status = rte_fbk_hash_lookup(handle, keys[i]); 896 RETURN_IF_ERROR_FBK(status != vals[i], 897 "fbk hash lookup failed"); 898 } 899 900 /* Change value of added keys. */ 901 for (i = 0; i < 5; i++) { 902 status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]); 903 RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed"); 904 } 905 906 /* Find new values. */ 907 for (i = 0; i < 5; i++) { 908 status = rte_fbk_hash_lookup(handle, keys[i]); 909 RETURN_IF_ERROR_FBK(status != vals[4-i], 910 "fbk hash lookup failed"); 911 } 912 913 /* Delete keys individually. */ 914 for (i = 0; i < 5; i++) { 915 status = rte_fbk_hash_delete_key(handle, keys[i]); 916 RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed"); 917 } 918 919 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; 920 RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \ 921 "load factor right after deletion is not zero but it should be"); 922 /* Lookup should now fail. */ 923 for (i = 0; i < 5; i++) { 924 status = rte_fbk_hash_lookup(handle, keys[i]); 925 RETURN_IF_ERROR_FBK(status == 0, 926 "fbk hash lookup should have failed"); 927 } 928 929 /* Add keys again. */ 930 for (i = 0; i < 5; i++) { 931 status = rte_fbk_hash_add_key(handle, keys[i], vals[i]); 932 RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed"); 933 } 934 935 /* Make sure they were added. */ 936 for (i = 0; i < 5; i++) { 937 status = rte_fbk_hash_lookup(handle, keys[i]); 938 RETURN_IF_ERROR_FBK(status != vals[i], 939 "fbk hash lookup failed"); 940 } 941 942 /* Clear all entries. */ 943 rte_fbk_hash_clear_all(handle); 944 945 /* Lookup should fail. */ 946 for (i = 0; i < 5; i++) { 947 status = rte_fbk_hash_lookup(handle, keys[i]); 948 RETURN_IF_ERROR_FBK(status == 0, 949 "fbk hash lookup should have failed"); 950 } 951 952 /* coverage */ 953 954 /* fill up the hash_table */ 955 for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++) 956 rte_fbk_hash_add_key(handle, i, (uint16_t) i); 957 958 /* Find non-existent key in a full hashtable */ 959 status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1); 960 RETURN_IF_ERROR_FBK(status != -ENOENT, 961 "fbk hash lookup succeeded"); 962 963 /* Delete non-existent key in a full hashtable */ 964 status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1); 965 RETURN_IF_ERROR_FBK(status != -ENOENT, 966 "fbk hash delete succeeded"); 967 968 /* Delete one key from a full hashtable */ 969 status = rte_fbk_hash_delete_key(handle, 1); 970 RETURN_IF_ERROR_FBK(status != 0, 971 "fbk hash delete failed"); 972 973 /* Clear all entries. */ 974 rte_fbk_hash_clear_all(handle); 975 976 /* Cleanup. */ 977 rte_fbk_hash_free(handle); 978 979 /* Cover the NULL case. */ 980 rte_fbk_hash_free(0); 981 982 return 0; 983 } 984 985 /* 986 * Sequence of operations for find existing fbk hash table 987 * 988 * - create table 989 * - find existing table: hit 990 * - find non-existing table: miss 991 * 992 */ 993 static int test_fbk_hash_find_existing(void) 994 { 995 struct rte_fbk_hash_params params = { 996 .name = "fbk_hash_find_existing", 997 .entries = LOCAL_FBK_HASH_ENTRIES_MAX, 998 .entries_per_bucket = 4, 999 .socket_id = 0, 1000 }; 1001 struct rte_fbk_hash_table *handle = NULL, *result = NULL; 1002 1003 /* Create hash table. */ 1004 handle = rte_fbk_hash_create(¶ms); 1005 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed"); 1006 1007 /* Try to find existing fbk hash table */ 1008 result = rte_fbk_hash_find_existing("fbk_hash_find_existing"); 1009 RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table"); 1010 1011 /* Try to find non-existing fbk hash table */ 1012 result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing"); 1013 RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist"); 1014 1015 /* Cleanup. */ 1016 rte_fbk_hash_free(handle); 1017 1018 return 0; 1019 } 1020 1021 #define BUCKET_ENTRIES 4 1022 /* 1023 * Do tests for hash creation with bad parameters. 1024 */ 1025 static int test_hash_creation_with_bad_parameters(void) 1026 { 1027 struct rte_hash *handle, *tmp; 1028 struct rte_hash_parameters params; 1029 1030 handle = rte_hash_create(NULL); 1031 if (handle != NULL) { 1032 rte_hash_free(handle); 1033 printf("Impossible creating hash sucessfully without any parameter\n"); 1034 return -1; 1035 } 1036 1037 memcpy(¶ms, &ut_params, sizeof(params)); 1038 params.name = "creation_with_bad_parameters_0"; 1039 params.entries = RTE_HASH_ENTRIES_MAX + 1; 1040 handle = rte_hash_create(¶ms); 1041 if (handle != NULL) { 1042 rte_hash_free(handle); 1043 printf("Impossible creating hash sucessfully with entries in parameter exceeded\n"); 1044 return -1; 1045 } 1046 1047 memcpy(¶ms, &ut_params, sizeof(params)); 1048 params.name = "creation_with_bad_parameters_2"; 1049 params.entries = BUCKET_ENTRIES - 1; 1050 handle = rte_hash_create(¶ms); 1051 if (handle != NULL) { 1052 rte_hash_free(handle); 1053 printf("Impossible creating hash sucessfully if entries less than bucket_entries in parameter\n"); 1054 return -1; 1055 } 1056 1057 memcpy(¶ms, &ut_params, sizeof(params)); 1058 params.name = "creation_with_bad_parameters_3"; 1059 params.key_len = 0; 1060 handle = rte_hash_create(¶ms); 1061 if (handle != NULL) { 1062 rte_hash_free(handle); 1063 printf("Impossible creating hash sucessfully if key_len in parameter is zero\n"); 1064 return -1; 1065 } 1066 1067 memcpy(¶ms, &ut_params, sizeof(params)); 1068 params.name = "creation_with_bad_parameters_4"; 1069 params.socket_id = RTE_MAX_NUMA_NODES + 1; 1070 handle = rte_hash_create(¶ms); 1071 if (handle != NULL) { 1072 rte_hash_free(handle); 1073 printf("Impossible creating hash sucessfully with invalid socket\n"); 1074 return -1; 1075 } 1076 1077 /* test with same name should fail */ 1078 memcpy(¶ms, &ut_params, sizeof(params)); 1079 params.name = "same_name"; 1080 handle = rte_hash_create(¶ms); 1081 if (handle == NULL) { 1082 printf("Cannot create first hash table with 'same_name'\n"); 1083 return -1; 1084 } 1085 tmp = rte_hash_create(¶ms); 1086 if (tmp != NULL) { 1087 printf("Creation of hash table with same name should fail\n"); 1088 rte_hash_free(handle); 1089 rte_hash_free(tmp); 1090 return -1; 1091 } 1092 rte_hash_free(handle); 1093 1094 printf("# Test successful. No more errors expected\n"); 1095 1096 return 0; 1097 } 1098 1099 /* 1100 * Do tests for hash creation with parameters that look incorrect 1101 * but are actually valid. 1102 */ 1103 static int 1104 test_hash_creation_with_good_parameters(void) 1105 { 1106 struct rte_hash *handle; 1107 struct rte_hash_parameters params; 1108 1109 /* create with null hash function - should choose DEFAULT_HASH_FUNC */ 1110 memcpy(¶ms, &ut_params, sizeof(params)); 1111 params.name = "name"; 1112 params.hash_func = NULL; 1113 handle = rte_hash_create(¶ms); 1114 if (handle == NULL) { 1115 printf("Creating hash with null hash_func failed\n"); 1116 return -1; 1117 } 1118 1119 rte_hash_free(handle); 1120 1121 return 0; 1122 } 1123 1124 #define ITERATIONS 3 1125 /* 1126 * Test to see the average table utilization (entries added/max entries) 1127 * before hitting a random entry that cannot be added 1128 */ 1129 static int test_average_table_utilization(void) 1130 { 1131 struct rte_hash *handle; 1132 uint8_t simple_key[MAX_KEYSIZE]; 1133 unsigned i, j; 1134 unsigned added_keys, average_keys_added = 0; 1135 int ret; 1136 1137 printf("\n# Running test to determine average utilization" 1138 "\n before adding elements begins to fail\n"); 1139 printf("Measuring performance, please wait"); 1140 fflush(stdout); 1141 ut_params.entries = 1 << 16; 1142 ut_params.name = "test_average_utilization"; 1143 ut_params.hash_func = rte_jhash; 1144 handle = rte_hash_create(&ut_params); 1145 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 1146 1147 for (j = 0; j < ITERATIONS; j++) { 1148 ret = 0; 1149 /* Add random entries until key cannot be added */ 1150 for (added_keys = 0; ret >= 0; added_keys++) { 1151 for (i = 0; i < ut_params.key_len; i++) 1152 simple_key[i] = rte_rand() % 255; 1153 ret = rte_hash_add_key(handle, simple_key); 1154 } 1155 if (ret != -ENOSPC) { 1156 printf("Unexpected error when adding keys\n"); 1157 rte_hash_free(handle); 1158 return -1; 1159 } 1160 1161 average_keys_added += added_keys; 1162 1163 /* Reset the table */ 1164 rte_hash_reset(handle); 1165 1166 /* Print a dot to show progress on operations */ 1167 printf("."); 1168 fflush(stdout); 1169 } 1170 1171 average_keys_added /= ITERATIONS; 1172 1173 printf("\nAverage table utilization = %.2f%% (%u/%u)\n", 1174 ((double) average_keys_added / ut_params.entries * 100), 1175 average_keys_added, ut_params.entries); 1176 rte_hash_free(handle); 1177 1178 return 0; 1179 } 1180 1181 #define NUM_ENTRIES 256 1182 static int test_hash_iteration(void) 1183 { 1184 struct rte_hash *handle; 1185 unsigned i; 1186 uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE]; 1187 const void *next_key; 1188 void *next_data; 1189 void *data[NUM_ENTRIES]; 1190 unsigned added_keys; 1191 uint32_t iter = 0; 1192 int ret = 0; 1193 1194 ut_params.entries = NUM_ENTRIES; 1195 ut_params.name = "test_hash_iteration"; 1196 ut_params.hash_func = rte_jhash; 1197 ut_params.key_len = 16; 1198 handle = rte_hash_create(&ut_params); 1199 RETURN_IF_ERROR(handle == NULL, "hash creation failed"); 1200 1201 /* Add random entries until key cannot be added */ 1202 for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) { 1203 data[added_keys] = (void *) ((uintptr_t) rte_rand()); 1204 for (i = 0; i < ut_params.key_len; i++) 1205 keys[added_keys][i] = rte_rand() % 255; 1206 ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]); 1207 if (ret < 0) 1208 break; 1209 } 1210 1211 /* Iterate through the hash table */ 1212 while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) { 1213 /* Search for the key in the list of keys added */ 1214 for (i = 0; i < NUM_ENTRIES; i++) { 1215 if (memcmp(next_key, keys[i], ut_params.key_len) == 0) { 1216 if (next_data != data[i]) { 1217 printf("Data found in the hash table is" 1218 "not the data added with the key\n"); 1219 goto err; 1220 } 1221 added_keys--; 1222 break; 1223 } 1224 } 1225 if (i == NUM_ENTRIES) { 1226 printf("Key found in the hash table was not added\n"); 1227 goto err; 1228 } 1229 } 1230 1231 /* Check if all keys have been iterated */ 1232 if (added_keys != 0) { 1233 printf("There were still %u keys to iterate\n", added_keys); 1234 goto err; 1235 } 1236 1237 rte_hash_free(handle); 1238 return 0; 1239 1240 err: 1241 rte_hash_free(handle); 1242 return -1; 1243 } 1244 1245 static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03, 1246 0x04, 0x05, 0x06, 0x07, 1247 0x08, 0x09, 0x0a, 0x0b, 1248 0x0c, 0x0d, 0x0e, 0x0f}; 1249 static struct rte_hash_parameters hash_params_ex = { 1250 .name = NULL, 1251 .entries = 64, 1252 .key_len = 0, 1253 .hash_func = NULL, 1254 .hash_func_init_val = 0, 1255 .socket_id = 0, 1256 }; 1257 1258 /* 1259 * add/delete key with jhash2 1260 */ 1261 static int 1262 test_hash_add_delete_jhash2(void) 1263 { 1264 int ret = -1; 1265 struct rte_hash *handle; 1266 int32_t pos1, pos2; 1267 1268 hash_params_ex.name = "hash_test_jhash2"; 1269 hash_params_ex.key_len = 4; 1270 hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b; 1271 1272 handle = rte_hash_create(&hash_params_ex); 1273 if (handle == NULL) { 1274 printf("test_hash_add_delete_jhash2 fail to create hash\n"); 1275 goto fail_jhash2; 1276 } 1277 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1278 if (pos1 < 0) { 1279 printf("test_hash_add_delete_jhash2 fail to add hash key\n"); 1280 goto fail_jhash2; 1281 } 1282 1283 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1284 if (pos2 < 0 || pos1 != pos2) { 1285 printf("test_hash_add_delete_jhash2 delete different key from being added\n"); 1286 goto fail_jhash2; 1287 } 1288 ret = 0; 1289 1290 fail_jhash2: 1291 if (handle != NULL) 1292 rte_hash_free(handle); 1293 1294 return ret; 1295 } 1296 1297 /* 1298 * add/delete (2) key with jhash2 1299 */ 1300 static int 1301 test_hash_add_delete_2_jhash2(void) 1302 { 1303 int ret = -1; 1304 struct rte_hash *handle; 1305 int32_t pos1, pos2; 1306 1307 hash_params_ex.name = "hash_test_2_jhash2"; 1308 hash_params_ex.key_len = 8; 1309 hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b; 1310 1311 handle = rte_hash_create(&hash_params_ex); 1312 if (handle == NULL) 1313 goto fail_2_jhash2; 1314 1315 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1316 if (pos1 < 0) 1317 goto fail_2_jhash2; 1318 1319 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1320 if (pos2 < 0 || pos1 != pos2) 1321 goto fail_2_jhash2; 1322 1323 ret = 0; 1324 1325 fail_2_jhash2: 1326 if (handle != NULL) 1327 rte_hash_free(handle); 1328 1329 return ret; 1330 } 1331 1332 static uint32_t 1333 test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval) 1334 { 1335 const uint32_t *k = key; 1336 1337 RTE_SET_USED(length); 1338 1339 return rte_jhash_1word(k[0], initval); 1340 } 1341 1342 static uint32_t 1343 test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval) 1344 { 1345 const uint32_t *k = key; 1346 1347 RTE_SET_USED(length); 1348 1349 return rte_jhash_2words(k[0], k[1], initval); 1350 } 1351 1352 static uint32_t 1353 test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval) 1354 { 1355 const uint32_t *k = key; 1356 1357 RTE_SET_USED(length); 1358 1359 return rte_jhash_3words(k[0], k[1], k[2], initval); 1360 } 1361 1362 /* 1363 * add/delete key with jhash 1word 1364 */ 1365 static int 1366 test_hash_add_delete_jhash_1word(void) 1367 { 1368 int ret = -1; 1369 struct rte_hash *handle; 1370 int32_t pos1, pos2; 1371 1372 hash_params_ex.name = "hash_test_jhash_1word"; 1373 hash_params_ex.key_len = 4; 1374 hash_params_ex.hash_func = test_hash_jhash_1word; 1375 1376 handle = rte_hash_create(&hash_params_ex); 1377 if (handle == NULL) 1378 goto fail_jhash_1word; 1379 1380 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1381 if (pos1 < 0) 1382 goto fail_jhash_1word; 1383 1384 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1385 if (pos2 < 0 || pos1 != pos2) 1386 goto fail_jhash_1word; 1387 1388 ret = 0; 1389 1390 fail_jhash_1word: 1391 if (handle != NULL) 1392 rte_hash_free(handle); 1393 1394 return ret; 1395 } 1396 1397 /* 1398 * add/delete key with jhash 2word 1399 */ 1400 static int 1401 test_hash_add_delete_jhash_2word(void) 1402 { 1403 int ret = -1; 1404 struct rte_hash *handle; 1405 int32_t pos1, pos2; 1406 1407 hash_params_ex.name = "hash_test_jhash_2word"; 1408 hash_params_ex.key_len = 8; 1409 hash_params_ex.hash_func = test_hash_jhash_2word; 1410 1411 handle = rte_hash_create(&hash_params_ex); 1412 if (handle == NULL) 1413 goto fail_jhash_2word; 1414 1415 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1416 if (pos1 < 0) 1417 goto fail_jhash_2word; 1418 1419 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1420 if (pos2 < 0 || pos1 != pos2) 1421 goto fail_jhash_2word; 1422 1423 ret = 0; 1424 1425 fail_jhash_2word: 1426 if (handle != NULL) 1427 rte_hash_free(handle); 1428 1429 return ret; 1430 } 1431 1432 /* 1433 * add/delete key with jhash 3word 1434 */ 1435 static int 1436 test_hash_add_delete_jhash_3word(void) 1437 { 1438 int ret = -1; 1439 struct rte_hash *handle; 1440 int32_t pos1, pos2; 1441 1442 hash_params_ex.name = "hash_test_jhash_3word"; 1443 hash_params_ex.key_len = 12; 1444 hash_params_ex.hash_func = test_hash_jhash_3word; 1445 1446 handle = rte_hash_create(&hash_params_ex); 1447 if (handle == NULL) 1448 goto fail_jhash_3word; 1449 1450 pos1 = rte_hash_add_key(handle, (void *)&key[0]); 1451 if (pos1 < 0) 1452 goto fail_jhash_3word; 1453 1454 pos2 = rte_hash_del_key(handle, (void *)&key[0]); 1455 if (pos2 < 0 || pos1 != pos2) 1456 goto fail_jhash_3word; 1457 1458 ret = 0; 1459 1460 fail_jhash_3word: 1461 if (handle != NULL) 1462 rte_hash_free(handle); 1463 1464 return ret; 1465 } 1466 1467 /* 1468 * Do all unit and performance tests. 1469 */ 1470 static int 1471 test_hash(void) 1472 { 1473 if (test_add_delete() < 0) 1474 return -1; 1475 if (test_hash_add_delete_jhash2() < 0) 1476 return -1; 1477 if (test_hash_add_delete_2_jhash2() < 0) 1478 return -1; 1479 if (test_hash_add_delete_jhash_1word() < 0) 1480 return -1; 1481 if (test_hash_add_delete_jhash_2word() < 0) 1482 return -1; 1483 if (test_hash_add_delete_jhash_3word() < 0) 1484 return -1; 1485 if (test_hash_get_key_with_position() < 0) 1486 return -1; 1487 if (test_hash_find_existing() < 0) 1488 return -1; 1489 if (test_add_update_delete() < 0) 1490 return -1; 1491 if (test_five_keys() < 0) 1492 return -1; 1493 if (test_full_bucket() < 0) 1494 return -1; 1495 1496 if (test_fbk_hash_find_existing() < 0) 1497 return -1; 1498 if (fbk_hash_unit_test() < 0) 1499 return -1; 1500 if (test_hash_creation_with_bad_parameters() < 0) 1501 return -1; 1502 if (test_hash_creation_with_good_parameters() < 0) 1503 return -1; 1504 if (test_average_table_utilization() < 0) 1505 return -1; 1506 if (test_hash_iteration() < 0) 1507 return -1; 1508 1509 run_hash_func_tests(); 1510 1511 if (test_crc32_hash_alg_equiv() < 0) 1512 return -1; 1513 1514 return 0; 1515 } 1516 1517 REGISTER_TEST_COMMAND(hash_autotest, test_hash); 1518