ipsec: infra for selecting backends 23/15823/10
authorKlement Sekera <ksekera@cisco.com>
Thu, 8 Nov 2018 12:00:02 +0000 (13:00 +0100)
committerDamjan Marion <dmarion@me.com>
Thu, 15 Nov 2018 12:57:18 +0000 (12:57 +0000)
Change-Id: Ifa6d8391b1b2413a88b7720fc434e0bc849a149a
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Signed-off-by: Andrew Yourtchenko <ayourtch@gmail.com>
13 files changed:
src/plugins/dpdk/ipsec/ipsec.c
src/vnet/ipsec/ipsec.api
src/vnet/ipsec/ipsec.c
src/vnet/ipsec/ipsec.h
src/vnet/ipsec/ipsec_api.c
src/vnet/ipsec/ipsec_cli.c
src/vnet/ipsec/ipsec_if.c
test/template_ipsec.py
test/test_ipsec_ah.py
test/test_ipsec_api.py [new file with mode: 0644]
test/test_ipsec_esp.py
test/test_ipsec_tun_if_esp.py
test/vpp_papi_provider.py

index bcc4b62..e665db4 100644 (file)
@@ -1045,45 +1045,15 @@ dpdk_ipsec_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
       return 0;
     }
 
-  /* Add new next node and set it as default */
-  vlib_node_t *node, *next_node;
 
-  next_node = vlib_get_node_by_name (vm, (u8 *) "dpdk-esp4-encrypt");
-  ASSERT (next_node);
-  node = vlib_get_node_by_name (vm, (u8 *) "ipsec4-output");
-  ASSERT (node);
-  im->esp4_encrypt_node_index = next_node->index;
-  im->esp4_encrypt_next_index =
-    vlib_node_add_next (vm, node->index, next_node->index);
-
-  next_node = vlib_get_node_by_name (vm, (u8 *) "dpdk-esp4-decrypt");
-  ASSERT (next_node);
-  node = vlib_get_node_by_name (vm, (u8 *) "ipsec4-input");
-  ASSERT (node);
-  im->esp4_decrypt_node_index = next_node->index;
-  im->esp4_decrypt_next_index =
-    vlib_node_add_next (vm, node->index, next_node->index);
-
-  next_node = vlib_get_node_by_name (vm, (u8 *) "dpdk-esp6-encrypt");
-  ASSERT (next_node);
-  node = vlib_get_node_by_name (vm, (u8 *) "ipsec6-output");
-  ASSERT (node);
-  im->esp6_encrypt_node_index = next_node->index;
-  im->esp6_encrypt_next_index =
-    vlib_node_add_next (vm, node->index, next_node->index);
-
-  next_node = vlib_get_node_by_name (vm, (u8 *) "dpdk-esp6-decrypt");
-  ASSERT (next_node);
-  node = vlib_get_node_by_name (vm, (u8 *) "ipsec6-input");
-  ASSERT (node);
-  im->esp6_decrypt_node_index = next_node->index;
-  im->esp6_decrypt_next_index =
-    vlib_node_add_next (vm, node->index, next_node->index);
-
-  im->cb.check_support_cb = dpdk_ipsec_check_support;
-  im->cb.add_del_sa_sess_cb = add_del_sa_session;
+  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);
 
-  node = vlib_get_node_by_name (vm, (u8 *) "dpdk-crypto-input");
+  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);
index 793422d..148cdcd 100644 (file)
@@ -703,6 +703,42 @@ autoreply define ipsec_tunnel_if_set_sa {
   u8 is_outbound;
 };
 
+/** \brief Dump IPsec backends
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define ipsec_backend_dump {
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief IPsec backend details
+    @param name - name of the backend
+    @param protocol - IPsec protocol (value from ipsec_protocol_t)
+    @param index - backend index
+    @param active - set to 1 if the backend is active, otherwise 0
+*/
+define ipsec_backend_details {
+  u32 context;
+  u8 name[128];
+  u8 protocol;
+  u8 index;
+  u8 active;
+};
+
+/** \brief Select IPsec backend
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param protocol - IPsec protocol (value from ipsec_protocol_t)
+    @param index - backend index
+*/
+autoreply define ipsec_select_backend {
+  u32 client_index;
+  u32 context;
+  u8 protocol;
+  u8 index;
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
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;
index 6a9c5b1..ced7119 100644 (file)
@@ -20,8 +20,8 @@
 
 #define IPSEC_FLAG_IPSEC_GRE_TUNNEL (1 << 0)
 
-#define foreach_ipsec_output_next        \
-  _ (DROP, "error-drop")                 \
+#define foreach_ipsec_output_next  \
+  _ (DROP, "error-drop")           \
   _ (ESP4_ENCRYPT, "esp4-encrypt") \
   _ (AH4_ENCRYPT, "ah4-encrypt")   \
   _ (ESP6_ENCRYPT, "esp6-encrypt") \
@@ -35,8 +35,8 @@ typedef enum
     IPSEC_OUTPUT_N_NEXT,
 } ipsec_output_next_t;
 
