diff options
author | Klement Sekera <ksekera@cisco.com> | 2018-11-08 13:00:02 +0100 |
---|---|---|
committer | Damjan Marion <dmarion@me.com> | 2018-11-15 12:57:18 +0000 |
commit | b4d3053445499a115f0f4debde6a8c7b29a8c071 (patch) | |
tree | a1af7ee05a56199285ee9c6e39bbfe73d4d12c8c /src/vnet | |
parent | 2b209e3ee05ec719f566f1d071a82f4e3c6a9417 (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')
-rw-r--r-- | src/vnet/ipsec/ipsec.api | 36 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.c | 271 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.h | 145 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_api.c | 149 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_cli.c | 142 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if.c | 56 |
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; |