1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include "test.h" 6 7 #include <stdio.h> 8 #include <stdint.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include <rte_memory.h> 13 #include <rte_lpm6.h> 14 15 #include "test_lpm6_data.h" 16 17 #define TEST_LPM_ASSERT(cond) do { \ 18 if (!(cond)) { \ 19 printf("Error at line %d: \n", __LINE__); \ 20 return -1; \ 21 } \ 22 } while(0) 23 24 typedef int32_t (* rte_lpm6_test)(void); 25 26 static int32_t test0(void); 27 static int32_t test1(void); 28 static int32_t test2(void); 29 static int32_t test3(void); 30 static int32_t test4(void); 31 static int32_t test5(void); 32 static int32_t test6(void); 33 static int32_t test7(void); 34 static int32_t test8(void); 35 static int32_t test9(void); 36 static int32_t test10(void); 37 static int32_t test11(void); 38 static int32_t test12(void); 39 static int32_t test13(void); 40 static int32_t test14(void); 41 static int32_t test15(void); 42 static int32_t test16(void); 43 static int32_t test17(void); 44 static int32_t test18(void); 45 static int32_t test19(void); 46 static int32_t test20(void); 47 static int32_t test21(void); 48 static int32_t test22(void); 49 static int32_t test23(void); 50 static int32_t test24(void); 51 static int32_t test25(void); 52 static int32_t test26(void); 53 static int32_t test27(void); 54 static int32_t test28(void); 55 56 rte_lpm6_test tests6[] = { 57 /* Test Cases */ 58 test0, 59 test1, 60 test2, 61 test3, 62 test4, 63 test5, 64 test6, 65 test7, 66 test8, 67 test9, 68 test10, 69 test11, 70 test12, 71 test13, 72 test14, 73 test15, 74 test16, 75 test17, 76 test18, 77 test19, 78 test20, 79 test21, 80 test22, 81 test23, 82 test24, 83 test25, 84 test26, 85 test27, 86 test28, 87 }; 88 89 #define MAX_DEPTH 128 90 #define MAX_RULES 1000000 91 #define NUMBER_TBL8S (1 << 16) 92 #define MAX_NUM_TBL8S (1 << 21) 93 #define PASS 0 94 95 /* 96 * Check that rte_lpm6_create fails gracefully for incorrect user input 97 * arguments 98 */ 99 int32_t 100 test0(void) 101 { 102 struct rte_lpm6 *lpm = NULL; 103 struct rte_lpm6_config config; 104 105 config.max_rules = MAX_RULES; 106 config.number_tbl8s = NUMBER_TBL8S; 107 config.flags = 0; 108 109 /* rte_lpm6_create: lpm name == NULL */ 110 lpm = rte_lpm6_create(NULL, SOCKET_ID_ANY, &config); 111 TEST_LPM_ASSERT(lpm == NULL); 112 113 /* rte_lpm6_create: max_rules = 0 */ 114 /* Note: __func__ inserts the function name, in this case "test0". */ 115 config.max_rules = 0; 116 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 117 TEST_LPM_ASSERT(lpm == NULL); 118 119 /* socket_id < -1 is invalid */ 120 config.max_rules = MAX_RULES; 121 lpm = rte_lpm6_create(__func__, -2, &config); 122 TEST_LPM_ASSERT(lpm == NULL); 123 124 /* rte_lpm6_create: number_tbl8s is bigger than the maximum */ 125 config.number_tbl8s = MAX_NUM_TBL8S + 1; 126 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 127 TEST_LPM_ASSERT(lpm == NULL); 128 129 /* rte_lpm6_create: config = NULL */ 130 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, NULL); 131 TEST_LPM_ASSERT(lpm == NULL); 132 133 return PASS; 134 } 135 136 /* 137 * Creates two different LPM tables. Tries to create a third one with the same 138 * name as the first one and expects the create function to return the same 139 * pointer. 140 */ 141 int32_t 142 test1(void) 143 { 144 struct rte_lpm6 *lpm1 = NULL, *lpm2 = NULL, *lpm3 = NULL; 145 struct rte_lpm6_config config; 146 147 config.max_rules = MAX_RULES; 148 config.number_tbl8s = NUMBER_TBL8S; 149 config.flags = 0; 150 151 /* rte_lpm6_create: lpm name == LPM1 */ 152 lpm1 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config); 153 TEST_LPM_ASSERT(lpm1 != NULL); 154 155 /* rte_lpm6_create: lpm name == LPM2 */ 156 lpm2 = rte_lpm6_create("LPM2", SOCKET_ID_ANY, &config); 157 TEST_LPM_ASSERT(lpm2 != NULL); 158 159 /* rte_lpm6_create: lpm name == LPM2 */ 160 lpm3 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config); 161 TEST_LPM_ASSERT(lpm3 == NULL); 162 163 rte_lpm6_free(lpm1); 164 rte_lpm6_free(lpm2); 165 166 return PASS; 167 } 168 169 /* 170 * Create lpm table then delete lpm table 20 times 171 * Use a slightly different rules size each time 172 */ 173 int32_t 174 test2(void) 175 { 176 struct rte_lpm6 *lpm = NULL; 177 struct rte_lpm6_config config; 178 int32_t i; 179 180 config.number_tbl8s = NUMBER_TBL8S; 181 config.flags = 0; 182 183 /* rte_lpm6_free: Free NULL */ 184 for (i = 0; i < 20; i++) { 185 config.max_rules = MAX_RULES - i; 186 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 187 TEST_LPM_ASSERT(lpm != NULL); 188 189 rte_lpm6_free(lpm); 190 } 191 192 /* Can not test free so return success */ 193 return PASS; 194 } 195 196 /* 197 * Call rte_lpm6_free for NULL pointer user input. Note: free has no return and 198 * therefore it is impossible to check for failure but this test is added to 199 * increase function coverage metrics and to validate that freeing null does 200 * not crash. 201 */ 202 int32_t 203 test3(void) 204 { 205 struct rte_lpm6 *lpm = NULL; 206 struct rte_lpm6_config config; 207 208 config.max_rules = MAX_RULES; 209 config.number_tbl8s = NUMBER_TBL8S; 210 config.flags = 0; 211 212 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 213 TEST_LPM_ASSERT(lpm != NULL); 214 215 rte_lpm6_free(lpm); 216 rte_lpm6_free(NULL); 217 return PASS; 218 } 219 220 /* 221 * Check that rte_lpm6_add fails gracefully for incorrect user input arguments 222 */ 223 int32_t 224 test4(void) 225 { 226 struct rte_lpm6 *lpm = NULL; 227 struct rte_lpm6_config config; 228 229 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 230 uint8_t depth = 24, next_hop = 100; 231 int32_t status = 0; 232 233 config.max_rules = MAX_RULES; 234 config.number_tbl8s = NUMBER_TBL8S; 235 config.flags = 0; 236 237 /* rte_lpm6_add: lpm == NULL */ 238 status = rte_lpm6_add(NULL, &ip, depth, next_hop); 239 TEST_LPM_ASSERT(status < 0); 240 241 /*Create valid lpm to use in rest of test. */ 242 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 243 TEST_LPM_ASSERT(lpm != NULL); 244 245 /* rte_lpm6_add: depth < 1 */ 246 status = rte_lpm6_add(lpm, &ip, 0, next_hop); 247 TEST_LPM_ASSERT(status < 0); 248 249 /* rte_lpm6_add: depth > MAX_DEPTH */ 250 status = rte_lpm6_add(lpm, &ip, (MAX_DEPTH + 1), next_hop); 251 TEST_LPM_ASSERT(status < 0); 252 253 rte_lpm6_free(lpm); 254 255 return PASS; 256 } 257 258 /* 259 * Check that rte_lpm6_delete fails gracefully for incorrect user input 260 * arguments 261 */ 262 int32_t 263 test5(void) 264 { 265 struct rte_lpm6 *lpm = NULL; 266 struct rte_lpm6_config config; 267 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 268 uint8_t depth = 24; 269 int32_t status = 0; 270 271 config.max_rules = MAX_RULES; 272 config.number_tbl8s = NUMBER_TBL8S; 273 config.flags = 0; 274 275 /* rte_lpm_delete: lpm == NULL */ 276 status = rte_lpm6_delete(NULL, &ip, depth); 277 TEST_LPM_ASSERT(status < 0); 278 279 /*Create valid lpm to use in rest of test. */ 280 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 281 TEST_LPM_ASSERT(lpm != NULL); 282 283 /* rte_lpm_delete: depth < 1 */ 284 status = rte_lpm6_delete(lpm, &ip, 0); 285 TEST_LPM_ASSERT(status < 0); 286 287 /* rte_lpm_delete: depth > MAX_DEPTH */ 288 status = rte_lpm6_delete(lpm, &ip, (MAX_DEPTH + 1)); 289 TEST_LPM_ASSERT(status < 0); 290 291 rte_lpm6_free(lpm); 292 293 return PASS; 294 } 295 296 /* 297 * Check that rte_lpm6_lookup fails gracefully for incorrect user input 298 * arguments 299 */ 300 int32_t 301 test6(void) 302 { 303 struct rte_lpm6 *lpm = NULL; 304 struct rte_lpm6_config config; 305 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 306 uint32_t next_hop_return = 0; 307 int32_t status = 0; 308 309 config.max_rules = MAX_RULES; 310 config.number_tbl8s = NUMBER_TBL8S; 311 config.flags = 0; 312 313 /* rte_lpm6_lookup: lpm == NULL */ 314 status = rte_lpm6_lookup(NULL, &ip, &next_hop_return); 315 TEST_LPM_ASSERT(status < 0); 316 317 /*Create valid lpm to use in rest of test. */ 318 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 319 TEST_LPM_ASSERT(lpm != NULL); 320 321 /* rte_lpm6_lookup: ip = NULL */ 322 status = rte_lpm6_lookup(lpm, NULL, &next_hop_return); 323 TEST_LPM_ASSERT(status < 0); 324 325 /* rte_lpm6_lookup: next_hop = NULL */ 326 status = rte_lpm6_lookup(lpm, &ip, NULL); 327 TEST_LPM_ASSERT(status < 0); 328 329 rte_lpm6_free(lpm); 330 331 return PASS; 332 } 333 334 /* 335 * Checks that rte_lpm6_lookup_bulk_func fails gracefully for incorrect user 336 * input arguments 337 */ 338 int32_t 339 test7(void) 340 { 341 struct rte_lpm6 *lpm = NULL; 342 struct rte_lpm6_config config; 343 struct rte_ipv6_addr ips[10]; 344 int32_t next_hop_return[10]; 345 int32_t status = 0; 346 347 config.max_rules = MAX_RULES; 348 config.number_tbl8s = NUMBER_TBL8S; 349 config.flags = 0; 350 351 /* rte_lpm6_lookup: lpm == NULL */ 352 status = rte_lpm6_lookup_bulk_func(NULL, ips, next_hop_return, RTE_DIM(ips)); 353 TEST_LPM_ASSERT(status < 0); 354 355 /*Create valid lpm to use in rest of test. */ 356 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 357 TEST_LPM_ASSERT(lpm != NULL); 358 359 /* rte_lpm6_lookup: ip = NULL */ 360 status = rte_lpm6_lookup_bulk_func(lpm, NULL, next_hop_return, RTE_DIM(ips)); 361 TEST_LPM_ASSERT(status < 0); 362 363 /* rte_lpm6_lookup: next_hop = NULL */ 364 status = rte_lpm6_lookup_bulk_func(lpm, ips, NULL, RTE_DIM(ips)); 365 TEST_LPM_ASSERT(status < 0); 366 367 rte_lpm6_free(lpm); 368 369 return PASS; 370 } 371 372 /* 373 * Checks that rte_lpm6_delete_bulk_func fails gracefully for incorrect user 374 * input arguments 375 */ 376 int32_t 377 test8(void) 378 { 379 struct rte_lpm6 *lpm = NULL; 380 struct rte_lpm6_config config; 381 struct rte_ipv6_addr ips[10]; 382 uint8_t depth[10]; 383 int32_t status = 0; 384 385 config.max_rules = MAX_RULES; 386 config.number_tbl8s = NUMBER_TBL8S; 387 config.flags = 0; 388 389 /* rte_lpm6_delete: lpm == NULL */ 390 status = rte_lpm6_delete_bulk_func(NULL, ips, depth, RTE_DIM(ips)); 391 TEST_LPM_ASSERT(status < 0); 392 393 /*Create valid lpm to use in rest of test. */ 394 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 395 TEST_LPM_ASSERT(lpm != NULL); 396 397 /* rte_lpm6_delete: ip = NULL */ 398 status = rte_lpm6_delete_bulk_func(lpm, NULL, depth, RTE_DIM(ips)); 399 TEST_LPM_ASSERT(status < 0); 400 401 /* rte_lpm6_delete: next_hop = NULL */ 402 status = rte_lpm6_delete_bulk_func(lpm, ips, NULL, RTE_DIM(ips)); 403 TEST_LPM_ASSERT(status < 0); 404 405 rte_lpm6_free(lpm); 406 407 return PASS; 408 } 409 410 /* 411 * Call add, lookup and delete for a single rule with depth < 24. 412 * Check all the combinations for the first three bytes that result in a hit. 413 * Delete the rule and check that the same test returns a miss. 414 */ 415 int32_t 416 test9(void) 417 { 418 struct rte_lpm6 *lpm = NULL; 419 struct rte_lpm6_config config; 420 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 421 uint8_t depth = 16; 422 uint32_t next_hop_add = 100, next_hop_return = 0; 423 int32_t status = 0; 424 uint8_t i; 425 426 config.max_rules = MAX_RULES; 427 config.number_tbl8s = NUMBER_TBL8S; 428 config.flags = 0; 429 430 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 431 TEST_LPM_ASSERT(lpm != NULL); 432 433 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 434 TEST_LPM_ASSERT(status == 0); 435 436 for (i = 0; i < UINT8_MAX; i++) { 437 ip.a[2] = i; 438 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 439 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 440 } 441 442 status = rte_lpm6_delete(lpm, &ip, depth); 443 TEST_LPM_ASSERT(status == 0); 444 445 for (i = 0; i < UINT8_MAX; i++) { 446 ip.a[2] = i; 447 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 448 TEST_LPM_ASSERT(status == -ENOENT); 449 } 450 451 rte_lpm6_free(lpm); 452 453 return PASS; 454 } 455 456 /* 457 * Adds max_rules + 1 and expects a failure. Deletes a rule, then adds 458 * another one and expects success. 459 */ 460 int32_t 461 test10(void) 462 { 463 struct rte_lpm6 *lpm = NULL; 464 struct rte_lpm6_config config; 465 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 466 uint8_t depth; 467 uint32_t next_hop_add = 100; 468 int32_t status = 0; 469 int i; 470 471 config.max_rules = 127; 472 config.number_tbl8s = NUMBER_TBL8S; 473 config.flags = 0; 474 475 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 476 TEST_LPM_ASSERT(lpm != NULL); 477 478 for (i = 1; i < 128; i++) { 479 depth = (uint8_t)i; 480 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 481 TEST_LPM_ASSERT(status == 0); 482 } 483 484 depth = 128; 485 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 486 TEST_LPM_ASSERT(status == -ENOSPC); 487 488 depth = 127; 489 status = rte_lpm6_delete(lpm, &ip, depth); 490 TEST_LPM_ASSERT(status == 0); 491 492 depth = 128; 493 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 494 TEST_LPM_ASSERT(status == 0); 495 496 rte_lpm6_free(lpm); 497 498 return PASS; 499 } 500 501 /* 502 * Creates an LPM table with a small number of tbl8s and exhaust them in the 503 * middle of the process of creating a rule. 504 */ 505 int32_t 506 test11(void) 507 { 508 struct rte_lpm6 *lpm = NULL; 509 struct rte_lpm6_config config; 510 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 511 uint8_t depth; 512 uint32_t next_hop_add = 100; 513 int32_t status = 0; 514 515 config.max_rules = MAX_RULES; 516 config.number_tbl8s = 16; 517 config.flags = 0; 518 519 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 520 TEST_LPM_ASSERT(lpm != NULL); 521 522 depth = 128; 523 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 524 TEST_LPM_ASSERT(status == 0); 525 526 ip.a[0] = 1; 527 depth = 25; 528 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 529 TEST_LPM_ASSERT(status == 0); 530 531 status = rte_lpm6_delete(lpm, &ip, depth); 532 TEST_LPM_ASSERT(status == 0); 533 534 depth = 33; 535 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 536 TEST_LPM_ASSERT(status == 0); 537 538 status = rte_lpm6_delete(lpm, &ip, depth); 539 TEST_LPM_ASSERT(status == 0); 540 541 depth = 41; 542 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 543 TEST_LPM_ASSERT(status == 0); 544 545 status = rte_lpm6_delete(lpm, &ip, depth); 546 TEST_LPM_ASSERT(status == 0); 547 548 depth = 49; 549 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 550 TEST_LPM_ASSERT(status == -ENOSPC); 551 552 depth = 41; 553 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 554 TEST_LPM_ASSERT(status == 0); 555 556 rte_lpm6_free(lpm); 557 558 return PASS; 559 } 560 561 /* 562 * Creates an LPM table with a small number of tbl8s and exhaust them in the 563 * middle of the process of adding a rule when there is already an existing rule 564 * in that position and needs to be extended. 565 */ 566 int32_t 567 test12(void) 568 { 569 struct rte_lpm6 *lpm = NULL; 570 struct rte_lpm6_config config; 571 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 572 uint8_t depth; 573 uint32_t next_hop_add = 100; 574 int32_t status = 0; 575 576 config.max_rules = MAX_RULES; 577 config.number_tbl8s = 16; 578 config.flags = 0; 579 580 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 581 TEST_LPM_ASSERT(lpm != NULL); 582 583 depth = 128; 584 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 585 TEST_LPM_ASSERT(status == 0); 586 587 ip.a[0] = 1; 588 depth = 41; 589 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 590 TEST_LPM_ASSERT(status == 0); 591 592 depth = 49; 593 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 594 TEST_LPM_ASSERT(status == -ENOSPC); 595 596 rte_lpm6_free(lpm); 597 598 return PASS; 599 } 600 601 /* 602 * Creates an LPM table with max_rules = 2 and tries to add 3 rules. 603 * Delete one of the rules and tries to add the third one again. 604 */ 605 int32_t 606 test13(void) 607 { 608 struct rte_lpm6 *lpm = NULL; 609 struct rte_lpm6_config config; 610 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 611 uint8_t depth; 612 uint32_t next_hop_add = 100; 613 int32_t status = 0; 614 615 config.max_rules = 2; 616 config.number_tbl8s = NUMBER_TBL8S; 617 config.flags = 0; 618 619 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 620 TEST_LPM_ASSERT(lpm != NULL); 621 622 depth = 1; 623 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 624 TEST_LPM_ASSERT(status == 0); 625 626 depth = 2; 627 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 628 TEST_LPM_ASSERT(status == 0); 629 630 depth = 3; 631 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 632 TEST_LPM_ASSERT(status == -ENOSPC); 633 634 depth = 2; 635 status = rte_lpm6_delete(lpm, &ip, depth); 636 TEST_LPM_ASSERT(status == 0); 637 638 depth = 3; 639 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 640 TEST_LPM_ASSERT(status == 0); 641 642 rte_lpm6_free(lpm); 643 644 return PASS; 645 } 646 647 /* 648 * Add 2^12 routes with different first 12 bits and depth 25. 649 * Add one more route with the same depth and check that results in a failure. 650 * After that delete the last rule and create the one that was attempted to be 651 * created. This checks tbl8 exhaustion. 652 */ 653 int32_t 654 test14(void) 655 { 656 struct rte_lpm6 *lpm = NULL; 657 struct rte_lpm6_config config; 658 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 659 uint8_t depth = 25; 660 uint32_t next_hop_add = 100; 661 int32_t status = 0; 662 int i; 663 664 config.max_rules = MAX_RULES; 665 config.number_tbl8s = 256; 666 config.flags = 0; 667 668 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 669 TEST_LPM_ASSERT(lpm != NULL); 670 671 for (i = 0; i < 256; i++) { 672 ip.a[0] = (uint8_t)i; 673 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 674 TEST_LPM_ASSERT(status == 0); 675 } 676 677 ip.a[0] = 255; 678 ip.a[1] = 1; 679 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 680 TEST_LPM_ASSERT(status == -ENOSPC); 681 682 ip.a[0] = 255; 683 ip.a[1] = 0; 684 status = rte_lpm6_delete(lpm, &ip, depth); 685 TEST_LPM_ASSERT(status == 0); 686 687 ip.a[0] = 255; 688 ip.a[1] = 1; 689 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 690 TEST_LPM_ASSERT(status == 0); 691 692 rte_lpm6_free(lpm); 693 694 return PASS; 695 } 696 697 /* 698 * Call add, lookup and delete for a single rule with depth = 24 699 */ 700 int32_t 701 test15(void) 702 { 703 struct rte_lpm6 *lpm = NULL; 704 struct rte_lpm6_config config; 705 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 706 uint8_t depth = 24; 707 uint32_t next_hop_add = 100, next_hop_return = 0; 708 int32_t status = 0; 709 710 config.max_rules = MAX_RULES; 711 config.number_tbl8s = NUMBER_TBL8S; 712 config.flags = 0; 713 714 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 715 TEST_LPM_ASSERT(lpm != NULL); 716 717 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 718 TEST_LPM_ASSERT(status == 0); 719 720 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 721 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 722 723 status = rte_lpm6_delete(lpm, &ip, depth); 724 TEST_LPM_ASSERT(status == 0); 725 726 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 727 TEST_LPM_ASSERT(status == -ENOENT); 728 729 rte_lpm6_free(lpm); 730 731 return PASS; 732 } 733 734 /* 735 * Call add, lookup and delete for a single rule with depth > 24 736 */ 737 int32_t 738 test16(void) 739 { 740 struct rte_lpm6 *lpm = NULL; 741 struct rte_lpm6_config config; 742 struct rte_ipv6_addr ip = RTE_IPV6(0x0c0c, 0x0100, 0, 0, 0, 0, 0, 0); 743 uint8_t depth = 128; 744 uint32_t next_hop_add = 100, next_hop_return = 0; 745 int32_t status = 0; 746 747 config.max_rules = MAX_RULES; 748 config.number_tbl8s = NUMBER_TBL8S; 749 config.flags = 0; 750 751 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 752 TEST_LPM_ASSERT(lpm != NULL); 753 754 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 755 TEST_LPM_ASSERT(status == 0); 756 757 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 758 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 759 760 status = rte_lpm6_delete(lpm, &ip, depth); 761 TEST_LPM_ASSERT(status == 0); 762 763 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 764 TEST_LPM_ASSERT(status == -ENOENT); 765 766 rte_lpm6_free(lpm); 767 768 return PASS; 769 } 770 771 /* 772 * Use rte_lpm6_add to add rules which effect only the second half of the lpm 773 * table. Use all possible depths ranging from 1..32. Set the next hop = to the 774 * depth. Check lookup hit for on every add and check for lookup miss on the 775 * first half of the lpm table after each add. Finally delete all rules going 776 * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each 777 * delete. The lookup should return the next_hop_add value related to the 778 * previous depth value (i.e. depth -1). 779 */ 780 int32_t 781 test17(void) 782 { 783 struct rte_lpm6 *lpm = NULL; 784 struct rte_lpm6_config config; 785 struct rte_ipv6_addr ip1 = 786 RTE_IPV6(0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff); 787 struct rte_ipv6_addr ip2 = RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 788 uint8_t depth; 789 uint32_t next_hop_add, next_hop_return; 790 int32_t status = 0; 791 792 config.max_rules = MAX_RULES; 793 config.number_tbl8s = NUMBER_TBL8S; 794 config.flags = 0; 795 796 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 797 TEST_LPM_ASSERT(lpm != NULL); 798 799 /* Loop with rte_lpm6_add. */ 800 for (depth = 1; depth <= 16; depth++) { 801 /* Let the next_hop_add value = depth. Just for change. */ 802 next_hop_add = depth; 803 804 status = rte_lpm6_add(lpm, &ip2, depth, next_hop_add); 805 TEST_LPM_ASSERT(status == 0); 806 807 /* Check IP in first half of tbl24 which should be empty. */ 808 status = rte_lpm6_lookup(lpm, &ip1, &next_hop_return); 809 TEST_LPM_ASSERT(status == -ENOENT); 810 811 status = rte_lpm6_lookup(lpm, &ip2, &next_hop_return); 812 TEST_LPM_ASSERT((status == 0) && 813 (next_hop_return == next_hop_add)); 814 } 815 816 /* Loop with rte_lpm6_delete. */ 817 for (depth = 16; depth >= 1; depth--) { 818 next_hop_add = (depth - 1); 819 820 status = rte_lpm6_delete(lpm, &ip2, depth); 821 TEST_LPM_ASSERT(status == 0); 822 823 status = rte_lpm6_lookup(lpm, &ip2, &next_hop_return); 824 825 if (depth != 1) { 826 TEST_LPM_ASSERT((status == 0) && 827 (next_hop_return == next_hop_add)); 828 } 829 else { 830 TEST_LPM_ASSERT(status == -ENOENT); 831 } 832 833 status = rte_lpm6_lookup(lpm, &ip1, &next_hop_return); 834 TEST_LPM_ASSERT(status == -ENOENT); 835 } 836 837 rte_lpm6_free(lpm); 838 839 return PASS; 840 } 841 842 /* 843 * - Add & lookup to hit invalid TBL24 entry 844 * - Add & lookup to hit valid TBL24 entry not extended 845 * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry 846 * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry 847 */ 848 int32_t 849 test18(void) 850 { 851 struct rte_lpm6 *lpm = NULL; 852 struct rte_lpm6_config config; 853 struct rte_ipv6_addr ip, ip_1, ip_2; 854 uint8_t depth, depth_1, depth_2; 855 uint32_t next_hop_add, next_hop_add_1, 856 next_hop_add_2, next_hop_return; 857 int32_t status = 0; 858 859 config.max_rules = MAX_RULES; 860 config.number_tbl8s = NUMBER_TBL8S; 861 config.flags = 0; 862 863 /* Add & lookup to hit invalid TBL24 entry */ 864 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 865 depth = 24; 866 next_hop_add = 100; 867 868 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 869 TEST_LPM_ASSERT(lpm != NULL); 870 871 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 872 TEST_LPM_ASSERT(status == 0); 873 874 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 875 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 876 877 status = rte_lpm6_delete(lpm, &ip, depth); 878 TEST_LPM_ASSERT(status == 0); 879 880 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 881 TEST_LPM_ASSERT(status == -ENOENT); 882 883 rte_lpm6_delete_all(lpm); 884 885 /* Add & lookup to hit valid TBL24 entry not extended */ 886 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 887 depth = 23; 888 next_hop_add = 100; 889 890 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 891 TEST_LPM_ASSERT(status == 0); 892 893 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 894 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 895 896 depth = 24; 897 next_hop_add = 101; 898 899 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 900 TEST_LPM_ASSERT(status == 0); 901 902 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 903 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 904 905 depth = 24; 906 907 status = rte_lpm6_delete(lpm, &ip, depth); 908 TEST_LPM_ASSERT(status == 0); 909 910 depth = 23; 911 912 status = rte_lpm6_delete(lpm, &ip, depth); 913 TEST_LPM_ASSERT(status == 0); 914 915 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 916 TEST_LPM_ASSERT(status == -ENOENT); 917 918 rte_lpm6_delete_all(lpm); 919 920 /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8 921 * entry. 922 */ 923 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 924 depth = 32; 925 next_hop_add = 100; 926 927 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 928 TEST_LPM_ASSERT(status == 0); 929 930 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 931 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 932 933 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0x0005, 0, 0, 0, 0, 0, 0); 934 depth = 32; 935 next_hop_add = 101; 936 937 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 938 TEST_LPM_ASSERT(status == 0); 939 940 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 941 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 942 943 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 944 depth = 32; 945 next_hop_add = 100; 946 947 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 948 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 949 950 status = rte_lpm6_delete(lpm, &ip, depth); 951 TEST_LPM_ASSERT(status == 0); 952 953 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 954 TEST_LPM_ASSERT(status == -ENOENT); 955 956 rte_lpm6_delete_all(lpm); 957 958 /* Add & lookup to hit valid extended TBL24 entry with valid TBL8 959 * entry 960 */ 961 ip_1 = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 962 depth_1 = 25; 963 next_hop_add_1 = 101; 964 965 ip_2 = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0x0005, 0, 0, 0, 0, 0, 0); 966 depth_2 = 32; 967 next_hop_add_2 = 102; 968 969 next_hop_return = 0; 970 971 status = rte_lpm6_add(lpm, &ip_1, depth_1, next_hop_add_1); 972 TEST_LPM_ASSERT(status == 0); 973 974 status = rte_lpm6_lookup(lpm, &ip_1, &next_hop_return); 975 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); 976 977 status = rte_lpm6_add(lpm, &ip_2, depth_2, next_hop_add_2); 978 TEST_LPM_ASSERT(status == 0); 979 980 status = rte_lpm6_lookup(lpm, &ip_2, &next_hop_return); 981 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2)); 982 983 status = rte_lpm6_delete(lpm, &ip_2, depth_2); 984 TEST_LPM_ASSERT(status == 0); 985 986 status = rte_lpm6_lookup(lpm, &ip_2, &next_hop_return); 987 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); 988 989 status = rte_lpm6_delete(lpm, &ip_1, depth_1); 990 TEST_LPM_ASSERT(status == 0); 991 992 status = rte_lpm6_lookup(lpm, &ip_1, &next_hop_return); 993 TEST_LPM_ASSERT(status == -ENOENT); 994 995 rte_lpm6_free(lpm); 996 997 return PASS; 998 } 999 1000 /* 1001 * - Add rule that covers a TBL24 range previously invalid & lookup (& delete & 1002 * lookup) 1003 * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup) 1004 * - Add rule that extends a TBL24 valid entry & lookup for both rules (& 1005 * delete & lookup) 1006 * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup) 1007 * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup) 1008 * - Delete a rule that is not present in the TBL24 & lookup 1009 * - Delete a rule that is not present in the TBL8 & lookup 1010 */ 1011 int32_t 1012 test19(void) 1013 { 1014 struct rte_lpm6 *lpm = NULL; 1015 struct rte_lpm6_config config; 1016 struct rte_ipv6_addr ip; 1017 uint8_t depth; 1018 uint32_t next_hop_add, next_hop_return; 1019 int32_t status = 0; 1020 1021 config.max_rules = MAX_RULES; 1022 config.number_tbl8s = NUMBER_TBL8S; 1023 config.flags = 0; 1024 1025 /* Add rule that covers a TBL24 range previously invalid & lookup 1026 * (& delete & lookup) 1027 */ 1028 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1029 TEST_LPM_ASSERT(lpm != NULL); 1030 1031 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1032 depth = 16; 1033 next_hop_add = 100; 1034 1035 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1036 TEST_LPM_ASSERT(status == 0); 1037 1038 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1039 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1040 1041 status = rte_lpm6_delete(lpm, &ip, depth); 1042 TEST_LPM_ASSERT(status == 0); 1043 1044 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1045 TEST_LPM_ASSERT(status == -ENOENT); 1046 1047 rte_lpm6_delete_all(lpm); 1048 1049 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1050 depth = 25; 1051 next_hop_add = 100; 1052 1053 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1054 TEST_LPM_ASSERT(status == 0); 1055 1056 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1057 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1058 1059 status = rte_lpm6_delete(lpm, &ip, depth); 1060 TEST_LPM_ASSERT(status == 0); 1061 1062 rte_lpm6_delete_all(lpm); 1063 1064 /* 1065 * Add rule that extends a TBL24 valid entry & lookup for both rules 1066 * (& delete & lookup) 1067 */ 1068 1069 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1070 depth = 24; 1071 next_hop_add = 100; 1072 1073 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1074 TEST_LPM_ASSERT(status == 0); 1075 1076 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0x000a, 0, 0, 0, 0, 0, 0); 1077 depth = 32; 1078 next_hop_add = 101; 1079 1080 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1081 TEST_LPM_ASSERT(status == 0); 1082 1083 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1084 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1085 1086 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1087 next_hop_add = 100; 1088 1089 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1090 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1091 1092 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1093 depth = 24; 1094 1095 status = rte_lpm6_delete(lpm, &ip, depth); 1096 TEST_LPM_ASSERT(status == 0); 1097 1098 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1099 TEST_LPM_ASSERT(status == -ENOENT); 1100 1101 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0x000a, 0, 0, 0, 0, 0, 0); 1102 depth = 32; 1103 1104 status = rte_lpm6_delete(lpm, &ip, depth); 1105 TEST_LPM_ASSERT(status == 0); 1106 1107 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1108 TEST_LPM_ASSERT(status == -ENOENT); 1109 1110 rte_lpm6_delete_all(lpm); 1111 1112 /* 1113 * Add rule that updates the next hop in TBL24 & lookup 1114 * (& delete & lookup) 1115 */ 1116 1117 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1118 depth = 24; 1119 next_hop_add = 100; 1120 1121 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1122 TEST_LPM_ASSERT(status == 0); 1123 1124 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1125 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1126 1127 next_hop_add = 101; 1128 1129 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1130 TEST_LPM_ASSERT(status == 0); 1131 1132 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1133 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1134 1135 status = rte_lpm6_delete(lpm, &ip, depth); 1136 TEST_LPM_ASSERT(status == 0); 1137 1138 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1139 TEST_LPM_ASSERT(status == -ENOENT); 1140 1141 rte_lpm6_delete_all(lpm); 1142 1143 /* 1144 * Add rule that updates the next hop in TBL8 & lookup 1145 * (& delete & lookup) 1146 */ 1147 1148 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1149 depth = 32; 1150 next_hop_add = 100; 1151 1152 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1153 TEST_LPM_ASSERT(status == 0); 1154 1155 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1156 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1157 1158 next_hop_add = 101; 1159 1160 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1161 TEST_LPM_ASSERT(status == 0); 1162 1163 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1164 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1165 1166 status = rte_lpm6_delete(lpm, &ip, depth); 1167 TEST_LPM_ASSERT(status == 0); 1168 1169 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1170 TEST_LPM_ASSERT(status == -ENOENT); 1171 1172 rte_lpm6_delete_all(lpm); 1173 1174 /* Delete a rule that is not present in the TBL24 & lookup */ 1175 1176 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1177 depth = 24; 1178 next_hop_add = 100; 1179 1180 status = rte_lpm6_delete(lpm, &ip, depth); 1181 TEST_LPM_ASSERT(status < 0); 1182 1183 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1184 TEST_LPM_ASSERT(status == -ENOENT); 1185 1186 rte_lpm6_delete_all(lpm); 1187 1188 /* Delete a rule that is not present in the TBL8 & lookup */ 1189 1190 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1191 depth = 32; 1192 next_hop_add = 100; 1193 1194 status = rte_lpm6_delete(lpm, &ip, depth); 1195 TEST_LPM_ASSERT(status < 0); 1196 1197 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1198 TEST_LPM_ASSERT(status == -ENOENT); 1199 1200 rte_lpm6_free(lpm); 1201 1202 return PASS; 1203 } 1204 1205 /* 1206 * Add two rules, lookup to hit the more specific one, lookup to hit the less 1207 * specific one delete the less specific rule and lookup previous values again; 1208 * add a more specific rule than the existing rule, lookup again 1209 */ 1210 int32_t 1211 test20(void) 1212 { 1213 struct rte_lpm6 *lpm = NULL; 1214 struct rte_lpm6_config config; 1215 struct rte_ipv6_addr ip; 1216 uint8_t depth; 1217 uint32_t next_hop_add, next_hop_return; 1218 int32_t status = 0; 1219 1220 config.max_rules = MAX_RULES; 1221 config.number_tbl8s = NUMBER_TBL8S; 1222 config.flags = 0; 1223 1224 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1225 TEST_LPM_ASSERT(lpm != NULL); 1226 1227 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1228 depth = 24; 1229 next_hop_add = 100; 1230 1231 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1232 TEST_LPM_ASSERT(status == 0); 1233 1234 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0x000a); 1235 depth = 128; 1236 next_hop_add = 101; 1237 1238 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1239 TEST_LPM_ASSERT(status == 0); 1240 1241 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1242 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1243 1244 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1245 next_hop_add = 100; 1246 1247 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1248 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1249 1250 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1251 depth = 24; 1252 1253 status = rte_lpm6_delete(lpm, &ip, depth); 1254 TEST_LPM_ASSERT(status == 0); 1255 1256 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1257 TEST_LPM_ASSERT(status == -ENOENT); 1258 1259 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0x000a); 1260 depth = 128; 1261 1262 status = rte_lpm6_delete(lpm, &ip, depth); 1263 TEST_LPM_ASSERT(status == 0); 1264 1265 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1266 TEST_LPM_ASSERT(status == -ENOENT); 1267 1268 rte_lpm6_free(lpm); 1269 1270 return PASS; 1271 } 1272 1273 /* 1274 * Adds 3 rules and look them up through the lookup_bulk function. 1275 * Includes in the lookup a fourth IP address that won't match 1276 * and checks that the result is as expected. 1277 */ 1278 int32_t 1279 test21(void) 1280 { 1281 struct rte_lpm6 *lpm = NULL; 1282 struct rte_lpm6_config config; 1283 struct rte_ipv6_addr ip_batch[4]; 1284 uint8_t depth; 1285 uint32_t next_hop_add; 1286 int32_t next_hop_return[4]; 1287 int32_t status = 0; 1288 1289 config.max_rules = MAX_RULES; 1290 config.number_tbl8s = NUMBER_TBL8S; 1291 config.flags = 0; 1292 1293 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1294 TEST_LPM_ASSERT(lpm != NULL); 1295 1296 ip_batch[0] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0001, 0, 0, 0, 0, 0); 1297 depth = 48; 1298 next_hop_add = 100; 1299 1300 status = rte_lpm6_add(lpm, &ip_batch[0], depth, next_hop_add); 1301 TEST_LPM_ASSERT(status == 0); 1302 1303 ip_batch[1] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0002, 0, 0, 0, 0, 0); 1304 depth = 48; 1305 next_hop_add = 101; 1306 1307 status = rte_lpm6_add(lpm, &ip_batch[1], depth, next_hop_add); 1308 TEST_LPM_ASSERT(status == 0); 1309 1310 ip_batch[2] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0003, 0, 0, 0, 0, 0); 1311 depth = 48; 1312 next_hop_add = 102; 1313 1314 status = rte_lpm6_add(lpm, &ip_batch[2], depth, next_hop_add); 1315 TEST_LPM_ASSERT(status == 0); 1316 1317 ip_batch[3] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0004, 0, 0, 0, 0, 0); 1318 1319 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, 1320 next_hop_return, 4); 1321 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100 1322 && next_hop_return[1] == 101 && next_hop_return[2] == 102 1323 && next_hop_return[3] == -1); 1324 1325 rte_lpm6_free(lpm); 1326 1327 return PASS; 1328 } 1329 1330 /* 1331 * Adds 5 rules and look them up. 1332 * Use the delete_bulk function to delete two of them. Lookup again. 1333 * Use the delete_bulk function to delete one more. Lookup again. 1334 * Use the delete_bulk function to delete two more, one invalid. Lookup again. 1335 * Use the delete_bulk function to delete the remaining one. Lookup again. 1336 */ 1337 int32_t 1338 test22(void) 1339 { 1340 struct rte_lpm6 *lpm = NULL; 1341 struct rte_lpm6_config config; 1342 struct rte_ipv6_addr ip_batch[5]; 1343 uint8_t depth[5]; 1344 uint32_t next_hop_add; 1345 int32_t next_hop_return[5]; 1346 int32_t status = 0; 1347 1348 config.max_rules = MAX_RULES; 1349 config.number_tbl8s = NUMBER_TBL8S; 1350 config.flags = 0; 1351 1352 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1353 TEST_LPM_ASSERT(lpm != NULL); 1354 1355 /* Adds 5 rules and look them up */ 1356 1357 ip_batch[0] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0001, 0, 0, 0, 0, 0); 1358 depth[0] = 48; 1359 next_hop_add = 101; 1360 1361 status = rte_lpm6_add(lpm, &ip_batch[0], depth[0], next_hop_add); 1362 TEST_LPM_ASSERT(status == 0); 1363 1364 ip_batch[1] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0002, 0, 0, 0, 0, 0); 1365 depth[1] = 48; 1366 next_hop_add = 102; 1367 1368 status = rte_lpm6_add(lpm, &ip_batch[1], depth[1], next_hop_add); 1369 TEST_LPM_ASSERT(status == 0); 1370 1371 ip_batch[2] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0003, 0, 0, 0, 0, 0); 1372 depth[2] = 48; 1373 next_hop_add = 103; 1374 1375 status = rte_lpm6_add(lpm, &ip_batch[2], depth[2], next_hop_add); 1376 TEST_LPM_ASSERT(status == 0); 1377 1378 ip_batch[3] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0004, 0, 0, 0, 0, 0); 1379 depth[3] = 48; 1380 next_hop_add = 104; 1381 1382 status = rte_lpm6_add(lpm, &ip_batch[3], depth[3], next_hop_add); 1383 TEST_LPM_ASSERT(status == 0); 1384 1385 ip_batch[4] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0005, 0, 0, 0, 0, 0); 1386 depth[4] = 48; 1387 next_hop_add = 105; 1388 1389 status = rte_lpm6_add(lpm, &ip_batch[4], depth[4], next_hop_add); 1390 TEST_LPM_ASSERT(status == 0); 1391 1392 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, 1393 next_hop_return, 5); 1394 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101 1395 && next_hop_return[1] == 102 && next_hop_return[2] == 103 1396 && next_hop_return[3] == 104 && next_hop_return[4] == 105); 1397 1398 /* Use the delete_bulk function to delete two of them. Lookup again */ 1399 1400 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2); 1401 TEST_LPM_ASSERT(status == 0); 1402 1403 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, 1404 next_hop_return, 5); 1405 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1 1406 && next_hop_return[1] == -1 && next_hop_return[2] == 103 1407 && next_hop_return[3] == 104 && next_hop_return[4] == 105); 1408 1409 /* Use the delete_bulk function to delete one more. Lookup again */ 1410 1411 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1); 1412 TEST_LPM_ASSERT(status == 0); 1413 1414 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, 1415 next_hop_return, 5); 1416 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1 1417 && next_hop_return[1] == -1 && next_hop_return[2] == -1 1418 && next_hop_return[3] == 104 && next_hop_return[4] == 105); 1419 1420 /* Use the delete_bulk function to delete two, one invalid. Lookup again */ 1421 1422 ip_batch[4] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0006, 0, 0, 0, 0, 0); 1423 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2); 1424 TEST_LPM_ASSERT(status == 0); 1425 1426 ip_batch[4] = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0x0005, 0, 0, 0, 0, 0); 1427 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, 1428 next_hop_return, 5); 1429 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1 1430 && next_hop_return[1] == -1 && next_hop_return[2] == -1 1431 && next_hop_return[3] == -1 && next_hop_return[4] == 105); 1432 1433 /* Use the delete_bulk function to delete the remaining one. Lookup again */ 1434 1435 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1); 1436 TEST_LPM_ASSERT(status == 0); 1437 1438 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, 1439 next_hop_return, 5); 1440 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1 1441 && next_hop_return[1] == -1 && next_hop_return[2] == -1 1442 && next_hop_return[3] == -1 && next_hop_return[4] == -1); 1443 1444 rte_lpm6_free(lpm); 1445 1446 return PASS; 1447 } 1448 1449 /* 1450 * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete, 1451 * lookup (miss) in a for loop of 30 times. This will check tbl8 extension 1452 * and contraction. 1453 */ 1454 int32_t 1455 test23(void) 1456 { 1457 struct rte_lpm6 *lpm = NULL; 1458 struct rte_lpm6_config config; 1459 uint32_t i; 1460 struct rte_ipv6_addr ip; 1461 uint8_t depth; 1462 uint32_t next_hop_add, next_hop_return; 1463 int32_t status = 0; 1464 1465 config.max_rules = MAX_RULES; 1466 config.number_tbl8s = NUMBER_TBL8S; 1467 config.flags = 0; 1468 1469 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1470 TEST_LPM_ASSERT(lpm != NULL); 1471 1472 ip = (struct rte_ipv6_addr)RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 1473 depth = 128; 1474 next_hop_add = 100; 1475 1476 for (i = 0; i < 30; i++) { 1477 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1478 TEST_LPM_ASSERT(status == 0); 1479 1480 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1481 TEST_LPM_ASSERT((status == 0) && 1482 (next_hop_return == next_hop_add)); 1483 1484 status = rte_lpm6_delete(lpm, &ip, depth); 1485 TEST_LPM_ASSERT(status == 0); 1486 1487 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1488 TEST_LPM_ASSERT(status == -ENOENT); 1489 } 1490 1491 rte_lpm6_free(lpm); 1492 1493 return PASS; 1494 } 1495 1496 /* 1497 * Sequence of operations for find existing lpm table 1498 * 1499 * - create table 1500 * - find existing table: hit 1501 * - find non-existing table: miss 1502 */ 1503 int32_t 1504 test24(void) 1505 { 1506 struct rte_lpm6 *lpm = NULL, *result = NULL; 1507 struct rte_lpm6_config config; 1508 1509 config.max_rules = 256 * 32; 1510 config.number_tbl8s = NUMBER_TBL8S; 1511 config.flags = 0; 1512 1513 /* Create lpm */ 1514 lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config); 1515 TEST_LPM_ASSERT(lpm != NULL); 1516 1517 /* Try to find existing lpm */ 1518 result = rte_lpm6_find_existing("lpm_find_existing"); 1519 TEST_LPM_ASSERT(result == lpm); 1520 1521 /* Try to find non-existing lpm */ 1522 result = rte_lpm6_find_existing("lpm_find_non_existing"); 1523 TEST_LPM_ASSERT(result == NULL); 1524 1525 /* Cleanup. */ 1526 rte_lpm6_delete_all(lpm); 1527 rte_lpm6_free(lpm); 1528 1529 return PASS; 1530 } 1531 1532 /* 1533 * Add a set of random routes with random depths. 1534 * Lookup different IP addresses that match the routes previously added. 1535 * Checks that the next hop is the expected one. 1536 * The routes, IP addresses and expected result for every case have been 1537 * precalculated by using a python script and stored in a .h file. 1538 */ 1539 int32_t 1540 test25(void) 1541 { 1542 struct rte_lpm6 *lpm = NULL; 1543 struct rte_lpm6_config config; 1544 struct rte_ipv6_addr ip; 1545 uint32_t i; 1546 uint8_t depth; 1547 uint32_t next_hop_add, next_hop_return, next_hop_expected; 1548 int32_t status = 0; 1549 1550 config.max_rules = MAX_RULES; 1551 config.number_tbl8s = NUMBER_TBL8S; 1552 config.flags = 0; 1553 1554 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1555 TEST_LPM_ASSERT(lpm != NULL); 1556 1557 for (i = 0; i < 1000; i++) { 1558 ip = large_route_table[i].ip; 1559 depth = large_route_table[i].depth; 1560 next_hop_add = large_route_table[i].next_hop; 1561 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1562 TEST_LPM_ASSERT(status == 0); 1563 } 1564 1565 /* generate large IPS table and expected next_hops */ 1566 generate_large_ips_table(1); 1567 1568 for (i = 0; i < 100000; i++) { 1569 ip = large_ips_table[i].ip; 1570 next_hop_expected = large_ips_table[i].next_hop; 1571 1572 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1573 TEST_LPM_ASSERT((status == 0) && 1574 (next_hop_return == next_hop_expected)); 1575 } 1576 1577 rte_lpm6_free(lpm); 1578 1579 return PASS; 1580 } 1581 1582 /* 1583 * Test for overwriting of tbl8: 1584 * - add rule /32 and lookup 1585 * - add new rule /24 and lookup 1586 * - add third rule /25 and lookup 1587 * - lookup /32 and /24 rule to ensure the table has not been overwritten. 1588 */ 1589 int32_t 1590 test26(void) 1591 { 1592 struct rte_lpm6 *lpm = NULL; 1593 struct rte_lpm6_config config; 1594 struct rte_ipv6_addr ip_10_32 = RTE_IPV6(0x0a0a, 0x0a02, 0, 0, 0, 0, 0, 0); 1595 struct rte_ipv6_addr ip_10_24 = RTE_IPV6(0x0a0a, 0x0a00, 0, 0, 0, 0, 0, 0); 1596 struct rte_ipv6_addr ip_20_25 = RTE_IPV6(0x0a0a, 0x1402, 0, 0, 0, 0, 0, 0); 1597 uint8_t d_ip_10_32 = 32; 1598 uint8_t d_ip_10_24 = 24; 1599 uint8_t d_ip_20_25 = 25; 1600 uint32_t next_hop_ip_10_32 = 100; 1601 uint32_t next_hop_ip_10_24 = 105; 1602 uint32_t next_hop_ip_20_25 = 111; 1603 uint32_t next_hop_return = 0; 1604 int32_t status = 0; 1605 1606 config.max_rules = MAX_RULES; 1607 config.number_tbl8s = NUMBER_TBL8S; 1608 config.flags = 0; 1609 1610 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1611 TEST_LPM_ASSERT(lpm != NULL); 1612 1613 status = rte_lpm6_add(lpm, &ip_10_32, d_ip_10_32, next_hop_ip_10_32); 1614 TEST_LPM_ASSERT(status == 0); 1615 1616 status = rte_lpm6_lookup(lpm, &ip_10_32, &next_hop_return); 1617 uint32_t test_hop_10_32 = next_hop_return; 1618 TEST_LPM_ASSERT(status == 0); 1619 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); 1620 1621 status = rte_lpm6_add(lpm, &ip_10_24, d_ip_10_24, next_hop_ip_10_24); 1622 TEST_LPM_ASSERT(status == 0); 1623 1624 status = rte_lpm6_lookup(lpm, &ip_10_24, &next_hop_return); 1625 uint32_t test_hop_10_24 = next_hop_return; 1626 TEST_LPM_ASSERT(status == 0); 1627 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); 1628 1629 status = rte_lpm6_add(lpm, &ip_20_25, d_ip_20_25, next_hop_ip_20_25); 1630 TEST_LPM_ASSERT(status == 0); 1631 1632 status = rte_lpm6_lookup(lpm, &ip_20_25, &next_hop_return); 1633 uint32_t test_hop_20_25 = next_hop_return; 1634 TEST_LPM_ASSERT(status == 0); 1635 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25); 1636 1637 if (test_hop_10_32 == test_hop_10_24) { 1638 printf("Next hop return equal\n"); 1639 return -1; 1640 } 1641 1642 if (test_hop_10_24 == test_hop_20_25){ 1643 printf("Next hop return equal\n"); 1644 return -1; 1645 } 1646 1647 status = rte_lpm6_lookup(lpm, &ip_10_32, &next_hop_return); 1648 TEST_LPM_ASSERT(status == 0); 1649 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); 1650 1651 status = rte_lpm6_lookup(lpm, &ip_10_24, &next_hop_return); 1652 TEST_LPM_ASSERT(status == 0); 1653 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); 1654 1655 rte_lpm6_free(lpm); 1656 1657 return PASS; 1658 } 1659 1660 /* 1661 * Add a rule that reaches the end of the tree. 1662 * Add a rule that is more generic than the first one. 1663 * Check every possible combination that produces a match for the second rule. 1664 * This tests tbl expansion. 1665 */ 1666 int32_t 1667 test27(void) 1668 { 1669 struct rte_lpm6 *lpm = NULL; 1670 struct rte_lpm6_config config; 1671 struct rte_ipv6_addr ip = 1672 RTE_IPV6(0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0); 1673 uint8_t depth = 128; 1674 uint32_t next_hop_add = 100, next_hop_return; 1675 int32_t status = 0; 1676 int i, j; 1677 1678 config.max_rules = MAX_RULES; 1679 config.number_tbl8s = NUMBER_TBL8S; 1680 config.flags = 0; 1681 1682 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1683 TEST_LPM_ASSERT(lpm != NULL); 1684 1685 depth = 128; 1686 next_hop_add = 128; 1687 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1688 TEST_LPM_ASSERT(status == 0); 1689 1690 depth = 112; 1691 next_hop_add = 112; 1692 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1693 TEST_LPM_ASSERT(status == 0); 1694 1695 for (i = 0; i < 256; i++) { 1696 ip.a[14] = i; 1697 for (j = 0; j < 256; j++) { 1698 ip.a[15] = j; 1699 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1700 if (i == 0 && j == 0) 1701 TEST_LPM_ASSERT(status == 0 && next_hop_return == 128); 1702 else 1703 TEST_LPM_ASSERT(status == 0 && next_hop_return == 112); 1704 } 1705 } 1706 1707 rte_lpm6_free(lpm); 1708 1709 return PASS; 1710 } 1711 1712 /* 1713 * Call add, lookup and delete for a single rule with maximum 21bit next_hop 1714 * size. 1715 * Check that next_hop returned from lookup is equal to provisioned value. 1716 * Delete the rule and check that the same test returns a miss. 1717 */ 1718 int32_t 1719 test28(void) 1720 { 1721 struct rte_lpm6 *lpm = NULL; 1722 struct rte_lpm6_config config; 1723 struct rte_ipv6_addr ip = RTE_IPV6(0, 0, 0, 0, 0, 0, 0, 0); 1724 uint8_t depth = 16; 1725 uint32_t next_hop_add = 0x001FFFFF, next_hop_return = 0; 1726 int32_t status = 0; 1727 1728 config.max_rules = MAX_RULES; 1729 config.number_tbl8s = NUMBER_TBL8S; 1730 config.flags = 0; 1731 1732 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); 1733 TEST_LPM_ASSERT(lpm != NULL); 1734 1735 status = rte_lpm6_add(lpm, &ip, depth, next_hop_add); 1736 TEST_LPM_ASSERT(status == 0); 1737 1738 status = rte_lpm6_lookup(lpm, &ip, &next_hop_return); 1739 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 1740 1741 status = rte_lpm6_delete(lpm, &ip, depth); 1742 TEST_LPM_ASSERT(status == 0); 1743 rte_lpm6_free(lpm); 1744 1745 return PASS; 1746 } 1747 1748 /* 1749 * Do all unit tests. 1750 */ 1751 static int 1752 test_lpm6(void) 1753 { 1754 unsigned i; 1755 int status = -1, global_status = 0; 1756 1757 for (i = 0; i < RTE_DIM(tests6); i++) { 1758 printf("# test %02d\n", i); 1759 status = tests6[i](); 1760 1761 if (status < 0) { 1762 printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i])); 1763 global_status = status; 1764 } 1765 } 1766 1767 return global_status; 1768 } 1769 1770 REGISTER_FAST_TEST(lpm6_autotest, true, true, test_lpm6); 1771