summaryrefslogtreecommitdiffstats
path: root/src/vnet/ipsec/ipsec_if.c
diff options
context:
space:
mode:
authorMatthew Smith <mgsmith@netgate.com>2017-10-12 12:06:59 -0500
committerSergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>2017-10-26 13:48:54 +0000
commitca514fda1125573d513215cb6ea7f22057a82d6b (patch)
treec40b3964b2f295e541cb7fffc3feea378c66f24d /src/vnet/ipsec/ipsec_if.c
parentdb41776a92e3e13178d7a565b7700a2a05336f04 (diff)
Allow IPsec interface to have SAs reset
Make it easier to integrate with external IKE daemon. IPsec interfaces can have one or both SAs replaced after creation. This allows for the possibility of setting a new child SA on an interface when rekeying occurs. It also allows for the possibility of creating an interface ahead of time and updating the SA when parameters that are negotiated during IKE exchange become known. Change-Id: I0a31afdcc2bdff7098a924a51abbc58bdab2bd08 Signed-off-by: Matthew Smith <mgsmith@netgate.com>
Diffstat (limited to 'src/vnet/ipsec/ipsec_if.c')
-rw-r--r--src/vnet/ipsec/ipsec_if.c79
1 files changed, 79 insertions, 0 deletions
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)
{