ipsec: Targeted unit testing 88/24088/4
authorNeale Ranns <nranns@cisco.com>
Fri, 20 Dec 2019 00:54:57 +0000 (00:54 +0000)
committerNeale Ranns <nranns@cisco.com>
Sat, 4 Jan 2020 04:50:47 +0000 (04:50 +0000)
Type: fix

1 - big packets; chained buffers and those without enoguh space to add
ESP header
2 - IPv6 extension headers in packets that are encrypted/decrypted
3 - Interface protection with SAs that have null algorithms

Signed-off-by: Neale Ranns <nranns@cisco.com>
Change-Id: Ie330861fb06a9b248d9dcd5c730e21326ac8e973

src/vnet/ipsec/esp_decrypt.c
src/vnet/ipsec/esp_encrypt.c
src/vnet/ipsec/ipsec.c
src/vnet/ipsec/ipsec.h
src/vnet/ipsec/ipsec_tun.c
src/vnet/ipsec/ipsec_tun_in.c
test/template_ipsec.py
test/test_ipsec_esp.py
test/test_ipsec_tun_if_esp.py

index 16ae3a3..ee53b01 100644 (file)
@@ -53,6 +53,7 @@ typedef enum
  _(OVERSIZED_HEADER, "buffer with oversized header (dropped)")  \
  _(NO_TAIL_SPACE, "no enough buffer tail space (dropped)")      \
  _(TUN_NO_PROTO, "no tunnel protocol")                          \
  _(OVERSIZED_HEADER, "buffer with oversized header (dropped)")  \
  _(NO_TAIL_SPACE, "no enough buffer tail space (dropped)")      \
  _(TUN_NO_PROTO, "no tunnel protocol")                          \
+ _(UNSUP_PAYLOAD, "unsupported payload")                        \
 
 
 typedef enum
 
 
 typedef enum
@@ -311,9 +312,10 @@ esp_decrypt_inline (vlib_main_t * vm,
       b += 1;
     }
 
       b += 1;
     }
 
-  vlib_increment_combined_counter (&ipsec_sa_counters, thread_index,
-                                  current_sa_index, current_sa_pkts,
-                                  current_sa_bytes);
+  if (PREDICT_TRUE (~0 != current_sa_index))
+    vlib_increment_combined_counter (&ipsec_sa_counters, thread_index,
+                                    current_sa_index, current_sa_pkts,
+                                    current_sa_bytes);
 
   if ((n = vec_len (ptd->integ_ops)))
     {
 
   if ((n = vec_len (ptd->integ_ops)))
     {
@@ -513,6 +515,8 @@ esp_decrypt_inline (vlib_main_t * vm,
                      next[0] = ESP_DECRYPT_NEXT_IP6_INPUT;
                      break;
                    default:
                      next[0] = ESP_DECRYPT_NEXT_IP6_INPUT;
                      break;
                    default:
+                     b[0]->error =
+                       node->errors[ESP_DECRYPT_ERROR_UNSUP_PAYLOAD];
                      next[0] = ESP_DECRYPT_NEXT_DROP;
                      break;
                    }
                      next[0] = ESP_DECRYPT_NEXT_DROP;
                      break;
                    }
@@ -520,8 +524,7 @@ esp_decrypt_inline (vlib_main_t * vm,
              else
                {
                  next[0] = ESP_DECRYPT_NEXT_DROP;
              else
                {
                  next[0] = ESP_DECRYPT_NEXT_DROP;
-                 b[0]->error =
-                   node->errors[ESP_DECRYPT_ERROR_DECRYPTION_FAILED];
+                 b[0]->error = node->errors[ESP_DECRYPT_ERROR_UNSUP_PAYLOAD];
                  goto trace;
                }
            }
                  goto trace;
                }
            }
@@ -530,8 +533,20 @@ esp_decrypt_inline (vlib_main_t * vm,
              if (ipsec_sa_is_set_IS_PROTECT (sa0))
                {
                  /*
              if (ipsec_sa_is_set_IS_PROTECT (sa0))
                {
                  /*
-                  * Check that the reveal IP header matches that
-                  * of the tunnel we are protecting
+                  * 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.
                   */
                  const ipsec_tun_protect_t *itp;
 
                   */
                  const ipsec_tun_protect_t *itp;
 
index 4f1bb80..3c2fdf4 100644 (file)
@@ -176,17 +176,19 @@ ext_hdr_is_pre_esp (u8 nexthdr)
 }
 
 static_always_inline u8
 }
 
 static_always_inline u8
-esp_get_ip6_hdr_len (ip6_header_t * ip6)
+esp_get_ip6_hdr_len (ip6_header_t * ip6, ip6_ext_header_t ** ext_hdr)
 {
   /* this code assumes that HbH, route and frag headers will be before
      others, if that is not the case, they will end up encrypted */
 {
   /* this code assumes that HbH, route and frag headers will be before
      others, if that is not the case, they will end up encrypted */
-
   u8 len = sizeof (ip6_header_t);
   ip6_ext_header_t *p;
 
   /* if next packet doesn't have ext header */
   if (ext_hdr_is_pre_esp (ip6->protocol) == 0)
   u8 len = sizeof (ip6_header_t);
   ip6_ext_header_t *p;
 
   /* if next packet doesn't have ext header */
   if (ext_hdr_is_pre_esp (ip6->protocol) == 0)
-    return len;
+    {
+      *ext_hdr = NULL;
+      return len;
+    }
 
   p = (void *) (ip6 + 1);
   len += ip6_ext_header_len (p);
 
   p = (void *) (ip6 + 1);
   len += ip6_ext_header_len (p);
@@ -197,6 +199,7 @@ esp_get_ip6_hdr_len (ip6_header_t * ip6)
       p = ip6_ext_next_header (p);
     }
 
       p = ip6_ext_next_header (p);
     }
 
+  *ext_hdr = p;
   return len;
 }
 
   return len;
 }
 
