summaryrefslogtreecommitdiffstats
path: root/vnet/vnet/ipsec
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2016-08-10 01:55:36 -0700
committerKeith Burns <alagalah@gmail.com>2016-08-17 23:21:46 +0000
commit694265d4f10dc86bd27bfd29a2b7c49440aeb6b5 (patch)
tree48dac360be791a6de945b4eaf1eca495ef08ef0a /vnet/vnet/ipsec
parent0c25d1f2a872e693d22b81f1d9cd48cc46b10cc1 (diff)
VPP-202: L2-GRE over IPSecv16.12-rc0
GRE encapsulate layer 2 traffic and IPSec encrypt what is encapsulated by GRE. The whole point of L2-GRE over IPSec is to tunnel layer 2 over GRE and IPSec by bridging the physical interface with IPSec-GRE tunnel interface. Change-Id: Ia4cf9ed407bf663770e0d8905c0ad44ce73bd23b Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'vnet/vnet/ipsec')
-rw-r--r--vnet/vnet/ipsec/esp_decrypt.c14
-rw-r--r--vnet/vnet/ipsec/esp_encrypt.c33
-rw-r--r--vnet/vnet/ipsec/ipsec.c19
-rw-r--r--vnet/vnet/ipsec/ipsec.h15
-rw-r--r--vnet/vnet/ipsec/ipsec_cli.c2
-rw-r--r--vnet/vnet/ipsec/ipsec_if.c62
-rw-r--r--vnet/vnet/ipsec/ipsec_if_in.c2
-rw-r--r--vnet/vnet/ipsec/ipsec_input.c10
8 files changed, 136 insertions, 21 deletions
diff --git a/vnet/vnet/ipsec/esp_decrypt.c b/vnet/vnet/ipsec/esp_decrypt.c
index c350508917b..6c7f27f078c 100644
--- a/vnet/vnet/ipsec/esp_decrypt.c
+++ b/vnet/vnet/ipsec/esp_decrypt.c
@@ -27,7 +27,8 @@
#define foreach_esp_decrypt_next \
_(DROP, "error-drop") \
_(IP4_INPUT, "ip4-input") \
-_(IP6_INPUT, "ip6-input")
+_(IP6_INPUT, "ip6-input") \
+_(IPSEC_GRE_INPUT, "ipsec-gre-input")
#define _(v, s) ESP_DECRYPT_NEXT_##v,
typedef enum
@@ -421,7 +422,10 @@ esp_decrypt_node_fn (vlib_main_t * vm,
if (PREDICT_TRUE (tunnel_mode))
{
if (PREDICT_TRUE (f0->next_header == IP_PROTOCOL_IP_IN_IP))
- next0 = ESP_DECRYPT_NEXT_IP4_INPUT;
+ {
+ next0 = ESP_DECRYPT_NEXT_IP4_INPUT;
+ oh4 = vlib_buffer_get_current (o_b0);
+ }
else if (f0->next_header == IP_PROTOCOL_IPV6)
next0 = ESP_DECRYPT_NEXT_IP6_INPUT;
else
@@ -471,6 +475,12 @@ esp_decrypt_node_fn (vlib_main_t * vm,
}
}
+ /* for IPSec-GRE tunnel next node is ipsec-gre-input */
+ if (PREDICT_FALSE
+ ((vnet_buffer (i_b0)->output_features.ipsec_flags) &
+ IPSEC_FLAG_IPSEC_GRE_TUNNEL))
+ next0 = ESP_DECRYPT_NEXT_IPSEC_GRE_INPUT;
+
to_next[0] = o_bi0;
to_next += 1;
diff --git a/vnet/vnet/ipsec/esp_encrypt.c b/vnet/vnet/ipsec/esp_encrypt.c
index 45b4b3bb72b..0516d43f09b 100644
--- a/vnet/vnet/ipsec/esp_encrypt.c
+++ b/vnet/vnet/ipsec/esp_encrypt.c
@@ -248,6 +248,8 @@ esp_encrypt_node_fn (vlib_main_t * vm,
oh6_0->esp.spi = clib_net_to_host_u32 (sa0->spi);
oh6_0->esp.seq = clib_net_to_host_u32 (sa0->seq);
ip_proto = ih6_0->ip6.protocol;
+
+ next0 = ESP_ENCRYPT_NEXT_IP6_INPUT;
}
else
{
@@ -268,6 +270,8 @@ esp_encrypt_node_fn (vlib_main_t * vm,
oh0->esp.spi = clib_net_to_host_u32 (sa0->spi);
oh0->esp.seq = clib_net_to_host_u32 (sa0->seq);
ip_proto = ih0->ip4.protocol;
+
+ next0 = ESP_ENCRYPT_NEXT_IP4_INPUT;
}
if (PREDICT_TRUE
@@ -276,8 +280,6 @@ esp_encrypt_node_fn (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;
- /* in tunnel mode send it back to FIB */
- next0 = ESP_ENCRYPT_NEXT_IP4_INPUT;
vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
}
else if (is_ipv6 && sa0->is_tunnel && sa0->is_tunnel_ip6)
@@ -291,25 +293,26 @@ esp_encrypt_node_fn (vlib_main_t * vm,
oh6_0->ip6.dst_address.as_u64[1] =
sa0->tunnel_dst_addr.ip6.as_u64[1];
- /* in tunnel mode send it back to FIB */
- next0 = ESP_ENCRYPT_NEXT_IP6_INPUT;
vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
}
else
{
- transport_mode = 1;
- ethernet_header_t *ieh0, *oeh0;
- ieh0 = (ethernet_header_t *) i_b0->data;
- oeh0 = (ethernet_header_t *) o_b0->data;
- clib_memcpy (oeh0, ieh0, sizeof (ethernet_header_t));
vlib_buffer_advance (i_b0, ip_hdr_size);
next_hdr_type = ip_proto;
- next0 = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
- o_b0->flags |= BUFFER_OUTPUT_FEAT_DONE;
- vnet_buffer (o_b0)->sw_if_index[VLIB_TX] =
- vnet_buffer (i_b0)->sw_if_index[VLIB_TX];
- vnet_buffer (o_b0)->output_features.bitmap =
- vnet_buffer (i_b0)->output_features.bitmap;
+ if (vnet_buffer (i_b0)->sw_if_index[VLIB_TX] != ~0)
+ {
+ transport_mode = 1;
+ ethernet_header_t *ieh0, *oeh0;
+ ieh0 = (ethernet_header_t *) i_b0->data;
+ oeh0 = (ethernet_header_t *) o_b0->data;
+ clib_memcpy (oeh0, ieh0, sizeof (ethernet_header_t));
+ next0 = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
+ o_b0->flags |= BUFFER_OUTPUT_FEAT_DONE;
+ vnet_buffer (o_b0)->sw_if_index[VLIB_TX] =
+ vnet_buffer (i_b0)->sw_if_index[VLIB_TX];
+ vnet_buffer (o_b0)->output_features.bitmap =
+ vnet_buffer (i_b0)->output_features.bitmap;
+ }
}
ASSERT (sa0->crypto_alg < IPSEC_CRYPTO_N_ALG);
diff --git a/vnet/vnet/ipsec/ipsec.c b/vnet/vnet/ipsec/ipsec.c
index bf9dd973f86..1b3b9ffcc38 100644
--- a/vnet/vnet/ipsec/ipsec.c
+++ b/vnet/vnet/ipsec/ipsec.c
@@ -24,6 +24,17 @@
#include <vnet/ipsec/esp.h>
#include <vnet/ipsec/ikev2.h>
+u32
+ipsec_get_sa_index_by_sa_id (u32 sa_id)
+{
+ ipsec_main_t *im = &ipsec_main;
+ uword *p = hash_get (im->sa_index_by_sa_id, sa_id);
+ if (!p)
+ return ~0;
+
+ return p[0];
+}
+
int
ipsec_set_interface_spd (vlib_main_t * vm, u32 sw_if_index, u32 spd_id,
int is_add)
@@ -391,6 +402,7 @@ ipsec_is_sa_used (u32 sa_index)
ipsec_main_t *im = &ipsec_main;
ipsec_spd_t *spd;
ipsec_policy_t *p;
+ ipsec_tunnel_if_t *t;
/* *INDENT-OFF* */
pool_foreach(spd, im->spds, ({
@@ -402,6 +414,13 @@ ipsec_is_sa_used (u32 sa_index)
}
}));
}));
+
+ pool_foreach(t, im->tunnel_interfaces, ({
+ if (t->input_sa_index == sa_index)
+ return 1;
+ if (t->output_sa_index == sa_index)
+ return 1;
+ }));
/* *INDENT-ON* */
return 0;
diff --git a/vnet/vnet/ipsec/ipsec.h b/vnet/vnet/ipsec/ipsec.h
index 5b88c8278fb..fd3e8a361d1 100644
--- a/vnet/vnet/ipsec/ipsec.h
+++ b/vnet/vnet/ipsec/ipsec.h
@@ -16,6 +16,8 @@
#include <vnet/devices/dpdk/dpdk.h>
#endif
+#define IPSEC_FLAG_IPSEC_GRE_TUNNEL (1 << 0)
+
#define foreach_ipsec_policy_action \
_(0, BYPASS, "bypass") \
_(1, DISCARD, "discard") \
@@ -127,6 +129,15 @@ typedef struct
u8 remote_integ_key[128];
} ipsec_add_del_tunnel_args_t;
+typedef struct
+{
+ u8 is_add;
+ u32 local_sa_id;
+ u32 remote_sa_id;
+ ip4_address_t local_ip;
+ ip4_address_t remote_ip;
+} ipsec_add_del_ipsec_gre_tunnel_args_t;
+
typedef enum
{
IPSEC_IF_SET_KEY_TYPE_NONE,
@@ -243,6 +254,7 @@ int ipsec_add_del_policy (vlib_main_t * vm, ipsec_policy_t * policy,
int ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add);
int ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update);
+u32 ipsec_get_sa_index_by_sa_id (u32 sa_id);
u8 *format_ipsec_if_output_trace (u8 * s, va_list * args);
u8 *format_ipsec_policy_action (u8 * s, va_list * args);
u8 *format_ipsec_crypto_alg (u8 * s, va_list * args);
@@ -254,6 +266,9 @@ uword unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args);
/*u32 ipsec_add_del_tunnel_if (vnet_main_t * vnm, ipsec_add_del_tunnel_args_t * args); */
int ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args);
+int ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
+ ipsec_add_del_ipsec_gre_tunnel_args_t *
+ args);
int ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
ipsec_if_set_key_type_t type, u8 alg, u8 * key);
diff --git a/vnet/vnet/ipsec/ipsec_cli.c b/vnet/vnet/ipsec/ipsec_cli.c
index 8b15110af0d..785e040b006 100644
--- a/vnet/vnet/ipsec/ipsec_cli.c
+++ b/vnet/vnet/ipsec/ipsec_cli.c
@@ -561,6 +561,8 @@ show_ipsec_command_fn (vlib_main_t * vm,
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);
diff --git a/vnet/vnet/ipsec/ipsec_if.c b/vnet/vnet/ipsec/ipsec_if.c
index 475b7bda2bc..f4fad8d95b3 100644
--- a/vnet/vnet/ipsec/ipsec_if.c
+++ b/vnet/vnet/ipsec/ipsec_if.c
@@ -195,6 +195,68 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
}
int
+ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
+ ipsec_add_del_ipsec_gre_tunnel_args_t * args)
+{
+ ipsec_tunnel_if_t *t = 0;
+ ipsec_main_t *im = &ipsec_main;
+ uword *p;
+ ipsec_sa_t *sa;
+ u64 key;
+ u32 isa, osa;
+
+ p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
+ if (!p)
+ return VNET_API_ERROR_INVALID_VALUE;
+ isa = p[0];
+
+ p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
+ if (!p)
+ return VNET_API_ERROR_INVALID_VALUE;
+ osa = p[0];
+ sa = pool_elt_at_index (im->sad, p[0]);
+
+ if (sa->is_tunnel)
+ key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
+ else
+ key = (u64) args->remote_ip.as_u32 << 32 | (u64) sa->spi;
+
+ p = hash_get (im->ipsec_if_pool_index_by_key, key);
+
+ if (args->is_add)
+ {
+ /* check if same src/dst pair exists */
+ if (p)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
+ memset (t, 0, sizeof (*t));
+
+ t->input_sa_index = isa;
+ t->output_sa_index = osa;
+ t->hw_if_index = ~0;
+ hash_set (im->ipsec_if_pool_index_by_key, key,
+ t - im->tunnel_interfaces);
+
+ /*1st interface, register protocol */
+ if (pool_elts (im->tunnel_interfaces) == 1)
+ ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
+ ipsec_if_input_node.index);
+ }
+ else
+ {
+ /* check if exists */
+ if (!p)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
+ hash_unset (im->ipsec_if_pool_index_by_key, key);
+ pool_put (im->tunnel_interfaces, t);
+ }
+ return 0;
+}
+
+int
ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
ipsec_if_set_key_type_t type, u8 alg, u8 * key)
{
diff --git a/vnet/vnet/ipsec/ipsec_if_in.c b/vnet/vnet/ipsec/ipsec_if_in.c
index e5574421cfa..07d4bf30352 100644
--- a/vnet/vnet/ipsec/ipsec_if_in.c
+++ b/vnet/vnet/ipsec/ipsec_if_in.c
@@ -113,6 +113,8 @@ ipsec_if_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
vnet_buffer (b0)->output_features.ipsec_sad_index =
t->input_sa_index;
+ vnet_buffer (b0)->output_features.ipsec_flags =
+ t->hw_if_index == ~0 ? IPSEC_FLAG_IPSEC_GRE_TUNNEL : 0;
vlib_buffer_advance (b0, ip4_header_bytes (ip0));
next0 = IPSEC_IF_INPUT_NEXT_ESP_DECRYPT;
}
diff --git a/vnet/vnet/ipsec/ipsec_input.c b/vnet/vnet/ipsec/ipsec_input.c
index 2bc4e2b4999..8364e226ae1 100644
--- a/vnet/vnet/ipsec/ipsec_input.c
+++ b/vnet/vnet/ipsec/ipsec_input.c
@@ -239,11 +239,11 @@ ipsec_input_ip4_node_fn (vlib_main_t * vm,
ipsec_policy_t *p0;
p0 = ipsec_input_protect_policy_match (spd0,
clib_net_to_host_u32
- (ip0->src_address.
- as_u32),
+ (ip0->
+ src_address.as_u32),
clib_net_to_host_u32
- (ip0->dst_address.
- as_u32),
+ (ip0->
+ dst_address.as_u32),
clib_net_to_host_u32
(esp0->spi));
@@ -253,6 +253,7 @@ ipsec_input_ip4_node_fn (vlib_main_t * vm,
p0->counter.bytes += clib_net_to_host_u16 (ip0->length);
vnet_buffer (b0)->output_features.ipsec_sad_index =
p0->sa_index;
+ vnet_buffer (b0)->output_features.ipsec_flags = 0;
next0 = IPSEC_INPUT_NEXT_ESP_DECRYPT;
vlib_buffer_advance (b0, ip4_header_bytes (ip0));
goto trace0;
@@ -382,6 +383,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (ipsec_input_ip4_node, ipsec_input_ip4_node_fn)
p0->counter.bytes += header_size;
vnet_buffer (b0)->output_features.ipsec_sad_index =
p0->sa_index;
+ vnet_buffer (b0)->output_features.ipsec_flags = 0;
next0 = IPSEC_INPUT_NEXT_ESP_DECRYPT;
vlib_buffer_advance (b0, header_size);
goto trace0;