aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/ipsec
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/ipsec')
-rw-r--r--src/vnet/ipsec/ipsec.api16
-rw-r--r--src/vnet/ipsec/ipsec.c2
-rw-r--r--src/vnet/ipsec/ipsec.h3
-rw-r--r--src/vnet/ipsec/ipsec_api.c24
-rw-r--r--src/vnet/ipsec/ipsec_if.c79
5 files changed, 123 insertions, 1 deletions
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)
{