1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <string.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <stdint.h> 9 #include <inttypes.h> 10 #include <stdarg.h> 11 #include <errno.h> 12 #include <sys/queue.h> 13 14 #include <rte_common.h> 15 #include <rte_log.h> 16 #include <rte_debug.h> 17 #include <rte_memory.h> 18 #include <rte_launch.h> 19 #include <rte_cycles.h> 20 #include <rte_eal.h> 21 #include <rte_per_lcore.h> 22 #include <rte_lcore.h> 23 #include <rte_branch_prediction.h> 24 #include <rte_ring.h> 25 #include <rte_mempool.h> 26 #include <rte_spinlock.h> 27 #include <rte_malloc.h> 28 29 #ifdef RTE_LIB_HASH 30 #include <rte_hash.h> 31 #include <rte_fbk_hash.h> 32 #include <rte_jhash.h> 33 #endif /* RTE_LIB_HASH */ 34 35 #ifdef RTE_LIB_LPM 36 #include <rte_lpm.h> 37 #endif /* RTE_LIB_LPM */ 38 39 #include <rte_string_fns.h> 40 41 #include "test.h" 42 43 typedef int (*case_func_t)(void* arg); 44 typedef void (*case_clean_t)(unsigned lcore_id); 45 46 #define MAX_STRING_SIZE (256) 47 #define MAX_ITER_MULTI (16) 48 #define MAX_ITER_ONCE (4) 49 #define MAX_LPM_ITER_TIMES (6) 50 51 #define MEMPOOL_ELT_SIZE (sizeof(uint32_t)) 52 #define MEMPOOL_SIZE (4) 53 54 #define MAX_LCORES (RTE_MAX_MEMZONE / (MAX_ITER_MULTI * 4U)) 55 56 static uint32_t obj_count; 57 static uint32_t synchro; 58 59 #define WAIT_SYNCHRO_FOR_WORKERS() do { \ 60 if (lcore_self != rte_get_main_lcore()) \ 61 rte_wait_until_equal_32(&synchro, 1, __ATOMIC_RELAXED); \ 62 } while(0) 63 64 /* 65 * rte_eal_init only init once 66 */ 67 static int 68 test_eal_init_once(__rte_unused void *arg) 69 { 70 unsigned lcore_self = rte_lcore_id(); 71 72 WAIT_SYNCHRO_FOR_WORKERS(); 73 74 __atomic_store_n(&obj_count, 1, __ATOMIC_RELAXED); /* silent the check in the caller */ 75 if (rte_eal_init(0, NULL) != -1) 76 return -1; 77 78 return 0; 79 } 80 81 /* 82 * ring create/lookup reentrancy test 83 */ 84 static void 85 ring_clean(unsigned int lcore_id) 86 { 87 struct rte_ring *rp; 88 char ring_name[MAX_STRING_SIZE]; 89 int i; 90 91 rp = rte_ring_lookup("fr_test_once"); 92 rte_ring_free(rp); 93 94 for (i = 0; i < MAX_ITER_MULTI; i++) { 95 snprintf(ring_name, sizeof(ring_name), 96 "fr_test_%d_%d", lcore_id, i); 97 rp = rte_ring_lookup(ring_name); 98 rte_ring_free(rp); 99 } 100 } 101 102 static int 103 ring_create_lookup(__rte_unused void *arg) 104 { 105 unsigned lcore_self = rte_lcore_id(); 106 struct rte_ring * rp; 107 char ring_name[MAX_STRING_SIZE]; 108 int i; 109 110 WAIT_SYNCHRO_FOR_WORKERS(); 111 112 /* create the same ring simultaneously on all threads */ 113 for (i = 0; i < MAX_ITER_ONCE; i++) { 114 rp = rte_ring_create("fr_test_once", 4096, SOCKET_ID_ANY, 0); 115 if (rp != NULL) 116 __atomic_fetch_add(&obj_count, 1, __ATOMIC_RELAXED); 117 } 118 119 /* create/lookup new ring several times */ 120 for (i = 0; i < MAX_ITER_MULTI; i++) { 121 snprintf(ring_name, sizeof(ring_name), "fr_test_%d_%d", lcore_self, i); 122 rp = rte_ring_create(ring_name, 4096, SOCKET_ID_ANY, 0); 123 if (NULL == rp) 124 return -1; 125 if (rte_ring_lookup(ring_name) != rp) 126 return -1; 127 128 /* verify all ring created successful */ 129 if (rte_ring_lookup(ring_name) == NULL) 130 return -1; 131 } 132 133 return 0; 134 } 135 136 static void 137 my_obj_init(struct rte_mempool *mp, __rte_unused void *arg, 138 void *obj, unsigned i) 139 { 140 uint32_t *objnum = obj; 141 memset(obj, 0, mp->elt_size); 142 *objnum = i; 143 } 144 145 static void 146 mempool_clean(unsigned int lcore_id) 147 { 148 struct rte_mempool *mp; 149 char mempool_name[MAX_STRING_SIZE]; 150 int i; 151 152 mp = rte_mempool_lookup("fr_test_once"); 153 rte_mempool_free(mp); 154 155 for (i = 0; i < MAX_ITER_MULTI; i++) { 156 snprintf(mempool_name, sizeof(mempool_name), "fr_test_%d_%d", 157 lcore_id, i); 158 mp = rte_mempool_lookup(mempool_name); 159 rte_mempool_free(mp); 160 } 161 } 162 163 static int 164 mempool_create_lookup(__rte_unused void *arg) 165 { 166 unsigned lcore_self = rte_lcore_id(); 167 struct rte_mempool * mp; 168 char mempool_name[MAX_STRING_SIZE]; 169 int i; 170 171 WAIT_SYNCHRO_FOR_WORKERS(); 172 173 /* create the same mempool simultaneously on all threads */ 174 for (i = 0; i < MAX_ITER_ONCE; i++) { 175 mp = rte_mempool_create("fr_test_once", MEMPOOL_SIZE, 176 MEMPOOL_ELT_SIZE, 0, 0, 177 NULL, NULL, 178 my_obj_init, NULL, 179 SOCKET_ID_ANY, 0); 180 if (mp != NULL) 181 __atomic_fetch_add(&obj_count, 1, __ATOMIC_RELAXED); 182 } 183 184 /* create/lookup new ring several times */ 185 for (i = 0; i < MAX_ITER_MULTI; i++) { 186 snprintf(mempool_name, sizeof(mempool_name), "fr_test_%d_%d", lcore_self, i); 187 mp = rte_mempool_create(mempool_name, MEMPOOL_SIZE, 188 MEMPOOL_ELT_SIZE, 0, 0, 189 NULL, NULL, 190 my_obj_init, NULL, 191 SOCKET_ID_ANY, 0); 192 if (NULL == mp) 193 return -1; 194 if (rte_mempool_lookup(mempool_name) != mp) 195 return -1; 196 197 /* verify all ring created successful */ 198 if (rte_mempool_lookup(mempool_name) == NULL) 199 return -1; 200 } 201 202 return 0; 203 } 204 205 #ifdef RTE_LIB_HASH 206 static void 207 hash_clean(unsigned lcore_id) 208 { 209 char hash_name[MAX_STRING_SIZE]; 210 struct rte_hash *handle; 211 int i; 212 213 handle = rte_hash_find_existing("fr_test_once"); 214 rte_hash_free(handle); 215 216 for (i = 0; i < MAX_ITER_MULTI; i++) { 217 snprintf(hash_name, sizeof(hash_name), "fr_test_%d_%d", lcore_id, i); 218 219 if ((handle = rte_hash_find_existing(hash_name)) != NULL) 220 rte_hash_free(handle); 221 } 222 } 223 224 static int 225 hash_create_free(__rte_unused void *arg) 226 { 227 unsigned lcore_self = rte_lcore_id(); 228 struct rte_hash *handle; 229 char hash_name[MAX_STRING_SIZE]; 230 int i; 231 struct rte_hash_parameters hash_params = { 232 .name = NULL, 233 .entries = 16, 234 .key_len = 4, 235 .hash_func = (rte_hash_function)rte_jhash_32b, 236 .hash_func_init_val = 0, 237 .socket_id = 0, 238 }; 239 240 WAIT_SYNCHRO_FOR_WORKERS(); 241 242 /* create the same hash simultaneously on all threads */ 243 hash_params.name = "fr_test_once"; 244 for (i = 0; i < MAX_ITER_ONCE; i++) { 245 handle = rte_hash_create(&hash_params); 246 if (handle != NULL) 247 __atomic_fetch_add(&obj_count, 1, __ATOMIC_RELAXED); 248 } 249 250 /* create multiple times simultaneously */ 251 for (i = 0; i < MAX_ITER_MULTI; i++) { 252 snprintf(hash_name, sizeof(hash_name), "fr_test_%d_%d", lcore_self, i); 253 hash_params.name = hash_name; 254 255 handle = rte_hash_create(&hash_params); 256 if (NULL == handle) 257 return -1; 258 259 /* verify correct existing and then free all */ 260 if (handle != rte_hash_find_existing(hash_name)) 261 return -1; 262 263 rte_hash_free(handle); 264 265 /* verify free correct */ 266 if (NULL != rte_hash_find_existing(hash_name)) 267 return -1; 268 } 269 270 return 0; 271 } 272 273 static void 274 fbk_clean(unsigned lcore_id) 275 { 276 char fbk_name[MAX_STRING_SIZE]; 277 struct rte_fbk_hash_table *handle; 278 int i; 279 280 handle = rte_fbk_hash_find_existing("fr_test_once"); 281 if (handle != NULL) 282 rte_fbk_hash_free(handle); 283 284 for (i = 0; i < MAX_ITER_MULTI; i++) { 285 snprintf(fbk_name, sizeof(fbk_name), "fr_test_%d_%d", lcore_id, i); 286 287 if ((handle = rte_fbk_hash_find_existing(fbk_name)) != NULL) 288 rte_fbk_hash_free(handle); 289 } 290 } 291 292 static int 293 fbk_create_free(__rte_unused void *arg) 294 { 295 unsigned lcore_self = rte_lcore_id(); 296 struct rte_fbk_hash_table *handle; 297 char fbk_name[MAX_STRING_SIZE]; 298 int i; 299 struct rte_fbk_hash_params fbk_params = { 300 .name = NULL, 301 .entries = 4, 302 .entries_per_bucket = 4, 303 .socket_id = 0, 304 .hash_func = rte_jhash_1word, 305 .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT, 306 }; 307 308 WAIT_SYNCHRO_FOR_WORKERS(); 309 310 /* create the same fbk hash table simultaneously on all threads */ 311 fbk_params.name = "fr_test_once"; 312 for (i = 0; i < MAX_ITER_ONCE; i++) { 313 handle = rte_fbk_hash_create(&fbk_params); 314 if (handle != NULL) 315 __atomic_fetch_add(&obj_count, 1, __ATOMIC_RELAXED); 316 } 317 318 /* create multiple fbk tables simultaneously */ 319 for (i = 0; i < MAX_ITER_MULTI; i++) { 320 snprintf(fbk_name, sizeof(fbk_name), "fr_test_%d_%d", lcore_self, i); 321 fbk_params.name = fbk_name; 322 323 handle = rte_fbk_hash_create(&fbk_params); 324 if (NULL == handle) 325 return -1; 326 327 /* verify correct existing and then free all */ 328 if (handle != rte_fbk_hash_find_existing(fbk_name)) 329 return -1; 330 331 rte_fbk_hash_free(handle); 332 333 /* verify free correct */ 334 if (NULL != rte_fbk_hash_find_existing(fbk_name)) 335 return -1; 336 } 337 338 return 0; 339 } 340 #endif /* RTE_LIB_HASH */ 341 342 #ifdef RTE_LIB_LPM 343 static void 344 lpm_clean(unsigned int lcore_id) 345 { 346 char lpm_name[MAX_STRING_SIZE]; 347 struct rte_lpm *lpm; 348 int i; 349 350 lpm = rte_lpm_find_existing("fr_test_once"); 351 if (lpm != NULL) 352 rte_lpm_free(lpm); 353 354 for (i = 0; i < MAX_LPM_ITER_TIMES; i++) { 355 snprintf(lpm_name, sizeof(lpm_name), "fr_test_%d_%d", lcore_id, i); 356 357 if ((lpm = rte_lpm_find_existing(lpm_name)) != NULL) 358 rte_lpm_free(lpm); 359 } 360 } 361 362 static int 363 lpm_create_free(__rte_unused void *arg) 364 { 365 unsigned lcore_self = rte_lcore_id(); 366 struct rte_lpm *lpm; 367 struct rte_lpm_config config; 368 369 config.max_rules = 4; 370 config.number_tbl8s = 256; 371 config.flags = 0; 372 char lpm_name[MAX_STRING_SIZE]; 373 int i; 374 375 WAIT_SYNCHRO_FOR_WORKERS(); 376 377 /* create the same lpm simultaneously on all threads */ 378 for (i = 0; i < MAX_ITER_ONCE; i++) { 379 lpm = rte_lpm_create("fr_test_once", SOCKET_ID_ANY, &config); 380 if (lpm != NULL) 381 __atomic_fetch_add(&obj_count, 1, __ATOMIC_RELAXED); 382 } 383 384 /* create multiple fbk tables simultaneously */ 385 for (i = 0; i < MAX_LPM_ITER_TIMES; i++) { 386 snprintf(lpm_name, sizeof(lpm_name), "fr_test_%d_%d", lcore_self, i); 387 lpm = rte_lpm_create(lpm_name, SOCKET_ID_ANY, &config); 388 if (NULL == lpm) 389 return -1; 390 391 /* verify correct existing and then free all */ 392 if (lpm != rte_lpm_find_existing(lpm_name)) 393 return -1; 394 395 rte_lpm_free(lpm); 396 397 /* verify free correct */ 398 if (NULL != rte_lpm_find_existing(lpm_name)) 399 return -1; 400 } 401 402 return 0; 403 } 404 #endif /* RTE_LIB_LPM */ 405 406 struct test_case{ 407 case_func_t func; 408 void* arg; 409 case_clean_t clean; 410 char name[MAX_STRING_SIZE]; 411 }; 412 413 /* All test cases in the test suite */ 414 struct test_case test_cases[] = { 415 { test_eal_init_once, NULL, NULL, "eal init once" }, 416 { ring_create_lookup, NULL, ring_clean, "ring create/lookup" }, 417 { mempool_create_lookup, NULL, mempool_clean, 418 "mempool create/lookup" }, 419 #ifdef RTE_LIB_HASH 420 { hash_create_free, NULL, hash_clean, "hash create/free" }, 421 { fbk_create_free, NULL, fbk_clean, "fbk create/free" }, 422 #endif /* RTE_LIB_HASH */ 423 #ifdef RTE_LIB_LPM 424 { lpm_create_free, NULL, lpm_clean, "lpm create/free" }, 425 #endif /* RTE_LIB_LPM */ 426 }; 427 428 /** 429 * launch test case in two separate thread 430 */ 431 static int 432 launch_test(struct test_case *pt_case) 433 { 434 unsigned int lcore_id; 435 unsigned int cores; 436 unsigned int count; 437 int ret = 0; 438 439 if (pt_case->func == NULL) 440 return -1; 441 442 __atomic_store_n(&obj_count, 0, __ATOMIC_RELAXED); 443 __atomic_store_n(&synchro, 0, __ATOMIC_RELAXED); 444 445 cores = RTE_MIN(rte_lcore_count(), MAX_LCORES); 446 RTE_LCORE_FOREACH_WORKER(lcore_id) { 447 if (cores == 1) 448 break; 449 cores--; 450 rte_eal_remote_launch(pt_case->func, pt_case->arg, lcore_id); 451 } 452 453 __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED); 454 455 if (pt_case->func(pt_case->arg) < 0) 456 ret = -1; 457 458 RTE_LCORE_FOREACH_WORKER(lcore_id) { 459 if (rte_eal_wait_lcore(lcore_id) < 0) 460 ret = -1; 461 } 462 463 RTE_LCORE_FOREACH(lcore_id) { 464 if (pt_case->clean != NULL) 465 pt_case->clean(lcore_id); 466 } 467 468 count = __atomic_load_n(&obj_count, __ATOMIC_RELAXED); 469 if (count != 1) { 470 printf("%s: common object allocated %d times (should be 1)\n", 471 pt_case->name, count); 472 ret = -1; 473 } 474 475 return ret; 476 } 477 478 /** 479 * Main entry of func_reentrancy test 480 */ 481 static int 482 test_func_reentrancy(void) 483 { 484 uint32_t case_id; 485 struct test_case *pt_case = NULL; 486 487 if (RTE_EXEC_ENV_IS_WINDOWS) 488 return TEST_SKIPPED; 489 490 if (rte_lcore_count() < 2) { 491 printf("Not enough cores for func_reentrancy_autotest, expecting at least 2\n"); 492 return TEST_SKIPPED; 493 } 494 else if (rte_lcore_count() > MAX_LCORES) 495 printf("Too many lcores, some cores will be disabled\n"); 496 497 for (case_id = 0; case_id < RTE_DIM(test_cases); case_id++) { 498 pt_case = &test_cases[case_id]; 499 if (pt_case->func == NULL) 500 continue; 501 502 if (launch_test(pt_case) < 0) { 503 printf("Func-ReEnt CASE %"PRIu32": %s FAIL\n", case_id, pt_case->name); 504 return -1; 505 } 506 printf("Func-ReEnt CASE %"PRIu32": %s PASS\n", case_id, pt_case->name); 507 } 508 509 return 0; 510 } 511 512 REGISTER_TEST_COMMAND(func_reentrancy_autotest, test_func_reentrancy); 513