From 873b9ed405f291a954a8f45a0bba6b136d6ff19f Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 23 Apr 2019 20:57:55 -0400 Subject: IPSEC; dpdk backend for tunnel interface encryption (VPP-1662) Change-Id: Ide2a9df18db371c8428855d7f12f246006d7c04c Signed-off-by: Neale Ranns --- src/plugins/dpdk/ipsec/esp_encrypt.c | 77 ++++++++++++++++++++++++++++++++++-- src/plugins/dpdk/ipsec/ipsec.c | 2 + src/vnet/api_errno.h | 3 +- src/vnet/ipsec/ipsec.c | 66 +++++++++++++++++++++++-------- src/vnet/ipsec/ipsec.h | 10 +++++ src/vnet/ipsec/ipsec_api.c | 16 ++------ src/vnet/ipsec/ipsec_cli.c | 15 ++++--- src/vnet/ipsec/ipsec_if.c | 38 ++++++++++-------- src/vnet/ipsec/ipsec_sa.c | 2 +- src/vnet/ipsec/ipsec_sa.h | 1 - 10 files changed, 169 insertions(+), 61 deletions(-) diff --git a/src/plugins/dpdk/ipsec/esp_encrypt.c b/src/plugins/dpdk/ipsec/esp_encrypt.c index 908f846e315..6c3258602dd 100644 --- a/src/plugins/dpdk/ipsec/esp_encrypt.c +++ b/src/plugins/dpdk/ipsec/esp_encrypt.c @@ -110,7 +110,7 @@ format_esp_encrypt_trace (u8 * s, va_list * args) always_inline uword dpdk_esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * from_frame, int is_ip6) + vlib_frame_t * from_frame, int is_ip6, int is_tun) { u32 n_left_from, *from, *to_next, next_index, thread_index; ipsec_main_t *im = &ipsec_main; @@ -200,7 +200,16 @@ dpdk_esp_encrypt_inline (vlib_main_t * vm, sizeof (op[0]) + sizeof (op[0].sym[0]) + sizeof (priv[0]); CLIB_PREFETCH (op, op_len, STORE); - sa_index0 = vnet_buffer (b0)->ipsec.sad_index; + if (is_tun) + { + u32 tmp; + /* we are on a ipsec tunnel's feature arc */ + sa_index0 = *(u32 *) vnet_feature_next_with_data (&tmp, b0, + sizeof + (sa_index0)); + } + else + sa_index0 = vnet_buffer (b0)->ipsec.sad_index; if (sa_index0 != last_sa_index) { @@ -576,7 +585,7 @@ VLIB_NODE_FN (dpdk_esp4_encrypt_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { - return dpdk_esp_encrypt_inline (vm, node, from_frame, 0 /*is_ip6 */ ); + return dpdk_esp_encrypt_inline (vm, node, from_frame, 0 /*is_ip6 */ , 0); } /* *INDENT-OFF* */ @@ -599,7 +608,7 @@ VLIB_NODE_FN (dpdk_esp6_encrypt_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { - return dpdk_esp_encrypt_inline (vm, node, from_frame, 1 /*is_ip6 */ ); + return dpdk_esp_encrypt_inline (vm, node, from_frame, 1 /*is_ip6 */ , 0); } /* *INDENT-OFF* */ @@ -618,6 +627,66 @@ VLIB_REGISTER_NODE (dpdk_esp6_encrypt_node) = { }; /* *INDENT-ON* */ +VLIB_NODE_FN (dpdk_esp4_encrypt_tun_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + return dpdk_esp_encrypt_inline (vm, node, from_frame, 0 /*is_ip6 */ , 1); +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dpdk_esp4_encrypt_tun_node) = { + .name = "dpdk-esp4-encrypt-tun", + .flags = VLIB_NODE_FLAG_IS_OUTPUT, + .vector_size = sizeof (u32), + .format_trace = format_esp_encrypt_trace, + .n_errors = ARRAY_LEN (esp_encrypt_error_strings), + .error_strings = esp_encrypt_error_strings, + .n_next_nodes = 1, + .next_nodes = + { + [ESP_ENCRYPT_NEXT_DROP] = "error-drop", + } +}; + +VNET_FEATURE_INIT (dpdk_esp4_encrypt_tun_feat_node, static) = +{ + .arc_name = "ip4-output", + .node_name = "dpdk-esp4-encrypt-tun", + .runs_before = VNET_FEATURES ("adj-midchain-tx"), +}; +/* *INDENT-ON* */ + +VLIB_NODE_FN (dpdk_esp6_encrypt_tun_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + return dpdk_esp_encrypt_inline (vm, node, from_frame, 1 /*is_ip6 */ , 1); +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (dpdk_esp6_encrypt_tun_node) = { + .name = "dpdk-esp6-encrypt-tun", + .flags = VLIB_NODE_FLAG_IS_OUTPUT, + .vector_size = sizeof (u32), + .format_trace = format_esp_encrypt_trace, + .n_errors = ARRAY_LEN (esp_encrypt_error_strings), + .error_strings = esp_encrypt_error_strings, + .n_next_nodes = 1, + .next_nodes = + { + [ESP_ENCRYPT_NEXT_DROP] = "error-drop", + } +}; + +VNET_FEATURE_INIT (dpdk_esp6_encrypt_tun_feat_node, static) = +{ + .arc_name = "ip6-output", + .node_name = "dpdk-esp6-encrypt-tun", + .runs_before = VNET_FEATURES ("adj-midchain-tx"), +}; +/* *INDENT-ON* */ + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/dpdk/ipsec/ipsec.c b/src/plugins/dpdk/ipsec/ipsec.c index 682bcaf21c8..88fd75dcf1a 100644 --- a/src/plugins/dpdk/ipsec/ipsec.c +++ b/src/plugins/dpdk/ipsec/ipsec.c @@ -1069,8 +1069,10 @@ dpdk_ipsec_process (vlib_main_t * vm, vlib_node_runtime_t * rt, u32 idx = ipsec_register_esp_backend (vm, im, "dpdk backend", "dpdk-esp4-encrypt", + "dpdk-esp4-encrypt-tun", "dpdk-esp4-decrypt", "dpdk-esp6-encrypt", + "dpdk-esp6-encrypt-tun", "dpdk-esp6-decrypt", dpdk_ipsec_check_support, add_del_sa_session); diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index b474e194636..c4cb3c9dda7 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -147,7 +147,8 @@ _(INVALID_VALUE_3, -150, "Invalid value #3") \ _(NON_ETHERNET, -151, "Interface is not an Ethernet interface") \ _(BD_ALREADY_HAS_BVI, -152, "Bridge domain already has a BVI interface") \ _(INVALID_PROTOCOL, -153, "Invalid Protocol") \ -_(INVALID_ALGORITHM, -154, "Invalid Algorithm") +_(INVALID_ALGORITHM, -154, "Invalid Algorithm") \ +_(RSRC_IN_USE, -155, "Resource In Use") typedef enum { diff --git a/src/vnet/ipsec/ipsec.c b/src/vnet/ipsec/ipsec.c index 73c5cf4d7ab..b9392af2bd6 100644 --- a/src/vnet/ipsec/ipsec.c +++ b/src/vnet/ipsec/ipsec.c @@ -100,6 +100,16 @@ ipsec_add_node (vlib_main_t * vm, const char *node_name, *out_next_index = vlib_node_add_next (vm, prev_node->index, node->index); } +static void +ipsec_add_feature (const char *arc_name, + const char *node_name, u32 * out_feature_index) +{ + u8 arc; + + arc = vnet_get_feature_arc_index (arc_name); + *out_feature_index = vnet_get_feature_index (arc, node_name); +} + u32 ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im, const char *name, @@ -132,13 +142,16 @@ 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_encrypt_node_tun_name, const char *esp4_decrypt_node_name, const char *esp6_encrypt_node_name, + const char *esp6_encrypt_node_tun_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 (0, "%s%c", name, 0); @@ -151,27 +164,42 @@ ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im, ipsec_add_node (vm, esp6_decrypt_node_name, "ipsec6-input-feature", &b->esp6_decrypt_node_index, &b->esp6_decrypt_next_index); + ipsec_add_feature ("ip4-output", esp4_encrypt_node_tun_name, + &b->esp4_encrypt_tun_feature_index); + ipsec_add_feature ("ip6-output", esp6_encrypt_node_tun_name, + &b->esp6_encrypt_tun_feature_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; } -static walk_rc_t -ipsec_sa_restack (ipsec_sa_t * sa, void *ctx) +clib_error_t * +ipsec_rsc_in_use (ipsec_main_t * im) { - ipsec_sa_stack (sa); - - return (WALK_CONTINUE); + /* return an error is crypto resource are in use */ + if (pool_elts (im->sad) > 0) + return clib_error_return (0, + "%d SA entries configured", + pool_elts (im->sad)); + + if (pool_elts (im->tunnel_interfaces)) + return clib_error_return (0, + "%d tunnel-interface entries configured", + pool_elts (im->tunnel_interfaces)); + + return (NULL); } 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; - } + if (ipsec_rsc_in_use (im)) + return VNET_API_ERROR_RSRC_IN_USE; + + if (pool_is_free_index (im->ah_backends, backend_idx)) + return VNET_API_ERROR_INVALID_VALUE; + 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; @@ -183,18 +211,18 @@ ipsec_select_ah_backend (ipsec_main_t * im, u32 backend_idx) im->ah6_encrypt_next_index = b->ah6_encrypt_next_index; im->ah6_decrypt_next_index = b->ah6_decrypt_next_index; - ipsec_sa_walk (ipsec_sa_restack, NULL); 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; - } + if (ipsec_rsc_in_use (im)) + return VNET_API_ERROR_RSRC_IN_USE; + + if (pool_is_free_index (im->esp_backends, backend_idx)) + return VNET_API_ERROR_INVALID_VALUE; + 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; @@ -206,7 +234,9 @@ ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx) im->esp6_encrypt_next_index = b->esp6_encrypt_next_index; im->esp6_decrypt_next_index = b->esp6_decrypt_next_index; - ipsec_sa_walk (ipsec_sa_restack, NULL); + im->esp4_encrypt_tun_feature_index = b->esp4_encrypt_tun_feature_index; + im->esp6_encrypt_tun_feature_index = b->esp6_encrypt_tun_feature_index; + return 0; } @@ -243,8 +273,10 @@ ipsec_init (vlib_main_t * vm) idx = ipsec_register_esp_backend (vm, im, "default openssl backend", "esp4-encrypt", + "esp4-encrypt-tun", "esp4-decrypt", "esp6-encrypt", + "esp6-encrypt-tun", "esp6-decrypt", ipsec_check_esp_support, NULL); im->esp_default_backend = idx; diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h index 110bbcb3e5a..ea4b4a58ead 100644 --- a/src/vnet/ipsec/ipsec.h +++ b/src/vnet/ipsec/ipsec.h @@ -62,6 +62,8 @@ typedef struct u32 esp6_decrypt_node_index; u32 esp6_encrypt_next_index; u32 esp6_decrypt_next_index; + u32 esp4_encrypt_tun_feature_index; + u32 esp6_encrypt_tun_feature_index; } ipsec_esp_backend_t; typedef struct @@ -132,6 +134,10 @@ typedef struct u32 ah6_encrypt_next_index; u32 ah6_decrypt_next_index; + /* tun encrypt arcs and feature nodes */ + u32 esp4_encrypt_tun_feature_index; + u32 esp6_encrypt_tun_feature_index; + /* pool of ah backends */ ipsec_ah_backend_t *ah_backends; /* pool of esp backends */ @@ -212,8 +218,10 @@ u32 ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im, 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_encrypt_tun_node_name, const char *esp4_decrypt_node_name, const char *esp6_encrypt_node_name, + const char *esp6_encrypt_tun_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); @@ -221,6 +229,8 @@ u32 ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im, 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); +clib_error_t *ipsec_rsc_in_use (ipsec_main_t * im); + always_inline ipsec_sa_t * ipsec_sa_get (u32 sa_index) { diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c index 767cd2fb076..4311a30f859 100644 --- a/src/vnet/ipsec/ipsec_api.c +++ b/src/vnet/ipsec/ipsec_api.c @@ -909,23 +909,13 @@ vl_api_ipsec_select_backend_t_handler (vl_api_ipsec_select_backend_t * mp) switch (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); + rv = 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); + rv = ipsec_select_ah_backend (im, mp->index); break; default: - rv = VNET_API_ERROR_INVALID_VALUE; + rv = VNET_API_ERROR_INVALID_PROTOCOL; break; } #else diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c index 096060865e9..b97fb02b66d 100644 --- a/src/vnet/ipsec/ipsec_cli.c +++ b/src/vnet/ipsec/ipsec_cli.c @@ -658,17 +658,16 @@ ipsec_select_backend_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - u32 backend_index; + unformat_input_t _line_input, *line_input = &_line_input; ipsec_main_t *im = &ipsec_main; + clib_error_t *error; + u32 backend_index; - 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)); - } + error = ipsec_rsc_in_use (im); + + if (error) + return error; - 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; diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c index 8d0eef21ae0..46902055aad 100644 --- a/src/vnet/ipsec/ipsec_if.c +++ b/src/vnet/ipsec/ipsec_if.c @@ -231,18 +231,25 @@ ipsec_tun_mk_output_sa_id (u32 ti) } static void -ipsec_tunnel_feature_set (ipsec_tunnel_if_t * t, u8 enable) +ipsec_tunnel_feature_set (ipsec_main_t * im, ipsec_tunnel_if_t * t, u8 enable) { - vnet_feature_enable_disable ("ip4-output", - "esp4-encrypt-tun", - t->sw_if_index, enable, - &t->output_sa_index, - sizeof (t->output_sa_index)); - vnet_feature_enable_disable ("ip6-output", - "esp6-encrypt-tun", - t->sw_if_index, enable, - &t->output_sa_index, - sizeof (t->output_sa_index)); + u8 arc; + + arc = vnet_get_feature_arc_index ("ip4-output"); + + vnet_feature_enable_disable_with_index (arc, + im->esp4_encrypt_tun_feature_index, + t->sw_if_index, enable, + &t->output_sa_index, + sizeof (t->output_sa_index)); + + arc = vnet_get_feature_arc_index ("ip6-output"); + + vnet_feature_enable_disable_with_index (arc, + im->esp6_encrypt_tun_feature_index, + t->sw_if_index, enable, + &t->output_sa_index, + sizeof (t->output_sa_index)); } int @@ -377,7 +384,7 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, ~0); im->ipsec_if_by_sw_if_index[t->sw_if_index] = dev_instance; - ipsec_tunnel_feature_set (t, 1); + ipsec_tunnel_feature_set (im, t, 1); /*1st interface, register protocol */ if (pool_elts (im->tunnel_interfaces) == 1) @@ -402,7 +409,7 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, hi = vnet_get_hw_interface (vnm, t->hw_if_index); vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */ - ipsec_tunnel_feature_set (t, 0); + ipsec_tunnel_feature_set (im, t, 0); vnet_delete_hw_interface (vnm, t->hw_if_index); if (is_ip6) @@ -650,9 +657,9 @@ ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id, * re-enable the feature to get the new SA in * the workers are stopped so no packets are sent in the clear */ - ipsec_tunnel_feature_set (t, 0); + ipsec_tunnel_feature_set (im, t, 0); t->output_sa_index = sa_index; - ipsec_tunnel_feature_set (t, 1); + ipsec_tunnel_feature_set (im, t, 1); } /* remove sa_id to sa_index mapping on old SA */ @@ -669,7 +676,6 @@ ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id, return 0; } - clib_error_t * ipsec_tunnel_if_init (vlib_main_t * vm) { diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c index 8f41c95159b..d696e933bf7 100644 --- a/src/vnet/ipsec/ipsec_sa.c +++ b/src/vnet/ipsec/ipsec_sa.c @@ -66,7 +66,7 @@ ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len) /** * 'stack' (resolve the recursion for) the SA tunnel destination */ -void +static void ipsec_sa_stack (ipsec_sa_t * sa) { ipsec_main_t *im = &ipsec_main; diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h index f87e12e0204..f25a760592e 100644 --- a/src/vnet/ipsec/ipsec_sa.h +++ b/src/vnet/ipsec/ipsec_sa.h @@ -203,7 +203,6 @@ extern int ipsec_sa_add (u32 id, const ip46_address_t * tunnel_dst_addr, u32 * sa_index); extern u32 ipsec_sa_del (u32 id); -extern void ipsec_sa_stack (ipsec_sa_t * sa); extern void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa, ipsec_crypto_alg_t crypto_alg); extern void ipsec_sa_set_integ_alg (ipsec_sa_t * sa, -- cgit 1.2.3-korg