ipsec: handle UDP keepalives 77/20677/2
authorNeale Ranns <nranns@cisco.com>
Tue, 16 Jul 2019 13:19:35 +0000 (06:19 -0700)
committerNeale Ranns <nranns@cisco.com>
Tue, 16 Jul 2019 15:05:10 +0000 (15:05 +0000)
Type: feature

Change-Id: I87cc1168466f267e8c4bbec318401982f4bdf03a
Signed-off-by: Neale Ranns <nranns@cisco.com>
src/vnet/ipsec/esp.h
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_if_in.c
src/vnet/ipsec/ipsec_tun.c
src/vnet/ipsec/ipsec_tun_in.c
test/template_ipsec.py
test/test_ipsec_tun_if_esp.py
test/vpp_ipsec_tun_interface.py

index f36f52a..2ab7299 100644 (file)
 
 typedef struct
 {
-  u32 spi;
+  union
+  {
+    u32 spi;
+    u8 spi_bytes[4];
+  };
   u32 seq;
   u8 data[0];
 } esp_header_t;
index a5972bb..a7a6c0c 100644 (file)
@@ -942,6 +942,58 @@ VLIB_CLI_COMMAND (ipsec_tun_protect_show_node, static) =
 };
 /* *INDENT-ON* */
 
+static clib_error_t *
+ipsec_tun_protect_hash_show (vlib_main_t * vm,
+                            unformat_input_t * input,
+                            vlib_cli_command_t * cmd)
+{
+  ipsec_main_t *im = &ipsec_main;
+
+  {
+    ipsec_tun_lkup_result_t value;
+    ipsec4_tunnel_key_t key;
+
+    vlib_cli_output (vm, "IPv4:");
+
+    /* *INDENT-OFF* */
+    hash_foreach(key.as_u64, value.as_u64, im->tun4_protect_by_key,
+    ({
+      vlib_cli_output (vm, " %U", format_ipsec4_tunnel_key, &key);
+      vlib_cli_output (vm, "  tun:%d sa:%d", value.tun_index, value.sa_index);
+    }));
+    /* *INDENT-ON* */
+  }
+
+  {
+    ipsec_tun_lkup_result_t value;
+    ipsec6_tunnel_key_t *key;
+
+    vlib_cli_output (vm, "IPv6:");
+
+    /* *INDENT-OFF* */
+    hash_foreach_mem(key, value.as_u64, im->tun6_protect_by_key,
+    ({
+      vlib_cli_output (vm, " %U", format_ipsec6_tunnel_key, key);
+      vlib_cli_output (vm, "  tun:%d sa:%d", value.tun_index, value.sa_index);
+    }));
+    /* *INDENT-ON* */
+  }
+
+  return NULL;
+}
+
+/**
+ * show IPSEC tunnel protection hash tables
+ */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ipsec_tun_protect_hash_show_node, static) =
+{
+  .path = "show ipsec protect-hash",
+  .function = ipsec_tun_protect_hash_show,
+  .short_help =  "show ipsec protect-hash",
+};
+/* *INDENT-ON* */
+
 clib_error_t *
 ipsec_cli_init (vlib_main_t * vm)
 {
index 0d596c0..7a5e258 100644 (file)
@@ -259,9 +259,7 @@ format_ipsec_sa_flags (u8 * s, va_list * args)
 {
   ipsec_sa_flags_t flags = va_arg (*args, int);
 
-  if (0)
-    ;
-#define _(v, f, str) else if (flags & IPSEC_SA_FLAG_##f) s = format(s, "%s ", str);
+#define _(v, f, str) if (flags & IPSEC_SA_FLAG_##f) s = format(s, "%s ", str);
   foreach_ipsec_sa_flags
 #undef _
     return (s);
@@ -285,10 +283,8 @@ format_ipsec_sa (u8 * s, va_list * args)
 
   sa = pool_elt_at_index (im->sad, sai);
 
-  s = format (s, "[%d] sa %d (0x%x) spi %u (0x%08x) mode %s%s protocol %s %U",
+  s = format (s, "[%d] sa %u (0x%x) spi %u (0x%08x) protocol:%s flags:[%U]",
              sai, sa->id, sa->id, sa->spi, sa->spi,
-             ipsec_sa_is_set_IS_TUNNEL (sa) ? "tunnel" : "transport",
-             ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ? "-ip6" : "",
              sa->protocol ? "esp" : "ah", format_ipsec_sa_flags, sa->flags);
 
   if (!(flags & IPSEC_FORMAT_DETAIL))
@@ -402,6 +398,32 @@ done:
   return (s);
 }
 
+u8 *
+format_ipsec4_tunnel_key (u8 * s, va_list * args)
+{
+  ipsec4_tunnel_key_t *key = va_arg (*args, ipsec4_tunnel_key_t *);
+
+  s = format (s, "remote:%U spi:%u (0x%08x)",
+             format_ip4_address, &key->remote_ip,
+             clib_net_to_host_u32 (key->spi),
+             clib_net_to_host_u32 (key->spi));
+
+  return (s);
+}
+
+u8 *
+format_ipsec6_tunnel_key (u8 * s, va_list * args)
+{
+  ipsec6_tunnel_key_t *key = va_arg (*args, ipsec6_tunnel_key_t *);
+
+  s = format (s, "remote:%U spi:%u (0x%08x)",
+             format_ip6_address, &key->remote_ip,
+             clib_net_to_host_u32 (key->spi),
+             clib_net_to_host_u32 (key->spi));
+
+  return (s);
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index 562f40e..43997bc 100644 (file)
@@ -284,7 +284,7 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
 
   if (!is_ip6)
     {
-      key4.remote_ip = args->remote_ip.ip4.as_u32;
+      key4.remote_ip.as_u32 = args->remote_ip.ip4.as_u32;
       key4.spi = clib_host_to_net_u32 (args->remote_spi);
       p = hash_get (im->ipsec4_if_pool_index_by_key, key4.as_u64);
     }
@@ -375,8 +375,14 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
        hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key6,
                            t - im->tunnel_interfaces);
       else
-       hash_set (im->ipsec4_if_pool_index_by_key, key4.as_u64,
-                 t - im->tunnel_interfaces);
+       {
+         hash_set (im->ipsec4_if_pool_index_by_key, key4.as_u64,
+                   t - im->tunnel_interfaces);
+         if (1 == hash_elts (im->ipsec4_if_pool_index_by_key))
+           udp_register_dst_port (vlib_get_main (),
+                                  UDP_DST_PORT_ipsec,
+                                  ipsec4_if_input_node.index, 1);
+       }
 
       hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index,
                                             t - im->tunnel_interfaces,
@@ -427,9 +433,13 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
       if (is_ip6)
        hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key6);
       else
-       hash_unset (im->ipsec4_if_pool_index_by_key, key4.as_u64);
-
+       {
+         hash_unset (im->ipsec4_if_pool_index_by_key, key4.as_u64);
+         if (0 == hash_elts (im->ipsec4_if_pool_index_by_key))
+           udp_unregister_dst_port (vlib_get_main (), UDP_DST_PORT_ipsec, 1);
+       }
       hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance);
