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