ipsec: infra for selecting backends
[vpp.git] / src / vnet / ipsec / ipsec.c
index 6e4c7f1..8ebc579 100644 (file)
@@ -412,6 +412,28 @@ ipsec_is_sa_used (u32 sa_index)
   return 0;
 }
 
+clib_error_t *
+ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa,
+                             u32 sa_index, int is_add)
+{
+  ipsec_ah_backend_t *ab;
+  ipsec_esp_backend_t *eb;
+  switch (sa->protocol)
+    {
+    case IPSEC_PROTOCOL_AH:
+      ab = pool_elt_at_index (im->ah_backends, im->ah_current_backend);
+      if (ab->add_del_sa_sess_cb)
+       return ab->add_del_sa_sess_cb (sa_index, is_add);
+      break;
+    case IPSEC_PROTOCOL_ESP:
+      eb = pool_elt_at_index (im->esp_backends, im->esp_current_backend);
+      if (eb->add_del_sa_sess_cb)
+       return eb->add_del_sa_sess_cb (sa_index, is_add);
+      break;
+    }
+  return 0;
+}
+
 int
 ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add)
 {
@@ -439,12 +461,9 @@ ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add)
          return VNET_API_ERROR_SYSCALL_ERROR_1;        /* sa used in policy */
        }
       hash_unset (im->sa_index_by_sa_id, sa->id);
-      if (im->cb.add_del_sa_sess_cb)
-       {
-         err = im->cb.add_del_sa_sess_cb (sa_index, 0);
-         if (err)
-           return VNET_API_ERROR_SYSCALL_ERROR_1;
-       }
+      err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
+      if (err)
+       return VNET_API_ERROR_SYSCALL_ERROR_1;
       pool_put (im->sad, sa);
     }
   else                         /* create new SA */
@@ -453,12 +472,9 @@ ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add)
       clib_memcpy (sa, new_sa, sizeof (*sa));
       sa_index = sa - im->sad;
       hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
-      if (im->cb.add_del_sa_sess_cb)
-       {
-         err = im->cb.add_del_sa_sess_cb (sa_index, 1);
-         if (err)
-           return VNET_API_ERROR_SYSCALL_ERROR_1;
-       }
+      err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
+      if (err)
+       return VNET_API_ERROR_SYSCALL_ERROR_1;
     }
   return 0;
 }
@@ -497,12 +513,9 @@ ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update)
 
   if (0 < sa_update->crypto_key_len || 0 < sa_update->integ_key_len)
     {
-      if (im->cb.add_del_sa_sess_cb)
-       {
-         err = im->cb.add_del_sa_sess_cb (sa_index, 0);
-         if (err)
-           return VNET_API_ERROR_SYSCALL_ERROR_1;
-       }
+      err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
+      if (err)
+       return VNET_API_ERROR_SYSCALL_ERROR_1;
     }
 
   return 0;
@@ -536,13 +549,164 @@ ipsec_check_support (ipsec_sa_t * sa)
   return 0;
 }
 
