ffa7180d5188aae9dbd271536c8b3f23012f29e2
[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
39 #include "cperf.h"
40 #include "cperf_options.h"
41 #include "cperf_test_vector_parsing.h"
42 #include "cperf_test_throughput.h"
43 #include "cperf_test_latency.h"
44 #include "cperf_test_verify.h"
45 #include "cperf_test_pmd_cyclecount.h"
46
47 #define NUM_SESSIONS 2048
48 #define SESS_MEMPOOL_CACHE_SIZE 64
49
50 const char *cperf_test_type_strs[] = {
51         [CPERF_TEST_TYPE_THROUGHPUT] = "throughput",
52         [CPERF_TEST_TYPE_LATENCY] = "latency",
53         [CPERF_TEST_TYPE_VERIFY] = "verify",
54         [CPERF_TEST_TYPE_PMDCC] = "pmd-cyclecount"
55 };
56
57 const char *cperf_op_type_strs[] = {
58         [CPERF_CIPHER_ONLY] = "cipher-only",
59         [CPERF_AUTH_ONLY] = "auth-only",
60         [CPERF_CIPHER_THEN_AUTH] = "cipher-then-auth",
61         [CPERF_AUTH_THEN_CIPHER] = "auth-then-cipher",
62         [CPERF_AEAD] = "aead"
63 };
64
65 const struct cperf_test cperf_testmap[] = {
66                 [CPERF_TEST_TYPE_THROUGHPUT] = {
67                                 cperf_throughput_test_constructor,
68                                 cperf_throughput_test_runner,
69                                 cperf_throughput_test_destructor
70                 },
71                 [CPERF_TEST_TYPE_LATENCY] = {
72                                 cperf_latency_test_constructor,
73                                 cperf_latency_test_runner,
74                                 cperf_latency_test_destructor
75                 },
76                 [CPERF_TEST_TYPE_VERIFY] = {
77                                 cperf_verify_test_constructor,
78                                 cperf_verify_test_runner,
79                                 cperf_verify_test_destructor
80                 },
81                 [CPERF_TEST_TYPE_PMDCC] = {
82                                 cperf_pmd_cyclecount_test_constructor,
83                                 cperf_pmd_cyclecount_test_runner,
84                                 cperf_pmd_cyclecount_test_destructor
85                 }
86 };
87
88 static int
89 cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs,
90                         struct rte_mempool *session_pool_socket[])
91 {
92         uint8_t enabled_cdev_count = 0, nb_lcores, cdev_id;
93         unsigned int i;
94         int ret;
95
96         enabled_cdev_count = rte_cryptodev_devices_get(opts->device_type,
97                         enabled_cdevs, RTE_CRYPTO_MAX_DEVS);
98         if (enabled_cdev_count == 0) {
99                 printf("No crypto devices type %s available\n",
100                                 opts->device_type);
101                 return -EINVAL;
102         }
103
104         nb_lcores = rte_lcore_count() - 1;
105
106         if (enabled_cdev_count > nb_lcores) {
107                 printf("Number of capable crypto devices (%d) "
108                                 "has to be less or equal to number of slave "
109                                 "cores (%d)\n", enabled_cdev_count, nb_lcores);
110                 return -EINVAL;
111         }
112
113         /* Create a mempool shared by all the devices */
114         uint32_t max_sess_size = 0, sess_size;
115
116         for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
117                 sess_size = rte_cryptodev_get_private_session_size(cdev_id);
118                 if (sess_size > max_sess_size)
119                         max_sess_size = sess_size;
120         }
121
122         for (i = 0; i < enabled_cdev_count &&
123                         i < RTE_CRYPTO_MAX_DEVS; i++) {
124                 cdev_id = enabled_cdevs[i];
125                 uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
126
127                 struct rte_cryptodev_config conf = {
128                                 .nb_queue_pairs = 1,
129                                 .socket_id = socket_id
130                 };
131
132                 struct rte_cryptodev_qp_conf qp_conf = {
133                             .nb_descriptors = opts->nb_descriptors
134                 };
135
136
137                 if (session_pool_socket[socket_id] == NULL) {
138                         char mp_name[RTE_MEMPOOL_NAMESIZE];
139                         struct rte_mempool *sess_mp;
140
141                         snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
142                                 "sess_mp_%u", socket_id);
143
144                         sess_mp = rte_mempool_create(mp_name,
145                                                 NUM_SESSIONS,
146                                                 max_sess_size,
147                                                 SESS_MEMPOOL_CACHE_SIZE,
148                                                 0, NULL, NULL, NULL,
149                                                 NULL, socket_id,
150                                                 0);
151
152                         if (sess_mp == NULL) {
153                                 printf("Cannot create session pool on socket %d\n",
154                                         socket_id);
155                                 return -ENOMEM;
156                         }
157
158                         printf("Allocated session pool on socket %d\n", socket_id);
159                         session_pool_socket[socket_id] = sess_mp;
160                 }
161
162                 ret = rte_cryptodev_configure(cdev_id, &conf);
163                 if (ret < 0) {
164                         printf("Failed to configure cryptodev %u", cdev_id);
165                         return -EINVAL;
166                 }
167
168                 ret = rte_cryptodev_queue_pair_setup(cdev_id, 0,
169                                 &qp_conf, socket_id,
170                                 session_pool_socket[socket_id]);
171                         if (ret < 0) {
172                                 printf("Failed to setup queue pair %u on "
173                                         "cryptodev %u", 0, cdev_id);
174                                 return -EINVAL;
175                         }
176
177                 ret = rte_cryptodev_start(cdev_id);
178                 if (ret < 0) {
179                         printf("Failed to start device %u: error %d\n",
180                                         cdev_id, ret);
181                         return -EPERM;
182                 }
183         }
184
185         return enabled_cdev_count;
186 }
187
188 static int
189 cperf_verify_devices_capabilities(struct cperf_options *opts,
190                 uint8_t *enabled_cdevs, uint8_t nb_cryptodevs)
191 {
192         struct rte_cryptodev_sym_capability_idx cap_idx;
193         const struct rte_cryptodev_symmetric_capability *capability;
194
195         uint8_t i, cdev_id;
196         int ret;
197
198         for (i = 0; i < nb_cryptodevs; i++) {
199
200                 cdev_id = enabled_cdevs[i];
201
202                 if (opts->op_type == CPERF_AUTH_ONLY ||
203                                 opts->op_type == CPERF_CIPHER_THEN_AUTH ||
204                                 opts->op_type == CPERF_AUTH_THEN_CIPHER) {
205
206                         cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
207                         cap_idx.algo.auth = opts->auth_algo;
208
209                         capability = rte_cryptodev_sym_capability_get(cdev_id,
210                                         &cap_idx);
211                         if (capability == NULL)
212                                 return -1;
213
214                         ret = rte_cryptodev_sym_capability_check_auth(
215                                         capability,
216                                         opts->auth_key_sz,
217                                         opts->digest_sz,
218                                         opts->auth_iv_sz);
219                         if (ret != 0)
220                                 return ret;
221                 }
222
223                 if (opts->op_type == CPERF_CIPHER_ONLY ||
224                                 opts->op_type == CPERF_CIPHER_THEN_AUTH ||
225                                 opts->op_type == CPERF_AUTH_THEN_CIPHER) {
226
227                         cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
228                         cap_idx.algo.cipher = opts->cipher_algo;
229
230                         capability = rte_cryptodev_sym_capability_get(cdev_id,
231                                         &cap_idx);
232                         if (capability == NULL)
233                                 return -1;
234
235                         ret = rte_cryptodev_sym_capability_check_cipher(
236                                         capability,
237                                         opts->cipher_key_sz,
238                                         opts->cipher_iv_sz);
239                         if (ret != 0)
240                                 return ret;
241                 }
242
243                 if (opts->op_type == CPERF_AEAD) {
244
245                         cap_idx.type = RTE_CRYPTO_SYM_XFORM_AEAD;
246                         cap_idx.algo.aead = opts->aead_algo;
247
248                         capability = rte_cryptodev_sym_capability_get(cdev_id,
249                                         &cap_idx);
250                         if (capability == NULL)
251                                 return -1;
252
253                         ret = rte_cryptodev_sym_capability_check_aead(
254                                         capability,
255                                         opts->aead_key_sz,
256                                         opts->digest_sz,
257                                         opts->aead_aad_sz,
258                                         opts->aead_iv_sz);
259                         if (ret != 0)
260                                 return ret;
261                 }
262         }
263
264         return 0;
265 }
266
267 static int
268 cperf_check_test_vector(struct cperf_options *opts,
269                 struct cperf_test_vector *test_vec)
270 {
271         if (opts->op_type == CPERF_CIPHER_ONLY) {
272                 if (opts->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
273                         if (test_vec->plaintext.data == NULL)
274                                 return -1;
275                 } else if (opts->cipher_algo != RTE_CRYPTO_CIPHER_NULL) {
276                         if (test_vec->plaintext.data == NULL)
277                                 return -1;
278                         if (test_vec->plaintext.length < opts->max_buffer_size)
279                                 return -1;
280                         if (test_vec->ciphertext.data == NULL)
281                                 return -1;
282                         if (test_vec->ciphertext.length < opts->max_buffer_size)
283                                 return -1;
284                         if (test_vec->cipher_iv.data == NULL)
285                                 return -1;
286                         if (test_vec->cipher_iv.length != opts->cipher_iv_sz)
287                                 return -1;
288                         if (test_vec->cipher_key.data == NULL)
289                                 return -1;
290                         if (test_vec->cipher_key.length != opts->cipher_key_sz)
291                                 return -1;
292                 }
293         } else if (opts->op_type == CPERF_AUTH_ONLY) {
294                 if (opts->auth_algo != RTE_CRYPTO_AUTH_NULL) {
295                         if (test_vec->plaintext.data == NULL)
296                                 return -1;
297                         if (test_vec->plaintext.length < opts->max_buffer_size)
298                                 return -1;
299                         if (test_vec->auth_key.data == NULL)
300                                 return -1;
301                         if (test_vec->auth_key.length != opts->auth_key_sz)
302                                 return -1;
303                         if (test_vec->auth_iv.length != opts->auth_iv_sz)
304                                 return -1;
305                         /* Auth IV is only required for some algorithms */
306                         if (opts->auth_iv_sz && test_vec->auth_iv.data == NULL)
307                                 return -1;
308                         if (test_vec->digest.data == NULL)
309                                 return -1;
310                         if (test_vec->digest.length < opts->digest_sz)
311                                 return -1;
312                 }
313
314         } else if (opts->op_type == CPERF_CIPHER_THEN_AUTH ||
315                         opts->op_type == CPERF_AUTH_THEN_CIPHER) {
316                 if (opts->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
317                         if (test_vec->plaintext.data == NULL)
318                                 return -1;
319                         if (test_vec->plaintext.length < opts->max_buffer_size)
320                                 return -1;
321                 } else if (opts->cipher_algo != RTE_CRYPTO_CIPHER_NULL) {
322                         if (test_vec->plaintext.data == NULL)
323                                 return -1;
324                         if (test_vec->plaintext.length < opts->max_buffer_size)
325                                 return -1;
326                         if (test_vec->ciphertext.data == NULL)
327                                 return -1;
328                         if (test_vec->ciphertext.length < opts->max_buffer_size)
329                                 return -1;
330                         if (test_vec->cipher_iv.data == NULL)
331                                 return -1;
332                         if (test_vec->cipher_iv.length != opts->cipher_iv_sz)
333                                 return -1;
334                         if (test_vec->cipher_key.data == NULL)
335                                 return -1;
336                         if (test_vec->cipher_key.length != opts->cipher_key_sz)
337                                 return -1;
338                 }
339                 if (opts->auth_algo != RTE_CRYPTO_AUTH_NULL) {
340                         if (test_vec->auth_key.data == NULL)
341                                 return -1;
342                         if (test_vec->auth_key.length != opts->auth_key_sz)
343                                 return -1;
344                         if (test_vec->auth_iv.length != opts->auth_iv_sz)
345                                 return -1;
346                         /* Auth IV is only required for some algorithms */
347                         if (opts->auth_iv_sz && test_vec->auth_iv.data == NULL)
348                                 return -1;
349                         if (test_vec->digest.data == NULL)
350                                 return -1;
351                         if (test_vec->digest.length < opts->digest_sz)
352                                 return -1;
353                 }
354         } else if (opts->op_type == CPERF_AEAD) {
355                 if (test_vec->plaintext.data == NULL)
356                         return -1;
357                 if (test_vec->plaintext.length < opts->max_buffer_size)
358                         return -1;
359                 if (test_vec->ciphertext.data == NULL)
360                         return -1;
361                 if (test_vec->ciphertext.length < opts->max_buffer_size)
362                         return -1;
363                 if (test_vec->aead_iv.data == NULL)
364                         return -1;
365                 if (test_vec->aead_iv.length != opts->aead_iv_sz)
366                         return -1;
367                 if (test_vec->aad.data == NULL)
368                         return -1;
369                 if (test_vec->aad.length != opts->aead_aad_sz)
370                         return -1;
371                 if (test_vec->digest.data == NULL)
372                         return -1;
373                 if (test_vec->digest.length < opts->digest_sz)
374                         return -1;
375         }
376         return 0;
377 }
378
379 int
380 main(int argc, char **argv)
381 {
382         struct cperf_options opts = {0};
383         struct cperf_test_vector *t_vec = NULL;
384         struct cperf_op_fns op_fns;
385
386         void *ctx[RTE_MAX_LCORE] = { };
387         struct rte_mempool *session_pool_socket[RTE_MAX_NUMA_NODES] = { 0 };
388
389         int nb_cryptodevs = 0;
390         uint8_t cdev_id, i;
391         uint8_t enabled_cdevs[RTE_CRYPTO_MAX_DEVS] = { 0 };
392
393         uint8_t buffer_size_idx = 0;
394
395         int ret;
396         uint32_t lcore_id;
397
398         /* Initialise DPDK EAL */
399         ret = rte_eal_init(argc, argv);
400         if (ret < 0)
401                 rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n");
402         argc -= ret;
403         argv += ret;
404
405         cperf_options_default(&opts);
406
407         ret = cperf_options_parse(&opts, argc, argv);
408         if (ret) {
409                 RTE_LOG(ERR, USER1, "Parsing on or more user options failed\n");
410                 goto err;
411         }
412
413         ret = cperf_options_check(&opts);
414         if (ret) {
415                 RTE_LOG(ERR, USER1,
416                                 "Checking on or more user options failed\n");
417                 goto err;
418         }
419
420         if (!opts.silent)
421                 cperf_options_dump(&opts);
422
423         nb_cryptodevs = cperf_initialize_cryptodev(&opts, enabled_cdevs,
424                         session_pool_socket);
425         if (nb_cryptodevs < 1) {
426                 RTE_LOG(ERR, USER1, "Failed to initialise requested crypto "
427                                 "device type\n");
428                 nb_cryptodevs = 0;
429                 goto err;
430         }
431
432         ret = cperf_verify_devices_capabilities(&opts, enabled_cdevs,
433                         nb_cryptodevs);
434         if (ret) {
435                 RTE_LOG(ERR, USER1, "Crypto device type does not support "
436                                 "capabilities requested\n");
437                 goto err;
438         }
439
440         if (opts.test_file != NULL) {
441                 t_vec = cperf_test_vector_get_from_file(&opts);
442                 if (t_vec == NULL) {
443                         RTE_LOG(ERR, USER1,
444                                         "Failed to create test vector for"
445                                         " specified file\n");
446                         goto err;
447                 }
448
449                 if (cperf_check_test_vector(&opts, t_vec)) {
450                         RTE_LOG(ERR, USER1, "Incomplete necessary test vectors"
451                                         "\n");
452                         goto err;
453                 }
454         } else {
455                 t_vec = cperf_test_vector_get_dummy(&opts);
456                 if (t_vec == NULL) {
457                         RTE_LOG(ERR, USER1,
458                                         "Failed to create test vector for"
459                                         " specified algorithms\n");
460                         goto err;
461                 }
462         }
463
464         ret = cperf_get_op_functions(&opts, &op_fns);
465         if (ret) {
466                 RTE_LOG(ERR, USER1, "Failed to find function ops set for "
467                                 "specified algorithms combination\n");
468                 goto err;
469         }
470
471         if (!opts.silent)
472                 show_test_vector(t_vec);
473
474         i = 0;
475         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
476
477                 if (i == nb_cryptodevs)
478                         break;
479
480                 cdev_id = enabled_cdevs[i];
481
482                 uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
483
484                 ctx[cdev_id] = cperf_testmap[opts.test].constructor(
485                                 session_pool_socket[socket_id], cdev_id, 0,
486                                 &opts, t_vec, &op_fns);
487                 if (ctx[cdev_id] == NULL) {
488                         RTE_LOG(ERR, USER1, "Test run constructor failed\n");
489                         goto err;
490                 }
491                 i++;
492         }
493
494         /* Get first size from range or list */
495         if (opts.inc_buffer_size != 0)
496                 opts.test_buffer_size = opts.min_buffer_size;
497         else
498                 opts.test_buffer_size = opts.buffer_size_list[0];
499
500         while (opts.test_buffer_size <= opts.max_buffer_size) {
501                 i = 0;
502                 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
503
504                         if (i == nb_cryptodevs)
505                                 break;
506
507                         cdev_id = enabled_cdevs[i];
508
509                         rte_eal_remote_launch(cperf_testmap[opts.test].runner,
510                                 ctx[cdev_id], lcore_id);
511                         i++;
512                 }
513                 i = 0;
514                 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
515
516                         if (i == nb_cryptodevs)
517                                 break;
518                         rte_eal_wait_lcore(lcore_id);
519                         i++;
520                 }
521
522                 /* Get next size from range or list */
523                 if (opts.inc_buffer_size != 0)
524                         opts.test_buffer_size += opts.inc_buffer_size;
525                 else {
526                         if (++buffer_size_idx == opts.buffer_size_count)
527                                 break;
528                         opts.test_buffer_size = opts.buffer_size_list[buffer_size_idx];
529                 }
530         }
531
532         i = 0;
533         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
534
535                 if (i == nb_cryptodevs)
536                         break;
537
538                 cdev_id = enabled_cdevs[i];
539
540                 cperf_testmap[opts.test].destructor(ctx[cdev_id]);
541                 i++;
542         }
543
544         free_test_vector(t_vec, &opts);
545
546         printf("\n");
547         return EXIT_SUCCESS;
548
549 err:
550         i = 0;
551         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
552                 if (i == nb_cryptodevs)
553                         break;
554
555                 cdev_id = enabled_cdevs[i];
556
557                 if (ctx[cdev_id] && cperf_testmap[opts.test].destructor)
558                         cperf_testmap[opts.test].destructor(ctx[cdev_id]);
559                 i++;
560         }
561
562         free_test_vector(t_vec, &opts);
563
564         printf("\n");
565         return EXIT_FAILURE;
566 }