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 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
 - @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));
 }
 
   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)
 {
 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)                \
  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)                                       \
 _(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;
 }
 
   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)
 {
 static int
 api_set_punt (vat_main_t * vam)
 {
@@ -20173,99 +20090,6 @@ api_set_punt (vat_main_t * vam)
   return ret;
 }
 
   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)
 {
 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>]")                               \
 _(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"                                       \
 _(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_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
   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_if_in.c
   ipsec/ipsec_output.c
   ipsec/ipsec_input.c
+  ipsec/ipsec_tun_in.c
 )
 
 list(APPEND VNET_API_FILES ipsec/ipsec.api)
 )
 
 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)
 
 
 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
 ##############################################################################
 ##############################################################################
 # LISP control plane: lisp-cp
 ##############################################################################
index 6738f3c..812fe74 100644 (file)
@@ -276,6 +276,7 @@ typedef struct
     struct
     {
       u32 sad_index;
     struct
     {
       u32 sad_index;
+      u32 protect_index;
     } ipsec;
 
     /* MAP */
     } ipsec;
 
     /* MAP */
index 72c76fc..ab2567d 100644 (file)
@@ -530,6 +530,29 @@ format_gre_device (u8 * s, va_list * args)
   return s;
 }
 
   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",
 /* *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,
   .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
 #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);
 }
 
      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)
 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 vnet_main_t;
 struct vnet_hw_interface_t;
 struct vnet_sw_interface_t;
-struct ip46_address_t;
+union ip46_address_t_;
 
 typedef enum
 {
 
 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)
 
 #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
 {
 /* 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;
 
   /* 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);
 
   /* 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);
 
 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);
 /* 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* */
 } ip46_type_t;
 
 /* *INDENT-OFF* */
-typedef CLIB_PACKED (union {
+typedef CLIB_PACKED (union ip46_address_t_ {
   struct {
     u32 pad[3];
     ip4_address_t ip4;
   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 }}}
 
                                          && ((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)
 {
 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;
 }
 
   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",
 /* *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,
     .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
 #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,
     {
     /* *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
     /* *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")    \
 #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
 
 #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))
       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.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")           \
 
 #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
 
 #define _(v, s) ESP_DECRYPT_NEXT_##v,
 typedef enum
@@ -93,7 +93,7 @@ typedef struct
     {
       u8 icv_sz;
       u8 iv_sz;
     {
       u8 icv_sz;
       u8 iv_sz;
-      ipsec_sa_flags_t flags:8;
+      ipsec_sa_flags_t flags;
       u32 sa_index;
     };
     u64 sa_data;
       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,
 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;
 {
   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;
 
       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;
        {
          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];
            {
              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))
        {
     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)
 {
                                  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* */
 }
 
 /* *INDENT-OFF* */
@@ -497,16 +556,7 @@ VLIB_REGISTER_NODE (esp4_decrypt_node) = {
 #undef _
   },
 };
 #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),
 VLIB_REGISTER_NODE (esp6_decrypt_node) = {
   .name = "esp6-decrypt",
   .vector_size = sizeof (u32),
@@ -523,6 +573,40 @@ VLIB_REGISTER_NODE (esp6_decrypt_node) = {
 #undef _
   },
 };
 #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* */
 
 /*
 /* *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 */
          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)
          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);
            }
 
                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;
        }
 
       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"),
 };
   .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,
 /* *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";
 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
 
 /** \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;
 };
 
   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
 /** \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 *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;
 
   /* 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>
 
 #if WITH_LIBSSL > 0
 #include <vnet/ipsec/ipsec.h>
+#include <vnet/ipsec/ipsec_tun.h>
 #endif /* IPSEC */
 
 #define vl_typedefs            /* define message structures */
 #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_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)
 
 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);
 }
 
   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)
 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 _
 
   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
    */
   /*
    * 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/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,
 
 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))
        ;
        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;
        ;
       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;
 }
 
   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,
 };
 /* *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 *
 /* *INDENT-ON* */
 
 static clib_error_t *
@@ -823,6 +864,88 @@ VLIB_CLI_COMMAND (create_ipsec_tunnel_command, static) = {
 };
 /* *INDENT-ON* */
 
 };
 /* *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)
 {
 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/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)
 
 u8 *
 format_ipsec_policy_action (u8 * s, va_list * args)
@@ -368,6 +369,40 @@ done:
   return (s);
 }
 
   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
  *
 /*
  * 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)
  */
 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;
 
   /*
   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)
   {
    */
   FOR_EACH_FIB_IP_PROTOCOL (proto)
   {
@@ -433,86 +433,6 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
   return 0;
 }
 
   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)
 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* */
 
 }) 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_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);
 
 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")
 
   _ (PUNT, "punt-dispatch")        \
   _ (DROP, "error-drop")
 
-#define _(v, s) IPSEC_INPUT_NEXT_##v,
 typedef enum
 {
 typedef enum
 {
+#define _(v, s) IPSEC_INPUT_NEXT_##v,
   foreach_ipsec_input_next
 #undef _
     IPSEC_INPUT_N_NEXT,
   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/esp.h>
 #include <vnet/udp/udp.h>
 #include <vnet/fib/fib_table.h>
+#include <vnet/ipsec/ipsec_tun.h>
 
 /**
  * @brief
 
 /**
  * @brief
@@ -292,7 +293,7 @@ ipsec_sa_del (u32 id)
     {
       clib_warning ("sa_id %u used in policy", sa->id);
       /* sa used in policy */
     {
       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);
     }
   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;
 }
 
   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;
 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;
   ipsec_tunnel_if_t *t;
   ipsec_policy_t *p;
