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