+
       im->ipsec_if_by_sw_if_index[t->sw_if_index] = ~0;
 
       /* delete input and output SA */
@@ -506,7 +516,7 @@ ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
          ipsec4_tunnel_key_t key;
 
          /* unset old inbound hash entry. packets should stop arriving */
-         key.remote_ip = old_sa->tunnel_src_addr.ip4.as_u32;
+         key.remote_ip.as_u32 = old_sa->tunnel_src_addr.ip4.as_u32;
          key.spi = clib_host_to_net_u32 (old_sa->spi);
 
          p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64);
@@ -515,7 +525,7 @@ ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
 
          /* set new inbound SA, then set new hash entry */
          t->input_sa_index = sa_index;
-         key.remote_ip = sa->tunnel_src_addr.ip4.as_u32;
+         key.remote_ip.as_u32 = sa->tunnel_src_addr.ip4.as_u32;
          key.spi = clib_host_to_net_u32 (sa->spi);
 
          hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64,
@@ -572,9 +582,6 @@ ipsec_tunnel_if_init (vlib_main_t * vm)
                                                     sizeof (uword));
   im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword));
 
-  udp_register_dst_port (vm, UDP_DST_PORT_ipsec, ipsec4_if_input_node.index,
-                        1);
-
   /* set up feature nodes to drop outbound packets with no crypto alg set */
   ipsec_add_feature ("ip4-output", "esp4-no-crypto",
                     &im->esp4_no_crypto_tun_feature_index);