@@ -401,11 +404,12 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       else                     /* transport mode */
        {
          u8 *l2_hdr, l2_len, *ip_hdr, ip_len;
       else                     /* transport mode */
        {
          u8 *l2_hdr, l2_len, *ip_hdr, ip_len;
+         ip6_ext_header_t *ext_hdr;
          udp_header_t *udp = 0;
          u8 *old_ip_hdr = vlib_buffer_get_current (b[0]);
 
          ip_len = is_ip6 ?
          udp_header_t *udp = 0;
          u8 *old_ip_hdr = vlib_buffer_get_current (b[0]);
 
          ip_len = is_ip6 ?
-           esp_get_ip6_hdr_len ((ip6_header_t *) old_ip_hdr) :
+           esp_get_ip6_hdr_len ((ip6_header_t *) old_ip_hdr, &ext_hdr) :
            ip4_header_bytes ((ip4_header_t *) old_ip_hdr);
 
          vlib_buffer_advance (b[0], ip_len);
            ip4_header_bytes ((ip4_header_t *) old_ip_hdr);
 
          vlib_buffer_advance (b[0], ip_len);
@@ -445,21 +449,27 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          else
            l2_len = 0;
 
          else
            l2_len = 0;
 
-         clib_memcpy_le64 (ip_hdr, old_ip_hdr, ip_len);
-
          if (is_ip6)
            {
          if (is_ip6)
            {
-             ip6_header_t *ip6 = (ip6_header_t *) (ip_hdr);
-             *next_hdr_ptr = ip6->protocol;
-             ip6->protocol = IP_PROTOCOL_IPSEC_ESP;
+             ip6_header_t *ip6 = (ip6_header_t *) (old_ip_hdr);
+             if (PREDICT_TRUE (NULL == ext_hdr))
+               {
+                 *next_hdr_ptr = ip6->protocol;
+                 ip6->protocol = IP_PROTOCOL_IPSEC_ESP;
+               }
+             else
+               {
+                 *next_hdr_ptr = ext_hdr->next_hdr;
+                 ext_hdr->next_hdr = IP_PROTOCOL_IPSEC_ESP;
+               }
              ip6->payload_length =
                clib_host_to_net_u16 (payload_len + hdr_len - l2_len -
              ip6->payload_length =
                clib_host_to_net_u16 (payload_len + hdr_len - l2_len -
-                                     ip_len);
+                                     sizeof (ip6_header_t));
            }
          else
            {
              u16 len;
            }
          else
            {
              u16 len;
-             ip4_header_t *ip4 = (ip4_header_t *) (ip_hdr);
+             ip4_header_t *ip4 = (ip4_header_t *) (old_ip_hdr);
              *next_hdr_ptr = ip4->protocol;
              len = payload_len + hdr_len - l2_len;
              if (udp)
              *next_hdr_ptr = ip4->protocol;
              len = payload_len + hdr_len - l2_len;
              if (udp)
@@ -471,6 +481,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);
            }
 
+         clib_memcpy_le64 (ip_hdr, old_ip_hdr, ip_len);
+
          if (!is_tun)
            next[0] = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
        }
          if (!is_tun)
            next[0] = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
        }
index 0f4f282..1075fe4 100644 (file)
@@ -188,9 +188,13 @@ ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im,
                  &b->esp6_decrypt_node_index, &b->esp6_decrypt_next_index);
 
   ipsec_add_feature ("ip4-output", esp4_encrypt_node_tun_name,
                  &b->esp6_decrypt_node_index, &b->esp6_decrypt_next_index);
 
   ipsec_add_feature ("ip4-output", esp4_encrypt_node_tun_name,
-                    &b->esp4_encrypt_tun_feature_index);
+                    &b->esp44_encrypt_tun_feature_index);
+  ipsec_add_feature ("ip4-output", esp6_encrypt_node_tun_name,
+                    &b->esp46_encrypt_tun_feature_index);
   ipsec_add_feature ("ip6-output", esp6_encrypt_node_tun_name,
   ipsec_add_feature ("ip6-output", esp6_encrypt_node_tun_name,
-                    &b->esp6_encrypt_tun_feature_index);
+                    &b->esp66_encrypt_tun_feature_index);
+  ipsec_add_feature ("ip6-output", esp4_encrypt_node_tun_name,
+                    &b->esp64_encrypt_tun_feature_index);
 
   b->check_support_cb = esp_check_support_cb;
   b->add_del_sa_sess_cb = esp_add_del_sa_sess_cb;
 
   b->check_support_cb = esp_check_support_cb;
   b->add_del_sa_sess_cb = esp_add_del_sa_sess_cb;
@@ -252,8 +256,10 @@ ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx)
   im->esp6_encrypt_next_index = b->esp6_encrypt_next_index;
   im->esp6_decrypt_next_index = b->esp6_decrypt_next_index;
 
   im->esp6_encrypt_next_index = b->esp6_encrypt_next_index;
   im->esp6_decrypt_next_index = b->esp6_decrypt_next_index;
 
-  im->esp4_encrypt_tun_feature_index = b->esp4_encrypt_tun_feature_index;
-  im->esp6_encrypt_tun_feature_index = b->esp6_encrypt_tun_feature_index;
+  im->esp44_encrypt_tun_feature_index = b->esp44_encrypt_tun_feature_index;
+  im->esp64_encrypt_tun_feature_index = b->esp64_encrypt_tun_feature_index;
+  im->esp46_encrypt_tun_feature_index = b->esp46_encrypt_tun_feature_index;
+  im->esp66_encrypt_tun_feature_index = b->esp66_encrypt_tun_feature_index;
 
   return 0;
 }
 
   return 0;
 }
index af75841..65b888e 100644 (file)
@@ -61,8 +61,10 @@ typedef struct
   u32 esp6_decrypt_node_index;
   u32 esp6_encrypt_next_index;
   u32 esp6_decrypt_next_index;
   u32 esp6_decrypt_node_index;
   u32 esp6_encrypt_next_index;
   u32 esp6_decrypt_next_index;