+clib_error_t *
+ipsec_add_del_sa_sess_cb (ipsec_main_t * im, u32 sa_index, u8 is_add)
+{
+  ipsec_ah_backend_t *ah =
+    pool_elt_at_index (im->ah_backends, im->ah_current_backend);
+  if (ah->add_del_sa_sess_cb)
+    {
+      clib_error_t *err = ah->add_del_sa_sess_cb (sa_index, is_add);
+      if (err)
+       return err;
+    }
+  ipsec_esp_backend_t *esp =
+    pool_elt_at_index (im->esp_backends, im->esp_current_backend);
+  if (esp->add_del_sa_sess_cb)
+    {
+      clib_error_t *err = esp->add_del_sa_sess_cb (sa_index, is_add);
+      if (err)
+       return err;
+    }
+  return 0;
+}
+
+clib_error_t *
+ipsec_check_support_cb (ipsec_main_t * im, ipsec_sa_t * sa)
+{
+  clib_error_t *error = 0;
+  ipsec_ah_backend_t *ah =
+    pool_elt_at_index (im->ah_backends, im->ah_current_backend);
+  ASSERT (ah->check_support_cb);
+  error = ah->check_support_cb (sa);
+  if (error)
+    return error;
+  ipsec_esp_backend_t *esp =
+    pool_elt_at_index (im->esp_backends, im->esp_current_backend);
+  ASSERT (esp->check_support_cb);
+  error = esp->check_support_cb (sa);
+  return error;
+}
+
+
+static void
+ipsec_add_node (vlib_main_t * vm, const char *node_name,
+               const char *prev_node_name, u32 * out_node_index,
+               u32 * out_next_index)
+{
+  vlib_node_t *prev_node, *node;
+  prev_node = vlib_get_node_by_name (vm, (u8 *) prev_node_name);
+  ASSERT (prev_node);
+  node = vlib_get_node_by_name (vm, (u8 *) node_name);
+  ASSERT (node);
+  *out_node_index = node->index;
+  *out_next_index = vlib_node_add_next (vm, prev_node->index, node->index);
+}
+
+u32
+ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im,
+                          const char *name,
+                          const char *ah4_encrypt_node_name,
+                          const char *ah4_decrypt_node_name,
+                          const char *ah6_encrypt_node_name,
+                          const char *ah6_decrypt_node_name,
+                          check_support_cb_t ah_check_support_cb,
+                          add_del_sa_sess_cb_t ah_add_del_sa_sess_cb)
+{
+  ipsec_ah_backend_t *b;
+  pool_get (im->ah_backends, b);
+  b->name = format (NULL, "%s", name);
+
+  ipsec_add_node (vm, ah4_encrypt_node_name, "ipsec4-output",
+                 &b->ah4_encrypt_node_index, &b->ah4_encrypt_next_index);
+  ipsec_add_node (vm, ah4_decrypt_node_name, "ipsec4-input",
+                 &b->ah4_decrypt_node_index, &b->ah4_decrypt_next_index);
+  ipsec_add_node (vm, ah6_encrypt_node_name, "ipsec6-output",
+                 &b->ah6_encrypt_node_index, &b->ah6_encrypt_next_index);
+  ipsec_add_node (vm, ah6_decrypt_node_name, "ipsec6-input",
+                 &b->ah6_decrypt_node_index, &b->ah6_decrypt_next_index);
+
+  b->check_support_cb = ah_check_support_cb;
+  b->add_del_sa_sess_cb = ah_add_del_sa_sess_cb;
+  return b - im->ah_backends;
+}
+
+u32
+ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im,
+                           const char *name,
+                           const char *esp4_encrypt_node_name,
+                           const char *esp4_decrypt_node_name,
+                           const char *esp6_encrypt_node_name,
+                           const char *esp6_decrypt_node_name,
+                           check_support_cb_t esp_check_support_cb,
+                           add_del_sa_sess_cb_t esp_add_del_sa_sess_cb)
+{
+  ipsec_esp_backend_t *b;
+  pool_get (im->esp_backends, b);
+  b->name = format (NULL, "%s", name);
+
+  ipsec_add_node (vm, esp4_encrypt_node_name, "ipsec4-output",
+                 &b->esp4_encrypt_node_index, &b->esp4_encrypt_next_index);
+  ipsec_add_node (vm, esp4_decrypt_node_name, "ipsec4-input",
+                 &b->esp4_decrypt_node_index, &b->esp4_decrypt_next_index);
+  ipsec_add_node (vm, esp6_encrypt_node_name, "ipsec6-output",
+                 &b->esp6_encrypt_node_index, &b->esp6_encrypt_next_index);
+  ipsec_add_node (vm, esp6_decrypt_node_name, "ipsec6-input",
+                 &b->esp6_decrypt_node_index, &b->esp6_decrypt_next_index);
+
+  b->check_support_cb = esp_check_support_cb;
+  b->add_del_sa_sess_cb = esp_add_del_sa_sess_cb;
+  return b - im->esp_backends;
+}
+
+int
+ipsec_select_ah_backend (ipsec_main_t * im, u32 backend_idx)
+{
+  if (pool_elts (im->sad) > 0
+      || pool_is_free_index (im->ah_backends, backend_idx))
+    {
+      return -1;
+    }
+  ipsec_ah_backend_t *b = pool_elt_at_index (im->ah_backends, backend_idx);
+  im->ah_current_backend = backend_idx;
+  im->ah4_encrypt_node_index = b->ah4_encrypt_node_index;
+  im->ah4_decrypt_node_index = b->ah4_decrypt_node_index;
+  im->ah4_encrypt_next_index = b->ah4_encrypt_next_index;
+  im->ah4_decrypt_next_index = b->ah4_decrypt_next_index;
+  im->ah6_encrypt_node_index = b->ah6_encrypt_node_index;
+  im->ah6_decrypt_node_index = b->ah6_decrypt_node_index;
+  im->ah6_encrypt_next_index = b->ah6_encrypt_next_index;
+  im->ah6_decrypt_next_index = b->ah6_decrypt_next_index;
+  return 0;
+}
+
+int
+ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx)
+{
+  if (pool_elts (im->sad) > 0
+      || pool_is_free_index (im->esp_backends, backend_idx))
+    {
+      return -1;
+    }
+  ipsec_esp_backend_t *b = pool_elt_at_index (im->esp_backends, backend_idx);
+  im->esp_current_backend = backend_idx;
+  im->esp4_encrypt_node_index = b->esp4_encrypt_node_index;
+  im->esp4_decrypt_node_index = b->esp4_decrypt_node_index;
+  im->esp4_encrypt_next_index = b->esp4_encrypt_next_index;
+  im->esp4_decrypt_next_index = b->esp4_decrypt_next_index;
+  im->esp6_encrypt_node_index = b->esp6_encrypt_node_index;
+  im->esp6_decrypt_node_index = b->esp6_decrypt_node_index;
+  im->esp6_encrypt_next_index = b->esp6_encrypt_next_index;
+  im->esp6_decrypt_next_index = b->esp6_decrypt_next_index;
+  return 0;
+}
+
 static clib_error_t *
 ipsec_init (vlib_main_t * vm)
 {
   clib_error_t *error;
   ipsec_main_t *im = &ipsec_main;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
-  vlib_node_t *node;
 
   ipsec_rand_seed ();
 
@@ -558,53 +722,34 @@ ipsec_init (vlib_main_t * vm)
   vec_validate_aligned (im->empty_buffers, tm->n_vlib_mains - 1,
                        CLIB_CACHE_LINE_BYTES);
 
-  node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
+  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
   ASSERT (node);
   im->error_drop_node_index = node->index;
 
-  node = vlib_get_node_by_name (vm, (u8 *) "esp4-encrypt");
-  ASSERT (node);
-  im->esp4_encrypt_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "esp4-decrypt");
-  ASSERT (node);
-  im->esp4_decrypt_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "ah4-encrypt");
-  ASSERT (node);
-  im->ah4_encrypt_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "ah4-decrypt");
-  ASSERT (node);
-  im->ah4_decrypt_node_index = node->index;
-
-  im->esp4_encrypt_next_index = IPSEC_OUTPUT_NEXT_ESP4_ENCRYPT;
-  im->esp4_decrypt_next_index = IPSEC_INPUT_NEXT_ESP4_DECRYPT;
-  im->ah4_encrypt_next_index = IPSEC_OUTPUT_NEXT_AH4_ENCRYPT;
-  im->ah4_decrypt_next_index = IPSEC_INPUT_NEXT_AH4_DECRYPT;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "esp6-encrypt");
-  ASSERT (node);
-  im->esp6_encrypt_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "esp6-decrypt");
-  ASSERT (node);
-  im->esp6_decrypt_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "ah6-encrypt");
-  ASSERT (node);
-  im->ah6_encrypt_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "ah6-decrypt");
-  ASSERT (node);
-  im->ah6_decrypt_node_index = node->index;
-
-  im->esp6_encrypt_next_index = IPSEC_OUTPUT_NEXT_ESP6_ENCRYPT;
-  im->esp6_decrypt_next_index = IPSEC_INPUT_NEXT_ESP6_DECRYPT;
-  im->ah6_encrypt_next_index = IPSEC_OUTPUT_NEXT_AH6_ENCRYPT;
-  im->ah6_decrypt_next_index = IPSEC_INPUT_NEXT_AH6_DECRYPT;
-
-  im->cb.check_support_cb = ipsec_check_support;
+  u32 idx = ipsec_register_ah_backend (vm, im, "default openssl backend",
+                                      "ah4-encrypt",
+                                      "ah4-decrypt",
+                                      "ah6-encrypt",
+                                      "ah6-decrypt",
+                                      ipsec_check_support,
+                                      NULL);
+
+  im->ah_default_backend = idx;
+  int rv = ipsec_select_ah_backend (im, idx);
+  ASSERT (0 == rv);
+  (void) (rv);                 // avoid warning
+
+  idx = ipsec_register_esp_backend (vm, im, "default openssl backend",
+                                   "esp4-encrypt",
+                                   "esp4-decrypt",
+                                   "esp6-encrypt",
+                                   "esp6-decrypt",
+                                   ipsec_check_support, NULL);
+  im->esp_default_backend = idx;
+
+  rv = ipsec_select_esp_backend (im, idx);
+  ASSERT (0 == rv);
+  (void) (rv);                 // avoid warning
 
   if ((error = vlib_call_init_function (vm, ipsec_cli_init)))
     return error;