1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018 Vladimir Medvedkin <[email protected]> 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 13 #include "test.h" 14 15 #ifdef RTE_EXEC_ENV_WINDOWS 16 static int 17 test_fib(void) 18 { 19 printf("fib not supported on Windows, skipping test\n"); 20 return TEST_SKIPPED; 21 } 22 23 static int 24 test_slow_fib(void) 25 { 26 printf("slow_fib not supported on Windows, skipping test\n"); 27 return TEST_SKIPPED; 28 } 29 30 #else 31 32 #include <rte_fib.h> 33 34 typedef int32_t (*rte_fib_test)(void); 35 36 static int32_t test_create_invalid(void); 37 static int32_t test_multiple_create(void); 38 static int32_t test_free_null(void); 39 static int32_t test_add_del_invalid(void); 40 static int32_t test_get_invalid(void); 41 static int32_t test_lookup(void); 42 43 #define MAX_ROUTES (1 << 16) 44 #define MAX_TBL8 (1 << 15) 45 46 /* 47 * Check that rte_fib_create fails gracefully for incorrect user input 48 * arguments 49 */ 50 int32_t 51 test_create_invalid(void) 52 { 53 struct rte_fib *fib = NULL; 54 struct rte_fib_conf config; 55 56 config.max_routes = MAX_ROUTES; 57 config.rib_ext_sz = 0; 58 config.default_nh = 0; 59 config.type = RTE_FIB_DUMMY; 60 61 /* rte_fib_create: fib name == NULL */ 62 fib = rte_fib_create(NULL, SOCKET_ID_ANY, &config); 63 RTE_TEST_ASSERT(fib == NULL, 64 "Call succeeded with invalid parameters\n"); 65 66 /* rte_fib_create: config == NULL */ 67 fib = rte_fib_create(__func__, SOCKET_ID_ANY, NULL); 68 RTE_TEST_ASSERT(fib == NULL, 69 "Call succeeded with invalid parameters\n"); 70 71 /* socket_id < -1 is invalid */ 72 fib = rte_fib_create(__func__, -2, &config); 73 RTE_TEST_ASSERT(fib == NULL, 74 "Call succeeded with invalid parameters\n"); 75 76 /* rte_fib_create: max_routes = 0 */ 77 config.max_routes = 0; 78 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 79 RTE_TEST_ASSERT(fib == NULL, 80 "Call succeeded with invalid parameters\n"); 81 config.max_routes = MAX_ROUTES; 82 83 config.type = RTE_FIB_DIR24_8 + 1; 84 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 85 RTE_TEST_ASSERT(fib == NULL, 86 "Call succeeded with invalid parameters\n"); 87 88 config.type = RTE_FIB_DIR24_8; 89 config.dir24_8.num_tbl8 = MAX_TBL8; 90 91 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_8B + 1; 92 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 93 RTE_TEST_ASSERT(fib == NULL, 94 "Call succeeded with invalid parameters\n"); 95 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_8B; 96 97 config.dir24_8.num_tbl8 = 0; 98 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 99 RTE_TEST_ASSERT(fib == NULL, 100 "Call succeeded with invalid parameters\n"); 101 102 return TEST_SUCCESS; 103 } 104 105 /* 106 * Create fib table then delete fib table 10 times 107 * Use a slightly different rules size each time 108 */ 109 int32_t 110 test_multiple_create(void) 111 { 112 struct rte_fib *fib = NULL; 113 struct rte_fib_conf config; 114 int32_t i; 115 116 config.rib_ext_sz = 0; 117 config.default_nh = 0; 118 config.type = RTE_FIB_DUMMY; 119 120 for (i = 0; i < 100; i++) { 121 config.max_routes = MAX_ROUTES - i; 122 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 123 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 124 rte_fib_free(fib); 125 } 126 /* Can not test free so return success */ 127 return TEST_SUCCESS; 128 } 129 130 /* 131 * Call rte_fib_free for NULL pointer user input. Note: free has no return and 132 * therefore it is impossible to check for failure but this test is added to 133 * increase function coverage metrics and to validate that freeing null does 134 * not crash. 135 */ 136 int32_t 137 test_free_null(void) 138 { 139 struct rte_fib *fib = NULL; 140 struct rte_fib_conf config; 141 142 config.max_routes = MAX_ROUTES; 143 config.rib_ext_sz = 0; 144 config.default_nh = 0; 145 config.type = RTE_FIB_DUMMY; 146 147 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 148 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 149 150 rte_fib_free(fib); 151 rte_fib_free(NULL); 152 return TEST_SUCCESS; 153 } 154 155 /* 156 * Check that rte_fib_add and rte_fib_delete fails gracefully 157 * for incorrect user input arguments 158 */ 159 int32_t 160 test_add_del_invalid(void) 161 { 162 struct rte_fib *fib = NULL; 163 struct rte_fib_conf config; 164 uint64_t nh = 100; 165 uint32_t ip = RTE_IPV4(0, 0, 0, 0); 166 int ret; 167 uint8_t depth = 24; 168 169 config.max_routes = MAX_ROUTES; 170 config.rib_ext_sz = 0; 171 config.default_nh = 0; 172 config.type = RTE_FIB_DUMMY; 173 174 /* rte_fib_add: fib == NULL */ 175 ret = rte_fib_add(NULL, ip, depth, nh); 176 RTE_TEST_ASSERT(ret < 0, 177 "Call succeeded with invalid parameters\n"); 178 179 /* rte_fib_delete: fib == NULL */ 180 ret = rte_fib_delete(NULL, ip, depth); 181 RTE_TEST_ASSERT(ret < 0, 182 "Call succeeded with invalid parameters\n"); 183 184 /*Create valid fib to use in rest of test. */ 185 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 186 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 187 188 /* rte_fib_add: depth > RTE_FIB_MAXDEPTH */ 189 ret = rte_fib_add(fib, ip, RTE_FIB_MAXDEPTH + 1, nh); 190 RTE_TEST_ASSERT(ret < 0, 191 "Call succeeded with invalid parameters\n"); 192 193 /* rte_fib_delete: depth > RTE_FIB_MAXDEPTH */ 194 ret = rte_fib_delete(fib, ip, RTE_FIB_MAXDEPTH + 1); 195 RTE_TEST_ASSERT(ret < 0, 196 "Call succeeded with invalid parameters\n"); 197 198 rte_fib_free(fib); 199 200 return TEST_SUCCESS; 201 } 202 203 /* 204 * Check that rte_fib_get_dp and rte_fib_get_rib fails gracefully 205 * for incorrect user input arguments 206 */ 207 int32_t 208 test_get_invalid(void) 209 { 210 void *p; 211 212 p = rte_fib_get_dp(NULL); 213 RTE_TEST_ASSERT(p == NULL, 214 "Call succeeded with invalid parameters\n"); 215 216 p = rte_fib_get_rib(NULL); 217 RTE_TEST_ASSERT(p == NULL, 218 "Call succeeded with invalid parameters\n"); 219 220 return TEST_SUCCESS; 221 } 222 223 /* 224 * Add routes for one supernet with all possible depths and do lookup 225 * on each step 226 * After delete routes with doing lookup on each step 227 */ 228 static int 229 lookup_and_check_asc(struct rte_fib *fib, uint32_t ip_arr[RTE_FIB_MAXDEPTH], 230 uint32_t ip_missing, uint64_t def_nh, uint32_t n) 231 { 232 uint64_t nh_arr[RTE_FIB_MAXDEPTH]; 233 int ret; 234 uint32_t i = 0; 235 236 ret = rte_fib_lookup_bulk(fib, ip_arr, nh_arr, RTE_FIB_MAXDEPTH); 237 RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n"); 238 239 for (; i <= RTE_FIB_MAXDEPTH - n; i++) 240 RTE_TEST_ASSERT(nh_arr[i] == n, 241 "Failed to get proper nexthop\n"); 242 243 for (; i < RTE_FIB_MAXDEPTH; i++) 244 RTE_TEST_ASSERT(nh_arr[i] == --n, 245 "Failed to get proper nexthop\n"); 246 247 ret = rte_fib_lookup_bulk(fib, &ip_missing, nh_arr, 1); 248 RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh), 249 "Failed to get proper nexthop\n"); 250 251 return TEST_SUCCESS; 252 } 253 254 static int 255 lookup_and_check_desc(struct rte_fib *fib, uint32_t ip_arr[RTE_FIB_MAXDEPTH], 256 uint32_t ip_missing, uint64_t def_nh, uint32_t n) 257 { 258 uint64_t nh_arr[RTE_FIB_MAXDEPTH]; 259 int ret; 260 uint32_t i = 0; 261 262 ret = rte_fib_lookup_bulk(fib, ip_arr, nh_arr, RTE_FIB_MAXDEPTH); 263 RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n"); 264 265 for (; i < n; i++) 266 RTE_TEST_ASSERT(nh_arr[i] == RTE_FIB_MAXDEPTH - i, 267 "Failed to get proper nexthop\n"); 268 269 for (; i < RTE_FIB_MAXDEPTH; i++) 270 RTE_TEST_ASSERT(nh_arr[i] == def_nh, 271 "Failed to get proper nexthop\n"); 272 273 ret = rte_fib_lookup_bulk(fib, &ip_missing, nh_arr, 1); 274 RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh), 275 "Failed to get proper nexthop\n"); 276 277 return TEST_SUCCESS; 278 } 279 280 static int 281 check_fib(struct rte_fib *fib) 282 { 283 uint64_t def_nh = 100; 284 uint32_t ip_arr[RTE_FIB_MAXDEPTH]; 285 uint32_t ip_add = RTE_IPV4(128, 0, 0, 0); 286 uint32_t i, ip_missing = RTE_IPV4(127, 255, 255, 255); 287 int ret; 288 289 for (i = 0; i < RTE_FIB_MAXDEPTH; i++) 290 ip_arr[i] = ip_add + (1ULL << i) - 1; 291 292 ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 0); 293 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 294 295 for (i = 1; i <= RTE_FIB_MAXDEPTH; i++) { 296 ret = rte_fib_add(fib, ip_add, i, i); 297 RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n"); 298 ret = lookup_and_check_asc(fib, ip_arr, ip_missing, 299 def_nh, i); 300 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 301 } 302 303 for (i = RTE_FIB_MAXDEPTH; i > 1; i--) { 304 ret = rte_fib_delete(fib, ip_add, i); 305 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n"); 306 ret = lookup_and_check_asc(fib, ip_arr, ip_missing, 307 def_nh, i - 1); 308 309 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 310 } 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, 0); 314 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 315 316 for (i = 0; i < RTE_FIB_MAXDEPTH; i++) { 317 ret = rte_fib_add(fib, ip_add, RTE_FIB_MAXDEPTH - i, 318 RTE_FIB_MAXDEPTH - i); 319 RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n"); 320 ret = lookup_and_check_desc(fib, ip_arr, ip_missing, 321 def_nh, i + 1); 322 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 323 } 324 325 for (i = 1; i <= RTE_FIB_MAXDEPTH; i++) { 326 ret = rte_fib_delete(fib, ip_add, i); 327 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n"); 328 ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 329 RTE_FIB_MAXDEPTH - i); 330 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 331 } 332 333 return TEST_SUCCESS; 334 } 335 336 int32_t 337 test_lookup(void) 338 { 339 struct rte_fib *fib = NULL; 340 struct rte_fib_conf config; 341 uint64_t def_nh = 100; 342 int ret; 343 344 config.max_routes = MAX_ROUTES; 345 config.rib_ext_sz = 0; 346 config.default_nh = def_nh; 347 config.type = RTE_FIB_DUMMY; 348 349 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 350 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 351 ret = check_fib(fib); 352 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 353 "Check_fib fails for DUMMY type\n"); 354 rte_fib_free(fib); 355 356 config.type = RTE_FIB_DIR24_8; 357 358 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_1B; 359 config.dir24_8.num_tbl8 = 127; 360 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 361 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 362 ret = check_fib(fib); 363 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 364 "Check_fib fails for DIR24_8_1B type\n"); 365 rte_fib_free(fib); 366 367 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_2B; 368 config.dir24_8.num_tbl8 = MAX_TBL8 - 1; 369 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 370 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 371 ret = check_fib(fib); 372 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 373 "Check_fib fails for DIR24_8_2B type\n"); 374 rte_fib_free(fib); 375 376 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B; 377 config.dir24_8.num_tbl8 = MAX_TBL8; 378 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 379 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 380 ret = check_fib(fib); 381 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 382 "Check_fib fails for DIR24_8_4B type\n"); 383 rte_fib_free(fib); 384 385 config.dir24_8.nh_sz = RTE_FIB_DIR24_8_8B; 386 config.dir24_8.num_tbl8 = MAX_TBL8; 387 fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config); 388 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 389 ret = check_fib(fib); 390 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 391 "Check_fib fails for DIR24_8_8B type\n"); 392 rte_fib_free(fib); 393 394 return TEST_SUCCESS; 395 } 396 397 static struct unit_test_suite fib_fast_tests = { 398 .suite_name = "fib autotest", 399 .setup = NULL, 400 .teardown = NULL, 401 .unit_test_cases = { 402 TEST_CASE(test_create_invalid), 403 TEST_CASE(test_free_null), 404 TEST_CASE(test_add_del_invalid), 405 TEST_CASE(test_get_invalid), 406 TEST_CASE(test_lookup), 407 TEST_CASES_END() 408 } 409 }; 410 411 static struct unit_test_suite fib_slow_tests = { 412 .suite_name = "fib slow autotest", 413 .setup = NULL, 414 .teardown = NULL, 415 .unit_test_cases = { 416 TEST_CASE(test_multiple_create), 417 TEST_CASES_END() 418 } 419 }; 420 421 /* 422 * Do all unit tests. 423 */ 424 static int 425 test_fib(void) 426 { 427 return unit_test_suite_runner(&fib_fast_tests); 428 } 429 430 static int 431 test_slow_fib(void) 432 { 433 return unit_test_suite_runner(&fib_slow_tests); 434 } 435 436 #endif /* !RTE_EXEC_ENV_WINDOWS */ 437 438 REGISTER_TEST_COMMAND(fib_autotest, test_fib); 439 REGISTER_TEST_COMMAND(fib_slow_autotest, test_slow_fib); 440