New upstream version 17.11-rc3
[deb_dpdk.git] / app / test-crypto-perf / main.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *     * Neither the name of Intel Corporation nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <stdio.h>
34 #include <unistd.h>
35
36 #include <rte_eal.h>
37 #include <rte_cryptodev.h>
38 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
39 #include <rte_cryptodev_scheduler.h>
40 #endif
41
42 #include "cperf.h"
43 #include "cperf_options.h"
44 #include "cperf_test_vector_parsing.h"
45 #include "cperf_test_throughput.h"
46 #include "cperf_test_latency.h"
47 #include "cperf_test_verify.h"
48 #include "cperf_test_pmd_cyclecount.h"
49
50 #define NUM_SESSIONS 2048
51 #define SESS_MEMPOOL_CACHE_SIZE 64
52
53 const char *cperf_test_type_strs[] = {
54         [CPERF_TEST_TYPE_THROUGHPUT] = "throughput",
55         [CPERF_TEST_TYPE_LATENCY] = "latency",
56         [CPERF_TEST_TYPE_VERIFY] = "verify",
57         [CPERF_TEST_TYPE_PMDCC] = "pmd-cyclecount"
58 };
59
60 const char *cperf_op_type_strs[] = {
61         [CPERF_CIPHER_ONLY] = "cipher-only",
62         [CPERF_AUTH_ONLY] = "auth-only",
63         [CPERF_CIPHER_THEN_AUTH] = "cipher-then-auth",
64         [CPERF_AUTH_THEN_CIPHER] = "auth-then-cipher",
65         [CPERF_AEAD] = "aead"
66 };
67
68 const struct cperf_test cperf_testmap[] = {
69                 [CPERF_TEST_TYPE_THROUGHPUT] = {
70                                 cperf_throughput_test_constructor,
71                                 cperf_throughput_test_runner,
72                                 cperf_throughput_test_destructor
73                 },
74                 [CPERF_TEST_TYPE_LATENCY] = {
75                                 cperf_latency_test_constructor,
76                                 cperf_latency_test_runner,
77                                 cperf_latency_test_destructor
78                 },
79                 [CPERF_TEST_TYPE_VERIFY] = {
80                                 cperf_verify_test_constructor,
81                                 cperf_verify_test_runner,
82                                 cperf_verify_test_destructor
83                 },
84                 [CPERF_TEST_TYPE_PMDCC] = {
85                                 cperf_pmd_cyclecount_test_constructor,
86                                 cperf_pmd_cyclecount_test_runner,
87                                 cperf_pmd_cyclecount_test_destructor
88                 }
89 };
90
91 static int
92 cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs,
93                         struct rte_mempool *session_pool_socket[])
94 {
95         uint8_t enabled_cdev_count = 0, nb_lcores, cdev_id;
96         unsigned int i, j;
97         int ret;
98
99         enabled_cdev_count = rte_cryptodev_devices_get(opts->device_type,
100                         enabled_cdevs, RTE_CRYPTO_MAX_DEVS);
101         if (enabled_cdev_count == 0) {
102                 printf("No crypto devices type %s available\n",
103                                 opts->device_type);
104                 return -EINVAL;
105         }
106
107         nb_lcores = rte_lcore_count() - 1;
108
109         if (enabled_cdev_count > nb_lcores) {
110                 printf("Number of capable crypto devices (%d) "
111                                 "has to be less or equal to number of slave "
112                                 "cores (%d)\n", enabled_cdev_count, nb_lcores);
113                 return -EINVAL;
114         }
115
116         /* Create a mempool shared by all the devices */
117         uint32_t max_sess_size = 0, sess_size;
118
119         for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
120                 sess_size = rte_cryptodev_get_private_session_size(cdev_id);
121                 if (sess_size > max_sess_size)
122                         max_sess_size = sess_size;
123         }
124
125         /*
126          * Calculate number of needed queue pairs, based on the amount
127          * of available number of logical cores and crypto devices.
128          * For instance, if there are 4 cores and 2 crypto devices,
129          * 2 queue pairs will be set up per device.
130          */
131         opts->nb_qps = (nb_lcores % enabled_cdev_count) ?
132                                 (nb_lcores / enabled_cdev_count) + 1 :
133                                 nb_lcores / enabled_cdev_count;
134
135         for (i = 0; i < enabled_cdev_count &&
136                         i < RTE_CRYPTO_MAX_DEVS; i++) {
137                 cdev_id = enabled_cdevs[i];
138 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
139                 /*
140                  * If multi-core scheduler is used, limit the number
141                  * of queue pairs to 1, as there is no way to know
142                  * how many cores are being used by the PMD, and
143                  * how many will be available for the application.
144                  */
145                 if (!strcmp((const char *)opts->device_type, "crypto_scheduler") &&
146                                 rte_cryptodev_scheduler_mode_get(cdev_id) ==
147                                 CDEV_SCHED_MODE_MULTICORE)
148                         opts->nb_qps = 1;
149 #endif
150
151                 struct rte_cryptodev_info cdev_info;
152                 uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
153
154                 rte_cryptodev_info_get(cdev_id, &cdev_info);
155                 if (opts->nb_qps > cdev_info.max_nb_queue_pairs) {
156                         printf("Number of needed queue pairs is higher "
157                                 "than the maximum number of queue pairs "
158                                 "per device.\n");
159                         printf("Lower the number of cores or increase "
160                                 "the number of crypto devices\n");
161                         return -EINVAL;
162                 }
163                 struct rte_cryptodev_config conf = {
164                         .nb_queue_pairs = opts->nb_qps,
165                         .socket_id = socket_id
166                 };
167
168                 struct rte_cryptodev_qp_conf qp_conf = {
169                         .nb_descriptors = opts->nb_descriptors
170                 };
171
172                 if (session_pool_socket[socket_id] == NULL) {
173                         char mp_name[RTE_MEMPOOL_NAMESIZE];
174                         struct rte_mempool *sess_mp;
175
176                         snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
177                                 "sess_mp_%u", socket_id);
178
179                         sess_mp = rte_mempool_create(mp_name,
180                                                 NUM_SESSIONS,
181                                                 max_sess_size,
182                                                 SESS_MEMPOOL_CACHE_SIZE,
183                                                 0, NULL, NULL, NULL,
184                                                 NULL, socket_id,
185                                                 0);
186
187                         if (sess_mp == NULL) {
188                                 printf("Cannot create session pool on socket %d\n",
189                                         socket_id);
190                                 return -ENOMEM;
191                         }
192
193                         printf("Allocated session pool on socket %d\n", socket_id);
194                         session_pool_socket[socket_id] = sess_mp;
195                 }
196
197                 ret = rte_cryptodev_configure(cdev_id, &conf);
198                 if (ret < 0) {
199                         printf("Failed to configure cryptodev %u", cdev_id);
200                         return -EINVAL;
201                 }
202
203                 for (j = 0; j < opts->nb_qps; j++) {
204                         ret = rte_cryptodev_queue_pair_setup(cdev_id, j,
205                                 &qp_conf, socket_id,
206                                 session_pool_socket[socket_id]);
207                         if (ret < 0) {
208                                 printf("Failed to setup queue pair %u on "
209                                         "cryptodev %u", j, cdev_id);
210                                 return -EINVAL;
211                         }
212                 }
213
214                 ret = rte_cryptodev_start(cdev_id);
215                 if (ret < 0) {
216                         printf("Failed to start device %u: error %d\n",
217                                         cdev_id, ret);
218                         return -EPERM;
219                 }
220         }
221
222         return enabled_cdev_count;
223 }
224
225 static int
226 cperf_verify_devices_capabilities(struct cperf_options *opts,
227                 uint8_t *enabled_cdevs, uint8_t nb_cryptodevs)
228 {
229         struct rte_cryptodev_sym_capability_idx cap_idx;
230         const struct rte_cryptodev_symmetric_capability *capability;
231
232         uint8_t i, cdev_id;
233         int ret;
234
235         for (i = 0; i < nb_cryptodevs; i++) {
236
237                 cdev_id = enabled_cdevs[i];
238
239                 if (opts->op_type == CPERF_AUTH_ONLY ||
240                                 opts->op_type == CPERF_CIPHER_THEN_AUTH ||
241                                 opts->op_type == CPERF_AUTH_THEN_CIPHER) {
242
243                         cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
244                         cap_idx.algo.auth = opts->auth_algo;
245
246                         capability = rte_cryptodev_sym_capability_get(cdev_id,
247                                         &cap_idx);
248                         if (capability == NULL)
249                                 return -1;
250
251                         ret = rte_cryptodev_sym_capability_check_auth(
252                                         capability,
253                                         opts->auth_key_sz,
254                                         opts->digest_sz,
255                                         opts->auth_iv_sz);
256                         if (ret != 0)
257                                 return ret;
258                 }
259
260                 if (opts->op_type == CPERF_CIPHER_ONLY ||
261                                 opts->op_type == CPERF_CIPHER_THEN_AUTH ||
262                                 opts->op_type == CPERF_AUTH_THEN_CIPHER) {
263
264                         cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
265                         cap_idx.algo.cipher = opts->cipher_algo;
266
267                         capability = rte_cryptodev_sym_capability_get(cdev_id,
268                                         &cap_idx);
269                         if (capability == NULL)
270                                 return -1;
271
272                         ret = rte_cryptodev_sym_capability_check_cipher(
273                                         capability,
274                                         opts->cipher_key_sz,
275                                         opts->cipher_iv_sz);
276                         if (ret != 0)
277                                 return ret;
278                 }
279
280                 if (opts->op_type == CPERF_AEAD) {
281
282                         cap_idx.type = RTE_CRYPTO_SYM_XFORM_AEAD;
283                         cap_idx.algo.aead = opts->aead_algo;
284
285                         capability = rte_cryptodev_sym_capability_get(cdev_id,
286                                         &cap_idx);
287                         if (capability == NULL)
288                                 return -1;
289
290                         ret = rte_cryptodev_sym_capability_check_aead(
291                                         capability,
292                                         opts->aead_key_sz,
293                                         opts->digest_sz,
294                                         opts->aead_aad_sz,
295                                         opts->aead_iv_sz);
296                         if (ret != 0)
297                                 return ret;
298                 }
299         }
300
301         return 0;
302 }
303
304 static int
305 cperf_check_test_vector(struct cperf_options *opts,
306                 struct cperf_test_vector *test_vec)
307 {
308         if (opts->op_type == CPERF_CIPHER_ONLY) {
309                 if (opts->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
310                         if (test_vec->plaintext.data == NULL)
311                                 return -1;
312                 } else if (opts->cipher_algo != RTE_CRYPTO_CIPHER_NULL) {
313                         if (test_vec->plaintext.data == NULL)
314                                 return -1;
315                         if (test_vec->plaintext.length < opts->max_buffer_size)
316                                 return -1;
317                         if (test_vec->ciphertext.data == NULL)
318                                 return -1;
319                         if (test_vec->ciphertext.length < opts->max_buffer_size)
320                                 return -1;
321                         if (test_vec->cipher_iv.data == NULL)
322                                 return -1;
323                         if (test_vec->cipher_iv.length != opts->cipher_iv_sz)
324                                 return -1;
325                         if (test_vec->cipher_key.data == NULL)
326                                 return -1;
327                         if (test_vec->cipher_key.length != opts->cipher_key_sz)
328                                 return -1;
329                 }
330         } else if (opts->op_type == CPERF_AUTH_ONLY) {
331                 if (opts->auth_algo != RTE_CRYPTO_AUTH_NULL) {
332                         if (test_vec->plaintext.data == NULL)
333                                 return -1;
334                         if (test_vec->plaintext.length < opts->max_buffer_size)
335                                 return -1;
336                         if (test_vec->auth_key.data == NULL)
337                                 return -1;
338                         if (test_vec->auth_key.length != opts->auth_key_sz)
339                                 return -1;
340                         if (test_vec->auth_iv.length != opts->auth_iv_sz)
341                                 return -1;
342                         /* Auth IV is only required for some algorithms */
343                         if (opts->auth_iv_sz && test_vec->auth_iv.data == NULL)
344                                 return -1;
345                         if (test_vec->digest.data == NULL)
346                                 return -1;
347                         if (test_vec->digest.length < opts->digest_sz)
348                                 return -1;
349                 }
350
351         } else if (opts->op_type == CPERF_CIPHER_THEN_AUTH ||
352                         opts->op_type == CPERF_AUTH_THEN_CIPHER) {
353                 if (opts->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
354                         if (test_vec->plaintext.data == NULL)
355                                 return -1;
356                         if (test_vec->plaintext.length < opts->max_buffer_size)
357                                 return -1;
358                 } else if (opts->cipher_algo != RTE_CRYPTO_CIPHER_NULL) {
359                         if (test_vec->plaintext.data == NULL)
360                                 return -1;
361                         if (test_vec->plaintext.length < opts->max_buffer_size)
362                                 return -1;
363                         if (test_vec->ciphertext.data == NULL)
364                                 return -1;
365                         if (test_vec->ciphertext.length < opts->max_buffer_size)
366                                 return -1;
367                         if (test_vec->cipher_iv.data == NULL)
368                                 return -1;
369                         if (test_vec->cipher_iv.length != opts->cipher_iv_sz)
370                                 return -1;
371                         if (test_vec->cipher_key.data == NULL)
372                                 return -1;
373                         if (test_vec->cipher_key.length != opts->cipher_key_sz)
374                                 return -1;
375                 }
376                 if (opts->auth_algo != RTE_CRYPTO_AUTH_NULL) {
377                         if (test_vec->auth_key.data == NULL)
378                                 return -1;
379                         if (test_vec->auth_key.length != opts->auth_key_sz)
380                                 return -1;
381                         if (test_vec->auth_iv.length != opts->auth_iv_sz)
382                                 return -1;
383                         /* Auth IV is only required for some algorithms */
384                         if (opts->auth_iv_sz && test_vec->auth_iv.data == NULL)
385                                 return -1;
386                         if (test_vec->digest.data == NULL)
387                                 return -1;
388                         if (test_vec->digest.length < opts->digest_sz)
389                                 return -1;
390                 }
391         } else if (opts->op_type == CPERF_AEAD) {
392                 if (test_vec->plaintext.data == NULL)
393                         return -1;
394                 if (test_vec->plaintext.length < opts->max_buffer_size)
395                         return -1;
396                 if (test_vec->ciphertext.data == NULL)
397                         return -1;
398                 if (test_vec->ciphertext.length < opts->max_buffer_size)
399                         return -1;
400                 if (test_vec->aead_iv.data == NULL)
401                         return -1;
402                 if (test_vec->aead_iv.length != opts->aead_iv_sz)
403                         return -1;
404                 if (test_vec->aad.data == NULL)
405                         return -1;
406                 if (test_vec->aad.length != opts->aead_aad_sz)
407                         return -1;
408                 if (test_vec->digest.data == NULL)
409                         return -1;
410                 if (test_vec->digest.length < opts->digest_sz)
411                         return -1;
412         }
413         return 0;
414 }
415
416 int
417 main(int argc, char **argv)
418 {
419         struct cperf_options opts = {0};
420         struct cperf_test_vector *t_vec = NULL;
421         struct cperf_op_fns op_fns;
422
423         void *ctx[RTE_MAX_LCORE] = { };
424         struct rte_mempool *session_pool_socket[RTE_MAX_NUMA_NODES] = { 0 };
425
426         int nb_cryptodevs = 0;
427         uint16_t total_nb_qps = 0;
428         uint8_t cdev_id, i;
429         uint8_t enabled_cdevs[RTE_CRYPTO_MAX_DEVS] = { 0 };
430
431         uint8_t buffer_size_idx = 0;
432
433         int ret;
434         uint32_t lcore_id;
435
436         /* Initialise DPDK EAL */
437         ret = rte_eal_init(argc, argv);
438         if (ret < 0)
439                 rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n");
440         argc -= ret;
441         argv += ret;
442
443         cperf_options_default(&opts);
444
445         ret = cperf_options_parse(&opts, argc, argv);
446         if (ret) {
447                 RTE_LOG(ERR, USER1, "Parsing on or more user options failed\n");
448                 goto err;
449         }
450
451         ret = cperf_options_check(&opts);
452         if (ret) {
453                 RTE_LOG(ERR, USER1,
454                                 "Checking on or more user options failed\n");
455                 goto err;
456         }
457
458         nb_cryptodevs = cperf_initialize_cryptodev(&opts, enabled_cdevs,
459                         session_pool_socket);
460
461         if (!opts.silent)
462                 cperf_options_dump(&opts);
463
464         if (nb_cryptodevs < 1) {
465                 RTE_LOG(ERR, USER1, "Failed to initialise requested crypto "
466                                 "device type\n");
467                 nb_cryptodevs = 0;
468                 goto err;
469         }
470
471         ret = cperf_verify_devices_capabilities(&opts, enabled_cdevs,
472                         nb_cryptodevs);
473         if (ret) {
474                 RTE_LOG(ERR, USER1, "Crypto device type does not support "
475                                 "capabilities requested\n");
476                 goto err;
477         }
478
479         if (opts.test_file != NULL) {
480                 t_vec = cperf_test_vector_get_from_file(&opts);
481                 if (t_vec == NULL) {
482                         RTE_LOG(ERR, USER1,
483                                         "Failed to create test vector for"
484                                         " specified file\n");
485                         goto err;
486                 }
487
488                 if (cperf_check_test_vector(&opts, t_vec)) {
489                         RTE_LOG(ERR, USER1, "Incomplete necessary test vectors"
490                                         "\n");
491                         goto err;
492                 }
493         } else {
494                 t_vec = cperf_test_vector_get_dummy(&opts);
495                 if (t_vec == NULL) {
496                         RTE_LOG(ERR, USER1,
497                                         "Failed to create test vector for"
498                                         " specified algorithms\n");
499                         goto err;
500                 }
501         }
502
503         ret = cperf_get_op_functions(&opts, &op_fns);
504         if (ret) {
505                 RTE_LOG(ERR, USER1, "Failed to find function ops set for "
506                                 "specified algorithms combination\n");
507                 goto err;
508         }
509
510         if (!opts.silent)
511                 show_test_vector(t_vec);
512
513         total_nb_qps = nb_cryptodevs * opts.nb_qps;
514
515         i = 0;
516         uint8_t qp_id = 0, cdev_index = 0;
517         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
518
519                 if (i == total_nb_qps)
520                         break;
521
522                 cdev_id = enabled_cdevs[cdev_index];
523
524                 uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
525
526                 ctx[i] = cperf_testmap[opts.test].constructor(
527                                 session_pool_socket[socket_id], cdev_id, qp_id,
528                                 &opts, t_vec, &op_fns);
529                 if (ctx[i] == NULL) {
530                         RTE_LOG(ERR, USER1, "Test run constructor failed\n");
531                         goto err;
532                 }
533                 qp_id = (qp_id + 1) % opts.nb_qps;
534                 if (qp_id == 0)
535                         cdev_index++;
536                 i++;
537         }
538
539         /* Get first size from range or list */
540         if (opts.inc_buffer_size != 0)
541                 opts.test_buffer_size = opts.min_buffer_size;
542         else
543                 opts.test_buffer_size = opts.buffer_size_list[0];
544
545         while (opts.test_buffer_size <= opts.max_buffer_size) {
546                 i = 0;
547                 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
548
549                         if (i == total_nb_qps)
550                                 break;
551
552                         rte_eal_remote_launch(cperf_testmap[opts.test].runner,
553                                 ctx[i], lcore_id);
554                         i++;
555                 }
556                 i = 0;
557                 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
558
559                         if (i == total_nb_qps)
560                                 break;
561                         rte_eal_wait_lcore(lcore_id);
562                         i++;
563                 }
564
565                 /* Get next size from range or list */
566                 if (opts.inc_buffer_size != 0)
567                         opts.test_buffer_size += opts.inc_buffer_size;
568                 else {
569                         if (++buffer_size_idx == opts.buffer_size_count)
570                                 break;
571                         opts.test_buffer_size = opts.buffer_size_list[buffer_size_idx];
572                 }
573         }
574
575         i = 0;
576         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
577
578                 if (i == total_nb_qps)
579                         break;
580
581                 cperf_testmap[opts.test].destructor(ctx[i]);
582                 i++;
583         }
584
585         for (i = 0; i < nb_cryptodevs &&
586                         i < RTE_CRYPTO_MAX_DEVS; i++)
587                 rte_cryptodev_stop(enabled_cdevs[i]);
588
589         free_test_vector(t_vec, &opts);
590
591         printf("\n");
592         return EXIT_SUCCESS;
593
594 err:
595         i = 0;
596         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
597                 if (i == total_nb_qps)
598                         break;
599
600                 cdev_id = enabled_cdevs[i];
601
602                 if (ctx[i] && cperf_testmap[opts.test].destructor)
603                         cperf_testmap[opts.test].destructor(ctx[i]);
604                 i++;
605         }
606
607         for (i = 0; i < nb_cryptodevs &&
608                         i < RTE_CRYPTO_MAX_DEVS; i++)
609                 rte_cryptodev_stop(enabled_cdevs[i]);
610
611         free_test_vector(t_vec, &opts);
612
613         printf("\n");
614         return EXIT_FAILURE;
615 }