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