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