ipsec: use boolean or vs. bitwise or to avoid compiler error
[vpp.git] / src / plugins / dpdk / ipsec / ipsec.c
1 /*
2  * Copyright (c) 2017 Intel 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 <vnet/vnet.h>
16 #include <vnet/ip/ip.h>
17 #include <vnet/api_errno.h>
18 #include <vnet/ipsec/ipsec.h>
19 #include <vlib/node_funcs.h>
20
21 #include <dpdk/device/dpdk.h>
22 #include <dpdk/ipsec/ipsec.h>
23
24 #define EMPTY_STRUCT {0}
25
26 static void
27 algos_init (u32 n_mains)
28 {
29   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
30   crypto_alg_t *a;
31
32   vec_validate_aligned (dcm->cipher_algs, IPSEC_CRYPTO_N_ALG - 1, 8);
33
34   {
35 #define _(v,f,str) \
36   dcm->cipher_algs[IPSEC_CRYPTO_ALG_##f].name = str; \
37   dcm->cipher_algs[IPSEC_CRYPTO_ALG_##f].disabled = n_mains;
38     foreach_ipsec_crypto_alg
39 #undef _
40   }
41
42   /* Minimum boundary for ciphers is 4B, required by ESP */
43   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_NONE];
44   a->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
45   a->alg = RTE_CRYPTO_CIPHER_NULL;
46   a->boundary = 4;              /* 1 */
47   a->key_len = 0;
48   a->iv_len = 0;
49
50   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_CBC_128];
51   a->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
52   a->alg = RTE_CRYPTO_CIPHER_AES_CBC;
53   a->boundary = 16;
54   a->key_len = 16;
55   a->iv_len = 16;
56
57   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_CBC_192];
58   a->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
59   a->alg = RTE_CRYPTO_CIPHER_AES_CBC;
60   a->boundary = 16;
61   a->key_len = 24;
62   a->iv_len = 16;
63
64   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_CBC_256];
65   a->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
66   a->alg = RTE_CRYPTO_CIPHER_AES_CBC;
67   a->boundary = 16;
68   a->key_len = 32;
69   a->iv_len = 16;
70
71   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_CTR_128];
72   a->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
73   a->alg = RTE_CRYPTO_CIPHER_AES_CTR;
74   a->boundary = 4;              /* 1 */
75   a->key_len = 16;
76   a->iv_len = 8;
77
78   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_CTR_192];
79   a->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
80   a->alg = RTE_CRYPTO_CIPHER_AES_CTR;
81   a->boundary = 4;              /* 1 */
82   a->key_len = 24;
83   a->iv_len = 8;
84
85   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_CTR_256];
86   a->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
87   a->alg = RTE_CRYPTO_CIPHER_AES_CTR;
88   a->boundary = 4;              /* 1 */
89   a->key_len = 32;
90   a->iv_len = 8;
91
92 #if DPDK_NO_AEAD
93 #define AES_GCM_TYPE RTE_CRYPTO_SYM_XFORM_CIPHER
94 #define AES_GCM_ALG RTE_CRYPTO_CIPHER_AES_GCM
95 #else
96 #define AES_GCM_TYPE RTE_CRYPTO_SYM_XFORM_AEAD
97 #define AES_GCM_ALG RTE_CRYPTO_AEAD_AES_GCM
98 #endif
99
100   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_GCM_128];
101   a->type = AES_GCM_TYPE;
102   a->alg = AES_GCM_ALG;
103   a->boundary = 4;              /* 1 */
104   a->key_len = 16;
105   a->iv_len = 8;
106   a->trunc_size = 16;
107
108   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_GCM_192];
109   a->type = AES_GCM_TYPE;
110   a->alg = AES_GCM_ALG;
111   a->boundary = 4;              /* 1 */
112   a->key_len = 24;
113   a->iv_len = 8;
114   a->trunc_size = 16;
115
116   a = &dcm->cipher_algs[IPSEC_CRYPTO_ALG_AES_GCM_256];
117   a->type = AES_GCM_TYPE;
118   a->alg = AES_GCM_ALG;
119   a->boundary = 4;              /* 1 */
120   a->key_len = 32;
121   a->iv_len = 8;
122   a->trunc_size = 16;
123
124   vec_validate (dcm->auth_algs, IPSEC_INTEG_N_ALG - 1);
125
126   {
127 #define _(v,f,str) \
128   dcm->auth_algs[IPSEC_INTEG_ALG_##f].name = str; \
129   dcm->auth_algs[IPSEC_INTEG_ALG_##f].disabled = n_mains;
130     foreach_ipsec_integ_alg
131 #undef _
132   }
133
134   a = &dcm->auth_algs[IPSEC_INTEG_ALG_NONE];
135   a->type = RTE_CRYPTO_SYM_XFORM_AUTH;
136   a->alg = RTE_CRYPTO_AUTH_NULL;
137   a->key_len = 0;
138   a->trunc_size = 0;
139
140   a = &dcm->auth_algs[IPSEC_INTEG_ALG_MD5_96];
141   a->type = RTE_CRYPTO_SYM_XFORM_AUTH;
142   a->alg = RTE_CRYPTO_AUTH_MD5_HMAC;
143   a->key_len = 16;
144   a->trunc_size = 12;
145
146   a = &dcm->auth_algs[IPSEC_INTEG_ALG_SHA1_96];
147   a->type = RTE_CRYPTO_SYM_XFORM_AUTH;
148   a->alg = RTE_CRYPTO_AUTH_SHA1_HMAC;
149   a->key_len = 20;
150   a->trunc_size = 12;
151
152   a = &dcm->auth_algs[IPSEC_INTEG_ALG_SHA_256_96];
153   a->type = RTE_CRYPTO_SYM_XFORM_AUTH;
154   a->alg = RTE_CRYPTO_AUTH_SHA256_HMAC;
155   a->key_len = 32;
156   a->trunc_size = 12;
157
158   a = &dcm->auth_algs[IPSEC_INTEG_ALG_SHA_256_128];
159   a->type = RTE_CRYPTO_SYM_XFORM_AUTH;
160   a->alg = RTE_CRYPTO_AUTH_SHA256_HMAC;
161   a->key_len = 32;
162   a->trunc_size = 16;
163
164   a = &dcm->auth_algs[IPSEC_INTEG_ALG_SHA_384_192];
165   a->type = RTE_CRYPTO_SYM_XFORM_AUTH;
166   a->alg = RTE_CRYPTO_AUTH_SHA384_HMAC;
167   a->key_len = 48;
168   a->trunc_size = 24;
169
170   a = &dcm->auth_algs[IPSEC_INTEG_ALG_SHA_512_256];
171   a->type = RTE_CRYPTO_SYM_XFORM_AUTH;
172   a->alg = RTE_CRYPTO_AUTH_SHA512_HMAC;
173   a->key_len = 64;
174   a->trunc_size = 32;
175 }
176
177 static u8
178 cipher_alg_index (const crypto_alg_t * alg)
179 {
180   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
181
182   return (alg - dcm->cipher_algs);
183 }
184
185 static u8
186 auth_alg_index (const crypto_alg_t * alg)
187 {
188   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
189
190   return (alg - dcm->auth_algs);
191 }
192
193 static crypto_alg_t *
194 cipher_cap_to_alg (const struct rte_cryptodev_capabilities *cap, u8 key_len)
195 {
196   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
197   crypto_alg_t *alg;
198
199   if (cap->op != RTE_CRYPTO_OP_TYPE_SYMMETRIC)
200     return NULL;
201
202   /* *INDENT-OFF* */
203   vec_foreach (alg, dcm->cipher_algs)
204     {
205       if ((cap->sym.xform_type == RTE_CRYPTO_SYM_XFORM_CIPHER) &&
206           (alg->type == RTE_CRYPTO_SYM_XFORM_CIPHER) &&
207           (cap->sym.cipher.algo == alg->alg) &&
208           (alg->key_len == key_len))
209         return alg;
210 #if ! DPDK_NO_AEAD
211       if ((cap->sym.xform_type == RTE_CRYPTO_SYM_XFORM_AEAD) &&
212           (alg->type == RTE_CRYPTO_SYM_XFORM_AEAD) &&
213           (cap->sym.aead.algo == alg->alg) &&
214           (alg->key_len == key_len))
215         return alg;
216 #endif
217     }
218   /* *INDENT-ON* */
219
220   return NULL;
221 }
222
223 static crypto_alg_t *
224 auth_cap_to_alg (const struct rte_cryptodev_capabilities *cap, u8 trunc_size)
225 {
226   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
227   crypto_alg_t *alg;
228
229   if ((cap->op != RTE_CRYPTO_OP_TYPE_SYMMETRIC) ||
230       (cap->sym.xform_type != RTE_CRYPTO_SYM_XFORM_AUTH))
231     return NULL;
232
233   /* *INDENT-OFF* */
234   vec_foreach (alg, dcm->auth_algs)
235     {
236       if ((cap->sym.auth.algo == alg->alg) &&
237           (alg->trunc_size == trunc_size))
238         return alg;
239     }
240   /* *INDENT-ON* */
241
242   return NULL;
243 }
244
245 #if ! DPDK_NO_AEAD
246 static void
247 crypto_set_aead_xform (struct rte_crypto_sym_xform *xform,
248                        ipsec_sa_t * sa, u8 is_outbound)
249 {
250   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
251   crypto_alg_t *c;
252
253   c = vec_elt_at_index (dcm->cipher_algs, sa->crypto_alg);
254
255   ASSERT (c->type == RTE_CRYPTO_SYM_XFORM_AEAD);
256
257   xform->type = RTE_CRYPTO_SYM_XFORM_AEAD;
258   xform->aead.algo = c->alg;
259   xform->aead.key.data = sa->crypto_key;
260   xform->aead.key.length = c->key_len;
261   xform->aead.iv.offset =
262     crypto_op_get_priv_offset () + offsetof (dpdk_op_priv_t, cb);
263   xform->aead.iv.length = 12;
264   xform->aead.digest_length = c->trunc_size;
265   xform->aead.aad_length = sa->use_esn ? 12 : 8;
266   xform->next = NULL;
267
268   if (is_outbound)
269     xform->aead.op = RTE_CRYPTO_AEAD_OP_ENCRYPT;
270   else
271     xform->aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
272 }
273 #endif
274
275 static void
276 crypto_set_cipher_xform (struct rte_crypto_sym_xform *xform,
277                          ipsec_sa_t * sa, u8 is_outbound)
278 {
279   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
280   crypto_alg_t *c;
281
282   c = vec_elt_at_index (dcm->cipher_algs, sa->crypto_alg);
283
284   ASSERT (c->type == RTE_CRYPTO_SYM_XFORM_CIPHER);
285
286   xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
287   xform->cipher.algo = c->alg;
288   xform->cipher.key.data = sa->crypto_key;
289   xform->cipher.key.length = c->key_len;
290 #if ! DPDK_NO_AEAD
291   xform->cipher.iv.offset =
292     crypto_op_get_priv_offset () + offsetof (dpdk_op_priv_t, cb);
293   xform->cipher.iv.length = c->iv_len;
294 #endif
295   xform->next = NULL;
296
297   if (is_outbound)
298     xform->cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
299   else
300     xform->cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
301 }
302
303 static void
304 crypto_set_auth_xform (struct rte_crypto_sym_xform *xform,
305                        ipsec_sa_t * sa, u8 is_outbound)
306 {
307   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
308   crypto_alg_t *a;
309
310   a = vec_elt_at_index (dcm->auth_algs, sa->integ_alg);
311
312   ASSERT (a->type == RTE_CRYPTO_SYM_XFORM_AUTH);
313
314   xform->type = RTE_CRYPTO_SYM_XFORM_AUTH;
315   xform->auth.algo = a->alg;
316   xform->auth.key.data = sa->integ_key;
317   xform->auth.key.length = a->key_len;
318   xform->auth.digest_length = a->trunc_size;
319 #if DPDK_NO_AEAD
320   if (sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_128 ||
321       sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_192 ||
322       sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_256)
323     xform->auth.algo = RTE_CRYPTO_AUTH_AES_GCM;
324   xform->auth.add_auth_data_length = sa->use_esn ? 12 : 8;
325 #else
326 #if 0
327   xform->auth.iv.offset =
328     sizeof (struct rte_crypto_op) + sizeof (struct rte_crypto_sym_op) +
329     offsetof (dpdk_op_priv_t, cb);
330   xform->auth.iv.length = a->iv_len;
331 #endif
332 #endif
333   xform->next = NULL;
334
335   if (is_outbound)
336     xform->auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
337   else
338     xform->auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
339 }
340
341 clib_error_t *
342 create_sym_session (struct rte_cryptodev_sym_session **session,
343                     u32 sa_idx,
344                     crypto_resource_t * res,
345                     crypto_worker_main_t * cwm, u8 is_outbound)
346 {
347   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
348   ipsec_main_t *im = &ipsec_main;
349   crypto_data_t *data;
350   ipsec_sa_t *sa;
351   struct rte_crypto_sym_xform cipher_xform = { 0 };
352   struct rte_crypto_sym_xform auth_xform = { 0 };
353   struct rte_crypto_sym_xform *xfs;
354   crypto_session_key_t key = { 0 };
355
356   key.drv_id = res->drv_id;
357   key.sa_idx = sa_idx;
358
359   sa = pool_elt_at_index (im->sad, sa_idx);
360
361 #if ! DPDK_NO_AEAD
362   if ((sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_128) |
363       (sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_192) |
364       (sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_256))
365     {
366       crypto_set_aead_xform (&cipher_xform, sa, is_outbound);
367       xfs = &cipher_xform;
368     }
369   else
370 #endif /* ! DPDK_NO_AEAD */
371     {
372       crypto_set_cipher_xform (&cipher_xform, sa, is_outbound);
373       crypto_set_auth_xform (&auth_xform, sa, is_outbound);
374
375       if (is_outbound)
376         {
377           cipher_xform.next = &auth_xform;
378           xfs = &cipher_xform;
379         }
380       else
381         {
382           auth_xform.next = &cipher_xform;
383           xfs = &auth_xform;
384         }
385     }
386
387   data = vec_elt_at_index (dcm->data, res->numa);
388
389 #if DPDK_NO_AEAD
390   /*
391    * DPDK_VER <= 1705:
392    *   Each worker/thread has its own session per device driver
393    */
394   session[0] = rte_cryptodev_sym_session_create (res->dev_id, xfs);
395   if (!session[0])
396     {
397       data->session_drv_failed[res->drv_id] += 1;
398       return clib_error_return (0, "failed to create session for dev %u",
399                                 res->dev_id);
400     }
401 #else
402   /*
403    * DPDK_VER >= 1708:
404    *   Multiple worker/threads share the session for an SA
405    *   Single session per SA, initialized for each device driver
406    */
407   session[0] = (void *) hash_get (data->session_by_sa_index, sa_idx);
408
409   if (!session[0])
410     {
411       session[0] = rte_cryptodev_sym_session_create (data->session_h);
412       if (!session[0])
413         {
414           data->session_h_failed += 1;
415           return clib_error_return (0, "failed to create session header");
416         }
417       hash_set (data->session_by_sa_index, sa_idx, session[0]);
418     }
419
420   struct rte_mempool **mp;
421   mp = vec_elt_at_index (data->session_drv, res->drv_id);
422   ASSERT (mp[0] != NULL);
423
424   i32 ret =
425     rte_cryptodev_sym_session_init (res->dev_id, session[0], xfs, mp[0]);
426   if (ret)
427     {
428       data->session_drv_failed[res->drv_id] += 1;
429       return clib_error_return (0, "failed to init session for drv %u",
430                                 res->drv_id);
431     }
432 #endif /* DPDK_NO_AEAD */
433
434   hash_set (cwm->session_by_drv_id_and_sa_index, key.val, session[0]);
435
436   return 0;
437 }
438
439 static void __attribute__ ((unused)) clear_and_free_obj (void *obj)
440 {
441   struct rte_mempool *mp = rte_mempool_from_obj (obj);
442
443   memset (obj, 0, mp->elt_size);
444
445   rte_mempool_put (mp, obj);
446 }
447
448 #if ! DPDK_NO_AEAD
449 /* This is from rte_cryptodev_pmd.h */
450 static inline void *
451 get_session_private_data (const struct rte_cryptodev_sym_session *sess,
452                           uint8_t driver_id)
453 {
454   return sess->sess_private_data[driver_id];
455 }
456
457 /* This is from rte_cryptodev_pmd.h */
458 static inline void
459 set_session_private_data (struct rte_cryptodev_sym_session *sess,
460                           uint8_t driver_id, void *private_data)
461 {
462   sess->sess_private_data[driver_id] = private_data;
463 }
464 #endif
465
466 static clib_error_t *
467 add_del_sa_session (u32 sa_index, u8 is_add)
468 {
469   ipsec_main_t *im = &ipsec_main;
470   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
471   crypto_worker_main_t *cwm;
472   struct rte_cryptodev_sym_session *s;
473   crypto_session_key_t key = { 0 };
474   uword *val;
475   u32 drv_id;
476   i32 ret;
477
478   key.sa_idx = sa_index;
479
480   if (is_add)
481     {
482 #if 1
483       ipsec_sa_t *sa = pool_elt_at_index (im->sad, sa_index);
484       u32 seed;
485       switch (sa->crypto_alg)
486         {
487         case IPSEC_CRYPTO_ALG_AES_GCM_128:
488         case IPSEC_CRYPTO_ALG_AES_GCM_192:
489         case IPSEC_CRYPTO_ALG_AES_GCM_256:
490           clib_memcpy (&sa->salt, &sa->crypto_key[sa->crypto_key_len - 4], 4);
491           break;
492         default:
493           seed = (u32) clib_cpu_time_now ();
494           sa->salt = random_u32 (&seed);
495         }
496 #endif
497       return 0;
498     }
499
500   /* XXX Wait N cycles to be sure session is not in use OR
501    * keep refcnt at SA level per worker/thread ? */
502   unix_sleep (0.2);
503
504   /* *INDENT-OFF* */
505   vec_foreach (cwm, dcm->workers_main)
506     {
507       for (drv_id = 0; drv_id < dcm->max_drv_id; drv_id++)
508         {
509           key.drv_id = drv_id;
510           val = hash_get (cwm->session_by_drv_id_and_sa_index, key.val);
511           s = (struct rte_cryptodev_sym_session *) val;
512
513           if (!s)
514             continue;
515
516 #if DPDK_NO_AEAD
517           ret = (rte_cryptodev_sym_session_free (s->dev_id, s) == NULL);
518           ASSERT (ret);
519 #endif
520           hash_unset (cwm->session_by_drv_id_and_sa_index, key.val);
521         }
522     }
523   /* *INDENT-ON* */
524
525 #if ! DPDK_NO_AEAD
526   crypto_data_t *data;
527   /* *INDENT-OFF* */
528   vec_foreach (data, dcm->data)
529     {
530       val = hash_get (data->session_by_sa_index, sa_index);
531       s = (struct rte_cryptodev_sym_session *) val;
532
533       if (!s)
534         continue;
535
536       hash_unset (data->session_by_sa_index, sa_index);
537
538       void *drv_session;
539       vec_foreach_index (drv_id, dcm->drv)
540         {
541           drv_session = get_session_private_data (s, drv_id);
542           if (!drv_session)
543             continue;
544
545           /*
546            * Custom clear to avoid finding a dev_id for drv_id:
547            *  ret = rte_cryptodev_sym_session_clear (dev_id, drv_session);
548            *  ASSERT (!ret);
549            */
550           clear_and_free_obj (drv_session);
551
552           set_session_private_data (s, drv_id, NULL);
553         }
554
555       ret = rte_cryptodev_sym_session_free(s);
556       ASSERT (!ret);
557     }
558   /* *INDENT-ON* */
559 #endif
560
561   return 0;
562 }
563
564 static clib_error_t *
565 dpdk_ipsec_check_support (ipsec_sa_t * sa)
566 {
567   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
568
569   if (sa->integ_alg == IPSEC_INTEG_ALG_NONE)
570     switch (sa->crypto_alg)
571       {
572       case IPSEC_CRYPTO_ALG_AES_GCM_128:
573       case IPSEC_CRYPTO_ALG_AES_GCM_192:
574       case IPSEC_CRYPTO_ALG_AES_GCM_256:
575         break;
576       default:
577         return clib_error_return (0, "unsupported integ-alg %U crypto-alg %U",
578                                   format_ipsec_integ_alg, sa->integ_alg,
579                                   format_ipsec_crypto_alg, sa->crypto_alg);
580       }
581
582   /* XXX do we need the NONE check? */
583   if (sa->crypto_alg != IPSEC_CRYPTO_ALG_NONE &&
584       dcm->cipher_algs[sa->crypto_alg].disabled)
585     return clib_error_return (0, "disabled crypto-alg %U",
586                               format_ipsec_crypto_alg, sa->crypto_alg);
587
588   /* XXX do we need the NONE check? */
589   if (sa->integ_alg != IPSEC_INTEG_ALG_NONE &&
590       dcm->auth_algs[sa->integ_alg].disabled)
591     return clib_error_return (0, "disabled integ-alg %U",
592                               format_ipsec_integ_alg, sa->integ_alg);
593   return NULL;
594 }
595
596 static void
597 crypto_parse_capabilities (crypto_dev_t * dev,
598                            const struct rte_cryptodev_capabilities *cap,
599                            u32 n_mains)
600 {
601   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
602   crypto_alg_t *alg;
603   u8 len, inc;
604
605   for (; cap->op != RTE_CRYPTO_OP_TYPE_UNDEFINED; cap++)
606     {
607       /* A single capability maps to multiple cipher/auth algorithms */
608       switch (cap->sym.xform_type)
609         {
610 #if ! DPDK_NO_AEAD
611         case RTE_CRYPTO_SYM_XFORM_AEAD:
612 #endif
613         case RTE_CRYPTO_SYM_XFORM_CIPHER:
614           inc = cap->sym.cipher.key_size.increment;
615           inc = inc ? inc : 1;
616           for (len = cap->sym.cipher.key_size.min;
617                len <= cap->sym.cipher.key_size.max; len += inc)
618             {
619               alg = cipher_cap_to_alg (cap, len);
620               if (!alg)
621                 continue;
622               dev->cipher_support[cipher_alg_index (alg)] = 1;
623               alg->resources += vec_len (dev->free_resources);
624               /* At least enough resources to support one algo */
625               dcm->enabled |= (alg->resources >= n_mains);
626             }
627           break;
628         case RTE_CRYPTO_SYM_XFORM_AUTH:
629           inc = cap->sym.auth.digest_size.increment;
630           inc = inc ? inc : 1;
631           for (len = cap->sym.auth.digest_size.min;
632                len <= cap->sym.auth.digest_size.max; len += inc)
633             {
634               alg = auth_cap_to_alg (cap, len);
635               if (!alg)
636                 continue;
637               dev->auth_support[auth_alg_index (alg)] = 1;
638               alg->resources += vec_len (dev->free_resources);
639               /* At least enough resources to support one algo */
640               dcm->enabled |= (alg->resources >= n_mains);
641             }
642           break;
643         default:
644           ;
645         }
646     }
647 }
648
649 #define DPDK_CRYPTO_N_QUEUE_DESC  2048
650 #define DPDK_CRYPTO_NB_SESS_OBJS  20000
651
652 static clib_error_t *
653 crypto_dev_conf (u8 dev, u16 n_qp, u8 numa)
654 {
655   struct rte_cryptodev_config dev_conf;
656   struct rte_cryptodev_qp_conf qp_conf;
657   i32 ret;
658   u16 qp;
659   i8 *error_str;
660
661   dev_conf.socket_id = numa;
662   dev_conf.nb_queue_pairs = n_qp;
663 #if DPDK_NO_AEAD
664   dev_conf.session_mp.nb_objs = DPDK_CRYPTO_NB_SESS_OBJS;
665   dev_conf.session_mp.cache_size = 512;
666 #endif
667
668   error_str = "failed to configure crypto device %u";
669   ret = rte_cryptodev_configure (dev, &dev_conf);
670   if (ret < 0)
671     return clib_error_return (0, error_str, dev);
672
673   error_str = "failed to setup crypto device %u queue pair %u";
674   qp_conf.nb_descriptors = DPDK_CRYPTO_N_QUEUE_DESC;
675   for (qp = 0; qp < n_qp; qp++)
676     {
677 #if DPDK_NO_AEAD
678       ret = rte_cryptodev_queue_pair_setup (dev, qp, &qp_conf, numa);
679 #else
680       ret = rte_cryptodev_queue_pair_setup (dev, qp, &qp_conf, numa, NULL);
681 #endif
682       if (ret < 0)
683         return clib_error_return (0, error_str, dev, qp);
684     }
685
686   return 0;
687 }
688
689 static void
690 crypto_scan_devs (u32 n_mains)
691 {
692   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
693   struct rte_cryptodev *cryptodev;
694   struct rte_cryptodev_info info;
695   crypto_dev_t *dev;
696   crypto_resource_t *res;
697   clib_error_t *error;
698   u32 i;
699   u16 max_res_idx, res_idx, j;
700   u8 drv_id;
701
702   vec_validate_init_empty (dcm->dev, rte_cryptodev_count () - 1,
703                            (crypto_dev_t) EMPTY_STRUCT);
704
705   for (i = 0; i < rte_cryptodev_count (); i++)
706     {
707       dev = vec_elt_at_index (dcm->dev, i);
708
709       cryptodev = &rte_cryptodevs[i];
710       rte_cryptodev_info_get (i, &info);
711
712       dev->id = i;
713       dev->name = cryptodev->data->name;
714       dev->numa = rte_cryptodev_socket_id (i);
715       dev->features = info.feature_flags;
716       dev->max_qp = info.max_nb_queue_pairs;
717 #if DPDK_NO_AEAD
718       drv_id = cryptodev->dev_type;
719 #else
720       drv_id = info.driver_id;
721 #endif
722       if (drv_id >= vec_len (dcm->drv))
723         vec_validate_init_empty (dcm->drv, drv_id,
724                                  (crypto_drv_t) EMPTY_STRUCT);
725       vec_elt_at_index (dcm->drv, drv_id)->name = info.driver_name;
726       dev->drv_id = drv_id;
727       vec_add1 (vec_elt_at_index (dcm->drv, drv_id)->devs, i);
728
729       if (!(info.feature_flags & RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING))
730         continue;
731
732       if ((error = crypto_dev_conf (i, dev->max_qp, dev->numa)))
733         {
734           clib_error_report (error);
735           continue;
736         }
737
738       max_res_idx = (dev->max_qp / 2) - 1;
739
740       vec_validate (dev->free_resources, max_res_idx);
741
742       res_idx = vec_len (dcm->resource);
743       vec_validate_init_empty_aligned (dcm->resource, res_idx + max_res_idx,
744                                        (crypto_resource_t) EMPTY_STRUCT,
745                                        CLIB_CACHE_LINE_BYTES);
746
747       for (j = 0; j <= max_res_idx; j++, res_idx++)
748         {
749           vec_elt (dev->free_resources, max_res_idx - j) = res_idx;
750           res = &dcm->resource[res_idx];
751           res->dev_id = i;
752           res->drv_id = drv_id;
753           res->qp_id = j * 2;
754           res->numa = dev->numa;
755           res->thread_idx = (u16) ~ 0;
756         }
757
758       crypto_parse_capabilities (dev, info.capabilities, n_mains);
759     }
760 }
761
762 void
763 crypto_auto_placement (void)
764 {
765   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
766   crypto_resource_t *res;
767   crypto_worker_main_t *cwm;
768   crypto_dev_t *dev;
769   u32 thread_idx, skip_master;
770   u16 res_idx, *idx;
771   u8 used;
772   u16 i;
773
774   skip_master = vlib_num_workers () > 0;
775
776   /* *INDENT-OFF* */
777   vec_foreach (dev, dcm->dev)
778     {
779       vec_foreach_index (thread_idx, dcm->workers_main)
780         {
781           if (vec_len (dev->free_resources) == 0)
782             break;
783
784           if (thread_idx < skip_master)
785             continue;
786
787           /* Check thread is not already using the device */
788           vec_foreach (idx, dev->used_resources)
789             if (dcm->resource[idx[0]].thread_idx == thread_idx)
790               continue;
791
792           cwm = vec_elt_at_index (dcm->workers_main, thread_idx);
793
794           used = 0;
795           res_idx = vec_pop (dev->free_resources);
796
797           /* Set device only for supported algos */
798           for (i = 0; i < IPSEC_CRYPTO_N_ALG; i++)
799             if (dev->cipher_support[i] &&
800                 cwm->cipher_resource_idx[i] == (u16) ~0)
801               {
802                 dcm->cipher_algs[i].disabled--;
803                 cwm->cipher_resource_idx[i] = res_idx;
804                 used = 1;
805               }
806
807           for (i = 0; i < IPSEC_INTEG_N_ALG; i++)
808             if (dev->auth_support[i] &&
809                 cwm->auth_resource_idx[i] == (u16) ~0)
810               {
811                 dcm->auth_algs[i].disabled--;
812                 cwm->auth_resource_idx[i] = res_idx;
813                 used = 1;
814               }
815
816           if (!used)
817             {
818               vec_add1 (dev->free_resources, res_idx);
819               continue;
820             }
821
822           vec_add1 (dev->used_resources, res_idx);
823
824           res = vec_elt_at_index (dcm->resource, res_idx);
825
826           ASSERT (res->thread_idx == (u16) ~0);
827           res->thread_idx = thread_idx;
828
829           /* Add device to vector of polling resources */
830           vec_add1 (cwm->resource_idx, res_idx);
831         }
832     }
833   /* *INDENT-ON* */
834 }
835
836 static void
837 crypto_op_init (struct rte_mempool *mempool,
838                 void *_arg __attribute__ ((unused)),
839                 void *_obj, unsigned i __attribute__ ((unused)))
840 {
841   struct rte_crypto_op *op = _obj;
842
843 #if DPDK_NO_AEAD
844   op->sym = (struct rte_crypto_sym_op *) (op + 1);
845   op->sym->sess_type = RTE_CRYPTO_SYM_OP_WITH_SESSION;
846 #else
847   op->sess_type = RTE_CRYPTO_OP_WITH_SESSION;
848 #endif
849   op->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
850   op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
851   op->phys_addr = rte_mem_virt2phy (_obj);
852   op->mempool = mempool;
853 }
854
855 static clib_error_t *
856 crypto_create_crypto_op_pool (u8 numa)
857 {
858   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
859   dpdk_config_main_t *conf = &dpdk_config_main;
860   crypto_data_t *data;
861   u8 *pool_name;
862   u32 pool_priv_size = sizeof (struct rte_crypto_op_pool_private);
863   struct rte_crypto_op_pool_private *priv;
864   clib_error_t *error = NULL;
865
866   data = vec_elt_at_index (dcm->data, numa);
867
868   if (data->crypto_op)
869     return NULL;
870
871   pool_name = format (0, "crypto_pool_numa%u%c", numa, 0);
872
873   data->crypto_op =
874     rte_mempool_create ((i8 *) pool_name, conf->num_mbufs, crypto_op_len (),
875                         512, pool_priv_size, NULL, NULL, crypto_op_init, NULL,
876                         numa, 0);
877
878   if (!data->crypto_op)
879     {
880       error = clib_error_return (0, "failed to allocate %s", pool_name);
881       goto done;
882     }
883
884   priv = rte_mempool_get_priv (data->crypto_op);
885
886   priv->priv_size = pool_priv_size;
887   priv->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
888
889 done:
890   vec_free (pool_name);
891
892   return error;
893 }
894
895 static clib_error_t *
896 crypto_create_session_h_pool (u8 numa)
897 {
898 #if DPDK_NO_AEAD
899   return NULL;
900 #else
901   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
902   crypto_data_t *data;
903   u8 *pool_name;
904   u32 elt_size;
905   clib_error_t *error = NULL;
906
907   data = vec_elt_at_index (dcm->data, numa);
908
909   if (data->session_h)
910     return NULL;
911
912   pool_name = format (0, "session_h_pool_numa%u%c", numa, 0);
913   elt_size = rte_cryptodev_get_header_session_size ();
914
915   data->session_h =
916     rte_mempool_create ((i8 *) pool_name, DPDK_CRYPTO_NB_SESS_OBJS, elt_size,
917                         512, 0, NULL, NULL, NULL, NULL, numa, 0);
918
919   if (!data->session_h)
920     error = clib_error_return (0, "failed to allocate %s", pool_name);
921
922   vec_free (pool_name);
923
924   return error;
925 #endif
926 }
927
928 static clib_error_t *
929 crypto_create_session_drv_pool (crypto_dev_t * dev)
930 {
931 #if DPDK_NO_AEAD
932   return NULL;
933 #else
934   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
935   crypto_data_t *data;
936   u8 *pool_name;
937   u32 elt_size;
938   clib_error_t *error = NULL;
939   u8 numa = dev->numa;
940
941   data = vec_elt_at_index (dcm->data, numa);
942
943   vec_validate (data->session_drv, dev->drv_id);
944   vec_validate (data->session_drv_failed, dev->drv_id);
945
946   if (data->session_drv[dev->drv_id])
947     return NULL;
948
949   pool_name = format (0, "session_drv%u_pool_numa%u%c", dev->drv_id, numa, 0);
950   elt_size = rte_cryptodev_get_private_session_size (dev->id);
951
952   data->session_drv[dev->drv_id] =
953     rte_mempool_create ((i8 *) pool_name, DPDK_CRYPTO_NB_SESS_OBJS, elt_size,
954                         512, 0, NULL, NULL, NULL, NULL, numa, 0);
955
956   if (!data->session_drv[dev->drv_id])
957     error = clib_error_return (0, "failed to allocate %s", pool_name);
958
959   vec_free (pool_name);
960
961   return error;
962 #endif
963 }
964
965 static clib_error_t *
966 crypto_create_pools (void)
967 {
968   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
969   clib_error_t *error = NULL;
970   crypto_dev_t *dev;
971
972   /* *INDENT-OFF* */
973   vec_foreach (dev, dcm->dev)
974     {
975       vec_validate (dcm->data, dev->numa);
976
977       error = crypto_create_crypto_op_pool (dev->numa);
978       if (error)
979         return error;
980
981       error = crypto_create_session_h_pool (dev->numa);
982       if (error)
983         return error;
984
985       error = crypto_create_session_drv_pool (dev);
986       if (error)
987         return error;
988     }
989   /* *INDENT-ON* */
990
991   return NULL;
992 }
993
994 static void
995 crypto_disable (void)
996 {
997   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
998   crypto_data_t *data;
999   u8 i;
1000
1001   dcm->enabled = 0;
1002
1003   /* *INDENT-OFF* */
1004   vec_foreach (data, dcm->data)
1005     {
1006       rte_mempool_free (data->crypto_op);
1007       rte_mempool_free (data->session_h);
1008
1009       vec_foreach_index (i, data->session_drv)
1010         rte_mempool_free (data->session_drv[i]);
1011
1012       vec_free (data->session_drv);
1013     }
1014   /* *INDENT-ON* */
1015
1016   vec_free (dcm->data);
1017
1018   vec_free (dcm->workers_main);
1019   vec_free (dcm->sa_session);
1020   vec_free (dcm->dev);
1021   vec_free (dcm->resource);
1022   vec_free (dcm->cipher_algs);
1023   vec_free (dcm->auth_algs);
1024 }
1025
1026 static uword
1027 dpdk_ipsec_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
1028                     vlib_frame_t * f)
1029 {
1030   ipsec_main_t *im = &ipsec_main;
1031   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
1032   vlib_thread_main_t *tm = vlib_get_thread_main ();
1033   crypto_worker_main_t *cwm;
1034   clib_error_t *error = NULL;
1035   u32 i, skip_master, n_mains;
1036
1037   n_mains = tm->n_vlib_mains;
1038   skip_master = vlib_num_workers () > 0;
1039
1040   algos_init (n_mains - skip_master);
1041
1042   crypto_scan_devs (n_mains - skip_master);
1043
1044   if (!(dcm->enabled))
1045     {
1046       clib_warning ("not enough DPDK crypto resources, default to OpenSSL");
1047       crypto_disable ();
1048       return 0;
1049     }
1050
1051   vec_validate_init_empty (dcm->workers_main, n_mains - 1,
1052                            (crypto_worker_main_t) EMPTY_STRUCT);
1053
1054   /* *INDENT-OFF* */
1055   vec_foreach (cwm, dcm->workers_main)
1056     {
1057       memset (cwm->cipher_resource_idx, ~0,
1058               IPSEC_CRYPTO_N_ALG * sizeof(*cwm->cipher_resource_idx));
1059       memset (cwm->auth_resource_idx, ~0,
1060               IPSEC_INTEG_N_ALG * sizeof(*cwm->auth_resource_idx));
1061     }
1062   /* *INDENT-ON* */
1063
1064   crypto_auto_placement ();
1065
1066   error = crypto_create_pools ();
1067   if (error)
1068     {
1069       clib_error_report (error);
1070       crypto_disable ();
1071       return 0;
1072     }
1073
1074   /* Add new next node and set it as default */
1075   vlib_node_t *node, *next_node;
1076
1077   next_node = vlib_get_node_by_name (vm, (u8 *) "dpdk-esp-encrypt");
1078   ASSERT (next_node);
1079   node = vlib_get_node_by_name (vm, (u8 *) "ipsec-output-ip4");
1080   ASSERT (node);
1081   im->esp_encrypt_node_index = next_node->index;
1082   im->esp_encrypt_next_index =
1083     vlib_node_add_next (vm, node->index, next_node->index);
1084
1085   next_node = vlib_get_node_by_name (vm, (u8 *) "dpdk-esp-decrypt");
1086   ASSERT (next_node);
1087   node = vlib_get_node_by_name (vm, (u8 *) "ipsec-input-ip4");
1088   ASSERT (node);
1089   im->esp_decrypt_node_index = next_node->index;
1090   im->esp_decrypt_next_index =
1091     vlib_node_add_next (vm, node->index, next_node->index);
1092
1093   im->cb.check_support_cb = dpdk_ipsec_check_support;
1094   im->cb.add_del_sa_sess_cb = add_del_sa_session;
1095
1096   node = vlib_get_node_by_name (vm, (u8 *) "dpdk-crypto-input");
1097   ASSERT (node);
1098   for (i = skip_master; i < n_mains; i++)
1099     vlib_node_set_state (vlib_mains[i], node->index, VLIB_NODE_STATE_POLLING);
1100   return 0;
1101 }
1102
1103 /* *INDENT-OFF* */
1104 VLIB_REGISTER_NODE (dpdk_ipsec_process_node,static) = {
1105     .function = dpdk_ipsec_process,
1106     .type = VLIB_NODE_TYPE_PROCESS,
1107     .name = "dpdk-ipsec-process",
1108     .process_log2_n_stack_bytes = 17,
1109 };
1110 /* *INDENT-ON* */
1111
1112 /*
1113  * fd.io coding-style-patch-verification: ON
1114  *
1115  * Local Variables:
1116  * eval: (c-set-style "gnu")
1117  * End:
1118  */