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