index 042ddde..ecaf3c9 100644 (file)
@@ -64,7 +64,7 @@ typedef CLIB_PACKED
    */
   union {
     struct {
-      u32 remote_ip;
+      ip4_address_t remote_ip;
       u32 spi;
     };
     u64 as_u64;
@@ -84,6 +84,9 @@ typedef CLIB_PACKED
 }) ipsec6_tunnel_key_t;
 /* *INDENT-ON* */
 
+extern u8 *format_ipsec4_tunnel_key (u8 * s, va_list * args);
+extern u8 *format_ipsec6_tunnel_key (u8 * s, va_list * args);
+
 extern int ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
                                             ipsec_add_del_tunnel_args_t *
                                             args, u32 * sw_if_index);
index fea25fe..f9341d6 100644 (file)
@@ -29,6 +29,8 @@
 _(RX, "good packets received")                                   \
 _(DISABLED, "ipsec packets received on disabled interface")       \
 _(NO_TUNNEL, "no matching tunnel")                                \
+_(NAT_KEEPALIVE, "NAT Keepalive")                                 \
+_(TOO_SHORT, "Too Short")                                         \
 _(SPI_0, "SPI 0")
 
 static char *ipsec_if_input_error_strings[] = {
@@ -48,7 +50,12 @@ typedef enum
 
 typedef struct
 {
-  u32 spi;
+  union
+  {
+    ipsec4_tunnel_key_t key4;
+    ipsec6_tunnel_key_t key6;
+  };
+  u8 is_ip6;
   u32 seq;
 } ipsec_if_input_trace_t;
 
@@ -59,7 +66,12 @@ format_ipsec_if_input_trace (u8 * s, va_list * args)
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
   ipsec_if_input_trace_t *t = va_arg (*args, ipsec_if_input_trace_t *);
 
-  s = format (s, "IPSec: spi %u (0x%08x) seq %u", t->spi, t->spi, t->seq);
+  if (t->is_ip6)
+    s = format (s, "IPSec: %U seq %u",
+               format_ipsec6_tunnel_key, &t->key6, t->seq);
+  else
+    s = format (s, "IPSec: %U seq %u",
+               format_ipsec4_tunnel_key, &t->key4, t->seq);
   return s;
 }
 
@@ -215,6 +227,19 @@ ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       len0 = vlib_buffer_length_in_chain (vm, b[0]);
       len1 = vlib_buffer_length_in_chain (vm, b[1]);
 
+      /* If the packet is too short to contain an SPI, then maybe
+       * it's a keep alive */
+      if (len0 < sizeof (esp_header_t))
+       {
+         if (esp0->spi_bytes[0] == 0xff)
+           b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_NAT_KEEPALIVE];
+         else
+           b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_TOO_SHORT];
+
+         next[0] = IPSEC_INPUT_NEXT_DROP;
+         goto pkt1;
+       }
+
       if (is_ip6)
        {
          key60.remote_ip = ip60->src_address;
@@ -245,7 +270,7 @@ ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
        }
       else                     /* !is_ip6 */
        {
-         key40.remote_ip = ip40->src_address.as_u32;
+         key40.remote_ip = ip40->src_address;
          key40.spi = esp0->spi;
 
          if (key40.as_u64 == last_key4.as_u64)
@@ -312,6 +337,18 @@ ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
        }
 
     pkt1:
