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