+  u32 sai;
 
   /* *INDENT-OFF* */
   pool_foreach(p, im->policies, ({
 
   /* *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;
   }));
     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* */
 
   /* *INDENT-ON* */
 
+
   return 0;
 }
 
   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 = {
  * 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")                          \
   _ (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")                                \
 
   _ (64, IS_INBOUND, "inboud")                            \
   _ (128, IS_AEAD, "aead")                                \
 
@@ -183,6 +183,13 @@ foreach_ipsec_sa_flags
   }
   foreach_ipsec_sa_flags
 #undef _
   }
   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
 /**
  * @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);
                         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,
 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/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>
 #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;
 }
 
   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)
 {
 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)                     \
 _(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)                                                   \
 _(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}
  * 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}
  * 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 """
 
 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))
             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)
 
             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 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:
         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)
                                                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,
             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"))
         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 """
 
     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"))
         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):
 
 
 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 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, \
 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
 
 from vpp_ip import DpoProto
 from vpp_papi import VppEnum
 
+NUM_PKTS = 67
+
 
 class ConfigIpsecESP(TemplateIpsec):
     encryption_type = ESP
 
 class ConfigIpsecESP(TemplateIpsec):
     encryption_type = ESP
@@ -350,6 +352,8 @@ class TestIpsecEspUdp(TemplateIpsecEspUdp, IpsecTra4Tests):
     pass
 
 
     pass
 
 
+@unittest.skipIf(is_skip_aarch64_set and is_platform_aarch64,
+                 "test doesn't work on aarch64")
 class TestIpsecEspAll(ConfigIpsecESP,
                       IpsecTra4, IpsecTra6,
                       IpsecTun4, IpsecTun6):
 class TestIpsecEspAll(ConfigIpsecESP,
                       IpsecTra4, IpsecTra6,
                       IpsecTun4, IpsecTun6):
@@ -470,10 +474,12 @@ class TestIpsecEspAll(ConfigIpsecESP,
                     #  An exhautsive 4o6, 6o4 is not necessary
                     #  for each algo
                     #
                     #  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
 
                     #
                     # 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.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 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_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
 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):
         r.add_vpp_config()
 
     def tearDown(self):
-        if not self.vpp_dead:
-            self.vapi.cli("show hardware")
         super(TemplateIpsec4TunIfEsp, self).tearDown()
 
 
         super(TemplateIpsec4TunIfEsp, self).tearDown()
 
 
@@ -131,8 +131,6 @@ class TemplateIpsec6TunIfEsp(TemplateIpsec):
         r.add_vpp_config()
 
     def tearDown(self):
         r.add_vpp_config()
 
     def tearDown(self):
-        if not self.vpp_dead:
-            self.vapi.cli("show hardware")
         super(TemplateIpsec6TunIfEsp, self).tearDown()
 
 
         super(TemplateIpsec6TunIfEsp, self).tearDown()
 
 
@@ -198,8 +196,6 @@ class TestIpsec4MultiTunIfEsp(TemplateIpsec, IpsecTun4):
                                      0xffffffff)]).add_vpp_config()
 
     def tearDown(self):
                                      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):
         super(TestIpsec4MultiTunIfEsp, self).tearDown()
 
     def test_tun_44(self):
@@ -442,8 +438,6 @@ class TestIpsec6MultiTunIfEsp(TemplateIpsec, IpsecTun6):
             r.add_vpp_config()
 
     def tearDown(self):
             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):
         super(TestIpsec6MultiTunIfEsp, self).tearDown()
 
     def test_tun_66(self):
@@ -456,9 +450,13 @@ class TestIpsec6MultiTunIfEsp(TemplateIpsec, IpsecTun6):
             self.assertEqual(c['packets'], 127)
 
 
             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"
 
     encryption_type = ESP
     omac = "00:11:22:33:44:55"
 
@@ -509,7 +507,7 @@ class TemplateIpsecGRETunIfEsp(TemplateIpsec):
                 raise
 
     def setUp(self):
                 raise
 
     def setUp(self):
-        super(TemplateIpsecGRETunIfEsp, self).setUp()
+        super(TestIpsecGreTebIfEsp, self).setUp()
 
         self.tun_if = self.pg0
 
 
         self.tun_if = self.pg0
 
@@ -534,33 +532,634 @@ class TemplateIpsecGRETunIfEsp(TemplateIpsec):
                                  self.pg0.local_ip4)
         p.tun_sa_in.add_vpp_config()
 
                                  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()
         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()
 
         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()
 
         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):
     def tearDown(self):
-        if not self.vpp_dead:
-            self.vapi.cli("show hardware")
         self.tun.unconfig_ip4()
         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 """
     """ 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)
 
 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]
     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
 
     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
             })
 
                 '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})
     def ipsec_select_backend(self, protocol, index):
         return self.api(self.papi.ipsec_select_backend,
                         {'protocol': protocol, 'index': index})