+
+      if (len1 < sizeof (esp_header_t))
+       {
+         if (esp0->spi_bytes[0] == 0xff)
+           b[1]->error = node->errors[IPSEC_IF_INPUT_ERROR_NAT_KEEPALIVE];
+         else
+           b[1]->error = node->errors[IPSEC_IF_INPUT_ERROR_TOO_SHORT];
+
+         next[1] = IPSEC_INPUT_NEXT_DROP;
+         goto trace1;
+       }
+
       if (is_ip6)
        {
          key61.remote_ip = ip61->src_address;
@@ -342,7 +379,7 @@ ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
        }
       else                     /* !is_ip6 */
        {
-         key41.remote_ip = ip41->src_address.as_u32;
+         key41.remote_ip = ip41->src_address;
          key41.spi = esp1->spi;
 
          if (key41.as_u64 == last_key4.as_u64)
@@ -415,14 +452,22 @@ ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            {
              ipsec_if_input_trace_t *tr =
                vlib_add_trace (vm, node, b[0], sizeof (*tr));
-             tr->spi = clib_host_to_net_u32 (esp0->spi);
+             if (is_ip6)
+               clib_memcpy (&tr->key6, &key60, sizeof (tr->key6));
+             else
+               clib_memcpy (&tr->key4, &key40, sizeof (tr->key4));
+             tr->is_ip6 = is_ip6;
              tr->seq = clib_host_to_net_u32 (esp0->seq);
            }
          if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
            {
              ipsec_if_input_trace_t *tr =
                vlib_add_trace (vm, node, b[1], sizeof (*tr));
-             tr->spi = clib_host_to_net_u32 (esp1->spi);
+             if (is_ip6)
+               clib_memcpy (&tr->key6, &key61, sizeof (tr->key6));
+             else
+               clib_memcpy (&tr->key4, &key41, sizeof (tr->key4));
+             tr->is_ip6 = is_ip6;
              tr->seq = clib_host_to_net_u32 (esp1->seq);
            }
        }
@@ -477,6 +522,17 @@ ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       vlib_buffer_advance (b[0], buf_adv0);
       len0 = vlib_buffer_length_in_chain (vm, b[0]);
 
+      if (len0 < sizeof (esp_header_t))
+       {
+         if (esp0->spi_bytes[0] == 0xff)
+           b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_NAT_KEEPALIVE];
+         else
+           b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_TOO_SHORT];
+
+         next[0] = IPSEC_INPUT_NEXT_DROP;
+         goto trace00;
+       }
+
       if (is_ip6)
        {
          key60.remote_ip = ip60->src_address;
@@ -507,7 +563,7 @@ ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
        }
       else                     /* !is_ip6 */
        {
-         key40.remote_ip = ip40->src_address.as_u32;
+         key40.remote_ip = ip40->src_address;
          key40.spi = esp0->spi;
 
          if (key40.as_u64 == last_key4.as_u64)
@@ -580,7 +636,11 @@ ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            {
              ipsec_if_input_trace_t *tr =
                vlib_add_trace (vm, node, b[0], sizeof (*tr));
-             tr->spi = clib_host_to_net_u32 (esp0->spi);
+             if (is_ip6)
+               clib_memcpy (&tr->key6, &key60, sizeof (tr->key6));
+             else
+               clib_memcpy (&tr->key4, &key40, sizeof (tr->key4));
+             tr->is_ip6 = is_ip6;
              tr->seq = clib_host_to_net_u32 (esp0->seq);
            }
        }
index 46980df..859fab8 100644 (file)
@@ -98,10 +98,14 @@ ipsec_tun_protect_db_add (ipsec_main_t * im, const ipsec_tun_protect_t * itp)
       if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
         {
           ipsec4_tunnel_key_t key = {
-            .remote_ip = itp->itp_crypto.dst.ip4.as_u32,
+            .remote_ip = itp->itp_crypto.dst.ip4,
             .spi = clib_host_to_net_u32 (sa->spi),
           };
           hash_set (im->tun4_protect_by_key, key.as_u64, res.as_u64);
+          if (1 == hash_elts(im->tun4_protect_by_key))
+            udp_register_dst_port (vlib_get_main(),
+                                   UDP_DST_PORT_ipsec,
+                                   ipsec4_tun_input_node.index, 1);
         }
       else
         {
@@ -127,10 +131,14 @@ ipsec_tun_protect_db_remove (ipsec_main_t * im,
       if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
         {
           ipsec4_tunnel_key_t key = {
-            .remote_ip = itp->itp_crypto.dst.ip4.as_u32,
+            .remote_ip = itp->itp_crypto.dst.ip4,
             .spi = clib_host_to_net_u32 (sa->spi),
           };
           hash_unset (im->tun4_protect_by_key, &key);
+          if (0 == hash_elts(im->tun4_protect_by_key))
+            udp_unregister_dst_port (vlib_get_main(),
+                                     UDP_DST_PORT_ipsec,
+                                     1);
         }
       else
         {
@@ -359,10 +367,10 @@ ipsec_tun_protect_del (u32 sw_if_index)
 
   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); */
+  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);
 }
