bpf: allow self-xor operation
[dpdk.git] / app / test / test_ipsec_perf.c
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
22 struct 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
29 struct rte_mempool *mbuf_pool, *cop_pool;
30
31 struct 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
40 struct 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
55 static 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
63 static 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
72 static struct rte_ring *ring_inb_prepare;
73 static struct rte_ring *ring_inb_process;
74 static struct rte_ring *ring_outb_prepare;
75 static struct rte_ring *ring_outb_process;
76
77 struct 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
85 struct 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
93 struct 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
103 const 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
113 const 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
122 const 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
134 static 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
146 static int
147 fill_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
214 static int
215 create_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
251 static int
252 packet_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
294 static int
295 packet_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
319 static int
320 create_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
367 static void
368 fill_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
389 static void
390 fill_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
410 static int
411 init_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
435 static int
436 testsuite_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
495 static int
496 measure_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
520 static void
521 print_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
552 static void
553 testsuite_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
580 static int
581 test_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
614 REGISTER_TEST_COMMAND(ipsec_perf_autotest, test_libipsec_perf);