summaryrefslogtreecommitdiffstats
path: root/src/vnet
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet')
-rw-r--r--src/vnet/fib/fib_node.h4
-rw-r--r--src/vnet/ipsec/ah_decrypt.c6
-rw-r--r--src/vnet/ipsec/ah_encrypt.c21
-rw-r--r--src/vnet/ipsec/esp_decrypt.c7
-rw-r--r--src/vnet/ipsec/esp_encrypt.c30
-rw-r--r--src/vnet/ipsec/ikev2.c16
-rw-r--r--src/vnet/ipsec/ipsec.api33
-rw-r--r--src/vnet/ipsec/ipsec_api.c224
-rw-r--r--src/vnet/ipsec/ipsec_cli.c244
-rw-r--r--src/vnet/ipsec/ipsec_format.c72
-rw-r--r--src/vnet/ipsec/ipsec_if.c147
-rw-r--r--src/vnet/ipsec/ipsec_if.h2
-rw-r--r--src/vnet/ipsec/ipsec_if_in.c12
-rw-r--r--src/vnet/ipsec/ipsec_sa.c274
-rw-r--r--src/vnet/ipsec/ipsec_sa.h68
15 files changed, 716 insertions, 444 deletions
diff --git a/src/vnet/fib/fib_node.h b/src/vnet/fib/fib_node.h
index 1179dfc0a50..e9c45c55efd 100644
--- a/src/vnet/fib/fib_node.h
+++ b/src/vnet/fib/fib_node.h
@@ -48,6 +48,7 @@ typedef enum fib_node_type_t_ {
FIB_NODE_TYPE_BIER_FMASK,
FIB_NODE_TYPE_BIER_ENTRY,
FIB_NODE_TYPE_VXLAN_GBP_TUNNEL,
+ FIB_NODE_TYPE_IPSEC_SA,
/**
* Marker. New types before this one. leave the test last.
*/
@@ -75,7 +76,8 @@ typedef enum fib_node_type_t_ {
[FIB_NODE_TYPE_UDP_ENCAP] = "udp-encap", \
[FIB_NODE_TYPE_BIER_FMASK] = "bier-fmask", \
[FIB_NODE_TYPE_BIER_ENTRY] = "bier-entry", \
- [FIB_NODE_TYPE_VXLAN_GBP_TUNNEL] = "vxlan-gbp-tunnel" \
+ [FIB_NODE_TYPE_VXLAN_GBP_TUNNEL] = "vxlan-gbp-tunnel", \
+ [FIB_NODE_TYPE_IPSEC_SA] = "ipsec-sa" \
}
/**
diff --git a/src/vnet/ipsec/ah_decrypt.c b/src/vnet/ipsec/ah_decrypt.c
index c8c89028f9d..7d2bf814fcc 100644
--- a/src/vnet/ipsec/ah_decrypt.c
+++ b/src/vnet/ipsec/ah_decrypt.c
@@ -200,9 +200,9 @@ ah_decrypt_inline (vlib_main_t * vm,
icv_padding_len =
ah_calc_icv_padding_len (icv_size, 0 /* is_ipv6 */ );
}
- hmac_calc (sa0->integ_alg, sa0->integ_key, sa0->integ_key_len,
- (u8 *) ih4, i_b0->current_length, sig, sa0->use_esn,
- sa0->seq_hi);
+ hmac_calc (sa0->integ_alg, sa0->integ_key.data,
+ sa0->integ_key.len, (u8 *) ih4, i_b0->current_length,
+ sig, sa0->use_esn, sa0->seq_hi);
if (PREDICT_FALSE (memcmp (digest, sig, icv_size)))
{
diff --git a/src/vnet/ipsec/ah_encrypt.c b/src/vnet/ipsec/ah_encrypt.c
index 8b0c14f0cf3..66286094682 100644
--- a/src/vnet/ipsec/ah_encrypt.c
+++ b/src/vnet/ipsec/ah_encrypt.c
@@ -59,6 +59,7 @@ static char *ah_encrypt_error_strings[] = {
typedef struct
{
+ u32 sa_index;
u32 spi;
u32 seq;
ipsec_integ_alg_t integ_alg;
@@ -72,8 +73,9 @@ format_ah_encrypt_trace (u8 * s, va_list * args)
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
ah_encrypt_trace_t *t = va_arg (*args, ah_encrypt_trace_t *);
- s = format (s, "ah: spi %u seq %u integrity %U",
- t->spi, t->seq, format_ipsec_integ_alg, t->integ_alg);
+ s = format (s, "ah: sa-index %d spi %u seq %u integrity %U",
+ t->sa_index, t->spi, t->seq,
+ format_ipsec_integ_alg, t->integ_alg);
return s;
}
@@ -237,8 +239,9 @@ ah_encrypt_inline (vlib_main_t * vm,
oh0->ip4.src_address.as_u32 = sa0->tunnel_src_addr.ip4.as_u32;
oh0->ip4.dst_address.as_u32 = sa0->tunnel_dst_addr.ip4.as_u32;
- next0 = AH_ENCRYPT_NEXT_IP4_LOOKUP;
- vnet_buffer (i_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
+ next0 = sa0->dpo[IPSEC_PROTOCOL_AH].dpoi_next_node;
+ vnet_buffer (i_b0)->ip.adj_index[VLIB_TX] =
+ sa0->dpo[IPSEC_PROTOCOL_AH].dpoi_index;
}
else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6)
{
@@ -251,8 +254,9 @@ ah_encrypt_inline (vlib_main_t * vm,
oh6_0->ip6.dst_address.as_u64[1] =
sa0->tunnel_dst_addr.ip6.as_u64[1];
- next0 = AH_ENCRYPT_NEXT_IP6_LOOKUP;
- vnet_buffer (i_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
+ next0 = sa0->dpo[IPSEC_PROTOCOL_AH].dpoi_next_node;
+ vnet_buffer (i_b0)->ip.adj_index[VLIB_TX] =
+ sa0->dpo[IPSEC_PROTOCOL_AH].dpoi_index;
}
u8 sig[64];
@@ -262,8 +266,8 @@ ah_encrypt_inline (vlib_main_t * vm,
sizeof (ah_header_t);
clib_memset (digest, 0, icv_size);
- unsigned size = hmac_calc (sa0->integ_alg, sa0->integ_key,
- sa0->integ_key_len,
+ unsigned size = hmac_calc (sa0->integ_alg, sa0->integ_key.data,
+ sa0->integ_key.len,
vlib_buffer_get_current (i_b0),
i_b0->current_length, sig, sa0->use_esn,
sa0->seq_hi);
@@ -297,6 +301,7 @@ ah_encrypt_inline (vlib_main_t * vm,
tr->spi = sa0->spi;
tr->seq = sa0->seq - 1;
tr->integ_alg = sa0->integ_alg;
+ tr->sa_index = sa_index0;
}
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
diff --git a/src/vnet/ipsec/esp_decrypt.c b/src/vnet/ipsec/esp_decrypt.c
index 3f463505e01..5a3ccdcacd9 100644
--- a/src/vnet/ipsec/esp_decrypt.c
+++ b/src/vnet/ipsec/esp_decrypt.c
@@ -206,8 +206,9 @@ esp_decrypt_inline (vlib_main_t * vm,
icv_size;
i_b0->current_length -= icv_size;
- hmac_calc (sa0->integ_alg, sa0->integ_key, sa0->integ_key_len,
- (u8 *) esp0, i_b0->current_length, sig, sa0->use_esn,
+ hmac_calc (sa0->integ_alg, sa0->integ_key.data,
+ sa0->integ_key.len, (u8 *) esp0,
+ i_b0->current_length, sig, sa0->use_esn,
sa0->seq_hi);
if (PREDICT_FALSE (memcmp (icv, sig, icv_size)))
@@ -299,7 +300,7 @@ esp_decrypt_inline (vlib_main_t * vm,
esp0->data + IV_SIZE,
(u8 *) vlib_buffer_get_current (o_b0) +
ip_hdr_size, BLOCK_SIZE * blocks,
- sa0->crypto_key, esp0->data);
+ sa0->crypto_key.data, esp0->data);
o_b0->current_length = (blocks * BLOCK_SIZE) - 2 + ip_hdr_size;
o_b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c
index 16f985c6cfe..4b325e08b5f 100644
--- a/src/vnet/ipsec/esp_encrypt.c
+++ b/src/vnet/ipsec/esp_encrypt.c
@@ -62,6 +62,7 @@ static char *esp_encrypt_error_strings[] = {
typedef struct
{
+ u32 sa_index;
u32 spi;
u32 seq;
u8 udp_encap;
@@ -77,8 +78,8 @@ format_esp_encrypt_trace (u8 * s, va_list * args)
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
esp_encrypt_trace_t *t = va_arg (*args, esp_encrypt_trace_t *);
- s = format (s, "esp: spi %u seq %u crypto %U integrity %U%s",
- t->spi, t->seq,
+ s = format (s, "esp: sa-index %d spi %u seq %u crypto %U integrity %U%s",
+ t->sa_index, t->spi, t->seq,
format_ipsec_crypto_alg, t->crypto_alg,
format_ipsec_integ_alg, t->integ_alg,
t->udp_encap ? " udp-encap-enabled" : "");
@@ -279,7 +280,9 @@ esp_encrypt_inline (vlib_main_t * vm,
oh0->ip4.src_address.as_u32 = sa0->tunnel_src_addr.ip4.as_u32;
oh0->ip4.dst_address.as_u32 = sa0->tunnel_dst_addr.ip4.as_u32;
- vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = sa0->tx_fib_index;
+ next0 = sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_next_node;
+ vnet_buffer (o_b0)->ip.adj_index[VLIB_TX] =
+ sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_index;
}
else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6)
{
@@ -292,7 +295,9 @@ esp_encrypt_inline (vlib_main_t * vm,
oh6_0->ip6.dst_address.as_u64[1] =
sa0->tunnel_dst_addr.ip6.as_u64[1];
- vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = sa0->tx_fib_index;
+ next0 = sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_next_node;
+ vnet_buffer (o_b0)->ip.adj_index[VLIB_TX] =
+ sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_index;
}
else
{
@@ -367,17 +372,15 @@ esp_encrypt_inline (vlib_main_t * vm,
(u8 *) vlib_buffer_get_current (o_b0) +
ip_udp_hdr_size + sizeof (esp_header_t) +
IV_SIZE, BLOCK_SIZE * blocks,
- sa0->crypto_key, iv);
+ sa0->crypto_key.data, iv);
}
- o_b0->current_length += hmac_calc (sa0->integ_alg, sa0->integ_key,
- sa0->integ_key_len,
- (u8 *) o_esp0,
- o_b0->current_length -
- ip_udp_hdr_size,
- vlib_buffer_get_current (o_b0) +
- o_b0->current_length,
- sa0->use_esn, sa0->seq_hi);
+ o_b0->current_length +=
+ hmac_calc (sa0->integ_alg, sa0->integ_key.data,
+ sa0->integ_key.len, (u8 *) o_esp0,
+ o_b0->current_length - ip_udp_hdr_size,
+ vlib_buffer_get_current (o_b0) + o_b0->current_length,
+ sa0->use_esn, sa0->seq_hi);
if (is_ip6)
@@ -412,6 +415,7 @@ esp_encrypt_inline (vlib_main_t * vm,
o_b0->trace_index = i_b0->trace_index;
esp_encrypt_trace_t *tr =
vlib_add_trace (vm, node, o_b0, sizeof (*tr));
+ tr->sa_index = sa_index0;
tr->spi = sa0->spi;
tr->seq = sa0->seq - 1;
tr->udp_encap = sa0->udp_encap;
diff --git a/src/vnet/ipsec/ikev2.c b/src/vnet/ipsec/ikev2.c
index 80497f20807..3d5c0f766cf 100644
--- a/src/vnet/ipsec/ikev2.c
+++ b/src/vnet/ipsec/ikev2.c
@@ -1492,16 +1492,16 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa,
a.is_add = 1;
if (sa->is_initiator)
{
- a.local_ip.as_u32 = sa->iaddr.as_u32;
- a.remote_ip.as_u32 = sa->raddr.as_u32;
+ a.local_ip.ip4.as_u32 = sa->iaddr.as_u32;
+ a.remote_ip.ip4.as_u32 = sa->raddr.as_u32;
proposals = child->i_proposals;
a.local_spi = child->r_proposals[0].spi;
a.remote_spi = child->i_proposals[0].spi;
}
else
{
- a.local_ip.as_u32 = sa->raddr.as_u32;
- a.remote_ip.as_u32 = sa->iaddr.as_u32;
+ a.local_ip.ip4.as_u32 = sa->raddr.as_u32;
+ a.remote_ip.ip4.as_u32 = sa->iaddr.as_u32;
proposals = child->r_proposals;
a.local_spi = child->i_proposals[0].spi;
a.remote_spi = child->r_proposals[0].spi;
@@ -1642,8 +1642,8 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa,
return 0;
a.is_add = 0;
- a.local_ip.as_u32 = sa->iaddr.as_u32;
- a.remote_ip.as_u32 = sa->raddr.as_u32;
+ a.local_ip.ip4.as_u32 = sa->iaddr.as_u32;
+ a.remote_ip.ip4.as_u32 = sa->raddr.as_u32;
a.local_spi = child->r_proposals[0].spi;
a.remote_spi = child->i_proposals[0].spi;
}
@@ -1653,8 +1653,8 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa,
return 0;
a.is_add = 0;
- a.local_ip.as_u32 = sa->raddr.as_u32;
- a.remote_ip.as_u32 = sa->iaddr.as_u32;
+ a.local_ip.ip4.as_u32 = sa->raddr.as_u32;
+ a.remote_ip.ip4.as_u32 = sa->iaddr.as_u32;
a.local_spi = child->i_proposals[0].spi;
a.remote_spi = child->r_proposals[0].spi;
}
diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api
index 54cc76bb9d6..ece0b024485 100644
--- a/src/vnet/ipsec/ipsec.api
+++ b/src/vnet/ipsec/ipsec.api
@@ -232,6 +232,10 @@ enum ipsec_sad_flags
IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 0x08,
/* enable UDP encapsulation for NAT traversal */
IPSEC_API_SAD_FLAG_UDP_ENCAP = 0x10,
+
+ /* come-on Ole please fix this */
+ IPSEC_API_SAD_COMBO_12 = 12,
+ IPSEC_API_SAD_COMBO_20 = 20,
};
enum ipsec_proto
@@ -261,6 +265,7 @@ typedef key
@param integrity_key - integrity keying material
@param tunnel_src_address - IPsec tunnel source address IPv6 if is_tunnel_ipv6 is non-zero, else IPv4. Only valid if is_tunnel is non-zero
@param tunnel_dst_address - IPsec tunnel destination address IPv6 if is_tunnel_ipv6 is non-zero, else IPv4. Only valid if is_tunnel is non-zero
+ @param tx_table_id - the FIB id used for encapsulated packets
*/
typedef ipsec_sad_entry
{
@@ -280,6 +285,7 @@ typedef ipsec_sad_entry
vl_api_address_t tunnel_src;
vl_api_address_t tunnel_dst;
+ u32 tx_table_id;
};
/** \brief IPsec: Add/delete Security Association Database entry
@@ -687,41 +693,18 @@ define ipsec_sa_dump {
@param replay_window - bit map of seq nums received relative to last_seq if using anti-replay
@param total_data_size - total bytes sent or received
@param udp_encap - 1 if UDP encap enabled, 0 otherwise
- @param tx_table_id - the FIB id used for encapsulated packets
*/
define ipsec_sa_details {
u32 context;
- u32 sa_id;
- u32 sw_if_index;
-
- u32 spi;
- u8 protocol;
-
- u8 crypto_alg;
- u8 crypto_key_len;
- u8 crypto_key[128];
-
- u8 integ_alg;
- u8 integ_key_len;
- u8 integ_key[128];
-
- u8 use_esn;
- u8 use_anti_replay;
-
- u8 is_tunnel;
- u8 is_tunnel_ip6;
- u8 tunnel_src_addr[16];
- u8 tunnel_dst_addr[16];
+ vl_api_ipsec_sad_entry_t entry;
+ u32 sw_if_index;
u32 salt;
u64 seq_outbound;
u64 last_seq_inbound;
u64 replay_window;
u64 total_data_size;
- u8 udp_encap;
-
- u32 tx_table_id;
};
/** \brief Set key on IPsec interface
diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c
index 06f954622c7..2d464b31290 100644
--- a/src/vnet/ipsec/ipsec_api.c
+++ b/src/vnet/ipsec/ipsec_api.c
@@ -217,6 +217,19 @@ ipsec_proto_decode (vl_api_ipsec_proto_t in, ipsec_protocol_t * out)
return (VNET_API_ERROR_UNIMPLEMENTED);
}
+static vl_api_ipsec_proto_t
+ipsec_proto_encode (ipsec_protocol_t p)
+{
+ switch (p)
+ {
+ case IPSEC_PROTOCOL_ESP:
+ return clib_host_to_net_u32 (IPSEC_API_PROTO_ESP);
+ case IPSEC_PROTOCOL_AH:
+ return clib_host_to_net_u32 (IPSEC_API_PROTO_AH);
+ }
+ return (VNET_API_ERROR_UNIMPLEMENTED);
+}
+
static int
ipsec_crypto_algo_decode (vl_api_ipsec_crypto_alg_t in,
ipsec_crypto_alg_t * out)
@@ -234,6 +247,23 @@ ipsec_crypto_algo_decode (vl_api_ipsec_crypto_alg_t in,
return (VNET_API_ERROR_UNIMPLEMENTED);
}
+static vl_api_ipsec_crypto_alg_t
+ipsec_crypto_algo_encode (ipsec_crypto_alg_t c)
+{
+ switch (c)
+ {
+#define _(v,f,s) case IPSEC_CRYPTO_ALG_##f: \
+ return clib_host_to_net_u32(IPSEC_API_CRYPTO_ALG_##f);
+ foreach_ipsec_crypto_alg
+#undef _
+ case IPSEC_CRYPTO_N_ALG:
+ break;
+ }
+ ASSERT (0);
+ return (VNET_API_ERROR_UNIMPLEMENTED);
+}
+
+
static int
ipsec_integ_algo_decode (vl_api_ipsec_integ_alg_t in, ipsec_integ_alg_t * out)
{
@@ -250,86 +280,122 @@ ipsec_integ_algo_decode (vl_api_ipsec_integ_alg_t in, ipsec_integ_alg_t * out)
return (VNET_API_ERROR_UNIMPLEMENTED);
}
+static vl_api_ipsec_integ_alg_t
+ipsec_integ_algo_encode (ipsec_integ_alg_t i)
+{
+ switch (i)
+ {
+#define _(v,f,s) case IPSEC_INTEG_ALG_##f: \
+ return (clib_host_to_net_u32(IPSEC_API_INTEG_ALG_##f));
+ foreach_ipsec_integ_alg
+#undef _
+ case IPSEC_INTEG_N_ALG:
+ break;
+ }
+ ASSERT (0);
+ return (VNET_API_ERROR_UNIMPLEMENTED);
+}
+
static void
-vl_api_ipsec_key_decode (const vl_api_key_t * key, u8 * len, u8 out[128])
+ipsec_key_decode (const vl_api_key_t * key, ipsec_key_t * out)
{
- *len = key->length;
- clib_memcpy (out, key->data, key->length);
+ ipsec_mk_key (out, key->data, key->length);
}
static void
-vl_api_ipsec_sad_flags_decode (vl_api_ipsec_sad_flags_t in, ipsec_sa_t * sa)
+ipsec_key_encode (const ipsec_key_t * in, vl_api_key_t * out)
+{
+ out->length = in->len;
+ clib_memcpy (out->data, in->data, out->length);
+}
+
+static ipsec_sa_flags_t
+ipsec_sa_flags_decode (vl_api_ipsec_sad_flags_t in)
{
+ ipsec_sa_flags_t flags = IPSEC_SA_FLAG_NONE;
in = clib_net_to_host_u32 (in);
- if (in & IPSEC_API_SAD_FLAG_USE_EXTENDED_SEQ_NUM)
- sa->use_esn = 1;
- if (in & IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY)
- sa->use_anti_replay = 1;
- if (in & IPSEC_API_SAD_FLAG_IS_TUNNEL)
- sa->is_tunnel = 1;
- if (in & IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
- sa->is_tunnel_ip6 = 1;
- if (in & IPSEC_API_SAD_FLAG_UDP_ENCAP)
- sa->udp_encap = 1;
+#define _(v,f,s) if (in & IPSEC_API_SAD_FLAG_##f) \
+ flags |= IPSEC_SA_FLAG_##f;
+ foreach_ipsec_sa_flags
+#undef _
+ return (flags);
}
+static vl_api_ipsec_sad_flags_t
+ipsec_sad_flags_encode (const ipsec_sa_t * sa)
+{
+ vl_api_ipsec_sad_flags_t flags = IPSEC_API_SAD_FLAG_NONE;
+
+ if (sa->use_esn)
+ flags |= IPSEC_API_SAD_FLAG_USE_EXTENDED_SEQ_NUM;
+ if (sa->use_anti_replay)
+ flags |= IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY;
+ if (sa->is_tunnel)
+ flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL;
+ if (sa->is_tunnel_ip6)
+ flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL_V6;
+ if (sa->udp_encap)
+ flags |= IPSEC_API_SAD_FLAG_UDP_ENCAP;
+
+ return clib_host_to_net_u32 (flags);
+}
static void vl_api_ipsec_sad_entry_add_del_t_handler
(vl_api_ipsec_sad_entry_add_del_t * mp)
{
vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
vl_api_ipsec_sad_entry_add_del_reply_t *rmp;
+ ip46_address_t tun_src = { }, tun_dst =
+ {
+ };
+ ipsec_key_t crypto_key, integ_key;
+ ipsec_crypto_alg_t crypto_alg;
+ ipsec_integ_alg_t integ_alg;
+ ipsec_protocol_t proto;
+ ipsec_sa_flags_t flags;
+ u32 id, spi;
int rv;
-#if WITH_LIBSSL > 0
- ipsec_main_t *im = &ipsec_main;
- ipsec_sa_t sa;
- clib_memset (&sa, 0, sizeof (sa));
+#if WITH_LIBSSL > 0
- sa.id = ntohl (mp->entry.sad_id);
- sa.spi = ntohl (mp->entry.spi);
+ id = ntohl (mp->entry.sad_id);
+ spi = ntohl (mp->entry.spi);
- rv = ipsec_proto_decode (mp->entry.protocol, &sa.protocol);
+ rv = ipsec_proto_decode (mp->entry.protocol, &proto);
if (rv)
goto out;
- rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &sa.crypto_alg);
+ rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg);
if (rv)
goto out;
- rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &sa.integ_alg);
+ rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg);
if (rv)
goto out;
- vl_api_ipsec_key_decode (&mp->entry.crypto_key,
- &sa.crypto_key_len, sa.crypto_key);
- vl_api_ipsec_key_decode (&mp->entry.integrity_key,
- &sa.integ_key_len, sa.integ_key);
+ ipsec_key_decode (&mp->entry.crypto_key, &crypto_key);
+ ipsec_key_decode (&mp->entry.integrity_key, &integ_key);
- vl_api_ipsec_sad_flags_decode (mp->entry.flags, &sa);
+ flags = ipsec_sa_flags_decode (mp->entry.flags);
- if (sa.is_tunnel_ip6 || sa.is_tunnel)
- {
- ip_address_decode (&mp->entry.tunnel_src, &sa.tunnel_src_addr);
- ip_address_decode (&mp->entry.tunnel_dst, &sa.tunnel_dst_addr);
- }
+ ip_address_decode (&mp->entry.tunnel_src, &tun_src);
+ ip_address_decode (&mp->entry.tunnel_dst, &tun_dst);
- clib_error_t *err = ipsec_check_support_cb (im, &sa);
- if (err)
- {
- clib_warning ("%s", err->what);
- rv = VNET_API_ERROR_UNIMPLEMENTED;
- goto out;
- }
- rv = ipsec_add_del_sa (vm, &sa, mp->is_add);
+ if (mp->is_add)
+ rv = ipsec_sa_add (id, spi, proto,
+ crypto_alg, &crypto_key,
+ integ_alg, &integ_key, flags,
+ 0, &tun_src, &tun_dst, NULL);
+ else
+ rv = ipsec_sa_del (id);
+
#else
rv = VNET_API_ERROR_UNIMPLEMENTED;
- goto out;
#endif
out:
@@ -525,17 +591,17 @@ vl_api_ipsec_sa_set_key_t_handler (vl_api_ipsec_sa_set_key_t * mp)
{
vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
vl_api_ipsec_sa_set_key_reply_t *rmp;
+ ipsec_key_t ck, ik;
+ u32 id;
int rv;
#if WITH_LIBSSL > 0
- ipsec_sa_t sa;
- sa.id = ntohl (mp->sa_id);
- vl_api_ipsec_key_decode (&mp->crypto_key,
- &sa.crypto_key_len, sa.crypto_key);
- vl_api_ipsec_key_decode (&mp->integrity_key,
- &sa.integ_key_len, sa.integ_key);
+ id = ntohl (mp->sa_id);
- rv = ipsec_set_sa_key (vm, &sa);
+ ipsec_key_decode (&mp->crypto_key, &ck);
+ ipsec_key_decode (&mp->integrity_key, &ik);
+
+ rv = ipsec_set_sa_key (id, &ck, &ik);
#else
rv = VNET_API_ERROR_UNIMPLEMENTED;
#endif
@@ -571,8 +637,8 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
tun.remote_integ_key_len = mp->remote_integ_key_len;
tun.udp_encap = mp->udp_encap;
tun.tx_table_id = ntohl (mp->tx_table_id);
- memcpy (&tun.local_ip, mp->local_ip, 4);
- memcpy (&tun.remote_ip, mp->remote_ip, 4);
+ memcpy (&tun.local_ip.ip4, mp->local_ip, 4);
+ memcpy (&tun.remote_ip.ip4, mp->remote_ip, 4);
memcpy (&tun.local_crypto_key, &mp->local_crypto_key,
mp->local_crypto_key_len);
memcpy (&tun.remote_crypto_key, &mp->remote_crypto_key,
@@ -590,11 +656,12 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
rv = VNET_API_ERROR_UNIMPLEMENTED;
#endif
- REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY, (
- {
- rmp->sw_if_index =
- htonl (sw_if_index);
- }));
+ /* *INDENT-OFF* */
+ REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY,
+ ({
+ rmp->sw_if_index = htonl (sw_if_index);
+ }));
+ /* *INDENT-ON* */
}
static void
@@ -608,40 +675,29 @@ send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg,
mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_DETAILS);
mp->context = context;
- mp->sa_id = htonl (sa->id);
- mp->sw_if_index = htonl (sw_if_index);
-
- mp->spi = htonl (sa->spi);
- mp->protocol = sa->protocol;
-
- mp->crypto_alg = sa->crypto_alg;
- mp->crypto_key_len = sa->crypto_key_len;
- memcpy (mp->crypto_key, sa->crypto_key, sa->crypto_key_len);
+ mp->entry.sad_id = htonl (sa->id);
+ mp->entry.spi = htonl (sa->spi);
+ mp->entry.protocol = ipsec_proto_encode (sa->protocol);
+ mp->entry.tx_table_id =
+ htonl (fib_table_get_table_id (sa->tx_fib_index, FIB_PROTOCOL_IP4));
- mp->integ_alg = sa->integ_alg;
- mp->integ_key_len = sa->integ_key_len;
- memcpy (mp->integ_key, sa->integ_key, sa->integ_key_len);
+ mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
+ ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
- mp->use_esn = sa->use_esn;
- mp->use_anti_replay = sa->use_anti_replay;
+ mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
+ ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
- mp->is_tunnel = sa->is_tunnel;
- mp->is_tunnel_ip6 = sa->is_tunnel_ip6;
+ mp->entry.flags = ipsec_sad_flags_encode (sa);
if (sa->is_tunnel)
{
- if (sa->is_tunnel_ip6)
- {
- memcpy (mp->tunnel_src_addr, &sa->tunnel_src_addr.ip6, 16);
- memcpy (mp->tunnel_dst_addr, &sa->tunnel_dst_addr.ip6, 16);
- }
- else
- {
- memcpy (mp->tunnel_src_addr, &sa->tunnel_src_addr.ip4, 4);
- memcpy (mp->tunnel_dst_addr, &sa->tunnel_dst_addr.ip4, 4);
- }
+ ip_address_encode (&sa->tunnel_src_addr, IP46_TYPE_ANY,
+ &mp->entry.tunnel_src);
+ ip_address_encode (&sa->tunnel_dst_addr, IP46_TYPE_ANY,
+ &mp->entry.tunnel_dst);
}
+ mp->sw_if_index = htonl (sw_if_index);
mp->salt = clib_host_to_net_u32 (sa->salt);
mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
@@ -653,10 +709,6 @@ send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg,
if (sa->use_anti_replay)
mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
mp->total_data_size = clib_host_to_net_u64 (sa->total_data_size);
- mp->udp_encap = sa->udp_encap;
-
- mp->tx_table_id =
- htonl (fib_table_get_table_id (sa->tx_fib_index, FIB_PROTOCOL_IP4));
vl_api_send_msg (reg, (u8 *) mp);
}
diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c
index 4bc14372042..f66bf6d5aa1 100644
--- a/src/vnet/ipsec/ipsec_cli.c
+++ b/src/vnet/ipsec/ipsec_cli.c
@@ -73,87 +73,62 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
- ipsec_main_t *im = &ipsec_main;
unformat_input_t _line_input, *line_input = &_line_input;
- ipsec_sa_t sa;
- int is_add = ~0;
- u8 *ck = 0, *ik = 0;
- clib_error_t *error = NULL;
-
- clib_memset (&sa, 0, sizeof (sa));
- sa.tx_fib_index = ~((u32) 0); /* Only supported for ipsec interfaces */
+ ip46_address_t tun_src = { }, tun_dst =
+ {
+ };
+ ipsec_crypto_alg_t crypto_alg;
+ ipsec_integ_alg_t integ_alg;
+ ipsec_protocol_t proto;
+ ipsec_sa_flags_t flags;
+ clib_error_t *error;
+ ipsec_key_t ck, ik;
+ int is_add, rv;
+ u32 id, spi;
+
+ error = NULL;
+ is_add = 0;
+ flags = IPSEC_SA_FLAG_NONE;
+ proto = IPSEC_PROTOCOL_ESP;
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (line_input, "add %u", &sa.id))
+ if (unformat (line_input, "add %u", &id))
is_add = 1;
- else if (unformat (line_input, "del %u", &sa.id))
+ else if (unformat (line_input, "del %u", &id))
is_add = 0;
- else if (unformat (line_input, "spi %u", &sa.spi))
+ else if (unformat (line_input, "spi %u", &spi))
;
else if (unformat (line_input, "esp"))
- sa.protocol = IPSEC_PROTOCOL_ESP;
+ proto = IPSEC_PROTOCOL_ESP;
else if (unformat (line_input, "ah"))
- {
- sa.protocol = IPSEC_PROTOCOL_AH;
- }
- else
- if (unformat (line_input, "crypto-key %U", unformat_hex_string, &ck))
- sa.crypto_key_len = vec_len (ck);
- else
- if (unformat
- (line_input, "crypto-alg %U", unformat_ipsec_crypto_alg,
- &sa.crypto_alg))
- {
- if (sa.crypto_alg < IPSEC_CRYPTO_ALG_NONE ||
- sa.crypto_alg >= IPSEC_CRYPTO_N_ALG)
- {
- error = clib_error_return (0, "unsupported crypto-alg: '%U'",
- format_ipsec_crypto_alg,
- sa.crypto_alg);
- goto done;
- }
- }
- else
- if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik))
- sa.integ_key_len = vec_len (ik);
- else if (unformat (line_input, "integ-alg %U", unformat_ipsec_integ_alg,
- &sa.integ_alg))
- {
- if (sa.integ_alg < IPSEC_INTEG_ALG_NONE ||
- sa.integ_alg >= IPSEC_INTEG_N_ALG)
- {
- error = clib_error_return (0, "unsupported integ-alg: '%U'",
- format_ipsec_integ_alg,
- sa.integ_alg);
- goto done;
- }
- }
- else if (unformat (line_input, "tunnel-src %U",
- unformat_ip4_address, &sa.tunnel_src_addr.ip4))
- sa.is_tunnel = 1;
- else if (unformat (line_input, "tunnel-dst %U",
- unformat_ip4_address, &sa.tunnel_dst_addr.ip4))
- sa.is_tunnel = 1;
+ proto = IPSEC_PROTOCOL_AH;
+ else if (unformat (line_input, "crypto-key %U",
+ unformat_ipsec_key, &ck))
+ ;
+ else if (unformat (line_input, "crypto-alg %U",
+ unformat_ipsec_crypto_alg, &crypto_alg))
+ ;
+ else if (unformat (line_input, "integ-key %U", unformat_ipsec_key, &ik))
+ ;
+ else if (unformat (line_input, "integ-alg %U",
+ unformat_ipsec_integ_alg, &integ_alg))
+ ;
else if (unformat (line_input, "tunnel-src %U",
- unformat_ip6_address, &sa.tunnel_src_addr.ip6))
+ unformat_ip46_address, &tun_src))
{
- sa.is_tunnel = 1;
- sa.is_tunnel_ip6 = 1;
+ flags |= IPSEC_SA_FLAG_IS_TUNNEL;
+ if (!ip46_address_is_ip4 (&tun_src))
+ flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6;
}
else if (unformat (line_input, "tunnel-dst %U",
- unformat_ip6_address, &sa.tunnel_dst_addr.ip6))
- {
- sa.is_tunnel = 1;
- sa.is_tunnel_ip6 = 1;
- }
+ unformat_ip46_address, &tun_dst))
+ ;
else if (unformat (line_input, "udp-encap"))
- {
- sa.udp_encap = 1;
- }
+ flags |= IPSEC_SA_FLAG_UDP_ENCAP;
else
{
error = clib_error_return (0, "parse error: '%U'",
@@ -162,26 +137,15 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm,
}
}
- if (sa.crypto_key_len > sizeof (sa.crypto_key))
- sa.crypto_key_len = sizeof (sa.crypto_key);
-
- if (sa.integ_key_len > sizeof (sa.integ_key))
- sa.integ_key_len = sizeof (sa.integ_key);
-
- if (ck)
- memcpy (sa.crypto_key, ck, sa.crypto_key_len);
-
- if (ik)
- memcpy (sa.integ_key, ik, sa.integ_key_len);
-
if (is_add)
- {
- error = ipsec_check_support_cb (im, &sa);
- if (error)
- goto done;
- }
+ rv = ipsec_sa_add (id, spi, proto, crypto_alg,
+ &ck, integ_alg, &ik, flags,
+ 0, &tun_src, &tun_dst, NULL);
+ else
+ rv = ipsec_sa_del (id);
- ipsec_add_del_sa (vm, &sa, is_add);
+ if (rv)
+ clib_error_return (0, "failed");
done:
unformat_free (line_input);
@@ -388,25 +352,22 @@ set_ipsec_sa_key_command_fn (vlib_main_t * vm,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
- ipsec_sa_t sa;
- u8 *ck = 0, *ik = 0;
clib_error_t *error = NULL;
-
- clib_memset (&sa, 0, sizeof (sa));
+ ipsec_key_t ck, ik;
+ u32 id;
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (line_input, "%u", &sa.id))
+ if (unformat (line_input, "%u", &id))
;
else
- if (unformat (line_input, "crypto-key %U", unformat_hex_string, &ck))
- sa.crypto_key_len = vec_len (ck);
- else
- if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik))
- sa.integ_key_len = vec_len (ik);
+ if (unformat (line_input, "crypto-key %U", unformat_ipsec_key, &ck))
+ ;
+ else if (unformat (line_input, "integ-key %U", unformat_ipsec_key, &ik))
+ ;
else
{
error = clib_error_return (0, "parse error: '%U'",
@@ -415,19 +376,7 @@ set_ipsec_sa_key_command_fn (vlib_main_t * vm,
}
}
- if (sa.crypto_key_len > sizeof (sa.crypto_key))
- sa.crypto_key_len = sizeof (sa.crypto_key);
-
- if (sa.integ_key_len > sizeof (sa.integ_key))
- sa.integ_key_len = sizeof (sa.integ_key);
-
- if (ck)
- strncpy ((char *) sa.crypto_key, (char *) ck, sa.crypto_key_len);
-
- if (ik)
- strncpy ((char *) sa.integ_key, (char *) ik, sa.integ_key_len);
-
- ipsec_set_sa_key (vm, &sa);
+ ipsec_set_sa_key (id, &ck, &ik);
done:
unformat_free (line_input);
@@ -448,96 +397,45 @@ static clib_error_t *
show_ipsec_command_fn (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
- ipsec_sa_t *sa;
ipsec_main_t *im = &ipsec_main;
- u32 i;
- ipsec_tunnel_if_t *t;
+ u32 spd_id, sw_if_index, sai;
vnet_hw_interface_t *hi;
+ ipsec_tunnel_if_t *t;
u8 *protocol = NULL;
u8 *policy = NULL;
- u32 tx_table_id, spd_id, sw_if_index;
+ u32 i;
/* *INDENT-OFF* */
- pool_foreach (sa, im->sad, ({
- if (sa->id) {
- vlib_cli_output(vm, "sa %u spi %u mode %s protocol %s%s%s%s", sa->id, sa->spi,
- sa->is_tunnel ? "tunnel" : "transport",
- sa->protocol ? "esp" : "ah",
- sa->udp_encap ? " udp-encap-enabled" : "",
- sa->use_anti_replay ? " anti-replay" : "",
- sa->use_esn ? " extended-sequence-number" : "");
- if (sa->protocol == IPSEC_PROTOCOL_ESP) {
- vlib_cli_output(vm, " crypto alg %U%s%U integrity alg %U%s%U",
- format_ipsec_crypto_alg, sa->crypto_alg,
- sa->crypto_alg ? " key " : "",
- format_hex_bytes, sa->crypto_key, sa->crypto_key_len,
- format_ipsec_integ_alg, sa->integ_alg,
- sa->integ_alg ? " key " : "",
- format_hex_bytes, sa->integ_key, sa->integ_key_len);
- }
- if (sa->is_tunnel && sa->is_tunnel_ip6) {
- vlib_cli_output(vm, " tunnel src %U dst %U",
- format_ip6_address, &sa->tunnel_src_addr.ip6,
- format_ip6_address, &sa->tunnel_dst_addr.ip6);
- } else if (sa->is_tunnel) {
- vlib_cli_output(vm, " tunnel src %U dst %U",
- format_ip4_address, &sa->tunnel_src_addr.ip4,
- format_ip4_address, &sa->tunnel_dst_addr.ip4);
- }
- }
+ pool_foreach_index (sai, im->sad, ({
+ vlib_cli_output(vm, "%U", format_ipsec_sa, sai);
}));
- /* *INDENT-ON* */
-
- /* *INDENT-OFF* */
pool_foreach_index (i, im->spds, ({
vlib_cli_output(vm, "%U", format_ipsec_spd, i);
}));
- /* *INDENT-ON* */
vlib_cli_output (vm, "SPD Bindings:");
- /* *INDENT-OFF* */
+
hash_foreach(sw_if_index, spd_id, im->spd_index_by_sw_if_index, ({
- vlib_cli_output (vm, " %d -> %U", spd_id,
- format_vnet_sw_if_index_name, im->vnet_main,
- sw_if_index);
+ vlib_cli_output (vm, " %d -> %U", spd_id,
+ format_vnet_sw_if_index_name, im->vnet_main,
+ sw_if_index);
}));
/* *INDENT-ON* */
-
vlib_cli_output (vm, "tunnel interfaces");
/* *INDENT-OFF* */
pool_foreach (t, im->tunnel_interfaces, ({
if (t->hw_if_index == ~0)
continue;
hi = vnet_get_hw_interface (im->vnet_main, t->hw_if_index);
- vlib_cli_output(vm, " %s seq", hi->name);
- sa = pool_elt_at_index(im->sad, t->output_sa_index);
-
- tx_table_id = fib_table_get_table_id(sa->tx_fib_index, FIB_PROTOCOL_IP4);
-
- vlib_cli_output(vm, " seq %u seq-hi %u esn %u anti-replay %u udp-encap %u tx-table %u",
- sa->seq, sa->seq_hi, sa->use_esn, sa->use_anti_replay, sa->udp_encap, tx_table_id);
- vlib_cli_output(vm, " local-spi %u local-ip %U", sa->spi,
- format_ip4_address, &sa->tunnel_src_addr.ip4);
- vlib_cli_output(vm, " local-crypto %U %U",
- format_ipsec_crypto_alg, sa->crypto_alg,
- format_hex_bytes, sa->crypto_key, sa->crypto_key_len);
- vlib_cli_output(vm, " local-integrity %U %U",
- format_ipsec_integ_alg, sa->integ_alg,
- format_hex_bytes, sa->integ_key, sa->integ_key_len);
- sa = pool_elt_at_index(im->sad, t->input_sa_index);
- vlib_cli_output(vm, " last-seq %u last-seq-hi %u esn %u anti-replay %u window %U",
- sa->last_seq, sa->last_seq_hi, sa->use_esn,
- sa->use_anti_replay,
- format_ipsec_replay_window, sa->replay_window);
- vlib_cli_output(vm, " remote-spi %u remote-ip %U", sa->spi,
- format_ip4_address, &sa->tunnel_src_addr.ip4);
- vlib_cli_output(vm, " remote-crypto %U %U",
- format_ipsec_crypto_alg, sa->crypto_alg,
- format_hex_bytes, sa->crypto_key, sa->crypto_key_len);
- vlib_cli_output(vm, " remote-integrity %U %U",
- format_ipsec_integ_alg, sa->integ_alg,
- format_hex_bytes, sa->integ_key, sa->integ_key_len);
+
+ vlib_cli_output(vm, " %s", hi->name);
+
+ vlib_cli_output(vm, " out-bound sa");
+ vlib_cli_output(vm, " %U", format_ipsec_sa, t->output_sa_index);
+
+ vlib_cli_output(vm, " in-bound sa");
+ vlib_cli_output(vm, " %U", format_ipsec_sa, t->input_sa_index);
}));
vec_free(policy);
vec_free(protocol);
diff --git a/src/vnet/ipsec/ipsec_format.c b/src/vnet/ipsec/ipsec_format.c
index cbd67239680..04a2a0b5be1 100644
--- a/src/vnet/ipsec/ipsec_format.c
+++ b/src/vnet/ipsec/ipsec_format.c
@@ -19,6 +19,7 @@
#include <vnet/api_errno.h>
#include <vnet/ip/ip.h>
#include <vnet/interface.h>
+#include <vnet/fib/fib_table.h>
#include <vnet/ipsec/ipsec.h>
@@ -208,6 +209,77 @@ format_ipsec_spd (u8 * s, va_list * args)
return (s);
}
+u8 *
+format_ipsec_key (u8 * s, va_list * args)
+{
+ ipsec_key_t *key = va_arg (*args, ipsec_key_t *);
+
+ return (format (s, "%U", format_hex_bytes, key->data, key->len));
+}
+
+uword
+unformat_ipsec_key (unformat_input_t * input, va_list * args)
+{
+ ipsec_key_t *key = va_arg (*args, ipsec_key_t *);
+ u8 *data;
+
+ if (unformat (input, "%U", unformat_hex_string, &data))
+ {
+ ipsec_mk_key (key, data, vec_len (data));
+ vec_free (data);
+ }
+ else
+ return 0;
+ return 1;
+}
+
+u8 *
+format_ipsec_sa (u8 * s, va_list * args)
+{
+ u32 sai = va_arg (*args, u32);
+ ipsec_main_t *im = &ipsec_main;
+ u32 tx_table_id;
+ ipsec_sa_t *sa;
+
+ sa = pool_elt_at_index (im->sad, sai);
+
+ s = format (s, "[%d] sa %u spi %u mode %s%s protocol %s%s%s%s",
+ sai, sa->id, sa->spi,
+ sa->is_tunnel ? "tunnel" : "transport",
+ sa->is_tunnel_ip6 ? "-ip6" : "",
+ sa->protocol ? "esp" : "ah",
+ sa->udp_encap ? " udp-encap-enabled" : "",
+ sa->use_anti_replay ? " anti-replay" : "",
+ sa->use_esn ? " extended-sequence-number" : "");
+ s = format (s, "\n last-seq %u last-seq-hi %u window %U",
+ sa->last_seq, sa->last_seq_hi,
+ format_ipsec_replay_window, sa->replay_window);
+ s = format (s, "\n crypto alg %U%s%U",
+ format_ipsec_crypto_alg, sa->crypto_alg,
+ sa->crypto_alg ? " key " : "",
+ format_ipsec_key, &sa->crypto_key);
+ s = format (s, "\n integrity alg %U%s%U",
+ format_ipsec_integ_alg, sa->integ_alg,
+ sa->integ_alg ? " key " : "", format_ipsec_key, &sa->integ_key);
+
+ if (sa->is_tunnel)
+ {
+ tx_table_id = fib_table_get_table_id (sa->tx_fib_index,
+ FIB_PROTOCOL_IP4);
+ s = format (s, "\n table-ID %d tunnel src %U dst %U",
+ tx_table_id,
+ format_ip46_address, &sa->tunnel_src_addr, IP46_TYPE_ANY,
+ format_ip46_address, &sa->tunnel_dst_addr, IP46_TYPE_ANY);
+ s = format (s, "\n resovle via fib-entry: %d", sa->fib_entry_index);
+ s = format (s, "\n stacked on:");
+ s =
+ format (s, "\n %U", format_dpo_id, &sa->dpo[IPSEC_PROTOCOL_ESP],
+ 6);
+ }
+
+ return (s);
+}
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c
index 0dfb6909e42..357d638d38b 100644
--- a/src/vnet/ipsec/ipsec_if.c
+++ b/src/vnet/ipsec/ipsec_if.c
@@ -250,6 +250,18 @@ ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
return 0;
}
+static u32
+ipsec_tun_mk_input_sa_id (u32 ti)
+{
+ return (0x80000000 | ti);
+}
+
+static u32
+ipsec_tun_mk_output_sa_id (u32 ti)
+{
+ return (0xc0000000 | ti);
+}
+
int
ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
ipsec_add_del_tunnel_args_t * args,
@@ -260,12 +272,13 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
vnet_hw_interface_t *hi = NULL;
u32 hw_if_index = ~0;
uword *p;
- ipsec_sa_t *sa;
u32 dev_instance;
u32 slot;
- u32 tx_fib_index = ~0;
+ ipsec_key_t crypto_key, integ_key;
+ ipsec_sa_flags_t flags;
+ int rv;
- u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
+ u64 key = (u64) args->remote_ip.ip4.as_u32 << 32 | (u64) args->remote_spi;
p = hash_get (im->ipsec_if_pool_index_by_key, key);
if (args->is_add)
@@ -274,10 +287,6 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
if (p)
return VNET_API_ERROR_INVALID_VALUE;
- tx_fib_index = fib_table_find (FIB_PROTOCOL_IP4, args->tx_table_id);
- if (tx_fib_index == ~((u32) 0))
- return VNET_API_ERROR_NO_SUCH_FIB;
-
pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
clib_memset (t, 0, sizeof (*t));
@@ -296,59 +305,53 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
hash_set (im->ipsec_if_real_dev_by_show_dev, t->show_instance,
dev_instance);
- pool_get (im->sad, sa);
- clib_memset (sa, 0, sizeof (*sa));
- t->input_sa_index = sa - im->sad;
- sa->protocol = IPSEC_PROTOCOL_ESP;
- sa->spi = args->remote_spi;
- sa->tunnel_src_addr.ip4.as_u32 = args->remote_ip.as_u32;
- sa->tunnel_dst_addr.ip4.as_u32 = args->local_ip.as_u32;
- sa->is_tunnel = 1;
- sa->use_esn = args->esn;
- sa->use_anti_replay = args->anti_replay;
- sa->integ_alg = args->integ_alg;
- sa->udp_encap = args->udp_encap;
- sa->tx_fib_index = ~((u32) 0); /* Not used, but set for troubleshooting */
- if (args->remote_integ_key_len <= sizeof (args->remote_integ_key))
- {
- sa->integ_key_len = args->remote_integ_key_len;
- clib_memcpy (sa->integ_key, args->remote_integ_key,
- args->remote_integ_key_len);
- }
- sa->crypto_alg = args->crypto_alg;
- if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key))
- {
- sa->crypto_key_len = args->remote_crypto_key_len;
- clib_memcpy (sa->crypto_key, args->remote_crypto_key,
- args->remote_crypto_key_len);
- }
-
- pool_get (im->sad, sa);
- clib_memset (sa, 0, sizeof (*sa));
- t->output_sa_index = sa - im->sad;
- sa->protocol = IPSEC_PROTOCOL_ESP;
- sa->spi = args->local_spi;
- sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32;
- sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32;
- sa->is_tunnel = 1;
- sa->use_esn = args->esn;
- sa->use_anti_replay = args->anti_replay;
- sa->integ_alg = args->integ_alg;
- sa->udp_encap = args->udp_encap;
- sa->tx_fib_index = tx_fib_index;
- if (args->local_integ_key_len <= sizeof (args->local_integ_key))
- {
- sa->integ_key_len = args->local_integ_key_len;
- clib_memcpy (sa->integ_key, args->local_integ_key,
- args->local_integ_key_len);
- }
- sa->crypto_alg = args->crypto_alg;
- if (args->local_crypto_key_len <= sizeof (args->local_crypto_key))
- {
- sa->crypto_key_len = args->local_crypto_key_len;
- clib_memcpy (sa->crypto_key, args->local_crypto_key,
- args->local_crypto_key_len);
- }
+ flags = IPSEC_SA_FLAG_IS_TUNNEL;
+ if (args->udp_encap)
+ flags |= IPSEC_SA_FLAG_UDP_ENCAP;
+ if (args->esn)
+ flags |= IPSEC_SA_FLAG_USE_EXTENDED_SEQ_NUM;
+ if (args->anti_replay)
+ flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY;
+
+ ipsec_mk_key (&crypto_key,
+ args->remote_crypto_key, args->remote_crypto_key_len);
+ ipsec_mk_key (&integ_key,
+ args->remote_integ_key, args->remote_integ_key_len);
+
+ rv = ipsec_sa_add (ipsec_tun_mk_input_sa_id (dev_instance),
+ args->remote_spi,
+ IPSEC_PROTOCOL_ESP,
+ args->crypto_alg,
+ &crypto_key,
+ args->integ_alg,
+ &integ_key,
+ flags,
+ args->tx_table_id,
+ &args->remote_ip,
+ &args->local_ip, &t->input_sa_index);
+
+ if (rv)
+ return VNET_API_ERROR_UNIMPLEMENTED;
+
+ ipsec_mk_key (&crypto_key,
+ args->local_crypto_key, args->local_crypto_key_len);
+ ipsec_mk_key (&integ_key,
+ args->local_integ_key, args->local_integ_key_len);
+
+ rv = ipsec_sa_add (ipsec_tun_mk_output_sa_id (dev_instance),
+ args->local_spi,
+ IPSEC_PROTOCOL_ESP,
+ args->crypto_alg,
+ &crypto_key,
+ args->integ_alg,
+ &integ_key,
+ flags,
+ args->tx_table_id,
+ &args->local_ip,
+ &args->remote_ip, &t->output_sa_index);
+
+ if (rv)
+ return VNET_API_ERROR_UNIMPLEMENTED;
hash_set (im->ipsec_if_pool_index_by_key, key,
t - im->tunnel_interfaces);
@@ -392,18 +395,14 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
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);
- 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);
+
+ /* delete input and output SA */
+ ipsec_sa_del (ipsec_tun_mk_input_sa_id (p[0]));
+ ipsec_sa_del (ipsec_tun_mk_output_sa_id (p[0]));
}
if (sw_if_index)
@@ -493,29 +492,25 @@ ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
{
sa = pool_elt_at_index (im->sad, t->output_sa_index);
sa->crypto_alg = alg;
- sa->crypto_key_len = vec_len (key);
- clib_memcpy (sa->crypto_key, key, vec_len (key));
+ ipsec_mk_key (&sa->crypto_key, key, vec_len (key));
}
else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
{
sa = pool_elt_at_index (im->sad, t->output_sa_index);
sa->integ_alg = alg;
- sa->integ_key_len = vec_len (key);
- clib_memcpy (sa->integ_key, key, vec_len (key));
+ ipsec_mk_key (&sa->integ_key, key, vec_len (key));
}
else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
{
sa = pool_elt_at_index (im->sad, t->input_sa_index);
sa->crypto_alg = alg;
- sa->crypto_key_len = vec_len (key);
- clib_memcpy (sa->crypto_key, key, vec_len (key));
+ ipsec_mk_key (&sa->crypto_key, key, vec_len (key));
}
else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
{
sa = pool_elt_at_index (im->sad, t->input_sa_index);
sa->integ_alg = alg;
- sa->integ_key_len = vec_len (key);
- clib_memcpy (sa->integ_key, key, vec_len (key));
+ ipsec_mk_key (&sa->integ_key, key, vec_len (key));
}
else
return VNET_API_ERROR_INVALID_VALUE;
diff --git a/src/vnet/ipsec/ipsec_if.h b/src/vnet/ipsec/ipsec_if.h
index 96a109ddaf5..67d5554e777 100644
--- a/src/vnet/ipsec/ipsec_if.h
+++ b/src/vnet/ipsec/ipsec_if.h
@@ -41,7 +41,7 @@ typedef struct
u8 is_add;
u8 esn;
u8 anti_replay;
- ip4_address_t local_ip, remote_ip;
+ ip46_address_t local_ip, remote_ip;
u32 local_spi;
u32 remote_spi;
ipsec_crypto_alg_t crypto_alg;
diff --git a/src/vnet/ipsec/ipsec_if_in.c b/src/vnet/ipsec/ipsec_if_in.c
index 1dbd12710c9..833f8485340 100644
--- a/src/vnet/ipsec/ipsec_if_in.c
+++ b/src/vnet/ipsec/ipsec_if_in.c
@@ -25,7 +25,8 @@
/* Statistics (not really errors) */
#define foreach_ipsec_if_input_error \
_(RX, "good packets received") \
-_(DISABLED, "ipsec packets received on disabled interface")
+_(DISABLED, "ipsec packets received on disabled interface") \
+_(NO_TUNNEL, "no matching tunnel")
static char *ipsec_if_input_error_strings[] = {
#define _(sym,string) string,
@@ -76,7 +77,7 @@ VLIB_NODE_FN (ipsec_if_input_node) (vlib_main_t * vm,
ipsec_sa_t *sa0;
vlib_combined_counter_main_t *rx_counter;
vlib_combined_counter_main_t *drop_counter;
- u32 n_disabled = 0;
+ u32 n_disabled = 0, n_no_tunnel = 0;
rx_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
drop_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
@@ -181,6 +182,11 @@ VLIB_NODE_FN (ipsec_if_input_node) (vlib_main_t * vm,
vlib_buffer_advance (b0, ip4_header_bytes (ip0));
next0 = im->esp4_decrypt_next_index;
}
+ else
+ {
+ b0->error = node->errors[IPSEC_IF_INPUT_ERROR_NO_TUNNEL];
+ n_no_tunnel++;
+ }
trace:
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
@@ -216,6 +222,8 @@ VLIB_NODE_FN (ipsec_if_input_node) (vlib_main_t * vm,
vlib_node_increment_counter (vm, ipsec_if_input_node.index,
IPSEC_IF_INPUT_ERROR_DISABLED, n_disabled);
+ vlib_node_increment_counter (vm, ipsec_if_input_node.index,
+ IPSEC_IF_INPUT_ERROR_DISABLED, n_no_tunnel);
return from_frame->n_vectors;
}
diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c
index d439b4d46d3..f20d941fd68 100644
--- a/src/vnet/ipsec/ipsec_sa.c
+++ b/src/vnet/ipsec/ipsec_sa.c
@@ -14,6 +14,7 @@
*/
#include <vnet/ipsec/ipsec.h>
+#include <vnet/fib/fib_table.h>
static clib_error_t *
ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa,
@@ -37,8 +38,146 @@ ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa,
return 0;
}
+void
+ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len)
+{
+ memset (key, 0, sizeof (*key));
+
+ if (len > sizeof (key->data))
+ key->len = sizeof (key->data);
+ else
+ key->len = len;
+
+ memcpy (key->data, data, key->len);
+}
+
+/**
+ * 'stack' (resolve the recursion for) the SA tunnel destination
+ */
+static void
+ipsec_sa_stack (ipsec_sa_t * sa)
+{
+ fib_forward_chain_type_t fct;
+ dpo_id_t tmp = DPO_INVALID;
+ vlib_node_t *node;
+
+ fct = fib_forw_chain_type_from_fib_proto ((sa->is_tunnel_ip6 ?
+ FIB_PROTOCOL_IP6 :
+ FIB_PROTOCOL_IP4));
+
+ fib_entry_contribute_forwarding (sa->fib_entry_index, fct, &tmp);
+
+ node = vlib_get_node_by_name (vlib_get_main (),
+ (sa->is_tunnel_ip6 ?
+ (u8 *) "ah6-encrypt" :
+ (u8 *) "ah4-encrypt"));
+ dpo_stack_from_node (node->index, &sa->dpo[IPSEC_PROTOCOL_AH], &tmp);
+
+ node = vlib_get_node_by_name (vlib_get_main (),
+ (sa->is_tunnel_ip6 ?
+ (u8 *) "esp6-encrypt" :
+ (u8 *) "esp4-encrypt"));
+ dpo_stack_from_node (node->index, &sa->dpo[IPSEC_PROTOCOL_ESP], &tmp);
+}
+
int
-ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add)
+ipsec_sa_add (u32 id,
+ u32 spi,
+ ipsec_protocol_t proto,
+ ipsec_crypto_alg_t crypto_alg,
+ const ipsec_key_t * ck,
+ ipsec_integ_alg_t integ_alg,
+ const ipsec_key_t * ik,
+ ipsec_sa_flags_t flags,
+ u32 tx_table_id,
+ const ip46_address_t * tun_src,
+ const ip46_address_t * tun_dst, u32 * sa_out_index)
+{
+ ipsec_main_t *im = &ipsec_main;
+ clib_error_t *err;
+ ipsec_sa_t *sa;
+ u32 sa_index;
+ uword *p;
+
+ p = hash_get (im->sa_index_by_sa_id, id);
+ if (p)
+ return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
+
+ pool_get_zero (im->sad, sa);
+
+ fib_node_init (&sa->node, FIB_NODE_TYPE_IPSEC_SA);
+ sa_index = sa - im->sad;
+
+ sa->id = id;
+ sa->spi = spi;
+ sa->protocol = proto;
+ sa->crypto_alg = crypto_alg;
+ clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key));
+ sa->integ_alg = integ_alg;
+ clib_memcpy (&sa->integ_key, ik, sizeof (sa->integ_key));
+ ip46_address_copy (&sa->tunnel_src_addr, tun_src);
+ ip46_address_copy (&sa->tunnel_dst_addr, tun_dst);
+
+ if (flags & IPSEC_SA_FLAG_USE_EXTENDED_SEQ_NUM)
+ sa->use_esn = 1;
+ if (flags & IPSEC_SA_FLAG_USE_ANTI_REPLAY)
+ sa->use_anti_replay = 1;
+ if (flags & IPSEC_SA_FLAG_IS_TUNNEL)
+ sa->is_tunnel = 1;
+ if (flags & IPSEC_SA_FLAG_IS_TUNNEL_V6)
+ sa->is_tunnel_ip6 = 1;
+ if (flags & IPSEC_SA_FLAG_UDP_ENCAP)
+ sa->udp_encap = 1;
+
+ err = ipsec_check_support_cb (im, sa);
+ if (err)
+ {
+ clib_warning ("%s", err->what);
+ pool_put (im->sad, sa);
+ return VNET_API_ERROR_UNIMPLEMENTED;
+ }
+
+ err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
+ if (err)
+ {
+ pool_put (im->sad, sa);
+ return VNET_API_ERROR_SYSCALL_ERROR_1;
+ }
+
+ if (sa->is_tunnel)
+ {
+ fib_protocol_t fproto = (sa->is_tunnel_ip6 ?
+ FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
+ fib_prefix_t pfx = {
+ .fp_addr = sa->tunnel_dst_addr,
+ .fp_len = (sa->is_tunnel_ip6 ? 128 : 32),
+ .fp_proto = fproto,
+ };
+ sa->tx_fib_index = fib_table_find (fproto, tx_table_id);
+ if (sa->tx_fib_index == ~((u32) 0))
+ {
+ pool_put (im->sad, sa);
+ return VNET_API_ERROR_NO_SUCH_FIB;
+ }
+
+ sa->fib_entry_index = fib_table_entry_special_add (sa->tx_fib_index,
+ &pfx,
+ FIB_SOURCE_RR,
+ FIB_ENTRY_FLAG_NONE);
+ sa->sibling = fib_entry_child_add (sa->fib_entry_index,
+ FIB_NODE_TYPE_IPSEC_SA, sa_index);
+ ipsec_sa_stack (sa);
+ }
+ hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
+
+ if (sa_out_index)
+ *sa_out_index = sa_index;
+
+ return (0);
+}
+
+u32
+ipsec_sa_del (u32 id)
{
ipsec_main_t *im = &ipsec_main;
ipsec_sa_t *sa = 0;
@@ -46,39 +185,33 @@ ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add)
u32 sa_index;
clib_error_t *err;
- clib_warning ("id %u spi %u", new_sa->id, new_sa->spi);
+ p = hash_get (im->sa_index_by_sa_id, id);
- p = hash_get (im->sa_index_by_sa_id, new_sa->id);
- if (p && is_add)
- return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
- if (!p && !is_add)
+ if (!p)
return VNET_API_ERROR_NO_SUCH_ENTRY;
- if (!is_add) /* delete */
+ sa_index = p[0];
+ sa = pool_elt_at_index (im->sad, sa_index);
+ if (ipsec_is_sa_used (sa_index))
{
- sa_index = p[0];
- sa = pool_elt_at_index (im->sad, sa_index);
- if (ipsec_is_sa_used (sa_index))
- {
- clib_warning ("sa_id %u used in policy", sa->id);
- return VNET_API_ERROR_SYSCALL_ERROR_1; /* sa used in policy */
- }
- hash_unset (im->sa_index_by_sa_id, sa->id);
- err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
- if (err)
- return VNET_API_ERROR_SYSCALL_ERROR_1;
- pool_put (im->sad, sa);
+ clib_warning ("sa_id %u used in policy", sa->id);
+ /* sa used in policy */
+ return VNET_API_ERROR_SYSCALL_ERROR_1;
}
- else /* create new SA */
+ hash_unset (im->sa_index_by_sa_id, sa->id);
+ err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
+ if (err)
+ return VNET_API_ERROR_SYSCALL_ERROR_1;
+ if (sa->is_tunnel)
{
- pool_get (im->sad, sa);
- clib_memcpy (sa, new_sa, sizeof (*sa));
- sa_index = sa - im->sad;
- hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
- err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
- if (err)
- return VNET_API_ERROR_SYSCALL_ERROR_1;
+ fib_entry_child_remove (sa->fib_entry_index, sa->sibling);
+ fib_table_entry_special_remove
+ (sa->tx_fib_index,
+ fib_entry_get_prefix (sa->fib_entry_index), FIB_SOURCE_RR);
+ dpo_reset (&sa->dpo[IPSEC_PROTOCOL_AH]);
+ dpo_reset (&sa->dpo[IPSEC_PROTOCOL_ESP]);
}
+ pool_put (im->sad, sa);
return 0;
}
@@ -110,7 +243,7 @@ ipsec_is_sa_used (u32 sa_index)
}
int
-ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update)
+ipsec_set_sa_key (u32 id, const ipsec_key_t * ck, const ipsec_key_t * ik)
{
ipsec_main_t *im = &ipsec_main;
uword *p;
@@ -118,7 +251,7 @@ ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update)
ipsec_sa_t *sa = 0;
clib_error_t *err;
- p = hash_get (im->sa_index_by_sa_id, sa_update->id);
+ p = hash_get (im->sa_index_by_sa_id, id);
if (!p)
return VNET_API_ERROR_SYSCALL_ERROR_1; /* no such sa-id */
@@ -126,22 +259,18 @@ ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update)
sa = pool_elt_at_index (im->sad, sa_index);
/* new crypto key */
- if (0 < sa_update->crypto_key_len)
+ if (ck)
{
- clib_memcpy (sa->crypto_key, sa_update->crypto_key,
- sa_update->crypto_key_len);
- sa->crypto_key_len = sa_update->crypto_key_len;
+ clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key));
}
/* new integ key */
- if (0 < sa_update->integ_key_len)
+ if (ik)
{
- clib_memcpy (sa->integ_key, sa_update->integ_key,
- sa_update->integ_key_len);
- sa->integ_key_len = sa_update->integ_key_len;
+ clib_memcpy (&sa->integ_key, 0, sizeof (sa->integ_key));
}
- if (0 < sa_update->crypto_key_len || 0 < sa_update->integ_key_len)
+ if (ck || ik)
{
err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
if (err)
@@ -162,6 +291,75 @@ ipsec_get_sa_index_by_sa_id (u32 sa_id)
return p[0];
}
+/**
+ * Function definition to get a FIB node from its index
+ */
+static fib_node_t *
+ipsec_sa_fib_node_get (fib_node_index_t index)
+{
+ ipsec_main_t *im;
+ ipsec_sa_t *sa;
+
+ im = &ipsec_main;
+ sa = pool_elt_at_index (im->sad, index);
+
+ return (&sa->node);
+}
+
+/**
+ * Function definition to inform the FIB node that its last lock has gone.
+ */
+static void
+ipsec_sa_last_lock_gone (fib_node_t * node)
+{
+ /*
+ * The ipsec SA is a root of the graph. As such
+ * it never has children and thus is never locked.
+ */
+ ASSERT (0);
+}
+
+static ipsec_sa_t *
+ipsec_sa_from_fib_node (fib_node_t * node)
+{
+ ASSERT (FIB_NODE_TYPE_IPSEC_SA == node->fn_type);
+ return ((ipsec_sa_t *) (((char *) node) -
+ STRUCT_OFFSET_OF (ipsec_sa_t, node)));
+
+}
+
+/**
+ * Function definition to backwalk a FIB node
+ */
+static fib_node_back_walk_rc_t
+ipsec_sa_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
+{
+ ipsec_sa_stack (ipsec_sa_from_fib_node (node));
+
+ return (FIB_NODE_BACK_WALK_CONTINUE);
+}
+
+/*
+ * Virtual function table registered by MPLS GRE tunnels
+ * for participation in the FIB object graph.
+ */
+const static fib_node_vft_t ipsec_sa_vft = {
+ .fnv_get = ipsec_sa_fib_node_get,
+ .fnv_last_lock = ipsec_sa_last_lock_gone,
+ .fnv_back_walk = ipsec_sa_back_walk,
+};
+
+/* force inclusion from application's main.c */
+clib_error_t *
+ipsec_sa_interface_init (vlib_main_t * vm)
+{
+ fib_node_register_type (FIB_NODE_TYPE_IPSEC_SA, &ipsec_sa_vft);
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (ipsec_sa_interface_init);
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h
index 43d699be928..775343b4b73 100644
--- a/src/vnet/ipsec/ipsec_sa.h
+++ b/src/vnet/ipsec/ipsec_sa.h
@@ -17,6 +17,7 @@
#include <vlib/vlib.h>
#include <vnet/ip/ip.h>
+#include <vnet/fib/fib_node.h>
#define foreach_ipsec_crypto_alg \
_ (0, NONE, "none") \
@@ -63,19 +64,50 @@ typedef enum
IPSEC_PROTOCOL_ESP = 1
} ipsec_protocol_t;
+#define IPSEC_N_PROTOCOLS (IPSEC_PROTOCOL_ESP+1)
+
+#define IPSEC_KEY_MAX_LEN 128
+typedef struct ipsec_key_t_
+{
+ u8 len;
+ u8 data[IPSEC_KEY_MAX_LEN];
+} ipsec_key_t;
+
+/*
+ * Enable extended sequence numbers
+ * Enable Anti-replay
+ * IPsec tunnel mode if non-zero, else transport mode
+ * IPsec tunnel mode is IPv6 if non-zero,
+ * else IPv4 tunnel only valid if is_tunnel is non-zero
+ * enable UDP encapsulation for NAT traversal
+ */
+#define foreach_ipsec_sa_flags \
+ _ (0, NONE, "none") \
+ _ (1, USE_EXTENDED_SEQ_NUM, "esn") \
+ _ (2, USE_ANTI_REPLAY, "anti-replay") \
+ _ (4, IS_TUNNEL, "tunnel") \
+ _ (8, IS_TUNNEL_V6, "tunnel-v6") \
+ _ (16, UDP_ENCAP, "udp-encap") \
+
+typedef enum ipsec_sad_flags_t_
+{
+#define _(v, f, s) IPSEC_SA_FLAG_##f = v,
+ foreach_ipsec_sa_flags
+#undef _
+} ipsec_sa_flags_t;
+
typedef struct
{
+ fib_node_t node;
u32 id;
u32 spi;
ipsec_protocol_t protocol;
ipsec_crypto_alg_t crypto_alg;
- u8 crypto_key_len;
- u8 crypto_key[128];
+ ipsec_key_t crypto_key;
ipsec_integ_alg_t integ_alg;
- u8 integ_key_len;
- u8 integ_key[128];
+ ipsec_key_t integ_key;
u8 use_esn;
u8 use_anti_replay;
@@ -86,6 +118,10 @@ typedef struct
ip46_address_t tunnel_src_addr;
ip46_address_t tunnel_dst_addr;
+ fib_node_index_t fib_entry_index;
+ u32 sibling;
+ dpo_id_t dpo[IPSEC_N_PROTOCOLS];
+
u32 tx_fib_index;
u32 salt;
@@ -100,18 +136,36 @@ typedef struct
u64 total_data_size;
} ipsec_sa_t;
-extern int ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa,
- int is_add);
+extern void ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len);
+
+extern int ipsec_sa_add (u32 id,
+ u32 spi,
+ ipsec_protocol_t proto,
+ ipsec_crypto_alg_t crypto_alg,
+ const ipsec_key_t * ck,
+ ipsec_integ_alg_t integ_alg,
+ const ipsec_key_t * ik,
+ ipsec_sa_flags_t flags,
+ u32 tx_table_id,
+ const ip46_address_t * tunnel_src_addr,
+ const ip46_address_t * tunnel_dst_addr,
+ u32 * sa_index);
+extern u32 ipsec_sa_del (u32 id);
+
extern u8 ipsec_is_sa_used (u32 sa_index);
-extern int ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update);
+extern int ipsec_set_sa_key (u32 id,
+ const ipsec_key_t * ck, const ipsec_key_t * ik);
extern u32 ipsec_get_sa_index_by_sa_id (u32 sa_id);
extern u8 *format_ipsec_crypto_alg (u8 * s, va_list * args);
extern u8 *format_ipsec_integ_alg (u8 * s, va_list * args);
+extern u8 *format_ipsec_sa (u8 * s, va_list * args);
+extern u8 *format_ipsec_key (u8 * s, va_list * args);
extern uword unformat_ipsec_crypto_alg (unformat_input_t * input,
va_list * args);
extern uword unformat_ipsec_integ_alg (unformat_input_t * input,
va_list * args);
+extern uword unformat_ipsec_key (unformat_input_t * input, va_list * args);
#endif /* __IPSEC_SPD_SA_H__ */