diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/vnet/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/vnet/ipsec/esp_decrypt.c | 34 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.api | 10 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.c | 8 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.h | 4 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_api.c | 288 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_cli.c | 155 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_format.c | 34 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if.c | 600 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if.h | 108 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if_in.c | 721 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_sa.c | 14 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_sa.h | 1 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_tun.c | 119 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_tun.h | 37 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_tun_in.c | 15 |
16 files changed, 495 insertions, 1658 deletions
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index 7120809636e..b4ea14e9762 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -570,8 +570,6 @@ list(APPEND VNET_SOURCES ipsec/ipsec_cli.c ipsec/ipsec_format.c ipsec/ipsec_input.c - ipsec/ipsec_if.c - ipsec/ipsec_if_in.c ipsec/ipsec_punt.c ipsec/ipsec_sa.c ipsec/ipsec_spd.c @@ -591,7 +589,6 @@ list(APPEND VNET_MULTIARCH_SOURCES ipsec/esp_decrypt.c ipsec/ah_decrypt.c ipsec/ah_encrypt.c - ipsec/ipsec_if_in.c ipsec/ipsec_output.c ipsec/ipsec_input.c ipsec/ipsec_tun_in.c @@ -608,7 +605,7 @@ list(APPEND VNET_HEADERS ipsec/ipsec_spd.h ipsec/ipsec_spd_policy.h ipsec/ipsec_sa.h - ipsec/ipsec_if.h + ipsec/ipsec_tun.h ipsec/ipsec_punt.h ipsec/esp.h ipsec/ah.h diff --git a/src/vnet/ipsec/esp_decrypt.c b/src/vnet/ipsec/esp_decrypt.c index 986ac94676c..cddda1f8e54 100644 --- a/src/vnet/ipsec/esp_decrypt.c +++ b/src/vnet/ipsec/esp_decrypt.c @@ -47,7 +47,8 @@ typedef enum _(RUNT, "undersized packet") \ _(CHAINED_BUFFER, "chained buffers (packet dropped)") \ _(OVERSIZED_HEADER, "buffer with oversized header (dropped)") \ - _(NO_TAIL_SPACE, "no enough buffer tail space (dropped)") + _(NO_TAIL_SPACE, "no enough buffer tail space (dropped)") \ + _(TUN_NO_PROTO, "no tunnel protocol") \ typedef enum @@ -497,8 +498,11 @@ esp_decrypt_inline (vlib_main_t * vm, &ip4->dst_address) || !ip46_address_is_equal_v4 (&itp->itp_tun.dst, &ip4->src_address)) - next[0] = ESP_DECRYPT_NEXT_DROP; - + { + next[0] = ESP_DECRYPT_NEXT_DROP; + b[0]->error = + node->errors[ESP_DECRYPT_ERROR_TUN_NO_PROTO]; + } } else if (f->next_header == IP_PROTOCOL_IPV6) { @@ -510,7 +514,11 @@ esp_decrypt_inline (vlib_main_t * vm, &ip6->dst_address) || !ip46_address_is_equal_v6 (&itp->itp_tun.dst, &ip6->src_address)) - next[0] = ESP_DECRYPT_NEXT_DROP; + { + next[0] = ESP_DECRYPT_NEXT_DROP; + b[0]->error = + node->errors[ESP_DECRYPT_ERROR_TUN_NO_PROTO]; + } } } } @@ -615,16 +623,9 @@ VLIB_REGISTER_NODE (esp4_decrypt_tun_node) = { .vector_size = sizeof (u32), .format_trace = format_esp_decrypt_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(esp_decrypt_error_strings), .error_strings = esp_decrypt_error_strings, - - .n_next_nodes = ESP_DECRYPT_N_NEXT, - .next_nodes = { -#define _(s,n) [ESP_DECRYPT_NEXT_##s] = n, - foreach_esp_decrypt_next -#undef _ - }, + .sibling_of = "esp4-decrypt", }; VLIB_REGISTER_NODE (esp6_decrypt_tun_node) = { @@ -632,16 +633,9 @@ VLIB_REGISTER_NODE (esp6_decrypt_tun_node) = { .vector_size = sizeof (u32), .format_trace = format_esp_decrypt_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(esp_decrypt_error_strings), .error_strings = esp_decrypt_error_strings, - - .n_next_nodes = ESP_DECRYPT_N_NEXT, - .next_nodes = { -#define _(s,n) [ESP_DECRYPT_NEXT_##s] = n, - foreach_esp_decrypt_next -#undef _ - }, + .sibling_of = "esp6-decrypt", }; /* *INDENT-ON* */ diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api index 12bdad0f9c3..72677d6e0ea 100644 --- a/src/vnet/ipsec/ipsec.api +++ b/src/vnet/ipsec/ipsec.api @@ -368,6 +368,9 @@ autoreply define ipsec_tunnel_protect_del vl_api_interface_index_t sw_if_index; }; +/** + * @brief Dump all tunnel protections + */ define ipsec_tunnel_protect_dump { u32 client_index; @@ -407,6 +410,10 @@ define ipsec_spd_interface_details { }; /** \brief Add or delete IPsec tunnel interface + + !!DEPRECATED!! + use the tunnel protect APIs instead + @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_add - add IPsec tunnel interface if nonzero, else delete @@ -523,6 +530,9 @@ define ipsec_sa_details { }; /** \brief Set new SA on IPsec interface + + !! DEPRECATED !! + @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - index of tunnel interface diff --git a/src/vnet/ipsec/ipsec.c b/src/vnet/ipsec/ipsec.c index 9f3e1d36507..c54b94a4799 100644 --- a/src/vnet/ipsec/ipsec.c +++ b/src/vnet/ipsec/ipsec.c @@ -206,11 +206,6 @@ ipsec_rsc_in_use (ipsec_main_t * im) "%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); } @@ -315,9 +310,6 @@ ipsec_init (vlib_main_t * vm) if ((error = vlib_call_init_function (vm, ipsec_cli_init))) return error; - if ((error = vlib_call_init_function (vm, ipsec_tunnel_if_init))) - return error; - vec_validate (im->crypto_algs, IPSEC_CRYPTO_N_ALG - 1); a = im->crypto_algs + IPSEC_CRYPTO_ALG_NONE; diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h index 3c3cb0469ca..be928a2572e 100644 --- a/src/vnet/ipsec/ipsec.h +++ b/src/vnet/ipsec/ipsec.h @@ -25,7 +25,6 @@ #include <vnet/ipsec/ipsec_spd.h> #include <vnet/ipsec/ipsec_spd_policy.h> #include <vnet/ipsec/ipsec_sa.h> -#include <vnet/ipsec/ipsec_if.h> 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); @@ -98,9 +97,6 @@ typedef struct /* pool of policies */ ipsec_policy_t *policies; - /* pool of tunnel interfaces */ - ipsec_tunnel_if_t *tunnel_interfaces; - uword *tunnel_index_by_key; /* convenience */ diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c index 371e4fe4ed0..b1b6db7e290 100644 --- a/src/vnet/ipsec/ipsec_api.c +++ b/src/vnet/ipsec/ipsec_api.c @@ -25,6 +25,7 @@ #include <vnet/ip/ip.h> #include <vnet/ip/ip_types_api.h> #include <vnet/fib/fib.h> +#include <vnet/ipip/ipip.h> #include <vnet/vnet_msg_enum.h> @@ -159,16 +160,16 @@ static void vl_api_ipsec_tunnel_protect_del_t_handler REPLY_MACRO (VL_API_IPSEC_TUNNEL_PROTECT_DEL_REPLY); } -typedef struct ipsec_tunnel_protect_walk_ctx_t_ +typedef struct ipsec_dump_walk_ctx_t_ { vl_api_registration_t *reg; u32 context; -} ipsec_tunnel_protect_walk_ctx_t; +} ipsec_dump_walk_ctx_t; static walk_rc_t send_ipsec_tunnel_protect_details (index_t itpi, void *arg) { - ipsec_tunnel_protect_walk_ctx_t *ctx = arg; + ipsec_dump_walk_ctx_t *ctx = arg; vl_api_ipsec_tunnel_protect_details_t *mp; ipsec_tun_protect_t *itp; u32 sai, ii = 0; @@ -209,7 +210,7 @@ vl_api_ipsec_tunnel_protect_dump_t_handler (vl_api_ipsec_tunnel_protect_dump_t if (!reg) return; - ipsec_tunnel_protect_walk_ctx_t ctx = { + ipsec_dump_walk_ctx_t ctx = { .reg = reg, .context = mp->context, }; @@ -383,7 +384,6 @@ ipsec_crypto_algo_encode (ipsec_crypto_alg_t c) return (VNET_API_ERROR_UNIMPLEMENTED); } - static int ipsec_integ_algo_decode (vl_api_ipsec_integ_alg_t in, ipsec_integ_alg_t * out) { @@ -719,56 +719,146 @@ vl_api_ipsec_spd_interface_dump_t_handler (vl_api_ipsec_spd_interface_dump_t * #endif } +static u32 +ipsec_tun_mk_input_sa_id (u32 ti) +{ + return (0x80000000 | ti); +} + +static u32 +ipsec_tun_mk_output_sa_id (u32 ti) +{ + return (0xc0000000 | ti); +} + static void vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t * mp) { vl_api_ipsec_tunnel_if_add_del_reply_t *rmp; - ipsec_main_t *im = &ipsec_main; - vnet_main_t *vnm = im->vnet_main; u32 sw_if_index = ~0; - ip46_type_t itype; int rv; #if WITH_LIBSSL > 0 - ipsec_add_del_tunnel_args_t tun; - - clib_memset (&tun, 0, sizeof (ipsec_add_del_tunnel_args_t)); - - tun.is_add = mp->is_add; - tun.esn = mp->esn; - tun.anti_replay = mp->anti_replay; - tun.local_spi = ntohl (mp->local_spi); - tun.remote_spi = ntohl (mp->remote_spi); - tun.crypto_alg = mp->crypto_alg; - tun.local_crypto_key_len = mp->local_crypto_key_len; - tun.remote_crypto_key_len = mp->remote_crypto_key_len; - tun.integ_alg = mp->integ_alg; - tun.local_integ_key_len = mp->local_integ_key_len; - tun.remote_integ_key_len = mp->remote_integ_key_len; - tun.udp_encap = mp->udp_encap; - tun.tx_table_id = ntohl (mp->tx_table_id); - tun.salt = mp->salt; - itype = ip_address_decode (&mp->local_ip, &tun.local_ip); - itype = ip_address_decode (&mp->remote_ip, &tun.remote_ip); - tun.is_ip6 = (IP46_TYPE_IP6 == itype); - memcpy (&tun.local_crypto_key, &mp->local_crypto_key, - mp->local_crypto_key_len); - memcpy (&tun.remote_crypto_key, &mp->remote_crypto_key, - mp->remote_crypto_key_len); - memcpy (&tun.local_integ_key, &mp->local_integ_key, - mp->local_integ_key_len); - memcpy (&tun.remote_integ_key, &mp->remote_integ_key, - mp->remote_integ_key_len); - tun.renumber = mp->renumber; - tun.show_instance = ntohl (mp->show_instance); - - rv = ipsec_add_del_tunnel_if_internal (vnm, &tun, &sw_if_index); + ip46_address_t local_ip = ip46_address_initializer; + ip46_address_t remote_ip = ip46_address_initializer; + ipsec_key_t crypto_key, integ_key; + ipsec_sa_flags_t flags; + ip46_type_t local_ip_type, remote_ip_type; + ipip_transport_t transport; + u32 fib_index; + + local_ip_type = ip_address_decode (&mp->local_ip, &local_ip); + remote_ip_type = ip_address_decode (&mp->remote_ip, &remote_ip); + transport = (IP46_TYPE_IP6 == local_ip_type ? + IPIP_TRANSPORT_IP6 : IPIP_TRANSPORT_IP4); + + if (local_ip_type != remote_ip_type) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto done; + } + + flags = IPSEC_SA_FLAG_NONE; + + if (mp->udp_encap) + flags |= IPSEC_SA_FLAG_UDP_ENCAP; + if (mp->esn) + flags |= IPSEC_SA_FLAG_USE_ESN; + if (mp->anti_replay) + flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY; + + ipsec_mk_key (&crypto_key, mp->remote_crypto_key, + mp->remote_crypto_key_len); + ipsec_mk_key (&integ_key, mp->remote_integ_key, mp->remote_integ_key_len); + ipsec_mk_key (&crypto_key, mp->local_crypto_key, mp->local_crypto_key_len); + ipsec_mk_key (&integ_key, mp->local_integ_key, mp->local_integ_key_len); + + fib_index = + fib_table_find (fib_proto_from_ip46 (local_ip_type), + ntohl (mp->tx_table_id)); + + if (~0 == fib_index) + { + rv = VNET_API_ERROR_NO_SUCH_FIB; + goto done; + } + + if (mp->is_add) + { + // remote = input, local = output + /* create an ip-ip tunnel, then the two SA, then bind them */ + rv = ipip_add_tunnel (transport, + ntohl (mp->show_instance), + &local_ip, + &remote_ip, fib_index, 0, &sw_if_index); + + if (rv) + goto done; + + rv = ipsec_sa_add_and_lock (ipsec_tun_mk_input_sa_id (sw_if_index), + ntohl (mp->remote_spi), + IPSEC_PROTOCOL_ESP, + mp->crypto_alg, + &crypto_key, + mp->integ_alg, + &integ_key, + (flags | IPSEC_SA_FLAG_IS_INBOUND), + ntohl (mp->tx_table_id), + mp->salt, &remote_ip, &local_ip, NULL); + + if (rv) + goto done; + + rv = ipsec_sa_add_and_lock (ipsec_tun_mk_output_sa_id (sw_if_index), + ntohl (mp->local_spi), + IPSEC_PROTOCOL_ESP, + mp->crypto_alg, + &crypto_key, + mp->integ_alg, + &integ_key, + flags, + ntohl (mp->tx_table_id), + mp->salt, &local_ip, &remote_ip, NULL); + + if (rv) + goto done; + + rv = ipsec_tun_protect_update_one (sw_if_index, + ipsec_tun_mk_output_sa_id + (sw_if_index), + ipsec_tun_mk_input_sa_id + (sw_if_index)); + if (rv) + goto done; + + /* the SAs are locked as a result of being used for proection, + * they cannot be removed from the API, since they cannot be refered + * to by the API. unlock them now, so that if the tunnel is rekeyed + * they-ll disapper + */ + ipsec_sa_unlock_id (ipsec_tun_mk_input_sa_id (sw_if_index)); + ipsec_sa_unlock_id (ipsec_tun_mk_output_sa_id (sw_if_index)); + } + else + { + + ipip_tunnel_key_t key = { + .transport = transport, + .fib_index = fib_index, + .src = local_ip, + .dst = remote_ip + }; + ipip_tunnel_t *t = ipip_tunnel_db_find (&key); + + rv = ipsec_tun_protect_del (t->sw_if_index); + ipip_del_tunnel (t->sw_if_index); + } #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif - +done: /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY, ({ @@ -777,16 +867,51 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t * /* *INDENT-ON* */ } -static void -send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg, - u32 context, u32 sw_if_index) +typedef struct ipsec_sa_dump_match_ctx_t_ { + index_t sai; + u32 sw_if_index; +} ipsec_sa_dump_match_ctx_t; + +static walk_rc_t +ipsec_sa_dump_match_sa (index_t itpi, void *arg) +{ + ipsec_sa_dump_match_ctx_t *ctx = arg; + ipsec_tun_protect_t *itp; + index_t sai; + + itp = ipsec_tun_protect_get (itpi); + + if (itp->itp_out_sa == ctx->sai) + { + ctx->sw_if_index = itp->itp_sw_if_index; + return (WALK_STOP); + } + /* *INDENT-OFF* */ + FOR_EACH_IPSEC_PROTECT_INPUT_SAI (itp, sai, + ({ + if (sai == ctx->sai) + { + ctx->sw_if_index = itp->itp_sw_if_index; + return (WALK_STOP); + } + })); + /* *INDENT-OFF* */ + + return (WALK_CONTINUE); +} + +static walk_rc_t +send_ipsec_sa_details (ipsec_sa_t * sa, void *arg) +{ + ipsec_dump_walk_ctx_t *ctx = arg; vl_api_ipsec_sa_details_t *mp; + ipsec_main_t *im = &ipsec_main; mp = vl_msg_api_alloc (sizeof (*mp)); clib_memset (mp, 0, sizeof (*mp)); mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_DETAILS); - mp->context = context; + mp->context = ctx->context; mp->entry.sad_id = htonl (sa->id); mp->entry.spi = htonl (sa->spi); @@ -801,6 +926,20 @@ send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg, ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key); mp->entry.flags = ipsec_sad_flags_encode (sa); + mp->entry.salt = clib_host_to_net_u32 (sa->salt); + + if (ipsec_sa_is_set_IS_PROTECT (sa)) + { + ipsec_sa_dump_match_ctx_t ctx = { + .sai = sa - im->sad, + .sw_if_index = ~0, + }; + ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx); + + mp->sw_if_index = htonl (ctx.sw_if_index); + } + else + mp->sw_if_index = ~0; if (ipsec_sa_is_set_IS_TUNNEL (sa)) { @@ -810,8 +949,6 @@ send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg, &mp->entry.tunnel_dst); } - mp->sw_if_index = htonl (sw_if_index); - mp->salt = clib_host_to_net_u32 (sa->salt); mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq)); mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq)); if (ipsec_sa_is_set_USE_ESN (sa)) @@ -822,49 +959,28 @@ send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg, if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa)) mp->replay_window = clib_host_to_net_u64 (sa->replay_window); - vl_api_send_msg (reg, (u8 *) mp); -} + vl_api_send_msg (ctx->reg, (u8 *) mp); + return (WALK_CONTINUE); +} static void vl_api_ipsec_sa_dump_t_handler (vl_api_ipsec_sa_dump_t * mp) { vl_api_registration_t *reg; - ipsec_main_t *im = &ipsec_main; - vnet_main_t *vnm = im->vnet_main; - ipsec_sa_t *sa; - ipsec_tunnel_if_t *t; - u32 *sa_index_to_tun_if_index = 0; #if WITH_LIBSSL > 0 reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg || pool_elts (im->sad) == 0) + if (!reg) return; - vec_validate_init_empty (sa_index_to_tun_if_index, vec_len (im->sad) - 1, - ~0); - - /* *INDENT-OFF* */ - pool_foreach (t, im->tunnel_interfaces, - ({ - vnet_hw_interface_t *hi; - u32 sw_if_index = ~0; - - hi = vnet_get_hw_interface (vnm, t->hw_if_index); - sw_if_index = hi->sw_if_index; - sa_index_to_tun_if_index[t->input_sa_index] = sw_if_index; - sa_index_to_tun_if_index[t->output_sa_index] = sw_if_index; - })); + ipsec_dump_walk_ctx_t ctx = { + .reg = reg, + .context = mp->context, + }; - pool_foreach (sa, im->sad, - ({ - if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == sa->id) - send_ipsec_sa_details (sa, reg, mp->context, - sa_index_to_tun_if_index[sa - im->sad]); - })); - /* *INDENT-ON* */ + ipsec_sa_walk (send_ipsec_sa_details, &ctx); - vec_free (sa_index_to_tun_if_index); #else clib_warning ("unimplemented"); #endif @@ -874,20 +990,24 @@ static void vl_api_ipsec_tunnel_if_set_sa_t_handler (vl_api_ipsec_tunnel_if_set_sa_t * mp) { vl_api_ipsec_tunnel_if_set_sa_reply_t *rmp; - ipsec_main_t *im = &ipsec_main; - vnet_main_t *vnm = im->vnet_main; - vnet_sw_interface_t *sw; int rv; #if WITH_LIBSSL > 0 - sw = vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index)); + VALIDATE_SW_IF_INDEX(mp); + + if (mp->is_outbound) + rv = ipsec_tun_protect_update_out (ntohl (mp->sw_if_index), + ntohl (mp->sa_id)); + else + rv = ipsec_tun_protect_update_in (ntohl (mp->sw_if_index), + ntohl (mp->sa_id)); - rv = ipsec_set_interface_sa (vnm, sw->hw_if_index, ntohl (mp->sa_id), - mp->is_outbound); #else clib_warning ("unimplemented"); #endif + BAD_SW_IF_INDEX_LABEL; + REPLY_MACRO (VL_API_IPSEC_TUNNEL_IF_SET_SA_REPLY); } diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c index 1bff6086741..630e60a43ec 100644 --- a/src/vnet/ipsec/ipsec_cli.c +++ b/src/vnet/ipsec/ipsec_cli.c @@ -20,6 +20,7 @@ #include <vnet/ip/ip.h> #include <vnet/interface.h> #include <vnet/fib/fib.h> +#include <vnet/ipip/ipip.h> #include <vnet/ipsec/ipsec.h> #include <vnet/ipsec/ipsec_tun.h> @@ -386,17 +387,18 @@ ipsec_spd_bindings_show_all (vlib_main_t * vm, ipsec_main_t * im) /* *INDENT-ON* */ } -static void -ipsec_tunnel_show_all (vlib_main_t * vm, ipsec_main_t * im) +static walk_rc_t +ipsec_tun_protect_show_one (index_t itpi, void *ctx) { - u32 ti; + vlib_cli_output (ctx, "%U", format_ipsec_tun_protect, itpi); - vlib_cli_output (vm, "Tunnel interfaces"); - /* *INDENT-OFF* */ - pool_foreach_index (ti, im->tunnel_interfaces, ({ - vlib_cli_output(vm, " %U", format_ipsec_tunnel, ti); - })); - /* *INDENT-ON* */ + return (WALK_CONTINUE); +} + +static void +ipsec_tunnel_show_all (vlib_main_t * vm) +{ + ipsec_tun_protect_walk (ipsec_tun_protect_show_one, vm); } static clib_error_t * @@ -408,7 +410,7 @@ show_ipsec_command_fn (vlib_main_t * vm, ipsec_sa_show_all (vm, im, 0); ipsec_spd_show_all (vm, im); ipsec_spd_bindings_show_all (vm, im); - ipsec_tunnel_show_all (vm, im); + ipsec_tun_protect_walk (ipsec_tun_protect_show_one, vm); return 0; } @@ -537,21 +539,7 @@ show_ipsec_tunnel_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - ipsec_main_t *im = &ipsec_main; - u32 ti = ~0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "%u", &ti)) - ; - else - break; - } - - if (~0 != ti) - vlib_cli_output (vm, "%U", format_ipsec_tunnel, ti); - else - ipsec_tunnel_show_all (vm, im); + ipsec_tunnel_show_all (vm); return 0; } @@ -559,7 +547,7 @@ show_ipsec_tunnel_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_ipsec_tunnel_command, static) = { .path = "show ipsec tunnel", - .short_help = "show ipsec tunnel [index]", + .short_help = "show ipsec tunnel", .function = show_ipsec_tunnel_command_fn, }; /* *INDENT-ON* */ @@ -719,25 +707,44 @@ VLIB_CLI_COMMAND (clear_ipsec_counters_command, static) = { }; /* *INDENT-ON* */ +static u32 +ipsec_tun_mk_local_sa_id (u32 ti) +{ + return (0x80000000 | ti); +} + +static u32 +ipsec_tun_mk_remote_sa_id (u32 ti) +{ + return (0xc0000000 | ti); +} + static clib_error_t * create_ipsec_tunnel_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - ipsec_add_del_tunnel_args_t a; + ip46_address_t local_ip = ip46_address_initializer; + ip46_address_t remote_ip = ip46_address_initializer; + ipsec_crypto_alg_t crypto_alg; + ipsec_integ_alg_t integ_alg; + ipsec_sa_flags_t flags; + u32 local_spi, remote_spi, salt, table_id, fib_index; + u32 instance = ~0; int rv; u32 num_m_args = 0; u8 ipv4_set = 0; u8 ipv6_set = 0; + u8 is_add = 1; clib_error_t *error = NULL; ipsec_key_t rck = { 0 }; ipsec_key_t lck = { 0 }; ipsec_key_t lik = { 0 }; ipsec_key_t rik = { 0 }; - clib_memset (&a, 0, sizeof (a)); - a.is_add = 1; + table_id = 0; + flags = IPSEC_SA_FLAG_NONE; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -746,36 +753,35 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat - (line_input, "local-ip %U", unformat_ip46_address, &a.local_ip, + (line_input, "local-ip %U", unformat_ip46_address, &local_ip, IP46_TYPE_ANY)) { - ip46_address_is_ip4 (&a.local_ip) ? (ipv4_set = 1) : (ipv6_set = 1); + ip46_address_is_ip4 (&local_ip) ? (ipv4_set = 1) : (ipv6_set = 1); num_m_args++; } else if (unformat - (line_input, "remote-ip %U", unformat_ip46_address, &a.remote_ip, + (line_input, "remote-ip %U", unformat_ip46_address, &remote_ip, IP46_TYPE_ANY)) { - ip46_address_is_ip4 (&a.remote_ip) ? (ipv4_set = 1) : (ipv6_set = - 1); + ip46_address_is_ip4 (&remote_ip) ? (ipv4_set = 1) : (ipv6_set = 1); num_m_args++; } - else if (unformat (line_input, "local-spi %u", &a.local_spi)) + else if (unformat (line_input, "local-spi %u", &local_spi)) num_m_args++; - else if (unformat (line_input, "remote-spi %u", &a.remote_spi)) + else if (unformat (line_input, "remote-spi %u", &remote_spi)) num_m_args++; - else if (unformat (line_input, "instance %u", &a.show_instance)) - a.renumber = 1; - else if (unformat (line_input, "salt 0x%x", &a.salt)) + else if (unformat (line_input, "salt 0x%x", &salt)) ; else if (unformat (line_input, "udp-encap")) - a.udp_encap = 1; + flags |= IPSEC_SA_FLAG_UDP_ENCAP; else if (unformat (line_input, "use-esn")) - a.esn = 1; + flags |= IPSEC_SA_FLAG_USE_ESN; else if (unformat (line_input, "use-anti-replay")) - a.anti_replay = 1; - else if (unformat (line_input, "tx-table %u", &a.tx_table_id)) + flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY; + else if (unformat (line_input, "instance %u", &instance)) + ; + else if (unformat (line_input, "tx-table %u", &table_id)) ; else if (unformat @@ -786,7 +792,7 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm, (line_input, "remote-crypto-key %U", unformat_ipsec_key, &rck)) ; else if (unformat (line_input, "crypto-alg %U", - unformat_ipsec_crypto_alg, &a.crypto_alg)) + unformat_ipsec_crypto_alg, &crypto_alg)) ; else if (unformat @@ -797,10 +803,10 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm, (line_input, "remote-integ-key %U", unformat_ipsec_key, &rik)) ; else if (unformat (line_input, "integ-alg %U", - unformat_ipsec_integ_alg, &a.integ_alg)) + unformat_ipsec_integ_alg, &integ_alg)) ; else if (unformat (line_input, "del")) - a.is_add = 0; + is_add = 0; else { error = clib_error_return (0, "unknown input `%U'", @@ -818,26 +824,52 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm, if (ipv4_set && ipv6_set) return clib_error_return (0, "both IPv4 and IPv6 addresses specified"); - a.is_ip6 = ipv6_set; - - clib_memcpy (a.local_crypto_key, lck.data, lck.len); - a.local_crypto_key_len = lck.len; - clib_memcpy (a.remote_crypto_key, rck.data, rck.len); - a.remote_crypto_key_len = rck.len; + fib_index = fib_table_find (fib_ip_proto (ipv6_set), table_id); - clib_memcpy (a.local_integ_key, lik.data, lik.len); - a.local_integ_key_len = lck.len; - clib_memcpy (a.remote_integ_key, rik.data, rik.len); - a.remote_integ_key_len = rck.len; + if (~0 == fib_index) + { + rv = VNET_API_ERROR_NO_SUCH_FIB; + goto done; + } - rv = ipsec_add_del_tunnel_if (&a); + if (is_add) + { + // remote = input, local = output + u32 sw_if_index; + + /* create an ip-ip tunnel, then the two SA, then bind them */ + rv = + ipip_add_tunnel (ipv6_set ? IPIP_TRANSPORT_IP6 : IPIP_TRANSPORT_IP4, + instance, &local_ip, &remote_ip, fib_index, 0, + &sw_if_index); + rv |= + ipsec_sa_add_and_lock (ipsec_tun_mk_local_sa_id (sw_if_index), + local_spi, IPSEC_PROTOCOL_ESP, crypto_alg, + &lck, integ_alg, &lik, flags, table_id, + clib_host_to_net_u32 (salt), &local_ip, + &remote_ip, NULL); + rv |= + ipsec_sa_add_and_lock (ipsec_tun_mk_remote_sa_id (sw_if_index), + remote_spi, IPSEC_PROTOCOL_ESP, crypto_alg, + &rck, integ_alg, &rik, + (flags | IPSEC_SA_FLAG_IS_INBOUND), table_id, + clib_host_to_net_u32 (salt), &remote_ip, + &local_ip, NULL); + rv |= + ipsec_tun_protect_update_one (sw_if_index, + ipsec_tun_mk_local_sa_id (sw_if_index), + ipsec_tun_mk_remote_sa_id + (sw_if_index)); + } + else + rv = 0; switch (rv) { case 0: break; case VNET_API_ERROR_INVALID_VALUE: - if (a.is_add) + if (is_add) error = clib_error_return (0, "IPSec tunnel interface already exists..."); else @@ -918,13 +950,6 @@ VLIB_CLI_COMMAND (ipsec_tun_protect_cmd_node, static) = }; /* *INDENT-ON* */ -static walk_rc_t -ipsec_tun_protect_show_one (index_t itpi, void *ctx) -{ - vlib_cli_output (ctx, "%U", format_ipsec_tun_protect, itpi); - - return (WALK_CONTINUE); -} static clib_error_t * ipsec_tun_protect_show (vlib_main_t * vm, diff --git a/src/vnet/ipsec/ipsec_format.c b/src/vnet/ipsec/ipsec_format.c index bd7ebe45186..e6e828931dd 100644 --- a/src/vnet/ipsec/ipsec_format.c +++ b/src/vnet/ipsec/ipsec_format.c @@ -335,40 +335,6 @@ done: } u8 * -format_ipsec_tunnel (u8 * s, va_list * args) -{ - ipsec_main_t *im = &ipsec_main; - u32 ti = va_arg (*args, u32); - ipsec_tunnel_if_t *t; - - if (pool_is_free_index (im->tunnel_interfaces, ti)) - { - s = format (s, "No such tunnel index: %d", ti); - goto done; - } - - t = pool_elt_at_index (im->tunnel_interfaces, ti); - - if (t->hw_if_index == ~0) - goto done; - - s = - format (s, "%U\n", format_vnet_hw_if_index_name, im->vnet_main, - t->hw_if_index); - - s = format (s, " out-bound sa: "); - s = format (s, "%U\n", format_ipsec_sa, t->output_sa_index, - IPSEC_FORMAT_BRIEF); - - s = format (s, " in-bound sa: "); - s = format (s, "%U\n", format_ipsec_sa, t->input_sa_index, - IPSEC_FORMAT_BRIEF); - -done: - return (s); -} - -u8 * format_ipsec_tun_protect (u8 * s, va_list * args) { u32 itpi = va_arg (*args, u32); diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c deleted file mode 100644 index a7372747797..00000000000 --- a/src/vnet/ipsec/ipsec_if.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * ipsec_if.c : IPSec interface support - * - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <vnet/vnet.h> -#include <vnet/api_errno.h> -#include <vnet/ip/ip.h> -#include <vnet/fib/fib.h> -#include <vnet/udp/udp.h> -#include <vnet/adj/adj_midchain.h> - -#include <vnet/ipsec/ipsec.h> -#include <vnet/ipsec/esp.h> - -void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); - -static u8 * -format_ipsec_name (u8 * s, va_list * args) -{ - u32 dev_instance = va_arg (*args, u32); - ipsec_main_t *im = &ipsec_main; - ipsec_tunnel_if_t *t = im->tunnel_interfaces + dev_instance; - - return format (s, "ipsec%d", t->show_instance); -} - -/* Statistics (not really errors) */ -#define foreach_ipsec_if_tx_error \ -_(TX, "good packets transmitted") - -static void -ipsec_if_tunnel_stack (adj_index_t ai) -{ - ipsec_main_t *ipm = &ipsec_main; - ipsec_tunnel_if_t *it; - ip_adjacency_t *adj; - u32 sw_if_index; - - adj = adj_get (ai); - sw_if_index = adj->rewrite_header.sw_if_index; - - if ((vec_len (ipm->ipsec_if_by_sw_if_index) <= sw_if_index) || - (~0 == ipm->ipsec_if_by_sw_if_index[sw_if_index])) - return; - - it = pool_elt_at_index (ipm->tunnel_interfaces, - ipm->ipsec_if_by_sw_if_index[sw_if_index]); - - if (!vnet_hw_interface_is_link_up (vnet_get_main (), it->hw_if_index)) - { - adj_midchain_delegate_unstack (ai); - } - else - { - ipsec_sa_t *sa; - - sa = ipsec_sa_get (it->output_sa_index); - - /* *INDENT-OFF* */ - fib_prefix_t pfx = { - .fp_addr = sa->tunnel_dst_addr, - .fp_len = (ipsec_sa_is_set_IS_TUNNEL_V6(sa) ? 128 : 32), - .fp_proto = (ipsec_sa_is_set_IS_TUNNEL_V6(sa) ? - FIB_PROTOCOL_IP6 : - FIB_PROTOCOL_IP4), - }; - /* *INDENT-ON* */ - - adj_midchain_delegate_stack (ai, sa->tx_fib_index, &pfx); - } -} - -/** - * @brief Call back when restacking all adjacencies on a IPSec interface - */ -static adj_walk_rc_t -ipsec_if_adj_walk_cb (adj_index_t ai, void *ctx) -{ - ipsec_if_tunnel_stack (ai); - - return (ADJ_WALK_RC_CONTINUE); -} - -static void -ipsec_if_tunnel_restack (ipsec_tunnel_if_t * it) -{ - fib_protocol_t proto; - - /* - * walk all the adjacencies on the IPSec interface and restack them - */ - FOR_EACH_FIB_IP_PROTOCOL (proto) - { - adj_nbr_walk (it->sw_if_index, proto, ipsec_if_adj_walk_cb, NULL); - } -} - -static clib_error_t * -ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags) -{ - ipsec_main_t *im = &ipsec_main; - clib_error_t *err = 0; - ipsec_tunnel_if_t *t; - vnet_hw_interface_t *hi; - ipsec_sa_t *sa; - - hi = vnet_get_hw_interface (vnm, hw_if_index); - t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance); - t->flags = flags; - - if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) - { - sa = pool_elt_at_index (im->sad, t->input_sa_index); - - err = ipsec_check_support_cb (im, sa); - 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 = ipsec_check_support_cb (im, sa); - 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); - } - else - { - vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ ); - sa = pool_elt_at_index (im->sad, t->input_sa_index); - 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); - err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 0); - if (err) - return err; - } - - ipsec_if_tunnel_restack (t); - - return (NULL); -} - -static u8 * -ipsec_if_build_rewrite (vnet_main_t * vnm, - u32 sw_if_index, - vnet_link_t link_type, const void *dst_address) -{ - return (NULL); -} - -static void -ipsec_if_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai) -{ - adj_nbr_midchain_update_rewrite - (ai, NULL, NULL, ADJ_FLAG_MIDCHAIN_IP_STACK, - ipsec_if_build_rewrite (vnm, sw_if_index, adj_get_link_type (ai), NULL)); - - ipsec_if_tunnel_stack (ai); -} - -/* *INDENT-OFF* */ -VNET_DEVICE_CLASS (ipsec_device_class) = -{ - .name = "IPSec", - .format_device_name = format_ipsec_name, - .admin_up_down_function = ipsec_admin_up_down_function, -}; -/* *INDENT-ON* */ - -/* *INDENT-OFF* */ -VNET_HW_INTERFACE_CLASS (ipsec_hw_class) = -{ - .name = "IPSec", - .build_rewrite = default_build_rewrite, - .update_adjacency = ipsec_if_update_adj, - .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, -}; -/* *INDENT-ON* */ - -static int -ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a) -{ - vnet_main_t *vnm = vnet_get_main (); - ASSERT (vlib_get_thread_index () == 0); - - return ipsec_add_del_tunnel_if_internal (vnm, a, NULL); -} - -int -ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args) -{ - vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback, - (u8 *) args, sizeof (*args)); - return 0; -} - -static u32 -ipsec_tun_mk_input_sa_id (u32 ti) -{ - return (0x80000000 | ti); -} - -static u32 -ipsec_tun_mk_output_sa_id (u32 ti) -{ - return (0xc0000000 | ti); -} - -static void -ipsec_tunnel_feature_set (ipsec_main_t * im, ipsec_tunnel_if_t * t, u8 enable) -{ - u8 arc; - u32 esp4_feature_index, esp6_feature_index; - ipsec_sa_t *sa; - - sa = ipsec_sa_get (t->output_sa_index); - if (sa->crypto_alg == IPSEC_CRYPTO_ALG_NONE && - sa->integ_alg == IPSEC_INTEG_ALG_NONE) - { - esp4_feature_index = im->esp4_no_crypto_tun_feature_index; - esp6_feature_index = im->esp6_no_crypto_tun_feature_index; - } - else - { - esp4_feature_index = im->esp4_encrypt_tun_feature_index; - esp6_feature_index = im->esp6_encrypt_tun_feature_index; - } - - arc = vnet_get_feature_arc_index ("ip4-output"); - - vnet_feature_enable_disable_with_index (arc, esp4_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, esp6_feature_index, - t->sw_if_index, enable, - &t->output_sa_index, - sizeof (t->output_sa_index)); -} - -int -ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, - ipsec_add_del_tunnel_args_t * args, - u32 * sw_if_index_p) -{ - ipsec_tunnel_if_t *t; - ipsec_main_t *im = &ipsec_main; - vnet_hw_interface_t *hi = NULL; - u32 hw_if_index = ~0; - u32 sw_if_index = ~0; - uword *p; - u32 dev_instance; - ipsec_key_t crypto_key, integ_key; - ipsec_sa_flags_t flags; - int rv; - int is_ip6 = args->is_ip6; - ipsec4_tunnel_key_t key4; - ipsec6_tunnel_key_t key6; - - if (!is_ip6) - { - key4.remote_ip.as_u32 = args->remote_ip.ip4.as_u32; - key4.spi = clib_host_to_net_u32 (args->remote_spi); - p = hash_get (im->ipsec4_if_pool_index_by_key, key4.as_u64); - } - else - { - key6.remote_ip = args->remote_ip.ip6; - key6.spi = clib_host_to_net_u32 (args->remote_spi); - p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key6); - } - - if (args->is_add) - { - /* check if same src/dst pair exists */ - if (p) - return VNET_API_ERROR_INVALID_VALUE; - - pool_get_aligned_zero (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES); - - dev_instance = t - im->tunnel_interfaces; - if (args->renumber) - t->show_instance = args->show_instance; - else - t->show_instance = dev_instance; - - if (hash_get (im->ipsec_if_real_dev_by_show_dev, t->show_instance)) - { - pool_put (im->tunnel_interfaces, t); - return VNET_API_ERROR_INSTANCE_IN_USE; - } - - hash_set (im->ipsec_if_real_dev_by_show_dev, t->show_instance, - dev_instance); - - flags = IPSEC_SA_FLAG_IS_TUNNEL; - if (args->is_ip6) - flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6; - if (args->udp_encap) - flags |= IPSEC_SA_FLAG_UDP_ENCAP; - if (args->esn) - flags |= IPSEC_SA_FLAG_USE_ESN; - if (args->anti_replay) - flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY; - - ipsec_mk_key (&crypto_key, - args->remote_crypto_key, args->remote_crypto_key_len); - ipsec_mk_key (&integ_key, - args->remote_integ_key, args->remote_integ_key_len); - - rv = ipsec_sa_add_and_lock (ipsec_tun_mk_input_sa_id (dev_instance), - args->remote_spi, - IPSEC_PROTOCOL_ESP, - args->crypto_alg, - &crypto_key, - args->integ_alg, - &integ_key, - (flags | IPSEC_SA_FLAG_IS_INBOUND), - args->tx_table_id, - args->salt, - &args->remote_ip, - &args->local_ip, &t->input_sa_index); - - if (rv) - return rv; - - ipsec_mk_key (&crypto_key, - args->local_crypto_key, args->local_crypto_key_len); - ipsec_mk_key (&integ_key, - args->local_integ_key, args->local_integ_key_len); - - rv = ipsec_sa_add_and_lock (ipsec_tun_mk_output_sa_id (dev_instance), - args->local_spi, - IPSEC_PROTOCOL_ESP, - args->crypto_alg, - &crypto_key, - args->integ_alg, - &integ_key, - flags, - args->tx_table_id, - args->salt, - &args->local_ip, - &args->remote_ip, &t->output_sa_index); - - if (rv) - return rv; - - /* copy the key */ - if (is_ip6) - hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key6, - t - im->tunnel_interfaces); - else - hash_set (im->ipsec4_if_pool_index_by_key, key4.as_u64, - t - im->tunnel_interfaces); - - hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index, - t - im->tunnel_interfaces, - ipsec_hw_class.index, - t - im->tunnel_interfaces); - - hi = vnet_get_hw_interface (vnm, hw_if_index); - sw_if_index = hi->sw_if_index; - - t->hw_if_index = hw_if_index; - t->sw_if_index = hi->sw_if_index; - - /* Standard default jumbo MTU. */ - vnet_sw_interface_set_mtu (vnm, t->sw_if_index, 9000); - - /* Add the new tunnel to the DB of tunnels per sw_if_index ... */ - vec_validate_init_empty (im->ipsec_if_by_sw_if_index, t->sw_if_index, - ~0); - im->ipsec_if_by_sw_if_index[t->sw_if_index] = dev_instance; - - ipsec_tunnel_feature_set (im, t, 1); - - /*1st interface, register protocol */ - if (pool_elts (im->tunnel_interfaces) == 1) - { - ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP, - ipsec4_if_input_node.index); - ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP, - ipsec6_if_input_node.index); - } - - } - else - { - u32 ti; - - /* check if exists */ - if (!p) - return VNET_API_ERROR_INVALID_VALUE; - - ti = p[0]; - t = pool_elt_at_index (im->tunnel_interfaces, ti); - hi = vnet_get_hw_interface (vnm, t->hw_if_index); - sw_if_index = hi->sw_if_index; - - vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */ - - ipsec_tunnel_feature_set (im, t, 0); - vnet_delete_hw_interface (vnm, t->hw_if_index); - - if (is_ip6) - hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key6); - else - hash_unset (im->ipsec4_if_pool_index_by_key, key4.as_u64); - hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance); - - im->ipsec_if_by_sw_if_index[t->sw_if_index] = ~0; - - /* delete input and output SA */ - ipsec_sa_unlock (t->input_sa_index); - ipsec_sa_unlock (t->output_sa_index); - - pool_put (im->tunnel_interfaces, t); - } - - if (sw_if_index_p) - *sw_if_index_p = sw_if_index; - - return 0; -} - -int -ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id, - u8 is_outbound) -{ - ipsec_main_t *im = &ipsec_main; - vnet_hw_interface_t *hi; - ipsec_tunnel_if_t *t; - ipsec_sa_t *sa, *old_sa; - u32 sa_index, old_sa_index; - uword *p; - - hi = vnet_get_hw_interface (vnm, hw_if_index); - t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance); - - sa_index = ipsec_sa_find_and_lock (sa_id); - - if (INDEX_INVALID == sa_index) - { - clib_warning ("SA with ID %u not found", sa_id); - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - sa = pool_elt_at_index (im->sad, sa_index); - - if (!is_outbound) - { - old_sa_index = t->input_sa_index; - old_sa = pool_elt_at_index (im->sad, old_sa_index); - - if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ^ - ipsec_sa_is_set_IS_TUNNEL_V6 (old_sa)) - { - clib_warning ("IPsec interface SA endpoints type can't be changed"); - return VNET_API_ERROR_INVALID_VALUE; - } - - if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa)) - { - ipsec6_tunnel_key_t key; - - /* unset old inbound hash entry. packets should stop arriving */ - key.remote_ip = old_sa->tunnel_src_addr.ip6; - key.spi = clib_host_to_net_u32 (old_sa->spi); - - p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key); - if (p) - hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key); - - /* set new inbound SA, then set new hash entry */ - t->input_sa_index = sa_index; - key.remote_ip = sa->tunnel_src_addr.ip6; - key.spi = clib_host_to_net_u32 (sa->spi); - - hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key, - hi->dev_instance); - } - else - { - ipsec4_tunnel_key_t key; - - /* unset old inbound hash entry. packets should stop arriving */ - key.remote_ip.as_u32 = old_sa->tunnel_src_addr.ip4.as_u32; - key.spi = clib_host_to_net_u32 (old_sa->spi); - - p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64); - if (p) - hash_unset (im->ipsec4_if_pool_index_by_key, key.as_u64); - - /* set new inbound SA, then set new hash entry */ - t->input_sa_index = sa_index; - key.remote_ip.as_u32 = sa->tunnel_src_addr.ip4.as_u32; - key.spi = clib_host_to_net_u32 (sa->spi); - - hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64, - hi->dev_instance); - } - } - else - { - old_sa_index = t->output_sa_index; - old_sa = pool_elt_at_index (im->sad, old_sa_index); - - if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ^ - ipsec_sa_is_set_IS_TUNNEL_V6 (old_sa)) - { - clib_warning ("IPsec interface SA endpoints type can't be changed"); - return VNET_API_ERROR_INVALID_VALUE; - } - - /* - * 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 (im, t, 0); - t->output_sa_index = sa_index; - ipsec_tunnel_feature_set (im, t, 1); - } - - /* remove sa_id to sa_index mapping on old SA */ - hash_unset (im->sa_index_by_sa_id, old_sa->id); - - if (ipsec_add_del_sa_sess_cb (im, old_sa_index, 0)) - { - clib_warning ("IPsec backend add/del callback returned error"); - return VNET_API_ERROR_SYSCALL_ERROR_1; - } - - ipsec_sa_unlock (old_sa_index); - - return 0; -} - -clib_error_t * -ipsec_tunnel_if_init (vlib_main_t * vm) -{ - ipsec_main_t *im = &ipsec_main; - - /* initialize the ipsec-if ip4 hash */ - im->ipsec4_if_pool_index_by_key = - hash_create (0, sizeof (ipsec4_tunnel_key_t)); - /* initialize the ipsec-if ip6 hash */ - im->ipsec6_if_pool_index_by_key = hash_create_mem (0, - sizeof - (ipsec6_tunnel_key_t), - sizeof (uword)); - im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword)); - - /* set up feature nodes to drop outbound packets with no crypto alg set */ - ipsec_add_feature ("ip4-output", "esp4-no-crypto", - &im->esp4_no_crypto_tun_feature_index); - ipsec_add_feature ("ip6-output", "esp6-no-crypto", - &im->esp6_no_crypto_tun_feature_index); - - udp_register_dst_port (vlib_get_main (), - UDP_DST_PORT_ipsec, ipsec4_if_input_node.index, 1); - return 0; -} - -VLIB_INIT_FUNCTION (ipsec_tunnel_if_init); - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/ipsec/ipsec_if.h b/src/vnet/ipsec/ipsec_if.h deleted file mode 100644 index ecaf3c94205..00000000000 --- a/src/vnet/ipsec/ipsec_if.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __IPSEC_IF_H__ -#define __IPSEC_IF_H__ - -#include <vnet/ipsec/ipsec_sa.h> - -typedef struct -{ - /* Required for pool_get_aligned */ - CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - u32 input_sa_index; - u32 output_sa_index; - u32 hw_if_index; - u32 sw_if_index; - vnet_hw_interface_flags_t flags; - u32 show_instance; -} ipsec_tunnel_if_t; - -typedef struct -{ - u8 is_add; - u8 is_ip6; - u8 esn; - u8 anti_replay; - ip46_address_t local_ip, remote_ip; - u32 local_spi; - u32 remote_spi; - ipsec_crypto_alg_t crypto_alg; - u8 local_crypto_key_len; - u8 local_crypto_key[128]; - u8 remote_crypto_key_len; - u8 remote_crypto_key[128]; - ipsec_integ_alg_t integ_alg; - u8 local_integ_key_len; - u8 local_integ_key[128]; - u8 remote_integ_key_len; - u8 remote_integ_key[128]; - u8 renumber; - u32 show_instance; - u8 udp_encap; - u32 tx_table_id; - u32 salt; -} ipsec_add_del_tunnel_args_t; - -/* *INDENT-OFF* */ -typedef CLIB_PACKED -(struct { - /* - * Key fields: remote ip and spi on incoming packet - * all fields in NET byte order - */ - union { - struct { - ip4_address_t remote_ip; - u32 spi; - }; - u64 as_u64; - }; -}) ipsec4_tunnel_key_t; -/* *INDENT-ON* */ - -/* *INDENT-OFF* */ -typedef CLIB_PACKED -(struct { - /* - * Key fields: remote ip and spi on incoming packet - * all fields in NET byte order - */ - ip6_address_t remote_ip; - u32 spi; -}) ipsec6_tunnel_key_t; -/* *INDENT-ON* */ - -extern u8 *format_ipsec4_tunnel_key (u8 * s, va_list * args); -extern u8 *format_ipsec6_tunnel_key (u8 * s, va_list * args); - -extern int ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, - ipsec_add_del_tunnel_args_t * - args, u32 * sw_if_index); -extern int ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args); - -extern int ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, - u32 sa_id, u8 is_outbound); - -extern u8 *format_ipsec_tunnel (u8 * s, va_list * args); - -#endif /* __IPSEC_IF_H__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/ipsec/ipsec_if_in.c b/src/vnet/ipsec/ipsec_if_in.c deleted file mode 100644 index 974227f7a0e..00000000000 --- a/src/vnet/ipsec/ipsec_if_in.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * ipsec_if_in.c : IPSec interface input node - * - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <vnet/vnet.h> -#include <vnet/api_errno.h> -#include <vnet/ip/ip.h> - -#include <vnet/ipsec/ipsec.h> -#include <vnet/ipsec/esp.h> -#include <vnet/ipsec/ipsec_io.h> -#include <vnet/ipsec/ipsec_punt.h> - -/* Statistics (not really errors) */ -#define foreach_ipsec_if_input_error \ -_(RX, "good packets received") \ -_(DISABLED, "ipsec packets received on disabled interface") \ -_(NO_TUNNEL, "no matching tunnel") \ -_(NAT_KEEPALIVE, "NAT Keepalive") \ -_(TOO_SHORT, "Too Short") \ -_(SPI_0, "SPI 0") - -static char *ipsec_if_input_error_strings[] = { -#define _(sym,string) string, - foreach_ipsec_if_input_error -#undef _ -}; - -typedef enum -{ -#define _(sym,str) IPSEC_IF_INPUT_ERROR_##sym, - foreach_ipsec_if_input_error -#undef _ - IPSEC_IF_INPUT_N_ERROR, -} ipsec_if_input_error_t; - - -typedef struct -{ - union - { - ipsec4_tunnel_key_t key4; - ipsec6_tunnel_key_t key6; - }; - u8 is_ip6; - u32 seq; -} ipsec_if_input_trace_t; - -static u8 * -format_ipsec_if_input_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - ipsec_if_input_trace_t *t = va_arg (*args, ipsec_if_input_trace_t *); - - if (t->is_ip6) - s = format (s, "IPSec: %U seq %u", - format_ipsec6_tunnel_key, &t->key6, t->seq); - else - s = format (s, "IPSec: %U seq %u", - format_ipsec4_tunnel_key, &t->key4, t->seq); - return s; -} - -always_inline u16 -ipsec_ip4_if_no_tunnel (vlib_node_runtime_t * node, - vlib_buffer_t * b, - const esp_header_t * esp, - const ip4_header_t * ip4, u16 offset) -{ - if (PREDICT_FALSE (0 == esp->spi)) - { - b->error = node->errors[IPSEC_IF_INPUT_ERROR_SPI_0]; - b->punt_reason = - ipsec_punt_reason[(ip4->protocol == IP_PROTOCOL_UDP ? - IPSEC_PUNT_IP4_SPI_UDP_0 : - IPSEC_PUNT_IP4_NO_SUCH_TUNNEL)]; - } - else - { - b->error = node->errors[IPSEC_IF_INPUT_ERROR_NO_TUNNEL]; - b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP4_NO_SUCH_TUNNEL]; - } - vlib_buffer_advance (b, -offset); - return IPSEC_INPUT_NEXT_PUNT; -} - -always_inline u16 -ipsec_ip6_if_no_tunnel (vlib_node_runtime_t * node, - vlib_buffer_t * b, - const esp_header_t * esp, u16 offset) -{ - b->error = node->errors[IPSEC_IF_INPUT_ERROR_NO_TUNNEL]; - b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP6_NO_SUCH_TUNNEL]; - - vlib_buffer_advance (b, -offset); - return (IPSEC_INPUT_NEXT_PUNT); -} - -always_inline uword -ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * from_frame, int is_ip6) -{ - ipsec_main_t *im = &ipsec_main; - vnet_main_t *vnm = im->vnet_main; - vnet_interface_main_t *vim = &vnm->interface_main; - - int is_trace = node->flags & VLIB_NODE_FLAG_TRACE; - u32 thread_index = vm->thread_index; - - u32 n_left_from, *from; - u16 nexts[VLIB_FRAME_SIZE], *next; - vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; - - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - - vlib_get_buffers (vm, from, bufs, n_left_from); - b = bufs; - next = nexts; - - clib_memset_u16 (nexts, im->esp4_decrypt_next_index, n_left_from); - - u64 n_bytes = 0, n_packets = 0; - u32 n_disabled = 0, n_no_tunnel = 0; - - u32 last_sw_if_index = ~0; - u32 last_tunnel_id = ~0; - ipsec4_tunnel_key_t last_key4; - ipsec6_tunnel_key_t last_key6; - - vlib_combined_counter_main_t *rx_counter; - vlib_combined_counter_main_t *drop_counter; - - if (is_ip6) - clib_memset (&last_key6, 0xff, sizeof (last_key6)); - else - last_key4.as_u64 = ~0; - - rx_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX; - drop_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP; - - while (n_left_from >= 2) - { - u32 sw_if_index0, sw_if_index1; - ip4_header_t *ip40, *ip41; - ip6_header_t *ip60, *ip61; - esp_header_t *esp0, *esp1; - u32 len0, len1; - u16 buf_adv0, buf_adv1; - u16 buf_rewind0, buf_rewind1; - u32 tid0, tid1; - ipsec_tunnel_if_t *t0, *t1; - ipsec4_tunnel_key_t key40, key41; - ipsec6_tunnel_key_t key60, key61; - - if (n_left_from >= 4) - { - CLIB_PREFETCH (b[2], CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b[2]->data, CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (b[3], CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b[3]->data, CLIB_CACHE_LINE_BYTES, LOAD); - } - - ip40 = - (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset); - ip41 = - (ip4_header_t *) (b[1]->data + vnet_buffer (b[1])->l3_hdr_offset); - - if (is_ip6) - { - ip60 = (ip6_header_t *) ip40; - ip61 = (ip6_header_t *) ip41; - esp0 = (esp_header_t *) ((u8 *) ip60 + sizeof (ip6_header_t)); - esp1 = (esp_header_t *) ((u8 *) ip61 + sizeof (ip6_header_t)); - buf_adv0 = sizeof (ip6_header_t); - buf_adv1 = sizeof (ip6_header_t); - } - else - { - /* NAT UDP port 4500 case, don't advance any more */ - if (ip40->protocol == IP_PROTOCOL_UDP) - { - esp0 = - (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) + - sizeof (udp_header_t)); - buf_adv0 = 0; - buf_rewind0 = ip4_header_bytes (ip40) + sizeof (udp_header_t); - } - else - { - esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40)); - buf_rewind0 = buf_adv0 = ip4_header_bytes (ip40); - } - /* NAT UDP port 4500 case, don't advance any more */ - if (ip41->protocol == IP_PROTOCOL_UDP) - { - esp1 = - (esp_header_t *) ((u8 *) ip41 + ip4_header_bytes (ip41) + - sizeof (udp_header_t)); - buf_adv1 = 0; - buf_rewind1 = ip4_header_bytes (ip41) + sizeof (udp_header_t); - } - else - { - esp1 = (esp_header_t *) ((u8 *) ip41 + ip4_header_bytes (ip41)); - buf_rewind1 = buf_adv1 = ip4_header_bytes (ip41); - } - } - - vlib_buffer_advance (b[0], buf_adv0); - vlib_buffer_advance (b[1], buf_adv1); - - len0 = vlib_buffer_length_in_chain (vm, b[0]); - len1 = vlib_buffer_length_in_chain (vm, b[1]); - - /* If the packet is too short to contain an SPI, then maybe - * it's a keep alive */ - if (len0 < sizeof (esp_header_t)) - { - if (esp0->spi_bytes[0] == 0xff) - b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_NAT_KEEPALIVE]; - else - b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_TOO_SHORT]; - - next[0] = IPSEC_INPUT_NEXT_DROP; - goto pkt1; - } - - if (is_ip6) - { - key60.remote_ip = ip60->src_address; - key60.spi = esp0->spi; - - if (memcmp (&key60, &last_key6, sizeof (last_key6)) == 0) - { - tid0 = last_tunnel_id; - } - else - { - uword *p = - hash_get_mem (im->ipsec6_if_pool_index_by_key, &key60); - if (p) - { - tid0 = p[0]; - last_tunnel_id = tid0; - clib_memcpy_fast (&last_key6, &key60, sizeof (key60)); - } - else - { - next[0] = - ipsec_ip6_if_no_tunnel (node, b[0], esp0, buf_adv0); - n_no_tunnel++; - goto pkt1; - } - } - } - else /* !is_ip6 */ - { - key40.remote_ip = ip40->src_address; - key40.spi = esp0->spi; - - if (key40.as_u64 == last_key4.as_u64) - { - tid0 = last_tunnel_id; - } - else - { - uword *p = - hash_get (im->ipsec4_if_pool_index_by_key, key40.as_u64); - if (p) - { - tid0 = p[0]; - last_tunnel_id = tid0; - last_key4.as_u64 = key40.as_u64; - } - else - { - next[0] = - ipsec_ip4_if_no_tunnel (node, b[0], esp0, ip40, - buf_rewind0); - n_no_tunnel++; - goto pkt1; - } - } - } - - t0 = pool_elt_at_index (im->tunnel_interfaces, tid0); - vnet_buffer (b[0])->ipsec.sad_index = t0->input_sa_index; - - if (PREDICT_TRUE (t0->hw_if_index != ~0)) - { - sw_if_index0 = t0->sw_if_index; - vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index0; - - if (PREDICT_FALSE (!(t0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))) - { - vlib_increment_combined_counter - (drop_counter, thread_index, sw_if_index0, 1, len0); - n_disabled++; - b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_DISABLED]; - next[0] = IPSEC_INPUT_NEXT_DROP; - goto pkt1; - } - - if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index)) - { - n_packets++; - n_bytes += len0; - } - else - { - if (n_packets) - { - vlib_increment_combined_counter - (rx_counter, thread_index, last_sw_if_index, - n_packets, n_bytes); - } - - last_sw_if_index = sw_if_index0; - n_packets = 1; - n_bytes = len0; - } - } - - pkt1: - - if (len1 < sizeof (esp_header_t)) - { - if (esp0->spi_bytes[0] == 0xff) - b[1]->error = node->errors[IPSEC_IF_INPUT_ERROR_NAT_KEEPALIVE]; - else - b[1]->error = node->errors[IPSEC_IF_INPUT_ERROR_TOO_SHORT]; - - next[1] = IPSEC_INPUT_NEXT_DROP; - goto trace1; - } - - if (is_ip6) - { - key61.remote_ip = ip61->src_address; - key61.spi = esp1->spi; - - if (memcmp (&key61, &last_key6, sizeof (last_key6)) == 0) - { - tid1 = last_tunnel_id; - } - else - { - uword *p = - hash_get_mem (im->ipsec6_if_pool_index_by_key, &key61); - if (p) - { - tid1 = p[0]; - last_tunnel_id = tid1; - clib_memcpy_fast (&last_key6, &key61, sizeof (key61)); - } - else - { - next[1] = - ipsec_ip6_if_no_tunnel (node, b[1], esp1, buf_adv1); - n_no_tunnel++; - goto trace1; - } - } - } - else /* !is_ip6 */ - { - key41.remote_ip = ip41->src_address; - key41.spi = esp1->spi; - - if (key41.as_u64 == last_key4.as_u64) - { - tid1 = last_tunnel_id; - } - else - { - uword *p = - hash_get (im->ipsec4_if_pool_index_by_key, key41.as_u64); - if (p) - { - tid1 = p[0]; - last_tunnel_id = tid1; - last_key4.as_u64 = key41.as_u64; - } - else - { - next[1] = - ipsec_ip4_if_no_tunnel (node, b[1], esp1, ip41, - buf_rewind1); - n_no_tunnel++; - goto trace1; - } - } - } - - t1 = pool_elt_at_index (im->tunnel_interfaces, tid1); - vnet_buffer (b[1])->ipsec.sad_index = t1->input_sa_index; - - if (PREDICT_TRUE (t1->hw_if_index != ~0)) - { - sw_if_index1 = t1->sw_if_index; - vnet_buffer (b[1])->sw_if_index[VLIB_RX] = sw_if_index1; - - if (PREDICT_FALSE (!(t1->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))) - { - vlib_increment_combined_counter - (drop_counter, thread_index, sw_if_index1, 1, len1); - n_disabled++; - b[1]->error = node->errors[IPSEC_IF_INPUT_ERROR_DISABLED]; - next[1] = IPSEC_INPUT_NEXT_DROP; - goto trace1; - } - - if (PREDICT_TRUE (sw_if_index1 == last_sw_if_index)) - { - n_packets++; - n_bytes += len1; - } - else - { - if (n_packets) - { - vlib_increment_combined_counter - (rx_counter, thread_index, last_sw_if_index, - n_packets, n_bytes); - } - - last_sw_if_index = sw_if_index1; - n_packets = 1; - n_bytes = len1; - } - } - - trace1: - if (PREDICT_FALSE (is_trace)) - { - if (b[0]->flags & VLIB_BUFFER_IS_TRACED) - { - ipsec_if_input_trace_t *tr = - vlib_add_trace (vm, node, b[0], sizeof (*tr)); - if (is_ip6) - clib_memcpy (&tr->key6, &key60, sizeof (tr->key6)); - else - clib_memcpy (&tr->key4, &key40, sizeof (tr->key4)); - tr->is_ip6 = is_ip6; - tr->seq = - len0 >= - sizeof (*esp0) ? clib_host_to_net_u32 (esp0->seq) : ~0; - } - if (b[1]->flags & VLIB_BUFFER_IS_TRACED) - { - ipsec_if_input_trace_t *tr = - vlib_add_trace (vm, node, b[1], sizeof (*tr)); - if (is_ip6) - clib_memcpy (&tr->key6, &key61, sizeof (tr->key6)); - else - clib_memcpy (&tr->key4, &key41, sizeof (tr->key4)); - tr->is_ip6 = is_ip6; - tr->seq = - len1 >= - sizeof (*esp1) ? clib_host_to_net_u32 (esp1->seq) : ~0; - } - } - - /* next */ - b += 2; - next += 2; - n_left_from -= 2; - } - while (n_left_from > 0) - { - u32 sw_if_index0; - ip4_header_t *ip40; - ip6_header_t *ip60; - esp_header_t *esp0; - u32 len0; - u16 buf_adv0, buf_rewind0; - u32 tid0; - ipsec_tunnel_if_t *t0; - ipsec4_tunnel_key_t key40; - ipsec6_tunnel_key_t key60; - - ip40 = - (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset); - - if (is_ip6) - { - ip60 = (ip6_header_t *) ip40; - esp0 = (esp_header_t *) ((u8 *) ip60 + sizeof (ip6_header_t)); - buf_adv0 = sizeof (ip6_header_t); - } - else - { - /* NAT UDP port 4500 case, don't advance any more */ - if (ip40->protocol == IP_PROTOCOL_UDP) - { - esp0 = - (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) + - sizeof (udp_header_t)); - buf_adv0 = 0; - buf_rewind0 = ip4_header_bytes (ip40) + sizeof (udp_header_t); - } - else - { - esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40)); - buf_rewind0 = buf_adv0 = ip4_header_bytes (ip40); - } - } - - /* stats for the tunnel include all the data after the IP header - just like a norml IP-IP tunnel */ - vlib_buffer_advance (b[0], buf_adv0); - len0 = vlib_buffer_length_in_chain (vm, b[0]); - - if (len0 < sizeof (esp_header_t)) - { - if (esp0->spi_bytes[0] == 0xff) - b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_NAT_KEEPALIVE]; - else - b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_TOO_SHORT]; - - next[0] = IPSEC_INPUT_NEXT_DROP; - goto trace00; - } - - if (is_ip6) - { - key60.remote_ip = ip60->src_address; - key60.spi = esp0->spi; - - if (memcmp (&key60, &last_key6, sizeof (last_key6)) == 0) - { - tid0 = last_tunnel_id; - } - else - { - uword *p = - hash_get_mem (im->ipsec6_if_pool_index_by_key, &key60); - if (p) - { - tid0 = p[0]; - last_tunnel_id = tid0; - clib_memcpy_fast (&last_key6, &key60, sizeof (key60)); - } - else - { - next[0] = - ipsec_ip6_if_no_tunnel (node, b[0], esp0, buf_adv0); - n_no_tunnel++; - goto trace00; - } - } - } - else /* !is_ip6 */ - { - key40.remote_ip = ip40->src_address; - key40.spi = esp0->spi; - - if (key40.as_u64 == last_key4.as_u64) - { - tid0 = last_tunnel_id; - } - else - { - uword *p = - hash_get (im->ipsec4_if_pool_index_by_key, key40.as_u64); - if (p) - { - tid0 = p[0]; - last_tunnel_id = tid0; - last_key4.as_u64 = key40.as_u64; - } - else - { - next[0] = - ipsec_ip4_if_no_tunnel (node, b[0], esp0, ip40, - buf_rewind0); - n_no_tunnel++; - goto trace00; - } - } - } - - t0 = pool_elt_at_index (im->tunnel_interfaces, tid0); - vnet_buffer (b[0])->ipsec.sad_index = t0->input_sa_index; - - if (PREDICT_TRUE (t0->hw_if_index != ~0)) - { - sw_if_index0 = t0->sw_if_index; - vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index0; - - if (PREDICT_FALSE (!(t0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))) - { - vlib_increment_combined_counter - (drop_counter, thread_index, sw_if_index0, 1, len0); - n_disabled++; - b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_DISABLED]; - next[0] = IPSEC_INPUT_NEXT_DROP; - goto trace00; - } - - if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index)) - { - n_packets++; - n_bytes += len0; - } - else - { - if (n_packets) - { - vlib_increment_combined_counter - (rx_counter, thread_index, last_sw_if_index, - n_packets, n_bytes); - } - - last_sw_if_index = sw_if_index0; - n_packets = 1; - n_bytes = len0; - } - } - - trace00: - if (PREDICT_FALSE (is_trace)) - { - if (b[0]->flags & VLIB_BUFFER_IS_TRACED) - { - ipsec_if_input_trace_t *tr = - vlib_add_trace (vm, node, b[0], sizeof (*tr)); - if (is_ip6) - clib_memcpy (&tr->key6, &key60, sizeof (tr->key6)); - else - clib_memcpy (&tr->key4, &key40, sizeof (tr->key4)); - tr->is_ip6 = is_ip6; - tr->seq = - len0 >= - sizeof (*esp0) ? clib_host_to_net_u32 (esp0->seq) : ~0; - } - } - - /* next */ - b += 1; - next += 1; - n_left_from -= 1; - } - - if (n_packets) - { - vlib_increment_combined_counter (rx_counter, - thread_index, - last_sw_if_index, n_packets, n_bytes); - } - - vlib_node_increment_counter (vm, node->node_index, - IPSEC_IF_INPUT_ERROR_RX, - from_frame->n_vectors - (n_disabled + - n_no_tunnel)); - - vlib_buffer_enqueue_to_next (vm, node, from, nexts, from_frame->n_vectors); - - return from_frame->n_vectors; -} - -VLIB_NODE_FN (ipsec4_if_input_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return ipsec_if_input_inline (vm, node, from_frame, 0 /* is_ip6 */ ); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (ipsec4_if_input_node) = { - .name = "ipsec4-if-input", - .vector_size = sizeof (u32), - .format_trace = format_ipsec_if_input_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(ipsec_if_input_error_strings), - .error_strings = ipsec_if_input_error_strings, - .sibling_of = "ipsec4-input-feature", -}; -/* *INDENT-ON* */ - -VLIB_NODE_FN (ipsec6_if_input_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return ipsec_if_input_inline (vm, node, from_frame, 1 /* is_ip6 */ ); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (ipsec6_if_input_node) = { - .name = "ipsec6-if-input", - .vector_size = sizeof (u32), - .format_trace = format_ipsec_if_input_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(ipsec_if_input_error_strings), - .error_strings = ipsec_if_input_error_strings, - .sibling_of = "ipsec6-input-feature", -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c index f22458da562..712d0d5e42f 100644 --- a/src/vnet/ipsec/ipsec_sa.c +++ b/src/vnet/ipsec/ipsec_sa.c @@ -317,6 +317,20 @@ ipsec_sa_unlock (index_t sai) fib_node_unlock (&sa->node); } +void +ipsec_sa_lock (index_t sai) +{ + ipsec_main_t *im = &ipsec_main; + ipsec_sa_t *sa; + + if (INDEX_INVALID == sai) + return; + + sa = pool_elt_at_index (im->sad, sai); + + fib_node_lock (&sa->node); +} + index_t ipsec_sa_find_and_lock (u32 id) { diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h index b3e138bfbea..79971538646 100644 --- a/src/vnet/ipsec/ipsec_sa.h +++ b/src/vnet/ipsec/ipsec_sa.h @@ -211,6 +211,7 @@ extern int ipsec_sa_add_and_lock (u32 id, extern index_t ipsec_sa_find_and_lock (u32 id); extern int ipsec_sa_unlock_id (u32 id); extern void ipsec_sa_unlock (index_t sai); +extern void ipsec_sa_lock (index_t sai); extern void ipsec_sa_clear (index_t sai); extern void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa, ipsec_crypto_alg_t crypto_alg); diff --git a/src/vnet/ipsec/ipsec_tun.c b/src/vnet/ipsec/ipsec_tun.c index 7864cba08be..ca0091b3545 100644 --- a/src/vnet/ipsec/ipsec_tun.c +++ b/src/vnet/ipsec/ipsec_tun.c @@ -148,6 +148,7 @@ ipsec_tun_protect_config (ipsec_main_t * im, ipsec_tun_protect_t * itp, u32 sa_out, u32 * sas_in) { ipsec_sa_t *sa; + index_t sai; u32 ii; itp->itp_n_sa_in = vec_len (sas_in); @@ -155,7 +156,13 @@ ipsec_tun_protect_config (ipsec_main_t * im, itp->itp_in_sas[ii] = sas_in[ii]; itp->itp_out_sa = sa_out; + ipsec_sa_lock (itp->itp_out_sa); + /* *INDENT-OFF* */ + FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai, + ({ + ipsec_sa_lock(sai); + })); FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa, ({ if (ipsec_sa_is_set_IS_TUNNEL (sa)) @@ -183,7 +190,6 @@ ipsec_tun_protect_config (ipsec_main_t * im, * enable the encrypt feature for egress. */ ipsec_tun_protect_feature_set (itp, 1); - } static void @@ -221,10 +227,116 @@ ipsec_tun_protect_find (u32 sw_if_index) } int +ipsec_tun_protect_update_one (u32 sw_if_index, u32 sa_out, u32 sa_in) +{ + u32 *sas_in = NULL; + int rv; + + vec_add1 (sas_in, sa_in); + rv = ipsec_tun_protect_update (sw_if_index, sa_out, sas_in); + + return (rv); +} + +int +ipsec_tun_protect_update_out (u32 sw_if_index, u32 sa_out) +{ + u32 itpi, *sas_in, sai, *saip; + ipsec_tun_protect_t *itp; + ipsec_main_t *im; + int rv; + + sas_in = NULL; + rv = 0; + im = &ipsec_main; + vec_validate_init_empty (ipsec_protect_db.tunnels, sw_if_index, + INDEX_INVALID); + itpi = ipsec_protect_db.tunnels[sw_if_index]; + + if (INDEX_INVALID == itpi) + { + return (VNET_API_ERROR_INVALID_INTERFACE); + } + + itp = pool_elt_at_index (ipsec_protect_pool, itpi); + + /* *INDENT-0FF* */ + FOR_EACH_IPSEC_PROTECT_INPUT_SAI (itp, sai, ( + { + ipsec_sa_lock (sai); + vec_add1 (sas_in, sai); + } + )); + /* *INDENT-ON* */ + + sa_out = ipsec_sa_find_and_lock (sa_out); + + if (~0 == sa_out) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto out; + } + + ipsec_tun_protect_unconfig (im, itp); + ipsec_tun_protect_config (im, itp, sa_out, sas_in); + + ipsec_sa_unlock (sa_out); + vec_foreach (saip, sas_in) ipsec_sa_unlock (*saip); + +out: + vec_free (sas_in); + return (rv); +} + +int +ipsec_tun_protect_update_in (u32 sw_if_index, u32 sa_in) +{ + u32 itpi, *sas_in, sa_out; + ipsec_tun_protect_t *itp; + ipsec_main_t *im; + int rv; + + sas_in = NULL; + rv = 0; + im = &ipsec_main; + vec_validate_init_empty (ipsec_protect_db.tunnels, sw_if_index, + INDEX_INVALID); + itpi = ipsec_protect_db.tunnels[sw_if_index]; + + if (INDEX_INVALID == itpi) + { + return (VNET_API_ERROR_INVALID_INTERFACE); + } + + sa_in = ipsec_sa_find_and_lock (sa_in); + + if (~0 == sa_in) + { + rv = VNET_API_ERROR_INVALID_VALUE; + goto out; + } + vec_add1 (sas_in, sa_in); + + itp = pool_elt_at_index (ipsec_protect_pool, itpi); + sa_out = itp->itp_out_sa; + + ipsec_sa_lock (sa_out); + + ipsec_tun_protect_unconfig (im, itp); + ipsec_tun_protect_config (im, itp, sa_out, sas_in); + + ipsec_sa_unlock (sa_out); + ipsec_sa_unlock (sa_in); +out: + vec_free (sas_in); + return (rv); +} + +int ipsec_tun_protect_update (u32 sw_if_index, u32 sa_out, u32 * sas_in) { - u32 itpi, ii; ipsec_tun_protect_t *itp; + u32 itpi, ii, *saip; ipsec_main_t *im; int rv; @@ -330,7 +442,10 @@ ipsec_tun_protect_update (u32 sw_if_index, u32 sa_out, u32 * sas_in) ipsec_tun_protect_config (im, itp, sa_out, sas_in); } + ipsec_sa_unlock (sa_out); + vec_foreach (saip, sas_in) ipsec_sa_unlock (*saip); vec_free (sas_in); + out: return (rv); } diff --git a/src/vnet/ipsec/ipsec_tun.h b/src/vnet/ipsec/ipsec_tun.h index 2041cbe758b..840840335a5 100644 --- a/src/vnet/ipsec/ipsec_tun.h +++ b/src/vnet/ipsec/ipsec_tun.h @@ -17,6 +17,36 @@ #include <vnet/ipsec/ipsec.h> +/* *INDENT-OFF* */ +typedef CLIB_PACKED(struct { + /* + * Key fields: remote ip and spi on incoming packet + * all fields in NET byte order + */ + union { + struct { + ip4_address_t remote_ip; + u32 spi; + }; + u64 as_u64; + }; +}) ipsec4_tunnel_key_t; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +typedef CLIB_PACKED(struct { + /* + * Key fields: remote ip and spi on incoming packet + * all fields in NET byte order + */ + ip6_address_t remote_ip; + u32 spi; +}) ipsec6_tunnel_key_t; +/* *INDENT-ON* */ + +extern u8 *format_ipsec4_tunnel_key (u8 * s, va_list * args); +extern u8 *format_ipsec6_tunnel_key (u8 * s, va_list * args); + typedef enum ipsec_protect_flags_t_ { IPSEC_PROTECT_L2 = (1 << 0), @@ -66,8 +96,13 @@ typedef struct ipsec_tun_protect_t_ } \ } +extern int ipsec_tun_protect_update_one (u32 sw_if_index, u32 sa_out, + u32 sa_in); extern int ipsec_tun_protect_update (u32 sw_if_index, u32 sa_out, - u32 sa_ins[2]); + u32 * sa_ins); +extern int ipsec_tun_protect_update_in (u32 sw_if_index, u32 sa_in); +extern int ipsec_tun_protect_update_out (u32 sw_if_index, u32 sa_out); + extern int ipsec_tun_protect_del (u32 sw_if_index); typedef walk_rc_t (*ipsec_tun_protect_walk_cb_t) (index_t itpi, void *arg); diff --git a/src/vnet/ipsec/ipsec_tun_in.c b/src/vnet/ipsec/ipsec_tun_in.c index d88cc08ddbd..f25a76319f1 100644 --- a/src/vnet/ipsec/ipsec_tun_in.c +++ b/src/vnet/ipsec/ipsec_tun_in.c @@ -68,6 +68,7 @@ typedef struct }; u8 is_ip6; u32 seq; + u32 sa_index; } ipsec_tun_protect_input_trace_t; static u8 * @@ -79,11 +80,11 @@ format_ipsec_tun_protect_input_trace (u8 * s, va_list * args) va_arg (*args, ipsec_tun_protect_input_trace_t *); if (t->is_ip6) - s = format (s, "IPSec: %U seq %u", - format_ipsec6_tunnel_key, &t->key6, t->seq); + s = format (s, "IPSec: %U seq %u sa %d", + format_ipsec6_tunnel_key, &t->key6, t->seq, t->sa_index); else - s = format (s, "IPSec: %U seq %u", - format_ipsec4_tunnel_key, &t->key4, t->seq); + s = format (s, "IPSec: %U seq %u sa %d", + format_ipsec4_tunnel_key, &t->key4, t->seq, t->sa_index); return s; } @@ -376,9 +377,9 @@ ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, else clib_memcpy (&tr->key4, &key40, sizeof (tr->key4)); tr->is_ip6 = is_ip6; - tr->seq = - len0 >= - sizeof (*esp0) ? clib_host_to_net_u32 (esp0->seq) : ~0; + tr->seq = (len0 >= sizeof (*esp0) ? + clib_host_to_net_u32 (esp0->seq) : ~0); + tr->sa_index = vnet_buffer (b[0])->ipsec.sad_index; } } |