1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
9 #include <rte_malloc.h>
12 #include <rte_cycles.h>
14 #ifdef RTE_EXEC_ENV_WINDOWS
16 test_libipsec_perf(void)
18 printf("ipsec_perf not supported on Windows, skipping test\n");
24 #include <rte_ipsec.h>
25 #include <rte_random.h>
27 #include "test_cryptodev.h"
29 #define RING_SIZE 4096
34 struct ipsec_test_cfg {
35 uint32_t replay_win_sz;
38 enum rte_crypto_sym_xform_type type;
41 struct rte_mempool *mbuf_pool, *cop_pool;
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;
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;
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},
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),
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;
89 struct supported_cipher_algo {
91 enum rte_crypto_cipher_algorithm algo;
97 struct supported_auth_algo {
99 enum rte_crypto_auth_algorithm algo;
105 struct supported_aead_algo {
107 enum rte_crypto_aead_algorithm algo;
115 const struct supported_cipher_algo cipher_algo[] = {
117 .keyword = "aes-128-cbc",
118 .algo = RTE_CRYPTO_CIPHER_AES_CBC,
125 const struct supported_auth_algo auth_algo[] = {
127 .keyword = "sha1-hmac",
128 .algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
134 const struct supported_aead_algo aead_algo[] = {
136 .keyword = "aes-128-gcm",
137 .algo = RTE_CRYPTO_AEAD_AES_GCM,
146 static struct rte_mbuf *generate_mbuf_data(struct rte_mempool *mpool)
148 struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mpool);
159 fill_ipsec_param(struct ipsec_sa *sa)
161 struct rte_ipsec_sa_prm *prm = &sa->sa_prm;
163 memset(prm, 0, sizeof(*prm));
165 prm->flags = sa->sa_flags;
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;
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;
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;
185 if (sa->ipsec_xform.direction ==
186 RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
187 sa->aead_xform.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
189 sa->aead_xform.aead.op = RTE_CRYPTO_AEAD_OP_ENCRYPT;
192 sa->crypto_xforms = &sa->aead_xform;
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;
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;
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;
221 prm->crypto_xform = sa->crypto_xforms;
227 create_sa(enum rte_security_session_action_type action_type,
230 static struct rte_cryptodev_sym_session dummy_ses;
234 memset(&sa->ss[0], 0, sizeof(sa->ss[0]));
236 rc = fill_ipsec_param(sa);
238 printf("failed to fill ipsec param\n");
242 sz = rte_ipsec_sa_size(&sa->sa_prm);
243 TEST_ASSERT(sz > 0, "rte_ipsec_sa_size() failed\n");
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");
249 sa->ss[0].type = action_type;
250 sa->ss[0].crypto.ses = &dummy_ses;
252 rc = rte_ipsec_sa_init(sa->ss[0].sa, &sa->sa_prm, sz);
253 rc = (rc > 0 && (uint32_t)rc <= sz) ? 0 : -EINVAL;
256 rc = rte_ipsec_session_prepare(&sa->ss[0]);
264 packet_prepare(struct rte_mbuf **buf, struct ipsec_sa *sa,
270 for (i = 0; i < num_pkts; i++) {
272 sa->cop[i] = rte_crypto_op_alloc(cop_pool,
273 RTE_CRYPTO_OP_TYPE_SYMMETRIC);
275 if (sa->cop[i] == NULL) {
278 "Failed to allocate symmetric crypto op\n");
284 time_stamp = rte_rdtsc_precise();
286 k = rte_ipsec_pkt_crypto_prepare(&sa->ss[0], buf,
289 time_stamp = rte_rdtsc_precise() - time_stamp;
292 RTE_LOG(ERR, USER1, "rte_ipsec_pkt_crypto_prepare fail\n");
296 sa->cnt.prepare_ticks_elapsed += time_stamp;
297 sa->cnt.nb_prepare_call++;
298 sa->cnt.nb_prepare_pkt += k;
300 for (i = 0; i < num_pkts; i++)
301 rte_crypto_op_free(sa->cop[i]);
307 packet_process(struct rte_mbuf **buf, struct ipsec_sa *sa,
313 time_stamp = rte_rdtsc_precise();
315 k = rte_ipsec_pkt_process(&sa->ss[0], buf, num_pkts);
317 time_stamp = rte_rdtsc_precise() - time_stamp;
320 RTE_LOG(ERR, USER1, "rte_ipsec_pkt_process fail\n");
324 sa->cnt.process_ticks_elapsed += time_stamp;
325 sa->cnt.nb_process_call++;
326 sa->cnt.nb_process_pkt += k;
332 create_traffic(struct ipsec_sa *sa, struct rte_ring *deq_ring,
333 struct rte_ring *enq_ring, struct rte_ring *ring)
335 struct rte_mbuf *mbuf[BURST_SIZE];
336 uint16_t num_pkts, n;
338 while (rte_ring_empty(deq_ring) == 0) {
340 num_pkts = rte_ring_sc_dequeue_burst(deq_ring, (void **)mbuf,
341 RTE_DIM(mbuf), NULL);
346 n = packet_prepare(mbuf, sa, num_pkts);
350 num_pkts = rte_ring_sp_enqueue_burst(enq_ring, (void **)mbuf,
359 while (rte_ring_empty(deq_ring) == 0) {
361 num_pkts = rte_ring_sc_dequeue_burst(deq_ring, (void **)mbuf,
362 RTE_DIM(mbuf), NULL);
366 n = packet_process(mbuf, sa, num_pkts);
370 num_pkts = rte_ring_sp_enqueue_burst(enq_ring, (void **)mbuf,
380 fill_ipsec_sa_out(const struct ipsec_test_cfg *test_cfg,
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;
402 fill_ipsec_sa_in(const struct ipsec_test_cfg *test_cfg,
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;
423 init_sa_session(const struct ipsec_test_cfg *test_cfg,
424 struct ipsec_sa *sa_out, struct ipsec_sa *sa_in)
429 fill_ipsec_sa_in(test_cfg, sa_in);
430 fill_ipsec_sa_out(test_cfg, sa_out);
432 rc = create_sa(RTE_SECURITY_ACTION_TYPE_NONE, sa_out);
434 RTE_LOG(ERR, USER1, "out bound create_sa failed, cfg\n");
438 rc = create_sa(RTE_SECURITY_ACTION_TYPE_NONE, sa_in);
440 RTE_LOG(ERR, USER1, "out bound create_sa failed, cfg\n");
448 testsuite_setup(void)
450 struct rte_mbuf *mbuf;
453 mbuf_pool = rte_pktmbuf_pool_create("IPSEC_PERF_MBUFPOOL",
454 NUM_MBUFS, MBUF_CACHE_SIZE, 0, MBUF_SIZE,
456 if (mbuf_pool == NULL) {
457 RTE_LOG(ERR, USER1, "Can't create MBUFPOOL\n");
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,
466 sizeof(struct rte_crypto_sym_xform) +
469 if (cop_pool == NULL) {
470 RTE_LOG(ERR, USER1, "Can't create CRYPTO_OP_POOL\n");
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)
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)
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)
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)
494 for (i = 0; i < NUM_MBUF; i++) {
495 mbuf = generate_mbuf_data(mbuf_pool);
497 if (mbuf && rte_ring_sp_enqueue_bulk(ring_inb_prepare,
498 (void **)&mbuf, 1, NULL))
508 measure_performance(struct ipsec_sa *sa_out, struct ipsec_sa *sa_in)
510 uint64_t time_diff = 0;
512 uint64_t hz = rte_get_timer_hz();
514 begin = rte_get_timer_cycles();
517 if (create_traffic(sa_out, ring_inb_prepare, ring_inb_process,
518 ring_outb_prepare) < 0)
521 if (create_traffic(sa_in, ring_outb_prepare, ring_outb_process,
522 ring_inb_prepare) < 0)
525 time_diff = rte_get_timer_cycles() - begin;
527 } while (time_diff < (hz * 10));
533 print_metrics(const struct ipsec_test_cfg *test_cfg,
534 struct ipsec_sa *sa_out, struct ipsec_sa *sa_in)
536 printf("\nMetrics of libipsec prepare/process api:\n");
538 printf("replay window size = %u\n", test_cfg->replay_win_sz);
540 printf("replay esn is enabled\n");
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");
546 printf("CIPHER/AUTH algo is AES_CBC/SHA1\n");
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);
565 testsuite_teardown(void)
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);
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);
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);
586 ring_inb_prepare = NULL;
587 ring_inb_process = NULL;
588 ring_outb_prepare = NULL;
589 ring_outb_process = NULL;
593 test_libipsec_perf(void)
595 struct ipsec_sa sa_out;
596 struct ipsec_sa sa_in;
600 if (testsuite_setup() < 0) {
601 testsuite_teardown();
605 for (i = 0; i < RTE_DIM(test_cfg) ; i++) {
607 ret = init_sa_session(&test_cfg[i], &sa_out, &sa_in);
609 testsuite_teardown();
613 if (measure_performance(&sa_out, &sa_in) < 0) {
614 testsuite_teardown();
618 print_metrics(&test_cfg[i], &sa_out, &sa_in);
621 testsuite_teardown();
626 #endif /* !RTE_EXEC_ENV_WINDOWS */
628 REGISTER_TEST_COMMAND(ipsec_perf_autotest, test_libipsec_perf);