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_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 struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC; 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_IPV6_MAX_DEPTH */ 174 ret = rte_fib6_add(fib, &ip, RTE_IPV6_MAX_DEPTH + 1, nh); 175 RTE_TEST_ASSERT(ret < 0, 176 "Call succeeded with invalid parameters\n"); 177 178 /* rte_fib6_delete: depth > RTE_IPV6_MAX_DEPTH */ 179 ret = rte_fib6_delete(fib, &ip, RTE_IPV6_MAX_DEPTH + 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 struct rte_ipv6_addr *ip_arr, 216 struct rte_ipv6_addr *ip_missing, uint64_t def_nh, 217 uint32_t n) 218 { 219 uint64_t nh_arr[RTE_IPV6_MAX_DEPTH]; 220 int ret; 221 uint32_t i = 0; 222 223 ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_IPV6_MAX_DEPTH); 224 RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n"); 225 226 for (; i <= RTE_IPV6_MAX_DEPTH - n; i++) 227 RTE_TEST_ASSERT(nh_arr[i] == n, 228 "Failed to get proper nexthop\n"); 229 230 for (; i < RTE_IPV6_MAX_DEPTH; 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 struct rte_ipv6_addr *ip_arr, 244 struct rte_ipv6_addr *ip_missing, uint64_t def_nh, 245 uint32_t n) 246 { 247 uint64_t nh_arr[RTE_IPV6_MAX_DEPTH]; 248 int ret; 249 uint32_t i = 0; 250 251 ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_IPV6_MAX_DEPTH); 252 RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n"); 253 254 for (; i < n; i++) 255 RTE_TEST_ASSERT(nh_arr[i] == RTE_IPV6_MAX_DEPTH - i, 256 "Failed to get proper nexthop\n"); 257 258 for (; i < RTE_IPV6_MAX_DEPTH; 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 struct rte_ipv6_addr ip_arr[RTE_IPV6_MAX_DEPTH]; 274 struct rte_ipv6_addr ip_add = RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0); 275 struct rte_ipv6_addr ip_missing = 276 RTE_IPV6(0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff); 277 uint32_t i, j; 278 int ret; 279 280 for (i = 0; i < RTE_IPV6_MAX_DEPTH; i++) { 281 ip_arr[i] = ip_add; 282 j = (RTE_IPV6_MAX_DEPTH - i) / CHAR_BIT; 283 if (j < RTE_IPV6_ADDR_SIZE) { 284 ip_arr[i].a[j] |= UINT8_MAX >> ((RTE_IPV6_MAX_DEPTH - i) % CHAR_BIT); 285 for (j++; j < RTE_IPV6_ADDR_SIZE; j++) 286 ip_arr[i].a[j] = 0xff; 287 } 288 } 289 290 ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh, 0); 291 RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n"); 292 293 for (i = 1; i <= RTE_IPV6_MAX_DEPTH; i++) { 294 ret = rte_fib6_add(fib, &ip_add, i, i); 295 RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n"); 296 ret = lookup_and_check_asc(fib, ip_arr, &ip_missing, def_nh, i); 297 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 298 "Lookup and check fails\n"); 299 } 300 301 for (i = RTE_IPV6_MAX_DEPTH; i > 1; i--) { 302 ret = rte_fib6_delete(fib, &ip_add, i); 303 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n"); 304 ret = lookup_and_check_asc(fib, ip_arr, &ip_missing, 305 def_nh, i - 1); 306 307 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 308 "Lookup and check fails\n"); 309 } 310 ret = rte_fib6_delete(fib, &ip_add, i); 311 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n"); 312 ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh, 0); 313 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 314 "Lookup and check fails\n"); 315 316 for (i = 0; i < RTE_IPV6_MAX_DEPTH; i++) { 317 ret = rte_fib6_add(fib, &ip_add, RTE_IPV6_MAX_DEPTH - i, 318 RTE_IPV6_MAX_DEPTH - 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, 323 "Lookup and check fails\n"); 324 } 325 326 for (i = 1; i <= RTE_IPV6_MAX_DEPTH; i++) { 327 ret = rte_fib6_delete(fib, &ip_add, i); 328 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n"); 329 ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh, 330 RTE_IPV6_MAX_DEPTH - i); 331 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 332 "Lookup and check fails\n"); 333 } 334 335 return TEST_SUCCESS; 336 } 337 338 int32_t 339 test_lookup(void) 340 { 341 struct rte_fib6 *fib = NULL; 342 struct rte_fib6_conf config; 343 uint64_t def_nh = 100; 344 int ret; 345 346 config.max_routes = MAX_ROUTES; 347 config.rib_ext_sz = 0; 348 config.default_nh = def_nh; 349 config.type = RTE_FIB6_DUMMY; 350 351 fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config); 352 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 353 ret = check_fib(fib); 354 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 355 "Check_fib fails for DUMMY type\n"); 356 rte_fib6_free(fib); 357 358 config.type = RTE_FIB6_TRIE; 359 360 config.trie.nh_sz = RTE_FIB6_TRIE_2B; 361 config.trie.num_tbl8 = MAX_TBL8 - 1; 362 fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config); 363 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 364 ret = check_fib(fib); 365 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 366 "Check_fib fails for TRIE_2B type\n"); 367 rte_fib6_free(fib); 368 369 config.trie.nh_sz = RTE_FIB6_TRIE_4B; 370 config.trie.num_tbl8 = MAX_TBL8; 371 fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config); 372 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 373 ret = check_fib(fib); 374 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 375 "Check_fib fails for TRIE_4B type\n"); 376 rte_fib6_free(fib); 377 378 config.trie.nh_sz = RTE_FIB6_TRIE_8B; 379 config.trie.num_tbl8 = MAX_TBL8; 380 fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config); 381 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); 382 ret = check_fib(fib); 383 RTE_TEST_ASSERT(ret == TEST_SUCCESS, 384 "Check_fib fails for TRIE_8B type\n"); 385 rte_fib6_free(fib); 386 387 return TEST_SUCCESS; 388 } 389 390 static struct unit_test_suite fib6_fast_tests = { 391 .suite_name = "fib6 autotest", 392 .setup = NULL, 393 .teardown = NULL, 394 .unit_test_cases = { 395 TEST_CASE(test_create_invalid), 396 TEST_CASE(test_free_null), 397 TEST_CASE(test_add_del_invalid), 398 TEST_CASE(test_get_invalid), 399 TEST_CASE(test_lookup), 400 TEST_CASES_END() 401 } 402 }; 403 404 static struct unit_test_suite fib6_slow_tests = { 405 .suite_name = "fib6 slow autotest", 406 .setup = NULL, 407 .teardown = NULL, 408 .unit_test_cases = { 409 TEST_CASE(test_multiple_create), 410 TEST_CASES_END() 411 } 412 }; 413 414 /* 415 * Do all unit tests. 416 */ 417 static int 418 test_fib6(void) 419 { 420 return unit_test_suite_runner(&fib6_fast_tests); 421 } 422 423 static int 424 test_slow_fib6(void) 425 { 426 return unit_test_suite_runner(&fib6_slow_tests); 427 } 428 429 REGISTER_FAST_TEST(fib6_autotest, true, true, test_fib6); 430 REGISTER_PERF_TEST(fib6_slow_autotest, test_slow_fib6); 431