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