3bc06593742824cc8ece6c6891b742e5607f220b
[vpp.git] / src / plugins / unittest / crypto_test.c
1 /*
2  * Copyright (c) 2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vlib/vlib.h>
16 #include <vppinfra/time.h>
17 #include <vppinfra/cache.h>
18 #include <vppinfra/error.h>
19 #include <vnet/crypto/crypto.h>
20 #include <unittest/crypto/crypto.h>
21
22 crypto_test_main_t crypto_test_main;
23
24 static int
25 sort_registrations (void *a0, void *a1)
26 {
27   unittest_crypto_test_registration_t **r0 = a0;
28   unittest_crypto_test_registration_t **r1 = a1;
29
30   return (strncmp (r0[0]->name, r1[0]->name, 256));
31 }
32
33 static void
34 print_results (vlib_main_t * vm, unittest_crypto_test_registration_t ** rv,
35                vnet_crypto_op_t * ops, vnet_crypto_op_chunk_t * chunks,
36                u32 n_ops, int verbose)
37 {
38   int i;
39   unittest_crypto_test_registration_t *r;
40   vnet_crypto_op_chunk_t *chp;
41   u8 *s = 0, *err = 0;
42   vnet_crypto_op_t *op;
43
44   vec_foreach (op, ops)
45   {
46     int fail = 0;
47     r = rv[op->user_data];
48     unittest_crypto_test_data_t *exp_pt = 0, *exp_ct = 0;
49     unittest_crypto_test_data_t *exp_digest = 0, *exp_tag = 0;
50     unittest_crypto_test_data_t *exp_pt_chunks = 0, *exp_ct_chunks = 0;
51
52     switch (vnet_crypto_get_op_type (op->op))
53       {
54       case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
55         exp_tag = &r->tag;
56         /* fall through */
57       case VNET_CRYPTO_OP_TYPE_ENCRYPT:
58         exp_ct = &r->ciphertext;
59         exp_ct_chunks = r->ct_chunks;
60         break;
61       case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
62       case VNET_CRYPTO_OP_TYPE_DECRYPT:
63         exp_pt = &r->plaintext;
64         exp_pt_chunks = r->pt_chunks;
65         break;
66       case VNET_CRYPTO_OP_TYPE_HMAC:
67         exp_digest = &r->digest;
68         break;
69       default:
70         ASSERT (0);
71       }
72
73     vec_reset_length (err);
74
75     if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
76       err = format (err, "%sengine error: %U", vec_len (err) ? ", " : "",
77                     format_vnet_crypto_op_status, op->status);
78
79     if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS)
80       {
81         if (exp_ct_chunks)
82           {
83             chp = vec_elt_at_index (chunks, op->chunk_index);
84             for (i = 0; i < op->n_chunks; i++)
85               {
86                 if (memcmp (chp->dst, exp_ct_chunks[i].data, chp->len))
87                   err = format (err, "%sciphertext mismatch [chunk %d]",
88                                 vec_len (err) ? ", " : "", i);
89                 chp += 1;
90               }
91           }
92
93         if (exp_pt_chunks)
94           {
95             chp = vec_elt_at_index (chunks, op->chunk_index);
96             for (i = 0; i < op->n_chunks; i++)
97               {
98                 if (memcmp (chp->dst, exp_pt_chunks[i].data, chp->len))
99                   err = format (err, "%splaintext mismatch [chunk %d]",
100                                 vec_len (err) ? ", " : "", i);
101                 chp += 1;
102               }
103           }
104       }
105     else
106       {
107         if (exp_ct && memcmp (op->dst, exp_ct->data, exp_ct->length) != 0)
108           err = format (err, "%sciphertext mismatch",
109                         vec_len (err) ? ", " : "");
110
111         if (exp_pt && memcmp (op->dst, exp_pt->data, exp_pt->length) != 0)
112           err = format (err, "%splaintext mismatch",
113                         vec_len (err) ? ", " : "");
114       }
115
116     if (exp_tag && memcmp (op->tag, exp_tag->data, exp_tag->length) != 0)
117       err = format (err, "%stag mismatch", vec_len (err) ? ", " : "");
118
119     if (exp_digest &&
120         memcmp (op->digest, exp_digest->data, exp_digest->length) != 0)
121       err = format (err, "%sdigest mismatch", vec_len (err) ? ", " : "");
122
123     vec_reset_length (s);
124     s = format (s, "%s (%U)", r->name, format_vnet_crypto_op, op->op,
125                 r->is_chained);
126
127     if (vec_len (err))
128       fail = 1;
129
130     vlib_cli_output (vm, "%-60v%s%v", s, vec_len (err) ? "FAIL: " : "OK",
131                      err);
132     if (verbose)
133       {
134         if (verbose == 2)
135           fail = 1;
136
137         if (exp_ct && fail)
138           vlib_cli_output (vm, "Expected ciphertext:\n%U"
139                            "\nCalculated ciphertext:\n%U",
140                            format_hexdump, exp_ct->data, exp_ct->length,
141                            format_hexdump, op->dst, exp_ct->length);
142         if (exp_pt && fail)
143           vlib_cli_output (vm, "Expected plaintext:\n%U"
144                            "\nCalculated plaintext:\n%U",
145                            format_hexdump, exp_pt->data, exp_pt->length,
146                            format_hexdump, op->dst, exp_pt->length);
147         if (r->tag.length && fail)
148           vlib_cli_output (vm, "Expected tag:\n%U"
149                            "\nCalculated tag:\n%U",
150                            format_hexdump, r->tag.data, r->tag.length,
151                            format_hexdump, op->tag, op->tag_len);
152         if (exp_digest && fail)
153           vlib_cli_output (vm, "Expected digest:\n%U"
154                            "\nCalculated Digest:\n%U",
155                            format_hexdump, exp_digest->data,
156                            exp_digest->length, format_hexdump, op->digest,
157                            op->digest_len);
158       }
159   }
160   vec_free (err);
161   vec_free (s);
162 }
163
164 static clib_error_t *
165 test_crypto (vlib_main_t * vm, crypto_test_main_t * tm)
166 {
167   vnet_crypto_main_t *cm = &crypto_main;
168   unittest_crypto_test_registration_t *r = tm->test_registrations;
169   unittest_crypto_test_registration_t **rv = 0;
170   vnet_crypto_alg_data_t *ad;
171   vnet_crypto_op_t *ops = 0, *op, *chained_ops = 0;
172   vnet_crypto_op_t *current_chained_op = 0, *current_op = 0;
173   vnet_crypto_op_chunk_t *chunks = 0, ch;
174   vnet_crypto_key_index_t *key_indices = 0;
175   u8 *computed_data = 0;
176   u32 computed_data_total_len = 0, n_ops = 0, n_chained_ops = 0;
177   unittest_crypto_test_data_t *pt, *ct;
178   u32 i, j;
179
180   /* construct registration vector */
181   while (r)
182     {
183       vec_add1 (rv, r);
184       ad = vec_elt_at_index (cm->algs, r->alg);
185
186       for (i = 0; i < VNET_CRYPTO_OP_N_TYPES; i++)
187         {
188           vnet_crypto_op_id_t id = ad->op_by_type[i];
189
190           if (id == 0)
191             continue;
192
193           switch (i)
194             {
195             case VNET_CRYPTO_OP_TYPE_ENCRYPT:
196             case VNET_CRYPTO_OP_TYPE_DECRYPT:
197             case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
198               if (r->is_chained)
199                 {
200                   ct = r->ct_chunks;
201                   j = 0;
202                   while (ct->data)
203                     {
204                       if (j > CRYPTO_TEST_MAX_OP_CHUNKS)
205                         return clib_error_return (0,
206                                                   "test case '%s' exceeds extra data!",
207                                                   r->name);
208                       computed_data_total_len += ct->length;
209                       ct++;
210                       j++;
211                     }
212                   n_chained_ops += 1;
213                 }
214               else
215                 {
216                   computed_data_total_len += r->ciphertext.length;
217                   n_ops += 1;
218                 }
219               break;
220             case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
221               computed_data_total_len += r->ciphertext.length;
222               computed_data_total_len += r->tag.length;
223               if (r->is_chained)
224                 {
225                   ct = r->ct_chunks;
226                   j = 0;
227                   while (ct->data)
228                     {
229                       if (j > CRYPTO_TEST_MAX_OP_CHUNKS)
230                         return clib_error_return (0,
231                                                   "test case '%s' exceeds extra data!",
232                                                   r->name);
233                       computed_data_total_len += ct->length;
234                       ct++;
235                       j++;
236                     }
237                   n_chained_ops += 1;
238                 }
239               else
240                 n_ops += 1;
241               break;
242             case VNET_CRYPTO_OP_TYPE_HMAC:
243               computed_data_total_len += r->digest.length;
244               if (r->is_chained)
245                 n_chained_ops += 1;
246               else
247                 n_ops += 1;
248               break;
249             default:
250               break;
251             };
252         }
253
254       /* next */
255       r = r->next;
256     }
257
258   /* no tests registered */
259   if (n_ops == 0)
260     return 0;
261
262   vec_sort_with_function (rv, sort_registrations);
263
264   vec_validate_aligned (computed_data, computed_data_total_len - 1,
265                         CLIB_CACHE_LINE_BYTES);
266   vec_validate_aligned (ops, n_ops - 1, CLIB_CACHE_LINE_BYTES);
267   vec_validate_aligned (chained_ops, n_chained_ops - 1,
268                         CLIB_CACHE_LINE_BYTES);
269   computed_data_total_len = 0;
270
271   current_op = ops;
272   current_chained_op = chained_ops;
273   /* *INDENT-OFF* */
274   vec_foreach_index (i, rv)
275     {
276       r = rv[i];
277       int t;
278       ad = vec_elt_at_index (cm->algs, r->alg);
279       for (t = 0; t < VNET_CRYPTO_OP_N_TYPES; t++)
280         {
281           vnet_crypto_op_id_t id = ad->op_by_type[t];
282
283           if (id == 0)
284             continue;
285
286           if (r->is_chained)
287           {
288             op = current_chained_op;
289             current_chained_op += 1;
290           }
291           else
292           {
293             op = current_op;
294             current_op += 1;
295           }
296
297           vnet_crypto_op_init (op, id);
298
299           switch (t)
300             {
301             case VNET_CRYPTO_OP_TYPE_ENCRYPT:
302             case VNET_CRYPTO_OP_TYPE_DECRYPT:
303               op->iv = r->iv.data;
304               op->key_index = vnet_crypto_key_add (vm, r->alg,
305                                                    r->key.data,
306                                                    r->key.length);
307               vec_add1 (key_indices, op->key_index);
308
309               if (r->is_chained)
310               {
311               pt = r->pt_chunks;
312               ct = r->ct_chunks;
313               op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
314               op->chunk_index = vec_len (chunks);
315               while (pt->data)
316                 {
317                   ch.src = t == VNET_CRYPTO_OP_TYPE_ENCRYPT ?
318                     pt->data : ct->data;
319                   ch.len = pt->length;
320                   ch.dst = computed_data + computed_data_total_len;
321                   computed_data_total_len += pt->length;
322                   vec_add1 (chunks, ch);
323                   op->n_chunks++;
324                   pt++;
325                   ct++;
326                 }
327               }
328               else
329               {
330               op->len = r->plaintext.length;
331               op->src = t == VNET_CRYPTO_OP_TYPE_ENCRYPT ?
332                 r->plaintext.data : r->ciphertext.data;
333               op->dst = computed_data + computed_data_total_len;
334               computed_data_total_len += r->ciphertext.length;
335               }
336               break;
337             case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
338             case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
339               if (r->is_chained)
340               {
341               op->iv = r->iv.data;
342               op->key_index = vnet_crypto_key_add (vm, r->alg,
343                                                    r->key.data,
344                                                    r->key.length);
345               vec_add1 (key_indices, op->key_index);
346               op->aad = r->aad.data;
347               op->aad_len = r->aad.length;
348               if (t == VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT)
349                 {
350                   pt = r->pt_chunks;
351                   op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
352                   op->chunk_index = vec_len (chunks);
353                   while (pt->data)
354                     {
355                       ch.src = pt->data;
356                       ch.len = pt->length;
357                       ch.dst = computed_data + computed_data_total_len;
358                       computed_data_total_len += pt->length;
359                       vec_add1 (chunks, ch);
360                       op->n_chunks++;
361                       pt++;
362                     }
363                   op->tag = computed_data + computed_data_total_len;
364                   computed_data_total_len += r->tag.length;
365                 }
366               else
367                 {
368                   ct = r->ct_chunks;
369                   op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
370                   op->chunk_index = vec_len (chunks);
371                   while (ct->data)
372                     {
373                       ch.src = ct->data;
374                       ch.len = ct->length;
375                       ch.dst = computed_data + computed_data_total_len;
376                       computed_data_total_len += ct->length;
377                       vec_add1 (chunks, ch);
378                       op->n_chunks++;
379                       ct++;
380                     }
381                   op->tag = r->tag.data;
382                 }
383               op->tag_len = r->tag.length;
384               }
385               else
386               {
387               op->iv = r->iv.data;
388               op->key_index = vnet_crypto_key_add (vm, r->alg,
389                                                    r->key.data,
390                                                    r->key.length);
391               vec_add1 (key_indices, op->key_index);
392               op->aad = r->aad.data;
393               op->aad_len = r->aad.length;
394               op->len = r->plaintext.length;
395               op->dst = computed_data + computed_data_total_len;
396               computed_data_total_len += r->ciphertext.length;
397
398               if (t == VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT)
399                 {
400                   op->src = r->plaintext.data;
401                   op->tag = computed_data + computed_data_total_len;
402                   computed_data_total_len += r->tag.length;
403                 }
404               else
405                 {
406                   op->tag = r->tag.data;
407                   op->src = r->ciphertext.data;
408                 }
409               op->tag_len = r->tag.length;
410               }
411               break;
412             case VNET_CRYPTO_OP_TYPE_HMAC:
413               if (r->is_chained)
414               {
415               op->key_index = vnet_crypto_key_add (vm, r->alg,
416                                                    r->key.data,
417                                                    r->key.length);
418               vec_add1 (key_indices, op->key_index);
419               op->digest_len = r->digest.length;
420               op->digest = computed_data + computed_data_total_len;
421               computed_data_total_len += r->digest.length;
422               pt = r->pt_chunks;
423               op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
424               op->chunk_index = vec_len (chunks);
425               while (pt->data)
426                 {
427                   ch.src = pt->data;
428                   ch.len = pt->length;
429                   vec_add1 (chunks, ch);
430                   op->n_chunks++;
431                   pt++;
432                 }
433               }
434               else
435               {
436               op->key_index = vnet_crypto_key_add (vm, r->alg,
437                                                    r->key.data,
438                                                    r->key.length);
439               vec_add1 (key_indices, op->key_index);
440               op->digest_len = r->digest.length;
441               op->digest = computed_data + computed_data_total_len;
442               computed_data_total_len += r->digest.length;
443               op->src = r->plaintext.data;
444               op->len = r->plaintext.length;
445               }
446               break;
447             default:
448               break;
449             };
450
451           op->user_data = i;
452         }
453     }
454   /* *INDENT-ON* */
455
456   vnet_crypto_process_ops (vm, ops, vec_len (ops));
457   vnet_crypto_process_chained_ops (vm, chained_ops, chunks,
458                                    vec_len (chained_ops));
459
460   print_results (vm, rv, ops, chunks, vec_len (ops), tm->verbose);
461   print_results (vm, rv, chained_ops, chunks, vec_len (chained_ops),
462                  tm->verbose);
463
464   vec_foreach_index (i, key_indices) vnet_crypto_key_del (vm, key_indices[i]);
465
466   vec_free (computed_data);
467   vec_free (ops);
468   vec_free (chained_ops);
469   vec_free (chunks);
470   vec_free (rv);
471   return 0;
472 }
473
474 static u32
475 test_crypto_get_key_sz (vnet_crypto_alg_t alg)
476 {
477   switch (alg)
478     {
479 #define _(n, s, l) \
480   case VNET_CRYPTO_ALG_##n: \
481     return l;
482   /* *INDENT-OFF* */
483   foreach_crypto_cipher_alg
484   foreach_crypto_aead_alg
485   /* *INDENT-ON* */
486 #undef _
487     case VNET_CRYPTO_ALG_HMAC_MD5:
488     case VNET_CRYPTO_ALG_HMAC_SHA1:
489       return 20;
490     case VNET_CRYPTO_ALG_HMAC_SHA224:
491       return 28;
492     case VNET_CRYPTO_ALG_HMAC_SHA256:
493       return 32;
494     case VNET_CRYPTO_ALG_HMAC_SHA384:
495       return 48;
496     case VNET_CRYPTO_ALG_HMAC_SHA512:
497       return 64;
498     default:
499       return 0;
500     }
501
502   return 0;
503 }
504
505 static clib_error_t *
506 test_crypto_perf (vlib_main_t * vm, crypto_test_main_t * tm)
507 {
508   vnet_crypto_main_t *cm = &crypto_main;
509   clib_error_t *err = 0;
510   u32 n_buffers, n_alloc = 0, warmup_rounds, rounds;
511   u32 *buffer_indices = 0;
512   vnet_crypto_op_t *ops1 = 0, *ops2 = 0, *op1, *op2;
513   vnet_crypto_alg_data_t *ad = vec_elt_at_index (cm->algs, tm->alg);
514   vnet_crypto_key_index_t key_index = ~0;
515   u8 key[32];
516   int buffer_size = vlib_buffer_get_default_data_size (vm);
517   u64 seed = clib_cpu_time_now ();
518   u64 t0[5], t1[5], t2[5], n_bytes = 0;
519   int i, j;
520
521   if (tm->buffer_size > buffer_size)
522     return clib_error_return (0, "buffer size must be <= %u", buffer_size);
523
524   rounds = tm->rounds ? tm->rounds : 100;
525   n_buffers = tm->n_buffers ? tm->n_buffers : 256;
526   buffer_size = tm->buffer_size ? tm->buffer_size : 2048;
527   warmup_rounds = tm->warmup_rounds ? tm->warmup_rounds : 100;
528
529   if (buffer_size > vlib_buffer_get_default_data_size (vm))
530     return clib_error_return (0, "buffer size too big");
531
532   vec_validate_aligned (buffer_indices, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
533   vec_validate_aligned (ops1, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
534   vec_validate_aligned (ops2, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
535
536   n_alloc = vlib_buffer_alloc (vm, buffer_indices, n_buffers);
537   if (n_alloc != n_buffers)
538     {
539       if (n_alloc)
540         vlib_buffer_free (vm, buffer_indices, n_alloc);
541       err = clib_error_return (0, "buffer alloc failure");
542       goto done;
543     }
544
545   vlib_cli_output (vm, "%U: n_buffers %u buffer-size %u rounds %u "
546                    "warmup-rounds %u",
547                    format_vnet_crypto_alg, tm->alg, n_buffers, buffer_size,
548                    rounds, warmup_rounds);
549   vlib_cli_output (vm, "   cpu-freq %.2f GHz",
550                    (f64) vm->clib_time.clocks_per_second * 1e-9);
551
552   vnet_crypto_op_type_t ot = 0;
553
554   for (i = 0; i < sizeof (key); i++)
555     key[i] = i;
556
557   key_index = vnet_crypto_key_add (vm, tm->alg, key,
558                                    test_crypto_get_key_sz (tm->alg));
559
560   for (i = 0; i < VNET_CRYPTO_OP_N_TYPES; i++)
561     {
562       vnet_crypto_op_id_t id = ad->op_by_type[i];
563       if (id == 0)
564         continue;
565       ot = i;
566       break;
567     }
568
569   for (i = 0; i < n_buffers; i++)
570     {
571       vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
572       op1 = ops1 + i;
573       op2 = ops2 + i;
574
575       switch (ot)
576         {
577         case VNET_CRYPTO_OP_TYPE_ENCRYPT:
578         case VNET_CRYPTO_OP_TYPE_DECRYPT:
579           vnet_crypto_op_init (op1,
580                                ad->op_by_type[VNET_CRYPTO_OP_TYPE_ENCRYPT]);
581           vnet_crypto_op_init (op2,
582                                ad->op_by_type[VNET_CRYPTO_OP_TYPE_DECRYPT]);
583           op1->flags = VNET_CRYPTO_OP_FLAG_INIT_IV;
584           op1->src = op2->src = op1->dst = op2->dst = b->data;
585           op1->key_index = op2->key_index = key_index;
586           op1->iv = op2->iv = b->data - 64;
587           n_bytes += op1->len = op2->len = buffer_size;
588           break;
589         case VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT:
590         case VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT:
591           vnet_crypto_op_init (op1,
592                                ad->op_by_type
593                                [VNET_CRYPTO_OP_TYPE_AEAD_ENCRYPT]);
594           vnet_crypto_op_init (op2,
595                                ad->op_by_type
596                                [VNET_CRYPTO_OP_TYPE_AEAD_DECRYPT]);
597           op1->src = op2->src = op1->dst = op2->dst = b->data;
598           op1->key_index = op2->key_index = key_index;
599           op1->tag = op2->tag = b->data - 32;
600           op1->iv = op2->iv = b->data - 64;
601           op1->aad = op2->aad = b->data - VLIB_BUFFER_PRE_DATA_SIZE;
602           op1->aad_len = op2->aad_len = 64;
603           op1->tag_len = op2->tag_len = 16;
604           n_bytes += op1->len = op2->len = buffer_size;
605           break;
606         case VNET_CRYPTO_OP_TYPE_HMAC:
607           vnet_crypto_op_init (op1, ad->op_by_type[VNET_CRYPTO_OP_TYPE_HMAC]);
608           op1->src = b->data;
609           op1->key_index = key_index;
610           op1->iv = 0;
611           op1->digest = b->data - VLIB_BUFFER_PRE_DATA_SIZE;
612           op1->digest_len = 0;
613           n_bytes += op1->len = buffer_size;
614           break;
615         default:
616           return 0;
617         }
618
619       for (j = -VLIB_BUFFER_PRE_DATA_SIZE; j < buffer_size; j += 8)
620         *(u64 *) (b->data + j) = 1 + random_u64 (&seed);
621     }
622
623   for (i = 0; i < 5; i++)
624     {
625       for (j = 0; j < warmup_rounds; j++)
626         {
627           vnet_crypto_process_ops (vm, ops1, n_buffers);
628           if (ot != VNET_CRYPTO_OP_TYPE_HMAC)
629             vnet_crypto_process_ops (vm, ops2, n_buffers);
630         }
631
632       t0[i] = clib_cpu_time_now ();
633       for (j = 0; j < rounds; j++)
634         vnet_crypto_process_ops (vm, ops1, n_buffers);
635       t1[i] = clib_cpu_time_now ();
636
637       if (ot != VNET_CRYPTO_OP_TYPE_HMAC)
638         {
639           for (j = 0; j < rounds; j++)
640             vnet_crypto_process_ops (vm, ops2, n_buffers);
641           t2[i] = clib_cpu_time_now ();
642         }
643     }
644
645   for (i = 0; i < 5; i++)
646     {
647       f64 tpb1 = (f64) (t1[i] - t0[i]) / (n_bytes * rounds);
648       f64 gbps1 = vm->clib_time.clocks_per_second * 1e-9 * 8 / tpb1;
649       f64 tpb2, gbps2;
650
651       if (ot != VNET_CRYPTO_OP_TYPE_HMAC)
652         {
653           tpb2 = (f64) (t2[i] - t1[i]) / (n_bytes * rounds);
654           gbps2 = vm->clib_time.clocks_per_second * 1e-9 * 8 / tpb2;
655           vlib_cli_output (vm, "%-2u: encrypt %.03f ticks/byte, %.02f Gbps; "
656                            "decrypt %.03f ticks/byte, %.02f Gbps",
657                            i + 1, tpb1, gbps1, tpb2, gbps2);
658         }
659       else
660         {
661           vlib_cli_output (vm, "%-2u: hash %.03f ticks/byte, %.02f Gbps\n",
662                            i + 1, tpb1, gbps1);
663         }
664     }
665
666 done:
667   if (n_alloc)
668     vlib_buffer_free (vm, buffer_indices, n_alloc);
669
670   if (key_index != ~0)
671     vnet_crypto_key_del (vm, key_index);
672
673   vec_free (buffer_indices);
674   vec_free (ops1);
675   vec_free (ops2);
676   return err;
677 }
678
679 static clib_error_t *
680 test_crypto_command_fn (vlib_main_t * vm,
681                         unformat_input_t * input, vlib_cli_command_t * cmd)
682 {
683   crypto_test_main_t *tm = &crypto_test_main;
684   unittest_crypto_test_registration_t *tr;
685   int is_perf = 0;
686
687   tr = tm->test_registrations;
688   memset (tm, 0, sizeof (crypto_test_main_t));
689   tm->test_registrations = tr;
690   tm->alg = ~0;
691
692   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
693     {
694       if (unformat (input, "verbose"))
695         tm->verbose = 1;
696       else if (unformat (input, "detail"))
697         tm->verbose = 2;
698       else
699         if (unformat (input, "perf %U", unformat_vnet_crypto_alg, &tm->alg))
700         is_perf = 1;
701       else if (unformat (input, "buffers %u", &tm->n_buffers))
702         ;
703       else if (unformat (input, "rounds %u", &tm->rounds))
704         ;
705       else if (unformat (input, "warmup-rounds %u", &tm->warmup_rounds))
706         ;
707       else if (unformat (input, "buffer-size %u", &tm->buffer_size))
708         ;
709       else
710         return clib_error_return (0, "unknown input '%U'",
711                                   format_unformat_error, input);
712     }
713
714   if (is_perf)
715     return test_crypto_perf (vm, tm);
716   else
717     return test_crypto (vm, tm);
718 }
719
720 /* *INDENT-OFF* */
721 VLIB_CLI_COMMAND (test_crypto_command, static) =
722 {
723   .path = "test crypto",
724   .short_help = "test crypto",
725   .function = test_crypto_command_fn,
726 };
727 /* *INDENT-ON* */
728
729 static clib_error_t *
730 crypto_test_init (vlib_main_t * vm)
731 {
732   return (0);
733 }
734
735 VLIB_INIT_FUNCTION (crypto_test_init);
736
737 /*
738  * fd.io coding-style-patch-verification: ON
739  *
740  * Local Variables:
741  * eval: (c-set-style "gnu")
742  * End:
743  */