-#define foreach_ipsec_input_next         \
-  _ (DROP, "error-drop")                 \
+#define foreach_ipsec_input_next   \
+  _ (DROP, "error-drop")           \
   _ (ESP4_DECRYPT, "esp4-decrypt") \
   _ (AH4_DECRYPT, "ah4-decrypt")   \
   _ (ESP6_DECRYPT, "esp6-decrypt") \
@@ -50,55 +50,54 @@ typedef enum
     IPSEC_INPUT_N_NEXT,
 } ipsec_input_next_t;
 
-
 #define foreach_ipsec_policy_action \
-  _(0, BYPASS,  "bypass")          \
-  _(1, DISCARD, "discard")         \
-  _(2, RESOLVE, "resolve")         \
-  _(3, PROTECT, "protect")
+  _ (0, BYPASS, "bypass")           \
+  _ (1, DISCARD, "discard")         \
+  _ (2, RESOLVE, "resolve")         \
+  _ (3, PROTECT, "protect")
 
 typedef enum
 {
-#define _(v,f,s) IPSEC_POLICY_ACTION_##f = v,
+#define _(v, f, s) IPSEC_POLICY_ACTION_##f = v,
   foreach_ipsec_policy_action
 #undef _
     IPSEC_POLICY_N_ACTION,
 } ipsec_policy_action_t;
 
-#define foreach_ipsec_crypto_alg \
-  _(0, NONE,  "none")               \
-  _(1, AES_CBC_128, "aes-cbc-128")  \
-  _(2, AES_CBC_192, "aes-cbc-192")  \
-  _(3, AES_CBC_256, "aes-cbc-256")  \
-  _(4, AES_CTR_128, "aes-ctr-128")  \
-  _(5, AES_CTR_192, "aes-ctr-192")  \
-  _(6, AES_CTR_256, "aes-ctr-256")  \
-  _(7, AES_GCM_128, "aes-gcm-128")  \
-  _(8, AES_GCM_192, "aes-gcm-192")  \
-  _(9, AES_GCM_256, "aes-gcm-256")  \
-  _(10, DES_CBC, "des-cbc")         \
-  _(11, 3DES_CBC, "3des-cbc")
+#define foreach_ipsec_crypto_alg    \
+  _ (0, NONE, "none")               \
+  _ (1, AES_CBC_128, "aes-cbc-128") \
+  _ (2, AES_CBC_192, "aes-cbc-192") \
+  _ (3, AES_CBC_256, "aes-cbc-256") \
+  _ (4, AES_CTR_128, "aes-ctr-128") \
+  _ (5, AES_CTR_192, "aes-ctr-192") \
+  _ (6, AES_CTR_256, "aes-ctr-256") \
+  _ (7, AES_GCM_128, "aes-gcm-128") \
+  _ (8, AES_GCM_192, "aes-gcm-192") \
+  _ (9, AES_GCM_256, "aes-gcm-256") \
+  _ (10, DES_CBC, "des-cbc")        \
+  _ (11, 3DES_CBC, "3des-cbc")
 
 typedef enum
 {
-#define _(v,f,s) IPSEC_CRYPTO_ALG_##f = v,
+#define _(v, f, s) IPSEC_CRYPTO_ALG_##f = v,
   foreach_ipsec_crypto_alg
 #undef _
     IPSEC_CRYPTO_N_ALG,
 } ipsec_crypto_alg_t;
 
-#define foreach_ipsec_integ_alg \
-  _(0, NONE,  "none")                                                     \
-  _(1, MD5_96, "md5-96")           /* RFC2403 */                          \
-  _(2, SHA1_96, "sha1-96")         /* RFC2404 */                          \
-  _(3, SHA_256_96, "sha-256-96")   /* draft-ietf-ipsec-ciph-sha-256-00 */ \
-  _(4, SHA_256_128, "sha-256-128") /* RFC4868 */                          \
-  _(5, SHA_384_192, "sha-384-192") /* RFC4868 */                          \
-  _(6, SHA_512_256, "sha-512-256")     /* RFC4868 */
+#define foreach_ipsec_integ_alg                                            \
+  _ (0, NONE, "none")                                                      \
+  _ (1, MD5_96, "md5-96")           /* RFC2403 */                          \
+  _ (2, SHA1_96, "sha1-96")         /* RFC2404 */                          \
+  _ (3, SHA_256_96, "sha-256-96")   /* draft-ietf-ipsec-ciph-sha-256-00 */ \
+  _ (4, SHA_256_128, "sha-256-128") /* RFC4868 */                          \
+  _ (5, SHA_384_192, "sha-384-192") /* RFC4868 */                          \
+  _ (6, SHA_512_256, "sha-512-256")    /* RFC4868 */
 
 typedef enum
 {
-#define _(v,f,s) IPSEC_INTEG_ALG_##f = v,
+#define _(v, f, s) IPSEC_INTEG_ALG_##f = v,
   foreach_ipsec_integ_alg
 #undef _
     IPSEC_INTEG_N_ALG,
@@ -142,7 +141,7 @@ typedef struct
   u32 last_seq_hi;
   u64 replay_window;
 
-  /*lifetime data */
+  /* lifetime data */
   u64 total_data_size;
 } ipsec_sa_t;
 