-  u32 esp4_encrypt_tun_feature_index;
-  u32 esp6_encrypt_tun_feature_index;
+  u32 esp44_encrypt_tun_feature_index;
+  u32 esp46_encrypt_tun_feature_index;
+  u32 esp66_encrypt_tun_feature_index;
+  u32 esp64_encrypt_tun_feature_index;
 } ipsec_esp_backend_t;
 
 typedef struct
 } ipsec_esp_backend_t;
 
 typedef struct
@@ -135,8 +137,10 @@ typedef struct
   u32 ah6_decrypt_next_index;
 
   /* tun encrypt arcs and feature nodes */
   u32 ah6_decrypt_next_index;
 
   /* tun encrypt arcs and feature nodes */
-  u32 esp4_encrypt_tun_feature_index;
-  u32 esp6_encrypt_tun_feature_index;
+  u32 esp44_encrypt_tun_feature_index;
+  u32 esp64_encrypt_tun_feature_index;
+  u32 esp46_encrypt_tun_feature_index;
+  u32 esp66_encrypt_tun_feature_index;
 
   /* tun nodes to drop packets when no crypto alg set on outbound SA */
   u32 esp4_no_crypto_tun_feature_index;
 
   /* tun nodes to drop packets when no crypto alg set on outbound SA */
   u32 esp4_no_crypto_tun_feature_index;
index ca0091b..f6b09d6 100644 (file)
@@ -35,35 +35,61 @@ typedef struct ipsec_protect_db_t_
 
 static ipsec_protect_db_t ipsec_protect_db;
 
 
 static ipsec_protect_db_t ipsec_protect_db;
 
-static int
+static void
 ipsec_tun_protect_feature_set (ipsec_tun_protect_t * itp, u8 enable)
 {
 ipsec_tun_protect_feature_set (ipsec_tun_protect_t * itp, u8 enable)
 {
-  u32 sai = itp->itp_out_sa;
-  int rv;
+  u32 sai;
 
 
-  const char *enc_node = (ip46_address_is_ip4 (&itp->itp_tun.src) ?
-                         "esp4-encrypt-tun" : "esp6-encrypt-tun");
+  sai = itp->itp_out_sa;
 
   if (itp->itp_flags & IPSEC_PROTECT_L2)
     {
 
   if (itp->itp_flags & IPSEC_PROTECT_L2)
     {
-      rv = vnet_feature_enable_disable ("ethernet-output",
-                                       enc_node,
-                                       itp->itp_sw_if_index, enable,
-                                       &sai, sizeof (sai));
+      /* l2-GRE only supported by the vnet ipsec code */
+      vnet_feature_enable_disable ("ethernet-output",
+                                  (ip46_address_is_ip4 (&itp->itp_tun.src) ?
+                                   "esp4-encrypt-tun" :
+                                   "esp6-encrypt-tun"),
+                                  itp->itp_sw_if_index, enable,
+                                  &sai, sizeof (sai));
     }
   else
     {
     }
   else
     {
-      rv = vnet_feature_enable_disable ("ip4-output",
-                                       enc_node,
-                                       itp->itp_sw_if_index, enable,
-                                       &sai, sizeof (sai));
-      rv = vnet_feature_enable_disable ("ip6-output",
-                                       enc_node,
-                                       itp->itp_sw_if_index, enable,
-                                       &sai, sizeof (sai));
+      ipsec_main_t *im;
+      ipsec_sa_t *sa;
+      u32 fi4, fi6;
+
+      im = &ipsec_main;
+      sa = ipsec_sa_get (sai);
+
+      if (sa->crypto_alg == IPSEC_CRYPTO_ALG_NONE &&
+         sa->integ_alg == IPSEC_INTEG_ALG_NONE)
+       {
+         fi4 = im->esp4_no_crypto_tun_feature_index;
+         fi6 = im->esp6_no_crypto_tun_feature_index;
+       }
+      else
+       {
+         if (ip46_address_is_ip4 (&itp->itp_tun.src))
+           {
+             /* tunnel destination is v4 so we need the Xo4 indexes */
+             fi4 = im->esp44_encrypt_tun_feature_index;
+             fi6 = im->esp64_encrypt_tun_feature_index;
+           }
+         else
+           {
+             /* tunnel destination is v6 so we need the Xo6 indexes */
+             fi4 = im->esp46_encrypt_tun_feature_index;
+             fi6 = im->esp66_encrypt_tun_feature_index;
+           }
+       }
+
+      vnet_feature_enable_disable_with_index
+       (vnet_get_feature_arc_index ("ip4-output"),
+        fi4, itp->itp_sw_if_index, enable, &sai, sizeof (sai));
+      vnet_feature_enable_disable_with_index
+       (vnet_get_feature_arc_index ("ip6-output"),
+        fi6, itp->itp_sw_if_index, enable, &sai, sizeof (sai));
     }
     }
-  ASSERT (!rv);
-  return (rv);
 }
 
 static void
 }
 
 static void
@@ -505,6 +531,12 @@ ipsec_tunnel_protect_init (vlib_main_t * vm)
                                             sizeof (u64));
   im->tun4_protect_by_key = hash_create (0, sizeof (u64));
 
                                             sizeof (u64));
   im->tun4_protect_by_key = hash_create (0, sizeof (u64));
 
