aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/ipsec
diff options
context:
space:
mode:
authorKlement Sekera <ksekera@cisco.com>2018-11-08 13:00:02 +0100
committerDamjan Marion <dmarion@me.com>2018-11-15 12:57:18 +0000
commitb4d3053445499a115f0f4debde6a8c7b29a8c071 (patch)
treea1af7ee05a56199285ee9c6e39bbfe73d4d12c8c /src/vnet/ipsec
parent2b209e3ee05ec719f566f1d071a82f4e3c6a9417 (diff)
ipsec: infra for selecting backends
Change-Id: Ifa6d8391b1b2413a88b7720fc434e0bc849a149a Signed-off-by: Klement Sekera <ksekera@cisco.com> Signed-off-by: Andrew Yourtchenko <ayourtch@gmail.com>
Diffstat (limited to 'src/vnet/ipsec')
-rw-r--r--src/vnet/ipsec/ipsec.api36
-rw-r--r--src/vnet/ipsec/ipsec.c271
-rw-r--r--src/vnet/ipsec/ipsec.h145
-rw-r--r--src/vnet/ipsec/ipsec_api.c149
-rw-r--r--src/vnet/ipsec/ipsec_cli.c142
-rw-r--r--src/vnet/ipsec/ipsec_if.c56
6 files changed, 622 insertions, 177 deletions
diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api
index 793422d86fb..148cdcdc675 100644
--- a/src/vnet/ipsec/ipsec.api
+++ b/src/vnet/ipsec/ipsec.api
@@ -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")
diff --git a/src/vnet/ipsec/ipsec.c b/src/vnet/ipsec/ipsec.c
index 6e4c7f1b687..8ebc57956bb 100644
--- a/src/vnet/ipsec/ipsec.c
+++ b/src/vnet/ipsec/ipsec.c
@@ -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;
diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h
index 6a9c5b1c824..ced71194f39 100644
--- a/src/vnet/ipsec/ipsec.h
+++ b/src/vnet/ipsec/ipsec.h
@@ -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__ */
/*
diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c
index ced2c9ce6cd..f2333646cd0 100644
--- a/src/vnet/ipsec/ipsec_api.c
+++ b/src/vnet/ipsec/ipsec_api.c
@@ -47,35 +47,37 @@
#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)
{
diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c
index 4e382bdeab5..ee7dd404a87 100644
--- a/src/vnet/ipsec/ipsec_cli.c
+++ b/src/vnet/ipsec/ipsec_cli.c
@@ -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,12 +701,149 @@ 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,
vlib_cli_command_t * cmd)
diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c
index b8cba149584..2e0dae0a35d 100644
--- a/src/vnet/ipsec/ipsec_if.c
+++ b/src/vnet/ipsec/ipsec_if.c
@@ -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;