@@ -254,11 +253,42 @@ typedef struct
   u32 show_instance;
 } ipsec_tunnel_if_t;
 
+typedef clib_error_t *(*add_del_sa_sess_cb_t) (u32 sa_index, u8 is_add);
+typedef clib_error_t *(*check_support_cb_t) (ipsec_sa_t * sa);
+
 typedef struct
 {
-  clib_error_t *(*add_del_sa_sess_cb) (u32 sa_index, u8 is_add);
-  clib_error_t *(*check_support_cb) (ipsec_sa_t * sa);
-} ipsec_main_callbacks_t;
+  u8 *name;
+  /* add/del callback */
+  add_del_sa_sess_cb_t add_del_sa_sess_cb;
+  /* check support function */
+  check_support_cb_t check_support_cb;
+  u32 ah4_encrypt_node_index;
+  u32 ah4_decrypt_node_index;
+  u32 ah4_encrypt_next_index;
+  u32 ah4_decrypt_next_index;
+  u32 ah6_encrypt_node_index;
+  u32 ah6_decrypt_node_index;
+  u32 ah6_encrypt_next_index;
+  u32 ah6_decrypt_next_index;
+} ipsec_ah_backend_t;
+
+typedef struct
+{
+  u8 *name;
+  /* add/del callback */
+  add_del_sa_sess_cb_t add_del_sa_sess_cb;
+  /* check support function */
+  check_support_cb_t check_support_cb;
+  u32 esp4_encrypt_node_index;
+  u32 esp4_decrypt_node_index;
+  u32 esp4_encrypt_next_index;
+  u32 esp4_decrypt_next_index;
+  u32 esp6_encrypt_node_index;
+  u32 esp6_decrypt_node_index;
+  u32 esp6_encrypt_next_index;
+  u32 esp6_decrypt_next_index;
+} ipsec_esp_backend_t;
 
 typedef struct
 {
@@ -308,8 +338,18 @@ typedef struct
   u32 ah6_encrypt_next_index;
   u32 ah6_decrypt_next_index;
 
-  /* callbacks */
-  ipsec_main_callbacks_t cb;
+  /* pool of ah backends */
+  ipsec_ah_backend_t *ah_backends;
+  /* pool of esp backends */
+  ipsec_esp_backend_t *esp_backends;
+  /* index of current ah backend */
+  u32 ah_current_backend;
+  /* index of current esp backend */
+  u32 esp_current_backend;
+  /* index of default ah backend */
+  u32 ah_default_backend;
+  /* index of default esp backend */
+  u32 esp_default_backend;
 
   /* helper for sort function */
   ipsec_spd_t *spd_to_sort;
@@ -317,6 +357,11 @@ typedef struct
 
 extern ipsec_main_t ipsec_main;
 
+clib_error_t *ipsec_add_del_sa_sess_cb (ipsec_main_t * im, u32 sa_index,
+                                       u8 is_add);
+
+clib_error_t *ipsec_check_support_cb (ipsec_main_t * im, ipsec_sa_t * sa);
+
 extern vlib_node_registration_t esp4_encrypt_node;
 extern vlib_node_registration_t esp4_decrypt_node;
 extern vlib_node_registration_t ah4_encrypt_node;
@@ -327,7 +372,6 @@ extern vlib_node_registration_t ah6_encrypt_node;
 extern vlib_node_registration_t ah6_decrypt_node;
 extern vlib_node_registration_t ipsec_if_input_node;
 
-
 /*
  * functions
  */
@@ -361,7 +405,6 @@ int ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
 int ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
                            u8 is_outbound);
 
-
 /*
  *  inline functions
  */
@@ -399,6 +442,26 @@ get_next_output_feature_node_index (vlib_buffer_t * b,
   return node->next_nodes[next];
 }
 
