1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2022, Marvell 3 */ 4 5 #include <getopt.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 9 #include <rte_common.h> 10 #include <rte_cryptodev.h> 11 #include <rte_eal.h> 12 #include <rte_lcore.h> 13 #include <rte_malloc.h> 14 #include <rte_security.h> 15 16 #include <app/test/test_cryptodev.h> 17 #include <app/test/test_cryptodev_security_ipsec.h> 18 #include <app/test/test_cryptodev_security_ipsec_test_vectors.h> 19 20 #define NB_DESC 4096 21 #define DEF_NB_SESSIONS (16 * 10 * 1024) /* 16 * 10K tunnels */ 22 23 struct lcore_conf { 24 struct rte_crypto_sym_xform cipher_xform; 25 struct rte_crypto_sym_xform auth_xform; 26 struct rte_crypto_sym_xform aead_xform; 27 uint8_t dev_id; 28 uint8_t qp_id; 29 struct test_ctx *ctx; 30 }; 31 32 struct test_ctx { 33 struct lcore_conf lconf[RTE_MAX_LCORE]; 34 void *sec_ctx; 35 struct rte_mempool *sess_mp; 36 struct ipsec_test_data *td; 37 int nb_sess; 38 unsigned long td_idx; 39 uint8_t nb_lcores; 40 uint8_t nb_cryptodevs; 41 uint8_t enabled_cdevs[RTE_CRYPTO_MAX_DEVS]; 42 bool is_inbound; 43 }; 44 45 static struct test_ctx ctx; 46 47 static int 48 cryptodev_init(struct test_ctx *ctx, uint8_t nb_lcores) 49 { 50 const char dev_names[][RTE_CRYPTODEV_NAME_MAX_LEN] = { 51 "crypto_cn10k", 52 "crypto_cn9k", 53 "crypto_dpaa_sec", 54 "crypto_dpaa2_sec", 55 }; 56 struct rte_cryptodev_qp_conf qp_conf; 57 struct rte_cryptodev_info dev_info; 58 struct rte_cryptodev_config config; 59 unsigned int j, nb_qp, qps_reqd; 60 uint8_t socket_id; 61 uint32_t dev_cnt; 62 int ret, core_id; 63 void *sec_ctx; 64 uint64_t i; 65 66 i = 0; 67 do { 68 dev_cnt = rte_cryptodev_devices_get(dev_names[i], 69 ctx->enabled_cdevs, 70 RTE_CRYPTO_MAX_DEVS); 71 i++; 72 } while (dev_cnt == 0 && i < RTE_DIM(dev_names)); 73 74 if (dev_cnt == 0) 75 return -1; 76 77 /* Check first device for capabilities */ 78 rte_cryptodev_info_get(0, &dev_info); 79 if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_SECURITY)) { 80 RTE_LOG(ERR, USER1, 81 "Security not supported by the cryptodev\n"); 82 return -1; 83 } 84 85 sec_ctx = rte_cryptodev_get_sec_ctx(0); 86 ctx->sec_ctx = sec_ctx; 87 88 socket_id = rte_socket_id(); 89 qps_reqd = nb_lcores; 90 core_id = 0; 91 i = 0; 92 93 do { 94 rte_cryptodev_info_get(i, &dev_info); 95 qps_reqd = RTE_MIN(dev_info.max_nb_queue_pairs, qps_reqd); 96 97 for (j = 0; j < qps_reqd; j++) { 98 ctx->lconf[core_id].dev_id = i; 99 ctx->lconf[core_id].qp_id = j; 100 ctx->lconf[core_id].ctx = ctx; 101 core_id++; 102 if (core_id == RTE_MAX_LCORE) 103 break; 104 } 105 106 nb_qp = j; 107 108 memset(&config, 0, sizeof(config)); 109 config.nb_queue_pairs = nb_qp; 110 config.socket_id = socket_id; 111 112 ret = rte_cryptodev_configure(i, &config); 113 if (ret < 0) { 114 RTE_LOG(ERR, USER1, 115 "Could not configure cryptodev - %" PRIu64 "\n", 116 i); 117 return -1; 118 } 119 120 memset(&qp_conf, 0, sizeof(qp_conf)); 121 qp_conf.nb_descriptors = NB_DESC; 122 123 for (j = 0; j < nb_qp; j++) { 124 ret = rte_cryptodev_queue_pair_setup(i, j, &qp_conf, 125 socket_id); 126 if (ret < 0) { 127 RTE_LOG(ERR, USER1, 128 "Could not configure queue pair:" 129 " %" PRIu64 " - %d\n", i, j); 130 return -1; 131 } 132 } 133 134 ret = rte_cryptodev_start(i); 135 if (ret < 0) { 136 RTE_LOG(ERR, USER1, "Could not start cryptodev\n"); 137 return -1; 138 } 139 140 i++; 141 qps_reqd -= j; 142 143 } while (i < dev_cnt && core_id < RTE_MAX_LCORE); 144 145 ctx->nb_cryptodevs = i; 146 147 return 0; 148 } 149 150 static int 151 cryptodev_fini(struct test_ctx *ctx) 152 { 153 int i, ret = 0; 154 155 for (i = 0; i < ctx->nb_cryptodevs && 156 i < RTE_CRYPTO_MAX_DEVS; i++) { 157 rte_cryptodev_stop(ctx->enabled_cdevs[i]); 158 ret = rte_cryptodev_close(ctx->enabled_cdevs[i]); 159 if (ret) 160 RTE_LOG(ERR, USER1, 161 "Crypto device close error %d\n", ret); 162 } 163 164 return ret; 165 } 166 167 static int 168 mempool_init(struct test_ctx *ctx, uint8_t nb_lcores) 169 { 170 struct rte_mempool *sess_mpool; 171 unsigned int sec_sess_sz; 172 int nb_sess_total; 173 174 nb_sess_total = ctx->nb_sess + RTE_MEMPOOL_CACHE_MAX_SIZE * nb_lcores; 175 176 sec_sess_sz = rte_security_session_get_size(ctx->sec_ctx); 177 178 sess_mpool = rte_cryptodev_sym_session_pool_create("test_sess_mp", 179 nb_sess_total, sec_sess_sz, RTE_MEMPOOL_CACHE_MAX_SIZE, 180 0, SOCKET_ID_ANY); 181 if (sess_mpool == NULL) { 182 RTE_LOG(ERR, USER1, "Could not create mempool\n"); 183 return -1; 184 } 185 186 ctx->sess_mp = sess_mpool; 187 188 return 0; 189 } 190 191 static int 192 mempool_fini(struct test_ctx *ctx) 193 { 194 rte_mempool_free(ctx->sess_mp); 195 196 return 0; 197 } 198 199 static int 200 sec_conf_init(struct lcore_conf *conf, 201 struct rte_security_session_conf *sess_conf, 202 struct rte_security_ipsec_xform *ipsec_xform, 203 const struct ipsec_test_data *td) 204 { 205 uint16_t v6_src[8] = {0x2607, 0xf8b0, 0x400c, 0x0c03, 0x0000, 0x0000, 206 0x0000, 0x001a}; 207 uint16_t v6_dst[8] = {0x2001, 0x0470, 0xe5bf, 0xdead, 0x4957, 0x2174, 208 0xe82c, 0x4887}; 209 const struct rte_ipv4_hdr *ipv4 = 210 (const struct rte_ipv4_hdr *)td->output_text.data; 211 struct rte_security_capability_idx sec_cap_idx; 212 const struct rte_security_capability *sec_cap; 213 enum rte_security_ipsec_sa_direction dir; 214 uint32_t src, dst; 215 int salt_len; 216 217 /* Copy IPsec xform */ 218 memcpy(ipsec_xform, &td->ipsec_xform, sizeof(*ipsec_xform)); 219 220 dir = ipsec_xform->direction; 221 222 memcpy(&src, &ipv4->src_addr, sizeof(ipv4->src_addr)); 223 memcpy(&dst, &ipv4->dst_addr, sizeof(ipv4->dst_addr)); 224 225 if (td->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) { 226 if (td->ipsec_xform.tunnel.type == 227 RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 228 memcpy(&ipsec_xform->tunnel.ipv4.src_ip, &src, 229 sizeof(src)); 230 memcpy(&ipsec_xform->tunnel.ipv4.dst_ip, &dst, 231 sizeof(dst)); 232 233 } else { 234 memcpy(&ipsec_xform->tunnel.ipv6.src_addr, &v6_src, 235 sizeof(v6_src)); 236 memcpy(&ipsec_xform->tunnel.ipv6.dst_addr, &v6_dst, 237 sizeof(v6_dst)); 238 } 239 } 240 241 sec_cap_idx.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL; 242 sec_cap_idx.protocol = RTE_SECURITY_PROTOCOL_IPSEC; 243 sec_cap_idx.ipsec.proto = ipsec_xform->proto; 244 sec_cap_idx.ipsec.mode = ipsec_xform->mode; 245 sec_cap_idx.ipsec.direction = ipsec_xform->direction; 246 247 sec_cap = rte_security_capability_get(conf->ctx->sec_ctx, &sec_cap_idx); 248 if (sec_cap == NULL) { 249 RTE_LOG(ERR, USER1, "Could not get capabilities\n"); 250 return -1; 251 } 252 253 /* Copy cipher session parameters */ 254 if (td[0].aead) { 255 memcpy(&conf->aead_xform, &td[0].xform.aead, 256 sizeof(conf->aead_xform)); 257 conf->aead_xform.aead.key.data = td[0].key.data; 258 conf->aead_xform.aead.iv.offset = IV_OFFSET; 259 260 /* Verify crypto capabilities */ 261 if (test_ipsec_crypto_caps_aead_verify( 262 sec_cap, 263 &conf->aead_xform) != 0) { 264 RTE_LOG(ERR, USER1, 265 "Crypto capabilities not supported\n"); 266 return -1; 267 } 268 } else if (td[0].auth_only) { 269 memcpy(&conf->auth_xform, &td[0].xform.chain.auth, 270 sizeof(conf->auth_xform)); 271 conf->auth_xform.auth.key.data = td[0].auth_key.data; 272 273 if (test_ipsec_crypto_caps_auth_verify( 274 sec_cap, 275 &conf->auth_xform) != 0) { 276 RTE_LOG(INFO, USER1, 277 "Auth crypto capabilities not supported\n"); 278 return -1; 279 } 280 } else { 281 memcpy(&conf->cipher_xform, &td[0].xform.chain.cipher, 282 sizeof(conf->cipher_xform)); 283 memcpy(&conf->auth_xform, &td[0].xform.chain.auth, 284 sizeof(conf->auth_xform)); 285 conf->cipher_xform.cipher.key.data = td[0].key.data; 286 conf->cipher_xform.cipher.iv.offset = IV_OFFSET; 287 conf->auth_xform.auth.key.data = td[0].auth_key.data; 288 289 /* Verify crypto capabilities */ 290 291 if (test_ipsec_crypto_caps_cipher_verify( 292 sec_cap, 293 &conf->cipher_xform) != 0) { 294 RTE_LOG(ERR, USER1, 295 "Cipher crypto capabilities not supported\n"); 296 return -1; 297 } 298 299 if (test_ipsec_crypto_caps_auth_verify( 300 sec_cap, 301 &conf->auth_xform) != 0) { 302 RTE_LOG(ERR, USER1, 303 "Auth crypto capabilities not supported\n"); 304 return -1; 305 } 306 } 307 308 if (test_ipsec_sec_caps_verify(ipsec_xform, sec_cap, 0) != 0) 309 return -1; 310 311 sess_conf->action_type = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL; 312 sess_conf->protocol = RTE_SECURITY_PROTOCOL_IPSEC; 313 314 if (td[0].aead || td[0].aes_gmac) { 315 salt_len = RTE_MIN(sizeof(ipsec_xform->salt), td[0].salt.len); 316 memcpy(&ipsec_xform->salt, td[0].salt.data, salt_len); 317 } 318 319 if (td[0].aead) { 320 sess_conf->ipsec = *ipsec_xform; 321 sess_conf->crypto_xform = &conf->aead_xform; 322 } else if (td[0].auth_only) { 323 sess_conf->ipsec = *ipsec_xform; 324 sess_conf->crypto_xform = &conf->auth_xform; 325 } else { 326 sess_conf->ipsec = *ipsec_xform; 327 if (dir == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 328 sess_conf->crypto_xform = &conf->cipher_xform; 329 conf->cipher_xform.next = &conf->auth_xform; 330 } else { 331 sess_conf->crypto_xform = &conf->auth_xform; 332 conf->auth_xform.next = &conf->cipher_xform; 333 } 334 } 335 336 return 0; 337 } 338 339 static int 340 test_security_session_perf(void *arg) 341 { 342 uint64_t tsc_start, tsc_mid, tsc_end, tsc_setup_dur, tsc_destroy_dur; 343 struct rte_security_ipsec_xform ipsec_xform; 344 struct rte_security_session_conf sess_conf; 345 int i, ret, nb_sessions, nb_sess_total; 346 struct rte_security_session **sess; 347 void *sec_ctx; 348 double setup_rate, destroy_rate; 349 uint64_t setup_ms, destroy_ms; 350 struct lcore_conf *conf = arg; 351 struct rte_mempool *sess_mp; 352 uint8_t nb_lcores; 353 354 nb_lcores = conf->ctx->nb_lcores; 355 nb_sess_total = conf->ctx->nb_sess; 356 sec_ctx = conf->ctx->sec_ctx; 357 sess_mp = conf->ctx->sess_mp; 358 359 nb_sessions = nb_sess_total / nb_lcores; 360 361 if (conf->qp_id == 0) 362 nb_sessions += (nb_sess_total - nb_sessions * nb_lcores); 363 364 ret = sec_conf_init(conf, &sess_conf, &ipsec_xform, 365 &ctx.td[ctx.td_idx]); 366 if (ret) { 367 RTE_LOG(ERR, USER1, "Could not initialize session conf\n"); 368 return EXIT_FAILURE; 369 } 370 371 sess = rte_zmalloc(NULL, sizeof(void *) * nb_sessions, 0); 372 373 tsc_start = rte_rdtsc_precise(); 374 375 for (i = 0; i < nb_sessions; i++) { 376 sess[i] = rte_security_session_create(sec_ctx, 377 &sess_conf, 378 sess_mp); 379 if (unlikely(sess[i] == NULL)) { 380 RTE_LOG(ERR, USER1, "Could not create session\n"); 381 return EXIT_FAILURE; 382 } 383 } 384 385 tsc_mid = rte_rdtsc_precise(); 386 387 for (i = 0; i < nb_sessions; i++) { 388 ret = rte_security_session_destroy(sec_ctx, sess[i]); 389 if (unlikely(ret < 0)) { 390 RTE_LOG(ERR, USER1, "Could not destroy session\n"); 391 return EXIT_FAILURE; 392 } 393 } 394 395 tsc_end = rte_rdtsc_precise(); 396 397 tsc_setup_dur = tsc_mid - tsc_start; 398 tsc_destroy_dur = tsc_end - tsc_mid; 399 400 setup_ms = tsc_setup_dur * 1000 / rte_get_tsc_hz(); 401 destroy_ms = tsc_destroy_dur * 1000 / rte_get_tsc_hz(); 402 403 setup_rate = (double)nb_sessions * rte_get_tsc_hz() / tsc_setup_dur; 404 destroy_rate = (double)nb_sessions * rte_get_tsc_hz() / tsc_destroy_dur; 405 406 printf("%20u%20u%20"PRIu64"%20"PRIu64"%20.2f%20.2f\n", 407 rte_lcore_id(), 408 nb_sessions, 409 setup_ms, 410 destroy_ms, 411 setup_rate, 412 destroy_rate); 413 414 return EXIT_SUCCESS; 415 } 416 417 static void 418 usage(char *progname) 419 { 420 printf("\nusage: %s\n", progname); 421 printf(" --help : display this message and exit\n" 422 " --inbound : test for inbound direction\n" 423 " default outbound direction is tested\n" 424 " --nb-sess=N: to set the number of sessions\n" 425 " to be created, default is %d\n", DEF_NB_SESSIONS); 426 } 427 428 static void 429 args_parse(int argc, char **argv) 430 { 431 char **argvopt; 432 int n, opt; 433 int opt_idx; 434 435 static const struct option lgopts[] = { 436 /* Control */ 437 { "help", 0, 0, 0 }, 438 { "inbound", 0, 0, 0 }, 439 { "nb-sess", 1, 0, 0 }, 440 { NULL, 0, 0, 0 } 441 }; 442 443 argvopt = argv; 444 445 while ((opt = getopt_long(argc, argvopt, "", 446 lgopts, &opt_idx)) != EOF) { 447 switch (opt) { 448 case 0: 449 if (strcmp(lgopts[opt_idx].name, "help") == 0) { 450 usage(argv[0]); 451 exit(EXIT_SUCCESS); 452 } 453 454 if (strcmp(lgopts[opt_idx].name, "nb-sess") == 0) { 455 n = atoi(optarg); 456 if (n >= 0) 457 ctx.nb_sess = n; 458 else 459 rte_exit(EXIT_FAILURE, 460 "nb-sess should be >= 0\n"); 461 printf("nb-sess %d / ", ctx.nb_sess); 462 } else if (strcmp(lgopts[opt_idx].name, "inbound") == 463 0) { 464 ctx.is_inbound = true; 465 printf("inbound / "); 466 } 467 468 break; 469 470 default: 471 usage(argv[0]); 472 rte_exit(EXIT_FAILURE, "Invalid option: %s\n", 473 argv[opt_idx - 1]); 474 break; 475 } 476 } 477 478 printf("\n\n"); 479 } 480 481 int 482 main(int argc, char **argv) 483 { 484 struct ipsec_test_data td_outb[RTE_DIM(alg_list)]; 485 struct ipsec_test_data td_inb[RTE_DIM(alg_list)]; 486 struct ipsec_test_flags flags; 487 uint32_t lcore_id; 488 uint8_t nb_lcores; 489 unsigned long i; 490 int ret; 491 492 memset(&ctx, 0, sizeof(struct test_ctx)); 493 memset(&flags, 0, sizeof(flags)); 494 495 ret = rte_eal_init(argc, argv); 496 if (ret < 0) 497 rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n"); 498 argc -= ret; 499 argv += ret; 500 501 nb_lcores = rte_lcore_count() - 1; 502 if (nb_lcores < 1) { 503 RTE_LOG(ERR, USER1, 504 "Number of worker cores need to be higher than 1\n"); 505 return -EINVAL; 506 } 507 508 ctx.nb_sess = DEF_NB_SESSIONS + RTE_MEMPOOL_CACHE_MAX_SIZE * nb_lcores; 509 510 if (argc > 1) 511 args_parse(argc, argv); 512 513 ctx.nb_lcores = nb_lcores; 514 515 ret = cryptodev_init(&ctx, nb_lcores); 516 if (ret) 517 goto exit; 518 519 ret = mempool_init(&ctx, nb_lcores); 520 if (ret) 521 goto cryptodev_fini; 522 523 test_ipsec_alg_list_populate(); 524 525 for (i = 0; i < RTE_DIM(alg_list); i++) { 526 test_ipsec_td_prepare(alg_list[i].param1, 527 alg_list[i].param2, 528 &flags, 529 &td_outb[i], 530 1); 531 if (ctx.is_inbound) 532 test_ipsec_td_in_from_out(&td_outb[i], &td_inb[i]); 533 } 534 535 ctx.td = td_outb; 536 if (ctx.is_inbound) 537 ctx.td = td_inb; 538 539 for (ctx.td_idx = 0; ctx.td_idx < RTE_DIM(alg_list); ctx.td_idx++) { 540 541 printf("\n\n Algorithm combination:"); 542 test_ipsec_display_alg(alg_list[ctx.td_idx].param1, 543 alg_list[ctx.td_idx].param2); 544 printf(" ----------------------"); 545 546 printf("\n%20s%20s%20s%20s%20s%20s\n\n", 547 "lcore id", "nb_sessions", 548 "Setup time(ms)", "Destroy time(ms)", 549 "Setup rate(sess/s)", 550 "Destroy rate(sess/sec)"); 551 552 i = 0; 553 RTE_LCORE_FOREACH_WORKER(lcore_id) { 554 rte_eal_remote_launch(test_security_session_perf, 555 &ctx.lconf[i], 556 lcore_id); 557 i++; 558 } 559 560 RTE_LCORE_FOREACH_WORKER(lcore_id) { 561 ret |= rte_eal_wait_lcore(lcore_id); 562 } 563 564 } 565 566 cryptodev_fini(&ctx); 567 mempool_fini(&ctx); 568 569 return EXIT_SUCCESS; 570 cryptodev_fini: 571 cryptodev_fini(&ctx); 572 exit: 573 return EXIT_FAILURE; 574 575 } 576