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 "test.h" 7 8 #include <stdio.h> 9 #include <stdint.h> 10 #include <stdlib.h> 11 12 #include <rte_ip.h> 13 14 #ifdef RTE_EXEC_ENV_WINDOWS 15 static int 16 test_rib(void) 17 { 18 printf("rib not supported on Windows, skipping test\n"); 19 return TEST_SKIPPED; 20 } 21 22 static int 23 test_slow_rib(void) 24 { 25 printf("slow_rib not supported on Windows, skipping test\n"); 26 return TEST_SKIPPED; 27 } 28 #else 29 30 #include <rte_rib.h> 31 32 typedef int32_t (*rte_rib_test)(void); 33 34 static int32_t test_create_invalid(void); 35 static int32_t test_multiple_create(void); 36 static int32_t test_free_null(void); 37 static int32_t test_insert_invalid(void); 38 static int32_t test_get_fn(void); 39 static int32_t test_basic(void); 40 static int32_t test_tree_traversal(void); 41 42 #define MAX_DEPTH 32 43 #define MAX_RULES (1 << 22) 44 45 /* 46 * Check that rte_rib_create fails gracefully for incorrect user input 47 * arguments 48 */ 49 int32_t 50 test_create_invalid(void) 51 { 52 struct rte_rib *rib = NULL; 53 struct rte_rib_conf config; 54 55 config.max_nodes = MAX_RULES; 56 config.ext_sz = 0; 57 58 /* rte_rib_create: rib name == NULL */ 59 rib = rte_rib_create(NULL, SOCKET_ID_ANY, &config); 60 RTE_TEST_ASSERT(rib == NULL, 61 "Call succeeded with invalid parameters\n"); 62 63 /* rte_rib_create: config == NULL */ 64 rib = rte_rib_create(__func__, SOCKET_ID_ANY, NULL); 65 RTE_TEST_ASSERT(rib == NULL, 66 "Call succeeded with invalid parameters\n"); 67 68 /* socket_id < -1 is invalid */ 69 rib = rte_rib_create(__func__, -2, &config); 70 RTE_TEST_ASSERT(rib == NULL, 71 "Call succeeded with invalid parameters\n"); 72 73 /* rte_rib_create: max_nodes = 0 */ 74 config.max_nodes = 0; 75 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config); 76 RTE_TEST_ASSERT(rib == NULL, 77 "Call succeeded with invalid parameters\n"); 78 config.max_nodes = MAX_RULES; 79 80 return TEST_SUCCESS; 81 } 82 83 /* 84 * Create rib table then delete rib table 10 times 85 * Use a slightly different rules size each time 86 */ 87 int32_t 88 test_multiple_create(void) 89 { 90 struct rte_rib *rib = NULL; 91 struct rte_rib_conf config; 92 int32_t i; 93 94 config.ext_sz = 0; 95 96 for (i = 0; i < 100; i++) { 97 config.max_nodes = MAX_RULES - i; 98 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config); 99 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n"); 100 rte_rib_free(rib); 101 } 102 /* Can not test free so return success */ 103 return TEST_SUCCESS; 104 } 105 106 /* 107 * Call rte_rib_free for NULL pointer user input. Note: free has no return and 108 * therefore it is impossible to check for failure but this test is added to 109 * increase function coverage metrics and to validate that freeing null does 110 * not crash. 111 */ 112 int32_t 113 test_free_null(void) 114 { 115 struct rte_rib *rib = NULL; 116 struct rte_rib_conf config; 117 118 config.max_nodes = MAX_RULES; 119 config.ext_sz = 0; 120 121 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config); 122 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n"); 123 124 rte_rib_free(rib); 125 rte_rib_free(NULL); 126 return TEST_SUCCESS; 127 } 128 129 /* 130 * Check that rte_rib_insert fails gracefully for incorrect user input arguments 131 */ 132 int32_t 133 test_insert_invalid(void) 134 { 135 struct rte_rib *rib = NULL; 136 struct rte_rib_node *node, *node1; 137 struct rte_rib_conf config; 138 uint32_t ip = RTE_IPV4(0, 0, 0, 0); 139 uint8_t depth = 24; 140 141 config.max_nodes = MAX_RULES; 142 config.ext_sz = 0; 143 144 /* rte_rib_insert: rib == NULL */ 145 node = rte_rib_insert(NULL, ip, depth); 146 RTE_TEST_ASSERT(node == NULL, 147 "Call succeeded with invalid parameters\n"); 148 149 /*Create valid rib to use in rest of test. */ 150 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config); 151 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n"); 152 153 /* rte_rib_insert: depth > MAX_DEPTH */ 154 node = rte_rib_insert(rib, ip, MAX_DEPTH + 1); 155 RTE_TEST_ASSERT(node == NULL, 156 "Call succeeded with invalid parameters\n"); 157 158 /* insert the same ip/depth twice*/ 159 node = rte_rib_insert(rib, ip, depth); 160 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n"); 161 node1 = rte_rib_insert(rib, ip, depth); 162 RTE_TEST_ASSERT(node1 == NULL, 163 "Call succeeded with invalid parameters\n"); 164 165 rte_rib_free(rib); 166 167 return TEST_SUCCESS; 168 } 169 170 /* 171 * Call rte_rib_node access functions with incorrect input. 172 * After call rte_rib_node access functions with correct args 173 * and check the return values for correctness 174 */ 175 int32_t 176 test_get_fn(void) 177 { 178 struct rte_rib *rib = NULL; 179 struct rte_rib_node *node; 180 struct rte_rib_conf config; 181 void *ext; 182 uint32_t ip = RTE_IPV4(192, 0, 2, 0); 183 uint32_t ip_ret; 184 uint64_t nh_set = 10; 185 uint64_t nh_ret; 186 uint8_t depth = 24; 187 uint8_t depth_ret; 188 int ret; 189 190 config.max_nodes = MAX_RULES; 191 config.ext_sz = 0; 192 193 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config); 194 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n"); 195 196 node = rte_rib_insert(rib, ip, depth); 197 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n"); 198 199 /* test rte_rib_get_ip() with incorrect args */ 200 ret = rte_rib_get_ip(NULL, &ip_ret); 201 RTE_TEST_ASSERT(ret < 0, 202 "Call succeeded with invalid parameters\n"); 203 ret = rte_rib_get_ip(node, NULL); 204 RTE_TEST_ASSERT(ret < 0, 205 "Call succeeded with invalid parameters\n"); 206 207 /* test rte_rib_get_depth() with incorrect args */ 208 ret = rte_rib_get_depth(NULL, &depth_ret); 209 RTE_TEST_ASSERT(ret < 0, 210 "Call succeeded with invalid parameters\n"); 211 ret = rte_rib_get_depth(node, NULL); 212 RTE_TEST_ASSERT(ret < 0, 213 "Call succeeded with invalid parameters\n"); 214 215 /* test rte_rib_set_nh() with incorrect args */ 216 ret = rte_rib_set_nh(NULL, nh_set); 217 RTE_TEST_ASSERT(ret < 0, 218 "Call succeeded with invalid parameters\n"); 219 220 /* test rte_rib_get_nh() with incorrect args */ 221 ret = rte_rib_get_nh(NULL, &nh_ret); 222 RTE_TEST_ASSERT(ret < 0, 223 "Call succeeded with invalid parameters\n"); 224 ret = rte_rib_get_nh(node, NULL); 225 RTE_TEST_ASSERT(ret < 0, 226 "Call succeeded with invalid parameters\n"); 227 228 /* test rte_rib_get_ext() with incorrect args */ 229 ext = rte_rib_get_ext(NULL); 230 RTE_TEST_ASSERT(ext == NULL, 231 "Call succeeded with invalid parameters\n"); 232 233 /* check the return values */ 234 ret = rte_rib_get_ip(node, &ip_ret); 235 RTE_TEST_ASSERT((ret == 0) && (ip_ret == ip), 236 "Failed to get proper node ip\n"); 237 ret = rte_rib_get_depth(node, &depth_ret); 238 RTE_TEST_ASSERT((ret == 0) && (depth_ret == depth), 239 "Failed to get proper node depth\n"); 240 ret = rte_rib_set_nh(node, nh_set); 241 RTE_TEST_ASSERT(ret == 0, 242 "Failed to set rte_rib_node nexthop\n"); 243 ret = rte_rib_get_nh(node, &nh_ret); 244 RTE_TEST_ASSERT((ret == 0) && (nh_ret == nh_set), 245 "Failed to get proper nexthop\n"); 246 247 rte_rib_free(rib); 248 249 return TEST_SUCCESS; 250 } 251 252 /* 253 * Call insert, lookup/lookup_exact and delete for a single rule 254 */ 255 int32_t 256 test_basic(void) 257 { 258 struct rte_rib *rib = NULL; 259 struct rte_rib_node *node; 260 struct rte_rib_conf config; 261 262 uint32_t ip = RTE_IPV4(192, 0, 2, 0); 263 uint64_t next_hop_add = 10; 264 uint64_t next_hop_return; 265 uint8_t depth = 24; 266 int ret; 267 268 config.max_nodes = MAX_RULES; 269 config.ext_sz = 0; 270 271 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config); 272 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n"); 273 274 node = rte_rib_insert(rib, ip, depth); 275 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n"); 276 277 ret = rte_rib_set_nh(node, next_hop_add); 278 RTE_TEST_ASSERT(ret == 0, 279 "Failed to set rte_rib_node field\n"); 280 281 node = rte_rib_lookup(rib, ip); 282 RTE_TEST_ASSERT(node != NULL, "Failed to lookup\n"); 283 284 ret = rte_rib_get_nh(node, &next_hop_return); 285 RTE_TEST_ASSERT((ret == 0) && (next_hop_add == next_hop_return), 286 "Failed to get proper nexthop\n"); 287 288 node = rte_rib_lookup_exact(rib, ip, depth); 289 RTE_TEST_ASSERT(node != NULL, 290 "Failed to lookup\n"); 291 292 ret = rte_rib_get_nh(node, &next_hop_return); 293 RTE_TEST_ASSERT((ret == 0) && (next_hop_add == next_hop_return), 294 "Failed to get proper nexthop\n"); 295 296 rte_rib_remove(rib, ip, depth); 297 298 node = rte_rib_lookup(rib, ip); 299 RTE_TEST_ASSERT(node == NULL, 300 "Lookup returns non existent rule\n"); 301 node = rte_rib_lookup_exact(rib, ip, depth); 302 RTE_TEST_ASSERT(node == NULL, 303 "Lookup returns non existent rule\n"); 304 305 rte_rib_free(rib); 306 307 return TEST_SUCCESS; 308 } 309 310 int32_t 311 test_tree_traversal(void) 312 { 313 struct rte_rib *rib = NULL; 314 struct rte_rib_node *node; 315 struct rte_rib_conf config; 316 317 uint32_t ip1 = RTE_IPV4(10, 10, 10, 0); 318 uint32_t ip2 = RTE_IPV4(10, 10, 130, 80); 319 uint8_t depth = 30; 320 321 config.max_nodes = MAX_RULES; 322 config.ext_sz = 0; 323 324 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config); 325 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n"); 326 327 node = rte_rib_insert(rib, ip1, depth); 328 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n"); 329 330 node = rte_rib_insert(rib, ip2, depth); 331 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n"); 332 333 node = NULL; 334 node = rte_rib_get_nxt(rib, RTE_IPV4(10, 10, 130, 0), 24, node, 335 RTE_RIB_GET_NXT_ALL); 336 RTE_TEST_ASSERT(node != NULL, "Failed to get rib_node\n"); 337 338 rte_rib_free(rib); 339 340 return TEST_SUCCESS; 341 } 342 343 static struct unit_test_suite rib_tests = { 344 .suite_name = "rib autotest", 345 .setup = NULL, 346 .teardown = NULL, 347 .unit_test_cases = { 348 TEST_CASE(test_create_invalid), 349 TEST_CASE(test_free_null), 350 TEST_CASE(test_insert_invalid), 351 TEST_CASE(test_get_fn), 352 TEST_CASE(test_basic), 353 TEST_CASE(test_tree_traversal), 354 TEST_CASES_END() 355 } 356 }; 357 358 static struct unit_test_suite rib_slow_tests = { 359 .suite_name = "rib slow autotest", 360 .setup = NULL, 361 .teardown = NULL, 362 .unit_test_cases = { 363 TEST_CASE(test_multiple_create), 364 TEST_CASES_END() 365 } 366 }; 367 368 /* 369 * Do all unit tests. 370 */ 371 static int 372 test_rib(void) 373 { 374 return unit_test_suite_runner(&rib_tests); 375 } 376 377 static int 378 test_slow_rib(void) 379 { 380 return unit_test_suite_runner(&rib_slow_tests); 381 } 382 383 #endif /* !RTE_EXEC_ENV_WINDOWS */ 384 385 REGISTER_TEST_COMMAND(rib_autotest, test_rib); 386 REGISTER_TEST_COMMAND(rib_slow_autotest, test_slow_rib); 387