+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);
+
+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);
+
+int ipsec_select_ah_backend (ipsec_main_t * im, u32 ah_backend_idx);
+int ipsec_select_esp_backend (ipsec_main_t * im, u32 esp_backend_idx);
 #endif /* __IPSEC_H__ */
 
 /*
index ced2c9c..f233364 100644 (file)
 
 #include <vlibapi/api_helper_macros.h>
 
-#define foreach_vpe_api_msg                                             \
-_(IPSEC_SPD_ADD_DEL, ipsec_spd_add_del)                                 \
-_(IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd)             \
-_(IPSEC_SPD_ADD_DEL_ENTRY, ipsec_spd_add_del_entry)                     \
-_(IPSEC_SAD_ADD_DEL_ENTRY, ipsec_sad_add_del_entry)                     \
-_(IPSEC_SA_SET_KEY, ipsec_sa_set_key)                                   \
-_(IPSEC_SA_DUMP, ipsec_sa_dump)                                         \
-_(IPSEC_SPDS_DUMP, ipsec_spds_dump)                                     \
-_(IPSEC_SPD_DUMP, ipsec_spd_dump)                                       \
-_(IPSEC_SPD_INTERFACE_DUMP, ipsec_spd_interface_dump)                  \
-_(IPSEC_TUNNEL_IF_ADD_DEL, ipsec_tunnel_if_add_del)                     \
-_(IPSEC_TUNNEL_IF_SET_KEY, ipsec_tunnel_if_set_key)                     \
-_(IPSEC_TUNNEL_IF_SET_SA, ipsec_tunnel_if_set_sa)                       \
-_(IKEV2_PROFILE_ADD_DEL, ikev2_profile_add_del)                         \
-_(IKEV2_PROFILE_SET_AUTH, ikev2_profile_set_auth)                       \
-_(IKEV2_PROFILE_SET_ID, ikev2_profile_set_id)                           \
-_(IKEV2_PROFILE_SET_TS, ikev2_profile_set_ts)                           \
-_(IKEV2_SET_LOCAL_KEY, ikev2_set_local_key)                             \
-_(IKEV2_SET_RESPONDER, ikev2_set_responder)                             \
-_(IKEV2_SET_IKE_TRANSFORMS, ikev2_set_ike_transforms)                   \
-_(IKEV2_SET_ESP_TRANSFORMS, ikev2_set_esp_transforms)                   \
-_(IKEV2_SET_SA_LIFETIME, ikev2_set_sa_lifetime)                         \
-_(IKEV2_INITIATE_SA_INIT, ikev2_initiate_sa_init)                       \
-_(IKEV2_INITIATE_DEL_IKE_SA, ikev2_initiate_del_ike_sa)                 \
-_(IKEV2_INITIATE_DEL_CHILD_SA, ikev2_initiate_del_child_sa)             \
-_(IKEV2_INITIATE_REKEY_CHILD_SA, ikev2_initiate_rekey_child_sa)
-
-static void vl_api_ipsec_spd_add_del_t_handler
-  (vl_api_ipsec_spd_add_del_t * mp)
+#define foreach_vpe_api_msg                                     \
+_(IPSEC_SPD_ADD_DEL, ipsec_spd_add_del)                         \
+_(IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd)     \
+_(IPSEC_SPD_ADD_DEL_ENTRY, ipsec_spd_add_del_entry)             \
+_(IPSEC_SAD_ADD_DEL_ENTRY, ipsec_sad_add_del_entry)             \
+_(IPSEC_SA_SET_KEY, ipsec_sa_set_key)                           \
+_(IPSEC_SA_DUMP, ipsec_sa_dump)                                 \
+_(IPSEC_SPDS_DUMP, ipsec_spds_dump)                             \
+_(IPSEC_SPD_DUMP, ipsec_spd_dump)                               \
+_(IPSEC_SPD_INTERFACE_DUMP, ipsec_spd_interface_dump)          \
+_(IPSEC_TUNNEL_IF_ADD_DEL, ipsec_tunnel_if_add_del)             \
+_(IPSEC_TUNNEL_IF_SET_KEY, ipsec_tunnel_if_set_key)             \
+_(IPSEC_TUNNEL_IF_SET_SA, ipsec_tunnel_if_set_sa)               \
+_(IKEV2_PROFILE_ADD_DEL, ikev2_profile_add_del)                 \
+_(IKEV2_PROFILE_SET_AUTH, ikev2_profile_set_auth)               \
+_(IKEV2_PROFILE_SET_ID, ikev2_profile_set_id)                   \
+_(IKEV2_PROFILE_SET_TS, ikev2_profile_set_ts)                   \
+_(IKEV2_SET_LOCAL_KEY, ikev2_set_local_key)                     \
+_(IKEV2_SET_RESPONDER, ikev2_set_responder)                     \
+_(IKEV2_SET_IKE_TRANSFORMS, ikev2_set_ike_transforms)           \
+_(IKEV2_SET_ESP_TRANSFORMS, ikev2_set_esp_transforms)           \
+_(IKEV2_SET_SA_LIFETIME, ikev2_set_sa_lifetime)                 \
+_(IKEV2_INITIATE_SA_INIT, ikev2_initiate_sa_init)               \
+_(IKEV2_INITIATE_DEL_IKE_SA, ikev2_initiate_del_ike_sa)         \
+_(IKEV2_INITIATE_DEL_CHILD_SA, ikev2_initiate_del_child_sa)     \
+_(IKEV2_INITIATE_REKEY_CHILD_SA, ikev2_initiate_rekey_child_sa) \
+_(IPSEC_SELECT_BACKEND, ipsec_select_backend)                   \
+_(IPSEC_BACKEND_DUMP, ipsec_backend_dump)
+
+static void
+vl_api_ipsec_spd_add_del_t_handler (vl_api_ipsec_spd_add_del_t * mp)
 {
 #if WITH_LIBSSL == 0
   clib_warning ("unimplemented");
@@ -234,8 +236,7 @@ static void vl_api_ipsec_sad_add_del_entry_t_handler
     }
   sa.use_anti_replay = mp->use_anti_replay;
 
-  ASSERT (im->cb.check_support_cb);
-  clib_error_t *err = im->cb.check_support_cb (&sa);
+  clib_error_t *err = ipsec_check_support_cb (im, &sa);
   if (err)
     {
       clib_warning ("%s", err->what);
@@ -999,6 +1000,92 @@ setup_message_id_table (api_main_t * am)
 #undef _
 }
 
+static void
+vl_api_ipsec_backend_dump_t_handler (vl_api_ipsec_backend_dump_t * mp)
+{
+  vl_api_registration_t *rp;
+  ipsec_main_t *im = &ipsec_main;
+  u32 context = mp->context;
+
+  rp = vl_api_client_index_to_registration (mp->client_index);
+
+  if (rp == 0)
+    {
+      clib_warning ("Client %d AWOL", mp->client_index);
+      return;
+    }
+
+  ipsec_ah_backend_t *ab;
+  ipsec_esp_backend_t *eb;
+  /* *INDENT-OFF* */
+  pool_foreach (ab, im->ah_backends, {
+    vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
+    clib_memset (mp, 0, sizeof (*mp));
+    mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
+    mp->context = context;
+    snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (ab->name),
+              ab->name);
+    mp->protocol = IPSEC_PROTOCOL_AH;
+    mp->index = ab - im->ah_backends;
+    mp->active = mp->index == im->ah_current_backend ? 1 : 0;
+    vl_api_send_msg (rp, (u8 *)mp);
+  });
+  pool_foreach (eb, im->esp_backends, {
+    vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
+    clib_memset (mp, 0, sizeof (*mp));
+    mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
+    mp->context = context;
+    snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (eb->name),
+              eb->name);
+    mp->protocol = IPSEC_PROTOCOL_ESP;
+    mp->index = eb - im->esp_backends;
+    mp->active = mp->index == im->esp_current_backend ? 1 : 0;
+    vl_api_send_msg (rp, (u8 *)mp);
+  });
+  /* *INDENT-ON* */
+}
+
+static void
+vl_api_ipsec_select_backend_t_handler (vl_api_ipsec_select_backend_t * mp)
+{
+  ipsec_main_t *im = &ipsec_main;
+  vl_api_ipsec_select_backend_reply_t *rmp;
+  int rv = 0;
+  if (pool_elts (im->sad) > 0)
+    {
+      rv = VNET_API_ERROR_INSTANCE_IN_USE;
+      goto done;
+    }
+#if WITH_LIBSSL > 0
+  switch (mp->protocol)
+    {
+    case IPSEC_PROTOCOL_ESP:
+      if (pool_is_free_index (im->esp_backends, mp->index))
+       {
+         rv = VNET_API_ERROR_INVALID_VALUE;
+         break;
+       }
+      ipsec_select_esp_backend (im, mp->index);
+      break;
+    case IPSEC_PROTOCOL_AH:
+      if (pool_is_free_index (im->ah_backends, mp->index))
+       {
+         rv = VNET_API_ERROR_INVALID_VALUE;
+         break;
+       }
+      ipsec_select_ah_backend (im, mp->index);
+      break;
+    default:
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      break;
+    }
+#else
+  clib_warning ("unimplemented");      /* FIXME */
+#endif
+done:
+  REPLY_MACRO (VL_API_IPSEC_SELECT_BACKEND_REPLY);
+}
+
 static clib_error_t *
 ipsec_api_hookup (vlib_main_t * vm)
 {
index 4e382bd..ee7dd40 100644 (file)
@@ -174,8 +174,7 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm,
 
   if (is_add)
     {
-      ASSERT (im->cb.check_support_cb);
-      error = im->cb.check_support_cb (&sa);
+      error = ipsec_check_support_cb (im, &sa);
       if (error)
        goto done;
     }
@@ -702,11 +701,148 @@ show_ipsec_command_fn (vlib_main_t * vm,
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (show_ipsec_command, static) = {
     .path = "show ipsec",
-    .short_help = "show ipsec",
+    .short_help = "show ipsec [backends]",
     .function = show_ipsec_command_fn,
 };
 /* *INDENT-ON* */
 
+static clib_error_t *
+ipsec_show_backends_command_fn (vlib_main_t * vm,
+                               unformat_input_t * input,
+                               vlib_cli_command_t * cmd)
+{
+  ipsec_main_t *im = &ipsec_main;
+  u32 verbose = 0;
+
+  (void) unformat (input, "verbose %u", &verbose);
+
+  vlib_cli_output (vm, "IPsec AH backends available:");
+  u8 *s = format (NULL, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
+  ipsec_ah_backend_t *ab;
+  /* *INDENT-OFF* */
+  pool_foreach (ab, im->ah_backends, {
+    s = format (s, "%=25s %=25u %=10s\n", ab->name, ab - im->ah_backends,
+                ab - im->ah_backends == im->ah_current_backend ? "yes" : "no");
+    if (verbose) {
+        vlib_node_t *n;
+        n = vlib_get_node (vm, ab->ah4_encrypt_node_index);
+        s = format (s, "     enc4 %s (next %d)\n", n->name, ab->ah4_encrypt_next_index);
+        n = vlib_get_node (vm, ab->ah4_decrypt_node_index);
+        s = format (s, "     dec4 %s (next %d)\n", n->name, ab->ah4_decrypt_next_index);
+        n = vlib_get_node (vm, ab->ah6_encrypt_node_index);
+        s = format (s, "     enc6 %s (next %d)\n", n->name, ab->ah6_encrypt_next_index);
+        n = vlib_get_node (vm, ab->ah6_decrypt_node_index);
+        s = format (s, "     dec6 %s (next %d)\n", n->name, ab->ah6_decrypt_next_index);
+    }
+  });
+  /* *INDENT-ON* */
+  vlib_cli_output (vm, "%v", s);
+  _vec_len (s) = 0;
+  vlib_cli_output (vm, "IPsec ESP backends available:");
+  s = format (s, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
+  ipsec_esp_backend_t *eb;
+  /* *INDENT-OFF* */
+  pool_foreach (eb, im->esp_backends, {
+    s = format (s, "%=25s %=25u %=10s\n", eb->name, eb - im->esp_backends,
+                eb - im->esp_backends == im->esp_current_backend ? "yes"
+                                                                 : "no");
+    if (verbose) {
+        vlib_node_t *n;
+        n = vlib_get_node (vm, eb->esp4_encrypt_node_index);
+        s = format (s, "     enc4 %s (next %d)\n", n->name, eb->esp4_encrypt_next_index);
+        n = vlib_get_node (vm, eb->esp4_decrypt_node_index);
+        s = format (s, "     dec4 %s (next %d)\n", n->name, eb->esp4_decrypt_next_index);
+        n = vlib_get_node (vm, eb->esp6_encrypt_node_index);
+        s = format (s, "     enc6 %s (next %d)\n", n->name, eb->esp6_encrypt_next_index);
+        n = vlib_get_node (vm, eb->esp6_decrypt_node_index);
+        s = format (s, "     dec6 %s (next %d)\n", n->name, eb->esp6_decrypt_next_index);
+    }
+  });
+  /* *INDENT-ON* */
+  vlib_cli_output (vm, "%v", s);
+
+  vec_free (s);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ipsec_show_backends_command, static) = {
+    .path = "show ipsec backends",
+    .short_help = "show ipsec backends",
+    .function = ipsec_show_backends_command_fn,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+ipsec_select_backend_command_fn (vlib_main_t * vm,
+                                unformat_input_t * input,
+                                vlib_cli_command_t * cmd)
+{
+  u32 backend_index;
+  ipsec_main_t *im = &ipsec_main;
+
+  if (pool_elts (im->sad) > 0)
+    {
+      return clib_error_return (0,
+                               "Cannot change IPsec backend, while %u SA entries are configured",
+                               pool_elts (im->sad));
+    }
+
+  unformat_input_t _line_input, *line_input = &_line_input;
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  if (unformat (line_input, "ah"))
+    {
+      if (unformat (line_input, "%u", &backend_index))
+       {
+         if (ipsec_select_ah_backend (im, backend_index) < 0)
+           {
+             return clib_error_return (0, "Invalid AH backend index `%u'",
+                                       backend_index);
+           }
+       }
+      else
+       {
+         return clib_error_return (0, "Invalid backend index `%U'",
+                                   format_unformat_error, line_input);
+       }
+    }
+  else if (unformat (line_input, "esp"))
+    {
+      if (unformat (line_input, "%u", &backend_index))
+       {
+         if (ipsec_select_esp_backend (im, backend_index) < 0)
+           {
+             return clib_error_return (0, "Invalid ESP backend index `%u'",
+                                       backend_index);
+           }
+       }
+      else
+       {
+         return clib_error_return (0, "Invalid backend index `%U'",
+                                   format_unformat_error, line_input);
+       }
+    }
+  else
+    {
+      return clib_error_return (0, "Unknown input `%U'",
+                               format_unformat_error, line_input);
+    }
+
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ipsec_select_backend_command, static) = {
+    .path = "ipsec select backend",
+    .short_help = "ipsec select backend <ah|esp> <backend index>",
+    .function = ipsec_select_backend_command_fn,
+};
+
+/* *INDENT-ON* */
+
 static clib_error_t *
 clear_ipsec_counters_command_fn (vlib_main_t * vm,
                                 unformat_input_t * input,
index b8cba14..2e0dae0 100644 (file)
@@ -170,33 +170,25 @@ ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
 
   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     {
-      ASSERT (im->cb.check_support_cb);
-
       sa = pool_elt_at_index (im->sad, t->input_sa_index);
 
-      err = im->cb.check_support_cb (sa);
+      err = ipsec_check_support_cb (im, sa);
       if (err)
        return err;
 
-      if (im->cb.add_del_sa_sess_cb)
-       {
-         err = im->cb.add_del_sa_sess_cb (t->input_sa_index, 1);
-         if (err)
-           return err;
-       }
+      err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 1);
+      if (err)
+       return err;
 
       sa = pool_elt_at_index (im->sad, t->output_sa_index);
 
-      err = im->cb.check_support_cb (sa);
+      err = ipsec_check_support_cb (im, sa);
       if (err)
        return err;
 
-      if (im->cb.add_del_sa_sess_cb)
-       {
-         err = im->cb.add_del_sa_sess_cb (t->output_sa_index, 1);
-         if (err)
-           return err;
-       }
+      err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 1);
+      if (err)
+       return err;
 
       vnet_hw_interface_set_flags (vnm, hw_if_index,
                                   VNET_HW_INTERFACE_FLAG_LINK_UP);
@@ -204,24 +196,14 @@ ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
   else
     {
       vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
-
       sa = pool_elt_at_index (im->sad, t->input_sa_index);
-
-      if (im->cb.add_del_sa_sess_cb)
-       {
-         err = im->cb.add_del_sa_sess_cb (t->input_sa_index, 0);
-         if (err)
-           return err;
-       }
-
+      err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 0);
+      if (err)
+       return err;
       sa = pool_elt_at_index (im->sad, t->output_sa_index);
-
-      if (im->cb.add_del_sa_sess_cb)
-       {
-         err = im->cb.add_del_sa_sess_cb (t->output_sa_index, 0);
-         if (err)
-           return err;
-       }
+      err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 0);
+      if (err)
+       return err;
     }
 
   return /* no error */ 0;
@@ -596,15 +578,11 @@ ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
   if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index)
     hash_unset (im->sa_index_by_sa_id, old_sa->id);
 
-  if (im->cb.add_del_sa_sess_cb)
+  if (!ipsec_add_del_sa_sess_cb (im, old_sa_index, 0))
     {
-      clib_error_t *err;
-
-      err = im->cb.add_del_sa_sess_cb (old_sa_index, 0);
-      if (err)
-       return VNET_API_ERROR_SYSCALL_ERROR_1;
+      clib_warning ("IPsec backend add/del callback returned error");
+      return VNET_API_ERROR_SYSCALL_ERROR_1;
     }
-
   pool_put (im->sad, old_sa);
 
   return 0;
index bf13d71..bb45696 100644 (file)
@@ -95,6 +95,11 @@ class TemplateIpsec(VppTestCase):
     vpp_esp_protocol = 1
     vpp_ah_protocol = 0
 
+    @classmethod
+    def ipsec_select_backend(cls):
+        """ empty method to be overloaded when necessary """
+        pass
+
     @classmethod
     def setUpClass(cls):
         super(TemplateIpsec, cls).setUpClass()
@@ -106,6 +111,7 @@ class TemplateIpsec(VppTestCase):
             i.resolve_arp()
             i.config_ip6()
             i.resolve_ndp()
+        cls.ipsec_select_backend()
 
     def tearDown(self):
         super(TemplateIpsec, self).tearDown()
index 59f6864..e832bfa 100644 (file)
@@ -12,16 +12,6 @@ class TemplateIpsecAh(TemplateIpsec):
     """
     Basic test for IPSEC using AH transport and Tunnel mode
 
-    Below 4 cases are covered as part of this test
-    1) ipsec ah v4 transport basic test  - IPv4 Transport mode
-     scenario using HMAC-SHA1-96 intergrity algo
-    2) ipsec ah v4 transport burst test
-     Above test for 257 pkts
-    3) ipsec ah 4o4 tunnel basic test    - IPv4 Tunnel mode
-     scenario using HMAC-SHA1-96 intergrity algo
-    4) ipsec ah 4o4 tunnel burst test
-     Above test for 257 pkts
-
     TRANSPORT MODE:
 
      ---   encrypt   ---
@@ -180,7 +170,14 @@ class TemplateIpsecAh(TemplateIpsec):
 
 class TestIpsecAh1(TemplateIpsecAh, IpsecTraTests, IpsecTunTests):
     """ Ipsec AH - TUN & TRA tests """
-    pass
+    tra4_encrypt_node_name = "ah4-encrypt"
+    tra4_decrypt_node_name = "ah4-decrypt"
+    tra6_encrypt_node_name = "ah6-encrypt"
+    tra6_decrypt_node_name = "ah6-decrypt"
+    tun4_encrypt_node_name = "ah4-encrypt"
+    tun4_decrypt_node_name = "ah4-decrypt"
+    tun6_encrypt_node_name = "ah6-encrypt"
+    tun6_decrypt_node_name = "ah6-decrypt"
 
 
 class TestIpsecAh2(TemplateIpsecAh, IpsecTcpTests):
diff --git a/test/test_ipsec_api.py b/test/test_ipsec_api.py
new file mode 100644 (file)
index 0000000..fed996e
--- /dev/null
@@ -0,0 +1,78 @@
+import unittest
+
+from framework import VppTestCase, VppTestRunner
+from template_ipsec import TemplateIpsec
+
+
+class IpsecApiTestCase(VppTestCase):
+    """ IPSec API tests """
+
+    @classmethod
+    def setUpClass(cls):
+        super(IpsecApiTestCase, cls).setUpClass()
+        cls.create_pg_interfaces([0])
+        cls.pg0.config_ip4()
+        cls.pg0.admin_up()
+
+    def test_backend_dump(self):
+        """ backend dump """
+        d = self.vapi.ipsec_backend_dump()
+        self.assert_equal(len(d), 2, "number of ipsec backends in dump")
+        self.assert_equal(d[0].protocol, TemplateIpsec.vpp_ah_protocol,
+                          "ipsec protocol in dump entry")
+        self.assert_equal(d[0].index, 0, "index in dump entry")
+        self.assert_equal(d[0].active, 1, "active flag in dump entry")
+        self.assert_equal(d[1].protocol, TemplateIpsec.vpp_esp_protocol,
+                          "ipsec protocol in dump entry")
+        self.assert_equal(d[1].index, 0, "index in dump entry")
+        self.assert_equal(d[1].active, 1, "active flag in dump entry")
+
+    def test_select_valid_backend(self):
+        """ select valid backend """
+        self.vapi.ipsec_select_backend(TemplateIpsec.vpp_ah_protocol, 0)
+        self.vapi.ipsec_select_backend(TemplateIpsec.vpp_esp_protocol, 0)
+
+    def test_select_invalid_backend(self):
+        """ select invalid backend """
+        with self.vapi.assert_negative_api_retval():
+            self.vapi.ipsec_select_backend(TemplateIpsec.vpp_ah_protocol, 200)
+        with self.vapi.assert_negative_api_retval():
+            self.vapi.ipsec_select_backend(TemplateIpsec.vpp_esp_protocol, 200)
+
+    def test_select_backend_in_use(self):
+        """ attempt to change backend while sad configured """
+        params = TemplateIpsec.ipv4_params
+        addr_type = params.addr_type
+        is_ipv6 = params.is_ipv6
+        scapy_tun_sa_id = params.scapy_tun_sa_id
+        scapy_tun_spi = params.scapy_tun_spi
+        auth_algo_vpp_id = params.auth_algo_vpp_id
+        auth_key = params.auth_key
+        crypt_algo_vpp_id = params.crypt_algo_vpp_id
+        crypt_key = params.crypt_key
+
+        self.vapi.ipsec_sad_add_del_entry(scapy_tun_sa_id, scapy_tun_spi,
+                                          auth_algo_vpp_id, auth_key,
+                                          crypt_algo_vpp_id, crypt_key,
+                                          TemplateIpsec.vpp_ah_protocol,
+                                          self.pg0.local_addr_n[addr_type],
+                                          self.pg0.remote_addr_n[addr_type],
+                                          is_tunnel=1, is_tunnel_ipv6=is_ipv6)
+        with self.vapi.assert_negative_api_retval():
+            self.vapi.ipsec_select_backend(
+                protocol=TemplateIpsec.vpp_ah_protocol, index=0)
+
+        self.vapi.ipsec_sad_add_del_entry(scapy_tun_sa_id, scapy_tun_spi,
+                                          auth_algo_vpp_id, auth_key,
+                                          crypt_algo_vpp_id, crypt_key,
+                                          TemplateIpsec.vpp_ah_protocol,
+                                          self.pg0.local_addr_n[addr_type],
+                                          self.pg0.remote_addr_n[addr_type],
+                                          is_tunnel=1, is_tunnel_ipv6=is_ipv6,
+                                          is_add=0)
+        self.vapi.ipsec_select_backend(
+            protocol=TemplateIpsec.vpp_ah_protocol, index=0)
+
+
+if __name__ == '__main__':
+    unittest.main(testRunner=VppTestRunner)
index 23cf660..ed9d0d9 100644 (file)
@@ -174,7 +174,14 @@ class TemplateIpsecEsp(TemplateIpsec):
 
 class TestIpsecEsp1(TemplateIpsecEsp, IpsecTraTests, IpsecTunTests):
     """ Ipsec ESP - TUN & TRA tests """
-    pass
+    tra4_encrypt_node_name = "esp4-encrypt"
+    tra4_decrypt_node_name = "esp4-decrypt"
+    tra6_encrypt_node_name = "esp6-encrypt"
+    tra6_decrypt_node_name = "esp6-decrypt"
+    tun4_encrypt_node_name = "esp4-encrypt"
+    tun4_decrypt_node_name = "esp4-decrypt"
+    tun6_encrypt_node_name = "esp6-encrypt"
+    tun6_decrypt_node_name = "esp6-decrypt"
 
 
 class TestIpsecEsp2(TemplateIpsecEsp, IpsecTcpTests):
index 292458d..e10e2a3 100644 (file)
@@ -37,7 +37,8 @@ class TemplateIpsecTunIfEsp(TemplateIpsec):
 
 class TestIpsecTunIfEsp1(TemplateIpsecTunIfEsp, IpsecTun4Tests):
     """ Ipsec ESP - TUN tests """
-    pass
+    tun4_encrypt_node_name = "esp4-encrypt"
+    tun4_decrypt_node_name = "esp4-decrypt"
 
 
 class TestIpsecTunIfEsp2(TemplateIpsecTunIfEsp, IpsecTcpTests):
index 82990bc..1fcc4ce 100644 (file)
@@ -3452,6 +3452,13 @@ class VppPapiProvider(object):
              'show_instance': show_instance
              })
 
+    def ipsec_select_backend(self, protocol, index):
+        return self.api(self.papi.ipsec_select_backend,
+                        {'protocol': protocol, 'index': index})
+
+    def ipsec_backend_dump(self):
+        return self.api(self.papi.ipsec_backend_dump, {})
+
     def app_namespace_add(self,
                           namespace_id,
                           ip4_fib_id=0,