index df6d927..04f7a92 100644 (file)
@@ -32,6 +32,8 @@
   _(DISABLED, "ipsec packets received on disabled interface")     \
   _(NO_TUNNEL, "no matching tunnel")                              \
   _(TUNNEL_MISMATCH, "SPI-tunnel mismatch")                       \
+  _(NAT_KEEPALIVE, "NAT Keepalive")                               \
+  _(TOO_SHORT, "Too Short")                                       \
   _(SPI_0, "SPI 0")
 
 static char *ipsec_tun_protect_input_error_strings[] = {
@@ -59,7 +61,12 @@ typedef enum ipsec_tun_next_t_
 
 typedef struct
 {
-  u32 spi;
+  union
+  {
+    ipsec4_tunnel_key_t key4;
+    ipsec6_tunnel_key_t key6;
+  };
+  u8 is_ip6;
   u32 seq;
 } ipsec_tun_protect_input_trace_t;
 
@@ -71,7 +78,12 @@ format_ipsec_tun_protect_input_trace (u8 * s, va_list * args)
   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);
+  if (t->is_ip6)
+    s = format (s, "IPSec: %U seq %u",
+               format_ipsec6_tunnel_key, &t->key6, t->seq);
+  else
+    s = format (s, "IPSec: %U seq %u",
+               format_ipsec4_tunnel_key, &t->key4, t->seq);
   return s;
 }
 
@@ -160,8 +172,10 @@ ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       ip4_header_t *ip40;
       ip6_header_t *ip60;
       esp_header_t *esp0;
+      u16 buf_rewind0;
 
-      ip40 = vlib_buffer_get_current (b[0]);
+      ip40 =
+       (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset);
 
       if (is_ip6)
        {
@@ -178,11 +192,12 @@ ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) +
                                  sizeof (udp_header_t));
              hdr_sz0 = 0;
+             buf_rewind0 = ip4_header_bytes (ip40) + sizeof (udp_header_t);
            }
          else
            {
              esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40));
-             hdr_sz0 = ip4_header_bytes (ip40);
+             buf_rewind0 = hdr_sz0 = ip4_header_bytes (ip40);
            }
        }
 
@@ -191,6 +206,19 @@ ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       vlib_buffer_advance (b[0], hdr_sz0);
       len0 = vlib_buffer_length_in_chain (vm, b[0]);
 
+      if (len0 < sizeof (esp_header_t))
+       {
+         if (esp0->spi_bytes[0] == 0xff)
+           b[0]->error =
+             node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NAT_KEEPALIVE];
+         else
+           b[0]->error =
+             node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_TOO_SHORT];
+
+         next[0] = IPSEC_INPUT_NEXT_DROP;
+         goto trace00;
+       }
+
       if (is_ip6)
        {
          key60.remote_ip = ip60->src_address;
@@ -219,7 +247,7 @@ ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
        }
       else
        {
-         key40.remote_ip = ip40->src_address.as_u32;
+         key40.remote_ip = ip40->src_address;
          key40.spi = esp0->spi;
 
          if (key40.as_u64 == last_key4.as_u64)
@@ -238,6 +266,7 @@ ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              else
                {
                  next[0] = ipsec_ip4_if_no_tunnel (node, b[0], esp0, ip40);
+                 vlib_buffer_advance (b[0], -buf_rewind0);
                  n_no_tunnel++;
                  goto trace00;
                }
@@ -342,7 +371,11 @@ ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            {
              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);
+             if (is_ip6)
+               clib_memcpy (&tr->key6, &key60, sizeof (tr->key6));
+             else
+               clib_memcpy (&tr->key4, &key40, sizeof (tr->key4));
+             tr->is_ip6 = is_ip6;
              tr->seq = clib_host_to_net_u32 (esp0->seq);
            }
        }
