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