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