diff options
-rw-r--r-- | src/vat/api_format.c | 54 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.api | 16 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.c | 2 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.h | 3 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_api.c | 24 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if.c | 79 |
6 files changed, 177 insertions, 1 deletions
diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 08d0c2e033e..d8f72090ef7 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -5107,6 +5107,7 @@ _(ipsec_sad_add_del_entry_reply) \ _(ipsec_sa_set_key_reply) \ _(ipsec_tunnel_if_add_del_reply) \ _(ipsec_tunnel_if_set_key_reply) \ +_(ipsec_tunnel_if_set_sa_reply) \ _(ikev2_profile_add_del_reply) \ _(ikev2_profile_set_auth_reply) \ _(ikev2_profile_set_id_reply) \ @@ -5341,6 +5342,7 @@ _(IPSEC_SA_DETAILS, ipsec_sa_details) \ _(IPSEC_SA_SET_KEY_REPLY, ipsec_sa_set_key_reply) \ _(IPSEC_TUNNEL_IF_ADD_DEL_REPLY, ipsec_tunnel_if_add_del_reply) \ _(IPSEC_TUNNEL_IF_SET_KEY_REPLY, ipsec_tunnel_if_set_key_reply) \ +_(IPSEC_TUNNEL_IF_SET_SA_REPLY, ipsec_tunnel_if_set_sa_reply) \ _(IKEV2_PROFILE_ADD_DEL_REPLY, ikev2_profile_add_del_reply) \ _(IKEV2_PROFILE_SET_AUTH_REPLY, ikev2_profile_set_auth_reply) \ _(IKEV2_PROFILE_SET_ID_REPLY, ikev2_profile_set_id_reply) \ @@ -14402,6 +14404,57 @@ api_ipsec_tunnel_if_set_key (vat_main_t * vam) } static int +api_ipsec_tunnel_if_set_sa (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_tunnel_if_set_sa_t *mp; + u32 sw_if_index = ~0; + u32 sa_id = ~0; + u8 is_outbound = (u8) ~ 0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sa_id %d", &sa_id)) + ; + else if (unformat (i, "outbound")) + is_outbound = 1; + else if (unformat (i, "inbound")) + is_outbound = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index == ~0) + { + errmsg ("interface must be specified"); + return -99; + } + + if (sa_id == ~0) + { + errmsg ("SA ID must be specified"); + return -99; + } + + M (IPSEC_TUNNEL_IF_SET_SA, mp); + + mp->sw_if_index = htonl (sw_if_index); + mp->sa_id = htonl (sa_id); + mp->is_outbound = is_outbound; + + S (mp); + W (ret); + + return ret; +} + +static int api_ikev2_profile_add_del (vat_main_t * vam) { unformat_input_t *i = vam->input; @@ -21708,6 +21761,7 @@ _(ipsec_tunnel_if_add_del, "local_spi <n> remote_spi <n>\n" \ _(ipsec_sa_dump, "[sa_id <n>]") \ _(ipsec_tunnel_if_set_key, "<intfc> <local|remote> <crypto|integ>\n" \ " <alg> <hex>\n") \ +_(ipsec_tunnel_if_set_sa, "<intfc> sa_id <n> <inbound|outbound>\n") \ _(ikev2_profile_add_del, "name <profile_name> [del]") \ _(ikev2_profile_set_auth, "name <profile_name> auth_method <method>\n" \ "(auth_data 0x<data> | auth_data <data>)") \ diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api index 67c333665b7..1b2e4bdd01c 100644 --- a/src/vnet/ipsec/ipsec.api +++ b/src/vnet/ipsec/ipsec.api @@ -157,6 +157,7 @@ autoreply define ipsec_sad_add_del_entry u8 integrity_key[128]; u8 use_extended_sequence_number; + u8 use_anti_replay; u8 is_tunnel; u8 is_tunnel_ipv6; @@ -634,6 +635,21 @@ autoreply define ipsec_tunnel_if_set_key { u8 key[128]; }; +/** \brief Set new SA on IPsec interface + @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 + @param sa_id - ID of SA to use + @param is_outbound - 1 if outbound (local) SA, 0 if inbound (remote) +*/ +autoreply define ipsec_tunnel_if_set_sa { + u32 client_index; + u32 context; + u32 sw_if_index; + u32 sa_id; + u8 is_outbound; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/ipsec/ipsec.c b/src/vnet/ipsec/ipsec.c index 2adcfd0b9bd..cd05c1bb9bf 100644 --- a/src/vnet/ipsec/ipsec.c +++ b/src/vnet/ipsec/ipsec.c @@ -379,7 +379,7 @@ ipsec_add_del_policy (vlib_main_t * vm, ipsec_policy_t * policy, int is_add) return 0; } -static u8 +u8 ipsec_is_sa_used (u32 sa_index) { ipsec_main_t *im = &ipsec_main; diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h index 222025dbee8..1572e5501e2 100644 --- a/src/vnet/ipsec/ipsec.h +++ b/src/vnet/ipsec/ipsec.h @@ -306,6 +306,7 @@ int ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add); int ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update); u32 ipsec_get_sa_index_by_sa_id (u32 sa_id); +u8 ipsec_is_sa_used (u32 sa_index); u8 *format_ipsec_if_output_trace (u8 * s, va_list * args); u8 *format_ipsec_policy_action (u8 * s, va_list * args); u8 *format_ipsec_crypto_alg (u8 * s, va_list * args); @@ -324,6 +325,8 @@ int ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm, args); int ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, ipsec_if_set_key_type_t type, u8 alg, u8 * key); +int ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id, + u8 is_outbound); /* diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c index c3f5745b85f..e96da8168fa 100644 --- a/src/vnet/ipsec/ipsec_api.c +++ b/src/vnet/ipsec/ipsec_api.c @@ -57,6 +57,7 @@ _(IPSEC_SA_DUMP, ipsec_sa_dump) \ _(IPSEC_SPD_DUMP, ipsec_spd_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) \ @@ -236,6 +237,7 @@ static void vl_api_ipsec_sad_add_del_entry_t_handler clib_memcpy (&sa.tunnel_src_addr.ip4.data, mp->tunnel_src_address, 4); clib_memcpy (&sa.tunnel_dst_addr.ip4.data, mp->tunnel_dst_address, 4); } + sa.use_anti_replay = mp->use_anti_replay; ASSERT (im->cb.check_support_cb); clib_error_t *err = im->cb.check_support_cb (&sa); @@ -566,6 +568,28 @@ out: 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)); + + rv = ipsec_set_interface_sa (vnm, sw->hw_if_index, ntohl (mp->sa_id), + mp->is_outbound); +#else + clib_warning ("unimplemented"); +#endif + + REPLY_MACRO (VL_API_IPSEC_TUNNEL_IF_SET_SA_REPLY); +} + + +static void vl_api_ikev2_profile_add_del_t_handler (vl_api_ikev2_profile_add_del_t * mp) { vl_api_ikev2_profile_add_del_reply_t *rmp; diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c index 974553489ea..5a0d4898ccb 100644 --- a/src/vnet/ipsec/ipsec_if.c +++ b/src/vnet/ipsec/ipsec_if.c @@ -399,6 +399,85 @@ 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) +{ + 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_get_sa_index_by_sa_id (sa_id); + if (sa_index == ~0) + { + clib_warning ("SA with ID %u not found", sa_id); + return VNET_API_ERROR_INVALID_VALUE; + } + + if (ipsec_is_sa_used (sa_index)) + { + clib_warning ("SA with ID %u is already in use", sa_id); + return VNET_API_ERROR_INVALID_VALUE; + } + + sa = pool_elt_at_index (im->sad, sa_index); + if (sa->is_tunnel_ip6) + { + clib_warning ("IPsec interface not supported with IPv6 endpoints"); + return VNET_API_ERROR_UNIMPLEMENTED; + } + + if (!is_outbound) + { + u64 key; + + old_sa_index = t->input_sa_index; + old_sa = pool_elt_at_index (im->sad, old_sa_index); + + /* unset old inbound hash entry. packets should stop arriving */ + key = + (u64) old_sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) old_sa->spi; + p = hash_get (im->ipsec_if_pool_index_by_key, key); + if (p) + hash_unset (im->ipsec_if_pool_index_by_key, key); + + /* set new inbound SA, then set new hash entry */ + t->input_sa_index = sa_index; + key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi; + hash_set (im->ipsec_if_pool_index_by_key, key, hi->dev_instance); + } + else + { + old_sa_index = t->output_sa_index; + old_sa = pool_elt_at_index (im->sad, old_sa_index); + t->output_sa_index = sa_index; + } + + /* remove sa_id to sa_index mapping on old SA */ + 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) + { + 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; + } + + pool_put (im->sad, old_sa); + + return 0; +} + + clib_error_t * ipsec_tunnel_if_init (vlib_main_t * vm) { |