#include <vlib/vlib.h>
#include <vlib/unix/plugin.h>
+#include <vlibmemory/api.h>
#include <vpp/app/version.h>
#include <vnet/vnet.h>
#include <vnet/pg/pg.h>
}
static u32
-ikev2_mk_local_sa_id (u32 ti)
+ikev2_mk_local_sa_id (u32 sai, u32 ci, u32 ti)
{
- return (0x80000000 | ti);
+ return (0x80000000 | (ti << 24) | (sai << 12) | ci);
}
static u32
-ikev2_mk_remote_sa_id (u32 ti)
+ikev2_mk_remote_sa_id (u32 sai, u32 ci, u32 ti)
{
- return (0xc0000000 | ti);
+ return (0xc0000000 | (ti << 24) | (sai << 12) | ci);
+}
+
+typedef struct
+{
+ u32 salt_local;
+ u32 salt_remote;
+ u32 local_sa_id;
+ u32 remote_sa_id;
+ ipsec_sa_flags_t flags;
+ u32 local_spi;
+ u32 remote_spi;
+ ipsec_crypto_alg_t encr_type;
+ ipsec_integ_alg_t integ_type;
+ ip46_address_t local_ip;
+ ip46_address_t remote_ip;
+ ipsec_key_t loc_ckey, rem_ckey, loc_ikey, rem_ikey;
+} ikev2_add_ipsec_tunnel_args_t;
+
+static void
+ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a)
+{
+ ikev2_main_t *km = &ikev2_main;
+ u32 sw_if_index;
+ int rv;
+ uword *p = 0;
+
+ rv = ipip_add_tunnel (IPIP_TRANSPORT_IP4, ~0,
+ &a->local_ip, &a->remote_ip, 0,
+ TUNNEL_ENCAP_DECAP_FLAG_NONE, IP_DSCP_CS0,
+ &sw_if_index);
+
+ if (rv == VNET_API_ERROR_IF_ALREADY_EXISTS)
+ {
+ p = hash_get (km->sw_if_indices, sw_if_index);
+ if (p)
+ /* interface is managed by IKE; proceed with updating SAs */
+ rv = 0;
+ }
+
+ if (rv)
+ {
+ clib_warning ("installing ipip tunnel failed! loc:%U rem:%U",
+ format_ip4_address, &a->local_ip,
+ format_ip4_address, &a->remote_ip);
+ return;
+ }
+
+ rv |= ipsec_sa_add_and_lock (a->local_sa_id,
+ a->local_spi,
+ IPSEC_PROTOCOL_ESP, a->encr_type,
+ &a->loc_ckey, a->integ_type, &a->loc_ikey,
+ a->flags, 0, a->salt_local, &a->local_ip,
+ &a->remote_ip, NULL);
+ rv |= ipsec_sa_add_and_lock (a->remote_sa_id, a->remote_spi,
+ IPSEC_PROTOCOL_ESP, a->encr_type, &a->rem_ckey,
+ a->integ_type, &a->rem_ikey,
+ (a->flags | IPSEC_SA_FLAG_IS_INBOUND), 0,
+ a->salt_remote, &a->remote_ip,
+ &a->local_ip, NULL);
+
+ u32 *sas_in = NULL;
+ vec_add1 (sas_in, a->remote_sa_id);
+ rv |= ipsec_tun_protect_update (sw_if_index, a->local_sa_id, sas_in);
+ hash_set1 (km->sw_if_indices, sw_if_index);
}
static int
-ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa,
- ikev2_child_sa_t * child)
+ikev2_create_tunnel_interface (vnet_main_t * vnm,
+ u32 thread_index,
+ ikev2_sa_t * sa,
+ ikev2_child_sa_t * child, u32 sa_index,
+ u32 child_index)
{
ikev2_main_t *km = &ikev2_main;
+ ipsec_crypto_alg_t encr_type;
+ ipsec_integ_alg_t integ_type;
ikev2_profile_t *p = 0;
- ipsec_key_t loc_ckey, rem_ckey, loc_ikey, rem_ikey;
ikev2_sa_transform_t *tr;
ikev2_sa_proposal_t *proposals;
- ipsec_sa_flags_t flags = 0;
- ipsec_crypto_alg_t encr_type;
- ipsec_integ_alg_t integ_type;
- u32 local_spi, remote_spi;
u8 is_aead = 0;
- u32 salt_local = 0, salt_remote = 0;
- ip46_address_t local_ip, remote_ip;
- int rv;
+ ikev2_add_ipsec_tunnel_args_t a;
+
+ clib_memset (&a, 0, sizeof (a));
if (!child->r_proposals)
{
if (sa->is_initiator)
{
- ip46_address_set_ip4 (&local_ip, &sa->iaddr);
- ip46_address_set_ip4 (&remote_ip, &sa->raddr);
+ ip46_address_set_ip4 (&a.local_ip, &sa->iaddr);
+ ip46_address_set_ip4 (&a.remote_ip, &sa->raddr);
proposals = child->i_proposals;
- local_spi = child->r_proposals[0].spi;
- remote_spi = child->i_proposals[0].spi;
+ a.local_spi = child->r_proposals[0].spi;
+ a.remote_spi = child->i_proposals[0].spi;
}
else
{
- ip46_address_set_ip4 (&local_ip, &sa->raddr);
- ip46_address_set_ip4 (&remote_ip, &sa->iaddr);
+ ip46_address_set_ip4 (&a.local_ip, &sa->raddr);
+ ip46_address_set_ip4 (&a.remote_ip, &sa->iaddr);
proposals = child->r_proposals;
- local_spi = child->i_proposals[0].spi;
- remote_spi = child->r_proposals[0].spi;
+ a.local_spi = child->i_proposals[0].spi;
+ a.remote_spi = child->r_proposals[0].spi;
}
- flags = IPSEC_SA_FLAG_USE_ANTI_REPLAY;
+ a.flags = IPSEC_SA_FLAG_USE_ANTI_REPLAY;
tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_ESN);
if (tr && tr->esn_type)
- flags |= IPSEC_SA_FLAG_USE_ESN;
+ a.flags |= IPSEC_SA_FLAG_USE_ESN;
tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_ENCR);
if (tr)
ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN);
return 1;
}
+ a.encr_type = encr_type;
if (!is_aead)
{
integ_type = IPSEC_INTEG_ALG_NONE;
}
+ a.integ_type = integ_type;
ikev2_calc_child_keys (sa, child);
if (sa->is_initiator)
{
- ipsec_mk_key (&loc_ikey, child->sk_ai, vec_len (child->sk_ai));
- ipsec_mk_key (&rem_ikey, child->sk_ar, vec_len (child->sk_ar));
- ipsec_mk_key (&loc_ckey, child->sk_ei, vec_len (child->sk_ei));
- ipsec_mk_key (&rem_ckey, child->sk_er, vec_len (child->sk_er));
+ ipsec_mk_key (&a.loc_ikey, child->sk_ai, vec_len (child->sk_ai));
+ ipsec_mk_key (&a.rem_ikey, child->sk_ar, vec_len (child->sk_ar));
+ ipsec_mk_key (&a.loc_ckey, child->sk_ei, vec_len (child->sk_ei));
+ ipsec_mk_key (&a.rem_ckey, child->sk_er, vec_len (child->sk_er));
if (is_aead)
{
- salt_remote = child->salt_er;
- salt_local = child->salt_ei;
+ a.salt_remote = child->salt_er;
+ a.salt_local = child->salt_ei;
}
}
else
{
- ipsec_mk_key (&loc_ikey, child->sk_ar, vec_len (child->sk_ar));
- ipsec_mk_key (&rem_ikey, child->sk_ai, vec_len (child->sk_ai));
- ipsec_mk_key (&loc_ckey, child->sk_er, vec_len (child->sk_er));
- ipsec_mk_key (&rem_ckey, child->sk_ei, vec_len (child->sk_ei));
+ ipsec_mk_key (&a.loc_ikey, child->sk_ar, vec_len (child->sk_ar));
+ ipsec_mk_key (&a.rem_ikey, child->sk_ai, vec_len (child->sk_ai));
+ ipsec_mk_key (&a.loc_ckey, child->sk_er, vec_len (child->sk_er));
+ ipsec_mk_key (&a.rem_ckey, child->sk_ei, vec_len (child->sk_ei));
if (is_aead)
{
- salt_remote = child->salt_ei;
- salt_local = child->salt_er;
+ a.salt_remote = child->salt_ei;
+ a.salt_local = child->salt_er;
}
}
}
}
- rv = ipip_add_tunnel (IPIP_TRANSPORT_IP4, ~0,
- &local_ip, &remote_ip, 0, 0, &child->sw_if_index);
-
- child->local_sa = ikev2_mk_local_sa_id (child->sw_if_index);
- child->remote_sa = ikev2_mk_remote_sa_id (child->sw_if_index);
-
- rv |= ipsec_sa_add_and_lock (child->local_sa,
- local_spi,
- IPSEC_PROTOCOL_ESP, encr_type,
- &loc_ckey, integ_type, &loc_ikey, flags,
- 0, salt_local, &local_ip, &remote_ip, NULL);
- rv |= ipsec_sa_add_and_lock (child->remote_sa,
- remote_spi,
- IPSEC_PROTOCOL_ESP, encr_type,
- &rem_ckey, integ_type, &rem_ikey,
- (flags | IPSEC_SA_FLAG_IS_INBOUND),
- 0, salt_remote, &remote_ip, &local_ip, NULL);
+ if (thread_index & 0xffffffc0)
+ clib_warning ("error: thread index exceeds max range 0x3f!");
- u32 *sas_in = NULL;
- vec_add1 (sas_in, child->remote_sa);
- rv |=
- ipsec_tun_protect_update (child->sw_if_index, child->local_sa, sas_in);
+ if (child_index & 0xfffff000 || sa_index & 0xfffff000)
+ clib_warning ("error: sa/child index exceeds max range 0xfff!");
+
+ child->local_sa_id =
+ a.local_sa_id =
+ ikev2_mk_local_sa_id (sa_index, child_index, thread_index);
+ child->remote_sa_id =
+ a.remote_sa_id =
+ ikev2_mk_remote_sa_id (sa_index, child_index, thread_index);
+ vl_api_rpc_call_main_thread (ikev2_add_tunnel_from_main,
+ (u8 *) & a, sizeof (a));
return 0;
}
+typedef struct
+{
+ ip46_address_t local_ip;
+ ip46_address_t remote_ip;
+ u32 remote_sa_id;
+ u32 local_sa_id;
+} ikev2_del_ipsec_tunnel_args_t;
+
+static void
+ikev2_del_tunnel_from_main (ikev2_del_ipsec_tunnel_args_t * a)
+{
+ ikev2_main_t *km = &ikev2_main;
+ /* *INDENT-OFF* */
+ ipip_tunnel_key_t key = {
+ .src = a->local_ip,
+ .dst = a->remote_ip,
+ .transport = IPIP_TRANSPORT_IP4,
+ .fib_index = 0,
+ };
+ ipip_tunnel_t *ipip;
+ /* *INDENT-ON* */
+
+ ipip = ipip_tunnel_db_find (&key);
+
+ if (ipip)
+ {
+ hash_unset (km->sw_if_indices, ipip->sw_if_index);
+ ipsec_tun_protect_del (ipip->sw_if_index);
+ ipsec_sa_unlock_id (a->remote_sa_id);
+ ipsec_sa_unlock_id (a->local_sa_id);
+ ipip_del_tunnel (ipip->sw_if_index);
+ }
+}
+
static int
ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa,
ikev2_child_sa_t * child)
{
- ipsec_tun_protect_del (child->sw_if_index);
- ipsec_sa_unlock_id (child->remote_sa);
- ipsec_sa_unlock_id (child->local_sa);
- ipip_del_tunnel (child->sw_if_index);
+ ikev2_del_ipsec_tunnel_args_t a;
+
+ clib_memset (&a, 0, sizeof (a));
+
+ if (sa->is_initiator)
+ {
+ ip46_address_set_ip4 (&a.local_ip, &sa->iaddr);
+ ip46_address_set_ip4 (&a.remote_ip, &sa->raddr);
+ }
+ else
+ {
+ ip46_address_set_ip4 (&a.local_ip, &sa->raddr);
+ ip46_address_set_ip4 (&a.remote_ip, &sa->iaddr);
+ }
+
+ a.remote_sa_id = child->remote_sa_id;
+ a.local_sa_id = child->local_sa_id;
+
+ vl_api_rpc_call_main_thread (ikev2_del_tunnel_from_main, (u8 *) & a,
+ sizeof (a));
return 0;
}
ikev2_initial_contact_cleanup (sa0);
ikev2_sa_match_ts (sa0);
if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE)
- ikev2_create_tunnel_interface (km->vnet_main, sa0,
- &sa0->childs[0]);
+ ikev2_create_tunnel_interface (km->vnet_main,
+ thread_index, sa0,
+ &sa0->childs[0],
+ p[0], 0);
}
if (sa0->is_initiator)
{
if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE)
{
+ if (sa0->childs)
+ vec_free (sa0->childs);
ikev2_child_sa_t *child;
vec_add2 (sa0->childs, child, 1);
child->r_proposals = sa0->rekey[0].r_proposal;
child->i_proposals = sa0->rekey[0].i_proposal;
child->tsi = sa0->rekey[0].tsi;
child->tsr = sa0->rekey[0].tsr;
- ikev2_create_tunnel_interface (km->vnet_main, sa0,
- child);
+ ikev2_create_tunnel_interface (km->vnet_main,
+ thread_index, sa0,
+ child, p[0],
+ child - sa0->childs);
}
if (sa0->is_initiator)
{
}
km->sa_by_ispi = hash_create (0, sizeof (uword));
+ km->sw_if_indices = hash_create (0, 0);
udp_register_dst_port (vm, 500, ikev2_node.index, 1);