1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include "test.h" 6 7 #ifdef RTE_EXEC_ENV_WINDOWS 8 static int 9 test_lpm(void) 10 { 11 printf("lpm not supported on Windows, skipping test\n"); 12 return TEST_SKIPPED; 13 } 14 15 #else 16 17 #include <stdio.h> 18 #include <stdint.h> 19 #include <stdlib.h> 20 21 #include <rte_ip.h> 22 #include <rte_lpm.h> 23 #include <rte_malloc.h> 24 25 #include "test_xmmt_ops.h" 26 27 #define TEST_LPM_ASSERT(cond) do { \ 28 if (!(cond)) { \ 29 printf("Error at line %d: \n", __LINE__); \ 30 return -1; \ 31 } \ 32 } while(0) 33 34 typedef int32_t (*rte_lpm_test)(void); 35 36 static int32_t test0(void); 37 static int32_t test1(void); 38 static int32_t test2(void); 39 static int32_t test3(void); 40 static int32_t test4(void); 41 static int32_t test5(void); 42 static int32_t test6(void); 43 static int32_t test7(void); 44 static int32_t test8(void); 45 static int32_t test9(void); 46 static int32_t test10(void); 47 static int32_t test11(void); 48 static int32_t test12(void); 49 static int32_t test13(void); 50 static int32_t test14(void); 51 static int32_t test15(void); 52 static int32_t test16(void); 53 static int32_t test17(void); 54 static int32_t test18(void); 55 static int32_t test19(void); 56 static int32_t test20(void); 57 static int32_t test21(void); 58 59 rte_lpm_test tests[] = { 60 /* Test Cases */ 61 test0, 62 test1, 63 test2, 64 test3, 65 test4, 66 test5, 67 test6, 68 test7, 69 test8, 70 test9, 71 test10, 72 test11, 73 test12, 74 test13, 75 test14, 76 test15, 77 test16, 78 test17, 79 test18, 80 test19, 81 test20, 82 test21 83 }; 84 85 #define MAX_DEPTH 32 86 #define MAX_RULES 256 87 #define NUMBER_TBL8S 256 88 #define PASS 0 89 90 /* 91 * Check that rte_lpm_create fails gracefully for incorrect user input 92 * arguments 93 */ 94 int32_t 95 test0(void) 96 { 97 struct rte_lpm *lpm = NULL; 98 struct rte_lpm_config config; 99 100 config.max_rules = MAX_RULES; 101 config.number_tbl8s = NUMBER_TBL8S; 102 config.flags = 0; 103 104 /* rte_lpm_create: lpm name == NULL */ 105 lpm = rte_lpm_create(NULL, SOCKET_ID_ANY, &config); 106 TEST_LPM_ASSERT(lpm == NULL); 107 108 /* rte_lpm_create: max_rules = 0 */ 109 /* Note: __func__ inserts the function name, in this case "test0". */ 110 config.max_rules = 0; 111 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 112 TEST_LPM_ASSERT(lpm == NULL); 113 114 /* socket_id < -1 is invalid */ 115 config.max_rules = MAX_RULES; 116 lpm = rte_lpm_create(__func__, -2, &config); 117 TEST_LPM_ASSERT(lpm == NULL); 118 119 return PASS; 120 } 121 122 /* 123 * Create lpm table then delete lpm table 100 times 124 * Use a slightly different rules size each time 125 * */ 126 int32_t 127 test1(void) 128 { 129 struct rte_lpm *lpm = NULL; 130 struct rte_lpm_config config; 131 132 config.number_tbl8s = NUMBER_TBL8S; 133 config.flags = 0; 134 int32_t i; 135 136 /* rte_lpm_free: Free NULL */ 137 for (i = 0; i < 100; i++) { 138 config.max_rules = MAX_RULES - i; 139 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 140 TEST_LPM_ASSERT(lpm != NULL); 141 142 rte_lpm_free(lpm); 143 } 144 145 /* Can not test free so return success */ 146 return PASS; 147 } 148 149 /* 150 * Call rte_lpm_free for NULL pointer user input. Note: free has no return and 151 * therefore it is impossible to check for failure but this test is added to 152 * increase function coverage metrics and to validate that freeing null does 153 * not crash. 154 */ 155 int32_t 156 test2(void) 157 { 158 struct rte_lpm *lpm = NULL; 159 struct rte_lpm_config config; 160 161 config.max_rules = MAX_RULES; 162 config.number_tbl8s = NUMBER_TBL8S; 163 config.flags = 0; 164 165 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 166 TEST_LPM_ASSERT(lpm != NULL); 167 168 rte_lpm_free(lpm); 169 rte_lpm_free(NULL); 170 return PASS; 171 } 172 173 /* 174 * Check that rte_lpm_add fails gracefully for incorrect user input arguments 175 */ 176 int32_t 177 test3(void) 178 { 179 struct rte_lpm *lpm = NULL; 180 struct rte_lpm_config config; 181 182 config.max_rules = MAX_RULES; 183 config.number_tbl8s = NUMBER_TBL8S; 184 config.flags = 0; 185 uint32_t ip = RTE_IPV4(0, 0, 0, 0), next_hop = 100; 186 uint8_t depth = 24; 187 int32_t status = 0; 188 189 /* rte_lpm_add: lpm == NULL */ 190 status = rte_lpm_add(NULL, ip, depth, next_hop); 191 TEST_LPM_ASSERT(status < 0); 192 193 /*Create valid lpm to use in rest of test. */ 194 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 195 TEST_LPM_ASSERT(lpm != NULL); 196 197 /* rte_lpm_add: depth < 1 */ 198 status = rte_lpm_add(lpm, ip, 0, next_hop); 199 TEST_LPM_ASSERT(status < 0); 200 201 /* rte_lpm_add: depth > MAX_DEPTH */ 202 status = rte_lpm_add(lpm, ip, (MAX_DEPTH + 1), next_hop); 203 TEST_LPM_ASSERT(status < 0); 204 205 rte_lpm_free(lpm); 206 207 return PASS; 208 } 209 210 /* 211 * Check that rte_lpm_delete fails gracefully for incorrect user input 212 * arguments 213 */ 214 int32_t 215 test4(void) 216 { 217 struct rte_lpm *lpm = NULL; 218 struct rte_lpm_config config; 219 220 config.max_rules = MAX_RULES; 221 config.number_tbl8s = NUMBER_TBL8S; 222 config.flags = 0; 223 uint32_t ip = RTE_IPV4(0, 0, 0, 0); 224 uint8_t depth = 24; 225 int32_t status = 0; 226 227 /* rte_lpm_delete: lpm == NULL */ 228 status = rte_lpm_delete(NULL, ip, depth); 229 TEST_LPM_ASSERT(status < 0); 230 231 /*Create valid lpm to use in rest of test. */ 232 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 233 TEST_LPM_ASSERT(lpm != NULL); 234 235 /* rte_lpm_delete: depth < 1 */ 236 status = rte_lpm_delete(lpm, ip, 0); 237 TEST_LPM_ASSERT(status < 0); 238 239 /* rte_lpm_delete: depth > MAX_DEPTH */ 240 status = rte_lpm_delete(lpm, ip, (MAX_DEPTH + 1)); 241 TEST_LPM_ASSERT(status < 0); 242 243 rte_lpm_free(lpm); 244 245 return PASS; 246 } 247 248 /* 249 * Check that rte_lpm_lookup fails gracefully for incorrect user input 250 * arguments 251 */ 252 int32_t 253 test5(void) 254 { 255 #if defined(RTE_LIBRTE_LPM_DEBUG) 256 struct rte_lpm *lpm = NULL; 257 struct rte_lpm_config config; 258 259 config.max_rules = MAX_RULES; 260 config.number_tbl8s = NUMBER_TBL8S; 261 config.flags = 0; 262 uint32_t ip = RTE_IPV4(0, 0, 0, 0), next_hop_return = 0; 263 int32_t status = 0; 264 265 /* rte_lpm_lookup: lpm == NULL */ 266 status = rte_lpm_lookup(NULL, ip, &next_hop_return); 267 TEST_LPM_ASSERT(status < 0); 268 269 /*Create valid lpm to use in rest of test. */ 270 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 271 TEST_LPM_ASSERT(lpm != NULL); 272 273 /* rte_lpm_lookup: depth < 1 */ 274 status = rte_lpm_lookup(lpm, ip, NULL); 275 TEST_LPM_ASSERT(status < 0); 276 277 rte_lpm_free(lpm); 278 #endif 279 return PASS; 280 } 281 282 283 284 /* 285 * Call add, lookup and delete for a single rule with depth <= 24 286 */ 287 int32_t 288 test6(void) 289 { 290 struct rte_lpm *lpm = NULL; 291 struct rte_lpm_config config; 292 293 config.max_rules = MAX_RULES; 294 config.number_tbl8s = NUMBER_TBL8S; 295 config.flags = 0; 296 uint32_t ip = RTE_IPV4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0; 297 uint8_t depth = 24; 298 int32_t status = 0; 299 300 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 301 TEST_LPM_ASSERT(lpm != NULL); 302 303 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 304 TEST_LPM_ASSERT(status == 0); 305 306 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 307 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 308 309 status = rte_lpm_delete(lpm, ip, depth); 310 TEST_LPM_ASSERT(status == 0); 311 312 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 313 TEST_LPM_ASSERT(status == -ENOENT); 314 315 rte_lpm_free(lpm); 316 317 return PASS; 318 } 319 320 /* 321 * Call add, lookup and delete for a single rule with depth > 24 322 */ 323 324 int32_t 325 test7(void) 326 { 327 xmm_t ipx4; 328 uint32_t hop[4]; 329 struct rte_lpm *lpm = NULL; 330 struct rte_lpm_config config; 331 332 config.max_rules = MAX_RULES; 333 config.number_tbl8s = NUMBER_TBL8S; 334 config.flags = 0; 335 uint32_t ip = RTE_IPV4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0; 336 uint8_t depth = 32; 337 int32_t status = 0; 338 339 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 340 TEST_LPM_ASSERT(lpm != NULL); 341 342 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 343 TEST_LPM_ASSERT(status == 0); 344 345 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 346 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 347 348 ipx4 = vect_set_epi32(ip, ip + 0x100, ip - 0x100, ip); 349 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 350 TEST_LPM_ASSERT(hop[0] == next_hop_add); 351 TEST_LPM_ASSERT(hop[1] == UINT32_MAX); 352 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 353 TEST_LPM_ASSERT(hop[3] == next_hop_add); 354 355 status = rte_lpm_delete(lpm, ip, depth); 356 TEST_LPM_ASSERT(status == 0); 357 358 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 359 TEST_LPM_ASSERT(status == -ENOENT); 360 361 rte_lpm_free(lpm); 362 363 return PASS; 364 } 365 366 /* 367 * Use rte_lpm_add to add rules which effect only the second half of the lpm 368 * table. Use all possible depths ranging from 1..32. Set the next hop = to the 369 * depth. Check lookup hit for on every add and check for lookup miss on the 370 * first half of the lpm table after each add. Finally delete all rules going 371 * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each 372 * delete. The lookup should return the next_hop_add value related to the 373 * previous depth value (i.e. depth -1). 374 */ 375 int32_t 376 test8(void) 377 { 378 xmm_t ipx4; 379 uint32_t hop[4]; 380 struct rte_lpm *lpm = NULL; 381 struct rte_lpm_config config; 382 383 config.max_rules = MAX_RULES; 384 config.number_tbl8s = NUMBER_TBL8S; 385 config.flags = 0; 386 uint32_t ip1 = RTE_IPV4(127, 255, 255, 255), ip2 = RTE_IPV4(128, 0, 0, 0); 387 uint32_t next_hop_add, next_hop_return; 388 uint8_t depth; 389 int32_t status = 0; 390 391 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 392 TEST_LPM_ASSERT(lpm != NULL); 393 394 /* Loop with rte_lpm_add. */ 395 for (depth = 1; depth <= 32; depth++) { 396 /* Let the next_hop_add value = depth. Just for change. */ 397 next_hop_add = depth; 398 399 status = rte_lpm_add(lpm, ip2, depth, next_hop_add); 400 TEST_LPM_ASSERT(status == 0); 401 402 /* Check IP in first half of tbl24 which should be empty. */ 403 status = rte_lpm_lookup(lpm, ip1, &next_hop_return); 404 TEST_LPM_ASSERT(status == -ENOENT); 405 406 status = rte_lpm_lookup(lpm, ip2, &next_hop_return); 407 TEST_LPM_ASSERT((status == 0) && 408 (next_hop_return == next_hop_add)); 409 410 ipx4 = vect_set_epi32(ip2, ip1, ip2, ip1); 411 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 412 TEST_LPM_ASSERT(hop[0] == UINT32_MAX); 413 TEST_LPM_ASSERT(hop[1] == next_hop_add); 414 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 415 TEST_LPM_ASSERT(hop[3] == next_hop_add); 416 } 417 418 /* Loop with rte_lpm_delete. */ 419 for (depth = 32; depth >= 1; depth--) { 420 next_hop_add = (uint8_t) (depth - 1); 421 422 status = rte_lpm_delete(lpm, ip2, depth); 423 TEST_LPM_ASSERT(status == 0); 424 425 status = rte_lpm_lookup(lpm, ip2, &next_hop_return); 426 427 if (depth != 1) { 428 TEST_LPM_ASSERT((status == 0) && 429 (next_hop_return == next_hop_add)); 430 } else { 431 TEST_LPM_ASSERT(status == -ENOENT); 432 } 433 434 status = rte_lpm_lookup(lpm, ip1, &next_hop_return); 435 TEST_LPM_ASSERT(status == -ENOENT); 436 437 ipx4 = vect_set_epi32(ip1, ip1, ip2, ip2); 438 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 439 if (depth != 1) { 440 TEST_LPM_ASSERT(hop[0] == next_hop_add); 441 TEST_LPM_ASSERT(hop[1] == next_hop_add); 442 } else { 443 TEST_LPM_ASSERT(hop[0] == UINT32_MAX); 444 TEST_LPM_ASSERT(hop[1] == UINT32_MAX); 445 } 446 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 447 TEST_LPM_ASSERT(hop[3] == UINT32_MAX); 448 } 449 450 rte_lpm_free(lpm); 451 452 return PASS; 453 } 454 455 /* 456 * - Add & lookup to hit invalid TBL24 entry 457 * - Add & lookup to hit valid TBL24 entry not extended 458 * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry 459 * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry 460 * 461 */ 462 int32_t 463 test9(void) 464 { 465 struct rte_lpm *lpm = NULL; 466 struct rte_lpm_config config; 467 468 config.max_rules = MAX_RULES; 469 config.number_tbl8s = NUMBER_TBL8S; 470 config.flags = 0; 471 uint32_t ip, ip_1, ip_2; 472 uint8_t depth, depth_1, depth_2; 473 uint32_t next_hop_add, next_hop_add_1, next_hop_add_2, next_hop_return; 474 int32_t status = 0; 475 476 /* Add & lookup to hit invalid TBL24 entry */ 477 ip = RTE_IPV4(128, 0, 0, 0); 478 depth = 24; 479 next_hop_add = 100; 480 481 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 482 TEST_LPM_ASSERT(lpm != NULL); 483 484 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 485 TEST_LPM_ASSERT(status == 0); 486 487 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 488 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 489 490 status = rte_lpm_delete(lpm, ip, depth); 491 TEST_LPM_ASSERT(status == 0); 492 493 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 494 TEST_LPM_ASSERT(status == -ENOENT); 495 496 rte_lpm_delete_all(lpm); 497 498 /* Add & lookup to hit valid TBL24 entry not extended */ 499 ip = RTE_IPV4(128, 0, 0, 0); 500 depth = 23; 501 next_hop_add = 100; 502 503 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 504 TEST_LPM_ASSERT(status == 0); 505 506 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 507 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 508 509 depth = 24; 510 next_hop_add = 101; 511 512 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 513 TEST_LPM_ASSERT(status == 0); 514 515 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 516 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 517 518 depth = 24; 519 520 status = rte_lpm_delete(lpm, ip, depth); 521 TEST_LPM_ASSERT(status == 0); 522 523 depth = 23; 524 525 status = rte_lpm_delete(lpm, ip, depth); 526 TEST_LPM_ASSERT(status == 0); 527 528 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 529 TEST_LPM_ASSERT(status == -ENOENT); 530 531 rte_lpm_delete_all(lpm); 532 533 /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8 534 * entry */ 535 ip = RTE_IPV4(128, 0, 0, 0); 536 depth = 32; 537 next_hop_add = 100; 538 539 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 540 TEST_LPM_ASSERT(status == 0); 541 542 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 543 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 544 545 ip = RTE_IPV4(128, 0, 0, 5); 546 depth = 32; 547 next_hop_add = 101; 548 549 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 550 TEST_LPM_ASSERT(status == 0); 551 552 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 553 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 554 555 status = rte_lpm_delete(lpm, ip, depth); 556 TEST_LPM_ASSERT(status == 0); 557 558 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 559 TEST_LPM_ASSERT(status == -ENOENT); 560 561 ip = RTE_IPV4(128, 0, 0, 0); 562 depth = 32; 563 next_hop_add = 100; 564 565 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 566 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 567 568 status = rte_lpm_delete(lpm, ip, depth); 569 TEST_LPM_ASSERT(status == 0); 570 571 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 572 TEST_LPM_ASSERT(status == -ENOENT); 573 574 rte_lpm_delete_all(lpm); 575 576 /* Add & lookup to hit valid extended TBL24 entry with valid TBL8 577 * entry */ 578 ip_1 = RTE_IPV4(128, 0, 0, 0); 579 depth_1 = 25; 580 next_hop_add_1 = 101; 581 582 ip_2 = RTE_IPV4(128, 0, 0, 5); 583 depth_2 = 32; 584 next_hop_add_2 = 102; 585 586 next_hop_return = 0; 587 588 status = rte_lpm_add(lpm, ip_1, depth_1, next_hop_add_1); 589 TEST_LPM_ASSERT(status == 0); 590 591 status = rte_lpm_lookup(lpm, ip_1, &next_hop_return); 592 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); 593 594 status = rte_lpm_add(lpm, ip_2, depth_2, next_hop_add_2); 595 TEST_LPM_ASSERT(status == 0); 596 597 status = rte_lpm_lookup(lpm, ip_2, &next_hop_return); 598 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2)); 599 600 status = rte_lpm_delete(lpm, ip_2, depth_2); 601 TEST_LPM_ASSERT(status == 0); 602 603 status = rte_lpm_lookup(lpm, ip_2, &next_hop_return); 604 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); 605 606 status = rte_lpm_delete(lpm, ip_1, depth_1); 607 TEST_LPM_ASSERT(status == 0); 608 609 status = rte_lpm_lookup(lpm, ip_1, &next_hop_return); 610 TEST_LPM_ASSERT(status == -ENOENT); 611 612 rte_lpm_free(lpm); 613 614 return PASS; 615 } 616 617 618 /* 619 * - Add rule that covers a TBL24 range previously invalid & lookup (& delete & 620 * lookup) 621 * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup) 622 * - Add rule that extends a TBL24 valid entry & lookup for both rules (& 623 * delete & lookup) 624 * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup) 625 * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup) 626 * - Delete a rule that is not present in the TBL24 & lookup 627 * - Delete a rule that is not present in the TBL8 & lookup 628 * 629 */ 630 int32_t 631 test10(void) 632 { 633 634 struct rte_lpm *lpm = NULL; 635 struct rte_lpm_config config; 636 637 config.max_rules = MAX_RULES; 638 config.number_tbl8s = NUMBER_TBL8S; 639 config.flags = 0; 640 uint32_t ip, next_hop_add, next_hop_return; 641 uint8_t depth; 642 int32_t status = 0; 643 644 /* Add rule that covers a TBL24 range previously invalid & lookup 645 * (& delete & lookup) */ 646 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 647 TEST_LPM_ASSERT(lpm != NULL); 648 649 ip = RTE_IPV4(128, 0, 0, 0); 650 depth = 16; 651 next_hop_add = 100; 652 653 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 654 TEST_LPM_ASSERT(status == 0); 655 656 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 657 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 658 659 status = rte_lpm_delete(lpm, ip, depth); 660 TEST_LPM_ASSERT(status == 0); 661 662 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 663 TEST_LPM_ASSERT(status == -ENOENT); 664 665 rte_lpm_delete_all(lpm); 666 667 ip = RTE_IPV4(128, 0, 0, 0); 668 depth = 25; 669 next_hop_add = 100; 670 671 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 672 TEST_LPM_ASSERT(status == 0); 673 674 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 675 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 676 677 status = rte_lpm_delete(lpm, ip, depth); 678 TEST_LPM_ASSERT(status == 0); 679 680 rte_lpm_delete_all(lpm); 681 682 /* Add rule that extends a TBL24 valid entry & lookup for both rules 683 * (& delete & lookup) */ 684 685 ip = RTE_IPV4(128, 0, 0, 0); 686 depth = 24; 687 next_hop_add = 100; 688 689 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 690 TEST_LPM_ASSERT(status == 0); 691 692 ip = RTE_IPV4(128, 0, 0, 10); 693 depth = 32; 694 next_hop_add = 101; 695 696 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 697 TEST_LPM_ASSERT(status == 0); 698 699 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 700 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 701 702 ip = RTE_IPV4(128, 0, 0, 0); 703 next_hop_add = 100; 704 705 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 706 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 707 708 ip = RTE_IPV4(128, 0, 0, 0); 709 depth = 24; 710 711 status = rte_lpm_delete(lpm, ip, depth); 712 TEST_LPM_ASSERT(status == 0); 713 714 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 715 TEST_LPM_ASSERT(status == -ENOENT); 716 717 ip = RTE_IPV4(128, 0, 0, 10); 718 depth = 32; 719 720 status = rte_lpm_delete(lpm, ip, depth); 721 TEST_LPM_ASSERT(status == 0); 722 723 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 724 TEST_LPM_ASSERT(status == -ENOENT); 725 726 rte_lpm_delete_all(lpm); 727 728 /* Add rule that updates the next hop in TBL24 & lookup 729 * (& delete & lookup) */ 730 731 ip = RTE_IPV4(128, 0, 0, 0); 732 depth = 24; 733 next_hop_add = 100; 734 735 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 736 TEST_LPM_ASSERT(status == 0); 737 738 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 739 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 740 741 next_hop_add = 101; 742 743 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 744 TEST_LPM_ASSERT(status == 0); 745 746 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 747 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 748 749 status = rte_lpm_delete(lpm, ip, depth); 750 TEST_LPM_ASSERT(status == 0); 751 752 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 753 TEST_LPM_ASSERT(status == -ENOENT); 754 755 rte_lpm_delete_all(lpm); 756 757 /* Add rule that updates the next hop in TBL8 & lookup 758 * (& delete & lookup) */ 759 760 ip = RTE_IPV4(128, 0, 0, 0); 761 depth = 32; 762 next_hop_add = 100; 763 764 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 765 TEST_LPM_ASSERT(status == 0); 766 767 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 768 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 769 770 next_hop_add = 101; 771 772 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 773 TEST_LPM_ASSERT(status == 0); 774 775 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 776 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 777 778 status = rte_lpm_delete(lpm, ip, depth); 779 TEST_LPM_ASSERT(status == 0); 780 781 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 782 TEST_LPM_ASSERT(status == -ENOENT); 783 784 rte_lpm_delete_all(lpm); 785 786 /* Delete a rule that is not present in the TBL24 & lookup */ 787 788 ip = RTE_IPV4(128, 0, 0, 0); 789 depth = 24; 790 791 status = rte_lpm_delete(lpm, ip, depth); 792 TEST_LPM_ASSERT(status < 0); 793 794 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 795 TEST_LPM_ASSERT(status == -ENOENT); 796 797 rte_lpm_delete_all(lpm); 798 799 /* Delete a rule that is not present in the TBL8 & lookup */ 800 801 ip = RTE_IPV4(128, 0, 0, 0); 802 depth = 32; 803 804 status = rte_lpm_delete(lpm, ip, depth); 805 TEST_LPM_ASSERT(status < 0); 806 807 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 808 TEST_LPM_ASSERT(status == -ENOENT); 809 810 rte_lpm_free(lpm); 811 812 return PASS; 813 } 814 815 /* 816 * Add two rules, lookup to hit the more specific one, lookup to hit the less 817 * specific one delete the less specific rule and lookup previous values again; 818 * add a more specific rule than the existing rule, lookup again 819 * 820 * */ 821 int32_t 822 test11(void) 823 { 824 825 struct rte_lpm *lpm = NULL; 826 struct rte_lpm_config config; 827 828 config.max_rules = MAX_RULES; 829 config.number_tbl8s = NUMBER_TBL8S; 830 config.flags = 0; 831 uint32_t ip, next_hop_add, next_hop_return; 832 uint8_t depth; 833 int32_t status = 0; 834 835 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 836 TEST_LPM_ASSERT(lpm != NULL); 837 838 ip = RTE_IPV4(128, 0, 0, 0); 839 depth = 24; 840 next_hop_add = 100; 841 842 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 843 TEST_LPM_ASSERT(status == 0); 844 845 ip = RTE_IPV4(128, 0, 0, 10); 846 depth = 32; 847 next_hop_add = 101; 848 849 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 850 TEST_LPM_ASSERT(status == 0); 851 852 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 853 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 854 855 ip = RTE_IPV4(128, 0, 0, 0); 856 next_hop_add = 100; 857 858 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 859 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 860 861 ip = RTE_IPV4(128, 0, 0, 0); 862 depth = 24; 863 864 status = rte_lpm_delete(lpm, ip, depth); 865 TEST_LPM_ASSERT(status == 0); 866 867 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 868 TEST_LPM_ASSERT(status == -ENOENT); 869 870 ip = RTE_IPV4(128, 0, 0, 10); 871 depth = 32; 872 873 status = rte_lpm_delete(lpm, ip, depth); 874 TEST_LPM_ASSERT(status == 0); 875 876 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 877 TEST_LPM_ASSERT(status == -ENOENT); 878 879 rte_lpm_free(lpm); 880 881 return PASS; 882 } 883 884 /* 885 * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete, 886 * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension 887 * and contraction. 888 * 889 * */ 890 891 int32_t 892 test12(void) 893 { 894 xmm_t ipx4; 895 uint32_t hop[4]; 896 struct rte_lpm *lpm = NULL; 897 struct rte_lpm_config config; 898 899 config.max_rules = MAX_RULES; 900 config.number_tbl8s = NUMBER_TBL8S; 901 config.flags = 0; 902 uint32_t ip, i, next_hop_add, next_hop_return; 903 uint8_t depth; 904 int32_t status = 0; 905 906 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 907 TEST_LPM_ASSERT(lpm != NULL); 908 909 ip = RTE_IPV4(128, 0, 0, 0); 910 depth = 32; 911 next_hop_add = 100; 912 913 for (i = 0; i < 1000; i++) { 914 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 915 TEST_LPM_ASSERT(status == 0); 916 917 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 918 TEST_LPM_ASSERT((status == 0) && 919 (next_hop_return == next_hop_add)); 920 921 ipx4 = vect_set_epi32(ip, ip + 1, ip, ip - 1); 922 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 923 TEST_LPM_ASSERT(hop[0] == UINT32_MAX); 924 TEST_LPM_ASSERT(hop[1] == next_hop_add); 925 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 926 TEST_LPM_ASSERT(hop[3] == next_hop_add); 927 928 status = rte_lpm_delete(lpm, ip, depth); 929 TEST_LPM_ASSERT(status == 0); 930 931 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 932 TEST_LPM_ASSERT(status == -ENOENT); 933 } 934 935 rte_lpm_free(lpm); 936 937 return PASS; 938 } 939 940 /* 941 * Add a rule to tbl24, lookup (hit), then add a rule that will extend this 942 * tbl24 entry, lookup (hit). delete the rule that caused the tbl24 extension, 943 * lookup (miss) and repeat for loop of 1000 times. This will check tbl8 944 * extension and contraction. 945 * 946 * */ 947 948 int32_t 949 test13(void) 950 { 951 struct rte_lpm *lpm = NULL; 952 struct rte_lpm_config config; 953 954 config.max_rules = MAX_RULES; 955 config.number_tbl8s = NUMBER_TBL8S; 956 config.flags = 0; 957 uint32_t ip, i, next_hop_add_1, next_hop_add_2, next_hop_return; 958 uint8_t depth; 959 int32_t status = 0; 960 961 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 962 TEST_LPM_ASSERT(lpm != NULL); 963 964 ip = RTE_IPV4(128, 0, 0, 0); 965 depth = 24; 966 next_hop_add_1 = 100; 967 968 status = rte_lpm_add(lpm, ip, depth, next_hop_add_1); 969 TEST_LPM_ASSERT(status == 0); 970 971 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 972 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); 973 974 depth = 32; 975 next_hop_add_2 = 101; 976 977 for (i = 0; i < 1000; i++) { 978 status = rte_lpm_add(lpm, ip, depth, next_hop_add_2); 979 TEST_LPM_ASSERT(status == 0); 980 981 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 982 TEST_LPM_ASSERT((status == 0) && 983 (next_hop_return == next_hop_add_2)); 984 985 status = rte_lpm_delete(lpm, ip, depth); 986 TEST_LPM_ASSERT(status == 0); 987 988 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 989 TEST_LPM_ASSERT((status == 0) && 990 (next_hop_return == next_hop_add_1)); 991 } 992 993 depth = 24; 994 995 status = rte_lpm_delete(lpm, ip, depth); 996 TEST_LPM_ASSERT(status == 0); 997 998 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 999 TEST_LPM_ASSERT(status == -ENOENT); 1000 1001 rte_lpm_free(lpm); 1002 1003 return PASS; 1004 } 1005 1006 /* 1007 * For TBL8 extension exhaustion. Add 512 rules that require a tbl8 extension. 1008 * No more tbl8 extensions will be allowed. Now add one more rule that required 1009 * a tbl8 extension and get fail. 1010 * */ 1011 int32_t 1012 test14(void) 1013 { 1014 1015 /* We only use depth = 32 in the loop below so we must make sure 1016 * that we have enough storage for all rules at that depth*/ 1017 1018 struct rte_lpm *lpm = NULL; 1019 struct rte_lpm_config config; 1020 1021 config.max_rules = 256 * 32; 1022 config.number_tbl8s = 512; 1023 config.flags = 0; 1024 uint32_t ip, next_hop_base, next_hop_return; 1025 uint8_t depth; 1026 int32_t status = 0; 1027 xmm_t ipx4; 1028 uint32_t hop[4]; 1029 1030 /* Add enough space for 256 rules for every depth */ 1031 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1032 TEST_LPM_ASSERT(lpm != NULL); 1033 1034 depth = 32; 1035 next_hop_base = 100; 1036 ip = RTE_IPV4(0, 0, 0, 0); 1037 1038 /* Add 256 rules that require a tbl8 extension */ 1039 for (; ip <= RTE_IPV4(0, 1, 255, 0); ip += 256) { 1040 status = rte_lpm_add(lpm, ip, depth, next_hop_base + ip); 1041 TEST_LPM_ASSERT(status == 0); 1042 1043 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 1044 TEST_LPM_ASSERT((status == 0) && 1045 (next_hop_return == next_hop_base + ip)); 1046 1047 ipx4 = vect_set_epi32(ip + 3, ip + 2, ip + 1, ip); 1048 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 1049 TEST_LPM_ASSERT(hop[0] == next_hop_base + ip); 1050 TEST_LPM_ASSERT(hop[1] == UINT32_MAX); 1051 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 1052 TEST_LPM_ASSERT(hop[3] == UINT32_MAX); 1053 } 1054 1055 /* All tbl8 extensions have been used above. Try to add one more and 1056 * we get a fail */ 1057 ip = RTE_IPV4(1, 0, 0, 0); 1058 depth = 32; 1059 1060 status = rte_lpm_add(lpm, ip, depth, next_hop_base + ip); 1061 TEST_LPM_ASSERT(status < 0); 1062 1063 rte_lpm_free(lpm); 1064 1065 return PASS; 1066 } 1067 1068 /* 1069 * Sequence of operations for find existing lpm table 1070 * 1071 * - create table 1072 * - find existing table: hit 1073 * - find non-existing table: miss 1074 * 1075 */ 1076 int32_t 1077 test15(void) 1078 { 1079 struct rte_lpm *lpm = NULL, *result = NULL; 1080 struct rte_lpm_config config; 1081 1082 config.max_rules = 256 * 32; 1083 config.number_tbl8s = NUMBER_TBL8S; 1084 config.flags = 0; 1085 1086 /* Create lpm */ 1087 lpm = rte_lpm_create("lpm_find_existing", SOCKET_ID_ANY, &config); 1088 TEST_LPM_ASSERT(lpm != NULL); 1089 1090 /* Try to find existing lpm */ 1091 result = rte_lpm_find_existing("lpm_find_existing"); 1092 TEST_LPM_ASSERT(result == lpm); 1093 1094 /* Try to find non-existing lpm */ 1095 result = rte_lpm_find_existing("lpm_find_non_existing"); 1096 TEST_LPM_ASSERT(result == NULL); 1097 1098 /* Cleanup. */ 1099 rte_lpm_delete_all(lpm); 1100 rte_lpm_free(lpm); 1101 1102 return PASS; 1103 } 1104 1105 /* 1106 * test failure condition of overloading the tbl8 so no more will fit 1107 * Check we get an error return value in that case 1108 */ 1109 int32_t 1110 test16(void) 1111 { 1112 uint32_t ip; 1113 struct rte_lpm_config config; 1114 1115 config.max_rules = 256 * 32; 1116 config.number_tbl8s = NUMBER_TBL8S; 1117 config.flags = 0; 1118 struct rte_lpm *lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1119 1120 /* ip loops through all possibilities for top 24 bits of address */ 1121 for (ip = 0; ip < 0xFFFFFF; ip++) { 1122 /* add an entry within a different tbl8 each time, since 1123 * depth >24 and the top 24 bits are different */ 1124 if (rte_lpm_add(lpm, (ip << 8) + 0xF0, 30, 0) < 0) 1125 break; 1126 } 1127 1128 if (ip != NUMBER_TBL8S) { 1129 printf("Error, unexpected failure with filling tbl8 groups\n"); 1130 printf("Failed after %u additions, expected after %u\n", 1131 (unsigned)ip, (unsigned)NUMBER_TBL8S); 1132 } 1133 1134 rte_lpm_free(lpm); 1135 return 0; 1136 } 1137 1138 /* 1139 * Test for overwriting of tbl8: 1140 * - add rule /32 and lookup 1141 * - add new rule /24 and lookup 1142 * - add third rule /25 and lookup 1143 * - lookup /32 and /24 rule to ensure the table has not been overwritten. 1144 */ 1145 int32_t 1146 test17(void) 1147 { 1148 struct rte_lpm *lpm = NULL; 1149 struct rte_lpm_config config; 1150 1151 config.max_rules = MAX_RULES; 1152 config.number_tbl8s = NUMBER_TBL8S; 1153 config.flags = 0; 1154 const uint32_t ip_10_32 = RTE_IPV4(10, 10, 10, 2); 1155 const uint32_t ip_10_24 = RTE_IPV4(10, 10, 10, 0); 1156 const uint32_t ip_20_25 = RTE_IPV4(10, 10, 20, 2); 1157 const uint8_t d_ip_10_32 = 32, 1158 d_ip_10_24 = 24, 1159 d_ip_20_25 = 25; 1160 const uint32_t next_hop_ip_10_32 = 100, 1161 next_hop_ip_10_24 = 105, 1162 next_hop_ip_20_25 = 111; 1163 uint32_t next_hop_return = 0; 1164 int32_t status = 0; 1165 1166 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1167 TEST_LPM_ASSERT(lpm != NULL); 1168 1169 if ((status = rte_lpm_add(lpm, ip_10_32, d_ip_10_32, 1170 next_hop_ip_10_32)) < 0) 1171 return -1; 1172 1173 status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return); 1174 uint32_t test_hop_10_32 = next_hop_return; 1175 TEST_LPM_ASSERT(status == 0); 1176 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); 1177 1178 if ((status = rte_lpm_add(lpm, ip_10_24, d_ip_10_24, 1179 next_hop_ip_10_24)) < 0) 1180 return -1; 1181 1182 status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return); 1183 uint32_t test_hop_10_24 = next_hop_return; 1184 TEST_LPM_ASSERT(status == 0); 1185 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); 1186 1187 if ((status = rte_lpm_add(lpm, ip_20_25, d_ip_20_25, 1188 next_hop_ip_20_25)) < 0) 1189 return -1; 1190 1191 status = rte_lpm_lookup(lpm, ip_20_25, &next_hop_return); 1192 uint32_t test_hop_20_25 = next_hop_return; 1193 TEST_LPM_ASSERT(status == 0); 1194 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25); 1195 1196 if (test_hop_10_32 == test_hop_10_24) { 1197 printf("Next hop return equal\n"); 1198 return -1; 1199 } 1200 1201 if (test_hop_10_24 == test_hop_20_25) { 1202 printf("Next hop return equal\n"); 1203 return -1; 1204 } 1205 1206 status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return); 1207 TEST_LPM_ASSERT(status == 0); 1208 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); 1209 1210 status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return); 1211 TEST_LPM_ASSERT(status == 0); 1212 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); 1213 1214 rte_lpm_free(lpm); 1215 1216 return PASS; 1217 } 1218 1219 /* 1220 * Test for recycle of tbl8 1221 * - step 1: add a rule with depth=28 (> 24) 1222 * - step 2: add a rule with same 24-bit prefix and depth=23 (< 24) 1223 * - step 3: delete the first rule 1224 * - step 4: check tbl8 is freed 1225 * - step 5: add a rule same as the first one (depth=28) 1226 * - step 6: check same tbl8 is allocated 1227 * - step 7: add a rule with same 24-bit prefix and depth=24 1228 * - step 8: delete the rule (depth=28) added in step 5 1229 * - step 9: check tbl8 is freed 1230 * - step 10: add a rule with same 24-bit prefix and depth = 28 1231 * - setp 11: check same tbl8 is allocated again 1232 */ 1233 int32_t 1234 test18(void) 1235 { 1236 #define group_idx next_hop 1237 struct rte_lpm *lpm = NULL; 1238 struct rte_lpm_config config; 1239 uint32_t ip, next_hop; 1240 uint8_t depth; 1241 uint32_t tbl8_group_index; 1242 1243 config.max_rules = MAX_RULES; 1244 config.number_tbl8s = NUMBER_TBL8S; 1245 config.flags = 0; 1246 1247 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1248 TEST_LPM_ASSERT(lpm != NULL); 1249 1250 ip = RTE_IPV4(192, 168, 100, 100); 1251 depth = 28; 1252 next_hop = 1; 1253 rte_lpm_add(lpm, ip, depth, next_hop); 1254 1255 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); 1256 tbl8_group_index = lpm->tbl24[ip>>8].group_idx; 1257 1258 depth = 23; 1259 next_hop = 2; 1260 rte_lpm_add(lpm, ip, depth, next_hop); 1261 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); 1262 1263 depth = 28; 1264 rte_lpm_delete(lpm, ip, depth); 1265 1266 TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid_group); 1267 1268 next_hop = 3; 1269 rte_lpm_add(lpm, ip, depth, next_hop); 1270 1271 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); 1272 TEST_LPM_ASSERT(tbl8_group_index == lpm->tbl24[ip>>8].group_idx); 1273 1274 depth = 24; 1275 next_hop = 4; 1276 rte_lpm_add(lpm, ip, depth, next_hop); 1277 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); 1278 1279 depth = 28; 1280 rte_lpm_delete(lpm, ip, depth); 1281 1282 TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid_group); 1283 1284 next_hop = 5; 1285 rte_lpm_add(lpm, ip, depth, next_hop); 1286 1287 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); 1288 TEST_LPM_ASSERT(tbl8_group_index == lpm->tbl24[ip>>8].group_idx); 1289 1290 rte_lpm_free(lpm); 1291 #undef group_idx 1292 return PASS; 1293 } 1294 1295 /* 1296 * rte_lpm_rcu_qsbr_add positive and negative tests. 1297 * - Add RCU QSBR variable to LPM 1298 * - Add another RCU QSBR variable to LPM 1299 * - Check returns 1300 */ 1301 int32_t 1302 test19(void) 1303 { 1304 struct rte_lpm *lpm = NULL; 1305 struct rte_lpm_config config; 1306 size_t sz; 1307 struct rte_rcu_qsbr *qsv; 1308 struct rte_rcu_qsbr *qsv2; 1309 int32_t status; 1310 struct rte_lpm_rcu_config rcu_cfg = {0}; 1311 1312 config.max_rules = MAX_RULES; 1313 config.number_tbl8s = NUMBER_TBL8S; 1314 config.flags = 0; 1315 1316 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1317 TEST_LPM_ASSERT(lpm != NULL); 1318 1319 /* Create RCU QSBR variable */ 1320 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE); 1321 qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, 1322 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 1323 TEST_LPM_ASSERT(qsv != NULL); 1324 1325 status = rte_rcu_qsbr_init(qsv, RTE_MAX_LCORE); 1326 TEST_LPM_ASSERT(status == 0); 1327 1328 rcu_cfg.v = qsv; 1329 /* Invalid QSBR mode */ 1330 rcu_cfg.mode = 2; 1331 status = rte_lpm_rcu_qsbr_add(lpm, &rcu_cfg); 1332 TEST_LPM_ASSERT(status != 0); 1333 1334 rcu_cfg.mode = RTE_LPM_QSBR_MODE_DQ; 1335 /* Attach RCU QSBR to LPM table */ 1336 status = rte_lpm_rcu_qsbr_add(lpm, &rcu_cfg); 1337 TEST_LPM_ASSERT(status == 0); 1338 1339 /* Create and attach another RCU QSBR to LPM table */ 1340 qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, 1341 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 1342 TEST_LPM_ASSERT(qsv2 != NULL); 1343 1344 rcu_cfg.v = qsv2; 1345 rcu_cfg.mode = RTE_LPM_QSBR_MODE_SYNC; 1346 status = rte_lpm_rcu_qsbr_add(lpm, &rcu_cfg); 1347 TEST_LPM_ASSERT(status != 0); 1348 1349 rte_lpm_free(lpm); 1350 rte_free(qsv); 1351 rte_free(qsv2); 1352 1353 return PASS; 1354 } 1355 1356 /* 1357 * rte_lpm_rcu_qsbr_add DQ mode functional test. 1358 * Reader and writer are in the same thread in this test. 1359 * - Create LPM which supports 1 tbl8 group at max 1360 * - Add RCU QSBR variable to LPM 1361 * - Add a rule with depth=28 (> 24) 1362 * - Register a reader thread (not a real thread) 1363 * - Reader lookup existing rule 1364 * - Writer delete the rule 1365 * - Reader lookup the rule 1366 * - Writer re-add the rule (no available tbl8 group) 1367 * - Reader report quiescent state and unregister 1368 * - Writer re-add the rule 1369 * - Reader lookup the rule 1370 */ 1371 int32_t 1372 test20(void) 1373 { 1374 struct rte_lpm *lpm = NULL; 1375 struct rte_lpm_config config; 1376 size_t sz; 1377 struct rte_rcu_qsbr *qsv; 1378 int32_t status; 1379 uint32_t ip, next_hop, next_hop_return; 1380 uint8_t depth; 1381 struct rte_lpm_rcu_config rcu_cfg = {0}; 1382 1383 config.max_rules = MAX_RULES; 1384 config.number_tbl8s = 1; 1385 config.flags = 0; 1386 1387 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1388 TEST_LPM_ASSERT(lpm != NULL); 1389 1390 /* Create RCU QSBR variable */ 1391 sz = rte_rcu_qsbr_get_memsize(1); 1392 qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, 1393 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 1394 TEST_LPM_ASSERT(qsv != NULL); 1395 1396 status = rte_rcu_qsbr_init(qsv, 1); 1397 TEST_LPM_ASSERT(status == 0); 1398 1399 rcu_cfg.v = qsv; 1400 rcu_cfg.mode = RTE_LPM_QSBR_MODE_DQ; 1401 /* Attach RCU QSBR to LPM table */ 1402 status = rte_lpm_rcu_qsbr_add(lpm, &rcu_cfg); 1403 TEST_LPM_ASSERT(status == 0); 1404 1405 ip = RTE_IPV4(192, 0, 2, 100); 1406 depth = 28; 1407 next_hop = 1; 1408 status = rte_lpm_add(lpm, ip, depth, next_hop); 1409 TEST_LPM_ASSERT(status == 0); 1410 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); 1411 1412 /* Register pseudo reader */ 1413 status = rte_rcu_qsbr_thread_register(qsv, 0); 1414 TEST_LPM_ASSERT(status == 0); 1415 rte_rcu_qsbr_thread_online(qsv, 0); 1416 1417 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 1418 TEST_LPM_ASSERT(status == 0); 1419 TEST_LPM_ASSERT(next_hop_return == next_hop); 1420 1421 /* Writer update */ 1422 status = rte_lpm_delete(lpm, ip, depth); 1423 TEST_LPM_ASSERT(status == 0); 1424 TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid); 1425 1426 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 1427 TEST_LPM_ASSERT(status != 0); 1428 1429 status = rte_lpm_add(lpm, ip, depth, next_hop); 1430 TEST_LPM_ASSERT(status != 0); 1431 1432 /* Reader quiescent */ 1433 rte_rcu_qsbr_quiescent(qsv, 0); 1434 1435 status = rte_lpm_add(lpm, ip, depth, next_hop); 1436 TEST_LPM_ASSERT(status == 0); 1437 1438 rte_rcu_qsbr_thread_offline(qsv, 0); 1439 status = rte_rcu_qsbr_thread_unregister(qsv, 0); 1440 TEST_LPM_ASSERT(status == 0); 1441 1442 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 1443 TEST_LPM_ASSERT(status == 0); 1444 TEST_LPM_ASSERT(next_hop_return == next_hop); 1445 1446 rte_lpm_free(lpm); 1447 rte_free(qsv); 1448 1449 return PASS; 1450 } 1451 1452 static struct rte_lpm *g_lpm; 1453 static struct rte_rcu_qsbr *g_v; 1454 static uint32_t g_ip = RTE_IPV4(192, 0, 2, 100); 1455 static volatile uint8_t writer_done; 1456 /* Report quiescent state interval every 1024 lookups. Larger critical 1457 * sections in reader will result in writer polling multiple times. 1458 */ 1459 #define QSBR_REPORTING_INTERVAL 1024 1460 #define WRITER_ITERATIONS 512 1461 1462 /* 1463 * Reader thread using rte_lpm data structure with RCU. 1464 */ 1465 static int 1466 test_lpm_rcu_qsbr_reader(void *arg) 1467 { 1468 int i; 1469 uint32_t next_hop_return = 0; 1470 1471 RTE_SET_USED(arg); 1472 /* Register this thread to report quiescent state */ 1473 rte_rcu_qsbr_thread_register(g_v, 0); 1474 rte_rcu_qsbr_thread_online(g_v, 0); 1475 1476 do { 1477 for (i = 0; i < QSBR_REPORTING_INTERVAL; i++) 1478 rte_lpm_lookup(g_lpm, g_ip, &next_hop_return); 1479 1480 /* Update quiescent state */ 1481 rte_rcu_qsbr_quiescent(g_v, 0); 1482 } while (!writer_done); 1483 1484 rte_rcu_qsbr_thread_offline(g_v, 0); 1485 rte_rcu_qsbr_thread_unregister(g_v, 0); 1486 1487 return 0; 1488 } 1489 1490 /* 1491 * rte_lpm_rcu_qsbr_add sync mode functional test. 1492 * 1 Reader and 1 writer. They cannot be in the same thread in this test. 1493 * - Create LPM which supports 1 tbl8 group at max 1494 * - Add RCU QSBR variable with sync mode to LPM 1495 * - Register a reader thread. Reader keeps looking up a specific rule. 1496 * - Writer keeps adding and deleting a specific rule with depth=28 (> 24) 1497 */ 1498 int32_t 1499 test21(void) 1500 { 1501 struct rte_lpm_config config; 1502 size_t sz; 1503 int32_t status; 1504 uint32_t i, next_hop; 1505 uint8_t depth; 1506 struct rte_lpm_rcu_config rcu_cfg = {0}; 1507 1508 if (rte_lcore_count() < 2) { 1509 printf("Not enough cores for %s, expecting at least 2\n", 1510 __func__); 1511 return TEST_SKIPPED; 1512 } 1513 1514 config.max_rules = MAX_RULES; 1515 config.number_tbl8s = 1; 1516 config.flags = 0; 1517 1518 g_lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1519 TEST_LPM_ASSERT(g_lpm != NULL); 1520 1521 /* Create RCU QSBR variable */ 1522 sz = rte_rcu_qsbr_get_memsize(1); 1523 g_v = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, 1524 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 1525 TEST_LPM_ASSERT(g_v != NULL); 1526 1527 status = rte_rcu_qsbr_init(g_v, 1); 1528 TEST_LPM_ASSERT(status == 0); 1529 1530 rcu_cfg.v = g_v; 1531 rcu_cfg.mode = RTE_LPM_QSBR_MODE_SYNC; 1532 /* Attach RCU QSBR to LPM table */ 1533 status = rte_lpm_rcu_qsbr_add(g_lpm, &rcu_cfg); 1534 TEST_LPM_ASSERT(status == 0); 1535 1536 writer_done = 0; 1537 /* Launch reader thread */ 1538 rte_eal_remote_launch(test_lpm_rcu_qsbr_reader, NULL, 1539 rte_get_next_lcore(-1, 1, 0)); 1540 1541 depth = 28; 1542 next_hop = 1; 1543 status = rte_lpm_add(g_lpm, g_ip, depth, next_hop); 1544 if (status != 0) { 1545 printf("%s: Failed to add rule\n", __func__); 1546 goto error; 1547 } 1548 1549 /* Writer update */ 1550 for (i = 0; i < WRITER_ITERATIONS; i++) { 1551 status = rte_lpm_delete(g_lpm, g_ip, depth); 1552 if (status != 0) { 1553 printf("%s: Failed to delete rule at iteration %d\n", 1554 __func__, i); 1555 goto error; 1556 } 1557 1558 status = rte_lpm_add(g_lpm, g_ip, depth, next_hop); 1559 if (status != 0) { 1560 printf("%s: Failed to add rule at iteration %d\n", 1561 __func__, i); 1562 goto error; 1563 } 1564 } 1565 1566 error: 1567 writer_done = 1; 1568 /* Wait until reader exited. */ 1569 rte_eal_mp_wait_lcore(); 1570 1571 rte_lpm_free(g_lpm); 1572 rte_free(g_v); 1573 1574 return (status == 0) ? PASS : -1; 1575 } 1576 1577 /* 1578 * Do all unit tests. 1579 */ 1580 1581 static int 1582 test_lpm(void) 1583 { 1584 unsigned i; 1585 int status, global_status = 0; 1586 1587 for (i = 0; i < RTE_DIM(tests); i++) { 1588 status = tests[i](); 1589 if (status < 0) { 1590 printf("ERROR: LPM Test %u: FAIL\n", i); 1591 global_status = status; 1592 } 1593 } 1594 1595 return global_status; 1596 } 1597 1598 #endif /* !RTE_EXEC_ENV_WINDOWS */ 1599 1600 REGISTER_TEST_COMMAND(lpm_autotest, test_lpm); 1601