index d714a93..e40fa56 100644 (file)
@@ -558,6 +558,8 @@ class IpsecTun4(object):
     def verify_encrypted(self, p, sa, rxs):
         decrypt_pkts = []
         for rx in rxs:
+            if p.nat_header:
+                self.assertEqual(rx[UDP].dport, 4500)
             self.assert_packet_checksums_valid(rx)
             self.assertEqual(len(rx) - len(Ether()), rx[IP].len)
             try:
@@ -642,6 +644,23 @@ class IpsecTun4(object):
 
         self.verify_counters4(p, count)
 
+    def verify_keepalive(self, p):
+        pkt = (Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac) /
+               IP(src=p.remote_tun_if_host, dst=self.tun_if.local_ip4) /
+               UDP(sport=333, dport=4500) /
+               Raw(0xff))
+        self.send_and_assert_no_replies(self.tun_if, pkt*31)
+        self.assert_error_counter_equal(
+            '/err/%s/NAT Keepalive' % self.tun4_input_node, 31)
+
+        pkt = (Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac) /
+               IP(src=p.remote_tun_if_host, dst=self.tun_if.local_ip4) /
+               UDP(sport=333, dport=4500) /
+               Raw(0xfe))
+        self.send_and_assert_no_replies(self.tun_if, pkt*31)
+        self.assert_error_counter_equal(
+            '/err/%s/Too Short' % self.tun4_input_node, 31)
+
 
 class IpsecTun4Tests(IpsecTun4):
     """ UT test methods for Tunnel v4 """
index 20f1249..5cf311e 100644 (file)
@@ -63,6 +63,55 @@ class TemplateIpsec4TunIfEsp(TemplateIpsec):
         super(TemplateIpsec4TunIfEsp, self).tearDown()
 
 
+class TemplateIpsec4TunIfEspUdp(TemplateIpsec):
+    """ IPsec UDP tunnel interface tests """
+
+    tun4_encrypt_node_name = "esp4-encrypt-tun"
+    tun4_decrypt_node_name = "esp4-decrypt"
+    encryption_type = ESP
+
+    @classmethod
+    def setUpClass(cls):
+        super(TemplateIpsec4TunIfEspUdp, cls).setUpClass()
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TemplateIpsec4TunIfEspUdp, cls).tearDownClass()
+
+    def setUp(self):
+        super(TemplateIpsec4TunIfEspUdp, self).setUp()
+
+        self.tun_if = self.pg0
+
+        p = self.ipv4_params
+        p.flags = (VppEnum.vl_api_ipsec_sad_flags_t.
+                   IPSEC_API_SAD_FLAG_UDP_ENCAP)
+        p.nat_header = UDP(sport=5454, dport=4500)
+
+        p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
+                                        p.scapy_tun_spi, p.crypt_algo_vpp_id,
+                                        p.crypt_key, p.crypt_key,
+                                        p.auth_algo_vpp_id, p.auth_key,
+                                        p.auth_key, udp_encap=True)
+        p.tun_if.add_vpp_config()
+        p.tun_if.admin_up()
+        p.tun_if.config_ip4()
+        p.tun_if.config_ip6()
+
+        r = VppIpRoute(self, p.remote_tun_if_host, 32,
+                       [VppRoutePath(p.tun_if.remote_ip4,
+                                     0xffffffff)])
+        r.add_vpp_config()
+        r = VppIpRoute(self, p.remote_tun_if_host6, 128,
+                       [VppRoutePath(p.tun_if.remote_ip6,
+                                     0xffffffff,
+                                     proto=DpoProto.DPO_PROTO_IP6)])
+        r.add_vpp_config()
+
+    def tearDown(self):
+        super(TemplateIpsec4TunIfEspUdp, self).tearDown()
+
+
 class TestIpsec4TunIfEsp1(TemplateIpsec4TunIfEsp, IpsecTun4Tests):
     """ Ipsec ESP - TUN tests """
     tun4_encrypt_node_name = "esp4-encrypt-tun"
