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