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