@@ -94,6 +143,16 @@ class TestIpsec4TunIfEsp1(TemplateIpsec4TunIfEsp, IpsecTun4Tests):
                                        [9000, 0, 0, 0])
 
 
+class TestIpsec4TunIfEspUdp(TemplateIpsec4TunIfEspUdp, IpsecTun4Tests):
+    """ Ipsec ESP UDP tests """
+
+    tun4_input_node = "ipsec4-if-input"
+
+    def test_keepalive(self):
+        """ IPSEC NAT Keepalive """
+        self.verify_keepalive(self.ipv4_params)
+
+
 class TestIpsec4TunIfEsp2(TemplateIpsec4TunIfEsp, IpsecTcpTests):
     """ Ipsec ESP - TCP tests """
     pass
@@ -661,19 +720,26 @@ class TestIpsecGreIfEsp(TemplateIpsec,
 class TemplateIpsec4TunProtect(object):
     """ IPsec IPv4 Tunnel protect """
 
+    encryption_type = ESP
+    tun4_encrypt_node_name = "esp4-encrypt-tun"
+    tun4_decrypt_node_name = "esp4-decrypt-tun"
+    tun4_input_node = "ipsec4-tun-input"
+
     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)
+                                  self.vpp_esp_protocol,
+                                  flags=p.flags)
         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.vpp_esp_protocol,
+                                 flags=p.flags)
         p.tun_sa_in.add_vpp_config()
 
     def config_sa_tun(self, p):
@@ -684,7 +750,8 @@ class TemplateIpsec4TunProtect(object):
                                   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])
+                                  self.tun_if.local_addr[p.addr_type],
+                                  flags=p.flags)
         p.tun_sa_out.add_vpp_config()
 
         p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
@@ -692,7 +759,8 @@ class TemplateIpsec4TunProtect(object):
                                  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])
+                                 self.tun_if.local_addr[p.addr_type],
+                                 flags=p.flags)
         p.tun_sa_in.add_vpp_config()
 
     def config_protect(self, p):
@@ -732,10 +800,6 @@ class TestIpsec4TunProtect(TemplateIpsec,
                            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()
 
@@ -785,6 +849,47 @@ class TestIpsec4TunProtect(TemplateIpsec,
         self.unconfig_network(p)
 
 
+class TestIpsec4TunProtectUdp(TemplateIpsec,
+                              TemplateIpsec4TunProtect,
+                              IpsecTun4):
+    """ IPsec IPv4 Tunnel protect - transport mode"""
+
+    def setUp(self):
+        super(TestIpsec4TunProtectUdp, self).setUp()
+
+        self.tun_if = self.pg0
+
+        p = self.ipv4_params
+        p.flags = (VppEnum.vl_api_ipsec_sad_flags_t.
+                   IPSEC_API_SAD_FLAG_UDP_ENCAP)
+        p.nat_header = UDP(sport=5454, dport=4500)
+        self.config_network(p)
+        self.config_sa_tra(p)
+        self.config_protect(p)
+
+    def tearDown(self):
+        p = self.ipv4_params
+        self.unconfig_protect(p)
+        self.unconfig_sa(p)
+        self.unconfig_network(p)
+        super(TestIpsec4TunProtectUdp, self).tearDown()
+
+    def test_tun_44(self):
+        """IPSEC UDP tunnel protect"""
+
+        p = self.ipv4_params
+
+        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)
+
+    def test_keepalive(self):
+        """ IPSEC NAT Keepalive """
+        self.verify_keepalive(self.ipv4_params)
+
+
 class TestIpsec4TunProtectTun(TemplateIpsec,
                               TemplateIpsec4TunProtect,
                               IpsecTun4):
index 97359b1..c561a1f 100644 (file)
@@ -27,7 +27,7 @@ class VppIpsecTunInterface(VppTunnelInterface):
         else:
             self.local_ip = self.parent_if.local_ip4
             self.remote_ip = self.parent_if.remote_ip4
-        self.udp_encap = False
+        self.udp_encap = udp_encap
 
     def add_vpp_config(self):
         r = self.test.vapi.ipsec_tunnel_if_add_del(