aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2019-02-06 01:41:05 -0800
committerFlorin Coras <florin.coras@gmail.com>2019-02-07 19:13:32 +0000
commit8d7c502002636da1cb7c71a87757f328e7c2c4fd (patch)
tree1005d63dcb3a24f7bb2ad2d3224bfcb062909666
parent3d0ef26a0285b9baa486c91b2e6609125a2bc651 (diff)
IPSEC: no second lookup after tunnel encap
in the same maaner as with other tunnel tyeps we use the FIB to cache and track the destination used to reach the tunnel endpoint. Post encap we can then ship the packet straight to this adjacency and thus elide the costly second lookup. - SA add and del function so they can be used both directly from the API and for tunnels. - API change for the SA dump to use the SA type - ipsec_key_t type for convenience (copying, [un]formating) - no matching tunnel counters in ipsec-if-input Change-Id: I9d144a59667f7bf96442f4ca66bef5c1d3c7f1ea Signed-off-by: Neale Ranns <nranns@cisco.com>
-rw-r--r--src/plugins/dpdk/ipsec/ipsec.c9
-rw-r--r--src/vat/api_format.c114
-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
-rw-r--r--test/vpp_ipsec.py2
18 files changed, 781 insertions, 504 deletions
diff --git a/src/plugins/dpdk/ipsec/ipsec.c b/src/plugins/dpdk/ipsec/ipsec.c
index 2415422ae2d..f79b4301e9c 100644
--- a/src/plugins/dpdk/ipsec/ipsec.c
+++ b/src/plugins/dpdk/ipsec/ipsec.c
@@ -252,7 +252,7 @@ crypto_set_aead_xform (struct rte_crypto_sym_xform *xform,
xform->type = RTE_CRYPTO_SYM_XFORM_AEAD;
xform->aead.algo = c->alg;
- xform->aead.key.data = sa->crypto_key;
+ xform->aead.key.data = sa->crypto_key.data;
xform->aead.key.length = c->key_len;
xform->aead.iv.offset =
crypto_op_get_priv_offset () + offsetof (dpdk_op_priv_t, cb);
@@ -280,7 +280,7 @@ crypto_set_cipher_xform (struct rte_crypto_sym_xform *xform,
xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
xform->cipher.algo = c->alg;
- xform->cipher.key.data = sa->crypto_key;
+ xform->cipher.key.data = sa->crypto_key.data;
xform->cipher.key.length = c->key_len;
xform->cipher.iv.offset =
crypto_op_get_priv_offset () + offsetof (dpdk_op_priv_t, cb);
@@ -306,7 +306,7 @@ crypto_set_auth_xform (struct rte_crypto_sym_xform *xform,
xform->type = RTE_CRYPTO_SYM_XFORM_AUTH;
xform->auth.algo = a->alg;
- xform->auth.key.data = sa->integ_key;
+ xform->auth.key.data = sa->integ_key.data;
xform->auth.key.length = a->key_len;
xform->auth.digest_length = a->trunc_size;
xform->next = NULL;
@@ -511,7 +511,8 @@ add_del_sa_session (u32 sa_index, u8 is_add)
case IPSEC_CRYPTO_ALG_AES_GCM_128:
case IPSEC_CRYPTO_ALG_AES_GCM_192:
case IPSEC_CRYPTO_ALG_AES_GCM_256:
- clib_memcpy (&sa->salt, &sa->crypto_key[sa->crypto_key_len - 4], 4);
+ clib_memcpy (&sa->salt,
+ &sa->crypto_key.data[sa->crypto_key.len - 4], 4);
break;
default:
seed = (u32) clib_cpu_time_now ();
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index 5ddbb57f281..1d93cc17648 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -15215,21 +15215,21 @@ vl_api_ipsec_sa_details_t_handler (vl_api_ipsec_sa_details_t * mp)
vat_main_t *vam = &vat_main;
print (vam->ofp, "sa_id %u sw_if_index %u spi %u proto %u crypto_alg %u "
- "crypto_key %U integ_alg %u integ_key %U use_esn %u "
- "use_anti_replay %u is_tunnel %u is_tunnel_ip6 %u "
+ "crypto_key %U integ_alg %u integ_key %U flags %x "
"tunnel_src_addr %U tunnel_dst_addr %U "
"salt %u seq_outbound %lu last_seq_inbound %lu "
"replay_window %lu total_data_size %lu\n",
- ntohl (mp->sa_id), ntohl (mp->sw_if_index), ntohl (mp->spi),
- mp->protocol,
- mp->crypto_alg, format_hex_bytes, mp->crypto_key, mp->crypto_key_len,
- mp->integ_alg, format_hex_bytes, mp->integ_key, mp->integ_key_len,
- mp->use_esn, mp->use_anti_replay, mp->is_tunnel, mp->is_tunnel_ip6,
- (mp->is_tunnel_ip6) ? format_ip6_address : format_ip4_address,
- mp->tunnel_src_addr,
- (mp->is_tunnel_ip6) ? format_ip6_address : format_ip4_address,
- mp->tunnel_dst_addr,
- ntohl (mp->salt),
+ ntohl (mp->entry.sad_id),
+ ntohl (mp->sw_if_index),
+ ntohl (mp->entry.spi),
+ ntohl (mp->entry.protocol),
+ ntohl (mp->entry.crypto_algorithm),
+ format_hex_bytes, mp->entry.crypto_key.data,
+ mp->entry.crypto_key.length, ntohl (mp->entry.integrity_algorithm),
+ format_hex_bytes, mp->entry.integrity_key.data,
+ mp->entry.integrity_key.length, ntohl (mp->entry.flags),
+ format_vl_api_address, &mp->entry.tunnel_src, format_vl_api_address,
+ &mp->entry.tunnel_dst, ntohl (mp->salt),
clib_net_to_host_u64 (mp->seq_outbound),
clib_net_to_host_u64 (mp->last_seq_inbound),
clib_net_to_host_u64 (mp->replay_window),
@@ -15239,13 +15239,32 @@ vl_api_ipsec_sa_details_t_handler (vl_api_ipsec_sa_details_t * mp)
#define vl_api_ipsec_sa_details_t_endian vl_noop_handler
#define vl_api_ipsec_sa_details_t_print vl_noop_handler
+static void
+vat_json_object_add_address (vat_json_node_t * node,
+ const vl_api_address_t * addr)
+{
+ if (ADDRESS_IP6 == addr->af)
+ {
+ struct in6_addr ip6;
+
+ clib_memcpy (&ip6, &addr->un.ip6, sizeof (ip6));
+ vat_json_object_add_ip6 (node, "ip_address", ip6);
+ }
+ else
+ {
+ struct in_addr ip4;
+
+ clib_memcpy (&ip4, &addr->un.ip4, sizeof (ip4));
+ vat_json_object_add_ip4 (node, "ip_address", ip4);
+ }
+}
+
static void vl_api_ipsec_sa_details_t_handler_json
(vl_api_ipsec_sa_details_t * mp)
{
vat_main_t *vam = &vat_main;
vat_json_node_t *node = NULL;
- struct in_addr src_ip4, dst_ip4;
- struct in6_addr src_ip6, dst_ip6;
+ vl_api_ipsec_sad_flags_t flags;
if (VAT_JSON_ARRAY != vam->json_tree.type)
{
@@ -15255,39 +15274,36 @@ static void vl_api_ipsec_sa_details_t_handler_json
node = vat_json_array_add (&vam->json_tree);
vat_json_init_object (node);
- vat_json_object_add_uint (node, "sa_id", ntohl (mp->sa_id));
+ vat_json_object_add_uint (node, "sa_id", ntohl (mp->entry.sad_id));
vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index));
- vat_json_object_add_uint (node, "spi", ntohl (mp->spi));
- vat_json_object_add_uint (node, "proto", mp->protocol);
- vat_json_object_add_uint (node, "crypto_alg", mp->crypto_alg);
- vat_json_object_add_uint (node, "integ_alg", mp->integ_alg);
- vat_json_object_add_uint (node, "use_esn", mp->use_esn);
- vat_json_object_add_uint (node, "use_anti_replay", mp->use_anti_replay);
- vat_json_object_add_uint (node, "is_tunnel", mp->is_tunnel);
- vat_json_object_add_uint (node, "is_tunnel_ip6", mp->is_tunnel_ip6);
- vat_json_object_add_bytes (node, "crypto_key", mp->crypto_key,
- mp->crypto_key_len);
- vat_json_object_add_bytes (node, "integ_key", mp->integ_key,
- mp->integ_key_len);
- if (mp->is_tunnel_ip6)
- {
- clib_memcpy (&src_ip6, mp->tunnel_src_addr, sizeof (src_ip6));
- vat_json_object_add_ip6 (node, "tunnel_src_addr", src_ip6);
- clib_memcpy (&dst_ip6, mp->tunnel_dst_addr, sizeof (dst_ip6));
- vat_json_object_add_ip6 (node, "tunnel_dst_addr", dst_ip6);
- }
- else
- {
- clib_memcpy (&src_ip4, mp->tunnel_src_addr, sizeof (src_ip4));
- vat_json_object_add_ip4 (node, "tunnel_src_addr", src_ip4);
- clib_memcpy (&dst_ip4, mp->tunnel_dst_addr, sizeof (dst_ip4));
- vat_json_object_add_ip4 (node, "tunnel_dst_addr", dst_ip4);
- }
+ vat_json_object_add_uint (node, "spi", ntohl (mp->entry.spi));
+ vat_json_object_add_uint (node, "proto", ntohl (mp->entry.protocol));
+ vat_json_object_add_uint (node, "crypto_alg",
+ ntohl (mp->entry.crypto_algorithm));
+ vat_json_object_add_uint (node, "integ_alg",
+ ntohl (mp->entry.integrity_algorithm));
+ flags = ntohl (mp->entry.flags);
+ vat_json_object_add_uint (node, "use_esn",
+ ! !(flags &
+ IPSEC_API_SAD_FLAG_USE_EXTENDED_SEQ_NUM));
+ vat_json_object_add_uint (node, "use_anti_replay",
+ ! !(flags & IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY));
+ vat_json_object_add_uint (node, "is_tunnel",
+ ! !(flags & IPSEC_API_SAD_FLAG_IS_TUNNEL));
+ vat_json_object_add_uint (node, "is_tunnel_ip6",
+ ! !(flags & IPSEC_API_SAD_FLAG_IS_TUNNEL_V6));
+ vat_json_object_add_uint (node, "udp_encap",
+ ! !(flags & IPSEC_API_SAD_FLAG_UDP_ENCAP));
+ vat_json_object_add_bytes (node, "crypto_key", mp->entry.crypto_key.data,
+ mp->entry.crypto_key.length);
+ vat_json_object_add_bytes (node, "integ_key", mp->entry.integrity_key.data,
+ mp->entry.integrity_key.length);
+ vat_json_object_add_address (node, &mp->entry.tunnel_src);
+ vat_json_object_add_address (node, &mp->entry.tunnel_dst);
vat_json_object_add_uint (node, "replay_window",
clib_net_to_host_u64 (mp->replay_window));
vat_json_object_add_uint (node, "total_data_size",
clib_net_to_host_u64 (mp->total_data_size));
-
}
static int
@@ -20085,8 +20101,6 @@ static void vl_api_ip_neighbor_details_t_handler_json
vat_main_t *vam = &vat_main;
vat_json_node_t *node;
- struct in_addr ip4;
- struct in6_addr ip6;
if (VAT_JSON_ARRAY != vam->json_tree.type)
{
@@ -20104,17 +20118,7 @@ static void vl_api_ip_neighbor_details_t_handler_json
vat_json_object_add_string_copy (node, "link_layer",
format (0, "%U", format_vl_api_mac_address,
&mp->neighbor.mac_address));
-
- if (ADDRESS_IP6 == mp->neighbor.ip_address.af)
- {
- clib_memcpy (&ip6, &mp->neighbor.ip_address.un.ip6, sizeof (ip6));
- vat_json_object_add_ip6 (node, "ip_address", ip6);
- }
- else
- {
- clib_memcpy (&ip4, &mp->neighbor.ip_address.un.ip4, sizeof (ip4));
- vat_json_object_add_ip4 (node, "ip_address", ip4);
- }
+ vat_json_object_add_address (node, &mp->neighbor.ip_address);
}
static int
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__ */
diff --git a/test/vpp_ipsec.py b/test/vpp_ipsec.py
index 69aebc599d6..917574ee977 100644
--- a/test/vpp_ipsec.py
+++ b/test/vpp_ipsec.py
@@ -249,6 +249,6 @@ class VppIpsecSA(VppObject):
def query_vpp_config(self):
bs = self.test.vapi.ipsec_sa_dump()
for b in bs:
- if b.sa_id == self.id:
+ if b.entry.sad_id == self.id:
return True
return False