ipsec: ipsec-tun protect 56/18956/18
authorNeale Ranns <nranns@cisco.com>
Thu, 7 Feb 2019 15:26:12 +0000 (07:26 -0800)
committerDamjan Marion <dmarion@me.com>
Tue, 18 Jun 2019 13:54:35 +0000 (13:54 +0000)
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>
47 files changed:
doxygen/user_doc.md
src/scripts/vnet/ipsec_tun_protect [new file with mode: 0644]
src/vat/api_format.c
src/vnet/CMakeLists.txt
src/vnet/buffer.h
src/vnet/gre/gre.c
src/vnet/interface.c
src/vnet/interface.h
src/vnet/interface_funcs.h
src/vnet/ip/ip6_packet.h
src/vnet/ipip/ipip.c
src/vnet/ipip/ipip_api.c
src/vnet/ipsec-gre/dir.dox [deleted file]
src/vnet/ipsec-gre/error.def [deleted file]
src/vnet/ipsec-gre/interface.c [deleted file]
src/vnet/ipsec-gre/ipsec_gre.api [deleted file]
src/vnet/ipsec-gre/ipsec_gre.c [deleted file]
src/vnet/ipsec-gre/ipsec_gre.h [deleted file]
src/vnet/ipsec-gre/ipsec_gre_api.c [deleted file]
src/vnet/ipsec-gre/ipsec_gre_doc.md [deleted file]
src/vnet/ipsec-gre/node.c [deleted file]
src/vnet/ipsec/ah_decrypt.c
src/vnet/ipsec/esp_decrypt.c
src/vnet/ipsec/esp_encrypt.c
src/vnet/ipsec/ipsec.api
src/vnet/ipsec/ipsec.h
src/vnet/ipsec/ipsec_api.c
src/vnet/ipsec/ipsec_cli.c
src/vnet/ipsec/ipsec_format.c
src/vnet/ipsec/ipsec_if.c
src/vnet/ipsec/ipsec_if.h
src/vnet/ipsec/ipsec_io.h
src/vnet/ipsec/ipsec_sa.c
src/vnet/ipsec/ipsec_sa.h
src/vnet/ipsec/ipsec_tun.c [new file with mode: 0644]
src/vnet/ipsec/ipsec_tun.h [new file with mode: 0644]
src/vnet/ipsec/ipsec_tun_in.c [new file with mode: 0644]
src/vnet/vnet_all_api_h.h
src/vpp/api/custom_dump.c
src/vpp/api/vpe.api
test/template_ipsec.py
test/test_ipsec_esp.py
test/test_ipsec_tun_if_esp.py
test/vpp_ipip_tun_interface.py [new file with mode: 0644]
test/vpp_ipsec.py
test/vpp_ipsec_tun_interface.py
test/vpp_papi_provider.py

index d607d39..f39bc10 100644 (file)
@@ -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 (file)
index 0000000..ed81f91
--- /dev/null
@@ -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
+  }
+}
index fe1a87f..536c4b0 100644 (file)
@@ -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)                                       \
@@ -20086,52 +20049,6 @@ api_ip_source_and_port_range_check_interface_add_del (vat_main_t * vam)
   return ret;
 }
 
-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)
 {
@@ -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"                                       \
index 5465d71..462ced4 100644 (file)
@@ -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)
@@ -846,28 +849,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
 ##############################################################################
index 6738f3c..812fe74 100644 (file)
@@ -276,6 +276,7 @@ typedef struct
     struct
     {
       u32 sad_index;
+      u32 protect_index;
     } ipsec;
 
     /* MAP */
index 72c76fc..ab2567d 100644 (file)
@@ -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
index 8af2b58..1702cdc 100644 (file)
@@ -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)
index 5419fff..72a9326 100644 (file)
@@ -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);
 
index b862f48..6d404b4 100644 (file)
@@ -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);
index ff47830..c8bc4c8 100644 (file)
@@ -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)
 {
index 5d40708..66c945e 100644 (file)
@@ -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
index 35b846e..62a9965 100644 (file)
@@ -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 (file)
index e6ffd10..0000000
+++ /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 (file)
index d84e8ed..0000000
+++ /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 (file)
index 6a8bb7d..0000000
+++ /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 (file)
index b495009..0000000
+++ /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 (file)
index cdb23dd..0000000
+++ /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 (file)
index 730cd71..0000000
+++ /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 (file)
index 9e5d615..0000000
+++ /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 (file)
index e1bb9cd..0000000
+++ /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 (file)
index 6a3aaa1..0000000
+++ /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);
index d27d423..741fa91 100644 (file)
@@ -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))
index 710c8f1..48f08f4 100644 (file)
 #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* */
 
 /*
index d7cda05..cf48548 100644 (file)
@@ -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,
index bb9e805..12bdad0 100644 (file)
@@ -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
index 45576b3..c77d0fe 100644 (file)
@@ -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;
index 2c7c0d9..99e25f1 100644 (file)
@@ -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)
@@ -878,6 +1008,13 @@ ipsec_api_hookup (vlib_main_t * vm)
   foreach_vpe_api_msg;
 #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
    */
index 4172e10..1648179 100644 (file)
@@ -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)
 {
index d0d073b..1e6e2d5 100644 (file)
@@ -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
  *
index 6627d29..8e4f3f1 100644 (file)
@@ -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)
   {
@@ -433,86 +433,6 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
   return 0;
 }
 
-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)
index 4086710..042ddde 100644 (file)
@@ -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);
index 32668a0..b17d3d7 100644 (file)
@@ -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,
index e8a0159..afdecfe 100644 (file)
@@ -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 = {
index 53035aa..2848267 100644 (file)
@@ -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 (file)
index 0000000..a389cef
--- /dev/null
@@ -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 (file)
index 0000000..be5cef9
--- /dev/null
@@ -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 (file)
index 0000000..2ce1691
--- /dev/null
@@ -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:
+ */
index 31d9c34..5dcdad4 100644 (file)
@@ -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>
index d754c3a..494e1ab 100644 (file)
@@ -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)                                                   \
index 94732bb..735b31d 100644 (file)
@@ -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}
index 87565ed..d714a93 100644 (file)
@@ -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):
index 8ed80c3..9678771 100644 (file)
@@ -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
index 5ef0bdb..cc220d5 100644 (file)
@@ -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 (file)
index 0000000..6e5ade6
--- /dev/null
@@ -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
index 77a9d74..0df8cb2 100644 (file)
@@ -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
index 223ea4d..97359b1 100644 (file)
@@ -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
index 038a371..75ec57f 100644 (file)
@@ -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})