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