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