+  /* 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);
+  ipsec_add_feature ("ip6-output", "esp6-no-crypto",
+                    &im->esp6_no_crypto_tun_feature_index);
+
   return 0;
 }
 
   return 0;
 }
 
index f25a763..e6ad67b 100644 (file)
@@ -311,58 +311,6 @@ ipsec_tun_protect_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              n_bytes = len0;
            }
 
              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:
          next[0] = IPSEC_TUN_PROTECT_NEXT_DECRYPT;
        }
     trace00:
index bcfc0d9..398a6bb 100644 (file)
@@ -6,7 +6,9 @@ from scapy.layers.inet import IP, ICMP, TCP, UDP
 from scapy.layers.ipsec import SecurityAssociation, ESP
 from scapy.layers.l2 import Ether
 from scapy.packet import Raw
 from scapy.layers.ipsec import SecurityAssociation, ESP
 from scapy.layers.l2 import Ether
 from scapy.packet import Raw
-from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest
+from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, IPv6ExtHdrHopByHop, \
+    IPv6ExtHdrFragment, IPv6ExtHdrDestOpt
+
 
 from framework import VppTestCase, VppTestRunner
 from util import ppp, reassemble4, fragment_rfc791, fragment_rfc8200
 
 from framework import VppTestCase, VppTestRunner
 from util import ppp, reassemble4, fragment_rfc791, fragment_rfc8200
@@ -641,6 +643,108 @@ class IpsecTra6(object):
         self.assert_packet_counter_equal(self.tra6_encrypt_node_name, count)
         self.assert_packet_counter_equal(self.tra6_decrypt_node_name, count)
 
         self.assert_packet_counter_equal(self.tra6_encrypt_node_name, count)
         self.assert_packet_counter_equal(self.tra6_decrypt_node_name, count)
 
+    def gen_encrypt_pkts_ext_hdrs6(self, sa, sw_intf, src, dst, count=1,
+                                   payload_size=54):
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                sa.encrypt(IPv6(src=src, dst=dst) /
+                           ICMPv6EchoRequest(id=0, seq=1,
+                                             data='X' * payload_size))
+                for i in range(count)]
+
+    def gen_pkts_ext_hdrs6(self, sw_intf, src, dst, count=1, payload_size=54):
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                IPv6(src=src, dst=dst) /
+                IPv6ExtHdrHopByHop() /
+                IPv6ExtHdrFragment(id=2, offset=200) /
+                Raw(b'\xff' * 200)
+                for i in range(count)]
+
+    def verify_tra_encrypted6(self, p, sa, rxs):
+        decrypted = []
+        for rx in rxs:
+            self.assert_packet_checksums_valid(rx)
+            try:
+                decrypt_pkt = p.vpp_tra_sa.decrypt(rx[IPv6])
+                decrypted.append(decrypt_pkt)
+                self.assert_equal(decrypt_pkt.src, self.tra_if.local_ip6)
+                self.assert_equal(decrypt_pkt.dst, self.tra_if.remote_ip6)
+            except:
+                self.logger.debug(ppp("Unexpected packet:", rx))
+                try:
+                    self.logger.debug(ppp("Decrypted packet:", decrypt_pkt))
+                except:
+                    pass
+                raise
+        return decrypted
+
+    def verify_tra_66_ext_hdrs(self, p):
+        count = 63
+
+        #
+        # check we can decrypt with options
+        #
+        tx = self.gen_encrypt_pkts_ext_hdrs6(p.scapy_tra_sa, self.tra_if,
+                                             src=self.tra_if.remote_ip6,
+                                             dst=self.tra_if.local_ip6,
+                                             count=count)
+        self.send_and_expect(self.tra_if, tx, self.tra_if)
+
+        #
+        # injecting a packet from ourselves to be routed of box is a hack
+        # but it matches an outbout policy, alors je ne regrette rien
+        #
+
+        # one extension before ESP
+        tx = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
+              IPv6(src=self.tra_if.local_ip6,
+                   dst=self.tra_if.remote_ip6) /
+              IPv6ExtHdrFragment(id=2, offset=200) /
+              Raw(b'\xff' * 200))
+
+        rxs = self.send_and_expect(self.pg2, [tx], self.tra_if)
+        dcs = self.verify_tra_encrypted6(p, p.vpp_tra_sa, rxs)
+
+        for dc in dcs:
+            # for reasons i'm not going to investigate scapy does not
+            # created the correct headers after decrypt. but reparsing
+            # the ipv6 packet fixes it
+            dc = IPv6(raw(dc[IPv6]))
+            self.assert_equal(dc[IPv6ExtHdrFragment].id, 2)
+
+        # two extensions before ESP
+        tx = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
+              IPv6(src=self.tra_if.local_ip6,
+                   dst=self.tra_if.remote_ip6) /
+              IPv6ExtHdrHopByHop() /
+              IPv6ExtHdrFragment(id=2, offset=200) /
+              Raw(b'\xff' * 200))
+
+        rxs = self.send_and_expect(self.pg2, [tx], self.tra_if)
+        dcs = self.verify_tra_encrypted6(p, p.vpp_tra_sa, rxs)
+
+        for dc in dcs:
+            dc = IPv6(raw(dc[IPv6]))
+            self.assertTrue(dc[IPv6ExtHdrHopByHop])
+            self.assert_equal(dc[IPv6ExtHdrFragment].id, 2)
+
+        # two extensions before ESP, one after
+        tx = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
+              IPv6(src=self.tra_if.local_ip6,
+                   dst=self.tra_if.remote_ip6) /
+              IPv6ExtHdrHopByHop() /
+              IPv6ExtHdrFragment(id=2, offset=200) /
+              IPv6ExtHdrDestOpt() /
+              Raw(b'\xff' * 200))
+
+        rxs = self.send_and_expect(self.pg2, [tx], self.tra_if)
+        dcs = self.verify_tra_encrypted6(p, p.vpp_tra_sa, rxs)
+
+        for dc in dcs:
+            dc = IPv6(raw(dc[IPv6]))
+            self.assertTrue(dc[IPv6ExtHdrDestOpt])
+            self.assertTrue(dc[IPv6ExtHdrHopByHop])
+            self.assert_equal(dc[IPv6ExtHdrFragment].id, 2)
+
 
 class IpsecTra6Tests(IpsecTra6):
     """ UT test methods for Transport v6 """
 
 class IpsecTra6Tests(IpsecTra6):
     """ UT test methods for Transport v6 """
@@ -653,6 +757,12 @@ class IpsecTra6Tests(IpsecTra6):
         self.verify_tra_basic6(count=257)
 
 
         self.verify_tra_basic6(count=257)
 
 
+class IpsecTra6ExtTests(IpsecTra6):
+    def test_tra_ext_hdrs_66(self):
+        """ ipsec 6o6 tra extension headers test """
+        self.verify_tra_66_ext_hdrs(self.params[socket.AF_INET6])
+
+
 class IpsecTra46Tests(IpsecTra4Tests, IpsecTra6Tests):
     """ UT test methods for Transport v6 and v4"""
     pass
 class IpsecTra46Tests(IpsecTra4Tests, IpsecTra6Tests):
     """ UT test methods for Transport v6 and v4"""
     pass
@@ -715,6 +825,7 @@ class IpsecTun4(object):
 
     def verify_tun_44(self, p, count=1, payload_size=64, n_rx=None):
         self.vapi.cli("clear errors")
 
     def verify_tun_44(self, p, count=1, payload_size=64, n_rx=None):
         self.vapi.cli("clear errors")
+        self.vapi.cli("clear ipsec counters")
         if not n_rx:
             n_rx = count
         try:
         if not n_rx:
             n_rx = count
         try:
@@ -736,8 +847,45 @@ class IpsecTun4(object):
             self.logger.info(self.vapi.ppcli("show error"))
             self.logger.info(self.vapi.ppcli("show ipsec all"))
 
             self.logger.info(self.vapi.ppcli("show error"))
             self.logger.info(self.vapi.ppcli("show ipsec all"))
 
+        self.logger.info(self.vapi.ppcli("show ipsec sa 0"))
+        self.logger.info(self.vapi.ppcli("show ipsec sa 4"))
         self.verify_counters4(p, count, n_rx)
 
         self.verify_counters4(p, count, n_rx)
 
+    """ verify methods for Transport v4 """
+    def verify_tun_44_bad_packet_sizes(self, p):
+        # with a buffer size of 2048, 1989 bytes of payload
+        # means there isn't space to insert the ESP header
+        N_PKTS = 63
+        for p_siz in [1989, 8500]:
+            send_pkts = self.gen_encrypt_pkts(p.scapy_tun_sa, self.tun_if,
+                                              src=p.remote_tun_if_host,
+                                              dst=self.pg1.remote_ip4,
+                                              count=N_PKTS,
+                                              payload_size=p_siz)
+            self.send_and_assert_no_replies(self.tun_if, send_pkts)
+            send_pkts = self.gen_pkts(self.pg1, src=self.pg1.remote_ip4,
+                                      dst=p.remote_tun_if_host, count=N_PKTS,
+                                      payload_size=p_siz)
+            self.send_and_assert_no_replies(self.pg1, send_pkts,
+                                            self.tun_if)
+
+        # both large packets on decrpyt count against chained buffers
+        # the 9000 bytes one does on encrypt
+        self.assertEqual(2 * N_PKTS,
+                         self.statistics.get_err_counter(
+                             '/err/%s/chained buffers (packet dropped)' %
+                             self.tun4_decrypt_node_name))
+        self.assertEqual(N_PKTS,
+                         self.statistics.get_err_counter(
+                             '/err/%s/chained buffers (packet dropped)' %
+                             self.tun4_encrypt_node_name))
+
+        # on encrypt the 1989 size is no trailer space
+        self.assertEqual(N_PKTS,
+                         self.statistics.get_err_counter(
+                             '/err/%s/no trailer space (packet dropped)' %
+                             self.tun4_encrypt_node_name))
+
     def verify_tun_reass_44(self, p):
         self.vapi.cli("clear errors")
         self.vapi.ip_reassembly_enable_disable(
     def verify_tun_reass_44(self, p):
         self.vapi.cli("clear errors")
         self.vapi.ip_reassembly_enable_disable(
@@ -828,6 +976,10 @@ class IpsecTun4Tests(IpsecTun4):
     def test_tun_basic44(self):
         """ ipsec 4o4 tunnel basic test """
         self.verify_tun_44(self.params[socket.AF_INET], count=1)
     def test_tun_basic44(self):
         """ ipsec 4o4 tunnel basic test """
         self.verify_tun_44(self.params[socket.AF_INET], count=1)
+        self.tun_if.admin_down()
+        self.tun_if.resolve_arp()
+        self.tun_if.admin_up()
+        self.verify_tun_44(self.params[socket.AF_INET], count=1)
 
     def test_tun_reass_basic44(self):
         """ ipsec 4o4 tunnel basic reassembly test """
 
     def test_tun_reass_basic44(self):
         """ ipsec 4o4 tunnel basic reassembly test """
@@ -835,7 +987,13 @@ class IpsecTun4Tests(IpsecTun4):
 
     def test_tun_burst44(self):
         """ ipsec 4o4 tunnel burst test """
 
     def test_tun_burst44(self):
         """ ipsec 4o4 tunnel burst test """
-        self.verify_tun_44(self.params[socket.AF_INET], count=257)
+        self.verify_tun_44(self.params[socket.AF_INET], count=127)
+
+
+class IpsecTunEsp4Tests(IpsecTun4):
+    def test_tun_bad_packet_sizes(self):
+        """ ipsec v4 tunnel bad packet size """
+        self.verify_tun_44_bad_packet_sizes(self.params[socket.AF_INET])
 
 
 class IpsecTun6(object):
 
 
 class IpsecTun6(object):
@@ -926,7 +1084,7 @@ class IpsecTun6(object):
                                                src=p.remote_tun_if_host,
                                                dst=self.pg1.remote_ip6,
                                                count=1,
                                                src=p.remote_tun_if_host,
                                                dst=self.pg1.remote_ip6,
                                                count=1,
-                                               payload_size=1900)
+                                               payload_size=1850)
             send_pkts = fragment_rfc8200(send_pkts[0], 1, 1400, self.logger)
             recv_pkts = self.send_and_expect(self.tun_if, send_pkts,
                                              self.pg1, n_rx=1)
             send_pkts = fragment_rfc8200(send_pkts[0], 1, 1400, self.logger)
             recv_pkts = self.send_and_expect(self.tun_if, send_pkts,
                                              self.pg1, n_rx=1)
index 82346d6..60e5c93 100644 (file)
@@ -9,7 +9,8 @@ from template_ipsec import IpsecTra46Tests, IpsecTun46Tests, TemplateIpsec, \
     IpsecTcpTests, IpsecTun4Tests, IpsecTra4Tests, config_tra_params, \
     config_tun_params, IPsecIPv4Params, IPsecIPv6Params, \
     IpsecTra4, IpsecTun4, IpsecTra6, IpsecTun6, \
     IpsecTcpTests, IpsecTun4Tests, IpsecTra4Tests, config_tra_params, \
     config_tun_params, IPsecIPv4Params, IPsecIPv6Params, \
     IpsecTra4, IpsecTun4, IpsecTra6, IpsecTun6, \
-    IpsecTun6HandoffTests, IpsecTun4HandoffTests
+    IpsecTun6HandoffTests, IpsecTun4HandoffTests, \
+    IpsecTra6ExtTests, IpsecTunEsp4Tests
 from vpp_ipsec import VppIpsecSpd, VppIpsecSpdEntry, VppIpsecSA,\
     VppIpsecSpdItfBinding
 from vpp_ip_route import VppIpRoute, VppRoutePath
 from vpp_ipsec import VppIpsecSpd, VppIpsecSpdEntry, VppIpsecSA,\
     VppIpsecSpdItfBinding
 from vpp_ip_route import VppIpRoute, VppRoutePath
@@ -286,7 +287,9 @@ class TemplateIpsecEsp(ConfigIpsecESP):
         super(TemplateIpsecEsp, self).tearDown()
 
 
         super(TemplateIpsecEsp, self).tearDown()
 
 
-class TestIpsecEsp1(TemplateIpsecEsp, IpsecTra46Tests, IpsecTun46Tests):
+class TestIpsecEsp1(TemplateIpsecEsp, IpsecTra46Tests,
+                    IpsecTun46Tests, IpsecTunEsp4Tests,
+                    IpsecTra6ExtTests):
     """ Ipsec ESP - TUN & TRA tests """
     pass
 
     """ Ipsec ESP - TUN & TRA tests """
     pass
 
index eefd477..469ebc7 100644 (file)
@@ -304,6 +304,7 @@ class TestIpsec4MultiTunIfEsp(TemplateIpsec, IpsecTun4):
             p.scapy_tra_spi = p.scapy_tra_spi + ii
             p.vpp_tra_sa_id = p.vpp_tra_sa_id + ii
             p.vpp_tra_spi = p.vpp_tra_spi + ii
             p.scapy_tra_spi = p.scapy_tra_spi + ii
             p.vpp_tra_sa_id = p.vpp_tra_sa_id + ii
             p.vpp_tra_spi = p.vpp_tra_spi + ii
+            p.tun_dst = self.pg0.remote_hosts[ii].ip4
 
             p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
                                             p.scapy_tun_spi,
 
             p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
                                             p.scapy_tun_spi,
@@ -311,7 +312,7 @@ class TestIpsec4MultiTunIfEsp(TemplateIpsec, IpsecTun4):
                                             p.crypt_key, p.crypt_key,
                                             p.auth_algo_vpp_id, p.auth_key,
                                             p.auth_key,
                                             p.crypt_key, p.crypt_key,
                                             p.auth_algo_vpp_id, p.auth_key,
                                             p.auth_key,
-                                            dst=self.pg0.remote_hosts[ii].ip4)
+                                            dst=p.tun_dst)
             p.tun_if.add_vpp_config()
             p.tun_if.admin_up()
             p.tun_if.config_ip4()
             p.tun_if.add_vpp_config()
             p.tun_if.admin_up()
             p.tun_if.config_ip4()
@@ -334,6 +335,27 @@ class TestIpsec4MultiTunIfEsp(TemplateIpsec, IpsecTun4):
             c = p.tun_if.get_tx_stats()
             self.assertEqual(c['packets'], 127)
 
             c = p.tun_if.get_tx_stats()
             self.assertEqual(c['packets'], 127)
 
+    def test_tun_rr_44(self):
+        """ Round-robin packets acrros multiple interface """
+        tx = []
+        for p in self.multi_params:
+            tx = tx + self.gen_encrypt_pkts(p.scapy_tun_sa, self.tun_if,
+                                            src=p.remote_tun_if_host,
+                                            dst=self.pg1.remote_ip4)
+        rxs = self.send_and_expect(self.tun_if, tx, self.pg1)
+
+        for rx, p in zip(rxs, self.multi_params):
+            self.verify_decrypted(p, [rx])
+
+        tx = []
+        for p in self.multi_params:
+            tx = tx + self.gen_pkts(self.pg1, src=self.pg1.remote_ip4,
+                                    dst=p.remote_tun_if_host)
+        rxs = self.send_and_expect(self.pg1, tx, self.tun_if)
+
+        for rx, p in zip(rxs, self.multi_params):
+            self.verify_encrypted(p, p.vpp_tun_sa, [rx])
+
 
 class TestIpsec4TunIfEspAll(TemplateIpsec, IpsecTun4):
     """ IPsec IPv4 Tunnel interface all Algos """
 
 class TestIpsec4TunIfEspAll(TemplateIpsec, IpsecTun4):
     """ IPsec IPv4 Tunnel interface all Algos """
@@ -521,6 +543,69 @@ class TestIpsec4TunIfEspAll(TemplateIpsec, IpsecTun4):
                 p.tun_sa_in.remove_vpp_config()
 
 
                 p.tun_sa_in.remove_vpp_config()
 
 
+class TestIpsec4TunIfEspNoAlgo(TemplateIpsec, IpsecTun4):
+    """ IPsec IPv4 Tunnel interface all Algos """
+
+    encryption_type = ESP
+    tun4_encrypt_node_name = "esp4-encrypt-tun"
+    tun4_decrypt_node_name = "esp4-decrypt-tun"
+
+    def config_network(self, p):
+
+        p.auth_algo_vpp_id = (VppEnum.vl_api_ipsec_integ_alg_t.
+                              IPSEC_API_INTEG_ALG_NONE)
+        p.auth_algo = 'NULL'
+        p.auth_key = []
+
+        p.crypt_algo_vpp_id = (VppEnum.vl_api_ipsec_crypto_alg_t.
+                               IPSEC_API_CRYPTO_ALG_NONE)
+        p.crypt_algo = 'NULL'
+        p.crypt_key = []
+
+        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,
+                                        salt=p.salt)
+        p.tun_if.add_vpp_config()
+        p.tun_if.admin_up()
+        p.tun_if.config_ip4()
+        config_tun_params(p, self.encryption_type, p.tun_if)
+        self.logger.info(self.vapi.cli("sh ipsec sa 0"))
+        self.logger.info(self.vapi.cli("sh ipsec sa 1"))
+
+        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.tun_if.unconfig_ip4()
+        p.tun_if.remove_vpp_config()
+        p.route.remove_vpp_config()
+
+    def setUp(self):
+        super(TestIpsec4TunIfEspNoAlgo, self).setUp()
+
+        self.tun_if = self.pg0
+
+    def tearDown(self):
+        super(TestIpsec4TunIfEspNoAlgo, self).tearDown()
+
+    def test_tun_44(self):
+        p = self.ipv4_params
+
+        self.config_network(p)
+
+        tx = self.gen_pkts(self.pg1, src=self.pg1.remote_ip4,
+                           dst=p.remote_tun_if_host)
+        self.send_and_assert_no_replies(self.pg1, tx)
+
+        self.unconfig_network(p)
+
+
 class TestIpsec6MultiTunIfEsp(TemplateIpsec, IpsecTun6):
     """ IPsec IPv6 Multi Tunnel interface """
 
 class TestIpsec6MultiTunIfEsp(TemplateIpsec, IpsecTun6):
     """ IPsec IPv6 Multi Tunnel interface """
 
@@ -919,6 +1004,16 @@ class TestIpsecGreIfEspTra(TemplateIpsec,
                            Raw(b'X' * payload_size))
                 for i in range(count)]
 
                            Raw(b'X' * payload_size))
                 for i in range(count)]
 
+    def gen_encrypt_non_ip_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() /
+                           UDP(sport=1144, dport=2233) /
+                           Raw(b'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) /
     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) /
@@ -996,6 +1091,115 @@ class TestIpsecGreIfEspTra(TemplateIpsec,
         p.tun_if.unconfig_ip4()
         super(TestIpsecGreIfEspTra, self).tearDown()
 
         p.tun_if.unconfig_ip4()
         super(TestIpsecGreIfEspTra, self).tearDown()
 
+    def test_gre_non_ip(self):
+        p = self.ipv4_params
+        tx = self.gen_encrypt_non_ip_pkts(p.scapy_tun_sa, self.tun_if,
+                                          src=p.remote_tun_if_host,
+                                          dst=self.pg1.remote_ip6)
+        self.send_and_assert_no_replies(self.tun_if, tx)
+        node_name = ('/err/%s/unsupported payload' %
+                     self.tun4_decrypt_node_name)
+        self.assertEqual(1, self.statistics.get_err_counter(node_name))
+
+
+class TestIpsecGre6IfEspTra(TemplateIpsec,
+                            IpsecTun6Tests):
+    """ Ipsec GRE ESP - TRA tests """
+    tun6_encrypt_node_name = "esp6-encrypt-tun"
+    tun6_decrypt_node_name = "esp6-decrypt-tun"
+    encryption_type = ESP
+
+    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=self.pg0.remote_ip6,
+                                dst=self.pg0.local_ip6) /
+                           GRE() /
+                           IPv6(src=self.pg1.local_ip6,
+                                dst=self.pg1.remote_ip6) /
+                           UDP(sport=1144, dport=2233) /
+                           Raw(b'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="1::1", dst="1::2") /
+                UDP(sport=1144, dport=2233) /
+                Raw(b'X' * payload_size)
+                for i in range(count)]
+
+    def verify_decrypted6(self, p, rxs):
+        for rx in rxs:
+            self.assert_equal(rx[Ether].dst, self.pg1.remote_mac)
+            self.assert_equal(rx[IPv6].dst, self.pg1.remote_ip6)
+
+    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.assertTrue(pkt.haslayer(GRE))
+                e = pkt[GRE]
+                self.assertEqual(e[IPv6].dst, "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(TestIpsecGre6IfEspTra, self).setUp()
+
+        self.tun_if = self.pg0
+
+        p = self.ipv6_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)
+        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()
+
+        p.tun_if = VppGreInterface(self,
+                                   self.pg0.local_ip6,
+                                   self.pg0.remote_ip6)
+        p.tun_if.add_vpp_config()
+
+        p.tun_protect = VppIpsecTunProtect(self,
+                                           p.tun_if,
+                                           p.tun_sa_out,
+                                           [p.tun_sa_in])
+        p.tun_protect.add_vpp_config()
+
+        p.tun_if.admin_up()
+        p.tun_if.config_ip6()
+        config_tra_params(p, self.encryption_type, p.tun_if)
+
+        r = VppIpRoute(self, "1::2", 128,
+                       [VppRoutePath(p.tun_if.remote_ip6,
+                                     0xffffffff,
+                                     proto=DpoProto.DPO_PROTO_IP6)])
+        r.add_vpp_config()
+
+    def tearDown(self):
+        p = self.ipv6_params
+        p.tun_if.unconfig_ip6()
+        super(TestIpsecGre6IfEspTra, self).tearDown()
+
 
 class TemplateIpsec4TunProtect(object):
     """ IPsec IPv4 Tunnel protect """
 
 class TemplateIpsec4TunProtect(object):
     """ IPsec IPv4 Tunnel protect """
@@ -1286,6 +1490,54 @@ class TestIpsec4TunProtectTun(TemplateIpsec,
         self.unconfig_network(p)
 
 
         self.unconfig_network(p)
 
 
+class TestIpsec4TunProtectTunDrop(TemplateIpsec,
+                                  TemplateIpsec4TunProtect,
+                                  IpsecTun4):
+    """ IPsec IPv4 Tunnel protect - tunnel mode - drop"""
+
+    encryption_type = ESP
+    tun4_encrypt_node_name = "esp4-encrypt-tun"
+    tun4_decrypt_node_name = "esp4-decrypt-tun"
+
+    def setUp(self):
+        super(TestIpsec4TunProtectTunDrop, self).setUp()
+
+        self.tun_if = self.pg0
+
+    def tearDown(self):
+        super(TestIpsec4TunProtectTunDrop, 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="5.5.5.5") /
+                           IP(src=src, dst=dst) /
+                           UDP(sport=1144, dport=2233) /
+                           Raw(b'X' * payload_size))
+                for i in range(count)]
+
+    def test_tun_drop_44(self):
+        """IPSEC tunnel protect bogus tunnel header """
+
+        p = self.ipv4_params
+
+        self.config_network(p)
+        self.config_sa_tun(p)
+        self.config_protect(p)
+
+        tx = self.gen_encrypt_pkts(p.scapy_tun_sa, self.tun_if,
+                                   src=p.remote_tun_if_host,
+                                   dst=self.pg1.remote_ip4,
+                                   count=63)
+        self.send_and_assert_no_replies(self.tun_if, tx)
+
+        # teardown
+        self.unconfig_protect(p)
+        self.unconfig_sa(p)
+        self.unconfig_network(p)
+
+
 class TemplateIpsec6TunProtect(object):
     """ IPsec IPv6 Tunnel protect """
 
 class TemplateIpsec6TunProtect(object):
     """ IPsec IPv6 Tunnel protect """
 
@@ -1379,7 +1631,7 @@ class TestIpsec6TunProtect(TemplateIpsec,
         super(TestIpsec6TunProtect, self).tearDown()
 
     def test_tun_66(self):
         super(TestIpsec6TunProtect, self).tearDown()
 
     def test_tun_66(self):
-        """IPSEC tunnel protect"""
+        """IPSEC tunnel protect 6o6"""
 
         p = self.ipv6_params
 
 
         p = self.ipv6_params
 
@@ -1413,6 +1665,15 @@ class TestIpsec6TunProtect(TemplateIpsec,
         c = p.tun_if.get_tx_stats()
         self.assertEqual(c['packets'], 254)
 
         c = p.tun_if.get_tx_stats()
         self.assertEqual(c['packets'], 254)
 
+        # bounce the interface state
+        p.tun_if.admin_down()
+        self.verify_drop_tun_66(np, count=127)
+        node = ('/err/ipsec6-tun-input/%s' %
+                'ipsec packets received on disabled interface')
+        self.assertEqual(127, self.statistics.get_err_counter(node))
+        p.tun_if.admin_up()
+        self.verify_tun_66(np, count=127)
+
         # 3 phase rekey
         #  1) add two input SAs [old, new]
         #  2) swap output SA to [new]
         # 3 phase rekey
         #  1) add two input SAs [old, new]
         #  2) swap output SA to [new]
@@ -1447,9 +1708,9 @@ class TestIpsec6TunProtect(TemplateIpsec,
         self.verify_drop_tun_66(np, count=127)
 
         c = p.tun_if.get_rx_stats()
         self.verify_drop_tun_66(np, count=127)
 
         c = p.tun_if.get_rx_stats()
-        self.assertEqual(c['packets'], 127*7)
+        self.assertEqual(c['packets'], 127*9)
         c = p.tun_if.get_tx_stats()
         c = p.tun_if.get_tx_stats()
-        self.assertEqual(c['packets'], 127*7)
+        self.assertEqual(c['packets'], 127*8)
         self.unconfig_sa(np)
 
         # teardown
         self.unconfig_sa(np)
 
         # teardown
@@ -1458,7 +1719,7 @@ class TestIpsec6TunProtect(TemplateIpsec,
         self.unconfig_network(p)
 
     def test_tun_46(self):
         self.unconfig_network(p)
 
     def test_tun_46(self):
-        """IPSEC tunnel protect"""
+        """IPSEC tunnel protect 4o6"""
 
         p = self.ipv6_params
 
 
         p = self.ipv6_params
 
@@ -1581,5 +1842,54 @@ class TestIpsec6TunProtectTun(TemplateIpsec,
         self.unconfig_network(p)
 
 
         self.unconfig_network(p)
 
 
+class TestIpsec6TunProtectTunDrop(TemplateIpsec,
+                                  TemplateIpsec6TunProtect,
+                                  IpsecTun6):
+    """ IPsec IPv6 Tunnel protect - tunnel mode - drop"""
+
+    encryption_type = ESP
+    tun6_encrypt_node_name = "esp6-encrypt-tun"
+    tun6_decrypt_node_name = "esp6-decrypt-tun"
+
+    def setUp(self):
+        super(TestIpsec6TunProtectTunDrop, self).setUp()
+
+        self.tun_if = self.pg0
+
+    def tearDown(self):
+        super(TestIpsec6TunProtectTunDrop, self).tearDown()
+
+    def gen_encrypt_pkts5(self, sa, sw_intf, src, dst, count=1,
+                          payload_size=100):
+        # the IP destination of the revelaed packet does not match
+        # that assigned to the tunnel
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                sa.encrypt(IPv6(src=sw_intf.remote_ip6,
+                                dst="5::5") /
+                           IPv6(src=src, dst=dst) /
+                           UDP(sport=1144, dport=2233) /
+                           Raw(b'X' * payload_size))
+                for i in range(count)]
+
+    def test_tun_drop_66(self):
+        """IPSEC 6 tunnel protect bogus tunnel header """
+
+        p = self.ipv6_params
+
+        self.config_network(p)
+        self.config_sa_tun(p)
+        self.config_protect(p)
+
+        tx = self.gen_encrypt_pkts6(p.scapy_tun_sa, self.tun_if,
+                                    src=p.remote_tun_if_host,
+                                    dst=self.pg1.remote_ip6,
+                                    count=63)
+        self.send_and_assert_no_replies(self.tun_if, tx)
+
+        self.unconfig_protect(p)
+        self.unconfig_sa(p)
+        self.unconfig_network(p)
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)