1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com> 3 * Copyright(c) 2019 Intel Corporation 4 */ 5 6 #include <stdio.h> 7 #include <stdint.h> 8 #include <stdlib.h> 9 10 #include <rte_ip.h> 11 #include <rte_log.h> 12 #include <rte_fib.h> 13 #include <rte_malloc.h> 14 15 #include "test.h" 16 17 typedef int32_t (*rte_fib_test)(void); 18 19 static int32_t test_create_invalid(void); 20 static int32_t test_multiple_create(void); 21 static int32_t test_free_null(void); 22 static int32_t test_add_del_invalid(void); 23 static int32_t test_get_invalid(void); 24 static int32_t test_lookup(void); 25 static int32_t test_invalid_rcu(void); 26 static int32_t test_fib_rcu_sync_rw(void); 27 28 #define MAX_ROUTES (1 << 16) 29 #define MAX_TBL8 (1 << 15) 30 31 /* 32 * Check that rte_fib_create fails gracefully for incorrect user input 33 * arguments 34 */ 35 int32_t 36 test_create_invalid(void) 37 { 38 struct rte_fib *fib = NULL; 39 struct rte_fib_conf config = { 0 }; 40 41 config.max_routes = MAX_ROUTES; 42 config.rib_ext_sz = 0; 43 config.default_nh = 0; 44 config.type = RTE_FIB_DUMMY; 45 46 /* rte_fib_create: fib name == NULL */ 47 fib = rte_fib_create(NULL, SOCKET_ID_ANY, &config); 48 RTE_TEST_ASSERT(fib == NULL, 49 "Call succeeded with invalid parameters\n"); 50 51 /* rte_fib_create: config == NULL */ 52 fib = rte_fib_create(__func__, SOCKET_ID_ANY, NULL); 53 RTE_TEST_ASSERT(fib == NULL, 54 "Call succeeded with invalid parameters\n"); 55 56 /* socket_id < -1 is invalid */ 57 fib = rte_fib_create(__func__, -2, &config); 58 RTE_TEST_ASSERT(fib == NULL, 59 "Call succeeded with invalid parameters\n"); 60 61 /* rte_fib_create: max_routes = 0 */ 62 config.max_routes = 0; 63 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 64 RTE_TEST_ASSERT(fib == NULL, 65 "Call succeeded with invalid parameters\n"); 66 config.max_routes = MAX_ROUTES; 67 68 config.type = RTE_FIB_DIR24_8 + 1; 69 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 70 RTE_TEST_ASSERT(fib == NULL, 71 "Call succeeded with invalid parameters\n"); 72 73 config.type = RTE_FIB_DIR24_8; 74 config.dir24_8.num_tbl8 = MAX_TBL8; 75 76 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_8B + 1; 77 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 78 RTE_TEST_ASSERT(fib == NULL, 79 "Call succeeded with invalid parameters\n"); 80 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_8B; 81 82 config.dir24_8.num_tbl8 = 0; 83 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 84 RTE_TEST_ASSERT(fib == NULL, 85 "Call succeeded with invalid parameters\n"); 86 87 return TEST_SUCCESS; 88 } 89 90 /* 91 * Create fib table then delete fib table 10 times 92 * Use a slightly different rules size each time 93 */ 94 int32_t 95 test_multiple_create(void) 96 { 97 struct rte_fib *fib = NULL; 98 struct rte_fib_conf config = { 0 }; 99 int32_t i; 100 101 config.rib_ext_sz = 0; 102 config.default_nh = 0; 103 config.type = RTE_FIB_DUMMY; 104 105 for (i = 0; i < 100; i++) { 106 config.max_routes = MAX_ROUTES - i; 107 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 108 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 109 rte_fib_free(fib); 110 } 111 /* Can not test free so return success */ 112 return TEST_SUCCESS; 113 } 114 115 /* 116 * Call rte_fib_free for NULL pointer user input. Note: free has no return and 117 * therefore it is impossible to check for failure but this test is added to 118 * increase function coverage metrics and to validate that freeing null does 119 * not crash. 120 */ 121 int32_t 122 test_free_null(void) 123 { 124 struct rte_fib *fib = NULL; 125 struct rte_fib_conf config = { 0 }; 126 127 config.max_routes = MAX_ROUTES; 128 config.rib_ext_sz = 0; 129 config.default_nh = 0; 130 config.type = RTE_FIB_DUMMY; 131 132 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 133 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 134 135 rte_fib_free(fib); 136 rte_fib_free(NULL); 137 return TEST_SUCCESS; 138 } 139 140 /* 141 * Check that rte_fib_add and rte_fib_delete fails gracefully 142 * for incorrect user input arguments 143 */ 144 int32_t 145 test_add_del_invalid(void) 146 { 147 struct rte_fib *fib = NULL; 148 struct rte_fib_conf config = { 0 }; 149 uint64_t nh = 100; 150 uint32_t ip = RTE_IPV4(0, 0, 0, 0); 151 int ret; 152 uint8_t depth = 24; 153 154 config.max_routes = MAX_ROUTES; 155 config.rib_ext_sz = 0; 156 config.default_nh = 0; 157 config.type = RTE_FIB_DUMMY; 158 159 /* rte_fib_add: fib == NULL */ 160 ret = rte_fib_add(NULL, ip, depth, nh); 161 RTE_TEST_ASSERT(ret < 0, 162 "Call succeeded with invalid parameters\n"); 163 164 /* rte_fib_delete: fib == NULL */ 165 ret = rte_fib_delete(NULL, ip, depth); 166 RTE_TEST_ASSERT(ret < 0, 167 "Call succeeded with invalid parameters\n"); 168 169 /*Create valid fib to use in rest of test. */ 170 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 171 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 172 173 /* rte_fib_add: depth > RTE_FIB_MAXDEPTH */ 174 ret = rte_fib_add(fib, ip, RTE_FIB_MAXDEPTH + 1, nh); 175 RTE_TEST_ASSERT(ret < 0, 176 "Call succeeded with invalid parameters\n"); 177 178 /* rte_fib_delete: depth > RTE_FIB_MAXDEPTH */ 179 ret = rte_fib_delete(fib, ip, RTE_FIB_MAXDEPTH + 1); 180 RTE_TEST_ASSERT(ret < 0, 181 "Call succeeded with invalid parameters\n"); 182 183 rte_fib_free(fib); 184 185 return TEST_SUCCESS; 186 } 187 188 /* 189 * Check that rte_fib_get_dp and rte_fib_get_rib fails gracefully 190 * for incorrect user input arguments 191 */ 192 int32_t 193 test_get_invalid(void) 194 { 195 void *p; 196 197 p = rte_fib_get_dp(NULL); 198 RTE_TEST_ASSERT(p == NULL, 199 "Call succeeded with invalid parameters\n"); 200 201 p = rte_fib_get_rib(NULL); 202 RTE_TEST_ASSERT(p == NULL, 203 "Call succeeded with invalid parameters\n"); 204 205 return TEST_SUCCESS; 206 } 207 208 /* 209 * Add routes for one supernet with all possible depths and do lookup 210 * on each step 211 * After delete routes with doing lookup on each step 212 */ 213 static int 214 lookup_and_check_asc(struct rte_fib *fib, uint32_t ip_arr[RTE_FIB_MAXDEPTH], 215 uint32_t ip_missing, uint64_t def_nh, uint32_t n) 216 { 217 uint64_t nh_arr[RTE_FIB_MAXDEPTH]; 218 int ret; 219 uint32_t i = 0; 220 221 ret = rte_fib_lookup_bulk(fib, ip_arr, nh_arr, RTE_FIB_MAXDEPTH); 222 RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n"); 223 224 for (; i <= RTE_FIB_MAXDEPTH - n; i++) 225 RTE_TEST_ASSERT(nh_arr[i] == n, 226 "Failed to get proper nexthop\n"); 227 228 for (; i < RTE_FIB_MAXDEPTH; i++) 229 RTE_TEST_ASSERT(nh_arr[i] == --n, 230 "Failed to get proper nexthop\n"); 231 232 ret = rte_fib_lookup_bulk(fib, &ip_missing, nh_arr, 1); 233 RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh), 234 "Failed to get proper nexthop\n"); 235 236 return TEST_SUCCESS; 237 } 238 239 static int 240 lookup_and_check_desc(struct rte_fib *fib, uint32_t ip_arr[RTE_FIB_MAXDEPTH], 241 uint32_t ip_missing, uint64_t def_nh, uint32_t n) 242 { 243 uint64_t nh_arr[RTE_FIB_MAXDEPTH]; 244 int ret; 245 uint32_t i = 0; 246 247 ret = rte_fib_lookup_bulk(fib, ip_arr, nh_arr, RTE_FIB_MAXDEPTH); 248 RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n"); 249 250 for (; i < n; i++) 251 RTE_TEST_ASSERT(nh_arr[i] == RTE_FIB_MAXDEPTH - i, 252 "Failed to get proper nexthop\n"); 253 254 for (; i < RTE_FIB_MAXDEPTH; i++) 255 RTE_TEST_ASSERT(nh_arr[i] == def_nh, 256 "Failed to get proper nexthop\n"); 257 258 ret = rte_fib_lookup_bulk(fib, &ip_missing, nh_arr, 1); 259 RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh), 260 "Failed to get proper nexthop\n"); 261 262 return TEST_SUCCESS; 263 } 264 265 static int 266 check_fib(struct rte_fib *fib) 267 { 268 uint64_t def_nh = 100; 269 uint32_t ip_arr[RTE_FIB_MAXDEPTH]; 270 uint32_t ip_add = RTE_IPV4(128, 0, 0, 0); 271 uint32_t i, ip_missing = RTE_IPV4(127, 255, 255, 255); 272 int ret; 273 274 for (i = 0; i < RTE_FIB_MAXDEPTH; i++) 275 ip_arr[i] = ip_add + (1ULL << i) - 1; 276 277 ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 0); 278 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 279 280 for (i = 1; i <= RTE_FIB_MAXDEPTH; i++) { 281 ret = rte_fib_add(fib, ip_add, i, i); 282 RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n"); 283 ret = lookup_and_check_asc(fib, ip_arr, ip_missing, 284 def_nh, i); 285 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 286 } 287 288 for (i = RTE_FIB_MAXDEPTH; i > 1; i--) { 289 ret = rte_fib_delete(fib, ip_add, i); 290 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n"); 291 ret = lookup_and_check_asc(fib, ip_arr, ip_missing, 292 def_nh, i - 1); 293 294 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 295 } 296 ret = rte_fib_delete(fib, ip_add, i); 297 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n"); 298 ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 0); 299 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 300 301 for (i = 0; i < RTE_FIB_MAXDEPTH; i++) { 302 ret = rte_fib_add(fib, ip_add, RTE_FIB_MAXDEPTH - i, 303 RTE_FIB_MAXDEPTH - i); 304 RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n"); 305 ret = lookup_and_check_desc(fib, ip_arr, ip_missing, 306 def_nh, i + 1); 307 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 308 } 309 310 for (i = 1; i <= RTE_FIB_MAXDEPTH; i++) { 311 ret = rte_fib_delete(fib, ip_add, i); 312 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n"); 313 ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 314 RTE_FIB_MAXDEPTH - i); 315 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 316 } 317 318 return TEST_SUCCESS; 319 } 320 321 int32_t 322 test_lookup(void) 323 { 324 struct rte_fib *fib = NULL; 325 struct rte_fib_conf config = { 0 }; 326 uint64_t def_nh = 100; 327 int ret; 328 329 config.max_routes = MAX_ROUTES; 330 config.rib_ext_sz = 0; 331 config.default_nh = def_nh; 332 config.type = RTE_FIB_DUMMY; 333 334 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 335 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 336 ret = check_fib(fib); 337 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 338 "Check_fib fails for DUMMY type\n"); 339 rte_fib_free(fib); 340 341 config.type = RTE_FIB_DIR24_8; 342 343 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_1B; 344 config.dir24_8.num_tbl8 = 127; 345 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 346 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 347 ret = check_fib(fib); 348 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 349 "Check_fib fails for DIR24_8_1B type\n"); 350 rte_fib_free(fib); 351 352 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_2B; 353 config.dir24_8.num_tbl8 = MAX_TBL8 - 1; 354 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 355 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 356 ret = check_fib(fib); 357 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 358 "Check_fib fails for DIR24_8_2B type\n"); 359 rte_fib_free(fib); 360 361 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B; 362 config.dir24_8.num_tbl8 = MAX_TBL8; 363 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 364 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 365 ret = check_fib(fib); 366 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 367 "Check_fib fails for DIR24_8_4B type\n"); 368 rte_fib_free(fib); 369 370 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_8B; 371 config.dir24_8.num_tbl8 = MAX_TBL8; 372 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 373 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 374 ret = check_fib(fib); 375 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 376 "Check_fib fails for DIR24_8_8B type\n"); 377 rte_fib_free(fib); 378 379 return TEST_SUCCESS; 380 } 381 382 /* 383 * rte_fib_rcu_qsbr_add positive and negative tests. 384 * - Add RCU QSBR variable to FIB 385 * - Add another RCU QSBR variable to FIB 386 * - Check returns 387 */ 388 int32_t 389 test_invalid_rcu(void) 390 { 391 struct rte_fib *fib = NULL; 392 struct rte_fib_conf config = { 0 }; 393 size_t sz; 394 struct rte_rcu_qsbr *qsv; 395 struct rte_rcu_qsbr *qsv2; 396 int32_t status; 397 struct rte_fib_rcu_config rcu_cfg = {0}; 398 uint64_t def_nh = 100; 399 400 config.max_routes = MAX_ROUTES; 401 config.rib_ext_sz = 0; 402 config.default_nh = def_nh; 403 404 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 405 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 406 407 /* Create RCU QSBR variable */ 408 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE); 409 qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE, 410 SOCKET_ID_ANY); 411 RTE_TEST_ASSERT(qsv != NULL, "Can not allocate memory for RCU\n"); 412 413 status = rte_rcu_qsbr_init(qsv, RTE_MAX_LCORE); 414 RTE_TEST_ASSERT(status == 0, "Can not initialize RCU\n"); 415 416 rcu_cfg.v = qsv; 417 418 /* adding rcu to RTE_FIB_DUMMY FIB type */ 419 config.type = RTE_FIB_DUMMY; 420 rcu_cfg.mode = RTE_FIB_QSBR_MODE_SYNC; 421 status = rte_fib_rcu_qsbr_add(fib, &rcu_cfg); 422 RTE_TEST_ASSERT(status == -ENOTSUP, 423 "rte_fib_rcu_qsbr_add returned wrong error status when called with DUMMY type FIB\n"); 424 rte_fib_free(fib); 425 426 config.type = RTE_FIB_DIR24_8; 427 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B; 428 config.dir24_8.num_tbl8 = MAX_TBL8; 429 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 430 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 431 432 /* Call rte_fib_rcu_qsbr_add without fib or config */ 433 status = rte_fib_rcu_qsbr_add(NULL, &rcu_cfg); 434 RTE_TEST_ASSERT(status == -EINVAL, "RCU added without fib\n"); 435 status = rte_fib_rcu_qsbr_add(fib, NULL); 436 RTE_TEST_ASSERT(status == -EINVAL, "RCU added without config\n"); 437 438 /* Invalid QSBR mode */ 439 rcu_cfg.mode = 2; 440 status = rte_fib_rcu_qsbr_add(fib, &rcu_cfg); 441 RTE_TEST_ASSERT(status == -EINVAL, "RCU added with incorrect mode\n"); 442 443 rcu_cfg.mode = RTE_FIB_QSBR_MODE_DQ; 444 445 /* Attach RCU QSBR to FIB to check for double attach */ 446 status = rte_fib_rcu_qsbr_add(fib, &rcu_cfg); 447 RTE_TEST_ASSERT(status == 0, "Can not attach RCU to FIB\n"); 448 449 /* Create and attach another RCU QSBR to FIB table */ 450 qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE, 451 SOCKET_ID_ANY); 452 RTE_TEST_ASSERT(qsv2 != NULL, "Can not allocate memory for RCU\n"); 453 454 rcu_cfg.v = qsv2; 455 rcu_cfg.mode = RTE_FIB_QSBR_MODE_SYNC; 456 status = rte_fib_rcu_qsbr_add(fib, &rcu_cfg); 457 RTE_TEST_ASSERT(status == -EEXIST, "Secondary RCU was mistakenly attached\n"); 458 459 rte_fib_free(fib); 460 rte_free(qsv); 461 rte_free(qsv2); 462 463 return TEST_SUCCESS; 464 } 465 466 static struct rte_fib *g_fib; 467 static struct rte_rcu_qsbr *g_v; 468 static uint32_t g_ip = RTE_IPV4(192, 0, 2, 100); 469 static volatile uint8_t writer_done; 470 /* Report quiescent state interval every 1024 lookups. Larger critical 471 * sections in reader will result in writer polling multiple times. 472 */ 473 #define QSBR_REPORTING_INTERVAL 1024 474 #define WRITER_ITERATIONS 512 475 476 /* 477 * Reader thread using rte_fib data structure with RCU. 478 */ 479 static int 480 test_fib_rcu_qsbr_reader(void *arg) 481 { 482 int i; 483 uint64_t next_hop_return = 0; 484 485 RTE_SET_USED(arg); 486 /* Register this thread to report quiescent state */ 487 rte_rcu_qsbr_thread_register(g_v, 0); 488 rte_rcu_qsbr_thread_online(g_v, 0); 489 490 do { 491 for (i = 0; i < QSBR_REPORTING_INTERVAL; i++) 492 rte_fib_lookup_bulk(g_fib, &g_ip, &next_hop_return, 1); 493 494 /* Update quiescent state */ 495 rte_rcu_qsbr_quiescent(g_v, 0); 496 } while (!writer_done); 497 498 rte_rcu_qsbr_thread_offline(g_v, 0); 499 rte_rcu_qsbr_thread_unregister(g_v, 0); 500 501 return 0; 502 } 503 504 /* 505 * rte_fib_rcu_qsbr_add sync mode functional test. 506 * 1 Reader and 1 writer. They cannot be in the same thread in this test. 507 * - Create FIB which supports 1 tbl8 group at max 508 * - Add RCU QSBR variable with sync mode to FIB 509 * - Register a reader thread. Reader keeps looking up a specific rule. 510 * - Writer keeps adding and deleting a specific rule with depth=28 (> 24) 511 */ 512 int32_t 513 test_fib_rcu_sync_rw(void) 514 { 515 struct rte_fib_conf config = { 0 }; 516 size_t sz; 517 int32_t status; 518 uint32_t i, next_hop; 519 uint8_t depth; 520 struct rte_fib_rcu_config rcu_cfg = {0}; 521 uint64_t def_nh = 100; 522 523 if (rte_lcore_count() < 2) { 524 printf("Not enough cores for %s, expecting at least 2\n", __func__); 525 return TEST_SKIPPED; 526 } 527 528 config.max_routes = MAX_ROUTES; 529 config.rib_ext_sz = 0; 530 config.default_nh = def_nh; 531 config.type = RTE_FIB_DIR24_8; 532 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B; 533 config.dir24_8.num_tbl8 = 1; 534 535 g_fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 536 RTE_TEST_ASSERT(g_fib != NULL, "Failed to create FIB\n"); 537 538 /* Create RCU QSBR variable */ 539 sz = rte_rcu_qsbr_get_memsize(1); 540 g_v = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE, 541 SOCKET_ID_ANY); 542 RTE_TEST_ASSERT(g_v != NULL, "Can not allocate memory for RCU\n"); 543 544 status = rte_rcu_qsbr_init(g_v, 1); 545 RTE_TEST_ASSERT(status == 0, "Can not initialize RCU\n"); 546 547 rcu_cfg.v = g_v; 548 rcu_cfg.mode = RTE_FIB_QSBR_MODE_SYNC; 549 /* Attach RCU QSBR to FIB table */ 550 status = rte_fib_rcu_qsbr_add(g_fib, &rcu_cfg); 551 RTE_TEST_ASSERT(status == 0, "Can not attach RCU to FIB\n"); 552 553 writer_done = 0; 554 /* Launch reader thread */ 555 rte_eal_remote_launch(test_fib_rcu_qsbr_reader, NULL, rte_get_next_lcore(-1, 1, 0)); 556 557 depth = 28; 558 next_hop = 1; 559 status = rte_fib_add(g_fib, g_ip, depth, next_hop); 560 if (status != 0) { 561 printf("%s: Failed to add rule\n", __func__); 562 goto error; 563 } 564 565 /* Writer update */ 566 for (i = 0; i < WRITER_ITERATIONS; i++) { 567 status = rte_fib_delete(g_fib, g_ip, depth); 568 if (status != 0) { 569 printf("%s: Failed to delete rule at iteration %d\n", __func__, i); 570 goto error; 571 } 572 573 status = rte_fib_add(g_fib, g_ip, depth, next_hop); 574 if (status != 0) { 575 printf("%s: Failed to add rule at iteration %d\n", __func__, i); 576 goto error; 577 } 578 } 579 580 error: 581 writer_done = 1; 582 /* Wait until reader exited. */ 583 rte_eal_mp_wait_lcore(); 584 585 rte_fib_free(g_fib); 586 rte_free(g_v); 587 588 return status == 0 ? TEST_SUCCESS : TEST_FAILED; 589 } 590 591 static struct unit_test_suite fib_fast_tests = { 592 .suite_name = "fib autotest", 593 .setup = NULL, 594 .teardown = NULL, 595 .unit_test_cases = { 596 TEST_CASE(test_create_invalid), 597 TEST_CASE(test_free_null), 598 TEST_CASE(test_add_del_invalid), 599 TEST_CASE(test_get_invalid), 600 TEST_CASE(test_lookup), 601 TEST_CASE(test_invalid_rcu), 602 TEST_CASE(test_fib_rcu_sync_rw), 603 TEST_CASES_END() 604 } 605 }; 606 607 static struct unit_test_suite fib_slow_tests = { 608 .suite_name = "fib slow autotest", 609 .setup = NULL, 610 .teardown = NULL, 611 .unit_test_cases = { 612 TEST_CASE(test_multiple_create), 613 TEST_CASES_END() 614 } 615 }; 616 617 /* 618 * Do all unit tests. 619 */ 620 static int 621 test_fib(void) 622 { 623 return unit_test_suite_runner(&fib_fast_tests); 624 } 625 626 static int 627 test_slow_fib(void) 628 { 629 return unit_test_suite_runner(&fib_slow_tests); 630 } 631 632 REGISTER_FAST_TEST(fib_autotest, true, true, test_fib); 633 REGISTER_PERF_TEST(fib_slow_autotest, test_slow_fib); 634