aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2019-02-07 07:26:12 -0800
committerDamjan Marion <dmarion@me.com>2019-06-18 13:54:35 +0000
commitc87b66c86201458c0475d50c6e93f1497f9eec2e (patch)
tree57bf69c2adb85a93b26a86b5a1110e4290e7f391
parent097fa66b986f06281f603767d321ab13ab6c88c3 (diff)
ipsec: ipsec-tun protect
please consult the new tunnel proposal at: https://wiki.fd.io/view/VPP/IPSec Type: feature Change-Id: I52857fc92ae068b85f59be08bdbea1bd5932e291 Signed-off-by: Neale Ranns <nranns@cisco.com>
-rw-r--r--doxygen/user_doc.md1
-rw-r--r--src/scripts/vnet/ipsec_tun_protect71
-rw-r--r--src/vat/api_format.c179
-rw-r--r--src/vnet/CMakeLists.txt25
-rw-r--r--src/vnet/buffer.h1
-rw-r--r--src/vnet/gre/gre.c24
-rw-r--r--src/vnet/interface.c24
-rw-r--r--src/vnet/interface.h12
-rw-r--r--src/vnet/interface_funcs.h3
-rw-r--r--src/vnet/ip/ip6_packet.h17
-rw-r--r--src/vnet/ipip/ipip.c18
-rw-r--r--src/vnet/ipip/ipip_api.c4
-rw-r--r--src/vnet/ipsec-gre/dir.dox18
-rw-r--r--src/vnet/ipsec-gre/error.def26
-rw-r--r--src/vnet/ipsec-gre/interface.c301
-rw-r--r--src/vnet/ipsec-gre/ipsec_gre.api88
-rw-r--r--src/vnet/ipsec-gre/ipsec_gre.c394
-rw-r--r--src/vnet/ipsec-gre/ipsec_gre.h105
-rw-r--r--src/vnet/ipsec-gre/ipsec_gre_api.c190
-rw-r--r--src/vnet/ipsec-gre/ipsec_gre_doc.md74
-rw-r--r--src/vnet/ipsec-gre/node.c426
-rw-r--r--src/vnet/ipsec/ah_decrypt.c7
-rw-r--r--src/vnet/ipsec/esp_decrypt.c120
-rw-r--r--src/vnet/ipsec/esp_encrypt.c26
-rw-r--r--src/vnet/ipsec/ipsec.api76
-rw-r--r--src/vnet/ipsec/ipsec.h2
-rw-r--r--src/vnet/ipsec/ipsec_api.c139
-rw-r--r--src/vnet/ipsec/ipsec_cli.c125
-rw-r--r--src/vnet/ipsec/ipsec_format.c35
-rw-r--r--src/vnet/ipsec/ipsec_if.c84
-rw-r--r--src/vnet/ipsec/ipsec_if.h13
-rw-r--r--src/vnet/ipsec/ipsec_io.h2
-rw-r--r--src/vnet/ipsec/ipsec_sa.c25
-rw-r--r--src/vnet/ipsec/ipsec_sa.h10
-rw-r--r--src/vnet/ipsec/ipsec_tun.c398
-rw-r--r--src/vnet/ipsec/ipsec_tun.h114
-rw-r--r--src/vnet/ipsec/ipsec_tun_in.c436
-rw-r--r--src/vnet/vnet_all_api_h.h1
-rw-r--r--src/vpp/api/custom_dump.c36
-rw-r--r--src/vpp/api/vpe.api1
-rw-r--r--test/template_ipsec.py98
-rw-r--r--test/test_ipsec_esp.py16
-rw-r--r--test/test_ipsec_tun_if_esp.py659
-rw-r--r--test/vpp_ipip_tun_interface.py40
-rw-r--r--test/vpp_ipsec.py50
-rw-r--r--test/vpp_ipsec_tun_interface.py45
-rw-r--r--test/vpp_papi_provider.py13
47 files changed, 2447 insertions, 2125 deletions
diff --git a/doxygen/user_doc.md b/doxygen/user_doc.md
index d607d39f619..f39bc10c958 100644
--- a/doxygen/user_doc.md
+++ b/doxygen/user_doc.md
@@ -10,7 +10,6 @@ Several modules provide operational, dataplane-user focused documentation.
- @subpage dhcp6_pd_doc
- @subpage flowprobe_plugin_doc
- @subpage ioam_plugin_doc
-- @subpage ipsec_gre_doc
- @subpage kp_plugin_doc
- @subpage lacp_plugin_doc
- @subpage lb_plugin_doc
diff --git a/src/scripts/vnet/ipsec_tun_protect b/src/scripts/vnet/ipsec_tun_protect
new file mode 100644
index 00000000000..ed81f913139
--- /dev/null
+++ b/src/scripts/vnet/ipsec_tun_protect
@@ -0,0 +1,71 @@
+
+create packet-generator interface pg0
+create packet-generator interface pg1
+
+pipe create
+
+ip table add 1
+set int ip table pg1 1
+set int ip table pipe0.1 1
+
+set int ip address pg0 192.168.0.1/24
+set int ip address pg1 192.168.1.1/24
+
+set int ip address pipe0.0 10.0.0.1/24
+set int ip address pipe0.1 10.0.0.2/24
+
+set int state pg0 up
+set int state pg1 up
+set int state pipe0 up
+
+ipsec sa add 20 spi 200 crypto-key 6541686776336961656264656f6f6579 crypto-alg aes-cbc-128
+ipsec sa add 30 spi 300 crypto-key 6541686776336961656264656f6f6579 crypto-alg aes-cbc-128
+
+create ipip tunnel src 10.0.0.1 dst 10.0.0.2
+create ipip tunnel src 10.0.0.2 dst 10.0.0.1
+
+ipsec tunnel protect ipip0 sa-in 20 sa-out 30
+ipsec tunnel protect ipip1 sa-in 30 sa-out 20
+
+set int state ipip0 up
+set int unnum ipip0 use pg0
+
+set int state ipip1 up
+set int ip table ipip1 1
+set int unnum ipip1 use pg1
+
+ip route add 192.168.1.0/24 via ipip0
+set ip arp pg1 192.168.1.2 00:11:22:33:44:55
+ip route add table 1 192.168.0.0/24 via ipip1
+set ip arp pg0 192.168.0.2 00:11:22:33:44:66
+
+trace add pg-input 100
+
+packet-generator new {
+ name ipsec1
+ limit 1
+ rate 1e4
+ node ip4-input
+ interface pg0
+ size 100-100
+ data {
+ UDP: 192.168.0.2 -> 192.168.1.2
+ UDP: 4321 -> 1234
+ length 72
+ incrementing 100
+ }
+}
+packet-generator new {
+ name ipsec2
+ limit 1
+ rate 1e4
+ node ip4-input
+ interface pg1
+ size 100-100
+ data {
+ UDP: 192.168.1.2 -> 192.168.0.2
+ UDP: 4321 -> 1234
+ length 72
+ incrementing 100
+ }
+}
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index fe1a87f573e..536c4b06ba2 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -5084,41 +5084,6 @@ static void vl_api_policer_classify_details_t_handler_json
vat_json_object_add_uint (node, "table_index", ntohl (mp->table_index));
}
-static void vl_api_ipsec_gre_tunnel_add_del_reply_t_handler
- (vl_api_ipsec_gre_tunnel_add_del_reply_t * mp)
-{
- vat_main_t *vam = &vat_main;
- i32 retval = ntohl (mp->retval);
- if (vam->async_mode)
- {
- vam->async_errors += (retval < 0);
- }
- else
- {
- vam->retval = retval;
- vam->sw_if_index = ntohl (mp->sw_if_index);
- vam->result_ready = 1;
- }
- vam->regenerate_interface_table = 1;
-}
-
-static void vl_api_ipsec_gre_tunnel_add_del_reply_t_handler_json
- (vl_api_ipsec_gre_tunnel_add_del_reply_t * mp)
-{
- vat_main_t *vam = &vat_main;
- vat_json_node_t node;
-
- vat_json_init_object (&node);
- vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
- vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index));
-
- vat_json_print (vam->ofp, &node);
- vat_json_free (&node);
-
- vam->retval = ntohl (mp->retval);
- vam->result_ready = 1;
-}
-
static void vl_api_flow_classify_details_t_handler
(vl_api_flow_classify_details_t * mp)
{
@@ -5599,8 +5564,6 @@ _(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY, \
ip_source_and_port_range_check_add_del_reply) \
_(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL_REPLY, \
ip_source_and_port_range_check_interface_add_del_reply) \
-_(IPSEC_GRE_TUNNEL_ADD_DEL_REPLY, ipsec_gre_tunnel_add_del_reply) \
-_(IPSEC_GRE_TUNNEL_DETAILS, ipsec_gre_tunnel_details) \
_(DELETE_SUBIF_REPLY, delete_subif_reply) \
_(L2_INTERFACE_PBB_TAG_REWRITE_REPLY, l2_interface_pbb_tag_rewrite_reply) \
_(SET_PUNT_REPLY, set_punt_reply) \
@@ -20087,52 +20050,6 @@ api_ip_source_and_port_range_check_interface_add_del (vat_main_t * vam)
}
static int
-api_ipsec_gre_tunnel_add_del (vat_main_t * vam)
-{
- unformat_input_t *i = vam->input;
- vl_api_ipsec_gre_tunnel_add_del_t *mp;
- u32 local_sa_id = 0;
- u32 remote_sa_id = 0;
- vl_api_ip4_address_t src_address;
- vl_api_ip4_address_t dst_address;
- u8 is_add = 1;
- int ret;
-
- while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (i, "local_sa %d", &local_sa_id))
- ;
- else if (unformat (i, "remote_sa %d", &remote_sa_id))
- ;
- else
- if (unformat (i, "src %U", unformat_vl_api_ip4_address, &src_address))
- ;
- else
- if (unformat (i, "dst %U", unformat_vl_api_ip4_address, &dst_address))
- ;
- else if (unformat (i, "del"))
- is_add = 0;
- else
- {
- clib_warning ("parse error '%U'", format_unformat_error, i);
- return -99;
- }
- }
-
- M (IPSEC_GRE_TUNNEL_ADD_DEL, mp);
-
- mp->tunnel.local_sa_id = ntohl (local_sa_id);
- mp->tunnel.remote_sa_id = ntohl (remote_sa_id);
- clib_memcpy (mp->tunnel.src, &src_address, sizeof (src_address));
- clib_memcpy (mp->tunnel.dst, &dst_address, sizeof (dst_address));
- mp->is_add = is_add;
-
- S (mp);
- W (ret);
- return ret;
-}
-
-static int
api_set_punt (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
@@ -20173,99 +20090,6 @@ api_set_punt (vat_main_t * vam)
return ret;
}
-static void vl_api_ipsec_gre_tunnel_details_t_handler
- (vl_api_ipsec_gre_tunnel_details_t * mp)
-{
- vat_main_t *vam = &vat_main;
-
- print (vam->ofp, "%11d%15U%15U%14d%14d",
- ntohl (mp->tunnel.sw_if_index),
- format_vl_api_ip4_address, mp->tunnel.src,
- format_vl_api_ip4_address, mp->tunnel.dst,
- ntohl (mp->tunnel.local_sa_id), ntohl (mp->tunnel.remote_sa_id));
-}
-
-static void
-vat_json_object_add_vl_api_ip4 (vat_json_node_t * node,
- const char *name,
- const vl_api_ip4_address_t addr)
-{
- struct in_addr ip4;
-
- clib_memcpy (&ip4, addr, sizeof (ip4));
- vat_json_object_add_ip4 (node, name, ip4);
-}
-
-static void vl_api_ipsec_gre_tunnel_details_t_handler_json
- (vl_api_ipsec_gre_tunnel_details_t * mp)
-{
- vat_main_t *vam = &vat_main;
- vat_json_node_t *node = NULL;
-
- if (VAT_JSON_ARRAY != vam->json_tree.type)
- {
- ASSERT (VAT_JSON_NONE == vam->json_tree.type);
- vat_json_init_array (&vam->json_tree);
- }
- node = vat_json_array_add (&vam->json_tree);
-
- vat_json_init_object (node);
- vat_json_object_add_uint (node, "sw_if_index",
- ntohl (mp->tunnel.sw_if_index));
- vat_json_object_add_vl_api_ip4 (node, "src", mp->tunnel.src);
- vat_json_object_add_vl_api_ip4 (node, "src", mp->tunnel.dst);
- vat_json_object_add_uint (node, "local_sa_id",
- ntohl (mp->tunnel.local_sa_id));
- vat_json_object_add_uint (node, "remote_sa_id",
- ntohl (mp->tunnel.remote_sa_id));
-}
-
-static int
-api_ipsec_gre_tunnel_dump (vat_main_t * vam)
-{
- unformat_input_t *i = vam->input;
- vl_api_ipsec_gre_tunnel_dump_t *mp;
- vl_api_control_ping_t *mp_ping;
- u32 sw_if_index;
- u8 sw_if_index_set = 0;
- int ret;
-
- /* Parse args required to build the message */
- while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (i, "sw_if_index %d", &sw_if_index))
- sw_if_index_set = 1;
- else
- break;
- }
-
- if (sw_if_index_set == 0)
- {
- sw_if_index = ~0;
- }
-
- if (!vam->json_output)
- {
- print (vam->ofp, "%11s%15s%15s%14s%14s",
- "sw_if_index", "src_address", "dst_address",
- "local_sa_id", "remote_sa_id");
- }
-
- /* Get list of gre-tunnel interfaces */
- M (IPSEC_GRE_TUNNEL_DUMP, mp);
-
- mp->sw_if_index = htonl (sw_if_index);
-
- S (mp);
-
- /* Use a control ping for synchronization */
- MPING (CONTROL_PING, mp_ping);
- S (mp_ping);
-
- W (ret);
- return ret;
-}
-
static int
api_delete_subif (vat_main_t * vam)
{
@@ -22409,9 +22233,6 @@ _(ip_source_and_port_range_check_add_del, \
_(ip_source_and_port_range_check_interface_add_del, \
"<intf> | sw_if_index <nn> [tcp-out-vrf <id>] [tcp-in-vrf <id>]" \
"[udp-in-vrf <id>] [udp-out-vrf <id>]") \
-_(ipsec_gre_tunnel_add_del, \
- "src <addr> dst <addr> local_sa <sa-id> remote_sa <sa-id> [del]") \
-_(ipsec_gre_tunnel_dump, "[sw_if_index <nn>]") \
_(delete_subif,"<intfc> | sw_if_index <nn>") \
_(l2_interface_pbb_tag_rewrite, \
"<intfc> | sw_if_index <nn> \n" \
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt
index 5465d717f8c..462ced4ae23 100644
--- a/src/vnet/CMakeLists.txt
+++ b/src/vnet/CMakeLists.txt
@@ -566,6 +566,8 @@ list(APPEND VNET_SOURCES
ipsec/ipsec_sa.c
ipsec/ipsec_spd.c
ipsec/ipsec_spd_policy.c
+ ipsec/ipsec_tun.c
+ ipsec/ipsec_tun_in.c
ipsec/esp_format.c
ipsec/esp_encrypt.c
ipsec/esp_decrypt.c
@@ -582,6 +584,7 @@ list(APPEND VNET_MULTIARCH_SOURCES
ipsec/ipsec_if_in.c
ipsec/ipsec_output.c
ipsec/ipsec_input.c
+ ipsec/ipsec_tun_in.c
)
list(APPEND VNET_API_FILES ipsec/ipsec.api)
@@ -847,28 +850,6 @@ list(APPEND VNET_HEADERS
list(APPEND VNET_API_FILES vxlan-gpe/vxlan_gpe.api)
##############################################################################
-# Tunnel protocol: ipsec+gre
-##############################################################################
-list(APPEND VNET_SOURCES
- ipsec-gre/ipsec_gre.c
- ipsec-gre/node.c
- ipsec-gre/interface.c
- ipsec-gre/ipsec_gre_api.c
-)
-
-list(APPEND VNET_MULTIARCH_SOURCES
- ipsec-gre/node.c
- ipsec-gre/ipsec_gre.c
-)
-
-list(APPEND VNET_HEADERS
- ipsec-gre/ipsec_gre.h
- ipsec-gre/error.def
-)
-
-list(APPEND VNET_API_FILES ipsec-gre/ipsec_gre.api)
-
-##############################################################################
# LISP control plane: lisp-cp
##############################################################################
diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h
index 6738f3cdca8..812fe7478c0 100644
--- a/src/vnet/buffer.h
+++ b/src/vnet/buffer.h
@@ -276,6 +276,7 @@ typedef struct
struct
{
u32 sad_index;
+ u32 protect_index;
} ipsec;
/* MAP */
diff --git a/src/vnet/gre/gre.c b/src/vnet/gre/gre.c
index 72c76fca5df..ab2567dc5b7 100644
--- a/src/vnet/gre/gre.c
+++ b/src/vnet/gre/gre.c
@@ -530,6 +530,29 @@ format_gre_device (u8 * s, va_list * args)
return s;
}
+static int
+gre_tunnel_desc (u32 sw_if_index,
+ ip46_address_t * src, ip46_address_t * dst, u8 * is_l2)
+{
+ gre_main_t *gm = &gre_main;
+ gre_tunnel_t *t;
+ u32 ti;
+
+ ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
+
+ if (~0 == ti)
+ /* not one of ours */
+ return -1;
+
+ t = pool_elt_at_index (gm->tunnels, ti);
+
+ *src = t->tunnel_src;
+ *dst = t->tunnel_dst.fp_addr;
+ *is_l2 = t->type == GRE_TUNNEL_TYPE_TEB;
+
+ return (0);
+}
+
/* *INDENT-OFF* */
VNET_DEVICE_CLASS (gre_device_class) = {
.name = "GRE tunnel device",
@@ -537,6 +560,7 @@ VNET_DEVICE_CLASS (gre_device_class) = {
.format_device = format_gre_device,
.format_tx_trace = format_gre_tx_trace,
.admin_up_down_function = gre_interface_admin_up_down,
+ .ip_tun_desc = gre_tunnel_desc,
#ifdef SOON
.clear counter = 0;
#endif
diff --git a/src/vnet/interface.c b/src/vnet/interface.c
index 8af2b58ae8a..1702cdc00d1 100644
--- a/src/vnet/interface.c
+++ b/src/vnet/interface.c
@@ -515,6 +515,30 @@ vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index,
VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
}
+void
+vnet_sw_interface_admin_up (vnet_main_t * vnm, u32 sw_if_index)
+{
+ u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+
+ if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
+ {
+ flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
+ vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+ }
+}
+
+void
+vnet_sw_interface_admin_down (vnet_main_t * vnm, u32 sw_if_index)
+{
+ u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+
+ if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+ {
+ flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+ vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+ }
+}
+
static u32
vnet_create_sw_interface_no_callbacks (vnet_main_t * vnm,
vnet_sw_interface_t * template)
diff --git a/src/vnet/interface.h b/src/vnet/interface.h
index 5419fff92a5..72a93269175 100644
--- a/src/vnet/interface.h
+++ b/src/vnet/interface.h
@@ -47,7 +47,7 @@
struct vnet_main_t;
struct vnet_hw_interface_t;
struct vnet_sw_interface_t;
-struct ip46_address_t;
+union ip46_address_t_;
typedef enum
{
@@ -174,6 +174,14 @@ static __clib_unused void * __clib_unused_##f = f;
#define VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION_PRIO(f,p) \
_VNET_INTERFACE_FUNCTION_DECL_PRIO(f,sw_interface_admin_up_down, p)
+/**
+ * Tunnel description parameters
+ */
+typedef int (*vnet_dev_class_ip_tunnel_desc_t) (u32 sw_if_index,
+ union ip46_address_t_ * src,
+ union ip46_address_t_ * dst,
+ u8 * is_l2);
+
/* A class of hardware interface devices. */
typedef struct _vnet_device_class
{
@@ -235,6 +243,8 @@ typedef struct _vnet_device_class
/* Format flow offload entry */
format_function_t *format_flow;
+ vnet_dev_class_ip_tunnel_desc_t ip_tun_desc;
+
/* Function to clear hardware counters for device. */
void (*clear_counters) (u32 dev_class_instance);
diff --git a/src/vnet/interface_funcs.h b/src/vnet/interface_funcs.h
index b862f48ef36..6d404b46098 100644
--- a/src/vnet/interface_funcs.h
+++ b/src/vnet/interface_funcs.h
@@ -356,6 +356,9 @@ clib_error_t *vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index,
clib_error_t *vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index,
vnet_sw_interface_flags_t flags);
+void vnet_sw_interface_admin_up (vnet_main_t * vnm, u32 sw_if_index);
+void vnet_sw_interface_admin_down (vnet_main_t * vnm, u32 sw_if_index);
+
/* Change interface class. */
clib_error_t *vnet_hw_interface_set_class (vnet_main_t * vnm, u32 hw_if_index,
u32 new_hw_class_index);
diff --git a/src/vnet/ip/ip6_packet.h b/src/vnet/ip/ip6_packet.h
index ff47830dff3..c8bc4c817e8 100644
--- a/src/vnet/ip/ip6_packet.h
+++ b/src/vnet/ip/ip6_packet.h
@@ -75,7 +75,7 @@ typedef enum
} ip46_type_t;
/* *INDENT-OFF* */
-typedef CLIB_PACKED (union {
+typedef CLIB_PACKED (union ip46_address_t_ {
struct {
u32 pad[3];
ip4_address_t ip4;
@@ -95,6 +95,21 @@ typedef CLIB_PACKED (union {
&& ((a1)->as_u64[1] == (a2)->as_u64[1]))
#define ip46_address_initializer {{{ 0 }}}
+static_always_inline int
+ip46_address_is_equal_v4 (const ip46_address_t * ip46,
+ const ip4_address_t * ip4)
+{
+ return (ip46->ip4.as_u32 == ip4->as_u32);
+}
+
+static_always_inline int
+ip46_address_is_equal_v6 (const ip46_address_t * ip46,
+ const ip6_address_t * ip6)
+{
+ return ((ip46->ip6.as_u64[0] == ip6->as_u64[0]) &&
+ (ip46->ip6.as_u64[1] == ip6->as_u64[1]));
+}
+
static_always_inline void
ip46_address_copy (ip46_address_t * dst, const ip46_address_t * src)
{
diff --git a/src/vnet/ipip/ipip.c b/src/vnet/ipip/ipip.c
index 5d407084205..66c945e346e 100644
--- a/src/vnet/ipip/ipip.c
+++ b/src/vnet/ipip/ipip.c
@@ -297,6 +297,23 @@ ipip_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
return /* no error */ 0;
}
+static int
+ipip_tunnel_desc (u32 sw_if_index,
+ ip46_address_t * src, ip46_address_t * dst, u8 * is_l2)
+{
+ ipip_tunnel_t *t;
+
+ t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
+ if (!t)
+ return -1;
+
+ *src = t->tunnel_src;
+ *dst = t->tunnel_dst;
+ *is_l2 = 0;
+
+ return (0);
+}
+
/* *INDENT-OFF* */
VNET_DEVICE_CLASS(ipip_device_class) = {
.name = "IPIP tunnel device",
@@ -304,6 +321,7 @@ VNET_DEVICE_CLASS(ipip_device_class) = {
.format_device = format_ipip_device,
.format_tx_trace = format_ipip_tx_trace,
.admin_up_down_function = ipip_interface_admin_up_down,
+ .ip_tun_desc = ipip_tunnel_desc,
#ifdef SOON
.clear counter = 0;
#endif
diff --git a/src/vnet/ipip/ipip_api.c b/src/vnet/ipip/ipip_api.c
index 35b846e5c8b..62a99659eee 100644
--- a/src/vnet/ipip/ipip_api.c
+++ b/src/vnet/ipip/ipip_api.c
@@ -150,7 +150,9 @@ vl_api_ipip_tunnel_dump_t_handler (vl_api_ipip_tunnel_dump_t * mp)
{
/* *INDENT-OFF* */
pool_foreach(t, gm->tunnels,
- ({ send_ipip_tunnel_details(t, reg, mp->context); }));
+ ({
+ send_ipip_tunnel_details(t, reg, mp->context);
+ }));
/* *INDENT-ON* */
}
else
diff --git a/src/vnet/ipsec-gre/dir.dox b/src/vnet/ipsec-gre/dir.dox
deleted file mode 100644
index e6ffd10b01b..00000000000
--- a/src/vnet/ipsec-gre/dir.dox
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- @dir vnet/vnet/ipsec-gre
- @brief L2-GRE over IPSec tunnel interface implementation
-*/
diff --git a/src/vnet/ipsec-gre/error.def b/src/vnet/ipsec-gre/error.def
deleted file mode 100644
index d84e8ed1759..00000000000
--- a/src/vnet/ipsec-gre/error.def
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @file
- * @brief L2-GRE over IPSec errors.
- */
-
-
-ipsec_gre_error (NONE, "no error")
-ipsec_gre_error (UNKNOWN_PROTOCOL, "unknown protocol")
-ipsec_gre_error (UNSUPPORTED_VERSION, "unsupported version")
-ipsec_gre_error (PKTS_DECAP, "GRE input packets decapsulated")
-ipsec_gre_error (PKTS_ENCAP, "GRE output packets encapsulated")
-ipsec_gre_error (NO_SUCH_TUNNEL, "GRE input packets dropped due to missing tunnel")
diff --git a/src/vnet/ipsec-gre/interface.c b/src/vnet/ipsec-gre/interface.c
deleted file mode 100644
index 6a8bb7d8f0b..00000000000
--- a/src/vnet/ipsec-gre/interface.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * gre_interface.c: gre interfaces
- *
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @file
- * @brief L2-GRE over IPSec tunnel interface.
- *
- * Creates ipsec-gre tunnel interface.
- * Provides a command line interface so humans can interact with VPP.
- */
-
-#include <vnet/vnet.h>
-#include <vnet/pg/pg.h>
-#include <vnet/ipsec-gre/ipsec_gre.h>
-#include <vnet/ip/format.h>
-#include <vnet/ipsec/ipsec.h>
-#include <vnet/l2/l2_input.h>
-
-#include <vnet/ipsec/esp.h>
-
-u8 *
-format_ipsec_gre_tunnel (u8 * s, va_list * args)
-{
- ipsec_gre_tunnel_t *t = va_arg (*args, ipsec_gre_tunnel_t *);
- ipsec_gre_main_t *gm = &ipsec_gre_main;
-
- s = format (s,
- "[%d] %U (src) %U (dst) local-sa %d remote-sa %d",
- t - gm->tunnels,
- format_ip4_address, &t->tunnel_src,
- format_ip4_address, &t->tunnel_dst,
- t->local_sa_id, t->remote_sa_id);
- return s;
-}
-
-static clib_error_t *
-show_ipsec_gre_tunnel_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- ipsec_gre_main_t *igm = &ipsec_gre_main;
- ipsec_gre_tunnel_t *t;
-
- if (pool_elts (igm->tunnels) == 0)
- vlib_cli_output (vm, "No IPSec GRE tunnels configured...");
-
- /* *INDENT-OFF* */
- pool_foreach (t, igm->tunnels,
- ({
- vlib_cli_output (vm, "%U", format_ipsec_gre_tunnel, t);
- }));
- /* *INDENT-ON* */
-
- return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (show_ipsec_gre_tunnel_command, static) = {
- .path = "show ipsec gre tunnel",
- .function = show_ipsec_gre_tunnel_command_fn,
-};
-/* *INDENT-ON* */
-
-/* force inclusion from application's main.c */
-clib_error_t *
-ipsec_gre_interface_init (vlib_main_t * vm)
-{
- return 0;
-}
-
-VLIB_INIT_FUNCTION (ipsec_gre_interface_init);
-
-/**
- * @brief Add or delete ipsec-gre tunnel interface.
- *
- * @param *a vnet_ipsec_gre_tunnel_add_del_args_t - tunnel interface parameters
- * @param *sw_if_indexp u32 - software interface index
- * @return int - 0 if success otherwise <code>VNET_API_ERROR_</code>
- */
-int
-vnet_ipsec_gre_tunnel_add_del (const ipsec_gre_tunnel_add_del_args_t * a,
- u32 * sw_if_indexp)
-{
- ipsec_gre_main_t *igm = &ipsec_gre_main;
- vnet_main_t *vnm = igm->vnet_main;
- ipsec_main_t *im = &ipsec_main;
- ipsec_gre_tunnel_t *t;
- vnet_hw_interface_t *hi;
- u32 hw_if_index, sw_if_index;
- u32 slot;
- uword *p;
- u64 key;
-
- key = (u64) a->src.as_u32 << 32 | (u64) a->dst.as_u32;
- p = hash_get (igm->tunnel_by_key, key);
-
- if (a->is_add)
- {
- /* check if same src/dst pair exists */
- if (p)
- return VNET_API_ERROR_INVALID_VALUE;
-
- pool_get_aligned (igm->tunnels, t, CLIB_CACHE_LINE_BYTES);
- clib_memset (t, 0, sizeof (*t));
-
- if (vec_len (igm->free_ipsec_gre_tunnel_hw_if_indices) > 0)
- {
- vnet_interface_main_t *im = &vnm->interface_main;
-
- hw_if_index = igm->free_ipsec_gre_tunnel_hw_if_indices
- [vec_len (igm->free_ipsec_gre_tunnel_hw_if_indices) - 1];
- _vec_len (igm->free_ipsec_gre_tunnel_hw_if_indices) -= 1;
-
- hi = vnet_get_hw_interface (vnm, hw_if_index);
- hi->dev_instance = t - igm->tunnels;
- hi->hw_instance = hi->dev_instance;
-
- /* clear old stats of freed tunnel before reuse */
- sw_if_index = hi->sw_if_index;
- vnet_interface_counter_lock (im);
- vlib_zero_combined_counter
- (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX],
- sw_if_index);
- vlib_zero_combined_counter
- (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX],
- sw_if_index);
- vlib_zero_simple_counter
- (&im->sw_if_counters[VNET_INTERFACE_COUNTER_DROP], sw_if_index);
- vnet_interface_counter_unlock (im);
- }
- else
- {
- hw_if_index = vnet_register_interface
- (vnm, ipsec_gre_device_class.index, t - igm->tunnels,
- ipsec_gre_hw_interface_class.index, t - igm->tunnels);
- hi = vnet_get_hw_interface (vnm, hw_if_index);
- sw_if_index = hi->sw_if_index;
- }
-
- t->hw_if_index = hw_if_index;
- t->sw_if_index = sw_if_index;
- t->local_sa_id = a->local_sa_id;
- t->remote_sa_id = a->remote_sa_id;
- t->local_sa = ipsec_get_sa_index_by_sa_id (t->local_sa_id);
- t->remote_sa = ipsec_get_sa_index_by_sa_id (t->remote_sa_id);
-
- ip4_sw_interface_enable_disable (sw_if_index, 1);
-
- vec_validate_init_empty (igm->tunnel_index_by_sw_if_index,
- sw_if_index, ~0);
- igm->tunnel_index_by_sw_if_index[sw_if_index] = t - igm->tunnels;
-
- hi->min_packet_bytes = 64 + sizeof (gre_header_t) +
- sizeof (ip4_header_t) + sizeof (esp_header_t) + sizeof (esp_footer_t);
-
- /* Standard default gre MTU. */
- /* TODO: Should take tunnel overhead into consideration */
- vnet_sw_interface_set_mtu (vnm, sw_if_index, 9000);
-
- clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
- clib_memcpy (&t->tunnel_dst, &a->dst, sizeof (t->tunnel_dst));
-
- hash_set (igm->tunnel_by_key, key, t - igm->tunnels);
-
- slot = vlib_node_add_next_with_slot
- (vnm->vlib_main, hi->tx_node_index, im->esp4_encrypt_node_index,
- IPSEC_GRE_OUTPUT_NEXT_ESP_ENCRYPT);
-
- ASSERT (slot == IPSEC_GRE_OUTPUT_NEXT_ESP_ENCRYPT);
- }
- else
- { /* !is_add => delete */
- /* tunnel needs to exist */
- if (!p)
- return VNET_API_ERROR_NO_SUCH_ENTRY;
-
- t = pool_elt_at_index (igm->tunnels, p[0]);
-
- sw_if_index = t->sw_if_index;
- ip4_sw_interface_enable_disable (sw_if_index, 0);
- vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
- /* make sure tunnel is removed from l2 bd or xconnect */
- set_int_l2_mode (igm->vlib_main, vnm, MODE_L3, sw_if_index, 0,
- L2_BD_PORT_TYPE_NORMAL, 0, 0);
- vec_add1 (igm->free_ipsec_gre_tunnel_hw_if_indices, t->hw_if_index);
- igm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
-
- hash_unset (igm->tunnel_by_key, key);
- pool_put (igm->tunnels, t);
- }
-
- if (sw_if_indexp)
- *sw_if_indexp = sw_if_index;
-
- return ipsec_add_del_ipsec_gre_tunnel (vnm, a);
-}
-
-static clib_error_t *
-create_ipsec_gre_tunnel_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- u32 num_m_args = 0;
- ipsec_gre_tunnel_add_del_args_t _a, *a = &_a;
- int rv;
- u32 sw_if_index;
- clib_error_t *error = NULL;
-
- clib_memset (a, 0, sizeof (*a));
- a->is_add = 1;
-
- /* Get a line of input. */
- 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, "del"))
- a->is_add = 0;
- else if (unformat (line_input, "src %U", unformat_ip4_address, &a->src))
- num_m_args++;
- else if (unformat (line_input, "dst %U", unformat_ip4_address, &a->dst))
- num_m_args++;
- else if (unformat (line_input, "local-sa %d", &a->local_sa_id))
- num_m_args++;
- else if (unformat (line_input, "remote-sa %d", &a->remote_sa_id))
- num_m_args++;
- else
- {
- error = clib_error_return (0, "unknown input `%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- if (num_m_args < 4)
- {
- error = clib_error_return (0, "mandatory argument(s) missing");
- goto done;
- }
-
- if (memcmp (&a->src, &a->dst, sizeof (a->src)) == 0)
- {
- error = clib_error_return (0, "src and dst are identical");
- goto done;
- }
-
- rv = vnet_ipsec_gre_tunnel_add_del (a, &sw_if_index);
-
- switch (rv)
- {
- case 0:
- vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
- vnet_get_main (), sw_if_index);
- break;
- case VNET_API_ERROR_INVALID_VALUE:
- error = clib_error_return (0, "GRE tunnel already exists...");
- goto done;
- default:
- error = clib_error_return (0,
- "vnet_ipsec_gre_tunnel_add_del returned %d",
- rv);
- goto done;
- }
-
-done:
- unformat_free (line_input);
-
- return error;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (create_ipsec_gre_tunnel_command, static) = {
- .path = "create ipsec gre tunnel",
- .short_help = "create ipsec gre tunnel src <addr> dst <addr> "
- "local-sa <id> remote-sa <id> [del]",
- .function = create_ipsec_gre_tunnel_command_fn,
-};
-/* *INDENT-ON* */
-
-/*
-* fd.io coding-style-patch-verification: ON
-*
-* Local Variables:
-* eval: (c-set-style "gnu")
-* End:
-*/
diff --git a/src/vnet/ipsec-gre/ipsec_gre.api b/src/vnet/ipsec-gre/ipsec_gre.api
deleted file mode 100644
index b4950097f61..00000000000
--- a/src/vnet/ipsec-gre/ipsec_gre.api
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2015-2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-option version = "1.1.0";
-
-import "vnet/ip/ip_types.api";
-
-/** \brief Add / del ipsec gre tunnel request
- @param client_index - opaque cookie to identify the sender
- @param context - sender context, to match reply w/ request
- @param local_sa_id - local/output SA id
- @param remote_sa_id - remote/input SA id
- @param is_add - 1 if adding the tunnel, 0 if deleting
- @param sw_if_index - software index of the ipsec gre tunnel
- ignored on create. set in dump/details
- @param src - tunnel source address
- @param dst - tunnel destination address
-*/
-typedef ipsec_gre_tunnel {
- u32 client_index;
- u32 context;
- u32 local_sa_id;
- u32 remote_sa_id;
- u8 is_add;
- u32 sw_if_index;
- vl_api_ip4_address_t src;
- vl_api_ip4_address_t dst;
-};
-
-define ipsec_gre_tunnel_add_del {
- u32 client_index;
- u32 context;
- u8 is_add;
- vl_api_ipsec_gre_tunnel_t tunnel;
-};
-
-/** \brief Reply for add / del ipsec gre tunnel request
- @param context - returned sender context, to match reply w/ request
- @param retval - return code
- @param sw_if_index - software index of the new ipsec gre tunnel
-*/
-define ipsec_gre_tunnel_add_del_reply {
- u32 context;
- i32 retval;
- u32 sw_if_index;
-};
-
-/** \brief Dump ipsec gre tunnel table
- @param client_index - opaque cookie to identify the sender
- @param context - sender context, to match reply w/ request
- @param tunnel_index - gre tunnel identifier or -1 in case of all tunnels
-*/
-define ipsec_gre_tunnel_dump {
- u32 client_index;
- u32 context;
- u32 sw_if_index;
-};
-
-/** \brief ipsec gre tunnel operational state response
- @param context - returned sender context, to match reply w/ request
- @param local_sa_id - local SA id
- @param remote_sa_id - remote SA id
- @param src_address - tunnel source address
- @param dst_address - tunnel destination address
-*/
-define ipsec_gre_tunnel_details {
- u32 context;
- vl_api_ipsec_gre_tunnel_t tunnel;
-};
-
-/*
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
-
diff --git a/src/vnet/ipsec-gre/ipsec_gre.c b/src/vnet/ipsec-gre/ipsec_gre.c
deleted file mode 100644
index cdb23dd9deb..00000000000
--- a/src/vnet/ipsec-gre/ipsec_gre.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @file
- * @brief L2-GRE over IPSec packet processing.
- *
- * Add GRE header to thr packet and send it to the esp-encrypt node.
-*/
-
-#include <vnet/vnet.h>
-#include <vnet/ipsec-gre/ipsec_gre.h>
-
-extern ipsec_gre_main_t ipsec_gre_main;
-
-#ifndef CLIB_MARCH_VARIANT
-ipsec_gre_main_t ipsec_gre_main;
-#endif /* CLIB_MARCH_VARIANT */
-
-/**
- * @brief IPv4 and GRE header union.
- *
-*/
-typedef struct
-{
- union
- {
- ip4_and_gre_header_t ip4_and_gre;
- u64 as_u64[3];
- };
-} ip4_and_gre_union_t;
-
-/**
- * @brief Packet trace.
- *
-*/
-typedef struct
-{
- u32 tunnel_id; /**< Tunnel-id / index in tunnel vector */
-
- u32 length; /**< pkt length */
-
- ip4_address_t src; /**< tunnel src IPv4 address */
- ip4_address_t dst; /**< tunnel dst IPv4 address */
-
- u32 sa_id; /**< tunnel IPSec SA id */
-} ipsec_gre_tx_trace_t;
-
-static u8 *
-format_ipsec_gre_tx_trace (u8 * s, va_list * args)
-{
- CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
- CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
- ipsec_gre_tx_trace_t *t = va_arg (*args, ipsec_gre_tx_trace_t *);
-
- s = format (s, "GRE: tunnel %d len %d src %U dst %U sa-id %d",
- t->tunnel_id, clib_net_to_host_u16 (t->length),
- format_ip4_address, &t->src.as_u8,
- format_ip4_address, &t->dst.as_u8, t->sa_id);
- return s;
-}
-
-/**
- * @brief IPSec-GRE tunnel interface tx function.
- *
- * Add GRE header to the packet.
- *
- * @param vm vlib_main_t corresponding to the current thread.
- * @param node vlib_node_runtime_t data for this node.
- * @param frame vlib_frame_t whose contents should be dispatched.
- *
- * @par Graph mechanics: buffer metadata, next index usage
- *
- * <em>Uses:</em>
- * - <code>node->runtime_data</code>
- * - Match tunnel by <code>rd->dev_instance</code> in IPSec-GRE tunnels
- * pool.
- *
- * <em>Sets:</em>
- * - <code>vnet_buffer(b)->output_features.ipsec_sad_index</code>
- * - Set IPSec Security Association for packet encryption.
- * - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
- * - Reset output sw_if_index.
- *
- * <em>Next Index:</em>
- * - Dispatches the packet to the esp-encrypt node.
-*/
-VNET_DEVICE_CLASS_TX_FN (ipsec_gre_device_class) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
-{
- ipsec_gre_main_t *igm = &ipsec_gre_main;
- u32 next_index;
- u32 *from, *to_next, n_left_from, n_left_to_next;
- vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
- ipsec_gre_tunnel_t *t = pool_elt_at_index (igm->tunnels, rd->dev_instance);
-
- u16 l2_gre_protocol_ethertype = clib_net_to_host_u16 (GRE_PROTOCOL_teb);
-
- /* Vector of buffer / pkt indices we're supposed to process */
- from = vlib_frame_vector_args (frame);
-
- /* Number of buffers / pkts */
- n_left_from = frame->n_vectors;
-
- /* Speculatively send the first buffer to the last disposition we used */
- next_index = node->cached_next_index;
-
- while (n_left_from > 0)
- {
- /* set up to enqueue to our disposition with index = next_index */
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
- /*
- * As long as we have enough pkts left to process two pkts
- * and prefetch two pkts...
- */
- while (n_left_from >= 4 && n_left_to_next >= 2)
- {
- vlib_buffer_t *b0, *b1;
- ip4_header_t *ip0, *ip1;
- ip4_and_gre_union_t *h0, *h1;
- u32 bi0, next0, bi1, next1;
- __attribute__ ((unused)) u8 error0, error1;
-
- /* Prefetch the next iteration */
- {
- vlib_buffer_t *p2, *p3;
-
- p2 = vlib_get_buffer (vm, from[2]);
- p3 = vlib_get_buffer (vm, from[3]);
-
- vlib_prefetch_buffer_header (p2, LOAD);
- vlib_prefetch_buffer_header (p3, LOAD);
-
- /*
- * Prefetch packet data. We expect to overwrite
- * the inbound L2 header with an ip header and a
- * gre header. Might want to prefetch the last line
- * of rewrite space as well; need profile data
- */
- CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
- CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
- }
-
- /* Pick up the next two buffer indices */
- bi0 = from[0];
- bi1 = from[1];
-
- /* Speculatively enqueue them where we sent the last buffer */
- to_next[0] = bi0;
- to_next[1] = bi1;
- from += 2;
- to_next += 2;
- n_left_to_next -= 2;
- n_left_from -= 2;
-
- b0 = vlib_get_buffer (vm, bi0);
- b1 = vlib_get_buffer (vm, bi1);
-
- vlib_buffer_advance (b0, -sizeof (*h0));
- vlib_buffer_advance (b1, -sizeof (*h1));
-
- h0 = vlib_buffer_get_current (b0);
- h1 = vlib_buffer_get_current (b1);
- h0->as_u64[0] = 0;
- h0->as_u64[1] = 0;
- h0->as_u64[2] = 0;
-
- h1->as_u64[0] = 0;
- h1->as_u64[1] = 0;
- h1->as_u64[2] = 0;
-
- ip0 = &h0->ip4_and_gre.ip4;
- h0->ip4_and_gre.gre.protocol = l2_gre_protocol_ethertype;
- ip0->ip_version_and_header_length = 0x45;
- ip0->ttl = 254;
- ip0->protocol = IP_PROTOCOL_GRE;
-
- ip1 = &h1->ip4_and_gre.ip4;
- h1->ip4_and_gre.gre.protocol = l2_gre_protocol_ethertype;
- ip1->ip_version_and_header_length = 0x45;
- ip1->ttl = 254;
- ip1->protocol = IP_PROTOCOL_GRE;
-
- ip0->length =
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
- ip1->length =
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
- ip0->src_address.as_u32 = t->tunnel_src.as_u32;
- ip1->src_address.as_u32 = t->tunnel_src.as_u32;
- ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
- ip1->dst_address.as_u32 = t->tunnel_dst.as_u32;
- ip0->checksum = ip4_header_checksum (ip0);
- ip1->checksum = ip4_header_checksum (ip1);
-
- vnet_buffer (b0)->sw_if_index[VLIB_RX] =
- vnet_buffer (b0)->sw_if_index[VLIB_TX];
- vnet_buffer (b1)->sw_if_index[VLIB_RX] =
- vnet_buffer (b1)->sw_if_index[VLIB_TX];
-
- vnet_buffer (b0)->ipsec.sad_index = t->local_sa;
- vnet_buffer (b1)->ipsec.sad_index = t->local_sa;
-
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
- vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
-
- next0 = IPSEC_GRE_OUTPUT_NEXT_ESP_ENCRYPT;
- next1 = IPSEC_GRE_OUTPUT_NEXT_ESP_ENCRYPT;
- error0 = IPSEC_GRE_ERROR_NONE;
- error1 = IPSEC_GRE_ERROR_NONE;
-
- if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- ipsec_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
- b0, sizeof (*tr));
- tr->tunnel_id = t - igm->tunnels;
- tr->length = ip0->length;
- tr->src.as_u32 = ip0->src_address.as_u32;
- tr->dst.as_u32 = ip0->dst_address.as_u32;
- tr->sa_id = t->local_sa_id;
- }
-
- if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
- {
- ipsec_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
- b1, sizeof (*tr));
- tr->tunnel_id = t - igm->tunnels;
- tr->length = ip1->length;
- tr->src.as_u32 = ip1->src_address.as_u32;
- tr->dst.as_u32 = ip1->dst_address.as_u32;
- tr->sa_id = t->local_sa_id;
- }
-
- vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, bi1, next0, next1);
- }
-
- while (n_left_from > 0 && n_left_to_next > 0)
- {
- vlib_buffer_t *b0;
- ip4_header_t *ip0;
- ip4_and_gre_union_t *h0;
- u32 bi0, next0;
- __attribute__ ((unused)) u8 error0;
-
- bi0 = to_next[0] = from[0];
- from += 1;
- n_left_from -= 1;
- to_next += 1;
- n_left_to_next -= 1;
-
- b0 = vlib_get_buffer (vm, bi0);
-
- vlib_buffer_advance (b0, -sizeof (*h0));
-
- h0 = vlib_buffer_get_current (b0);
- h0->as_u64[0] = 0;
- h0->as_u64[1] = 0;
- h0->as_u64[2] = 0;
-
- ip0 = &h0->ip4_and_gre.ip4;
- h0->ip4_and_gre.gre.protocol = l2_gre_protocol_ethertype;
- ip0->ip_version_and_header_length = 0x45;
- ip0->ttl = 254;
- ip0->protocol = IP_PROTOCOL_GRE;
- ip0->length =
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
- ip0->src_address.as_u32 = t->tunnel_src.as_u32;
- ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
- ip0->checksum = ip4_header_checksum (ip0);
-
- vnet_buffer (b0)->sw_if_index[VLIB_RX] =
- vnet_buffer (b0)->sw_if_index[VLIB_TX];
- vnet_buffer (b0)->ipsec.sad_index = t->local_sa;
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
-
- next0 = IPSEC_GRE_OUTPUT_NEXT_ESP_ENCRYPT;
- error0 = IPSEC_GRE_ERROR_NONE;
-
- if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- ipsec_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
- b0, sizeof (*tr));
- tr->tunnel_id = t - igm->tunnels;
- tr->length = ip0->length;
- tr->src.as_u32 = ip0->src_address.as_u32;
- tr->dst.as_u32 = ip0->dst_address.as_u32;
- tr->sa_id = t->local_sa_id;
- }
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, next0);
- }
-
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
-
- vlib_node_increment_counter (vm, ipsec_gre_input_node.index,
- IPSEC_GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
-
- return frame->n_vectors;
-}
-
-static clib_error_t *
-ipsec_gre_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
- u32 flags)
-{
- if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
- vnet_hw_interface_set_flags (vnm, hw_if_index,
- VNET_HW_INTERFACE_FLAG_LINK_UP);
- else
- vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
-
- return /* no error */ 0;
-}
-
-static u8 *
-format_ipsec_gre_tunnel_name (u8 * s, va_list * args)
-{
- u32 dev_instance = va_arg (*args, u32);
- return format (s, "ipsec-gre%d", dev_instance);
-}
-
-static u8 *
-format_ipsec_gre_device (u8 * s, va_list * args)
-{
- u32 dev_instance = va_arg (*args, u32);
- CLIB_UNUSED (int verbose) = va_arg (*args, int);
-
- s = format (s, "IPSEC-GRE tunnel: id %d\n", dev_instance);
- return s;
-}
-
-/* *INDENT-OFF* */
-VNET_DEVICE_CLASS (ipsec_gre_device_class) = {
- .name = "IPSec GRE tunnel device",
- .format_device_name = format_ipsec_gre_tunnel_name,
- .format_device = format_ipsec_gre_device,
- .format_tx_trace = format_ipsec_gre_tx_trace,
- .admin_up_down_function = ipsec_gre_interface_admin_up_down,
-};
-
-
-#ifndef CLIB_MARCH_VARIANT
-VNET_HW_INTERFACE_CLASS (ipsec_gre_hw_interface_class) = {
- .name = "IPSEC-GRE",
-};
-#endif /* CLIB_MARCH_VARIANT */
-/* *INDENT-ON* */
-
-static clib_error_t *
-ipsec_gre_init (vlib_main_t * vm)
-{
- ipsec_gre_main_t *igm = &ipsec_gre_main;
- clib_error_t *error;
-
- clib_memset (igm, 0, sizeof (igm[0]));
- igm->vlib_main = vm;
- igm->vnet_main = vnet_get_main ();
-
- if ((error = vlib_call_init_function (vm, ip_main_init)))
- return error;
-
- if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
- return error;
-
- igm->tunnel_by_key = hash_create (0, sizeof (uword));
-
- return vlib_call_init_function (vm, ipsec_gre_input_init);
-}
-
-VLIB_INIT_FUNCTION (ipsec_gre_init);
-
-/*
-* fd.io coding-style-patch-verification: ON
-*
-* Local Variables:
-* eval: (c-set-style "gnu")
-* End:
-*/
diff --git a/src/vnet/ipsec-gre/ipsec_gre.h b/src/vnet/ipsec-gre/ipsec_gre.h
deleted file mode 100644
index 730cd717795..00000000000
--- a/src/vnet/ipsec-gre/ipsec_gre.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @file
- * @brief L2-GRE over IPSec packet processing.
-*/
-
-#ifndef included_ipsec_gre_h
-#define included_ipsec_gre_h
-
-#include <vnet/vnet.h>
-#include <vnet/gre/packet.h>
-#include <vnet/gre/gre.h>
-#include <vnet/ip/ip.h>
-#include <vnet/ip/ip4.h>
-#include <vnet/ip/ip4_packet.h>
-#include <vnet/pg/pg.h>
-#include <vnet/ip/format.h>
-#include <vnet/ipsec/ipsec.h>
-#include <vnet/ipsec/ipsec_if.h>
-
-extern vnet_hw_interface_class_t ipsec_gre_hw_interface_class;
-
-/**
- * @brief IPSec-GRE errors.
- *
-*/
-typedef enum
-{
-#define ipsec_gre_error(n,s) IPSEC_GRE_ERROR_##n,
-#include <vnet/ipsec-gre/error.def>
-#undef ipsec_gre_error
- IPSEC_GRE_N_ERROR,
-} ipsec_gre_error_t;
-
-/**
- * @brief IPSec-GRE tunnel parameters.
- *
-*/
-typedef struct
-{
- /* Required for pool_get_aligned */
- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
- ip4_address_t tunnel_src; /**< tunnel IPv4 src address */
- ip4_address_t tunnel_dst; /**< tunnel IPv4 dst address */
- u32 local_sa; /**< local IPSec SA index */
- u32 remote_sa; /**< remote IPSec SA index */
- u32 local_sa_id; /**< local IPSec SA id */
- u32 remote_sa_id; /**< remote IPSec SA id */
- u32 hw_if_index;; /**< hardware interface index */
- u32 sw_if_index;; /**< software interface index */
-} ipsec_gre_tunnel_t;
-
-/**
- * @brief IPSec-GRE state.
- *
-*/
-typedef struct
-{
- ipsec_gre_tunnel_t *tunnels; /**< pool of tunnel instances */
-
- uword *tunnel_by_key; /**< hash mapping src/dst addr pair to tunnel */
-
- u32 *free_ipsec_gre_tunnel_hw_if_indices; /**< free vlib hw_if_indices */
-
- u32 *tunnel_index_by_sw_if_index; /**< mapping from sw_if_index to tunnel
- index */
-
- vlib_main_t *vlib_main; /**< convenience */
- vnet_main_t *vnet_main; /**< convenience */
-} ipsec_gre_main_t;
-
-extern ipsec_gre_main_t ipsec_gre_main;
-
-extern vlib_node_registration_t ipsec_gre_input_node;
-extern vnet_device_class_t ipsec_gre_device_class;
-
-/* manually added to the interface output node in ipsec_gre.c */
-#define IPSEC_GRE_OUTPUT_NEXT_ESP_ENCRYPT 0
-
-extern int vnet_ipsec_gre_tunnel_add_del (const
- ipsec_gre_tunnel_add_del_args_t * a,
- u32 * sw_if_indexp);
-
-#endif /* included_ipsec_gre_h */
-
-/*
-* fd.io coding-style-patch-verification: ON
-*
-* Local Variables:
-* eval: (c-set-style "gnu")
-* End:
-*/
diff --git a/src/vnet/ipsec-gre/ipsec_gre_api.c b/src/vnet/ipsec-gre/ipsec_gre_api.c
deleted file mode 100644
index 9e5d615f977..00000000000
--- a/src/vnet/ipsec-gre/ipsec_gre_api.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- *------------------------------------------------------------------
- * ipsec_gre_api.c - ipsec_gre api
- *
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *------------------------------------------------------------------
- */
-
-#include <vnet/vnet.h>
-#include <vlibmemory/api.h>
-
-#include <vnet/interface.h>
-#include <vnet/api_errno.h>
-#include <vnet/ipsec-gre/ipsec_gre.h>
-#include <vnet/ip/ip_types_api.h>
-
-#include <vnet/vnet_msg_enum.h>
-
-#define vl_typedefs /* define message structures */
-#include <vnet/vnet_all_api_h.h>
-#undef vl_typedefs
-
-#define vl_endianfun /* define message structures */
-#include <vnet/vnet_all_api_h.h>
-#undef vl_endianfun
-
-/* instantiate all the print functions we know about */
-#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
-#define vl_printfun
-#include <vnet/vnet_all_api_h.h>
-#undef vl_printfun
-
-#include <vlibapi/api_helper_macros.h>
-
-#define foreach_vpe_api_msg \
-_(IPSEC_GRE_TUNNEL_ADD_DEL, ipsec_gre_tunnel_add_del) \
-_(IPSEC_GRE_TUNNEL_DUMP, ipsec_gre_tunnel_dump)
-
-static void
-vl_api_ipsec_gre_tunnel_add_del_t_handler (vl_api_ipsec_gre_tunnel_add_del_t *
- mp)
-{
- vl_api_ipsec_gre_tunnel_add_del_reply_t *rmp;
- int rv = 0;
- ipsec_gre_tunnel_add_del_args_t _a, *a = &_a;
- u32 sw_if_index = ~0;
-
- clib_memset (a, 0, sizeof (*a));
-
- ip4_address_decode (mp->tunnel.src, &a->src);
- ip4_address_decode (mp->tunnel.dst, &a->dst);
-
- /* Check src & dst are different */
- if (a->src.as_u32 == a->dst.as_u32)
- {
- rv = VNET_API_ERROR_SAME_SRC_DST;
- goto out;
- }
-
- a->is_add = mp->is_add;
- a->local_sa_id = ntohl (mp->tunnel.local_sa_id);
- a->remote_sa_id = ntohl (mp->tunnel.remote_sa_id);
-
- rv = vnet_ipsec_gre_tunnel_add_del (a, &sw_if_index);
-
-out:
- /* *INDENT-OFF* */
- REPLY_MACRO2(VL_API_IPSEC_GRE_TUNNEL_ADD_DEL_REPLY,
- ({
- rmp->sw_if_index = ntohl (sw_if_index);
- }));
- /* *INDENT-ON* */
-}
-
-static void send_ipsec_gre_tunnel_details
- (ipsec_gre_tunnel_t * t, vl_api_registration_t * reg, u32 context)
-{
- vl_api_ipsec_gre_tunnel_details_t *rmp;
-
- rmp = vl_msg_api_alloc (sizeof (*rmp));
- clib_memset (rmp, 0, sizeof (*rmp));
- rmp->_vl_msg_id = ntohs (VL_API_IPSEC_GRE_TUNNEL_DETAILS);
-
- ip4_address_encode (&t->tunnel_src, rmp->tunnel.src);
- ip4_address_encode (&t->tunnel_dst, rmp->tunnel.dst);
- rmp->tunnel.sw_if_index = htonl (t->sw_if_index);
- rmp->tunnel.local_sa_id = htonl (t->local_sa_id);
- rmp->tunnel.remote_sa_id = htonl (t->remote_sa_id);
- rmp->context = context;
-
- vl_api_send_msg (reg, (u8 *) rmp);
-}
-
-static void vl_api_ipsec_gre_tunnel_dump_t_handler
- (vl_api_ipsec_gre_tunnel_dump_t * mp)
-{
- vl_api_registration_t *reg;
- ipsec_gre_main_t *igm = &ipsec_gre_main;
- ipsec_gre_tunnel_t *t;
- u32 sw_if_index;
-
- reg = vl_api_client_index_to_registration (mp->client_index);
- if (!reg)
- return;
-
- sw_if_index = ntohl (mp->sw_if_index);
-
- if (~0 == sw_if_index)
- {
- /* *INDENT-OFF* */
- pool_foreach (t, igm->tunnels,
- ({
- send_ipsec_gre_tunnel_details(t, reg, mp->context);
- }));
- /* *INDENT-ON* */
- }
- else
- {
- if ((sw_if_index >= vec_len (igm->tunnel_index_by_sw_if_index)) ||
- (~0 == igm->tunnel_index_by_sw_if_index[sw_if_index]))
- {
- return;
- }
- t = &igm->tunnels[igm->tunnel_index_by_sw_if_index[sw_if_index]];
- send_ipsec_gre_tunnel_details (t, reg, mp->context);
- }
-}
-
-/*
- * ipsec_gre_api_hookup
- * Add vpe's API message handlers to the table.
- * vlib has already mapped shared memory and
- * added the client registration handlers.
- * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
- */
-#define vl_msg_name_crc_list
-#include <vnet/vnet_all_api_h.h>
-#undef vl_msg_name_crc_list
-
-static void
-setup_message_id_table (api_main_t * am)
-{
-#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
- foreach_vl_msg_name_crc_ipsec_gre;
-#undef _
-}
-
-static clib_error_t *
-ipsec_gre_api_hookup (vlib_main_t * vm)
-{
- api_main_t *am = &api_main;
-
-#define _(N,n) \
- vl_msg_api_set_handlers(VL_API_##N, #n, \
- vl_api_##n##_t_handler, \
- vl_noop_handler, \
- vl_api_##n##_t_endian, \
- vl_api_##n##_t_print, \
- sizeof(vl_api_##n##_t), 1);
- foreach_vpe_api_msg;
-#undef _
-
- /*
- * Set up the (msg_name, crc, message-id) table
- */
- setup_message_id_table (am);
-
- return 0;
-}
-
-VLIB_API_INIT_FUNCTION (ipsec_gre_api_hookup);
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/vnet/ipsec-gre/ipsec_gre_doc.md b/src/vnet/ipsec-gre/ipsec_gre_doc.md
deleted file mode 100644
index e1bb9cdab1a..00000000000
--- a/src/vnet/ipsec-gre/ipsec_gre_doc.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# VPP L2-GRE over IPsec implementation {#ipsec_gre_doc}
-
-This is a memo intended to contain documentation of the VPP L2-GRE over IPsec implementation.
-Everything that is not directly obvious should come here.
-
-
-## L2-GRE over IPsec
-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.
-
-There are 2 dedicated nodes for encapsulation:
-* ipsec-gre<n>-tx - add GRE header
-* esp-encrypt - encrypt GRE packet to ESP packet
-
-There are 3 dedicated nodes for decapsulation:
-* ipsec-if-input - match IPSec SA by source IP address and SPI in ESP packet
-* esp-decrypt - decrypt ESP packet
-* ipsec-gre-input - remove GRE header
-
-
-### Configuration
-
-L2-GRE over IPsec support the following CLI configuration command:
- create ipsec gre tunnel src <addr> dst <addr> local-sa <id> remote-sa <id> [del]
-
-src: tunnel source IPv4 address
-dst: tunnel destination IPv4 address
-local-sa: tunnel local IPSec Security Association
-remote-sa: tunnel remote IPSec Security Association
-del: delete IPSec-GRE tunnel
-
-L2-GRE over IPsec support the following API configuration command:
- ipsec_gre_add_del_tunnel src <addr> dst <addr> local_sa <sa-id> remote_sa <sa-id> [del]
-
-src: tunnel source IPv4 address
-dst: tunnel destination IPv4 address
-local_sa: tunnel local IPSec Security Association
-remote_sa: tunnel remote IPSec Security Association
-del: delete IPSec-GRE tunnel
-
-
-### Configuration example
-
-Interface GigabitEthernet0/9/0 is in bridge with ipsec-gre0 tunnel interface, interface GigabitEthernet0/8/0 sending encapsulated and encrypted traffic.
-
-Configure IPv4 address on sending interface:
-set int ip address GigabitEthernet0/8/0 192.168.1.1/24
-
-Configure IPSec Security Associations:
-ipsec sa add 10 spi 1001 esp crypto-key 4a506a794f574265564551694d653768 crypto-alg aes-cbc-128 integ-key 4339314b55523947594d6d3547666b45764e6a58 integ-alg sha1-96
-ipsec sa add 20 spi 1000 esp crypto-key 49517065716d6235726c734a4372466c crypto-alg aes-cbc-128 integ-key 307439636a5542735133595835546f68534e4f64 integ-alg sha1-96
-
-Create IPSec-GRE tunnel:
-create ipsec gre tunnel src 192.168.1.1 dst 192.168.1.2 local-sa 10 remote-sa 20
-
-Set interfaces state:
-set int state GigabitEthernet0/8/0 up
-set int state GigabitEthernet0/9/0 up
-set int state ipsec-gre0 up
-
-Bridge physical interface with IPSec-GRE tunnel interface:
-set interface l2 bridge GigabitEthernet0/9/0 1
-set interface l2 bridge ipsec-gre0 1
-
-
-### Operational data
-
-L2-GRE over IPsec support the following CLI show command:
- show ipsec gre tunnel
-
-L2-GRE over IPsec support the following API dump command:
- ipsec_gre_tunnel_dump [sw_if_index <nn>]
-
-sw_if_index: software interface index of the IPSec-GRE tunnel interface
-
diff --git a/src/vnet/ipsec-gre/node.c b/src/vnet/ipsec-gre/node.c
deleted file mode 100644
index 6a3aaa12e8c..00000000000
--- a/src/vnet/ipsec-gre/node.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @file
- * @brief L2-GRE over IPSec packet processing.
- *
- * Removes GRE header from the packet and sends it to the l2-input node.
-*/
-
-#include <vlib/vlib.h>
-#include <vnet/pg/pg.h>
-#include <vnet/ipsec-gre/ipsec_gre.h>
-#include <vppinfra/sparse_vec.h>
-
-#define foreach_ipsec_gre_input_next \
-_(PUNT, "error-punt") \
-_(DROP, "error-drop") \
-_(L2_INPUT, "l2-input")
-
-typedef enum {
-#define _(s,n) IPSEC_GRE_INPUT_NEXT_##s,
- foreach_ipsec_gre_input_next
-#undef _
- IPSEC_GRE_INPUT_N_NEXT,
-} ipsec_gre_input_next_t;
-
-typedef struct {
- u32 tunnel_id;
- u32 length;
- ip4_address_t src;
- ip4_address_t dst;
-} ipsec_gre_rx_trace_t;
-
-static u8 * format_ipsec_gre_rx_trace (u8 * s, va_list * args)
-{
- CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
- CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
- ipsec_gre_rx_trace_t * t = va_arg (*args, ipsec_gre_rx_trace_t *);
-
- s = format (s, "GRE: tunnel %d len %d src %U dst %U",
- t->tunnel_id, clib_net_to_host_u16(t->length),
- format_ip4_address, &t->src.as_u8,
- format_ip4_address, &t->dst.as_u8);
- return s;
-}
-
-/**
- * @brief L2-GRE over IPSec input node.
- * @node ipsec-gre-input
- *
- * This node remove GRE header.
- *
- * @param vm vlib_main_t corresponding to the current thread.
- * @param node vlib_node_runtime_t data for this node.
- * @param from_frame vlib_frame_t whose contents should be dispatched.
- *
- * @par Graph mechanics: buffer metadata, next index usage
- *
- * <em>Uses:</em>
- * - <code>ip->src_address</code> and <code>ip->dst_address</code>
- * - Match tunnel by source and destination addresses in GRE IP header.
- *
- * <em>Sets:</em>
- * - <code>vnet_buffer(b)->gre.src</code>
- * - Save tunnel source IPv4 address.
- * - <code>vnet_buffer(b)->gre.dst</code>
- * - Save tunnel destination IPv4 address.
- * - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
- * - Set input sw_if_index to IPSec-GRE tunnel for learning.
- *
- * <em>Next Index:</em>
- * - Dispatches the packet to the l2-input node.
-*/
-VLIB_NODE_FN (ipsec_gre_input_node) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * from_frame)
-{
- ipsec_gre_main_t * igm = &ipsec_gre_main;
- u32 n_left_from, next_index, * from, * to_next;
- u64 cached_tunnel_key = (u64) ~0;
- u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index;
- u32 tun_src0, tun_dst0;
- u32 tun_src1, tun_dst1;
-
- from = vlib_frame_vector_args (from_frame);
- n_left_from = from_frame->n_vectors;
-
- next_index = node->cached_next_index;
-
- while (n_left_from > 0)
- {
- u32 n_left_to_next;
-
- vlib_get_next_frame (vm, node, next_index,
- to_next, n_left_to_next);
-
- while (n_left_from >= 4 && n_left_to_next >= 2)
- {
- u32 bi0, bi1;
- vlib_buffer_t * b0, * b1;
- gre_header_t * h0, * h1;
- u16 version0, version1, protocol0, protocol1;
- int verr0, verr1;
- u32 next0, next1;
- ip4_header_t *ip0, *ip1;
-
- /* Prefetch next iteration. */
- {
- vlib_buffer_t * p2, * p3;
-
- p2 = vlib_get_buffer (vm, from[2]);
- p3 = vlib_get_buffer (vm, from[3]);
-
- vlib_prefetch_buffer_header (p2, LOAD);
- vlib_prefetch_buffer_header (p3, LOAD);
-
- CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
- CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
- }
-
- bi0 = from[0];
- bi1 = from[1];
- to_next[0] = bi0;
- to_next[1] = bi1;
- from += 2;
- to_next += 2;
- n_left_to_next -= 2;
- n_left_from -= 2;
-
- b0 = vlib_get_buffer (vm, bi0);
- b1 = vlib_get_buffer (vm, bi1);
-
- /* ip4_local hands us the ip header, not the gre header */
- ip0 = vlib_buffer_get_current (b0);
- ip1 = vlib_buffer_get_current (b1);
-
- /* Save src + dst ip4 address */
- tun_src0 = ip0->src_address.as_u32;
- tun_dst0 = ip0->dst_address.as_u32;
- tun_src1 = ip1->src_address.as_u32;
- tun_dst1 = ip1->dst_address.as_u32;
-
- vlib_buffer_advance (b0, sizeof (*ip0));
- vlib_buffer_advance (b1, sizeof (*ip1));
-
- h0 = vlib_buffer_get_current (b0);
- h1 = vlib_buffer_get_current (b1);
-
- protocol0 = clib_net_to_host_u16 (h0->protocol);
- protocol1 = clib_net_to_host_u16 (h1->protocol);
- if (PREDICT_TRUE(protocol0 == GRE_PROTOCOL_teb))
- {
- next0 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
- b0->error = node->errors[IPSEC_GRE_ERROR_NONE];
- }
- else
- {
- b0->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
- next0 = IPSEC_GRE_INPUT_NEXT_DROP;
- }
- if (PREDICT_TRUE(protocol1 == GRE_PROTOCOL_teb))
- {
- next1 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
- b1->error = node->errors[IPSEC_GRE_ERROR_NONE];
- }
- else
- {
- b1->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
- next1 = IPSEC_GRE_INPUT_NEXT_DROP;
- }
-
- version0 = clib_net_to_host_u16 (h0->flags_and_version);
- verr0 = version0 & GRE_VERSION_MASK;
- version1 = clib_net_to_host_u16 (h1->flags_and_version);
- verr1 = version1 & GRE_VERSION_MASK;
-
- b0->error = verr0 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
- : b0->error;
- next0 = verr0 ? IPSEC_GRE_INPUT_NEXT_DROP : next0;
- b1->error = verr1 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
- : b1->error;
- next1 = verr1 ? IPSEC_GRE_INPUT_NEXT_DROP : next1;
-
- /* For L2 payload set input sw_if_index to GRE tunnel for learning */
- if (PREDICT_TRUE(next0 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
- {
- u64 key = ((u64)(tun_dst0) << 32) | (u64)(tun_src0);
-
- if (cached_tunnel_key != key)
- {
- vnet_hw_interface_t * hi;
- ipsec_gre_tunnel_t * t;
- uword * p;
-
- p = hash_get (igm->tunnel_by_key, key);
- if (!p)
- {
- next0 = IPSEC_GRE_INPUT_NEXT_DROP;
- b0->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
- goto drop0;
- }
- t = pool_elt_at_index (igm->tunnels, p[0]);
- hi = vnet_get_hw_interface (igm->vnet_main,
- t->hw_if_index);
- tunnel_sw_if_index = hi->sw_if_index;
- cached_tunnel_sw_if_index = tunnel_sw_if_index;
- }
- else
- {
- tunnel_sw_if_index = cached_tunnel_sw_if_index;
- }
- vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
- }
-
-drop0:
- /* For L2 payload set input sw_if_index to GRE tunnel for learning */
- if (PREDICT_TRUE(next1 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
- {
- u64 key = ((u64)(tun_dst1) << 32) | (u64)(tun_src1);
-
- if (cached_tunnel_key != key)
- {
- vnet_hw_interface_t * hi;
- ipsec_gre_tunnel_t * t;
- uword * p;
-
- p = hash_get (igm->tunnel_by_key, key);
- if (!p)
- {
- next1 = IPSEC_GRE_INPUT_NEXT_DROP;
- b1->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
- goto drop1;
- }
- t = pool_elt_at_index (igm->tunnels, p[0]);
- hi = vnet_get_hw_interface (igm->vnet_main,
- t->hw_if_index);
- tunnel_sw_if_index = hi->sw_if_index;
- cached_tunnel_sw_if_index = tunnel_sw_if_index;
- }
- else
- {
- tunnel_sw_if_index = cached_tunnel_sw_if_index;
- }
- vnet_buffer(b1)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
- }
-
-drop1:
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
- b0, sizeof (*tr));
- tr->tunnel_id = ~0;
- tr->length = ip0->length;
- tr->src.as_u32 = ip0->src_address.as_u32;
- tr->dst.as_u32 = ip0->dst_address.as_u32;
- }
-
- if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
- {
- ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
- b1, sizeof (*tr));
- tr->tunnel_id = ~0;
- tr->length = ip1->length;
- tr->src.as_u32 = ip1->src_address.as_u32;
- tr->dst.as_u32 = ip1->dst_address.as_u32;
- }
-
- vlib_buffer_advance (b0, sizeof (*h0));
- vlib_buffer_advance (b1, sizeof (*h1));
-
- vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, bi1, next0, next1);
- }
-
- while (n_left_from > 0 && n_left_to_next > 0)
- {
- u32 bi0;
- vlib_buffer_t * b0;
- gre_header_t * h0;
- ip4_header_t * ip0;
- u16 version0, protocol0;
- int verr0;
- u32 next0;
- u32 tun_src0, tun_dst0;
-
- bi0 = from[0];
- to_next[0] = bi0;
- from += 1;
- to_next += 1;
- n_left_from -= 1;
- n_left_to_next -= 1;
-
- b0 = vlib_get_buffer (vm, bi0);
- ip0 = vlib_buffer_get_current (b0);
-
- tun_src0 = ip0->src_address.as_u32;
- tun_dst0 = ip0->dst_address.as_u32;
-
- vlib_buffer_advance (b0, sizeof (*ip0));
-
- h0 = vlib_buffer_get_current (b0);
-
- protocol0 = clib_net_to_host_u16 (h0->protocol);
- if (PREDICT_TRUE(protocol0 == GRE_PROTOCOL_teb))
- {
- next0 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
- b0->error = node->errors[IPSEC_GRE_ERROR_NONE];
- }
- else
- {
- b0->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
- next0 = IPSEC_GRE_INPUT_NEXT_DROP;
- }
-
- version0 = clib_net_to_host_u16 (h0->flags_and_version);
- verr0 = version0 & GRE_VERSION_MASK;
- b0->error = verr0 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
- : b0->error;
- next0 = verr0 ? IPSEC_GRE_INPUT_NEXT_DROP : next0;
-
- /* For L2 payload set input sw_if_index to GRE tunnel for learning */
- if (PREDICT_TRUE(next0 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
- {
- u64 key = ((u64)(tun_dst0) << 32) | (u64)(tun_src0);
-
- if (cached_tunnel_key != key)
- {
- vnet_hw_interface_t * hi;
- ipsec_gre_tunnel_t * t;
- uword * p;
-
- p = hash_get (igm->tunnel_by_key, key);
- if (!p)
- {
- next0 = IPSEC_GRE_INPUT_NEXT_DROP;
- b0->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
- goto drop;
- }
- t = pool_elt_at_index (igm->tunnels, p[0]);
- hi = vnet_get_hw_interface (igm->vnet_main,
- t->hw_if_index);
- tunnel_sw_if_index = hi->sw_if_index;
- cached_tunnel_sw_if_index = tunnel_sw_if_index;
- }
- else
- {
- tunnel_sw_if_index = cached_tunnel_sw_if_index;
- }
- vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
- }
-
-drop:
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
- b0, sizeof (*tr));
- tr->tunnel_id = ~0;
- tr->length = ip0->length;
- tr->src.as_u32 = ip0->src_address.as_u32;
- tr->dst.as_u32 = ip0->dst_address.as_u32;
- }
-
- vlib_buffer_advance (b0, sizeof (*h0));
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, next0);
- }
-
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
- vlib_node_increment_counter (vm, ipsec_gre_input_node.index,
- IPSEC_GRE_ERROR_PKTS_DECAP, from_frame->n_vectors);
- return from_frame->n_vectors;
-}
-
-static char * ipsec_gre_error_strings[] = {
-#define ipsec_gre_error(n,s) s,
-#include "error.def"
-#undef ipsec_gre_error
-};
-
-VLIB_REGISTER_NODE (ipsec_gre_input_node) = {
- .name = "ipsec-gre-input",
- /* Takes a vector of packets. */
- .vector_size = sizeof (u32),
-
- .n_errors = IPSEC_GRE_N_ERROR,
- .error_strings = ipsec_gre_error_strings,
-
- .n_next_nodes = IPSEC_GRE_INPUT_N_NEXT,
- .next_nodes = {
-#define _(s,n) [IPSEC_GRE_INPUT_NEXT_##s] = n,
- foreach_ipsec_gre_input_next
-#undef _
- },
-
- .format_trace = format_ipsec_gre_rx_trace,
-};
-
-static clib_error_t * ipsec_gre_input_init (vlib_main_t * vm)
-{
- {
- clib_error_t * error;
- error = vlib_call_init_function (vm, ipsec_gre_init);
- if (error)
- clib_error_report (error);
- }
-
- return 0;
-}
-
-VLIB_INIT_FUNCTION (ipsec_gre_input_init);
diff --git a/src/vnet/ipsec/ah_decrypt.c b/src/vnet/ipsec/ah_decrypt.c
index d27d42384d5..741fa91b95c 100644
--- a/src/vnet/ipsec/ah_decrypt.c
+++ b/src/vnet/ipsec/ah_decrypt.c
@@ -27,8 +27,7 @@
#define foreach_ah_decrypt_next \
_ (DROP, "error-drop") \
_ (IP4_INPUT, "ip4-input") \
- _ (IP6_INPUT, "ip6-input") \
- _ (IPSEC_GRE_INPUT, "ipsec-gre-input")
+ _ (IP6_INPUT, "ip6-input")
#define _(v, s) AH_DECRYPT_NEXT_##v,
typedef enum
@@ -371,10 +370,6 @@ ah_decrypt_inline (vlib_main_t * vm,
}
}
- /* for IPSec-GRE tunnel next node is ipsec-gre-input */
- if (PREDICT_FALSE (ipsec_sa_is_set_IS_GRE (sa0)))
- next[0] = AH_DECRYPT_NEXT_IPSEC_GRE_INPUT;
-
vnet_buffer (b[0])->sw_if_index[VLIB_TX] = (u32) ~ 0;
trace:
if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
diff --git a/src/vnet/ipsec/esp_decrypt.c b/src/vnet/ipsec/esp_decrypt.c
index 710c8f17762..48f08f42e33 100644
--- a/src/vnet/ipsec/esp_decrypt.c
+++ b/src/vnet/ipsec/esp_decrypt.c
@@ -22,12 +22,12 @@
#include <vnet/ipsec/ipsec.h>
#include <vnet/ipsec/esp.h>
#include <vnet/ipsec/ipsec_io.h>
+#include <vnet/ipsec/ipsec_tun.h>
#define foreach_esp_decrypt_next \
_(DROP, "error-drop") \
_(IP4_INPUT, "ip4-input-no-checksum") \
-_(IP6_INPUT, "ip6-input") \
-_(IPSEC_GRE_INPUT, "ipsec-gre-input")
+_(IP6_INPUT, "ip6-input")
#define _(v, s) ESP_DECRYPT_NEXT_##v,
typedef enum
@@ -93,7 +93,7 @@ typedef struct
{
u8 icv_sz;
u8 iv_sz;
- ipsec_sa_flags_t flags:8;
+ ipsec_sa_flags_t flags;
u32 sa_index;
};
u64 sa_data;
@@ -111,7 +111,7 @@ STATIC_ASSERT_SIZEOF (esp_decrypt_packet_data_t, 2 * sizeof (u64));
always_inline uword
esp_decrypt_inline (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * from_frame,
- int is_ip6)
+ int is_ip6, int is_tun)
{
ipsec_main_t *im = &ipsec_main;
u32 thread_index = vm->thread_index;
@@ -378,7 +378,7 @@ esp_decrypt_inline (vlib_main_t * vm,
u16 adv = pd->iv_sz + esp_sz;
u16 tail = sizeof (esp_footer_t) + f->pad_length + pd->icv_sz;
- if ((pd->flags & tun_flags) == 0) /* transport mode */
+ if ((pd->flags & tun_flags) == 0 && !is_tun) /* transport mode */
{
u8 udp_sz = (is_ip6 == 0 && pd->flags & IPSEC_SA_FLAG_UDP_ENCAP) ?
sizeof (udp_header_t) : 0;
@@ -437,12 +437,50 @@ esp_decrypt_inline (vlib_main_t * vm,
{
next[0] = ESP_DECRYPT_NEXT_DROP;
b[0]->error = node->errors[ESP_DECRYPT_ERROR_DECRYPTION_FAILED];
+ goto trace;
+ }
+ if (is_tun)
+ {
+ if (ipsec_sa_is_set_IS_PROTECT (sa0))
+ {
+ /*
+ * Check that the reveal IP header matches that
+ * of the tunnel we are protecting
+ */
+ const ipsec_tun_protect_t *itp;
+
+ itp =
+ ipsec_tun_protect_get (vnet_buffer (b[0])->
+ ipsec.protect_index);
+ if (PREDICT_TRUE (f->next_header == IP_PROTOCOL_IP_IN_IP))
+ {
+ const ip4_header_t *ip4;
+
+ ip4 = vlib_buffer_get_current (b[0]);
+
+ if (!ip46_address_is_equal_v4 (&itp->itp_tun.src,
+ &ip4->dst_address) ||
+ !ip46_address_is_equal_v4 (&itp->itp_tun.dst,
+ &ip4->src_address))
+ next[0] = ESP_DECRYPT_NEXT_DROP;
+
+ }
+ else if (f->next_header == IP_PROTOCOL_IPV6)
+ {
+ const ip6_header_t *ip6;
+
+ ip6 = vlib_buffer_get_current (b[0]);
+
+ if (!ip46_address_is_equal_v6 (&itp->itp_tun.src,
+ &ip6->dst_address) ||
+ !ip46_address_is_equal_v6 (&itp->itp_tun.dst,
+ &ip6->src_address))
+ next[0] = ESP_DECRYPT_NEXT_DROP;
+ }
+ }
}
}
- if (PREDICT_FALSE (ipsec_sa_is_set_IS_GRE (sa0)))
- next[0] = ESP_DECRYPT_NEXT_IPSEC_GRE_INPUT;
-
trace:
if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -477,7 +515,28 @@ VLIB_NODE_FN (esp4_decrypt_node) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
{
- return esp_decrypt_inline (vm, node, from_frame, 0 /* is_ip6 */ );
+ return esp_decrypt_inline (vm, node, from_frame, 0, 0);
+}
+
+VLIB_NODE_FN (esp4_decrypt_tun_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ return esp_decrypt_inline (vm, node, from_frame, 0, 1);
+}
+
+VLIB_NODE_FN (esp6_decrypt_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ return esp_decrypt_inline (vm, node, from_frame, 1, 0);
+}
+
+VLIB_NODE_FN (esp6_decrypt_tun_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ return esp_decrypt_inline (vm, node, from_frame, 1, 1);
}
/* *INDENT-OFF* */
@@ -497,16 +556,7 @@ VLIB_REGISTER_NODE (esp4_decrypt_node) = {
#undef _
},
};
-/* *INDENT-ON* */
-VLIB_NODE_FN (esp6_decrypt_node) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * from_frame)
-{
- return esp_decrypt_inline (vm, node, from_frame, 1 /* is_ip6 */ );
-}
-
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (esp6_decrypt_node) = {
.name = "esp6-decrypt",
.vector_size = sizeof (u32),
@@ -523,6 +573,40 @@ VLIB_REGISTER_NODE (esp6_decrypt_node) = {
#undef _
},
};
+
+VLIB_REGISTER_NODE (esp4_decrypt_tun_node) = {
+ .name = "esp4-decrypt-tun",
+ .vector_size = sizeof (u32),
+ .format_trace = format_esp_decrypt_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(esp_decrypt_error_strings),
+ .error_strings = esp_decrypt_error_strings,
+
+ .n_next_nodes = ESP_DECRYPT_N_NEXT,
+ .next_nodes = {
+#define _(s,n) [ESP_DECRYPT_NEXT_##s] = n,
+ foreach_esp_decrypt_next
+#undef _
+ },
+};
+
+VLIB_REGISTER_NODE (esp6_decrypt_tun_node) = {
+ .name = "esp6-decrypt-tun",
+ .vector_size = sizeof (u32),
+ .format_trace = format_esp_decrypt_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(esp_decrypt_error_strings),
+ .error_strings = esp_decrypt_error_strings,
+
+ .n_next_nodes = ESP_DECRYPT_N_NEXT,
+ .next_nodes = {
+#define _(s,n) [ESP_DECRYPT_NEXT_##s] = n,
+ foreach_esp_decrypt_next
+#undef _
+ },
+};
/* *INDENT-ON* */
/*
diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c
index d7cda052c92..cf485482c0e 100644
--- a/src/vnet/ipsec/esp_encrypt.c
+++ b/src/vnet/ipsec/esp_encrypt.c
@@ -408,12 +408,18 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
ip_hdr = payload - hdr_len;
/* L2 header */
- l2_len = vnet_buffer (b[0])->ip.save_rewrite_length;
- hdr_len += l2_len;
- l2_hdr = payload - hdr_len;
+ if (!is_tun)
+ {
+ l2_len = vnet_buffer (b[0])->ip.save_rewrite_length;
+ hdr_len += l2_len;
+ l2_hdr = payload - hdr_len;
+
+ /* copy l2 and ip header */
+ clib_memcpy_le32 (l2_hdr, old_ip_hdr - l2_len, l2_len);
+ }
+ else
+ l2_len = 0;
- /* copy l2 and ip header */
- clib_memcpy_le32 (l2_hdr, old_ip_hdr - l2_len, l2_len);
clib_memcpy_le64 (ip_hdr, old_ip_hdr, ip_len);
if (is_ip6)
@@ -440,7 +446,8 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
esp_update_ip4_hdr (ip4, len, /* is_transport */ 1, 0);
}
- next[0] = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
+ if (!is_tun)
+ next[0] = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
}
esp->spi = spi;
@@ -618,6 +625,13 @@ VNET_FEATURE_INIT (esp4_encrypt_tun_feat_node, static) =
.node_name = "esp4-encrypt-tun",
.runs_before = VNET_FEATURES ("adj-midchain-tx"),
};
+
+VNET_FEATURE_INIT (esp4_ethernet_encrypt_tun_feat_node, static) =
+{
+ .arc_name = "ethernet-output",
+ .node_name = "esp4-encrypt-tun",
+ .runs_before = VNET_FEATURES ("adj-midchain-tx", "adj-midchain-tx-no-count"),
+};
/* *INDENT-ON* */
VLIB_NODE_FN (esp6_encrypt_tun_node) (vlib_main_t * vm,
diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api
index bb9e8056251..12bdad0f9c3 100644
--- a/src/vnet/ipsec/ipsec.api
+++ b/src/vnet/ipsec/ipsec.api
@@ -17,6 +17,7 @@
option version = "3.0.0";
import "vnet/ip/ip_types.api";
+import "vnet/interface_types.api";
/** \brief IPsec: Add/delete Security Policy Database
@param client_index - opaque cookie to identify the sender
@@ -305,6 +306,81 @@ define ipsec_sad_entry_add_del_reply
u32 stat_index;
};
+/** \brief Add or Update Protection for a tunnel with IPSEC
+
+ Tunnel protection directly associates an SA with all packets
+ ingress and egress on the tunnel. This could also be achieved by
+ assigning an SPD to the tunnel, but that would incur an unnessccary
+ SPD entry lookup.
+
+ For tunnels the ESP acts on the post-encapsulated packet. So if this
+ packet:
+ +---------+------+
+ | Payload | O-IP |
+ +---------+------+
+ where O-IP is the overlay IP addrees that was routed into the tunnel,
+ the resulting encapsulated packet will be:
+ +---------+------+------+
+ | Payload | O-IP | T-IP |
+ +---------+------+------+
+ where T-IP is the tunnel's src.dst IP addresses.
+ If the SAs used for protection are in transport mode then the ESP is
+ inserted before T-IP, i.e.:
+ +---------+------+-----+------+
+ | Payload | O-IP | ESP | T-IP |
+ +---------+------+-----+------+
+ If the SAs used for protection are in tunnel mode then another
+ encapsulation occurs, i.e.:
+ +---------+------+------+-----+------+
+ | Payload | O-IP | T-IP | ESP | C-IP |
+ +---------+------+------+-----+------+
+ where C-IP are the crypto endpoint IP addresses defined as the tunnel
+ endpoints in the SA.
+ The mode for the inbound and outbound SA must be the same.
+
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_id_index - Tunnel interface to protect
+ @param sa_in - The ID [set] of inbound SAs
+ @param sa_out - The ID of outbound SA
+*/
+typedef ipsec_tunnel_protect
+{
+ vl_api_interface_index_t sw_if_index;
+ u32 sa_out;
+ u8 n_sa_in;
+ u32 sa_in[n_sa_in];
+};
+
+autoreply define ipsec_tunnel_protect_update
+{
+ u32 client_index;
+ u32 context;
+
+ vl_api_ipsec_tunnel_protect_t tunnel;
+};
+
+autoreply define ipsec_tunnel_protect_del
+{
+ u32 client_index;
+ u32 context;
+
+ vl_api_interface_index_t sw_if_index;
+};
+
+define ipsec_tunnel_protect_dump
+{
+ u32 client_index;
+ u32 context;
+ vl_api_interface_index_t sw_if_index;
+};
+
+define ipsec_tunnel_protect_details
+{
+ u32 context;
+ vl_api_ipsec_tunnel_protect_t tun;
+};
+
/** \brief IPsec: Get SPD interfaces
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h
index 45576b3c779..c77d0fe7dd8 100644
--- a/src/vnet/ipsec/ipsec.h
+++ b/src/vnet/ipsec/ipsec.h
@@ -115,6 +115,8 @@ typedef struct
uword *ipsec6_if_pool_index_by_key;
uword *ipsec_if_real_dev_by_show_dev;
uword *ipsec_if_by_sw_if_index;
+ uword *tun4_protect_by_key;
+ uword *tun6_protect_by_key;
/* node indices */
u32 error_drop_node_index;
diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c
index 2c7c0d9626d..99e25f1b17a 100644
--- a/src/vnet/ipsec/ipsec_api.c
+++ b/src/vnet/ipsec/ipsec_api.c
@@ -30,6 +30,7 @@
#if WITH_LIBSSL > 0
#include <vnet/ipsec/ipsec.h>
+#include <vnet/ipsec/ipsec_tun.h>
#endif /* IPSEC */
#define vl_typedefs /* define message structures */
@@ -60,7 +61,10 @@ _(IPSEC_SPD_INTERFACE_DUMP, ipsec_spd_interface_dump) \
_(IPSEC_TUNNEL_IF_ADD_DEL, ipsec_tunnel_if_add_del) \
_(IPSEC_TUNNEL_IF_SET_SA, ipsec_tunnel_if_set_sa) \
_(IPSEC_SELECT_BACKEND, ipsec_select_backend) \
-_(IPSEC_BACKEND_DUMP, ipsec_backend_dump)
+_(IPSEC_BACKEND_DUMP, ipsec_backend_dump) \
+_(IPSEC_TUNNEL_PROTECT_UPDATE, ipsec_tunnel_protect_update) \
+_(IPSEC_TUNNEL_PROTECT_DEL, ipsec_tunnel_protect_del) \
+_(IPSEC_TUNNEL_PROTECT_DUMP, ipsec_tunnel_protect_dump)
static void
vl_api_ipsec_spd_add_del_t_handler (vl_api_ipsec_spd_add_del_t * mp)
@@ -104,6 +108,132 @@ static void vl_api_ipsec_interface_add_del_spd_t_handler
REPLY_MACRO (VL_API_IPSEC_INTERFACE_ADD_DEL_SPD_REPLY);
}
+static void vl_api_ipsec_tunnel_protect_update_t_handler
+ (vl_api_ipsec_tunnel_protect_update_t * mp)
+{
+ vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
+ vl_api_ipsec_tunnel_protect_update_reply_t *rmp;
+ u32 sw_if_index, ii, *sa_ins = NULL;
+ int rv;
+
+ sw_if_index = ntohl (mp->tunnel.sw_if_index);
+
+ VALIDATE_SW_IF_INDEX (&(mp->tunnel));
+
+#if WITH_LIBSSL > 0
+
+ for (ii = 0; ii < mp->tunnel.n_sa_in; ii++)
+ vec_add1 (sa_ins, ntohl (mp->tunnel.sa_in[ii]));
+
+ rv = ipsec_tun_protect_update (sw_if_index,
+ ntohl (mp->tunnel.sa_out), sa_ins);
+#else
+ rv = VNET_API_ERROR_UNIMPLEMENTED;
+#endif
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_IPSEC_TUNNEL_PROTECT_UPDATE_REPLY);
+}
+
+static void vl_api_ipsec_tunnel_protect_del_t_handler
+ (vl_api_ipsec_tunnel_protect_del_t * mp)
+{
+ vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
+ vl_api_ipsec_tunnel_protect_del_reply_t *rmp;
+ int rv;
+ u32 sw_if_index;
+
+ sw_if_index = ntohl (mp->sw_if_index);
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+#if WITH_LIBSSL > 0
+ rv = ipsec_tun_protect_del (sw_if_index);
+#else
+ rv = VNET_API_ERROR_UNIMPLEMENTED;
+#endif
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_IPSEC_TUNNEL_PROTECT_DEL_REPLY);
+}
+
+typedef struct ipsec_tunnel_protect_walk_ctx_t_
+{
+ vl_api_registration_t *reg;
+ u32 context;
+} ipsec_tunnel_protect_walk_ctx_t;
+
+static walk_rc_t
+send_ipsec_tunnel_protect_details (index_t itpi, void *arg)
+{
+ ipsec_tunnel_protect_walk_ctx_t *ctx = arg;
+ vl_api_ipsec_tunnel_protect_details_t *mp;
+ ipsec_tun_protect_t *itp;
+ u32 sai, ii = 0;
+
+ itp = ipsec_tun_protect_get (itpi);
+
+
+ mp = vl_msg_api_alloc (sizeof (*mp) + (sizeof (u32) * itp->itp_n_sa_in));
+ clib_memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_IPSEC_TUNNEL_PROTECT_DETAILS);
+ mp->context = ctx->context;
+
+ mp->tun.sw_if_index = htonl (itp->itp_sw_if_index);
+
+ mp->tun.sa_out = htonl (itp->itp_out_sa);
+ mp->tun.n_sa_in = itp->itp_n_sa_in;
+ /* *INDENT-OFF* */
+ FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
+ ({
+ mp->tun.sa_in[ii++] = htonl (sai);
+ }));
+ /* *INDENT-ON* */
+
+ vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+ return (WALK_CONTINUE);
+}
+
+static void
+vl_api_ipsec_tunnel_protect_dump_t_handler (vl_api_ipsec_tunnel_protect_dump_t
+ * mp)
+{
+ vl_api_registration_t *reg;
+ u32 sw_if_index;
+
+#if WITH_LIBSSL > 0
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ ipsec_tunnel_protect_walk_ctx_t ctx = {
+ .reg = reg,
+ .context = mp->context,
+ };
+
+ sw_if_index = ntohl (mp->sw_if_index);
+
+ if (~0 == sw_if_index)
+ {
+ ipsec_tun_protect_walk (send_ipsec_tunnel_protect_details, &ctx);
+ }
+ else
+ {
+ index_t itpi;
+
+ itpi = ipsec_tun_protect_find (sw_if_index);
+
+ if (INDEX_INVALID != itpi)
+ send_ipsec_tunnel_protect_details (itpi, &ctx);
+ }
+#else
+ clib_warning ("unimplemented");
+#endif
+}
+
static int
ipsec_spd_action_decode (vl_api_ipsec_spd_action_t in,
ipsec_policy_action_t * out)
@@ -879,6 +1009,13 @@ ipsec_api_hookup (vlib_main_t * vm)
#undef _
/*
+ * Adding and deleting SAs is MP safe since when they are added/delete
+ * no traffic is using them
+ */
+ am->is_mp_safe[VL_API_IPSEC_SAD_ENTRY_ADD_DEL] = 1;
+ am->is_mp_safe[VL_API_IPSEC_SAD_ENTRY_ADD_DEL_REPLY] = 1;
+
+ /*
* Set up the (msg_name, crc, message-id) table
*/
setup_message_id_table (am);
diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c
index 4172e104a98..1648179bc20 100644
--- a/src/vnet/ipsec/ipsec_cli.c
+++ b/src/vnet/ipsec/ipsec_cli.c
@@ -22,6 +22,7 @@
#include <vnet/fib/fib.h>
#include <vnet/ipsec/ipsec.h>
+#include <vnet/ipsec/ipsec_tun.h>
static clib_error_t *
set_interface_spd_command_fn (vlib_main_t * vm,
@@ -105,7 +106,7 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm,
is_add = 0;
else if (unformat (line_input, "spi %u", &spi))
;
- else if (unformat (line_input, "salt %u", &salt))
+ else if (unformat (line_input, "salt 0x%x", &salt))
;
else if (unformat (line_input, "esp"))
proto = IPSEC_PROTOCOL_ESP;
@@ -446,12 +447,52 @@ show_ipsec_sa_command_fn (vlib_main_t * vm,
return 0;
}
+static clib_error_t *
+clear_ipsec_sa_command_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ ipsec_main_t *im = &ipsec_main;
+ u32 sai = ~0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%u", &sai))
+ ;
+ else
+ break;
+ }
+
+ if (~0 == sai)
+ {
+ /* *INDENT-OFF* */
+ pool_foreach_index (sai, im->sad, ({
+ ipsec_sa_clear(sai);
+ }));
+ /* *INDENT-ON* */
+ }
+ else
+ {
+ if (pool_is_free_index (im->sad, sai))
+ return clib_error_return (0, "unknown SA index: %d", sai);
+ else
+ ipsec_sa_clear (sai);
+ }
+
+ return 0;
+}
+
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (show_ipsec_sa_command, static) = {
.path = "show ipsec sa",
.short_help = "show ipsec sa [index]",
.function = show_ipsec_sa_command_fn,
};
+
+VLIB_CLI_COMMAND (clear_ipsec_sa_command, static) = {
+ .path = "clear ipsec sa",
+ .short_help = "clear ipsec sa [index]",
+ .function = clear_ipsec_sa_command_fn,
+};
/* *INDENT-ON* */
static clib_error_t *
@@ -823,6 +864,88 @@ VLIB_CLI_COMMAND (create_ipsec_tunnel_command, static) = {
};
/* *INDENT-ON* */
+static clib_error_t *
+ipsec_tun_protect_cmd (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u32 sw_if_index, is_del, sa_in, sa_out, *sa_ins = NULL;
+ vnet_main_t *vnm;
+
+ is_del = 0;
+ sw_if_index = ~0;
+ vnm = vnet_get_main ();
+
+ 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, "del"))
+ is_del = 1;
+ else if (unformat (line_input, "add"))
+ is_del = 0;
+ else if (unformat (line_input, "sa-in %d", &sa_in))
+ vec_add1 (sa_ins, sa_in);
+ else if (unformat (line_input, "sa-out %d", &sa_out))
+ ;
+ else if (unformat (line_input, "%U",
+ unformat_vnet_sw_interface, vnm, &sw_if_index))
+ ;
+ else
+ return (clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, line_input));
+ }
+
+ if (!is_del)
+ ipsec_tun_protect_update (sw_if_index, sa_out, sa_ins);
+
+ unformat_free (line_input);
+ return NULL;
+}
+
+/**
+ * Protect tunnel with IPSEC
+ */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ipsec_tun_protect_cmd_node, static) =
+{
+ .path = "ipsec tunnel protect",
+ .function = ipsec_tun_protect_cmd,
+ .short_help = "ipsec tunnel protect <interface> input-sa <SA> output-sa <SA>",
+ // this is not MP safe
+};
+/* *INDENT-ON* */
+
+static walk_rc_t
+ipsec_tun_protect_show_one (index_t itpi, void *ctx)
+{
+ vlib_cli_output (ctx, "%U", format_ipsec_tun_protect, itpi);
+
+ return (WALK_CONTINUE);
+}
+
+static clib_error_t *
+ipsec_tun_protect_show (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ ipsec_tun_protect_walk (ipsec_tun_protect_show_one, vm);
+
+ return NULL;
+}
+
+/**
+ * show IPSEC tunnel protection
+ */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ipsec_tun_protect_show_node, static) =
+{
+ .path = "show ipsec protect",
+ .function = ipsec_tun_protect_show,
+ .short_help = "show ipsec protect",
+};
+/* *INDENT-ON* */
+
clib_error_t *
ipsec_cli_init (vlib_main_t * vm)
{
diff --git a/src/vnet/ipsec/ipsec_format.c b/src/vnet/ipsec/ipsec_format.c
index d0d073bd2bb..1e6e2d5cb01 100644
--- a/src/vnet/ipsec/ipsec_format.c
+++ b/src/vnet/ipsec/ipsec_format.c
@@ -22,6 +22,7 @@
#include <vnet/fib/fib_table.h>
#include <vnet/ipsec/ipsec.h>
+#include <vnet/ipsec/ipsec_tun.h>
u8 *
format_ipsec_policy_action (u8 * s, va_list * args)
@@ -368,6 +369,40 @@ done:
return (s);
}
+u8 *
+format_ipsec_tun_protect (u8 * s, va_list * args)
+{
+ u32 itpi = va_arg (*args, u32);
+ ipsec_tun_protect_t *itp;
+ u32 sai;
+
+ if (pool_is_free_index (ipsec_protect_pool, itpi))
+ {
+ s = format (s, "No such tunnel index: %d", itpi);
+ goto done;
+ }
+
+ itp = pool_elt_at_index (ipsec_protect_pool, itpi);
+
+ s = format (s, "%U", format_vnet_sw_if_index_name,
+ vnet_get_main (), itp->itp_sw_if_index);
+ s = format (s, "\n output-sa:");
+ s =
+ format (s, "\n %U", format_ipsec_sa, itp->itp_out_sa,
+ IPSEC_FORMAT_BRIEF);
+
+ s = format (s, "\n input-sa:");
+ /* *INDENT-OFF* */
+ FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
+ ({
+ s = format (s, "\n %U", format_ipsec_sa, sai, IPSEC_FORMAT_BRIEF);
+ }));
+ /* *INDENT-ON* */
+
+done:
+ 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 6627d295f1e..8e4f3f1359d 100644
--- a/src/vnet/ipsec/ipsec_if.c
+++ b/src/vnet/ipsec/ipsec_if.c
@@ -84,7 +84,7 @@ ipsec_if_tunnel_stack (adj_index_t ai)
}
/**
- * @brief Call back when restacking all adjacencies on a GRE interface
+ * @brief Call back when restacking all adjacencies on a IPSec interface
*/
static adj_walk_rc_t
ipsec_if_adj_walk_cb (adj_index_t ai, void *ctx)
@@ -100,7 +100,7 @@ ipsec_if_tunnel_restack (ipsec_tunnel_if_t * it)
fib_protocol_t proto;
/*
- * walk all the adjacencies on th GRE interface and restack them
+ * walk all the adjacencies on the IPSec interface and restack them
*/
FOR_EACH_FIB_IP_PROTOCOL (proto)
{
@@ -434,86 +434,6 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
}
int
-ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
- const ipsec_gre_tunnel_add_del_args_t * args)
-{
- ipsec_tunnel_if_t *t = 0;
- ipsec_main_t *im = &ipsec_main;
- uword *p;
- ipsec_sa_t *sa;
- ipsec4_tunnel_key_t 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;
- osa = p[0];
- sa = pool_elt_at_index (im->sad, p[0]);
- ipsec_sa_set_IS_GRE (sa);
-
- p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
- if (!p)
- return VNET_API_ERROR_INVALID_VALUE;
- isa = p[0];
- sa = pool_elt_at_index (im->sad, p[0]);
- ipsec_sa_set_IS_GRE (sa);
-
- /* we form the key from the input/remote SA whose tunnel is srouce
- * at the remote end */
- if (ipsec_sa_is_set_IS_TUNNEL (sa))
- {
- key.remote_ip = sa->tunnel_src_addr.ip4.as_u32;
- key.spi = clib_host_to_net_u32 (sa->spi);
- }
- else
- {
- key.remote_ip = args->src.as_u32;
- key.spi = clib_host_to_net_u32 (sa->spi);
- }
-
- p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64);
-
- 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);
- clib_memset (t, 0, sizeof (*t));
-
- t->input_sa_index = isa;
- t->output_sa_index = osa;
- t->hw_if_index = ~0;
- hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64,
- t - im->tunnel_interfaces);
-
- /*1st interface, register protocol */
- if (pool_elts (im->tunnel_interfaces) == 1)
- {
- ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
- ipsec4_if_input_node.index);
- /* TBD, GRE IPSec6
- *
- ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
- ipsec6_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->ipsec4_if_pool_index_by_key, key.as_u64);
- pool_put (im->tunnel_interfaces, t);
- }
- return 0;
-}
-
-int
ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
u8 is_outbound)
{
diff --git a/src/vnet/ipsec/ipsec_if.h b/src/vnet/ipsec/ipsec_if.h
index 40867108293..042dddee880 100644
--- a/src/vnet/ipsec/ipsec_if.h
+++ b/src/vnet/ipsec/ipsec_if.h
@@ -84,23 +84,10 @@ typedef CLIB_PACKED
}) ipsec6_tunnel_key_t;
/* *INDENT-ON* */
-typedef struct
-{
- u8 is_add;
- u32 local_sa_id;
- u32 remote_sa_id;
- ip4_address_t src;
- ip4_address_t dst;
-} ipsec_gre_tunnel_add_del_args_t;
-
extern int ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
ipsec_add_del_tunnel_args_t *
args, u32 * sw_if_index);
extern int ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args);
-extern int ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
- const
- ipsec_gre_tunnel_add_del_args_t *
- args);
extern int ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index,
u32 sa_id, u8 is_outbound);
diff --git a/src/vnet/ipsec/ipsec_io.h b/src/vnet/ipsec/ipsec_io.h
index 32668a0474f..b17d3d7ecf0 100644
--- a/src/vnet/ipsec/ipsec_io.h
+++ b/src/vnet/ipsec/ipsec_io.h
@@ -30,9 +30,9 @@ typedef enum
_ (PUNT, "punt-dispatch") \
_ (DROP, "error-drop")
-#define _(v, s) IPSEC_INPUT_NEXT_##v,
typedef enum
{
+#define _(v, s) IPSEC_INPUT_NEXT_##v,
foreach_ipsec_input_next
#undef _
IPSEC_INPUT_N_NEXT,
diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c
index e8a015957ce..afdecfee10d 100644
--- a/src/vnet/ipsec/ipsec_sa.c
+++ b/src/vnet/ipsec/ipsec_sa.c
@@ -17,6 +17,7 @@
#include <vnet/ipsec/esp.h>
#include <vnet/udp/udp.h>
#include <vnet/fib/fib_table.h>
+#include <vnet/ipsec/ipsec_tun.h>
/**
* @brief
@@ -292,7 +293,7 @@ ipsec_sa_del (u32 id)
{
clib_warning ("sa_id %u used in policy", sa->id);
/* sa used in policy */
- return VNET_API_ERROR_SYSCALL_ERROR_1;
+ return VNET_API_ERROR_RSRC_IN_USE;
}
hash_unset (im->sa_index_by_sa_id, sa->id);
err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
@@ -313,12 +314,20 @@ ipsec_sa_del (u32 id)
return 0;
}
+void
+ipsec_sa_clear (index_t sai)
+{
+ vlib_zero_combined_counter (&ipsec_sa_counters, sai);
+}
+
u8
ipsec_is_sa_used (u32 sa_index)
{
ipsec_main_t *im = &ipsec_main;
+ ipsec_tun_protect_t *itp;
ipsec_tunnel_if_t *t;
ipsec_policy_t *p;
+ u32 sai;
/* *INDENT-OFF* */
pool_foreach(p, im->policies, ({
@@ -335,8 +344,20 @@ ipsec_is_sa_used (u32 sa_index)
if (t->output_sa_index == sa_index)
return 1;
}));
+
+ /* *INDENT-OFF* */
+ pool_foreach(itp, ipsec_protect_pool, ({
+ FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
+ ({
+ if (sai == sa_index)
+ return 1;
+ }));
+ if (itp->itp_out_sa == sa_index)
+ return 1;
+ }));
/* *INDENT-ON* */
+
return 0;
}
@@ -415,7 +436,7 @@ ipsec_sa_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
}
/*
- * Virtual function table registered by MPLS GRE tunnels
+ * Virtual function table registered by SAs
* for participation in the FIB object graph.
*/
const static fib_node_vft_t ipsec_sa_vft = {
diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h
index 53035aa2a20..284826772a0 100644
--- a/src/vnet/ipsec/ipsec_sa.h
+++ b/src/vnet/ipsec/ipsec_sa.h
@@ -93,7 +93,7 @@ typedef struct ipsec_key_t_
_ (4, IS_TUNNEL, "tunnel") \
_ (8, IS_TUNNEL_V6, "tunnel-v6") \
_ (16, UDP_ENCAP, "udp-encap") \
- _ (32, IS_GRE, "GRE") \
+ _ (32, IS_PROTECT, "Protect") \
_ (64, IS_INBOUND, "inboud") \
_ (128, IS_AEAD, "aead") \
@@ -183,6 +183,13 @@ foreach_ipsec_sa_flags
}
foreach_ipsec_sa_flags
#undef _
+#define _(a,v,s) \
+ always_inline int \
+ ipsec_sa_unset_##v (ipsec_sa_t *sa) { \
+ return (sa->flags &= ~IPSEC_SA_FLAG_##v); \
+ }
+ foreach_ipsec_sa_flags
+#undef _
/**
* @brief
* SA packet & bytes counters
@@ -205,6 +212,7 @@ extern int ipsec_sa_add (u32 id,
const ip46_address_t * tunnel_dst_addr,
u32 * sa_index);
extern u32 ipsec_sa_del (u32 id);
+extern void ipsec_sa_clear (index_t sai);
extern void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa,
ipsec_crypto_alg_t crypto_alg);
extern void ipsec_sa_set_integ_alg (ipsec_sa_t * sa,
diff --git a/src/vnet/ipsec/ipsec_tun.c b/src/vnet/ipsec/ipsec_tun.c
new file mode 100644
index 00000000000..a389cefc991
--- /dev/null
+++ b/src/vnet/ipsec/ipsec_tun.c
@@ -0,0 +1,398 @@
+/*
+ * ipsec_tun.h : IPSEC tunnel protection
+ *
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/ipsec/ipsec_tun.h>
+#include <vnet/ipsec/esp.h>
+#include <vnet/udp/udp.h>
+
+/**
+ * Pool of tunnel protection objects
+ */
+ipsec_tun_protect_t *ipsec_protect_pool;
+
+/**
+ * DB of protected tunnels
+ */
+typedef struct ipsec_protect_db_t_
+{
+ u32 *tunnels;
+ u32 count;
+} ipsec_protect_db_t;
+
+static ipsec_protect_db_t ipsec_protect_db;
+
+static int
+ipsec_tun_protect_feature_set (ipsec_tun_protect_t * itp, u8 enable)
+{
+ u32 sai = itp->itp_out_sa;
+ int is_ip4, is_l2, rv;
+
+ is_ip4 = ip46_address_is_ip4 (&itp->itp_tun.src);
+ is_l2 = itp->itp_flags & IPSEC_PROTECT_L2;
+
+ if (is_ip4)
+ {
+ if (is_l2)
+ rv = vnet_feature_enable_disable ("ethernet-output",
+ "esp4-encrypt-tun",
+ itp->itp_sw_if_index, enable,
+ &sai, sizeof (sai));
+ else
+ rv = vnet_feature_enable_disable ("ip4-output",
+ "esp4-encrypt-tun",
+ itp->itp_sw_if_index, enable,
+ &sai, sizeof (sai));
+ }
+ else
+ {
+ if (is_l2)
+ rv = vnet_feature_enable_disable ("ethernet-output",
+ "esp6-encrypt-tun",
+ itp->itp_sw_if_index, enable,
+ &sai, sizeof (sai));
+ else
+ rv = vnet_feature_enable_disable ("ip6-output",
+ "esp6-encrypt-tun",
+ itp->itp_sw_if_index, enable,
+ &sai, sizeof (sai));
+ }
+
+ ASSERT (!rv);
+ return (rv);
+}
+
+static void
+ipsec_tun_protect_db_add (ipsec_main_t * im, const ipsec_tun_protect_t * itp)
+{
+ const ipsec_sa_t *sa;
+ u32 sai;
+
+ /* *INDENT-OFF* */
+ FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
+ ({
+ sa = ipsec_sa_get (sai);
+
+ ipsec_tun_lkup_result_t res = {
+ .tun_index = itp - ipsec_protect_pool,
+ .sa_index = sai,
+ };
+
+ /*
+ * The key is formed from the tunnel's destination
+ * as the packet lookup is done from the packet's source
+ */
+ if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
+ {
+ ipsec4_tunnel_key_t key = {
+ .remote_ip = itp->itp_crypto.dst.ip4.as_u32,
+ .spi = clib_host_to_net_u32 (sa->spi),
+ };
+ hash_set (im->tun4_protect_by_key, key.as_u64, res.as_u64);
+ }
+ else
+ {
+ ipsec6_tunnel_key_t key = {
+ .remote_ip = itp->itp_crypto.dst.ip6,
+ .spi = clib_host_to_net_u32 (sa->spi),
+ };
+ hash_set_mem_alloc (&im->tun6_protect_by_key, &key, res.as_u64);
+ }
+ }))
+ /* *INDENT-ON* */
+}
+
+static void
+ipsec_tun_protect_db_remove (ipsec_main_t * im,
+ const ipsec_tun_protect_t * itp)
+{
+ const ipsec_sa_t *sa;
+
+ /* *INDENT-OFF* */
+ FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
+ ({
+ if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
+ {
+ ipsec4_tunnel_key_t key = {
+ .remote_ip = itp->itp_crypto.dst.ip4.as_u32,
+ .spi = clib_host_to_net_u32 (sa->spi),
+ };
+ hash_unset (im->tun4_protect_by_key, &key);
+ }
+ else
+ {
+ ipsec6_tunnel_key_t key = {
+ .remote_ip = itp->itp_crypto.dst.ip6,
+ .spi = clib_host_to_net_u32 (sa->spi),
+ };
+ hash_unset_mem_free (&im->tun6_protect_by_key, &key);
+ }
+ }))
+ /* *INDENT-ON* */
+}
+
+static void
+ipsec_tun_protect_config (ipsec_main_t * im,
+ ipsec_tun_protect_t * itp, u32 sa_out, u32 * sas_in)
+{
+ ipsec_sa_t *sa;
+ u32 ii;
+
+ itp->itp_n_sa_in = vec_len (sas_in);
+ for (ii = 0; ii < itp->itp_n_sa_in; ii++)
+ itp->itp_in_sas[ii] = sas_in[ii];
+ itp->itp_out_sa = sa_out;
+
+ /* *INDENT-OFF* */
+ FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
+ ({
+ if (ipsec_sa_is_set_IS_TUNNEL (sa))
+ {
+ itp->itp_crypto.src = sa->tunnel_dst_addr;
+ itp->itp_crypto.dst = sa->tunnel_src_addr;
+ ipsec_sa_set_IS_PROTECT (sa);
+ itp->itp_flags |= IPSEC_PROTECT_ENCAPED;
+ }
+ else
+ {
+ itp->itp_crypto.src = itp->itp_tun.src;
+ itp->itp_crypto.dst = itp->itp_tun.dst;
+ itp->itp_flags &= ~IPSEC_PROTECT_ENCAPED;
+ }
+ }));
+ /* *INDENT-ON* */
+
+ /*
+ * add to the DB against each SA
+ */
+ ipsec_tun_protect_db_add (im, itp);
+
+ /*
+ * enable the encrypt feature for egress.
+ */
+ ipsec_tun_protect_feature_set (itp, 1);
+
+}
+
+static void
+ipsec_tun_protect_unconfig (ipsec_main_t * im, ipsec_tun_protect_t * itp)
+{
+ ipsec_sa_t *sa;
+
+ ipsec_tun_protect_feature_set (itp, 0);
+
+ /* *INDENT-OFF* */
+ FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
+ ({
+ ipsec_sa_unset_IS_PROTECT (sa);
+ }));
+ /* *INDENT-ON* */
+
+ ipsec_tun_protect_db_remove (im, itp);
+}
+
+index_t
+ipsec_tun_protect_find (u32 sw_if_index)
+{
+ if (vec_len (ipsec_protect_db.tunnels) < sw_if_index)
+ return (INDEX_INVALID);
+
+ return (ipsec_protect_db.tunnels[sw_if_index]);
+}
+
+int
+ipsec_tun_protect_update (u32 sw_if_index, u32 sa_out, u32 * sas_in)
+{
+ u32 itpi, ii;
+ ipsec_tun_protect_t *itp;
+ ipsec_main_t *im;
+ int rv;
+
+ rv = 0;
+ im = &ipsec_main;
+ vec_validate_init_empty (ipsec_protect_db.tunnels, sw_if_index,
+ INDEX_INVALID);
+ itpi = ipsec_protect_db.tunnels[sw_if_index];
+
+ vec_foreach_index (ii, sas_in)
+ {
+ sas_in[ii] = ipsec_get_sa_index_by_sa_id (sas_in[ii]);
+ if (~0 == sas_in[ii])
+ {
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto out;
+ }
+ }
+
+ sa_out = ipsec_get_sa_index_by_sa_id (sa_out);
+
+ if (~0 == sa_out)
+ {
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ if (INDEX_INVALID == itpi)
+ {
+ vnet_device_class_t *dev_class;
+ vnet_hw_interface_t *hi;
+ vnet_main_t *vnm;
+ u8 is_l2;
+
+ vnm = vnet_get_main ();
+ hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
+ dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
+
+ if (NULL == dev_class->ip_tun_desc)
+ {
+ rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
+ goto out;
+ }
+
+ pool_get_zero (ipsec_protect_pool, itp);
+
+ itp->itp_sw_if_index = sw_if_index;
+ ipsec_protect_db.tunnels[sw_if_index] = itp - ipsec_protect_pool;
+ ipsec_protect_db.count++;
+
+ itp->itp_n_sa_in = vec_len (sas_in);
+ for (ii = 0; ii < itp->itp_n_sa_in; ii++)
+ itp->itp_in_sas[ii] = sas_in[ii];
+ itp->itp_out_sa = sa_out;
+
+ rv = dev_class->ip_tun_desc (sw_if_index,
+ &itp->itp_tun.src,
+ &itp->itp_tun.dst, &is_l2);
+
+ if (rv)
+ goto out;
+
+ if (is_l2)
+ itp->itp_flags |= IPSEC_PROTECT_L2;
+
+ /*
+ * add to the tunnel DB for ingress
+ * - if the SA is in trasnport mode, then the packates will arrivw
+ * with the IP src,dst of the protected tunnel, in which case we can
+ * simply strip the IP header and hand the payload to the protocol
+ * appropriate input handler
+ * - if the SA is in tunnel mode then there are two IP headers present
+ * one for the crytpo tunnel endpoints (described in the SA) and one
+ * for the tunnel endpoints. The outer IP headers in the srriving
+ * packets will have the crypto endpoints. So the DB needs to contain
+ * the crpto endpoint. Once the crypto header is stripped, revealing,
+ * the tunnel-IP we have 2 choices:
+ * 1) do a tunnel lookup based on the revealed header
+ * 2) skip the tunnel lookup and assume that the packet matches the
+ * one that is protected here.
+ * If we did 1) then we would allow our peer to use the SA for tunnel
+ * X to inject traffic onto tunnel Y, this is not good. If we do 2)
+ * then we don't verify that the peer is indeed using SA for tunnel
+ * X and addressing tunnel X. So we take a compromise, once the SA
+ * matches to tunnel X we veriy that the inner IP matches the value
+ * of the tunnel we are protecting, else it's dropped.
+ */
+ ipsec_tun_protect_config (im, itp, sa_out, sas_in);
+
+ if (1 == hash_elts (im->tun4_protect_by_key))
+ ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
+ ipsec4_tun_input_node.index);
+ if (1 == hash_elts (im->tun6_protect_by_key))
+ ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
+ ipsec6_tun_input_node.index);
+ }
+ else
+ {
+ /* updating SAs only */
+ itp = pool_elt_at_index (ipsec_protect_pool, itpi);
+
+ ipsec_tun_protect_unconfig (im, itp);
+ ipsec_tun_protect_config (im, itp, sa_out, sas_in);
+ }
+
+ vec_free (sas_in);
+out:
+ return (rv);
+}
+
+int
+ipsec_tun_protect_del (u32 sw_if_index)
+{
+ ipsec_tun_protect_t *itp;
+ ipsec_main_t *im;
+ index_t itpi;
+
+ im = &ipsec_main;
+
+ vec_validate_init_empty (ipsec_protect_db.tunnels, sw_if_index,
+ INDEX_INVALID);
+ itpi = ipsec_protect_db.tunnels[sw_if_index];
+
+ if (INDEX_INVALID == itpi)
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+
+ itp = ipsec_tun_protect_get (itpi);
+ ipsec_tun_protect_unconfig (im, itp);
+
+ ipsec_protect_db.tunnels[itp->itp_sw_if_index] = INDEX_INVALID;
+
+ pool_put (ipsec_protect_pool, itp);
+
+ /* if (0 == hash_elts (im->tun4_protect_by_key)) */
+ /* ip4_unregister_protocol (IP_PROTOCOL_IPSEC_ESP); */
+ /* if (0 == hash_elts (im->tun6_protect_by_key)) */
+ /* ip6_unregister_protocol (IP_PROTOCOL_IPSEC_ESP); */
+
+ return (0);
+}
+
+void
+ipsec_tun_protect_walk (ipsec_tun_protect_walk_cb_t fn, void *ctx)
+{
+ index_t itpi;
+
+ /* *INDENT-OFF* */
+ pool_foreach_index(itpi, ipsec_protect_pool,
+ ({
+ fn (itpi, ctx);
+ }));
+ /* *INDENT-ON* */
+}
+
+clib_error_t *
+ipsec_tunnel_protect_init (vlib_main_t * vm)
+{
+ ipsec_main_t *im;
+
+ im = &ipsec_main;
+ im->tun6_protect_by_key = hash_create_mem (0,
+ sizeof (ipsec6_tunnel_key_t),
+ sizeof (u64));
+ im->tun4_protect_by_key = hash_create (0, sizeof (u64));
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (ipsec_tunnel_protect_init);
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/ipsec/ipsec_tun.h b/src/vnet/ipsec/ipsec_tun.h
new file mode 100644
index 00000000000..be5cef9a8fc
--- /dev/null
+++ b/src/vnet/ipsec/ipsec_tun.h
@@ -0,0 +1,114 @@
+/*
+ * ipsec_tun.h : IPSEC tunnel protection
+ *
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/ipsec/ipsec.h>
+
+typedef enum ipsec_protect_flags_t_
+{
+ IPSEC_PROTECT_L2 = (1 << 0),
+ IPSEC_PROTECT_ENCAPED = (1 << 1),
+} __clib_packed ipsec_protect_flags_t;
+
+typedef struct ipsec_ep_t_
+{
+ ip46_address_t src;
+ ip46_address_t dst;
+} ipsec_ep_t;
+
+typedef struct ipsec_tun_protect_t_
+{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+ u32 itp_out_sa;
+
+ /* not using a vector since we want the memory inline
+ * with this struct */
+ u32 itp_n_sa_in;
+ u32 itp_in_sas[4];
+
+ u32 itp_sw_if_index;
+
+ ipsec_ep_t itp_crypto;
+
+ ipsec_protect_flags_t itp_flags;
+
+ ipsec_ep_t itp_tun;
+
+} ipsec_tun_protect_t;
+
+#define FOR_EACH_IPSEC_PROTECT_INPUT_SAI(_itp, _sai, body) \
+{ \
+ u32 __ii; \
+ for (__ii = 0; __ii < _itp->itp_n_sa_in; __ii++) { \
+ _sai = itp->itp_in_sas[__ii]; \
+ body; \
+ } \
+}
+#define FOR_EACH_IPSEC_PROTECT_INPUT_SA(_itp, _sa, body) \
+{ \
+ u32 __ii; \
+ for (__ii = 0; __ii < _itp->itp_n_sa_in; __ii++) { \
+ _sa = ipsec_sa_get(itp->itp_in_sas[__ii]); \
+ body; \
+ } \
+}
+
+extern int ipsec_tun_protect_update (u32 sw_if_index, u32 sa_out,
+ u32 sa_ins[2]);
+extern int ipsec_tun_protect_del (u32 sw_if_index);
+
+typedef walk_rc_t (*ipsec_tun_protect_walk_cb_t) (index_t itpi, void *arg);
+extern void ipsec_tun_protect_walk (ipsec_tun_protect_walk_cb_t fn,
+ void *cttx);
+extern index_t ipsec_tun_protect_find (u32 sw_if_index);
+
+extern u8 *format_ipsec_tun_protect (u8 * s, va_list * args);
+
+// FIXME
+extern vlib_node_registration_t ipsec4_tun_input_node;
+extern vlib_node_registration_t ipsec6_tun_input_node;
+
+/*
+ * DP API
+ */
+extern ipsec_tun_protect_t *ipsec_protect_pool;
+
+typedef struct ipsec_tun_lkup_result_t_
+{
+ union
+ {
+ struct
+ {
+ u32 tun_index;
+ u32 sa_index;
+ };
+ u64 as_u64;
+ };
+} ipsec_tun_lkup_result_t;
+
+always_inline ipsec_tun_protect_t *
+ipsec_tun_protect_get (u32 index)
+{
+ return (pool_elt_at_index (ipsec_protect_pool, index));
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/ipsec/ipsec_tun_in.c b/src/vnet/ipsec/ipsec_tun_in.c
new file mode 100644
index 00000000000..2ce1691b242
--- /dev/null
+++ b/src/vnet/ipsec/ipsec_tun_in.c
@@ -0,0 +1,436 @@
+/*
+ * ipsec_tun_protect_in.c : IPSec interface input node
+ *
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/api_errno.h>
+#include <vnet/ip/ip.h>
+
+#include <vnet/ipsec/ipsec.h>
+#include <vnet/ipsec/esp.h>
+#include <vnet/ipsec/ipsec_io.h>
+#include <vnet/ipsec/ipsec_punt.h>
+#include <vnet/ipsec/ipsec_tun.h>
+#include <vnet/ip/ip4_input.h>
+
+/* Statistics (not really errors) */
+#define foreach_ipsec_tun_protect_input_error \
+ _(RX, "good packets received") \
+ _(DISABLED, "ipsec packets received on disabled interface") \
+ _(NO_TUNNEL, "no matching tunnel") \
+ _(TUNNEL_MISMATCH, "SPI-tunnel mismatch") \
+ _(SPI_0, "SPI 0")
+
+static char *ipsec_tun_protect_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_ipsec_tun_protect_input_error
+#undef _
+};
+
+typedef enum
+{
+#define _(sym,str) IPSEC_TUN_PROTECT_INPUT_ERROR_##sym,
+ foreach_ipsec_tun_protect_input_error
+#undef _
+ IPSEC_TUN_PROTECT_INPUT_N_ERROR,
+} ipsec_tun_protect_input_error_t;
+
+typedef enum ipsec_tun_next_t_
+{
+#define _(v, s) IPSEC_TUN_PROTECT_NEXT_##v,
+ foreach_ipsec_input_next
+#undef _
+ IPSEC_TUN_PROTECT_NEXT_DECRYPT,
+ IPSEC_TUN_PROTECT_N_NEXT,
+} ipsec_tun_next_t;
+
+typedef struct
+{
+ u32 spi;
+ u32 seq;
+} ipsec_tun_protect_input_trace_t;
+
+static u8 *
+format_ipsec_tun_protect_input_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ ipsec_tun_protect_input_trace_t *t =
+ va_arg (*args, ipsec_tun_protect_input_trace_t *);
+
+ s = format (s, "IPSec: spi %u seq %u", t->spi, t->seq);
+ return s;
+}
+
+always_inline u16
+ipsec_ip4_if_no_tunnel (vlib_node_runtime_t * node,
+ vlib_buffer_t * b,
+ const esp_header_t * esp, const ip4_header_t * ip4)
+{
+ if (PREDICT_FALSE (0 == esp->spi))
+ {
+ b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_SPI_0];
+ b->punt_reason = ipsec_punt_reason[(ip4->protocol == IP_PROTOCOL_UDP ?
+ IPSEC_PUNT_IP4_SPI_UDP_0 :
+ IPSEC_PUNT_IP4_SPI_0)];
+ }
+ else
+ {
+ b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL];
+ b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP4_NO_SUCH_TUNNEL];
+ }
+ return IPSEC_INPUT_NEXT_PUNT;
+}
+
+always_inline u16
+ipsec_ip6_if_no_tunnel (vlib_node_runtime_t * node,
+ vlib_buffer_t * b, const esp_header_t * esp)
+{
+ if (PREDICT_FALSE (0 == esp->spi))
+ {
+ b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL];
+ b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP6_SPI_0];
+ }
+ else
+ {
+ b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL];
+ b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP6_NO_SUCH_TUNNEL];
+ }
+ return (IPSEC_INPUT_NEXT_PUNT);
+}
+
+always_inline uword
+ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame, int is_ip6)
+{
+ ipsec_main_t *im = &ipsec_main;
+ vnet_main_t *vnm = im->vnet_main;
+ vnet_interface_main_t *vim = &vnm->interface_main;
+
+ int is_trace = node->flags & VLIB_NODE_FLAG_TRACE;
+ u32 thread_index = vm->thread_index;
+
+ u32 n_left_from, *from;
+ u16 nexts[VLIB_FRAME_SIZE], *next;
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
+
+ from = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+
+ vlib_get_buffers (vm, from, bufs, n_left_from);
+ b = bufs;
+ next = nexts;
+
+ clib_memset_u16 (nexts, im->esp4_decrypt_next_index, n_left_from);
+
+ u64 n_bytes = 0, n_packets = 0;
+ u32 n_disabled = 0, n_no_tunnel = 0;
+
+ u32 last_sw_if_index = ~0;
+ ipsec_tun_lkup_result_t last_result = {
+ .tun_index = ~0
+ };
+ ipsec4_tunnel_key_t last_key4;
+ ipsec6_tunnel_key_t last_key6;
+
+ vlib_combined_counter_main_t *rx_counter;
+ vlib_combined_counter_main_t *drop_counter;
+ ipsec_tun_protect_t *itp0;
+
+ if (is_ip6)
+ clib_memset (&last_key6, 0xff, sizeof (last_key6));
+ else
+ last_key4.as_u64 = ~0;
+
+ rx_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
+ drop_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
+
+ while (n_left_from > 0)
+ {
+ u32 sw_if_index0, len0, hdr_sz0;
+ ipsec_tun_lkup_result_t itr0;
+ ipsec4_tunnel_key_t key40;
+ ipsec6_tunnel_key_t key60;
+ ip4_header_t *ip40;
+ ip6_header_t *ip60;
+ esp_header_t *esp0;
+
+ ip40 = vlib_buffer_get_current (b[0]);
+
+ if (is_ip6)
+ {
+ ip60 = (ip6_header_t *) ip40;
+ esp0 = (esp_header_t *) (ip60 + 1);
+ hdr_sz0 = sizeof (ip6_header_t);
+ }
+ else
+ {
+ /* NAT UDP port 4500 case, don't advance any more */
+ if (ip40->protocol == IP_PROTOCOL_UDP)
+ {
+ esp0 =
+ (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) +
+ sizeof (udp_header_t));
+ hdr_sz0 = 0;
+ }
+ else
+ {
+ esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40));
+ hdr_sz0 = ip4_header_bytes (ip40);
+ }
+ }
+
+ /* stats for the tunnel include all the data after the IP header
+ just like a norml IP-IP tunnel */
+ vlib_buffer_advance (b[0], hdr_sz0);
+ len0 = vlib_buffer_length_in_chain (vm, b[0]);
+
+ if (is_ip6)
+ {
+ key60.remote_ip = ip60->src_address;
+ key60.spi = esp0->spi;
+
+ if (memcmp (&key60, &last_key6, sizeof (last_key6)) == 0)
+ {
+ itr0 = last_result;
+ }
+ else
+ {
+ uword *p = hash_get_mem (im->tun6_protect_by_key, &key60);
+ if (p)
+ {
+ itr0.as_u64 = p[0];
+ last_result = itr0;
+ clib_memcpy_fast (&last_key6, &key60, sizeof (key60));
+ }
+ else
+ {
+ next[0] = ipsec_ip6_if_no_tunnel (node, b[0], esp0);
+ n_no_tunnel++;
+ goto trace00;
+ }
+ }
+ }
+ else
+ {
+ key40.remote_ip = ip40->src_address.as_u32;
+ key40.spi = esp0->spi;
+
+ if (key40.as_u64 == last_key4.as_u64)
+ {
+ itr0 = last_result;
+ }
+ else
+ {
+ uword *p = hash_get (im->tun4_protect_by_key, key40.as_u64);
+ if (p)
+ {
+ itr0.as_u64 = p[0];
+ last_result = itr0;
+ last_key4.as_u64 = key40.as_u64;
+ }
+ else
+ {
+ next[0] = ipsec_ip4_if_no_tunnel (node, b[0], esp0, ip40);
+ n_no_tunnel++;
+ goto trace00;
+ }
+ }
+ }
+
+ itp0 = pool_elt_at_index (ipsec_protect_pool, itr0.tun_index);
+ vnet_buffer (b[0])->ipsec.sad_index = itr0.sa_index;
+ vnet_buffer (b[0])->ipsec.protect_index = itr0.tun_index;
+
+ sw_if_index0 = itp0->itp_sw_if_index;
+ vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index0;
+
+ if (PREDICT_FALSE (!vnet_sw_interface_is_admin_up (vnm, sw_if_index0)))
+ {
+ vlib_increment_combined_counter
+ (drop_counter, thread_index, sw_if_index0, 1, len0);
+ n_disabled++;
+ b[0]->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_DISABLED];
+ next[0] = IPSEC_INPUT_NEXT_DROP;
+ goto trace00;
+ }
+ else
+ {
+ if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index))
+ {
+ n_packets++;
+ n_bytes += len0;
+ }
+ else
+ {
+ if (n_packets && !(itp0->itp_flags & IPSEC_PROTECT_ENCAPED))
+ {
+ vlib_increment_combined_counter
+ (rx_counter, thread_index, last_sw_if_index,
+ n_packets, n_bytes);
+ }
+
+ last_sw_if_index = sw_if_index0;
+ n_packets = 1;
+ n_bytes = len0;
+ }
+
+ /*
+ * compare the packet's outer IP headers to that of the tunnels
+ */
+ if (is_ip6)
+ {
+ if (PREDICT_FALSE
+ (!ip46_address_is_equal_v6
+ (&itp0->itp_crypto.dst, &ip60->src_address)
+ || !ip46_address_is_equal_v6 (&itp0->itp_crypto.src,
+ &ip60->dst_address)))
+ {
+ b[0]->error =
+ node->errors
+ [IPSEC_TUN_PROTECT_INPUT_ERROR_TUNNEL_MISMATCH];
+ next[0] = IPSEC_INPUT_NEXT_DROP;
+ goto trace00;
+ }
+ }
+ else
+ {
+ if (PREDICT_FALSE
+ (!ip46_address_is_equal_v4
+ (&itp0->itp_crypto.dst, &ip40->src_address)
+ || !ip46_address_is_equal_v4 (&itp0->itp_crypto.src,
+ &ip40->dst_address)))
+ {
+ b[0]->error =
+ node->errors
+ [IPSEC_TUN_PROTECT_INPUT_ERROR_TUNNEL_MISMATCH];
+ next[0] = IPSEC_INPUT_NEXT_DROP;
+ goto trace00;
+ }
+ }
+
+ /*
+ * There are two encap possibilities
+ * 1) the tunnel and ths SA are prodiving encap, i.e. it's
+ * MAC | SA-IP | TUN-IP | ESP | PAYLOAD
+ * implying the SA is in tunnel mode (on a tunnel interface)
+ * 2) only the tunnel provides encap
+ * MAC | TUN-IP | ESP | PAYLOAD
+ * implying the SA is in transport mode.
+ *
+ * For 2) we need only strip the tunnel encap and we're good.
+ * since the tunnel and crypto ecnap (int the tun=protect
+ * object) are the same and we verified above that these match
+ * for 1) we need to strip the SA-IP outer headers, to
+ * reveal the tunnel IP and then check that this matches
+ * the configured tunnel. this we can;t do here since it
+ * involves a lookup in the per-tunnel-type DB - so ship
+ * the packet to the tunnel-types provided node to do that
+ */
+ next[0] = IPSEC_TUN_PROTECT_NEXT_DECRYPT;
+ }
+ trace00:
+ if (PREDICT_FALSE (is_trace))
+ {
+ if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ ipsec_tun_protect_input_trace_t *tr =
+ vlib_add_trace (vm, node, b[0], sizeof (*tr));
+ tr->spi = clib_host_to_net_u32 (esp0->spi);
+ tr->seq = clib_host_to_net_u32 (esp0->seq);
+ }
+ }
+
+ /* next */
+ b += 1;
+ next += 1;
+ n_left_from -= 1;
+ }
+
+ if (n_packets && !(itp0->itp_flags & IPSEC_PROTECT_ENCAPED))
+ {
+ vlib_increment_combined_counter (rx_counter,
+ thread_index,
+ last_sw_if_index, n_packets, n_bytes);
+ }
+
+ vlib_node_increment_counter (vm, node->node_index,
+ IPSEC_TUN_PROTECT_INPUT_ERROR_RX,
+ from_frame->n_vectors - (n_disabled +
+ n_no_tunnel));
+
+ vlib_buffer_enqueue_to_next (vm, node, from, nexts, from_frame->n_vectors);
+
+ return from_frame->n_vectors;
+}
+
+VLIB_NODE_FN (ipsec4_tun_input_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ return ipsec_tun_protect_input_inline (vm, node, from_frame,
+ 0 /* is_ip6 */ );
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ipsec4_tun_input_node) = {
+ .name = "ipsec4-tun-input",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ipsec_tun_protect_input_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN(ipsec_tun_protect_input_error_strings),
+ .error_strings = ipsec_tun_protect_input_error_strings,
+ .n_next_nodes = IPSEC_TUN_PROTECT_N_NEXT,
+ .next_nodes = {
+ [IPSEC_TUN_PROTECT_NEXT_DROP] = "ip4-drop",
+ [IPSEC_TUN_PROTECT_NEXT_PUNT] = "punt-dispatch",
+ [IPSEC_TUN_PROTECT_NEXT_DECRYPT] = "esp4-decrypt-tun",
+ }
+};
+/* *INDENT-ON* */
+
+VLIB_NODE_FN (ipsec6_tun_input_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ return ipsec_tun_protect_input_inline (vm, node, from_frame,
+ 1 /* is_ip6 */ );
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ipsec6_tun_input_node) = {
+ .name = "ipsec6-tun-input",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ipsec_tun_protect_input_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN(ipsec_tun_protect_input_error_strings),
+ .error_strings = ipsec_tun_protect_input_error_strings,
+ .n_next_nodes = IPSEC_TUN_PROTECT_N_NEXT,
+ .next_nodes = {
+ [IPSEC_TUN_PROTECT_NEXT_DROP] = "ip6-drop",
+ [IPSEC_TUN_PROTECT_NEXT_PUNT] = "punt-dispatch",
+ [IPSEC_TUN_PROTECT_NEXT_DECRYPT] = "esp6-decrypt-tun",
+ }
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/vnet_all_api_h.h b/src/vnet/vnet_all_api_h.h
index 31d9c3444c2..5dcdad4f987 100644
--- a/src/vnet/vnet_all_api_h.h
+++ b/src/vnet/vnet_all_api_h.h
@@ -48,7 +48,6 @@
#include <vnet/vxlan-gpe/vxlan_gpe.api.h>
#include <vnet/bfd/bfd.api.h>
#include <vnet/ipsec/ipsec.api.h>
-#include <vnet/ipsec-gre/ipsec_gre.api.h>
#include <vnet/lisp-cp/lisp.api.h>
#include <vnet/lisp-gpe/lisp_gpe.api.h>
#include <vnet/lisp-cp/one.api.h>
diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c
index d754c3ade1c..494e1ab5cc8 100644
--- a/src/vpp/api/custom_dump.c
+++ b/src/vpp/api/custom_dump.c
@@ -3245,40 +3245,6 @@ static void *vl_api_ipsec_tunnel_if_add_del_t_print
FINISH;
}
-static void *vl_api_ipsec_gre_tunnel_add_del_t_print
- (vl_api_ipsec_gre_tunnel_add_del_t * mp, void *handle)
-{
- u8 *s;
-
- s = format (0, "SCRIPT: ipsec_gre_tunnel_add_del ");
-
- s = format (s, "dst %U ", format_vl_api_ip4_address, mp->tunnel.dst);
-
- s = format (s, "src %U ", format_vl_api_ip4_address, mp->tunnel.src);
-
- s = format (s, "local_sa %d ", ntohl (mp->tunnel.local_sa_id));
-
- s = format (s, "remote_sa %d ", ntohl (mp->tunnel.remote_sa_id));
-
- if (mp->is_add == 0)
- s = format (s, "del ");
-
- FINISH;
-}
-
-static void *vl_api_ipsec_gre_tunnel_dump_t_print
- (vl_api_ipsec_gre_tunnel_dump_t * mp, void *handle)
-{
- u8 *s;
-
- s = format (0, "SCRIPT: ipsec_gre_tunnel_dump ");
-
- if (mp->sw_if_index != ~0)
- s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
-
- FINISH;
-}
-
static void *vl_api_l2_interface_pbb_tag_rewrite_t_print
(vl_api_l2_interface_pbb_tag_rewrite_t * mp, void *handle)
{
@@ -3843,8 +3809,6 @@ _(SHOW_LISP_MAP_REGISTER_STATE, show_lisp_map_register_state) \
_(LISP_RLOC_PROBE_ENABLE_DISABLE, lisp_rloc_probe_enable_disable) \
_(LISP_MAP_REGISTER_ENABLE_DISABLE, lisp_map_register_enable_disable) \
_(IPSEC_TUNNEL_IF_ADD_DEL, ipsec_tunnel_if_add_del) \
-_(IPSEC_GRE_TUNNEL_ADD_DEL, ipsec_gre_tunnel_add_del) \
-_(IPSEC_GRE_TUNNEL_DUMP, ipsec_gre_tunnel_dump) \
_(DELETE_SUBIF, delete_subif) \
_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \
_(SET_PUNT, set_punt) \
diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api
index 94732bbc236..735b31d3faa 100644
--- a/src/vpp/api/vpe.api
+++ b/src/vpp/api/vpe.api
@@ -38,7 +38,6 @@ option version = "1.1.0";
* L2TP APIs: see .../src/vnet/l2tp/{l2tp.api, l2tp_api.c}
* BFD APIs: see .../src/vnet/bfd/{bfd.api, bfd_api.c}
* IPSEC APIs: see .../src/vnet/ipsec/{ipsec.api, ipsec_api.c}
- * IPSEC-GRE APIs: see .../src/vnet/ipsec-gre/{ipsec_gre.api, ipsec_gre_api.c}
* LISP APIs: see .../src/vnet/lisp/{lisp.api, lisp_api.c}
* LISP-GPE APIs: see .../src/vnet/lisp-gpe/{lisp_gpe.api, lisp_gpe_api.c}
* SESSION APIs: .../vnet/session/{session.api session_api.c}
diff --git a/test/template_ipsec.py b/test/template_ipsec.py
index 87565edfdd7..d714a93d378 100644
--- a/test/template_ipsec.py
+++ b/test/template_ipsec.py
@@ -656,59 +656,85 @@ class IpsecTun4Tests(IpsecTun4):
class IpsecTun6(object):
""" verify methods for Tunnel v6 """
- def verify_counters6(self, p, count):
- if (hasattr(p, "tun_sa_in")):
- pkts = p.tun_sa_in.get_stats()['packets']
+ def verify_counters6(self, p_in, p_out, count):
+ if (hasattr(p_in, "tun_sa_in")):
+ pkts = p_in.tun_sa_in.get_stats()['packets']
self.assertEqual(pkts, count,
"incorrect SA in counts: expected %d != %d" %
(count, pkts))
- pkts = p.tun_sa_out.get_stats()['packets']
+ if (hasattr(p_out, "tun_sa_out")):
+ pkts = p_out.tun_sa_out.get_stats()['packets']
self.assertEqual(pkts, count,
"incorrect SA out counts: expected %d != %d" %
(count, pkts))
self.assert_packet_counter_equal(self.tun6_encrypt_node_name, count)
self.assert_packet_counter_equal(self.tun6_decrypt_node_name, count)
- def verify_tun_66(self, p, count=1):
- """ ipsec 6o6 tunnel basic test """
+ def verify_decrypted6(self, p, rxs):
+ for rx in rxs:
+ self.assert_equal(rx[IPv6].src, p.remote_tun_if_host)
+ self.assert_equal(rx[IPv6].dst, self.pg1.remote_ip6)
+ self.assert_packet_checksums_valid(rx)
+
+ def verify_encrypted6(self, p, sa, rxs):
+ for rx in rxs:
+ self.assert_packet_checksums_valid(rx)
+ self.assertEqual(len(rx) - len(Ether()) - len(IPv6()),
+ rx[IPv6].plen)
+ try:
+ decrypt_pkt = p.vpp_tun_sa.decrypt(rx[IPv6])
+ if not decrypt_pkt.haslayer(IPv6):
+ decrypt_pkt = IPv6(decrypt_pkt[Raw].load)
+ self.assert_packet_checksums_valid(decrypt_pkt)
+ self.assert_equal(decrypt_pkt.src, self.pg1.remote_ip6)
+ self.assert_equal(decrypt_pkt.dst, p.remote_tun_if_host)
+ except:
+ self.logger.debug(ppp("Unexpected packet:", rx))
+ try:
+ self.logger.debug(ppp("Decrypted packet:", decrypt_pkt))
+ except:
+ pass
+ raise
+
+ def verify_drop_tun_66(self, p_in, count=1, payload_size=64):
self.vapi.cli("clear errors")
+ self.vapi.cli("clear ipsec sa")
+
+ config_tun_params(p_in, self.encryption_type, self.tun_if)
+ send_pkts = self.gen_encrypt_pkts6(p_in.scapy_tun_sa, self.tun_if,
+ src=p_in.remote_tun_if_host,
+ dst=self.pg1.remote_ip6,
+ count=count)
+ self.send_and_assert_no_replies(self.tun_if, send_pkts)
+ self.logger.info(self.vapi.cli("sh punt stats"))
+
+ def verify_tun_66(self, p_in, p_out=None, count=1, payload_size=64):
+ self.vapi.cli("clear errors")
+ self.vapi.cli("clear ipsec sa")
+ if not p_out:
+ p_out = p_in
try:
- config_tun_params(p, self.encryption_type, self.tun_if)
- send_pkts = self.gen_encrypt_pkts6(p.scapy_tun_sa, self.tun_if,
- src=p.remote_tun_if_host,
+ config_tun_params(p_in, self.encryption_type, self.tun_if)
+ config_tun_params(p_out, self.encryption_type, self.tun_if)
+ send_pkts = self.gen_encrypt_pkts6(p_in.scapy_tun_sa, self.tun_if,
+ src=p_in.remote_tun_if_host,
dst=self.pg1.remote_ip6,
count=count)
recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1)
- for recv_pkt in recv_pkts:
- self.assert_equal(recv_pkt[IPv6].src, p.remote_tun_if_host)
- self.assert_equal(recv_pkt[IPv6].dst, self.pg1.remote_ip6)
- self.assert_packet_checksums_valid(recv_pkt)
+ self.verify_decrypted6(p_in, recv_pkts)
+
send_pkts = self.gen_pkts6(self.pg1, src=self.pg1.remote_ip6,
- dst=p.remote_tun_if_host,
- count=count)
- recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if)
- for recv_pkt in recv_pkts:
- self.assertEqual(len(recv_pkt) - len(Ether()) - len(IPv6()),
- recv_pkt[IPv6].plen)
- try:
- decrypt_pkt = p.vpp_tun_sa.decrypt(recv_pkt[IPv6])
- if not decrypt_pkt.haslayer(IPv6):
- decrypt_pkt = IPv6(decrypt_pkt[Raw].load)
- self.assert_equal(decrypt_pkt.src, self.pg1.remote_ip6)
- self.assert_equal(decrypt_pkt.dst, p.remote_tun_if_host)
- self.assert_packet_checksums_valid(decrypt_pkt)
- except:
- self.logger.debug(ppp("Unexpected packet:", recv_pkt))
- try:
- self.logger.debug(
- ppp("Decrypted packet:", decrypt_pkt))
- except:
- pass
- raise
+ dst=p_out.remote_tun_if_host,
+ count=count,
+ payload_size=payload_size)
+ recv_pkts = self.send_and_expect(self.pg1, send_pkts,
+ self.tun_if)
+ self.verify_encrypted6(p_out, p_out.vpp_tun_sa, recv_pkts)
+
finally:
self.logger.info(self.vapi.ppcli("show error"))
self.logger.info(self.vapi.ppcli("show ipsec all"))
- self.verify_counters6(p, count)
+ self.verify_counters6(p_in, p_out, count)
def verify_tun_46(self, p, count=1):
""" ipsec 4o6 tunnel basic test """
@@ -747,7 +773,7 @@ class IpsecTun6(object):
finally:
self.logger.info(self.vapi.ppcli("show error"))
self.logger.info(self.vapi.ppcli("show ipsec all"))
- self.verify_counters6(p, count)
+ self.verify_counters6(p, p, count)
class IpsecTun6Tests(IpsecTun6):
diff --git a/test/test_ipsec_esp.py b/test/test_ipsec_esp.py
index 8ed80c3d8de..96787716fb4 100644
--- a/test/test_ipsec_esp.py
+++ b/test/test_ipsec_esp.py
@@ -3,7 +3,7 @@ import unittest
from scapy.layers.ipsec import ESP
from scapy.layers.inet import UDP
-from framework import VppTestRunner
+from framework import VppTestRunner, is_skip_aarch64_set, is_platform_aarch64
from template_ipsec import IpsecTra46Tests, IpsecTun46Tests, TemplateIpsec, \
IpsecTcpTests, IpsecTun4Tests, IpsecTra4Tests, config_tra_params, \
IPsecIPv4Params, IPsecIPv6Params, \
@@ -14,6 +14,8 @@ from vpp_ip_route import VppIpRoute, VppRoutePath
from vpp_ip import DpoProto
from vpp_papi import VppEnum
+NUM_PKTS = 67
+
class ConfigIpsecESP(TemplateIpsec):
encryption_type = ESP
@@ -350,6 +352,8 @@ class TestIpsecEspUdp(TemplateIpsecEspUdp, IpsecTra4Tests):
pass
+@unittest.skipIf(is_skip_aarch64_set and is_platform_aarch64,
+ "test doesn't work on aarch64")
class TestIpsecEspAll(ConfigIpsecESP,
IpsecTra4, IpsecTra6,
IpsecTun4, IpsecTun6):
@@ -470,10 +474,12 @@ class TestIpsecEspAll(ConfigIpsecESP,
# An exhautsive 4o6, 6o4 is not necessary
# for each algo
#
- self.verify_tra_basic6(count=17)
- self.verify_tra_basic4(count=17)
- self.verify_tun_66(self.params[socket.AF_INET6], 17)
- self.verify_tun_44(self.params[socket.AF_INET], 17)
+ self.verify_tra_basic6(count=NUM_PKTS)
+ self.verify_tra_basic4(count=NUM_PKTS)
+ self.verify_tun_66(self.params[socket.AF_INET6],
+ count=NUM_PKTS)
+ self.verify_tun_44(self.params[socket.AF_INET],
+ count=NUM_PKTS)
#
# remove the SPDs, SAs, etc
diff --git a/test/test_ipsec_tun_if_esp.py b/test/test_ipsec_tun_if_esp.py
index 5ef0bdbb8c6..cc220d5a0a4 100644
--- a/test/test_ipsec_tun_if_esp.py
+++ b/test/test_ipsec_tun_if_esp.py
@@ -5,13 +5,15 @@ import copy
from scapy.layers.ipsec import ESP
from scapy.layers.l2 import Ether, Raw, GRE
from scapy.layers.inet import IP, UDP
+from scapy.layers.inet6 import IPv6
from framework import VppTestRunner, is_skip_aarch64_set, is_platform_aarch64
from template_ipsec import TemplateIpsec, IpsecTun4Tests, IpsecTun6Tests, \
IpsecTun4, IpsecTun6, IpsecTcpTests, config_tun_params
-from vpp_ipsec_tun_interface import VppIpsecTunInterface, \
- VppIpsecGRETunInterface
+from vpp_ipsec_tun_interface import VppIpsecTunInterface
+from vpp_gre_interface import VppGreInterface
+from vpp_ipip_tun_interface import VppIpIpTunInterface
from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
-from vpp_ipsec import VppIpsecSA
+from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect
from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort
from util import ppp
from vpp_papi import VppEnum
@@ -58,8 +60,6 @@ class TemplateIpsec4TunIfEsp(TemplateIpsec):
r.add_vpp_config()
def tearDown(self):
- if not self.vpp_dead:
- self.vapi.cli("show hardware")
super(TemplateIpsec4TunIfEsp, self).tearDown()
@@ -131,8 +131,6 @@ class TemplateIpsec6TunIfEsp(TemplateIpsec):
r.add_vpp_config()
def tearDown(self):
- if not self.vpp_dead:
- self.vapi.cli("show hardware")
super(TemplateIpsec6TunIfEsp, self).tearDown()
@@ -198,8 +196,6 @@ class TestIpsec4MultiTunIfEsp(TemplateIpsec, IpsecTun4):
0xffffffff)]).add_vpp_config()
def tearDown(self):
- if not self.vpp_dead:
- self.vapi.cli("show hardware")
super(TestIpsec4MultiTunIfEsp, self).tearDown()
def test_tun_44(self):
@@ -442,8 +438,6 @@ class TestIpsec6MultiTunIfEsp(TemplateIpsec, IpsecTun6):
r.add_vpp_config()
def tearDown(self):
- if not self.vpp_dead:
- self.vapi.cli("show hardware")
super(TestIpsec6MultiTunIfEsp, self).tearDown()
def test_tun_66(self):
@@ -456,9 +450,13 @@ class TestIpsec6MultiTunIfEsp(TemplateIpsec, IpsecTun6):
self.assertEqual(c['packets'], 127)
-class TemplateIpsecGRETunIfEsp(TemplateIpsec):
- """ IPsec GRE tunnel interface tests """
-
+@unittest.skipIf(is_skip_aarch64_set and is_platform_aarch64,
+ "test doesn't work on aarch64")
+class TestIpsecGreTebIfEsp(TemplateIpsec,
+ IpsecTun4Tests):
+ """ Ipsec GRE TEB ESP - TUN tests """
+ tun4_encrypt_node_name = "esp4-encrypt-tun"
+ tun4_decrypt_node_name = "esp4-decrypt-tun"
encryption_type = ESP
omac = "00:11:22:33:44:55"
@@ -509,7 +507,7 @@ class TemplateIpsecGRETunIfEsp(TemplateIpsec):
raise
def setUp(self):
- super(TemplateIpsecGRETunIfEsp, self).setUp()
+ super(TestIpsecGreTebIfEsp, self).setUp()
self.tun_if = self.pg0
@@ -534,33 +532,634 @@ class TemplateIpsecGRETunIfEsp(TemplateIpsec):
self.pg0.local_ip4)
p.tun_sa_in.add_vpp_config()
- self.tun = VppIpsecGRETunInterface(self, self.pg0,
- p.tun_sa_out.id,
- p.tun_sa_in.id)
-
+ self.tun = VppGreInterface(self,
+ self.pg0.local_ip4,
+ self.pg0.remote_ip4,
+ type=(VppEnum.vl_api_gre_tunnel_type_t.
+ GRE_API_TUNNEL_TYPE_TEB))
self.tun.add_vpp_config()
+
+ p.tun_protect = VppIpsecTunProtect(self,
+ self.tun,
+ p.tun_sa_out,
+ [p.tun_sa_in])
+
+ p.tun_protect.add_vpp_config()
+
self.tun.admin_up()
self.tun.config_ip4()
- VppIpRoute(self, p.remote_tun_if_host, 32,
- [VppRoutePath(self.tun.remote_ip4,
- 0xffffffff)]).add_vpp_config()
VppBridgeDomainPort(self, bd1, self.tun).add_vpp_config()
VppBridgeDomainPort(self, bd1, self.pg1).add_vpp_config()
+ self.vapi.cli("clear ipsec sa")
+
def tearDown(self):
- if not self.vpp_dead:
- self.vapi.cli("show hardware")
self.tun.unconfig_ip4()
- super(TemplateIpsecGRETunIfEsp, self).tearDown()
+ super(TestIpsecGreTebIfEsp, self).tearDown()
-@unittest.skipIf(is_skip_aarch64_set and is_platform_aarch64,
- "test doesn't work on aarch64")
-class TestIpsecGRETunIfEsp1(TemplateIpsecGRETunIfEsp, IpsecTun4Tests):
+class TestIpsecGreIfEsp(TemplateIpsec,
+ IpsecTun4Tests):
""" Ipsec GRE ESP - TUN tests """
- tun4_encrypt_node_name = "esp4-encrypt"
- tun4_decrypt_node_name = "esp4-decrypt"
+ tun4_encrypt_node_name = "esp4-encrypt-tun"
+ tun4_decrypt_node_name = "esp4-decrypt-tun"
+ encryption_type = ESP
+
+ def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1,
+ payload_size=100):
+ return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+ sa.encrypt(IP(src=self.pg0.remote_ip4,
+ dst=self.pg0.local_ip4) /
+ GRE() /
+ IP(src=self.pg1.local_ip4,
+ dst=self.pg1.remote_ip4) /
+ UDP(sport=1144, dport=2233) /
+ Raw('X' * payload_size))
+ for i in range(count)]
+
+ def gen_pkts(self, sw_intf, src, dst, count=1,
+ payload_size=100):
+ return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+ IP(src="1.1.1.1", dst="1.1.1.2") /
+ UDP(sport=1144, dport=2233) /
+ Raw('X' * payload_size)
+ for i in range(count)]
+
+ def verify_decrypted(self, p, rxs):
+ for rx in rxs:
+ self.assert_equal(rx[Ether].dst, self.pg1.remote_mac)
+ self.assert_equal(rx[IP].dst, self.pg1.remote_ip4)
+
+ def verify_encrypted(self, p, sa, rxs):
+ for rx in rxs:
+ try:
+ pkt = sa.decrypt(rx[IP])
+ if not pkt.haslayer(IP):
+ pkt = IP(pkt[Raw].load)
+ self.assert_packet_checksums_valid(pkt)
+ self.assert_equal(pkt[IP].dst, self.pg0.remote_ip4)
+ self.assert_equal(pkt[IP].src, self.pg0.local_ip4)
+ self.assertTrue(pkt.haslayer(GRE))
+ e = pkt[GRE]
+ self.assertEqual(e[IP].dst, "1.1.1.2")
+ except (IndexError, AssertionError):
+ self.logger.debug(ppp("Unexpected packet:", rx))
+ try:
+ self.logger.debug(ppp("Decrypted packet:", pkt))
+ except:
+ pass
+ raise
+
+ def setUp(self):
+ super(TestIpsecGreIfEsp, self).setUp()
+
+ self.tun_if = self.pg0
+
+ p = self.ipv4_params
+
+ bd1 = VppBridgeDomain(self, 1)
+ bd1.add_vpp_config()
+
+ p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol,
+ self.pg0.local_ip4,
+ self.pg0.remote_ip4)
+ p.tun_sa_out.add_vpp_config()
+
+ p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol,
+ self.pg0.remote_ip4,
+ self.pg0.local_ip4)
+ p.tun_sa_in.add_vpp_config()
+
+ self.tun = VppGreInterface(self,
+ self.pg0.local_ip4,
+ self.pg0.remote_ip4)
+ self.tun.add_vpp_config()
+
+ p.tun_protect = VppIpsecTunProtect(self,
+ self.tun,
+ p.tun_sa_out,
+ [p.tun_sa_in])
+ p.tun_protect.add_vpp_config()
+
+ self.tun.admin_up()
+ self.tun.config_ip4()
+
+ VppIpRoute(self, "1.1.1.2", 32,
+ [VppRoutePath(self.tun.remote_ip4,
+ 0xffffffff)]).add_vpp_config()
+
+ def tearDown(self):
+ self.tun.unconfig_ip4()
+ super(TestIpsecGreIfEsp, self).tearDown()
+
+
+class TemplateIpsec4TunProtect(object):
+ """ IPsec IPv4 Tunnel protect """
+
+ def config_sa_tra(self, p):
+ config_tun_params(p, self.encryption_type, self.tun_if)
+
+ p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol)
+ p.tun_sa_out.add_vpp_config()
+
+ p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol)
+ p.tun_sa_in.add_vpp_config()
+
+ def config_sa_tun(self, p):
+ config_tun_params(p, self.encryption_type, self.tun_if)
+
+ p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol,
+ self.tun_if.remote_addr[p.addr_type],
+ self.tun_if.local_addr[p.addr_type])
+ p.tun_sa_out.add_vpp_config()
+
+ p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol,
+ self.tun_if.remote_addr[p.addr_type],
+ self.tun_if.local_addr[p.addr_type])
+ p.tun_sa_in.add_vpp_config()
+
+ def config_protect(self, p):
+ p.tun_protect = VppIpsecTunProtect(self,
+ p.tun_if,
+ p.tun_sa_out,
+ [p.tun_sa_in])
+ p.tun_protect.add_vpp_config()
+
+ def config_network(self, p):
+ p.tun_if = VppIpIpTunInterface(self, self.pg0,
+ self.pg0.local_ip4,
+ self.pg0.remote_ip4)
+ p.tun_if.add_vpp_config()
+ p.tun_if.admin_up()
+ p.tun_if.config_ip4()
+
+ p.route = VppIpRoute(self, p.remote_tun_if_host, 32,
+ [VppRoutePath(p.tun_if.remote_ip4,
+ 0xffffffff)])
+ p.route.add_vpp_config()
+
+ def unconfig_network(self, p):
+ p.route.remove_vpp_config()
+ p.tun_if.remove_vpp_config()
+
+ def unconfig_protect(self, p):
+ p.tun_protect.remove_vpp_config()
+
+ def unconfig_sa(self, p):
+ p.tun_sa_out.remove_vpp_config()
+ p.tun_sa_in.remove_vpp_config()
+
+
+class TestIpsec4TunProtect(TemplateIpsec,
+ TemplateIpsec4TunProtect,
+ IpsecTun4):
+ """ IPsec IPv4 Tunnel protect - transport mode"""
+
+ encryption_type = ESP
+ tun4_encrypt_node_name = "esp4-encrypt-tun"
+ tun4_decrypt_node_name = "esp4-decrypt-tun"
+
+ def setUp(self):
+ super(TestIpsec4TunProtect, self).setUp()
+
+ self.tun_if = self.pg0
+
+ def tearDown(self):
+ super(TestIpsec4TunProtect, self).tearDown()
+
+ def test_tun_44(self):
+ """IPSEC tunnel protect"""
+
+ p = self.ipv4_params
+
+ self.config_network(p)
+ self.config_sa_tra(p)
+ self.config_protect(p)
+
+ self.verify_tun_44(p, count=127)
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 127)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 127)
+
+ # rekey - create new SAs and update the tunnel protection
+ np = copy.copy(p)
+ np.crypt_key = 'X' + p.crypt_key[1:]
+ np.scapy_tun_spi += 100
+ np.scapy_tun_sa_id += 1
+ np.vpp_tun_spi += 100
+ np.vpp_tun_sa_id += 1
+ np.tun_if.local_spi = p.vpp_tun_spi
+ np.tun_if.remote_spi = p.scapy_tun_spi
+
+ self.config_sa_tra(np)
+ self.config_protect(np)
+ self.unconfig_sa(p)
+
+ self.verify_tun_44(np, count=127)
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 254)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 254)
+
+ # teardown
+ self.unconfig_protect(np)
+ self.unconfig_sa(np)
+ self.unconfig_network(p)
+
+
+class TestIpsec4TunProtectTun(TemplateIpsec,
+ TemplateIpsec4TunProtect,
+ IpsecTun4):
+ """ IPsec IPv4 Tunnel protect - tunnel mode"""
+
+ encryption_type = ESP
+ tun4_encrypt_node_name = "esp4-encrypt-tun"
+ tun4_decrypt_node_name = "esp4-decrypt-tun"
+
+ def setUp(self):
+ super(TestIpsec4TunProtectTun, self).setUp()
+
+ self.tun_if = self.pg0
+
+ def tearDown(self):
+ super(TestIpsec4TunProtectTun, self).tearDown()
+
+ def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1,
+ payload_size=100):
+ return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+ sa.encrypt(IP(src=sw_intf.remote_ip4,
+ dst=sw_intf.local_ip4) /
+ IP(src=src, dst=dst) /
+ UDP(sport=1144, dport=2233) /
+ Raw('X' * payload_size))
+ for i in range(count)]
+
+ def gen_pkts(self, sw_intf, src, dst, count=1,
+ payload_size=100):
+ return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+ IP(src=src, dst=dst) /
+ UDP(sport=1144, dport=2233) /
+ Raw('X' * payload_size)
+ for i in range(count)]
+
+ def verify_decrypted(self, p, rxs):
+ for rx in rxs:
+ self.assert_equal(rx[IP].dst, self.pg1.remote_ip4)
+ self.assert_equal(rx[IP].src, p.remote_tun_if_host)
+ self.assert_packet_checksums_valid(rx)
+
+ def verify_encrypted(self, p, sa, rxs):
+ for rx in rxs:
+ try:
+ pkt = sa.decrypt(rx[IP])
+ if not pkt.haslayer(IP):
+ pkt = IP(pkt[Raw].load)
+ self.assert_packet_checksums_valid(pkt)
+ self.assert_equal(pkt[IP].dst, self.pg0.remote_ip4)
+ self.assert_equal(pkt[IP].src, self.pg0.local_ip4)
+ inner = pkt[IP].payload
+ self.assertEqual(inner[IP][IP].dst, p.remote_tun_if_host)
+
+ except (IndexError, AssertionError):
+ self.logger.debug(ppp("Unexpected packet:", rx))
+ try:
+ self.logger.debug(ppp("Decrypted packet:", pkt))
+ except:
+ pass
+ raise
+
+ def test_tun_44(self):
+ """IPSEC tunnel protect """
+
+ p = self.ipv4_params
+
+ self.config_network(p)
+ self.config_sa_tun(p)
+ self.config_protect(p)
+
+ self.verify_tun_44(p, count=127)
+
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 127)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 127)
+
+ # rekey - create new SAs and update the tunnel protection
+ np = copy.copy(p)
+ np.crypt_key = 'X' + p.crypt_key[1:]
+ np.scapy_tun_spi += 100
+ np.scapy_tun_sa_id += 1
+ np.vpp_tun_spi += 100
+ np.vpp_tun_sa_id += 1
+ np.tun_if.local_spi = p.vpp_tun_spi
+ np.tun_if.remote_spi = p.scapy_tun_spi
+
+ self.config_sa_tun(np)
+ self.config_protect(np)
+ self.unconfig_sa(p)
+
+ self.verify_tun_44(np, count=127)
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 254)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 254)
+
+ # teardown
+ self.unconfig_protect(np)
+ self.unconfig_sa(np)
+ self.unconfig_network(p)
+
+
+class TemplateIpsec6TunProtect(object):
+ """ IPsec IPv6 Tunnel protect """
+
+ def config_sa_tra(self, p):
+ config_tun_params(p, self.encryption_type, self.tun_if)
+
+ p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol)
+ p.tun_sa_out.add_vpp_config()
+
+ p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol)
+ p.tun_sa_in.add_vpp_config()
+
+ def config_sa_tun(self, p):
+ config_tun_params(p, self.encryption_type, self.tun_if)
+
+ p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol,
+ self.tun_if.remote_addr[p.addr_type],
+ self.tun_if.local_addr[p.addr_type])
+ p.tun_sa_out.add_vpp_config()
+
+ p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+ p.auth_algo_vpp_id, p.auth_key,
+ p.crypt_algo_vpp_id, p.crypt_key,
+ self.vpp_esp_protocol,
+ self.tun_if.remote_addr[p.addr_type],
+ self.tun_if.local_addr[p.addr_type])
+ p.tun_sa_in.add_vpp_config()
+
+ def config_protect(self, p):
+ p.tun_protect = VppIpsecTunProtect(self,
+ p.tun_if,
+ p.tun_sa_out,
+ [p.tun_sa_in])
+ p.tun_protect.add_vpp_config()
+
+ def config_network(self, p):
+ p.tun_if = VppIpIpTunInterface(self, self.pg0,
+ self.pg0.local_ip6,
+ self.pg0.remote_ip6)
+ p.tun_if.add_vpp_config()
+ p.tun_if.admin_up()
+ p.tun_if.config_ip6()
+
+ p.route = VppIpRoute(self, p.remote_tun_if_host, 128,
+ [VppRoutePath(p.tun_if.remote_ip6,
+ 0xffffffff,
+ proto=DpoProto.DPO_PROTO_IP6)],
+ is_ip6=1)
+ p.route.add_vpp_config()
+
+ def unconfig_network(self, p):
+ p.route.remove_vpp_config()
+ p.tun_if.remove_vpp_config()
+
+ def unconfig_protect(self, p):
+ p.tun_protect.remove_vpp_config()
+
+ def unconfig_sa(self, p):
+ p.tun_sa_out.remove_vpp_config()
+ p.tun_sa_in.remove_vpp_config()
+
+
+class TestIpsec6TunProtect(TemplateIpsec,
+ TemplateIpsec6TunProtect,
+ IpsecTun6):
+ """ IPsec IPv6 Tunnel protect - transport mode"""
+
+ encryption_type = ESP
+ tun6_encrypt_node_name = "esp6-encrypt-tun"
+ tun6_decrypt_node_name = "esp6-decrypt-tun"
+
+ def setUp(self):
+ super(TestIpsec6TunProtect, self).setUp()
+
+ self.tun_if = self.pg0
+
+ def tearDown(self):
+ super(TestIpsec6TunProtect, self).tearDown()
+
+ def test_tun_66(self):
+ """IPSEC tunnel protect"""
+
+ p = self.ipv6_params
+
+ self.config_network(p)
+ self.config_sa_tra(p)
+ self.config_protect(p)
+
+ self.verify_tun_66(p, count=127)
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 127)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 127)
+
+ # rekey - create new SAs and update the tunnel protection
+ np = copy.copy(p)
+ np.crypt_key = 'X' + p.crypt_key[1:]
+ np.scapy_tun_spi += 100
+ np.scapy_tun_sa_id += 1
+ np.vpp_tun_spi += 100
+ np.vpp_tun_sa_id += 1
+ np.tun_if.local_spi = p.vpp_tun_spi
+ np.tun_if.remote_spi = p.scapy_tun_spi
+
+ self.config_sa_tra(np)
+ self.config_protect(np)
+ self.unconfig_sa(p)
+
+ self.verify_tun_66(np, count=127)
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 254)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 254)
+
+ # 3 phase rekey
+ # 1) add two input SAs [old, new]
+ # 2) swap output SA to [new]
+ # 3) use only [new] input SA
+ np3 = copy.copy(np)
+ np3.crypt_key = 'Z' + p.crypt_key[1:]
+ np3.scapy_tun_spi += 100
+ np3.scapy_tun_sa_id += 1
+ np3.vpp_tun_spi += 100
+ np3.vpp_tun_sa_id += 1
+ np3.tun_if.local_spi = p.vpp_tun_spi
+ np3.tun_if.remote_spi = p.scapy_tun_spi
+
+ self.config_sa_tra(np3)
+
+ # step 1;
+ p.tun_protect.update_vpp_config(np.tun_sa_out,
+ [np.tun_sa_in, np3.tun_sa_in])
+ self.verify_tun_66(np, np, count=127)
+ self.verify_tun_66(np3, np, count=127)
+
+ # step 2;
+ p.tun_protect.update_vpp_config(np3.tun_sa_out,
+ [np.tun_sa_in, np3.tun_sa_in])
+ self.verify_tun_66(np, np3, count=127)
+ self.verify_tun_66(np3, np3, count=127)
+
+ # step 1;
+ p.tun_protect.update_vpp_config(np3.tun_sa_out,
+ [np3.tun_sa_in])
+ self.verify_tun_66(np3, np3, count=127)
+ self.verify_drop_tun_66(np, count=127)
+
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 127*7)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 127*7)
+ self.unconfig_sa(np)
+
+ # teardown
+ self.unconfig_protect(np3)
+ self.unconfig_sa(np3)
+ self.unconfig_network(p)
+
+
+class TestIpsec6TunProtectTun(TemplateIpsec,
+ TemplateIpsec6TunProtect,
+ IpsecTun6):
+ """ IPsec IPv6 Tunnel protect - tunnel mode"""
+
+ encryption_type = ESP
+ tun6_encrypt_node_name = "esp6-encrypt-tun"
+ tun6_decrypt_node_name = "esp6-decrypt-tun"
+
+ def setUp(self):
+ super(TestIpsec6TunProtectTun, self).setUp()
+
+ self.tun_if = self.pg0
+
+ def tearDown(self):
+ super(TestIpsec6TunProtectTun, self).tearDown()
+
+ def gen_encrypt_pkts6(self, sa, sw_intf, src, dst, count=1,
+ payload_size=100):
+ return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+ sa.encrypt(IPv6(src=sw_intf.remote_ip6,
+ dst=sw_intf.local_ip6) /
+ IPv6(src=src, dst=dst) /
+ UDP(sport=1166, dport=2233) /
+ Raw('X' * payload_size))
+ for i in range(count)]
+
+ def gen_pkts6(self, sw_intf, src, dst, count=1,
+ payload_size=100):
+ return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+ IPv6(src=src, dst=dst) /
+ UDP(sport=1166, dport=2233) /
+ Raw('X' * payload_size)
+ for i in range(count)]
+
+ def verify_decrypted6(self, p, rxs):
+ for rx in rxs:
+ self.assert_equal(rx[IPv6].dst, self.pg1.remote_ip6)
+ self.assert_equal(rx[IPv6].src, p.remote_tun_if_host)
+ self.assert_packet_checksums_valid(rx)
+
+ def verify_encrypted6(self, p, sa, rxs):
+ for rx in rxs:
+ try:
+ pkt = sa.decrypt(rx[IPv6])
+ if not pkt.haslayer(IPv6):
+ pkt = IPv6(pkt[Raw].load)
+ self.assert_packet_checksums_valid(pkt)
+ self.assert_equal(pkt[IPv6].dst, self.pg0.remote_ip6)
+ self.assert_equal(pkt[IPv6].src, self.pg0.local_ip6)
+ inner = pkt[IPv6].payload
+ self.assertEqual(inner[IPv6][IPv6].dst, p.remote_tun_if_host)
+
+ except (IndexError, AssertionError):
+ self.logger.debug(ppp("Unexpected packet:", rx))
+ try:
+ self.logger.debug(ppp("Decrypted packet:", pkt))
+ except:
+ pass
+ raise
+
+ def test_tun_66(self):
+ """IPSEC tunnel protect """
+
+ p = self.ipv6_params
+
+ self.config_network(p)
+ self.config_sa_tun(p)
+ self.config_protect(p)
+
+ self.verify_tun_66(p, count=127)
+
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 127)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 127)
+
+ # rekey - create new SAs and update the tunnel protection
+ np = copy.copy(p)
+ np.crypt_key = 'X' + p.crypt_key[1:]
+ np.scapy_tun_spi += 100
+ np.scapy_tun_sa_id += 1
+ np.vpp_tun_spi += 100
+ np.vpp_tun_sa_id += 1
+ np.tun_if.local_spi = p.vpp_tun_spi
+ np.tun_if.remote_spi = p.scapy_tun_spi
+
+ self.config_sa_tun(np)
+ self.config_protect(np)
+ self.unconfig_sa(p)
+
+ self.verify_tun_66(np, count=127)
+ c = p.tun_if.get_rx_stats()
+ self.assertEqual(c['packets'], 254)
+ c = p.tun_if.get_tx_stats()
+ self.assertEqual(c['packets'], 254)
+
+ # teardown
+ self.unconfig_protect(np)
+ self.unconfig_sa(np)
+ self.unconfig_network(p)
+
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)
diff --git a/test/vpp_ipip_tun_interface.py b/test/vpp_ipip_tun_interface.py
new file mode 100644
index 00000000000..6e5ade6eb3d
--- /dev/null
+++ b/test/vpp_ipip_tun_interface.py
@@ -0,0 +1,40 @@
+from vpp_tunnel_interface import VppTunnelInterface
+from ipaddress import ip_address
+
+
+class VppIpIpTunInterface(VppTunnelInterface):
+ """
+ VPP IP-IP Tunnel interface
+ """
+
+ def __init__(self, test, parent_if, src, dst):
+ super(VppIpIpTunInterface, self).__init__(test, parent_if)
+ self.src = src
+ self.dst = dst
+
+ def add_vpp_config(self):
+ r = self.test.vapi.ipip_add_tunnel(
+ tunnel={
+ 'src': self.src,
+ 'dst': self.dst,
+ 'table_id': 0,
+ 'instance': 0xffffffff,
+ })
+ self.set_sw_if_index(r.sw_if_index)
+ self.test.registry.register(self, self.test.logger)
+
+ def remove_vpp_config(self):
+ self.test.vapi.ipip_del_tunnel(sw_if_index=self._sw_if_index)
+
+ def query_vpp_config(self):
+ ts = self.test.vapi.ipip_tunnel_dump(sw_if_index=0xffffffff)
+ for t in ts:
+ if t.tunnel.sw_if_index == self._sw_if_index:
+ return True
+ return False
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "ipip-%d" % self._sw_if_index
diff --git a/test/vpp_ipsec.py b/test/vpp_ipsec.py
index 77a9d74edf3..0df8cb2a88a 100644
--- a/test/vpp_ipsec.py
+++ b/test/vpp_ipsec.py
@@ -247,3 +247,53 @@ class VppIpsecSA(VppObject):
def get_stats(self):
c = self.test.statistics.get_counter("/net/ipsec/sa")
return c[0][self.stat_index]
+
+
+class VppIpsecTunProtect(VppObject):
+ """
+ VPP IPSEC tunnel protection
+ """
+
+ def __init__(self, test, itf, sa_out, sas_in):
+ self.test = test
+ self.itf = itf
+ self.sas_in = []
+ for sa in sas_in:
+ self.sas_in.append(sa.id)
+ self.sa_out = sa_out.id
+
+ def update_vpp_config(self, sa_out, sas_in):
+ self.sas_in = []
+ for sa in sas_in:
+ self.sas_in.append(sa.id)
+ self.sa_out = sa_out.id
+ self.test.vapi.ipsec_tunnel_protect_update(
+ tunnel={
+ 'sw_if_index': self.itf._sw_if_index,
+ 'n_sa_in': len(self.sas_in),
+ 'sa_out': self.sa_out,
+ 'sa_in': self.sas_in})
+
+ def object_id(self):
+ return "ipsec-tun-protect-%s" % self.itf
+
+ def add_vpp_config(self):
+ self.test.vapi.ipsec_tunnel_protect_update(
+ tunnel={
+ 'sw_if_index': self.itf._sw_if_index,
+ 'n_sa_in': len(self.sas_in),
+ 'sa_out': self.sa_out,
+ 'sa_in': self.sas_in})
+ self.test.registry.register(self, self.test.logger)
+
+ def remove_vpp_config(self):
+ self.test.vapi.ipsec_tunnel_protect_del(
+ sw_if_index=self.itf.sw_if_index)
+
+ def query_vpp_config(self):
+ bs = self.test.vapi.ipsec_tunnel_protect_dump(
+ sw_if_index=self.itf.sw_if_index)
+ for b in bs:
+ if b.tun.sw_if_index == self.itf.sw_if_index:
+ return True
+ return False
diff --git a/test/vpp_ipsec_tun_interface.py b/test/vpp_ipsec_tun_interface.py
index 223ea4df154..97359b13281 100644
--- a/test/vpp_ipsec_tun_interface.py
+++ b/test/vpp_ipsec_tun_interface.py
@@ -51,48 +51,3 @@ class VppIpsecTunInterface(VppTunnelInterface):
def object_id(self):
return "ipsec-tun-if-%d" % self._sw_if_index
-
-
-class VppIpsecGRETunInterface(VppTunnelInterface):
- """
- VPP IPsec GRE Tunnel interface
- this creates headers
- IP / ESP / IP / GRE / payload
- i.e. it's GRE over IPSEC, rather than IPSEC over GRE.
- """
-
- def __init__(self, test, parent_if, sa_out, sa_in):
- super(VppIpsecGRETunInterface, self).__init__(test, parent_if)
- self.sa_in = sa_in
- self.sa_out = sa_out
-
- def add_vpp_config(self):
- r = self.test.vapi.ipsec_gre_tunnel_add_del(
- self.parent_if.local_ip4n,
- self.parent_if.remote_ip4n,
- self.sa_out,
- self.sa_in)
- self.set_sw_if_index(r.sw_if_index)
- self.generate_remote_hosts()
- self.test.registry.register(self, self.test.logger)
-
- def remove_vpp_config(self):
- self.test.vapi.ipsec_gre_tunnel_add_del(
- self.parent_if.local_ip4n,
- self.parent_if.remote_ip4n,
- self.sa_out,
- self.sa_in,
- is_add=0)
-
- def query_vpp_config(self):
- ts = self.test.vapi.ipsec_gre_tunnel_dump(sw_if_index=0xffffffff)
- for t in ts:
- if t.tunnel.sw_if_index == self._sw_if_index:
- return True
- return False
-
- def __str__(self):
- return self.object_id()
-
- def object_id(self):
- return "ipsec-gre-tun-if-%d" % self._sw_if_index
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 038a3718dde..75ec57f8221 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -1968,19 +1968,6 @@ class VppPapiProvider(object):
'salt': salt
})
- def ipsec_gre_tunnel_add_del(self, local_ip, remote_ip,
- sa_out, sa_in, is_add=1):
- return self.api(self.papi.ipsec_gre_tunnel_add_del,
- {
- 'is_add': is_add,
- 'tunnel': {
- 'src': local_ip,
- 'dst': remote_ip,
- 'local_sa_id': sa_out,
- 'remote_sa_id': sa_in
- }
- })
-
def ipsec_select_backend(self, protocol, index):
return self.api(self.papi.ipsec_select_backend,
{'protocol': protocol, 'index': index})