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 38 #include <rte_lpm.h> 39 40 #include "test.h" 41 #include "test_lpm_routes.h" 42 #include "test_xmmt_ops.h" 43 44 #define TEST_LPM_ASSERT(cond) do { \ 45 if (!(cond)) { \ 46 printf("Error at line %d: \n", __LINE__); \ 47 return -1; \ 48 } \ 49 } while(0) 50 51 typedef int32_t (*rte_lpm_test)(void); 52 53 static int32_t test0(void); 54 static int32_t test1(void); 55 static int32_t test2(void); 56 static int32_t test3(void); 57 static int32_t test4(void); 58 static int32_t test5(void); 59 static int32_t test6(void); 60 static int32_t test7(void); 61 static int32_t test8(void); 62 static int32_t test9(void); 63 static int32_t test10(void); 64 static int32_t test11(void); 65 static int32_t test12(void); 66 static int32_t test13(void); 67 static int32_t test14(void); 68 static int32_t test15(void); 69 static int32_t test16(void); 70 static int32_t test17(void); 71 72 rte_lpm_test tests[] = { 73 /* Test Cases */ 74 test0, 75 test1, 76 test2, 77 test3, 78 test4, 79 test5, 80 test6, 81 test7, 82 test8, 83 test9, 84 test10, 85 test11, 86 test12, 87 test13, 88 test14, 89 test15, 90 test16, 91 test17, 92 }; 93 94 #define NUM_LPM_TESTS (sizeof(tests)/sizeof(tests[0])) 95 #define MAX_DEPTH 32 96 #define MAX_RULES 256 97 #define NUMBER_TBL8S 256 98 #define PASS 0 99 100 /* 101 * Check that rte_lpm_create fails gracefully for incorrect user input 102 * arguments 103 */ 104 int32_t 105 test0(void) 106 { 107 struct rte_lpm *lpm = NULL; 108 struct rte_lpm_config config; 109 110 config.max_rules = MAX_RULES; 111 config.number_tbl8s = NUMBER_TBL8S; 112 config.flags = 0; 113 114 /* rte_lpm_create: lpm name == NULL */ 115 lpm = rte_lpm_create(NULL, SOCKET_ID_ANY, &config); 116 TEST_LPM_ASSERT(lpm == NULL); 117 118 /* rte_lpm_create: max_rules = 0 */ 119 /* Note: __func__ inserts the function name, in this case "test0". */ 120 config.max_rules = 0; 121 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 122 TEST_LPM_ASSERT(lpm == NULL); 123 124 /* socket_id < -1 is invalid */ 125 config.max_rules = MAX_RULES; 126 lpm = rte_lpm_create(__func__, -2, &config); 127 TEST_LPM_ASSERT(lpm == NULL); 128 129 return PASS; 130 } 131 132 /* 133 * Create lpm table then delete lpm table 100 times 134 * Use a slightly different rules size each time 135 * */ 136 int32_t 137 test1(void) 138 { 139 struct rte_lpm *lpm = NULL; 140 struct rte_lpm_config config; 141 142 config.number_tbl8s = NUMBER_TBL8S; 143 config.flags = 0; 144 int32_t i; 145 146 /* rte_lpm_free: Free NULL */ 147 for (i = 0; i < 100; i++) { 148 config.max_rules = MAX_RULES - i; 149 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 150 TEST_LPM_ASSERT(lpm != NULL); 151 152 rte_lpm_free(lpm); 153 } 154 155 /* Can not test free so return success */ 156 return PASS; 157 } 158 159 /* 160 * Call rte_lpm_free for NULL pointer user input. Note: free has no return and 161 * therefore it is impossible to check for failure but this test is added to 162 * increase function coverage metrics and to validate that freeing null does 163 * not crash. 164 */ 165 int32_t 166 test2(void) 167 { 168 struct rte_lpm *lpm = NULL; 169 struct rte_lpm_config config; 170 171 config.max_rules = MAX_RULES; 172 config.number_tbl8s = NUMBER_TBL8S; 173 config.flags = 0; 174 175 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 176 TEST_LPM_ASSERT(lpm != NULL); 177 178 rte_lpm_free(lpm); 179 rte_lpm_free(NULL); 180 return PASS; 181 } 182 183 /* 184 * Check that rte_lpm_add fails gracefully for incorrect user input arguments 185 */ 186 int32_t 187 test3(void) 188 { 189 struct rte_lpm *lpm = NULL; 190 struct rte_lpm_config config; 191 192 config.max_rules = MAX_RULES; 193 config.number_tbl8s = NUMBER_TBL8S; 194 config.flags = 0; 195 uint32_t ip = IPv4(0, 0, 0, 0), next_hop = 100; 196 uint8_t depth = 24; 197 int32_t status = 0; 198 199 /* rte_lpm_add: lpm == NULL */ 200 status = rte_lpm_add(NULL, ip, depth, next_hop); 201 TEST_LPM_ASSERT(status < 0); 202 203 /*Create vaild lpm to use in rest of test. */ 204 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 205 TEST_LPM_ASSERT(lpm != NULL); 206 207 /* rte_lpm_add: depth < 1 */ 208 status = rte_lpm_add(lpm, ip, 0, next_hop); 209 TEST_LPM_ASSERT(status < 0); 210 211 /* rte_lpm_add: depth > MAX_DEPTH */ 212 status = rte_lpm_add(lpm, ip, (MAX_DEPTH + 1), next_hop); 213 TEST_LPM_ASSERT(status < 0); 214 215 rte_lpm_free(lpm); 216 217 return PASS; 218 } 219 220 /* 221 * Check that rte_lpm_delete fails gracefully for incorrect user input 222 * arguments 223 */ 224 int32_t 225 test4(void) 226 { 227 struct rte_lpm *lpm = NULL; 228 struct rte_lpm_config config; 229 230 config.max_rules = MAX_RULES; 231 config.number_tbl8s = NUMBER_TBL8S; 232 config.flags = 0; 233 uint32_t ip = IPv4(0, 0, 0, 0); 234 uint8_t depth = 24; 235 int32_t status = 0; 236 237 /* rte_lpm_delete: lpm == NULL */ 238 status = rte_lpm_delete(NULL, ip, depth); 239 TEST_LPM_ASSERT(status < 0); 240 241 /*Create vaild lpm to use in rest of test. */ 242 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 243 TEST_LPM_ASSERT(lpm != NULL); 244 245 /* rte_lpm_delete: depth < 1 */ 246 status = rte_lpm_delete(lpm, ip, 0); 247 TEST_LPM_ASSERT(status < 0); 248 249 /* rte_lpm_delete: depth > MAX_DEPTH */ 250 status = rte_lpm_delete(lpm, ip, (MAX_DEPTH + 1)); 251 TEST_LPM_ASSERT(status < 0); 252 253 rte_lpm_free(lpm); 254 255 return PASS; 256 } 257 258 /* 259 * Check that rte_lpm_lookup fails gracefully for incorrect user input 260 * arguments 261 */ 262 int32_t 263 test5(void) 264 { 265 #if defined(RTE_LIBRTE_LPM_DEBUG) 266 struct rte_lpm *lpm = NULL; 267 struct rte_lpm_config config; 268 269 config.max_rules = MAX_RULES; 270 config.number_tbl8s = NUMBER_TBL8S; 271 config.flags = 0; 272 uint32_t ip = IPv4(0, 0, 0, 0), next_hop_return = 0; 273 int32_t status = 0; 274 275 /* rte_lpm_lookup: lpm == NULL */ 276 status = rte_lpm_lookup(NULL, ip, &next_hop_return); 277 TEST_LPM_ASSERT(status < 0); 278 279 /*Create vaild lpm to use in rest of test. */ 280 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 281 TEST_LPM_ASSERT(lpm != NULL); 282 283 /* rte_lpm_lookup: depth < 1 */ 284 status = rte_lpm_lookup(lpm, ip, NULL); 285 TEST_LPM_ASSERT(status < 0); 286 287 rte_lpm_free(lpm); 288 #endif 289 return PASS; 290 } 291 292 293 294 /* 295 * Call add, lookup and delete for a single rule with depth <= 24 296 */ 297 int32_t 298 test6(void) 299 { 300 struct rte_lpm *lpm = NULL; 301 struct rte_lpm_config config; 302 303 config.max_rules = MAX_RULES; 304 config.number_tbl8s = NUMBER_TBL8S; 305 config.flags = 0; 306 uint32_t ip = IPv4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0; 307 uint8_t depth = 24; 308 int32_t status = 0; 309 310 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 311 TEST_LPM_ASSERT(lpm != NULL); 312 313 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 314 TEST_LPM_ASSERT(status == 0); 315 316 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 317 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 318 319 status = rte_lpm_delete(lpm, ip, depth); 320 TEST_LPM_ASSERT(status == 0); 321 322 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 323 TEST_LPM_ASSERT(status == -ENOENT); 324 325 rte_lpm_free(lpm); 326 327 return PASS; 328 } 329 330 /* 331 * Call add, lookup and delete for a single rule with depth > 24 332 */ 333 334 int32_t 335 test7(void) 336 { 337 xmm_t ipx4; 338 uint32_t hop[4]; 339 struct rte_lpm *lpm = NULL; 340 struct rte_lpm_config config; 341 342 config.max_rules = MAX_RULES; 343 config.number_tbl8s = NUMBER_TBL8S; 344 config.flags = 0; 345 uint32_t ip = IPv4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0; 346 uint8_t depth = 32; 347 int32_t status = 0; 348 349 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 350 TEST_LPM_ASSERT(lpm != NULL); 351 352 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 353 TEST_LPM_ASSERT(status == 0); 354 355 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 356 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 357 358 ipx4 = vect_set_epi32(ip, ip + 0x100, ip - 0x100, ip); 359 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 360 TEST_LPM_ASSERT(hop[0] == next_hop_add); 361 TEST_LPM_ASSERT(hop[1] == UINT32_MAX); 362 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 363 TEST_LPM_ASSERT(hop[3] == next_hop_add); 364 365 status = rte_lpm_delete(lpm, ip, depth); 366 TEST_LPM_ASSERT(status == 0); 367 368 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 369 TEST_LPM_ASSERT(status == -ENOENT); 370 371 rte_lpm_free(lpm); 372 373 return PASS; 374 } 375 376 /* 377 * Use rte_lpm_add to add rules which effect only the second half of the lpm 378 * table. Use all possible depths ranging from 1..32. Set the next hop = to the 379 * depth. Check lookup hit for on every add and check for lookup miss on the 380 * first half of the lpm table after each add. Finally delete all rules going 381 * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each 382 * delete. The lookup should return the next_hop_add value related to the 383 * previous depth value (i.e. depth -1). 384 */ 385 int32_t 386 test8(void) 387 { 388 xmm_t ipx4; 389 uint32_t hop[4]; 390 struct rte_lpm *lpm = NULL; 391 struct rte_lpm_config config; 392 393 config.max_rules = MAX_RULES; 394 config.number_tbl8s = NUMBER_TBL8S; 395 config.flags = 0; 396 uint32_t ip1 = IPv4(127, 255, 255, 255), ip2 = IPv4(128, 0, 0, 0); 397 uint32_t next_hop_add, next_hop_return; 398 uint8_t depth; 399 int32_t status = 0; 400 401 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 402 TEST_LPM_ASSERT(lpm != NULL); 403 404 /* Loop with rte_lpm_add. */ 405 for (depth = 1; depth <= 32; depth++) { 406 /* Let the next_hop_add value = depth. Just for change. */ 407 next_hop_add = depth; 408 409 status = rte_lpm_add(lpm, ip2, depth, next_hop_add); 410 TEST_LPM_ASSERT(status == 0); 411 412 /* Check IP in first half of tbl24 which should be empty. */ 413 status = rte_lpm_lookup(lpm, ip1, &next_hop_return); 414 TEST_LPM_ASSERT(status == -ENOENT); 415 416 status = rte_lpm_lookup(lpm, ip2, &next_hop_return); 417 TEST_LPM_ASSERT((status == 0) && 418 (next_hop_return == next_hop_add)); 419 420 ipx4 = vect_set_epi32(ip2, ip1, ip2, ip1); 421 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 422 TEST_LPM_ASSERT(hop[0] == UINT32_MAX); 423 TEST_LPM_ASSERT(hop[1] == next_hop_add); 424 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 425 TEST_LPM_ASSERT(hop[3] == next_hop_add); 426 } 427 428 /* Loop with rte_lpm_delete. */ 429 for (depth = 32; depth >= 1; depth--) { 430 next_hop_add = (uint8_t) (depth - 1); 431 432 status = rte_lpm_delete(lpm, ip2, depth); 433 TEST_LPM_ASSERT(status == 0); 434 435 status = rte_lpm_lookup(lpm, ip2, &next_hop_return); 436 437 if (depth != 1) { 438 TEST_LPM_ASSERT((status == 0) && 439 (next_hop_return == next_hop_add)); 440 } else { 441 TEST_LPM_ASSERT(status == -ENOENT); 442 } 443 444 status = rte_lpm_lookup(lpm, ip1, &next_hop_return); 445 TEST_LPM_ASSERT(status == -ENOENT); 446 447 ipx4 = vect_set_epi32(ip1, ip1, ip2, ip2); 448 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 449 if (depth != 1) { 450 TEST_LPM_ASSERT(hop[0] == next_hop_add); 451 TEST_LPM_ASSERT(hop[1] == next_hop_add); 452 } else { 453 TEST_LPM_ASSERT(hop[0] == UINT32_MAX); 454 TEST_LPM_ASSERT(hop[1] == UINT32_MAX); 455 } 456 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 457 TEST_LPM_ASSERT(hop[3] == UINT32_MAX); 458 } 459 460 rte_lpm_free(lpm); 461 462 return PASS; 463 } 464 465 /* 466 * - Add & lookup to hit invalid TBL24 entry 467 * - Add & lookup to hit valid TBL24 entry not extended 468 * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry 469 * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry 470 * 471 */ 472 int32_t 473 test9(void) 474 { 475 struct rte_lpm *lpm = NULL; 476 struct rte_lpm_config config; 477 478 config.max_rules = MAX_RULES; 479 config.number_tbl8s = NUMBER_TBL8S; 480 config.flags = 0; 481 uint32_t ip, ip_1, ip_2; 482 uint8_t depth, depth_1, depth_2; 483 uint32_t next_hop_add, next_hop_add_1, next_hop_add_2, next_hop_return; 484 int32_t status = 0; 485 486 /* Add & lookup to hit invalid TBL24 entry */ 487 ip = IPv4(128, 0, 0, 0); 488 depth = 24; 489 next_hop_add = 100; 490 491 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 492 TEST_LPM_ASSERT(lpm != NULL); 493 494 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 495 TEST_LPM_ASSERT(status == 0); 496 497 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 498 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 499 500 status = rte_lpm_delete(lpm, ip, depth); 501 TEST_LPM_ASSERT(status == 0); 502 503 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 504 TEST_LPM_ASSERT(status == -ENOENT); 505 506 rte_lpm_delete_all(lpm); 507 508 /* Add & lookup to hit valid TBL24 entry not extended */ 509 ip = IPv4(128, 0, 0, 0); 510 depth = 23; 511 next_hop_add = 100; 512 513 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 514 TEST_LPM_ASSERT(status == 0); 515 516 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 517 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 518 519 depth = 24; 520 next_hop_add = 101; 521 522 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 523 TEST_LPM_ASSERT(status == 0); 524 525 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 526 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 527 528 depth = 24; 529 530 status = rte_lpm_delete(lpm, ip, depth); 531 TEST_LPM_ASSERT(status == 0); 532 533 depth = 23; 534 535 status = rte_lpm_delete(lpm, ip, depth); 536 TEST_LPM_ASSERT(status == 0); 537 538 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 539 TEST_LPM_ASSERT(status == -ENOENT); 540 541 rte_lpm_delete_all(lpm); 542 543 /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8 544 * entry */ 545 ip = IPv4(128, 0, 0, 0); 546 depth = 32; 547 next_hop_add = 100; 548 549 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 550 TEST_LPM_ASSERT(status == 0); 551 552 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 553 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 554 555 ip = IPv4(128, 0, 0, 5); 556 depth = 32; 557 next_hop_add = 101; 558 559 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 560 TEST_LPM_ASSERT(status == 0); 561 562 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 563 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 564 565 status = rte_lpm_delete(lpm, ip, depth); 566 TEST_LPM_ASSERT(status == 0); 567 568 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 569 TEST_LPM_ASSERT(status == -ENOENT); 570 571 ip = IPv4(128, 0, 0, 0); 572 depth = 32; 573 next_hop_add = 100; 574 575 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 576 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 577 578 status = rte_lpm_delete(lpm, ip, depth); 579 TEST_LPM_ASSERT(status == 0); 580 581 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 582 TEST_LPM_ASSERT(status == -ENOENT); 583 584 rte_lpm_delete_all(lpm); 585 586 /* Add & lookup to hit valid extended TBL24 entry with valid TBL8 587 * entry */ 588 ip_1 = IPv4(128, 0, 0, 0); 589 depth_1 = 25; 590 next_hop_add_1 = 101; 591 592 ip_2 = IPv4(128, 0, 0, 5); 593 depth_2 = 32; 594 next_hop_add_2 = 102; 595 596 next_hop_return = 0; 597 598 status = rte_lpm_add(lpm, ip_1, depth_1, next_hop_add_1); 599 TEST_LPM_ASSERT(status == 0); 600 601 status = rte_lpm_lookup(lpm, ip_1, &next_hop_return); 602 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); 603 604 status = rte_lpm_add(lpm, ip_2, depth_2, next_hop_add_2); 605 TEST_LPM_ASSERT(status == 0); 606 607 status = rte_lpm_lookup(lpm, ip_2, &next_hop_return); 608 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2)); 609 610 status = rte_lpm_delete(lpm, ip_2, depth_2); 611 TEST_LPM_ASSERT(status == 0); 612 613 status = rte_lpm_lookup(lpm, ip_2, &next_hop_return); 614 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); 615 616 status = rte_lpm_delete(lpm, ip_1, depth_1); 617 TEST_LPM_ASSERT(status == 0); 618 619 status = rte_lpm_lookup(lpm, ip_1, &next_hop_return); 620 TEST_LPM_ASSERT(status == -ENOENT); 621 622 rte_lpm_free(lpm); 623 624 return PASS; 625 } 626 627 628 /* 629 * - Add rule that covers a TBL24 range previously invalid & lookup (& delete & 630 * lookup) 631 * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup) 632 * - Add rule that extends a TBL24 valid entry & lookup for both rules (& 633 * delete & lookup) 634 * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup) 635 * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup) 636 * - Delete a rule that is not present in the TBL24 & lookup 637 * - Delete a rule that is not present in the TBL8 & lookup 638 * 639 */ 640 int32_t 641 test10(void) 642 { 643 644 struct rte_lpm *lpm = NULL; 645 struct rte_lpm_config config; 646 647 config.max_rules = MAX_RULES; 648 config.number_tbl8s = NUMBER_TBL8S; 649 config.flags = 0; 650 uint32_t ip, next_hop_add, next_hop_return; 651 uint8_t depth; 652 int32_t status = 0; 653 654 /* Add rule that covers a TBL24 range previously invalid & lookup 655 * (& delete & lookup) */ 656 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 657 TEST_LPM_ASSERT(lpm != NULL); 658 659 ip = IPv4(128, 0, 0, 0); 660 depth = 16; 661 next_hop_add = 100; 662 663 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 664 TEST_LPM_ASSERT(status == 0); 665 666 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 667 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 668 669 status = rte_lpm_delete(lpm, ip, depth); 670 TEST_LPM_ASSERT(status == 0); 671 672 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 673 TEST_LPM_ASSERT(status == -ENOENT); 674 675 rte_lpm_delete_all(lpm); 676 677 ip = IPv4(128, 0, 0, 0); 678 depth = 25; 679 next_hop_add = 100; 680 681 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 682 TEST_LPM_ASSERT(status == 0); 683 684 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 685 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 686 687 status = rte_lpm_delete(lpm, ip, depth); 688 TEST_LPM_ASSERT(status == 0); 689 690 rte_lpm_delete_all(lpm); 691 692 /* Add rule that extends a TBL24 valid entry & lookup for both rules 693 * (& delete & lookup) */ 694 695 ip = IPv4(128, 0, 0, 0); 696 depth = 24; 697 next_hop_add = 100; 698 699 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 700 TEST_LPM_ASSERT(status == 0); 701 702 ip = IPv4(128, 0, 0, 10); 703 depth = 32; 704 next_hop_add = 101; 705 706 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 707 TEST_LPM_ASSERT(status == 0); 708 709 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 710 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 711 712 ip = IPv4(128, 0, 0, 0); 713 next_hop_add = 100; 714 715 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 716 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 717 718 ip = IPv4(128, 0, 0, 0); 719 depth = 24; 720 721 status = rte_lpm_delete(lpm, ip, depth); 722 TEST_LPM_ASSERT(status == 0); 723 724 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 725 TEST_LPM_ASSERT(status == -ENOENT); 726 727 ip = IPv4(128, 0, 0, 10); 728 depth = 32; 729 730 status = rte_lpm_delete(lpm, ip, depth); 731 TEST_LPM_ASSERT(status == 0); 732 733 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 734 TEST_LPM_ASSERT(status == -ENOENT); 735 736 rte_lpm_delete_all(lpm); 737 738 /* Add rule that updates the next hop in TBL24 & lookup 739 * (& delete & lookup) */ 740 741 ip = IPv4(128, 0, 0, 0); 742 depth = 24; 743 next_hop_add = 100; 744 745 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 746 TEST_LPM_ASSERT(status == 0); 747 748 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 749 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 750 751 next_hop_add = 101; 752 753 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 754 TEST_LPM_ASSERT(status == 0); 755 756 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 757 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 758 759 status = rte_lpm_delete(lpm, ip, depth); 760 TEST_LPM_ASSERT(status == 0); 761 762 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 763 TEST_LPM_ASSERT(status == -ENOENT); 764 765 rte_lpm_delete_all(lpm); 766 767 /* Add rule that updates the next hop in TBL8 & lookup 768 * (& delete & lookup) */ 769 770 ip = IPv4(128, 0, 0, 0); 771 depth = 32; 772 next_hop_add = 100; 773 774 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 775 TEST_LPM_ASSERT(status == 0); 776 777 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 778 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 779 780 next_hop_add = 101; 781 782 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 783 TEST_LPM_ASSERT(status == 0); 784 785 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 786 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 787 788 status = rte_lpm_delete(lpm, ip, depth); 789 TEST_LPM_ASSERT(status == 0); 790 791 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 792 TEST_LPM_ASSERT(status == -ENOENT); 793 794 rte_lpm_delete_all(lpm); 795 796 /* Delete a rule that is not present in the TBL24 & lookup */ 797 798 ip = IPv4(128, 0, 0, 0); 799 depth = 24; 800 801 status = rte_lpm_delete(lpm, ip, depth); 802 TEST_LPM_ASSERT(status < 0); 803 804 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 805 TEST_LPM_ASSERT(status == -ENOENT); 806 807 rte_lpm_delete_all(lpm); 808 809 /* Delete a rule that is not present in the TBL8 & lookup */ 810 811 ip = IPv4(128, 0, 0, 0); 812 depth = 32; 813 814 status = rte_lpm_delete(lpm, ip, depth); 815 TEST_LPM_ASSERT(status < 0); 816 817 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 818 TEST_LPM_ASSERT(status == -ENOENT); 819 820 rte_lpm_free(lpm); 821 822 return PASS; 823 } 824 825 /* 826 * Add two rules, lookup to hit the more specific one, lookup to hit the less 827 * specific one delete the less specific rule and lookup previous values again; 828 * add a more specific rule than the existing rule, lookup again 829 * 830 * */ 831 int32_t 832 test11(void) 833 { 834 835 struct rte_lpm *lpm = NULL; 836 struct rte_lpm_config config; 837 838 config.max_rules = MAX_RULES; 839 config.number_tbl8s = NUMBER_TBL8S; 840 config.flags = 0; 841 uint32_t ip, next_hop_add, next_hop_return; 842 uint8_t depth; 843 int32_t status = 0; 844 845 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 846 TEST_LPM_ASSERT(lpm != NULL); 847 848 ip = IPv4(128, 0, 0, 0); 849 depth = 24; 850 next_hop_add = 100; 851 852 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 853 TEST_LPM_ASSERT(status == 0); 854 855 ip = IPv4(128, 0, 0, 10); 856 depth = 32; 857 next_hop_add = 101; 858 859 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 860 TEST_LPM_ASSERT(status == 0); 861 862 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 863 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 864 865 ip = IPv4(128, 0, 0, 0); 866 next_hop_add = 100; 867 868 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 869 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); 870 871 ip = IPv4(128, 0, 0, 0); 872 depth = 24; 873 874 status = rte_lpm_delete(lpm, ip, depth); 875 TEST_LPM_ASSERT(status == 0); 876 877 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 878 TEST_LPM_ASSERT(status == -ENOENT); 879 880 ip = IPv4(128, 0, 0, 10); 881 depth = 32; 882 883 status = rte_lpm_delete(lpm, ip, depth); 884 TEST_LPM_ASSERT(status == 0); 885 886 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 887 TEST_LPM_ASSERT(status == -ENOENT); 888 889 rte_lpm_free(lpm); 890 891 return PASS; 892 } 893 894 /* 895 * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete, 896 * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension 897 * and contraction. 898 * 899 * */ 900 901 int32_t 902 test12(void) 903 { 904 xmm_t ipx4; 905 uint32_t hop[4]; 906 struct rte_lpm *lpm = NULL; 907 struct rte_lpm_config config; 908 909 config.max_rules = MAX_RULES; 910 config.number_tbl8s = NUMBER_TBL8S; 911 config.flags = 0; 912 uint32_t ip, i, next_hop_add, next_hop_return; 913 uint8_t depth; 914 int32_t status = 0; 915 916 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 917 TEST_LPM_ASSERT(lpm != NULL); 918 919 ip = IPv4(128, 0, 0, 0); 920 depth = 32; 921 next_hop_add = 100; 922 923 for (i = 0; i < 1000; i++) { 924 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 925 TEST_LPM_ASSERT(status == 0); 926 927 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 928 TEST_LPM_ASSERT((status == 0) && 929 (next_hop_return == next_hop_add)); 930 931 ipx4 = vect_set_epi32(ip, ip + 1, ip, ip - 1); 932 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); 933 TEST_LPM_ASSERT(hop[0] == UINT32_MAX); 934 TEST_LPM_ASSERT(hop[1] == next_hop_add); 935 TEST_LPM_ASSERT(hop[2] == UINT32_MAX); 936 TEST_LPM_ASSERT(hop[3] == next_hop_add); 937 938 status = rte_lpm_delete(lpm, ip, depth); 939 TEST_LPM_ASSERT(status == 0); 940 941 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 942 TEST_LPM_ASSERT(status == -ENOENT); 943 } 944 945 rte_lpm_free(lpm); 946 947 return PASS; 948 } 949 950 /* 951 * Add a rule to tbl24, lookup (hit), then add a rule that will extend this 952 * tbl24 entry, lookup (hit). delete the rule that caused the tbl24 extension, 953 * lookup (miss) and repeat for loop of 1000 times. This will check tbl8 954 * extension and contraction. 955 * 956 * */ 957 958 int32_t 959 test13(void) 960 { 961 struct rte_lpm *lpm = NULL; 962 struct rte_lpm_config config; 963 964 config.max_rules = MAX_RULES; 965 config.number_tbl8s = NUMBER_TBL8S; 966 config.flags = 0; 967 uint32_t ip, i, next_hop_add_1, next_hop_add_2, next_hop_return; 968 uint8_t depth; 969 int32_t status = 0; 970 971 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 972 TEST_LPM_ASSERT(lpm != NULL); 973 974 ip = IPv4(128, 0, 0, 0); 975 depth = 24; 976 next_hop_add_1 = 100; 977 978 status = rte_lpm_add(lpm, ip, depth, next_hop_add_1); 979 TEST_LPM_ASSERT(status == 0); 980 981 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 982 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); 983 984 depth = 32; 985 next_hop_add_2 = 101; 986 987 for (i = 0; i < 1000; i++) { 988 status = rte_lpm_add(lpm, ip, depth, next_hop_add_2); 989 TEST_LPM_ASSERT(status == 0); 990 991 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 992 TEST_LPM_ASSERT((status == 0) && 993 (next_hop_return == next_hop_add_2)); 994 995 status = rte_lpm_delete(lpm, ip, depth); 996 TEST_LPM_ASSERT(status == 0); 997 998 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 999 TEST_LPM_ASSERT((status == 0) && 1000 (next_hop_return == next_hop_add_1)); 1001 } 1002 1003 depth = 24; 1004 1005 status = rte_lpm_delete(lpm, ip, depth); 1006 TEST_LPM_ASSERT(status == 0); 1007 1008 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 1009 TEST_LPM_ASSERT(status == -ENOENT); 1010 1011 rte_lpm_free(lpm); 1012 1013 return PASS; 1014 } 1015 1016 /* 1017 * Fore TBL8 extension exhaustion. Add 256 rules that require a tbl8 extension. 1018 * No more tbl8 extensions will be allowed. Now add one more rule that required 1019 * a tbl8 extension and get fail. 1020 * */ 1021 int32_t 1022 test14(void) 1023 { 1024 1025 /* We only use depth = 32 in the loop below so we must make sure 1026 * that we have enough storage for all rules at that depth*/ 1027 1028 struct rte_lpm *lpm = NULL; 1029 struct rte_lpm_config config; 1030 1031 config.max_rules = 256 * 32; 1032 config.number_tbl8s = NUMBER_TBL8S; 1033 config.flags = 0; 1034 uint32_t ip, next_hop_add, next_hop_return; 1035 uint8_t depth; 1036 int32_t status = 0; 1037 1038 /* Add enough space for 256 rules for every depth */ 1039 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1040 TEST_LPM_ASSERT(lpm != NULL); 1041 1042 depth = 32; 1043 next_hop_add = 100; 1044 ip = IPv4(0, 0, 0, 0); 1045 1046 /* Add 256 rules that require a tbl8 extension */ 1047 for (; ip <= IPv4(0, 0, 255, 0); ip += 256) { 1048 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 1049 TEST_LPM_ASSERT(status == 0); 1050 1051 status = rte_lpm_lookup(lpm, ip, &next_hop_return); 1052 TEST_LPM_ASSERT((status == 0) && 1053 (next_hop_return == next_hop_add)); 1054 } 1055 1056 /* All tbl8 extensions have been used above. Try to add one more and 1057 * we get a fail */ 1058 ip = IPv4(1, 0, 0, 0); 1059 depth = 32; 1060 1061 status = rte_lpm_add(lpm, ip, depth, next_hop_add); 1062 TEST_LPM_ASSERT(status < 0); 1063 1064 rte_lpm_free(lpm); 1065 1066 return PASS; 1067 } 1068 1069 /* 1070 * Sequence of operations for find existing lpm table 1071 * 1072 * - create table 1073 * - find existing table: hit 1074 * - find non-existing table: miss 1075 * 1076 */ 1077 int32_t 1078 test15(void) 1079 { 1080 struct rte_lpm *lpm = NULL, *result = NULL; 1081 struct rte_lpm_config config; 1082 1083 config.max_rules = 256 * 32; 1084 config.number_tbl8s = NUMBER_TBL8S; 1085 config.flags = 0; 1086 1087 /* Create lpm */ 1088 lpm = rte_lpm_create("lpm_find_existing", SOCKET_ID_ANY, &config); 1089 TEST_LPM_ASSERT(lpm != NULL); 1090 1091 /* Try to find existing lpm */ 1092 result = rte_lpm_find_existing("lpm_find_existing"); 1093 TEST_LPM_ASSERT(result == lpm); 1094 1095 /* Try to find non-existing lpm */ 1096 result = rte_lpm_find_existing("lpm_find_non_existing"); 1097 TEST_LPM_ASSERT(result == NULL); 1098 1099 /* Cleanup. */ 1100 rte_lpm_delete_all(lpm); 1101 rte_lpm_free(lpm); 1102 1103 return PASS; 1104 } 1105 1106 /* 1107 * test failure condition of overloading the tbl8 so no more will fit 1108 * Check we get an error return value in that case 1109 */ 1110 int32_t 1111 test16(void) 1112 { 1113 uint32_t ip; 1114 struct rte_lpm_config config; 1115 1116 config.max_rules = 256 * 32; 1117 config.number_tbl8s = NUMBER_TBL8S; 1118 config.flags = 0; 1119 struct rte_lpm *lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1120 1121 /* ip loops through all possibilities for top 24 bits of address */ 1122 for (ip = 0; ip < 0xFFFFFF; ip++) { 1123 /* add an entry within a different tbl8 each time, since 1124 * depth >24 and the top 24 bits are different */ 1125 if (rte_lpm_add(lpm, (ip << 8) + 0xF0, 30, 0) < 0) 1126 break; 1127 } 1128 1129 if (ip != NUMBER_TBL8S) { 1130 printf("Error, unexpected failure with filling tbl8 groups\n"); 1131 printf("Failed after %u additions, expected after %u\n", 1132 (unsigned)ip, (unsigned)NUMBER_TBL8S); 1133 } 1134 1135 rte_lpm_free(lpm); 1136 return 0; 1137 } 1138 1139 /* 1140 * Test for overwriting of tbl8: 1141 * - add rule /32 and lookup 1142 * - add new rule /24 and lookup 1143 * - add third rule /25 and lookup 1144 * - lookup /32 and /24 rule to ensure the table has not been overwritten. 1145 */ 1146 int32_t 1147 test17(void) 1148 { 1149 struct rte_lpm *lpm = NULL; 1150 struct rte_lpm_config config; 1151 1152 config.max_rules = MAX_RULES; 1153 config.number_tbl8s = NUMBER_TBL8S; 1154 config.flags = 0; 1155 const uint32_t ip_10_32 = IPv4(10, 10, 10, 2); 1156 const uint32_t ip_10_24 = IPv4(10, 10, 10, 0); 1157 const uint32_t ip_20_25 = IPv4(10, 10, 20, 2); 1158 const uint8_t d_ip_10_32 = 32, 1159 d_ip_10_24 = 24, 1160 d_ip_20_25 = 25; 1161 const uint32_t next_hop_ip_10_32 = 100, 1162 next_hop_ip_10_24 = 105, 1163 next_hop_ip_20_25 = 111; 1164 uint32_t next_hop_return = 0; 1165 int32_t status = 0; 1166 1167 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); 1168 TEST_LPM_ASSERT(lpm != NULL); 1169 1170 if ((status = rte_lpm_add(lpm, ip_10_32, d_ip_10_32, 1171 next_hop_ip_10_32)) < 0) 1172 return -1; 1173 1174 status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return); 1175 uint32_t test_hop_10_32 = next_hop_return; 1176 TEST_LPM_ASSERT(status == 0); 1177 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); 1178 1179 if ((status = rte_lpm_add(lpm, ip_10_24, d_ip_10_24, 1180 next_hop_ip_10_24)) < 0) 1181 return -1; 1182 1183 status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return); 1184 uint32_t test_hop_10_24 = next_hop_return; 1185 TEST_LPM_ASSERT(status == 0); 1186 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); 1187 1188 if ((status = rte_lpm_add(lpm, ip_20_25, d_ip_20_25, 1189 next_hop_ip_20_25)) < 0) 1190 return -1; 1191 1192 status = rte_lpm_lookup(lpm, ip_20_25, &next_hop_return); 1193 uint32_t test_hop_20_25 = next_hop_return; 1194 TEST_LPM_ASSERT(status == 0); 1195 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25); 1196 1197 if (test_hop_10_32 == test_hop_10_24) { 1198 printf("Next hop return equal\n"); 1199 return -1; 1200 } 1201 1202 if (test_hop_10_24 == test_hop_20_25) { 1203 printf("Next hop return equal\n"); 1204 return -1; 1205 } 1206 1207 status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return); 1208 TEST_LPM_ASSERT(status == 0); 1209 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); 1210 1211 status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return); 1212 TEST_LPM_ASSERT(status == 0); 1213 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); 1214 1215 rte_lpm_free(lpm); 1216 1217 return PASS; 1218 } 1219 1220 /* 1221 * Do all unit tests. 1222 */ 1223 1224 static int 1225 test_lpm(void) 1226 { 1227 unsigned i; 1228 int status, global_status = 0; 1229 1230 for (i = 0; i < NUM_LPM_TESTS; i++) { 1231 status = tests[i](); 1232 if (status < 0) { 1233 printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests[i])); 1234 global_status = status; 1235 } 1236 } 1237 1238 return global_status; 1239 } 1240 1241 REGISTER_TEST_COMMAND(lpm_autotest, test_lpm); 1242