ipsec: Support MPLS over IPSec[46] interface
[vpp.git] / src / plugins / dpdk / ipsec / ipsec.c
index e665db4..5d9e10b 100644 (file)
 #include <vnet/api_errno.h>
 #include <vnet/ipsec/ipsec.h>
 #include <vlib/node_funcs.h>
+#include <vlib/log.h>
 
 #include <dpdk/device/dpdk.h>
+#include <dpdk/buffer.h>
 #include <dpdk/ipsec/ipsec.h>
 
 dpdk_crypto_main_t dpdk_crypto_main;
 
 #define EMPTY_STRUCT {0}
+#define NUM_CRYPTO_MBUFS 16384
 
 static void
 algos_init (u32 n_mains)
@@ -250,13 +253,13 @@ crypto_set_aead_xform (struct rte_crypto_sym_xform *xform,
 
   xform->type = RTE_CRYPTO_SYM_XFORM_AEAD;
   xform->aead.algo = c->alg;
-  xform->aead.key.data = sa->crypto_key;
+  xform->aead.key.data = sa->crypto_key.data;
   xform->aead.key.length = c->key_len;
   xform->aead.iv.offset =
     crypto_op_get_priv_offset () + offsetof (dpdk_op_priv_t, cb);
   xform->aead.iv.length = 12;
   xform->aead.digest_length = c->trunc_size;
-  xform->aead.aad_length = sa->use_esn ? 12 : 8;
+  xform->aead.aad_length = ipsec_sa_is_set_USE_ESN (sa) ? 12 : 8;
   xform->next = NULL;
 
   if (is_outbound)
@@ -278,7 +281,7 @@ crypto_set_cipher_xform (struct rte_crypto_sym_xform *xform,
 
   xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
   xform->cipher.algo = c->alg;
-  xform->cipher.key.data = sa->crypto_key;
+  xform->cipher.key.data = sa->crypto_key.data;
   xform->cipher.key.length = c->key_len;
   xform->cipher.iv.offset =
     crypto_op_get_priv_offset () + offsetof (dpdk_op_priv_t, cb);
@@ -304,7 +307,7 @@ crypto_set_auth_xform (struct rte_crypto_sym_xform *xform,
 
   xform->type = RTE_CRYPTO_SYM_XFORM_AUTH;
   xform->auth.algo = a->alg;
-  xform->auth.key.data = sa->integ_key;
+  xform->auth.key.data = sa->integ_key.data;
   xform->auth.key.length = a->key_len;
   xform->auth.digest_length = a->trunc_size;
   xform->next = NULL;
@@ -329,7 +332,7 @@ create_sym_session (struct rte_cryptodev_sym_session **session,
   struct rte_crypto_sym_xform auth_xform = { 0 };
   struct rte_crypto_sym_xform *xfs;
   struct rte_cryptodev_sym_session **s;
-  clib_error_t *erorr = 0;
+  clib_error_t *error = 0;
 
 
   sa = pool_elt_at_index (im->sad, sa_idx);
@@ -374,7 +377,7 @@ create_sym_session (struct rte_cryptodev_sym_session **session,
       if (!session[0])
        {
          data->session_h_failed += 1;
-         erorr = clib_error_return (0, "failed to create session header");
+         error = clib_error_return (0, "failed to create session header");
          goto done;
        }
       hash_set (data->session_by_sa_index, sa_idx, session[0]);
@@ -391,7 +394,7 @@ create_sym_session (struct rte_cryptodev_sym_session **session,
   if (ret)
     {
       data->session_drv_failed[res->drv_id] += 1;
-      erorr = clib_error_return (0, "failed to init session for drv %u",
+      error = clib_error_return (0, "failed to init session for drv %u",
                                 res->drv_id);
       goto done;
     }
@@ -400,7 +403,7 @@ create_sym_session (struct rte_cryptodev_sym_session **session,
 
 done:
   clib_spinlock_unlock_if_init (&data->lockp);
-  return erorr;
+  return error;
 }
 
 static void __attribute__ ((unused)) clear_and_free_obj (void *obj)
@@ -417,7 +420,14 @@ static inline void *
 get_session_private_data (const struct rte_cryptodev_sym_session *sess,
                          uint8_t driver_id)
 {
+#if RTE_VERSION < RTE_VERSION_NUM(19, 2, 0, 0)
   return sess->sess_private_data[driver_id];
+#else
+  if (unlikely (sess->nb_drivers <= driver_id))
+    return 0;
+
+  return sess->sess_data[driver_id].data;
+#endif
 }
 
 /* This is from rte_cryptodev_pmd.h */
@@ -425,7 +435,13 @@ static inline void
 set_session_private_data (struct rte_cryptodev_sym_session *sess,
                          uint8_t driver_id, void *private_data)
 {
+#if RTE_VERSION < RTE_VERSION_NUM(19, 2, 0, 0)
   sess->sess_private_data[driver_id] = private_data;
+#else
+  if (unlikely (sess->nb_drivers <= driver_id))
+    return;
+  sess->sess_data[driver_id].data = private_data;
+#endif
 }
 
 static clib_error_t *
@@ -479,7 +495,6 @@ dpdk_crypto_session_disposal (crypto_session_disposal_t * v, u64 ts)
 static clib_error_t *
 add_del_sa_session (u32 sa_index, u8 is_add)
 {
-  ipsec_main_t *im = &ipsec_main;
   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
   crypto_data_t *data;
   struct rte_cryptodev_sym_session *s;
@@ -487,24 +502,7 @@ add_del_sa_session (u32 sa_index, u8 is_add)
   u32 drv_id;
 
   if (is_add)
-    {
-#if 1
-      ipsec_sa_t *sa = pool_elt_at_index (im->sad, sa_index);
-      u32 seed;
-      switch (sa->crypto_alg)
-       {
-       case IPSEC_CRYPTO_ALG_AES_GCM_128:
-       case IPSEC_CRYPTO_ALG_AES_GCM_192:
-       case IPSEC_CRYPTO_ALG_AES_GCM_256:
-         clib_memcpy (&sa->salt, &sa->crypto_key[sa->crypto_key_len - 4], 4);
-         break;
-       default:
-         seed = (u32) clib_cpu_time_now ();
-         sa->salt = random_u32 (&seed);
-       }
-#endif
-      return 0;
-    }
+    return 0;
 
   /* *INDENT-OFF* */
   vec_foreach (data, dcm->data)
@@ -623,14 +621,11 @@ crypto_parse_capabilities (crypto_dev_t * dev,
     }
 }
 
-#define DPDK_CRYPTO_N_QUEUE_DESC  2048
-#define DPDK_CRYPTO_NB_SESS_OBJS  20000
-
 static clib_error_t *
 crypto_dev_conf (u8 dev, u16 n_qp, u8 numa)
 {
-  struct rte_cryptodev_config dev_conf;
-  struct rte_cryptodev_qp_conf qp_conf;
+  struct rte_cryptodev_config dev_conf = { 0 };
+  struct rte_cryptodev_qp_conf qp_conf = { 0 };
   i32 ret;
   u16 qp;
   char *error_str;
@@ -647,7 +642,11 @@ crypto_dev_conf (u8 dev, u16 n_qp, u8 numa)
   qp_conf.nb_descriptors = DPDK_CRYPTO_N_QUEUE_DESC;
   for (qp = 0; qp < n_qp; qp++)
     {
+#if RTE_VERSION < RTE_VERSION_NUM(19, 2, 0, 0)
       ret = rte_cryptodev_queue_pair_setup (dev, qp, &qp_conf, numa, NULL);
+#else
+      ret = rte_cryptodev_queue_pair_setup (dev, qp, &qp_conf, numa);
+#endif
       if (ret < 0)
        return clib_error_return (0, error_str, dev, qp);
     }
@@ -664,7 +663,7 @@ crypto_scan_devs (u32 n_mains)
 {
   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
   struct rte_cryptodev *cryptodev;
-  struct rte_cryptodev_info info;
+  struct rte_cryptodev_info info = { 0 };
   crypto_dev_t *dev;
   crypto_resource_t *res;
   clib_error_t *error;
@@ -704,7 +703,7 @@ crypto_scan_devs (u32 n_mains)
          continue;
        }
 
-      max_res_idx = (dev->max_qp / 2) - 1;
+      max_res_idx = dev->max_qp - 1;
 
       vec_validate (dev->free_resources, max_res_idx);
 
@@ -713,13 +712,13 @@ crypto_scan_devs (u32 n_mains)
                                       (crypto_resource_t) EMPTY_STRUCT,
                                       CLIB_CACHE_LINE_BYTES);
 
-      for (j = 0; j <= max_res_idx; j++, res_idx++)
+      for (j = 0; j <= max_res_idx; j++)
        {
-         vec_elt (dev->free_resources, max_res_idx - j) = res_idx;
-         res = &dcm->resource[res_idx];
+         vec_elt (dev->free_resources, max_res_idx - j) = res_idx + j;
+         res = &dcm->resource[res_idx + j];
          res->dev_id = i;
          res->drv_id = drv_id;
-         res->qp_id = j * 2;
+         res->qp_id = j;
          res->numa = dev->numa;
          res->thread_idx = (u16) ~ 0;
        }
@@ -826,8 +825,6 @@ crypto_create_crypto_op_pool (vlib_main_t * vm, u8 numa)
   u32 pool_priv_size = sizeof (struct rte_crypto_op_pool_private);
   struct rte_crypto_op_pool_private *priv;
   struct rte_mempool *mp;
-  clib_error_t *error = NULL;
-  u32 map_index;
 
   data = vec_elt_at_index (dcm->data, numa);
 
@@ -837,22 +834,23 @@ crypto_create_crypto_op_pool (vlib_main_t * vm, u8 numa)
 
   pool_name = format (0, "crypto_pool_numa%u%c", numa, 0);
 
-  error = dpdk_pool_create (vm, pool_name, crypto_op_len (), conf->num_mbufs,
-                           pool_priv_size, 512, numa, &mp, &map_index);
+  if (conf->num_crypto_mbufs == 0)
+    conf->num_crypto_mbufs = NUM_CRYPTO_MBUFS;
+
+  mp = rte_mempool_create ((char *) pool_name, conf->num_crypto_mbufs,
+                          crypto_op_len (), 512, pool_priv_size, NULL, NULL,
+                          crypto_op_init, NULL, numa, 0);
 
   vec_free (pool_name);
 
-  if (error)
-    return error;
+  if (!mp)
+    return clib_error_return (0, "failed to create crypto op mempool");
 
   /* Initialize mempool private data */
   priv = rte_mempool_get_priv (mp);
   priv->priv_size = pool_priv_size;
   priv->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
 
-  /* call the object initializers */
-  rte_mempool_obj_iter (mp, crypto_op_init, 0);
-
   data->crypto_op = mp;
 
   return NULL;
@@ -865,9 +863,7 @@ crypto_create_session_h_pool (vlib_main_t * vm, u8 numa)
   crypto_data_t *data;
   u8 *pool_name;
   struct rte_mempool *mp;
-  clib_error_t *error = NULL;
   u32 elt_size;
-  u32 map_index;
 
   data = vec_elt_at_index (dcm->data, numa);
 
@@ -879,13 +875,19 @@ crypto_create_session_h_pool (vlib_main_t * vm, u8 numa)
 
   elt_size = rte_cryptodev_sym_get_header_session_size ();
 
-  error = dpdk_pool_create (vm, pool_name, elt_size, DPDK_CRYPTO_NB_SESS_OBJS,
-                           0, 512, numa, &mp, &map_index);
-
+#if RTE_VERSION < RTE_VERSION_NUM(19, 2, 0, 0)
+  mp = rte_mempool_create ((char *) pool_name, DPDK_CRYPTO_NB_SESS_OBJS,
+                          elt_size, 512, 0, NULL, NULL, NULL, NULL, numa, 0);
+#else
+  /* XXX Experimental tag in DPDK 19.02 */
+  mp = rte_cryptodev_sym_session_pool_create ((char *) pool_name,
+                                             DPDK_CRYPTO_NB_SESS_OBJS,
+                                             elt_size, 512, 0, numa);
+#endif
   vec_free (pool_name);
 
-  if (error)
-    return error;
+  if (!mp)
+    return clib_error_return (0, "failed to create crypto session mempool");
 
   data->session_h = mp;
 
@@ -899,10 +901,8 @@ crypto_create_session_drv_pool (vlib_main_t * vm, crypto_dev_t * dev)
   crypto_data_t *data;
   u8 *pool_name;
   struct rte_mempool *mp;
-  clib_error_t *error = NULL;
   u32 elt_size;
   u8 numa = dev->numa;
-  u32 map_index;
 
   data = vec_elt_at_index (dcm->data, numa);
 
@@ -917,14 +917,14 @@ crypto_create_session_drv_pool (vlib_main_t * vm, crypto_dev_t * dev)
   pool_name = format (0, "session_drv%u_pool_numa%u%c", dev->drv_id, numa, 0);
 
   elt_size = rte_cryptodev_sym_get_private_session_size (dev->id);
-
-  error = dpdk_pool_create (vm, pool_name, elt_size, DPDK_CRYPTO_NB_SESS_OBJS,
-                           0, 512, numa, &mp, &map_index);
+  mp =
+    rte_mempool_create ((char *) pool_name, DPDK_CRYPTO_NB_SESS_OBJS,
+                       elt_size, 512, 0, NULL, NULL, NULL, NULL, numa, 0);
 
   vec_free (pool_name);
 
-  if (error)
-    return error;
+  if (!mp)
+    return clib_error_return (0, "failed to create session drv mempool");
 
   data->session_drv[dev->drv_id] = mp;
   clib_spinlock_init (&data->lockp);
@@ -992,16 +992,33 @@ crypto_disable (void)
   vec_free (dcm->auth_algs);
 }
 
-static uword
-dpdk_ipsec_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
-                   vlib_frame_t * f)
+static clib_error_t *
+dpdk_ipsec_enable_disable (int is_enable)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  vlib_thread_main_t *tm = vlib_get_thread_main ();
+  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "dpdk-crypto-input");
+  u32 skip_master = vlib_num_workers () > 0;
+  u32 n_mains = tm->n_vlib_mains;
+  u32 i;
+
+  ASSERT (node);
+  for (i = skip_master; i < n_mains; i++)
+    vlib_node_set_state (vlib_mains[i], node->index, is_enable != 0 ?
+                        VLIB_NODE_STATE_POLLING : VLIB_NODE_STATE_DISABLED);
+
+  return 0;
+}
+
+static clib_error_t *
+dpdk_ipsec_main_init (vlib_main_t * vm)
 {
   ipsec_main_t *im = &ipsec_main;
   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   crypto_worker_main_t *cwm;
   clib_error_t *error = NULL;
-  u32 i, skip_master, n_mains;
+  u32 skip_master, n_mains;
 
   n_mains = tm->n_vlib_mains;
   skip_master = vlib_num_workers () > 0;
@@ -1012,7 +1029,8 @@ dpdk_ipsec_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
 
   if (!(dcm->enabled))
     {
-      clib_warning ("not enough DPDK crypto resources, default to OpenSSL");
+      vlib_log_warn (dpdk_main.log_default,
+                    "not enough DPDK crypto resources");
       crypto_disable ();
       return 0;
     }
@@ -1045,29 +1063,22 @@ dpdk_ipsec_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
       return 0;
     }
 
-
-  ipsec_register_esp_backend (vm, im, "dpdk backend",
-                             "dpdk-esp4-encrypt",
-                             "dpdk-esp4-decrypt",
-                             "dpdk-esp6-encrypt",
-                             "dpdk-esp6-decrypt",
-                             dpdk_ipsec_check_support, add_del_sa_session);
-
-  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "dpdk-crypto-input");
-  ASSERT (node);
-  for (i = skip_master; i < n_mains; i++)
-    vlib_node_set_state (vlib_mains[i], node->index, VLIB_NODE_STATE_POLLING);
+  u32 idx = ipsec_register_esp_backend (
+    vm, im, "dpdk backend", "dpdk-esp4-encrypt", "dpdk-esp4-encrypt-tun",
+    "dpdk-esp4-decrypt", "dpdk-esp4-decrypt", "dpdk-esp6-encrypt",
+    "dpdk-esp6-encrypt-tun", "dpdk-esp6-decrypt", "dpdk-esp6-decrypt",
+    "error-drop", dpdk_ipsec_check_support, add_del_sa_session,
+    dpdk_ipsec_enable_disable);
+  int rv;
+  if (im->esp_current_backend == ~0)
+    {
+      rv = ipsec_select_esp_backend (im, idx);
+      ASSERT (rv == 0);
+    }
   return 0;
 }
 
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (dpdk_ipsec_process_node,static) = {
-    .function = dpdk_ipsec_process,
-    .type = VLIB_NODE_TYPE_PROCESS,
-    .name = "dpdk-ipsec-process",
-    .process_log2_n_stack_bytes = 17,
-};
-/* *INDENT-ON* */
+VLIB_MAIN_LOOP_ENTER_FUNCTION (dpdk_ipsec_main_init);
 
 /*
  * fd.io coding-style-patch-verification: ON