format_ipsec_name (u8 * s, va_list * args)
{
u32 dev_instance = va_arg (*args, u32);
- return format (s, "ipsec%d", dev_instance);
+ ipsec_main_t *im = &ipsec_main;
+ ipsec_tunnel_if_t *t = im->tunnel_interfaces + dev_instance;
+
+ return format (s, "ipsec%d", t->show_instance);
}
static uword
u32 hw_if_index = ~0;
uword *p;
ipsec_sa_t *sa;
+ u32 dev_instance;
u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
p = hash_get (im->ipsec_if_pool_index_by_key, key);
pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
memset (t, 0, sizeof (*t));
+ 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);
+
pool_get (im->sad, sa);
memset (sa, 0, sizeof (*sa));
t->input_sa_index = sa - im->sad;
hash_set (im->ipsec_if_pool_index_by_key, key,
t - im->tunnel_interfaces);
- if (vec_len (im->free_tunnel_if_indices) > 0)
- {
- hw_if_index =
- im->free_tunnel_if_indices[vec_len (im->free_tunnel_if_indices) -
- 1];
- _vec_len (im->free_tunnel_if_indices) -= 1;
- }
- else
- {
- hw_if_index =
- vnet_register_interface (vnm, ipsec_device_class.index,
- t - im->tunnel_interfaces,
- ipsec_hw_class.index,
- 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);
hi->output_node_index = ipsec_if_output_node.index;
t->hw_if_index = hw_if_index;
+ vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
+ hi->sw_if_index, 1, 0, 0);
+
/*1st interface, register protocol */
if (pool_elts (im->tunnel_interfaces) == 1)
ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
}
else
{
- vnet_interface_main_t *vim = &vnm->interface_main;
-
/* check if exists */
if (!p)
return VNET_API_ERROR_INVALID_VALUE;
t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
hi = vnet_get_hw_interface (vnm, t->hw_if_index);
vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */
- vec_add1 (im->free_tunnel_if_indices, t->hw_if_index);
- vnet_interface_counter_lock (vim);
- vlib_zero_combined_counter (vim->combined_sw_if_counters +
- VNET_INTERFACE_COUNTER_TX, hi->sw_if_index);
- vlib_zero_combined_counter (vim->combined_sw_if_counters +
- VNET_INTERFACE_COUNTER_RX, hi->sw_if_index);
- vnet_interface_counter_unlock (vim);
+ vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
+ hi->sw_if_index, 0, 0, 0);
+
+ vnet_delete_hw_interface (vnm, t->hw_if_index);
/* delete input and output SA */
- sa = pool_elt_at_index (im->sad, t->input_sa_index);
+ sa = pool_elt_at_index (im->sad, t->input_sa_index);
pool_put (im->sad, sa);
sa = pool_elt_at_index (im->sad, t->output_sa_index);
-
pool_put (im->sad, sa);
hash_unset (im->ipsec_if_pool_index_by_key, key);
+ hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance);
+
pool_put (im->tunnel_interfaces, t);
}
}
+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_src_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_src_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)
{
ipsec_main_t *im = &ipsec_main;
im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
+ im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword));
return 0;
}