1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 5 #include "test.h" 6 7 #include <stdio.h> 8 #include <rte_ip.h> 9 #include <rte_malloc.h> 10 #include <rte_ring.h> 11 #include <rte_mbuf.h> 12 #include <rte_cycles.h> 13 14 #ifdef RTE_EXEC_ENV_WINDOWS 15 static int 16 test_libipsec_perf(void) 17 { 18 printf("ipsec_perf not supported on Windows, skipping test\n"); 19 return TEST_SKIPPED; 20 } 21 22 #else 23 24 #include <rte_ipsec.h> 25 #include <rte_random.h> 26 27 #include "test_cryptodev.h" 28 29 #define RING_SIZE 4096 30 #define BURST_SIZE 64 31 #define NUM_MBUF 4095 32 #define DEFAULT_SPI 7 33 34 struct ipsec_test_cfg { 35 uint32_t replay_win_sz; 36 uint32_t esn; 37 uint64_t flags; 38 enum rte_crypto_sym_xform_type type; 39 }; 40 41 struct rte_mempool *mbuf_pool, *cop_pool; 42 43 struct stats_counter { 44 uint64_t nb_prepare_call; 45 uint64_t nb_prepare_pkt; 46 uint64_t nb_process_call; 47 uint64_t nb_process_pkt; 48 uint64_t prepare_ticks_elapsed; 49 uint64_t process_ticks_elapsed; 50 }; 51 52 struct ipsec_sa { 53 struct rte_ipsec_session ss[2]; 54 struct rte_ipsec_sa_prm sa_prm; 55 struct rte_security_ipsec_xform ipsec_xform; 56 struct rte_crypto_sym_xform cipher_xform; 57 struct rte_crypto_sym_xform auth_xform; 58 struct rte_crypto_sym_xform aead_xform; 59 struct rte_crypto_sym_xform *crypto_xforms; 60 struct rte_crypto_op *cop[BURST_SIZE]; 61 enum rte_crypto_sym_xform_type type; 62 struct stats_counter cnt; 63 uint32_t replay_win_sz; 64 uint32_t sa_flags; 65 }; 66 67 static const struct ipsec_test_cfg test_cfg[] = { 68 {0, 0, 0, RTE_CRYPTO_SYM_XFORM_AEAD}, 69 {0, 0, 0, RTE_CRYPTO_SYM_XFORM_CIPHER}, 70 {128, 1, 0, RTE_CRYPTO_SYM_XFORM_AEAD}, 71 {128, 1, 0, RTE_CRYPTO_SYM_XFORM_CIPHER}, 72 73 }; 74 75 static struct rte_ipv4_hdr ipv4_outer = { 76 .version_ihl = IPVERSION << 4 | 77 sizeof(ipv4_outer) / RTE_IPV4_IHL_MULTIPLIER, 78 .time_to_live = IPDEFTTL, 79 .next_proto_id = IPPROTO_ESP, 80 .src_addr = RTE_IPV4(192, 168, 1, 100), 81 .dst_addr = RTE_IPV4(192, 168, 2, 100), 82 }; 83 84 static struct rte_ring *ring_inb_prepare; 85 static struct rte_ring *ring_inb_process; 86 static struct rte_ring *ring_outb_prepare; 87 static struct rte_ring *ring_outb_process; 88 89 struct supported_cipher_algo { 90 const char *keyword; 91 enum rte_crypto_cipher_algorithm algo; 92 uint16_t iv_len; 93 uint16_t block_size; 94 uint16_t key_len; 95 }; 96 97 struct supported_auth_algo { 98 const char *keyword; 99 enum rte_crypto_auth_algorithm algo; 100 uint16_t digest_len; 101 uint16_t key_len; 102 uint8_t key_not_req; 103 }; 104 105 struct supported_aead_algo { 106 const char *keyword; 107 enum rte_crypto_aead_algorithm algo; 108 uint16_t iv_len; 109 uint16_t block_size; 110 uint16_t digest_len; 111 uint16_t key_len; 112 uint8_t aad_len; 113 }; 114 115 const struct supported_cipher_algo cipher_algo[] = { 116 { 117 .keyword = "aes-128-cbc", 118 .algo = RTE_CRYPTO_CIPHER_AES_CBC, 119 .iv_len = 16, 120 .block_size = 16, 121 .key_len = 16 122 } 123 }; 124 125 const struct supported_auth_algo auth_algo[] = { 126 { 127 .keyword = "sha1-hmac", 128 .algo = RTE_CRYPTO_AUTH_SHA1_HMAC, 129 .digest_len = 12, 130 .key_len = 20 131 } 132 }; 133 134 const struct supported_aead_algo aead_algo[] = { 135 { 136 .keyword = "aes-128-gcm", 137 .algo = RTE_CRYPTO_AEAD_AES_GCM, 138 .iv_len = 8, 139 .block_size = 4, 140 .key_len = 20, 141 .digest_len = 16, 142 .aad_len = 8, 143 } 144 }; 145 146 static struct rte_mbuf *generate_mbuf_data(struct rte_mempool *mpool) 147 { 148 struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mpool); 149 150 if (mbuf) { 151 mbuf->data_len = 64; 152 mbuf->pkt_len = 64; 153 } 154 155 return mbuf; 156 } 157 158 static int 159 fill_ipsec_param(struct ipsec_sa *sa) 160 { 161 struct rte_ipsec_sa_prm *prm = &sa->sa_prm; 162 163 memset(prm, 0, sizeof(*prm)); 164 165 prm->flags = sa->sa_flags; 166 167 /* setup ipsec xform */ 168 prm->ipsec_xform = sa->ipsec_xform; 169 prm->ipsec_xform.salt = (uint32_t)rte_rand(); 170 prm->ipsec_xform.replay_win_sz = sa->replay_win_sz; 171 172 /* setup tunnel related fields */ 173 prm->tun.hdr_len = sizeof(ipv4_outer); 174 prm->tun.next_proto = IPPROTO_IPIP; 175 prm->tun.hdr = &ipv4_outer; 176 177 if (sa->type == RTE_CRYPTO_SYM_XFORM_AEAD) { 178 sa->aead_xform.type = sa->type; 179 sa->aead_xform.aead.algo = aead_algo->algo; 180 sa->aead_xform.next = NULL; 181 sa->aead_xform.aead.digest_length = aead_algo->digest_len; 182 sa->aead_xform.aead.iv.offset = IV_OFFSET; 183 sa->aead_xform.aead.iv.length = 12; 184 185 if (sa->ipsec_xform.direction == 186 RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 187 sa->aead_xform.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT; 188 } else { 189 sa->aead_xform.aead.op = RTE_CRYPTO_AEAD_OP_ENCRYPT; 190 } 191 192 sa->crypto_xforms = &sa->aead_xform; 193 } else { 194 sa->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; 195 sa->cipher_xform.cipher.algo = cipher_algo->algo; 196 sa->cipher_xform.cipher.iv.offset = IV_OFFSET; 197 sa->cipher_xform.cipher.iv.length = 12; 198 sa->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; 199 sa->auth_xform.auth.algo = auth_algo->algo; 200 sa->auth_xform.auth.digest_length = auth_algo->digest_len; 201 202 203 if (sa->ipsec_xform.direction == 204 RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 205 sa->cipher_xform.cipher.op = 206 RTE_CRYPTO_CIPHER_OP_DECRYPT; 207 sa->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY; 208 sa->cipher_xform.next = NULL; 209 sa->auth_xform.next = &sa->cipher_xform; 210 sa->crypto_xforms = &sa->auth_xform; 211 } else { 212 sa->cipher_xform.cipher.op = 213 RTE_CRYPTO_CIPHER_OP_ENCRYPT; 214 sa->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; 215 sa->auth_xform.next = NULL; 216 sa->cipher_xform.next = &sa->auth_xform; 217 sa->crypto_xforms = &sa->cipher_xform; 218 } 219 } 220 221 prm->crypto_xform = sa->crypto_xforms; 222 223 return TEST_SUCCESS; 224 } 225 226 static int 227 create_sa(enum rte_security_session_action_type action_type, 228 struct ipsec_sa *sa) 229 { 230 static struct rte_cryptodev_sym_session dummy_ses; 231 size_t sz; 232 int rc; 233 234 memset(&sa->ss[0], 0, sizeof(sa->ss[0])); 235 236 rc = fill_ipsec_param(sa); 237 if (rc != 0) { 238 printf("failed to fill ipsec param\n"); 239 return TEST_FAILED; 240 } 241 242 sz = rte_ipsec_sa_size(&sa->sa_prm); 243 TEST_ASSERT(sz > 0, "rte_ipsec_sa_size() failed\n"); 244 245 sa->ss[0].sa = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE); 246 TEST_ASSERT_NOT_NULL(sa->ss[0].sa, 247 "failed to allocate memory for rte_ipsec_sa\n"); 248 249 sa->ss[0].type = action_type; 250 sa->ss[0].crypto.ses = &dummy_ses; 251 252 rc = rte_ipsec_sa_init(sa->ss[0].sa, &sa->sa_prm, sz); 253 rc = (rc > 0 && (uint32_t)rc <= sz) ? 0 : -EINVAL; 254 255 if (rc == 0) 256 rc = rte_ipsec_session_prepare(&sa->ss[0]); 257 else 258 return TEST_FAILED; 259 260 return TEST_SUCCESS; 261 } 262 263 static int 264 packet_prepare(struct rte_mbuf **buf, struct ipsec_sa *sa, 265 uint16_t num_pkts) 266 { 267 uint64_t time_stamp; 268 uint16_t k = 0, i; 269 270 for (i = 0; i < num_pkts; i++) { 271 272 sa->cop[i] = rte_crypto_op_alloc(cop_pool, 273 RTE_CRYPTO_OP_TYPE_SYMMETRIC); 274 275 if (sa->cop[i] == NULL) { 276 277 RTE_LOG(ERR, USER1, 278 "Failed to allocate symmetric crypto op\n"); 279 280 return k; 281 } 282 } 283 284 time_stamp = rte_rdtsc_precise(); 285 286 k = rte_ipsec_pkt_crypto_prepare(&sa->ss[0], buf, 287 sa->cop, num_pkts); 288 289 time_stamp = rte_rdtsc_precise() - time_stamp; 290 291 if (k != num_pkts) { 292 RTE_LOG(ERR, USER1, "rte_ipsec_pkt_crypto_prepare fail\n"); 293 return k; 294 } 295 296 sa->cnt.prepare_ticks_elapsed += time_stamp; 297 sa->cnt.nb_prepare_call++; 298 sa->cnt.nb_prepare_pkt += k; 299 300 for (i = 0; i < num_pkts; i++) 301 rte_crypto_op_free(sa->cop[i]); 302 303 return k; 304 } 305 306 static int 307 packet_process(struct rte_mbuf **buf, struct ipsec_sa *sa, 308 uint16_t num_pkts) 309 { 310 uint64_t time_stamp; 311 uint16_t k = 0; 312 313 time_stamp = rte_rdtsc_precise(); 314 315 k = rte_ipsec_pkt_process(&sa->ss[0], buf, num_pkts); 316 317 time_stamp = rte_rdtsc_precise() - time_stamp; 318 319 if (k != num_pkts) { 320 RTE_LOG(ERR, USER1, "rte_ipsec_pkt_process fail\n"); 321 return k; 322 } 323 324 sa->cnt.process_ticks_elapsed += time_stamp; 325 sa->cnt.nb_process_call++; 326 sa->cnt.nb_process_pkt += k; 327 328 return k; 329 } 330 331 static int 332 create_traffic(struct ipsec_sa *sa, struct rte_ring *deq_ring, 333 struct rte_ring *enq_ring, struct rte_ring *ring) 334 { 335 struct rte_mbuf *mbuf[BURST_SIZE]; 336 uint16_t num_pkts, n; 337 338 while (rte_ring_empty(deq_ring) == 0) { 339 340 num_pkts = rte_ring_sc_dequeue_burst(deq_ring, (void **)mbuf, 341 RTE_DIM(mbuf), NULL); 342 343 if (num_pkts == 0) 344 return TEST_FAILED; 345 346 n = packet_prepare(mbuf, sa, num_pkts); 347 if (n != num_pkts) 348 return TEST_FAILED; 349 350 num_pkts = rte_ring_sp_enqueue_burst(enq_ring, (void **)mbuf, 351 num_pkts, NULL); 352 if (num_pkts == 0) 353 return TEST_FAILED; 354 } 355 356 deq_ring = enq_ring; 357 enq_ring = ring; 358 359 while (rte_ring_empty(deq_ring) == 0) { 360 361 num_pkts = rte_ring_sc_dequeue_burst(deq_ring, (void **)mbuf, 362 RTE_DIM(mbuf), NULL); 363 if (num_pkts == 0) 364 return TEST_FAILED; 365 366 n = packet_process(mbuf, sa, num_pkts); 367 if (n != num_pkts) 368 return TEST_FAILED; 369 370 num_pkts = rte_ring_sp_enqueue_burst(enq_ring, (void **)mbuf, 371 num_pkts, NULL); 372 if (num_pkts == 0) 373 return TEST_FAILED; 374 } 375 376 return TEST_SUCCESS; 377 } 378 379 static void 380 fill_ipsec_sa_out(const struct ipsec_test_cfg *test_cfg, 381 struct ipsec_sa *sa) 382 { 383 sa->ipsec_xform.spi = DEFAULT_SPI; 384 sa->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS; 385 sa->ipsec_xform.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP; 386 sa->ipsec_xform.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; 387 sa->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; 388 sa->ipsec_xform.options.esn = test_cfg->esn; 389 sa->type = test_cfg->type; 390 sa->replay_win_sz = test_cfg->replay_win_sz; 391 sa->sa_flags = test_cfg->flags; 392 sa->cnt.nb_prepare_call = 0; 393 sa->cnt.nb_prepare_pkt = 0; 394 sa->cnt.nb_process_call = 0; 395 sa->cnt.nb_process_pkt = 0; 396 sa->cnt.process_ticks_elapsed = 0; 397 sa->cnt.prepare_ticks_elapsed = 0; 398 399 } 400 401 static void 402 fill_ipsec_sa_in(const struct ipsec_test_cfg *test_cfg, 403 struct ipsec_sa *sa) 404 { 405 sa->ipsec_xform.spi = DEFAULT_SPI; 406 sa->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS; 407 sa->ipsec_xform.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP; 408 sa->ipsec_xform.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL; 409 sa->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4; 410 sa->ipsec_xform.options.esn = test_cfg->esn; 411 sa->type = test_cfg->type; 412 sa->replay_win_sz = test_cfg->replay_win_sz; 413 sa->sa_flags = test_cfg->flags; 414 sa->cnt.nb_prepare_call = 0; 415 sa->cnt.nb_prepare_pkt = 0; 416 sa->cnt.nb_process_call = 0; 417 sa->cnt.nb_process_pkt = 0; 418 sa->cnt.process_ticks_elapsed = 0; 419 sa->cnt.prepare_ticks_elapsed = 0; 420 } 421 422 static int 423 init_sa_session(const struct ipsec_test_cfg *test_cfg, 424 struct ipsec_sa *sa_out, struct ipsec_sa *sa_in) 425 { 426 427 int rc; 428 429 fill_ipsec_sa_in(test_cfg, sa_in); 430 fill_ipsec_sa_out(test_cfg, sa_out); 431 432 rc = create_sa(RTE_SECURITY_ACTION_TYPE_NONE, sa_out); 433 if (rc != 0) { 434 RTE_LOG(ERR, USER1, "out bound create_sa failed, cfg\n"); 435 return TEST_FAILED; 436 } 437 438 rc = create_sa(RTE_SECURITY_ACTION_TYPE_NONE, sa_in); 439 if (rc != 0) { 440 RTE_LOG(ERR, USER1, "out bound create_sa failed, cfg\n"); 441 return TEST_FAILED; 442 } 443 444 return TEST_SUCCESS; 445 } 446 447 static int 448 testsuite_setup(void) 449 { 450 struct rte_mbuf *mbuf; 451 int i; 452 453 mbuf_pool = rte_pktmbuf_pool_create("IPSEC_PERF_MBUFPOOL", 454 NUM_MBUFS, MBUF_CACHE_SIZE, 0, MBUF_SIZE, 455 rte_socket_id()); 456 if (mbuf_pool == NULL) { 457 RTE_LOG(ERR, USER1, "Can't create MBUFPOOL\n"); 458 return TEST_FAILED; 459 } 460 461 cop_pool = rte_crypto_op_pool_create( 462 "MBUF_CRYPTO_SYM_OP_POOL", 463 RTE_CRYPTO_OP_TYPE_SYMMETRIC, 464 NUM_MBUFS, MBUF_CACHE_SIZE, 465 DEFAULT_NUM_XFORMS * 466 sizeof(struct rte_crypto_sym_xform) + 467 MAXIMUM_IV_LENGTH, 468 rte_socket_id()); 469 if (cop_pool == NULL) { 470 RTE_LOG(ERR, USER1, "Can't create CRYPTO_OP_POOL\n"); 471 return TEST_FAILED; 472 } 473 474 ring_inb_prepare = rte_ring_create("ipsec_test_ring_inb_prepare", 475 RING_SIZE, SOCKET_ID_ANY, 0); 476 if (ring_inb_prepare == NULL) 477 return TEST_FAILED; 478 479 ring_inb_process = rte_ring_create("ipsec_test_ring_inb_process", 480 RING_SIZE, SOCKET_ID_ANY, 0); 481 if (ring_inb_process == NULL) 482 return TEST_FAILED; 483 484 ring_outb_prepare = rte_ring_create("ipsec_test_ring_outb_prepare", 485 RING_SIZE, SOCKET_ID_ANY, 0); 486 if (ring_outb_prepare == NULL) 487 return TEST_FAILED; 488 489 ring_outb_process = rte_ring_create("ipsec_test_ring_outb_process", 490 RING_SIZE, SOCKET_ID_ANY, 0); 491 if (ring_outb_process == NULL) 492 return TEST_FAILED; 493 494 for (i = 0; i < NUM_MBUF; i++) { 495 mbuf = generate_mbuf_data(mbuf_pool); 496 497 if (mbuf && rte_ring_sp_enqueue_bulk(ring_inb_prepare, 498 (void **)&mbuf, 1, NULL)) 499 continue; 500 else 501 return TEST_FAILED; 502 } 503 504 return TEST_SUCCESS; 505 } 506 507 static int 508 measure_performance(struct ipsec_sa *sa_out, struct ipsec_sa *sa_in) 509 { 510 uint64_t time_diff = 0; 511 uint64_t begin = 0; 512 uint64_t hz = rte_get_timer_hz(); 513 514 begin = rte_get_timer_cycles(); 515 516 do { 517 if (create_traffic(sa_out, ring_inb_prepare, ring_inb_process, 518 ring_outb_prepare) < 0) 519 return TEST_FAILED; 520 521 if (create_traffic(sa_in, ring_outb_prepare, ring_outb_process, 522 ring_inb_prepare) < 0) 523 return TEST_FAILED; 524 525 time_diff = rte_get_timer_cycles() - begin; 526 527 } while (time_diff < (hz * 10)); 528 529 return TEST_SUCCESS; 530 } 531 532 static void 533 print_metrics(const struct ipsec_test_cfg *test_cfg, 534 struct ipsec_sa *sa_out, struct ipsec_sa *sa_in) 535 { 536 printf("\nMetrics of libipsec prepare/process api:\n"); 537 538 printf("replay window size = %u\n", test_cfg->replay_win_sz); 539 if (test_cfg->esn) 540 printf("replay esn is enabled\n"); 541 else 542 printf("replay esn is disabled\n"); 543 if (test_cfg->type == RTE_CRYPTO_SYM_XFORM_AEAD) 544 printf("AEAD algo is AES_GCM\n"); 545 else 546 printf("CIPHER/AUTH algo is AES_CBC/SHA1\n"); 547 548 549 printf("avg cycles for a pkt prepare in outbound is = %.2Lf\n", 550 (long double)sa_out->cnt.prepare_ticks_elapsed 551 / sa_out->cnt.nb_prepare_pkt); 552 printf("avg cycles for a pkt process in outbound is = %.2Lf\n", 553 (long double)sa_out->cnt.process_ticks_elapsed 554 / sa_out->cnt.nb_process_pkt); 555 printf("avg cycles for a pkt prepare in inbound is = %.2Lf\n", 556 (long double)sa_in->cnt.prepare_ticks_elapsed 557 / sa_in->cnt.nb_prepare_pkt); 558 printf("avg cycles for a pkt process in inbound is = %.2Lf\n", 559 (long double)sa_in->cnt.process_ticks_elapsed 560 / sa_in->cnt.nb_process_pkt); 561 562 } 563 564 static void 565 testsuite_teardown(void) 566 { 567 if (mbuf_pool != NULL) { 568 RTE_LOG(DEBUG, USER1, "MBUFPOOL count %u\n", 569 rte_mempool_avail_count(mbuf_pool)); 570 rte_mempool_free(mbuf_pool); 571 mbuf_pool = NULL; 572 } 573 574 if (cop_pool != NULL) { 575 RTE_LOG(DEBUG, USER1, "CRYPTO_OP_POOL count %u\n", 576 rte_mempool_avail_count(cop_pool)); 577 rte_mempool_free(cop_pool); 578 cop_pool = NULL; 579 } 580 581 rte_ring_free(ring_inb_prepare); 582 rte_ring_free(ring_inb_process); 583 rte_ring_free(ring_outb_prepare); 584 rte_ring_free(ring_outb_process); 585 586 ring_inb_prepare = NULL; 587 ring_inb_process = NULL; 588 ring_outb_prepare = NULL; 589 ring_outb_process = NULL; 590 } 591 592 static int 593 test_libipsec_perf(void) 594 { 595 struct ipsec_sa sa_out; 596 struct ipsec_sa sa_in; 597 uint32_t i; 598 int ret; 599 600 if (testsuite_setup() < 0) { 601 testsuite_teardown(); 602 return TEST_FAILED; 603 } 604 605 for (i = 0; i < RTE_DIM(test_cfg) ; i++) { 606 607 ret = init_sa_session(&test_cfg[i], &sa_out, &sa_in); 608 if (ret != 0) { 609 testsuite_teardown(); 610 return TEST_FAILED; 611 } 612 613 if (measure_performance(&sa_out, &sa_in) < 0) { 614 testsuite_teardown(); 615 return TEST_FAILED; 616 } 617 618 print_metrics(&test_cfg[i], &sa_out, &sa_in); 619 } 620 621 testsuite_teardown(); 622 623 return TEST_SUCCESS; 624 } 625 626 #endif /* !RTE_EXEC_ENV_WINDOWS */ 627 628 REGISTER_TEST_COMMAND(ipsec_perf_autotest, test_libipsec_perf); 629