ipsec: VPP-1316 calculate IP/TCP/UDP inner checksums 48/13048/4
authorKlement Sekera <ksekera@cisco.com>
Wed, 16 May 2018 08:52:45 +0000 (10:52 +0200)
committerFlorin Coras <florin.coras@gmail.com>
Thu, 21 Jun 2018 14:50:10 +0000 (14:50 +0000)
Calculate IP/TCP/UDP checksums in software before adding authentication.

Change-Id: I3e121cb00aeba667764f39ade8d62170f18f8b6b
Signed-off-by: Klement Sekera <ksekera@cisco.com>
19 files changed:
src/vnet.am
src/vnet/ipsec/ah_encrypt.c
src/vnet/ipsec/ipsec.h
src/vnet/ipsec/ipsec_if.c
src/vnet/ipsec/ipsec_if_out.c [deleted file]
src/vnet/ipsec/ipsec_output.c
test/bfd.py
test/discover_tests.py
test/framework.py
test/template_ipsec.py [new file with mode: 0644]
test/test_ipsec_ah.py
test/test_ipsec_esp.py
test/test_ipsec_nat.py
test/test_ipsec_tun_if_esp.py [new file with mode: 0644]
test/vpp_interface.py
test/vpp_ipsec_tun_interface.py [new file with mode: 0644]
test/vpp_papi_provider.py
test/vpp_pg_interface.py
test/vpp_tunnel_interface.py [new file with mode: 0644]

index cecc2e2..95b94c3 100644 (file)
@@ -451,7 +451,6 @@ libvnet_la_SOURCES +=                               \
  vnet/ipsec/ipsec_input.c                      \
  vnet/ipsec/ipsec_if.c                         \
  vnet/ipsec/ipsec_if_in.c                      \
  vnet/ipsec/ipsec_input.c                      \
  vnet/ipsec/ipsec_if.c                         \
  vnet/ipsec/ipsec_if_in.c                      \
- vnet/ipsec/ipsec_if_out.c                     \
  vnet/ipsec/esp_format.c                       \
  vnet/ipsec/esp_encrypt.c                      \
  vnet/ipsec/esp_decrypt.c                      \
  vnet/ipsec/esp_format.c                       \
  vnet/ipsec/esp_encrypt.c                      \
  vnet/ipsec/esp_decrypt.c                      \
index 6619d87..898c0f2 100644 (file)
@@ -263,19 +263,17 @@ ah_encrypt_node_fn (vlib_main_t * vm,
 
          u8 sig[64];
          memset (sig, 0, sizeof (sig));
 
          u8 sig[64];
          memset (sig, 0, sizeof (sig));
-         u8 *digest = NULL;
-         {
-           digest = vlib_buffer_get_current (i_b0) + ip_hdr_size + icv_size;
-           memset (digest, 0, icv_size);
-         }
+         u8 *digest =
+           vlib_buffer_get_current (i_b0) + ip_hdr_size + icv_size;
+         memset (digest, 0, icv_size);
 
 
-         hmac_calc (sa0->integ_alg, sa0->integ_key,
-                    sa0->integ_key_len,
-                    (u8 *) vlib_buffer_get_current (i_b0),
-                    i_b0->current_length, sig, sa0->use_esn, sa0->seq_hi);
-
-         memcpy (digest, (char *) &sig[0], 12);
+         unsigned size = hmac_calc (sa0->integ_alg, sa0->integ_key,
+                                    sa0->integ_key_len,
+                                    vlib_buffer_get_current (i_b0),
+                                    i_b0->current_length, sig, sa0->use_esn,
+                                    sa0->seq_hi);
 
 
+         memcpy (digest, sig, size);
          if (PREDICT_FALSE (is_ipv6))
            {
            }
          if (PREDICT_FALSE (is_ipv6))
            {
            }
@@ -287,7 +285,7 @@ ah_encrypt_node_fn (vlib_main_t * vm,
            }
 
          if (transport_mode)
            }
 
          if (transport_mode)
-           vlib_buffer_advance (i_b0, -sizeof (ethernet_header_t));;
+           vlib_buffer_advance (i_b0, -sizeof (ethernet_header_t));
 
        trace:
          if (PREDICT_FALSE (i_b0->flags & VLIB_BUFFER_IS_TRACED))
 
        trace:
          if (PREDICT_FALSE (i_b0->flags & VLIB_BUFFER_IS_TRACED))
index 404756a..e457e33 100644 (file)
@@ -310,7 +310,6 @@ extern vlib_node_registration_t esp_encrypt_node;
 extern vlib_node_registration_t esp_decrypt_node;
 extern vlib_node_registration_t ah_encrypt_node;
 extern vlib_node_registration_t ah_decrypt_node;
 extern vlib_node_registration_t esp_decrypt_node;
 extern vlib_node_registration_t ah_encrypt_node;
 extern vlib_node_registration_t ah_decrypt_node;
-extern vlib_node_registration_t ipsec_if_output_node;
 extern vlib_node_registration_t ipsec_if_input_node;
 
 
 extern vlib_node_registration_t ipsec_if_input_node;
 
 
@@ -328,7 +327,6 @@ int ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update);
 
 u32 ipsec_get_sa_index_by_sa_id (u32 sa_id);
 u8 ipsec_is_sa_used (u32 sa_index);
 
 u32 ipsec_get_sa_index_by_sa_id (u32 sa_id);
 u8 ipsec_is_sa_used (u32 sa_index);
-u8 *format_ipsec_if_output_trace (u8 * s, va_list * args);
 u8 *format_ipsec_policy_action (u8 * s, va_list * args);
 u8 *format_ipsec_crypto_alg (u8 * s, va_list * args);
 u8 *format_ipsec_integ_alg (u8 * s, va_list * args);
 u8 *format_ipsec_policy_action (u8 * s, va_list * args);
 u8 *format_ipsec_crypto_alg (u8 * s, va_list * args);
 u8 *format_ipsec_integ_alg (u8 * s, va_list * args);
index e7536b2..a7dbcba 100644 (file)
@@ -34,14 +34,128 @@ format_ipsec_name (u8 * s, va_list * args)
   return format (s, "ipsec%d", t->show_instance);
 }
 
   return format (s, "ipsec%d", t->show_instance);
 }
 
+/* Statistics (not really errors) */
+#define foreach_ipsec_if_tx_error    \
+_(TX, "good packets transmitted")
+
+static char *ipsec_if_tx_error_strings[] = {
+#define _(sym,string) string,
+  foreach_ipsec_if_tx_error
+#undef _
+};
+
+typedef enum
+{
+#define _(sym,str) IPSEC_IF_OUTPUT_ERROR_##sym,
+  foreach_ipsec_if_tx_error
+#undef _
+    IPSEC_IF_TX_N_ERROR,
+} ipsec_if_tx_error_t;
+
+typedef struct
+{
+  u32 spi;
+  u32 seq;
+} ipsec_if_tx_trace_t;
+
+u8 *
+format_ipsec_if_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_if_tx_trace_t *t = va_arg (*args, ipsec_if_tx_trace_t *);
+
+  s = format (s, "IPSec: spi %u seq %u", t->spi, t->seq);
+  return s;
+}
+
 static uword
 static uword
-dummy_interface_tx (vlib_main_t * vm,
-                   vlib_node_runtime_t * node, vlib_frame_t * frame)
+ipsec_if_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                    vlib_frame_t * from_frame)
 {
 {
-  clib_warning ("you shouldn't be here, leaking buffers...");
-  return frame->n_vectors;
+  ipsec_main_t *im = &ipsec_main;
+  vnet_main_t *vnm = im->vnet_main;
+  vnet_interface_main_t *vim = &vnm->interface_main;
+  u32 *from, *to_next = 0, next_index;
+  u32 n_left_from, sw_if_index0, last_sw_if_index = ~0;
+  u32 thread_index = vlib_get_thread_index ();
+  u32 n_bytes = 0, n_packets = 0;
+
+  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 > 0 && n_left_to_next > 0)
+       {
+         u32 bi0, next0, len0;
+         vlib_buffer_t *b0;
+         ipsec_tunnel_if_t *t0;
+         vnet_hw_interface_t *hi0;
+
+         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);
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
+         hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
+         t0 = pool_elt_at_index (im->tunnel_interfaces, hi0->dev_instance);
+         vnet_buffer (b0)->ipsec.sad_index = t0->output_sa_index;
+         next0 = IPSEC_OUTPUT_NEXT_ESP_ENCRYPT;
+
+         len0 = vlib_buffer_length_in_chain (vm, b0);
+
+         if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index))
+           {
+             n_packets++;
+             n_bytes += len0;
+           }
+         else
+           {
+             vlib_increment_combined_counter (vim->combined_sw_if_counters +
+                                              VNET_INTERFACE_COUNTER_TX,
+                                              thread_index, sw_if_index0,
+                                              n_packets, n_bytes);
+             last_sw_if_index = sw_if_index0;
+             n_packets = 1;
+             n_bytes = len0;
+           }
+
+         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             ipsec_if_tx_trace_t *tr =
+               vlib_add_trace (vm, node, b0, sizeof (*tr));
+             ipsec_sa_t *sa0 =
+               pool_elt_at_index (im->sad, t0->output_sa_index);
+             tr->spi = sa0->spi;
+             tr->seq = sa0->seq;
+           }
+
+         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);
+    }
+
+  if (last_sw_if_index != ~0)
+    {
+      vlib_increment_combined_counter (vim->combined_sw_if_counters +
+                                      VNET_INTERFACE_COUNTER_TX,
+                                      thread_index,
+                                      last_sw_if_index, n_packets, n_bytes);
+    }
+
+  return from_frame->n_vectors;
 }
 
 }
 
+
 static clib_error_t *
 ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
 {
 static clib_error_t *
 ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
 {
@@ -113,13 +227,16 @@ ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
   return /* no error */ 0;
 }
 
   return /* no error */ 0;
 }
 
+
 /* *INDENT-OFF* */
 VNET_DEVICE_CLASS (ipsec_device_class, static) =
 {
   .name = "IPSec",
   .format_device_name = format_ipsec_name,
 /* *INDENT-OFF* */
 VNET_DEVICE_CLASS (ipsec_device_class, static) =
 {
   .name = "IPSec",
   .format_device_name = format_ipsec_name,
-  .format_tx_trace = format_ipsec_if_output_trace,
-  .tx_function = dummy_interface_tx,
+  .format_tx_trace = format_ipsec_if_tx_trace,
+  .tx_function = ipsec_if_tx_node_fn,
+  .tx_function_n_errors = IPSEC_IF_TX_N_ERROR,
+  .tx_function_error_strings = ipsec_if_tx_error_strings,
   .admin_up_down_function = ipsec_admin_up_down_function,
 };
 /* *INDENT-ON* */
   .admin_up_down_function = ipsec_admin_up_down_function,
 };
 /* *INDENT-ON* */
@@ -162,6 +279,7 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
   uword *p;
   ipsec_sa_t *sa;
   u32 dev_instance;
   uword *p;
   ipsec_sa_t *sa;
   u32 dev_instance;
+  u32 slot;
 
   u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
   p = hash_get (im->ipsec_if_pool_index_by_key, key);
 
   u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
   p = hash_get (im->ipsec_if_pool_index_by_key, key);
@@ -247,7 +365,13 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
                                             t - im->tunnel_interfaces);
 
       hi = vnet_get_hw_interface (vnm, hw_if_index);
                                             t - im->tunnel_interfaces);
 
       hi = vnet_get_hw_interface (vnm, hw_if_index);
-      hi->output_node_index = ipsec_if_output_node.index;
+
+      slot = vlib_node_add_named_next_with_slot
+       (vnm->vlib_main, hi->tx_node_index, "esp-encrypt",
+        IPSEC_OUTPUT_NEXT_ESP_ENCRYPT);
+
+      ASSERT (slot == IPSEC_OUTPUT_NEXT_ESP_ENCRYPT);
+
       t->hw_if_index = hw_if_index;
 
       vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
       t->hw_if_index = hw_if_index;
 
       vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
diff --git a/src/vnet/ipsec/ipsec_if_out.c b/src/vnet/ipsec/ipsec_if_out.c
deleted file mode 100644 (file)
index cab6ff3..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * ipsec_if_out.c : IPSec interface output 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>
-
-/* Statistics (not really errors) */
-#define foreach_ipsec_if_output_error    \
-_(TX, "good packets transmitted")
-
-static char *ipsec_if_output_error_strings[] = {
-#define _(sym,string) string,
-  foreach_ipsec_if_output_error
-#undef _
-};
-
-typedef enum
-{
-#define _(sym,str) IPSEC_IF_OUTPUT_ERROR_##sym,
-  foreach_ipsec_if_output_error
-#undef _
-    IPSEC_IF_OUTPUT_N_ERROR,
-} ipsec_if_output_error_t;
-
-
-typedef struct
-{
-  u32 spi;
-  u32 seq;
-} ipsec_if_output_trace_t;
-
-u8 *
-format_ipsec_if_output_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_if_output_trace_t *t = va_arg (*args, ipsec_if_output_trace_t *);
-
-  s = format (s, "IPSec: spi %u seq %u", t->spi, t->seq);
-  return s;
-}
-
-static uword
-ipsec_if_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
-                        vlib_frame_t * from_frame)
-{
-  ipsec_main_t *im = &ipsec_main;
-  vnet_main_t *vnm = im->vnet_main;
-  vnet_interface_main_t *vim = &vnm->interface_main;
-  u32 *from, *to_next = 0, next_index;
-  u32 n_left_from, sw_if_index0, last_sw_if_index = ~0;
-  u32 thread_index = vlib_get_thread_index ();
-  u32 n_bytes = 0, n_packets = 0;
-
-  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 > 0 && n_left_to_next > 0)
-       {
-         u32 bi0, next0, len0;
-         vlib_buffer_t *b0;
-         ipsec_tunnel_if_t *t0;
-         vnet_hw_interface_t *hi0;
-
-         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);
-         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
-         hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
-         t0 = pool_elt_at_index (im->tunnel_interfaces, hi0->dev_instance);
-         vnet_buffer (b0)->ipsec.sad_index = t0->output_sa_index;
-         next0 = im->esp_encrypt_next_index;
-
-         len0 = vlib_buffer_length_in_chain (vm, b0);
-
-         if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index))
-           {
-             n_packets++;
-             n_bytes += len0;
-           }
-         else
-           {
-             vlib_increment_combined_counter (vim->combined_sw_if_counters +
-                                              VNET_INTERFACE_COUNTER_TX,
-                                              thread_index, sw_if_index0,
-                                              n_packets, n_bytes);
-             last_sw_if_index = sw_if_index0;
-             n_packets = 1;
-             n_bytes = len0;
-           }
-
-         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
-           {
-             ipsec_if_output_trace_t *tr =
-               vlib_add_trace (vm, node, b0, sizeof (*tr));
-             ipsec_sa_t *sa0 =
-               pool_elt_at_index (im->sad, t0->output_sa_index);
-             tr->spi = sa0->spi;
-             tr->seq = sa0->seq;
-           }
-
-         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);
-    }
-
-  if (last_sw_if_index != ~0)
-    {
-      vlib_increment_combined_counter (vim->combined_sw_if_counters +
-                                      VNET_INTERFACE_COUNTER_TX,
-                                      thread_index,
-                                      last_sw_if_index, n_packets, n_bytes);
-    }
-
-  vlib_node_increment_counter (vm, ipsec_if_output_node.index,
-                              IPSEC_IF_OUTPUT_ERROR_TX,
-                              from_frame->n_vectors);
-
-  return from_frame->n_vectors;
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ipsec_if_output_node) = {
-  .function = ipsec_if_output_node_fn,
-  .name = "ipsec-if-output",
-  .vector_size = sizeof (u32),
-  .format_trace = format_ipsec_if_output_trace,
-  .type = VLIB_NODE_TYPE_INTERNAL,
-
-  .n_errors = ARRAY_LEN(ipsec_if_output_error_strings),
-  .error_strings = ipsec_if_output_error_strings,
-
-  .sibling_of = "ipsec-output-ip4",
-};
-/* *INDENT-ON* */
-
-VLIB_NODE_FUNCTION_MULTIARCH (ipsec_if_output_node, ipsec_if_output_node_fn)
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
index 4bfbf60..a62c0a5 100644 (file)
@@ -190,6 +190,7 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
   vlib_frame_t *f = 0;
   u32 spd_index0 = ~0;
   ipsec_spd_t *spd0 = 0;
   vlib_frame_t *f = 0;
   u32 spd_index0 = ~0;
   ipsec_spd_t *spd0 = 0;
+  int bogus;
   u64 nc_protect = 0, nc_bypass = 0, nc_discard = 0, nc_nomatch = 0;
 
   from = vlib_frame_vector_args (from_frame);
   u64 nc_protect = 0, nc_bypass = 0, nc_discard = 0, nc_nomatch = 0;
 
   from = vlib_frame_vector_args (from_frame);
@@ -204,6 +205,7 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       ip6_header_t *ip6_0 = 0;
       udp_header_t *udp0;
       u32 iph_offset = 0;
       ip6_header_t *ip6_0 = 0;
       udp_header_t *udp0;
       u32 iph_offset = 0;
+      tcp_header_t *tcp0;
 
       bi0 = from[0];
       b0 = vlib_get_buffer (vm, bi0);
 
       bi0 = from[0];
       b0 = vlib_get_buffer (vm, bi0);
@@ -269,6 +271,7 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                                          clib_net_to_host_u16
                                          (udp0->dst_port));
        }
                                          clib_net_to_host_u16
                                          (udp0->dst_port));
        }
+      tcp0 = (void *) udp0;
 
       if (PREDICT_TRUE (p0 != NULL))
        {
 
       if (PREDICT_TRUE (p0 != NULL))
        {
@@ -282,18 +285,53 @@ ipsec_output_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              else
                next_node_index = im->ah_encrypt_node_index;
              vnet_buffer (b0)->ipsec.sad_index = p0->sa_index;
              else
                next_node_index = im->ah_encrypt_node_index;
              vnet_buffer (b0)->ipsec.sad_index = p0->sa_index;
-             vlib_buffer_advance (b0, iph_offset);
              p0->counter.packets++;
              if (is_ipv6)
                {
                  p0->counter.bytes +=
                    clib_net_to_host_u16 (ip6_0->payload_length);
                  p0->counter.bytes += sizeof (ip6_header_t);
              p0->counter.packets++;
              if (is_ipv6)
                {
                  p0->counter.bytes +=
                    clib_net_to_host_u16 (ip6_0->payload_length);
                  p0->counter.bytes += sizeof (ip6_header_t);
+                 if (PREDICT_FALSE
+                     (b0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM))
+                   {
+                     tcp0->checksum =
+                       ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip6_0,
+                                                          &bogus);
+                     b0->flags &= ~VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+                   }
+                 if (PREDICT_FALSE
+                     (b0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
+                   {
+                     udp0->checksum =
+                       ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip6_0,
+                                                          &bogus);
+                     b0->flags &= ~VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+                   }
                }
              else
                {
                  p0->counter.bytes += clib_net_to_host_u16 (ip0->length);
                }
              else
                {
                  p0->counter.bytes += clib_net_to_host_u16 (ip0->length);
+                 if (b0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM)
+                   {
+                     ip0->checksum = ip4_header_checksum (ip0);
+                     b0->flags &= ~VNET_BUFFER_F_OFFLOAD_IP_CKSUM;
+                   }
+                 if (PREDICT_FALSE
+                     (b0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM))
+                   {
+                     tcp0->checksum =
+                       ip4_tcp_udp_compute_checksum (vm, b0, ip0);
+                     b0->flags &= ~VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+                   }
+                 if (PREDICT_FALSE
+                     (b0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
+                   {
+                     udp0->checksum =
+                       ip4_tcp_udp_compute_checksum (vm, b0, ip0);
+                     b0->flags &= ~VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+                   }
                }
                }
+             vlib_buffer_advance (b0, iph_offset);
            }
          else if (p0->policy == IPSEC_POLICY_ACTION_BYPASS)
            {
            }
          else if (p0->policy == IPSEC_POLICY_ACTION_BYPASS)
            {
index 452a180..d99bbf6 100644 (file)
@@ -35,9 +35,6 @@ class BFDDiagCode(NumericConstant):
         reverse_concatenated_path_down: "Reverse Concatenated Path Down",
     }
 
         reverse_concatenated_path_down: "Reverse Concatenated Path Down",
     }
 
-    def __init__(self, value):
-        NumericConstant.__init__(self, value)
-
 
 class BFDState(NumericConstant):
     """ BFD State """
 
 class BFDState(NumericConstant):
     """ BFD State """
@@ -53,9 +50,6 @@ class BFDState(NumericConstant):
         up: "Up",
     }
 
         up: "Up",
     }
 
-    def __init__(self, value):
-        NumericConstant.__init__(self, value)
-
 
 class BFDAuthType(NumericConstant):
     """ BFD Authentication Type """
 
 class BFDAuthType(NumericConstant):
     """ BFD Authentication Type """
@@ -75,9 +69,6 @@ class BFDAuthType(NumericConstant):
         meticulous_keyed_sha1: "Meticulous Keyed SHA1",
     }
 
         meticulous_keyed_sha1: "Meticulous Keyed SHA1",
     }
 
-    def __init__(self, value):
-        NumericConstant.__init__(self, value)
-
 
 def bfd_is_auth_used(pkt):
     """ is packet authenticated? """
 
 def bfd_is_auth_used(pkt):
     """ is packet authenticated? """
@@ -148,6 +139,7 @@ class BFD(Packet):
         return self.sprintf("BFD(my_disc=%BFD.my_discriminator%,"
                             "your_disc=%BFD.your_discriminator%)")
 
         return self.sprintf("BFD(my_disc=%BFD.my_discriminator%,"
                             "your_disc=%BFD.your_discriminator%)")
 
+
 # glue the BFD packet class to scapy parser
 bind_layers(UDP, BFD, dport=BFD.udp_dport)
 
 # glue the BFD packet class to scapy parser
 bind_layers(UDP, BFD, dport=BFD.udp_dport)
 
@@ -169,6 +161,7 @@ class BFD_vpp_echo(Packet):
             "BFD_VPP_ECHO(disc=%BFD_VPP_ECHO.discriminator%,"
             "expire_time_clocks=%BFD_VPP_ECHO.expire_time_clocks%)")
 
             "BFD_VPP_ECHO(disc=%BFD_VPP_ECHO.discriminator%,"
             "expire_time_clocks=%BFD_VPP_ECHO.expire_time_clocks%)")
 
+
 # glue the BFD echo packet class to scapy parser
 bind_layers(UDP, BFD_vpp_echo, dport=BFD_vpp_echo.udp_dport)
 
 # glue the BFD echo packet class to scapy parser
 bind_layers(UDP, BFD_vpp_echo, dport=BFD_vpp_echo.udp_dport)
 
index eea5941..99016e2 100755 (executable)
@@ -30,7 +30,7 @@ def discover_tests(directory, callback):
                 continue
             if not issubclass(cls, unittest.TestCase):
                 continue
                 continue
             if not issubclass(cls, unittest.TestCase):
                 continue
-            if name == "VppTestCase":
+            if name == "VppTestCase" or name.startswith("Template"):
                 continue
             for method in dir(cls):
                 if not callable(getattr(cls, method)):
                 continue
             for method in dir(cls):
                 if not callable(getattr(cls, method)):
index f90197b..be8c209 100644 (file)
@@ -25,6 +25,7 @@ from vpp_papi_provider import VppPapiProvider
 from log import RED, GREEN, YELLOW, double_line_delim, single_line_delim, \
     getLogger, colorize
 from vpp_object import VppObjectRegistry
 from log import RED, GREEN, YELLOW, double_line_delim, single_line_delim, \
     getLogger, colorize
 from vpp_object import VppObjectRegistry
+from util import ppp
 from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
 from scapy.layers.inet6 import ICMPv6DestUnreach, ICMPv6EchoRequest
 from scapy.layers.inet6 import ICMPv6EchoReply
 from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
 from scapy.layers.inet6 import ICMPv6DestUnreach, ICMPv6EchoRequest
 from scapy.layers.inet6 import ICMPv6EchoReply
@@ -735,11 +736,14 @@ class VppTestCase(unittest.TestCase):
 
     def assert_packet_checksums_valid(self, packet,
                                       ignore_zero_udp_checksums=True):
 
     def assert_packet_checksums_valid(self, packet,
                                       ignore_zero_udp_checksums=True):
+        received = packet.__class__(str(packet))
+        self.logger.debug(
+            ppp("Verifying packet checksums for packet:", received))
         udp_layers = ['UDP', 'UDPerror']
         checksum_fields = ['cksum', 'chksum']
         checksums = []
         counter = 0
         udp_layers = ['UDP', 'UDPerror']
         checksum_fields = ['cksum', 'chksum']
         checksums = []
         counter = 0
-        temp = packet.__class__(str(packet))
+        temp = received.__class__(str(received))
         while True:
             layer = temp.getlayer(counter)
             if layer:
         while True:
             layer = temp.getlayer(counter)
             if layer:
@@ -754,12 +758,17 @@ class VppTestCase(unittest.TestCase):
             else:
                 break
             counter = counter + 1
             else:
                 break
             counter = counter + 1
+        if 0 == len(checksums):
+            return
         temp = temp.__class__(str(temp))
         for layer, cf in checksums:
         temp = temp.__class__(str(temp))
         for layer, cf in checksums:
-            self.assert_equal(getattr(packet[layer], cf),
-                              getattr(temp[layer], cf),
-                              "packet checksum on layer #%d: %s" % (
-                                  layer, temp[layer].name))
+            calc_sum = getattr(temp[layer], cf)
+            self.assert_equal(
+                getattr(received[layer], cf), calc_sum,
+                "packet checksum on layer #%d: %s" % (layer, temp[layer].name))
+            self.logger.debug(
+                "Checksum field `%s` on `%s` layer has correct value `%s`" %
+                (cf, temp[layer].name, calc_sum))
 
     def assert_checksum_valid(self, received_packet, layer,
                               field_name='chksum',
 
     def assert_checksum_valid(self, received_packet, layer,
                               field_name='chksum',
diff --git a/test/template_ipsec.py b/test/template_ipsec.py
new file mode 100644 (file)
index 0000000..9d95185
--- /dev/null
@@ -0,0 +1,208 @@
+import unittest
+
+from scapy.layers.inet import IP, ICMP, TCP
+from scapy.layers.ipsec import SecurityAssociation
+from scapy.layers.l2 import Ether, Raw
+
+from framework import VppTestCase, VppTestRunner
+from util import ppp
+
+
+class TemplateIpsec(VppTestCase):
+    """
+    TRANSPORT MODE:
+
+     ------   encrypt   ---
+    |tra_if| <-------> |VPP|
+     ------   decrypt   ---
+
+    TUNNEL MODE:
+
+     ------   encrypt   ---   plain   ---
+    |tun_if| <-------  |VPP| <------ |pg1|
+     ------             ---           ---
+
+     ------   decrypt   ---   plain   ---
+    |tun_if| ------->  |VPP| ------> |pg1|
+     ------             ---           ---
+    """
+
+    remote_tun_if_host = '1.1.1.1'
+    payload = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+
+    tun_spd_id = 1
+    scapy_tun_sa_id = 10
+    scapy_tun_spi = 1001
+    vpp_tun_sa_id = 20
+    vpp_tun_spi = 1000
+
+    tra_spd_id = 2
+    scapy_tra_sa_id = 30
+    scapy_tra_spi = 2001
+    vpp_tra_sa_id = 40
+    vpp_tra_spi = 2000
+
+    vpp_esp_protocol = 1
+    vpp_ah_protocol = 0
+
+    auth_algo_vpp_id = 2  # internal VPP enum value for SHA1_96
+    auth_algo = 'HMAC-SHA1-96'  # scapy name
+    auth_key = 'C91KUR9GYMm5GfkEvNjX'
+
+    crypt_algo_vpp_id = 1  # internal VPP enum value for AES_CBC_128
+    crypt_algo = 'AES-CBC'  # scapy name
+    crypt_key = 'JPjyOWBeVEQiMe7h'
+
+    @classmethod
+    def setUpClass(cls):
+        super(TemplateIpsec, cls).setUpClass()
+        cls.create_pg_interfaces(range(3))
+        cls.interfaces = list(cls.pg_interfaces)
+        for i in cls.interfaces:
+            i.admin_up()
+            i.config_ip4()
+            i.resolve_arp()
+
+    def tearDown(self):
+        super(TemplateIpsec, self).tearDown()
+        if not self.vpp_dead:
+            self.vapi.cli("show hardware")
+
+    def send_and_expect(self, input, pkts, output, count=1):
+        input.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = output.get_capture(count)
+        return rx
+
+    def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1):
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                sa.encrypt(IP(src=src, dst=dst) / ICMP() / self.payload)
+                for i in range(count)]
+
+    def gen_pkts(self, sw_intf, src, dst, count=1):
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                IP(src=src, dst=dst) / ICMP() / self.payload
+                for i in range(count)]
+
+    def configure_sa_tun(self):
+        scapy_tun_sa = SecurityAssociation(self.encryption_type,
+                                           spi=self.vpp_tun_spi,
+                                           crypt_algo=self.crypt_algo,
+                                           crypt_key=self.crypt_key,
+                                           auth_algo=self.auth_algo,
+                                           auth_key=self.auth_key,
+                                           tunnel_header=IP(
+                                               src=self.tun_if.remote_ip4,
+                                               dst=self.tun_if.local_ip4))
+        vpp_tun_sa = SecurityAssociation(self.encryption_type,
+                                         spi=self.scapy_tun_spi,
+                                         crypt_algo=self.crypt_algo,
+                                         crypt_key=self.crypt_key,
+                                         auth_algo=self.auth_algo,
+                                         auth_key=self.auth_key,
+                                         tunnel_header=IP(
+                                             dst=self.tun_if.remote_ip4,
+                                             src=self.tun_if.local_ip4))
+        return vpp_tun_sa, scapy_tun_sa
+
+    def configure_sa_tra(self):
+        scapy_tra_sa = SecurityAssociation(self.encryption_type,
+                                           spi=self.vpp_tra_spi,
+                                           crypt_algo=self.crypt_algo,
+                                           crypt_key=self.crypt_key,
+                                           auth_algo=self.auth_algo,
+                                           auth_key=self.auth_key)
+        vpp_tra_sa = SecurityAssociation(self.encryption_type,
+                                         spi=self.scapy_tra_spi,
+                                         crypt_algo=self.crypt_algo,
+                                         crypt_key=self.crypt_key,
+                                         auth_algo=self.auth_algo,
+                                         auth_key=self.auth_key)
+        return vpp_tra_sa, scapy_tra_sa
+
+
+class IpsecTcpTests(object):
+    def test_tcp_checksum(self):
+        """ verify checksum correctness for vpp generated packets """
+        self.vapi.cli("test http server")
+        vpp_tun_sa, scapy_tun_sa = self.configure_sa_tun()
+        send = (Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac) /
+                scapy_tun_sa.encrypt(IP(src=self.remote_tun_if_host,
+                                        dst=self.tun_if.local_ip4) /
+                                     TCP(flags='S', dport=80)))
+        self.logger.debug(ppp("Sending packet:", send))
+        recv = self.send_and_expect(self.tun_if, [send], self.tun_if, 1)
+        recv = recv[0]
+        decrypted = vpp_tun_sa.decrypt(recv[IP])
+        self.assert_packet_checksums_valid(decrypted)
+
+
+class IpsecTraTests(object):
+    def test_tra_basic(self, count=1):
+        """ ipsec v4 transport basic test """
+        try:
+            vpp_tra_sa, scapy_tra_sa = self.configure_sa_tra()
+            send_pkts = self.gen_encrypt_pkts(scapy_tra_sa, self.tra_if,
+                                              src=self.tra_if.remote_ip4,
+                                              dst=self.tra_if.local_ip4,
+                                              count=count)
+            recv_pkts = self.send_and_expect(self.tra_if, send_pkts,
+                                             self.tra_if, count=count)
+            for p in recv_pkts:
+                decrypted = vpp_tra_sa.decrypt(p[IP])
+                self.assert_packet_checksums_valid(decrypted)
+        finally:
+            self.logger.info(self.vapi.ppcli("show error"))
+            self.logger.info(self.vapi.ppcli("show ipsec"))
+
+    def test_tra_burst(self):
+        """ ipsec v4 transport burst test """
+        try:
+            self.test_tra_basic(count=257)
+        finally:
+            self.logger.info(self.vapi.ppcli("show error"))
+            self.logger.info(self.vapi.ppcli("show ipsec"))
+
+
+class IpsecTunTests(object):
+    def test_tun_basic(self, count=1):
+        """ ipsec 4o4 tunnel basic test """
+        try:
+            vpp_tun_sa, scapy_tun_sa = self.configure_sa_tun()
+            send_pkts = self.gen_encrypt_pkts(scapy_tun_sa, self.tun_if,
+                                              src=self.remote_tun_if_host,
+                                              dst=self.pg1.remote_ip4,
+                                              count=count)
+            recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1,
+                                             count=count)
+            for recv_pkt in recv_pkts:
+                self.assert_equal(recv_pkt[IP].src, self.remote_tun_if_host)
+                self.assert_equal(recv_pkt[IP].dst, self.pg1.remote_ip4)
+                self.assert_packet_checksums_valid(recv_pkt)
+            send_pkts = self.gen_pkts(self.pg1, src=self.pg1.remote_ip4,
+                                      dst=self.remote_tun_if_host, count=count)
+            recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if,
+                                             count=count)
+            for recv_pkt in recv_pkts:
+                decrypt_pkt = vpp_tun_sa.decrypt(recv_pkt[IP])
+                if not decrypt_pkt.haslayer(IP):
+                    decrypt_pkt = IP(decrypt_pkt[Raw].load)
+                self.assert_equal(decrypt_pkt.src, self.pg1.remote_ip4)
+                self.assert_equal(decrypt_pkt.dst, self.remote_tun_if_host)
+                self.assert_packet_checksums_valid(decrypt_pkt)
+        finally:
+            self.logger.info(self.vapi.ppcli("show error"))
+            self.logger.info(self.vapi.ppcli("show ipsec"))
+
+    def test_tun_burst(self):
+        """ ipsec 4o4 tunnel burst test """
+        try:
+            self.test_tun_basic(count=257)
+        finally:
+            self.logger.info(self.vapi.ppcli("show error"))
+            self.logger.info(self.vapi.ppcli("show ipsec"))
+
+
+if __name__ == '__main__':
+    unittest.main(testRunner=VppTestRunner)
index d173b2e..729f871 100644 (file)
@@ -1,14 +1,14 @@
 import socket
 import unittest
 
 import socket
 import unittest
 
-from scapy.layers.inet import IP, ICMP
-from scapy.layers.l2 import Ether, Raw
-from scapy.layers.ipsec import SecurityAssociation, AH
+from scapy.layers.ipsec import AH
 
 
-from framework import VppTestCase, VppTestRunner
+from framework import VppTestRunner
+from template_ipsec import TemplateIpsec, IpsecTraTests, IpsecTunTests
+from template_ipsec import IpsecTcpTests
 
 
 
 
-class TestIpsecAh(VppTestCase):
+class TemplateIpsecAh(TemplateIpsec):
     """
     Basic test for IPSEC using AH transport and Tunnel mode
 
     """
     Basic test for IPSEC using AH transport and Tunnel mode
 
@@ -41,214 +41,123 @@ class TestIpsecAh(VppTestCase):
     Note : IPv6 is not covered
     """
 
     Note : IPv6 is not covered
     """
 
-    remote_pg0_lb_addr = '1.1.1.1'
-    remote_pg1_lb_addr = '2.2.2.2'
-    payload = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+    encryption_type = AH
 
     @classmethod
     def setUpClass(cls):
 
     @classmethod
     def setUpClass(cls):
-        super(TestIpsecAh, cls).setUpClass()
-        try:
-            cls.create_pg_interfaces(range(3))
-            cls.interfaces = list(cls.pg_interfaces)
-            for i in cls.interfaces:
-                i.admin_up()
-                i.config_ip4()
-                i.resolve_arp()
-            cls.logger.info(cls.vapi.ppcli("show int addr"))
-            cls.config_ah_tra()
-            cls.logger.info(cls.vapi.ppcli("show ipsec"))
-            cls.config_ah_tun()
-            cls.logger.info(cls.vapi.ppcli("show ipsec"))
-        except Exception:
-            super(TestIpsecAh, cls).tearDownClass()
-            raise
+        super(TemplateIpsecAh, cls).setUpClass()
+        cls.tun_if = cls.pg0
+        cls.tra_if = cls.pg2
+        cls.logger.info(cls.vapi.ppcli("show int addr"))
+        cls.config_ah_tra()
+        cls.logger.info(cls.vapi.ppcli("show ipsec"))
+        cls.config_ah_tun()
+        cls.logger.info(cls.vapi.ppcli("show ipsec"))
+        src4 = socket.inet_pton(socket.AF_INET, cls.remote_tun_if_host)
+        cls.vapi.ip_add_del_route(src4, 32, cls.tun_if.remote_ip4n)
 
     @classmethod
     def config_ah_tun(cls):
 
     @classmethod
     def config_ah_tun(cls):
-        spd_id = 1
-        remote_sa_id = 10
-        local_sa_id = 20
-        remote_tun_spi = 1001
-        local_tun_spi = 1000
-        src4 = socket.inet_pton(socket.AF_INET, cls.remote_pg0_lb_addr)
-        cls.vapi.ip_add_del_route(src4, 32, cls.pg0.remote_ip4n)
-        dst4 = socket.inet_pton(socket.AF_INET, cls.remote_pg1_lb_addr)
-        cls.vapi.ip_add_del_route(dst4, 32, cls.pg1.remote_ip4n)
-        cls.vapi.ipsec_sad_add_del_entry(remote_sa_id, remote_tun_spi,
-                                         cls.pg0.local_ip4n,
-                                         cls.pg0.remote_ip4n,
-                                         integrity_key_length=20)
-        cls.vapi.ipsec_sad_add_del_entry(local_sa_id, local_tun_spi,
-                                         cls.pg0.remote_ip4n,
-                                         cls.pg0.local_ip4n,
-                                         integrity_key_length=20)
-        cls.vapi.ipsec_spd_add_del(spd_id)
-        cls.vapi.ipsec_interface_add_del_spd(spd_id, cls.pg0.sw_if_index)
+        cls.vapi.ipsec_sad_add_del_entry(cls.scapy_tun_sa_id,
+                                         cls.scapy_tun_spi,
+                                         cls.auth_algo_vpp_id, cls.auth_key,
+                                         cls.crypt_algo_vpp_id,
+                                         cls.crypt_key, cls.vpp_ah_protocol,
+                                         cls.tun_if.local_ip4n,
+                                         cls.tun_if.remote_ip4n)
+        cls.vapi.ipsec_sad_add_del_entry(cls.vpp_tun_sa_id,
+                                         cls.vpp_tun_spi,
+                                         cls.auth_algo_vpp_id, cls.auth_key,
+                                         cls.crypt_algo_vpp_id,
+                                         cls.crypt_key, cls.vpp_ah_protocol,
+                                         cls.tun_if.remote_ip4n,
+                                         cls.tun_if.local_ip4n)
+        cls.vapi.ipsec_spd_add_del(cls.tun_spd_id)
+        cls.vapi.ipsec_interface_add_del_spd(cls.tun_spd_id,
+                                             cls.tun_if.sw_if_index)
         l_startaddr = r_startaddr = socket.inet_pton(socket.AF_INET, "0.0.0.0")
         l_stopaddr = r_stopaddr = socket.inet_pton(socket.AF_INET,
                                                    "255.255.255.255")
         l_startaddr = r_startaddr = socket.inet_pton(socket.AF_INET, "0.0.0.0")
         l_stopaddr = r_stopaddr = socket.inet_pton(socket.AF_INET,
                                                    "255.255.255.255")
-        cls.vapi.ipsec_spd_add_del_entry(spd_id, l_startaddr, l_stopaddr,
-                                         r_startaddr, r_stopaddr,
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.vpp_tun_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr,
+                                         protocol=socket.IPPROTO_AH)
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.vpp_tun_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, is_outbound=0,
                                          protocol=socket.IPPROTO_AH)
                                          protocol=socket.IPPROTO_AH)
-        cls.vapi.ipsec_spd_add_del_entry(spd_id, l_startaddr, l_stopaddr,
-                                         r_startaddr, r_stopaddr,
-                                         protocol=socket.IPPROTO_AH,
-                                         is_outbound=0)
         l_startaddr = l_stopaddr = socket.inet_pton(socket.AF_INET,
         l_startaddr = l_stopaddr = socket.inet_pton(socket.AF_INET,
-                                                    cls.remote_pg0_lb_addr)
-        r_startaddr = r_stopaddr = socket.inet_pton(socket.AF_INET,
-                                                    cls.remote_pg1_lb_addr)
-        cls.vapi.ipsec_spd_add_del_entry(spd_id, l_startaddr, l_stopaddr,
-                                         r_startaddr, r_stopaddr,
-                                         priority=10, policy=3,
-                                         is_outbound=0, sa_id=local_sa_id)
-        cls.vapi.ipsec_spd_add_del_entry(spd_id, r_startaddr, r_stopaddr,
-                                         l_startaddr, l_stopaddr, priority=10,
-                                         policy=3, sa_id=remote_sa_id)
+                                                    cls.remote_tun_if_host)
+        r_startaddr = r_stopaddr = cls.pg1.remote_ip4n
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.vpp_tun_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, priority=10, policy=3,
+                                         is_outbound=0)
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.scapy_tun_sa_id,
+                                         r_startaddr, r_stopaddr, l_startaddr,
+                                         l_stopaddr, priority=10, policy=3)
+        r_startaddr = r_stopaddr = cls.pg0.local_ip4n
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.vpp_tun_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, priority=20, policy=3,
+                                         is_outbound=0)
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.scapy_tun_sa_id,
+                                         r_startaddr, r_stopaddr, l_startaddr,
+                                         l_stopaddr, priority=20, policy=3)
 
     @classmethod
     def config_ah_tra(cls):
 
     @classmethod
     def config_ah_tra(cls):
-        spd_id = 2
-        remote_sa_id = 30
-        local_sa_id = 40
-        remote_tra_spi = 2001
-        local_tra_spi = 2000
-        cls.vapi.ipsec_sad_add_del_entry(remote_sa_id, remote_tra_spi,
-                                         integrity_key_length=20, is_tunnel=0)
-        cls.vapi.ipsec_sad_add_del_entry(local_sa_id, local_tra_spi,
-                                         integrity_key_length=20, is_tunnel=0)
-        cls.vapi.ipsec_spd_add_del(spd_id)
-        cls.vapi.ipsec_interface_add_del_spd(spd_id, cls.pg2.sw_if_index)
+        cls.vapi.ipsec_sad_add_del_entry(cls.scapy_tra_sa_id,
+                                         cls.scapy_tra_spi,
+                                         cls.auth_algo_vpp_id, cls.auth_key,
+                                         cls.crypt_algo_vpp_id,
+                                         cls.crypt_key, cls.vpp_ah_protocol,
+                                         is_tunnel=0)
+        cls.vapi.ipsec_sad_add_del_entry(cls.vpp_tra_sa_id,
+                                         cls.vpp_tra_spi,
+                                         cls.auth_algo_vpp_id, cls.auth_key,
+                                         cls.crypt_algo_vpp_id,
+                                         cls.crypt_key, cls.vpp_ah_protocol,
+                                         is_tunnel=0)
+        cls.vapi.ipsec_spd_add_del(cls.tra_spd_id)
+        cls.vapi.ipsec_interface_add_del_spd(cls.tra_spd_id,
+                                             cls.tra_if.sw_if_index)
         l_startaddr = r_startaddr = socket.inet_pton(socket.AF_INET, "0.0.0.0")
         l_stopaddr = r_stopaddr = socket.inet_pton(socket.AF_INET,
                                                    "255.255.255.255")
         l_startaddr = r_startaddr = socket.inet_pton(socket.AF_INET, "0.0.0.0")
         l_stopaddr = r_stopaddr = socket.inet_pton(socket.AF_INET,
                                                    "255.255.255.255")
-        cls.vapi.ipsec_spd_add_del_entry(spd_id, l_startaddr, l_stopaddr,
-                                         r_startaddr, r_stopaddr,
+        cls.vapi.ipsec_spd_add_del_entry(cls.tra_spd_id, cls.vpp_tra_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr,
                                          protocol=socket.IPPROTO_AH)
                                          protocol=socket.IPPROTO_AH)
-        cls.vapi.ipsec_spd_add_del_entry(spd_id, l_startaddr, l_stopaddr,
-                                         r_startaddr, r_stopaddr,
-                                         protocol=socket.IPPROTO_AH,
+        cls.vapi.ipsec_spd_add_del_entry(cls.tra_spd_id, cls.scapy_tra_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, is_outbound=0,
+                                         protocol=socket.IPPROTO_AH)
+        l_startaddr = l_stopaddr = cls.tra_if.local_ip4n
+        r_startaddr = r_stopaddr = cls.tra_if.remote_ip4n
+        cls.vapi.ipsec_spd_add_del_entry(cls.tra_spd_id, cls.vpp_tra_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, priority=10, policy=3,
                                          is_outbound=0)
                                          is_outbound=0)
-        l_startaddr = l_stopaddr = cls.pg2.local_ip4n
-        r_startaddr = r_stopaddr = cls.pg2.remote_ip4n
-        cls.vapi.ipsec_spd_add_del_entry(spd_id, l_startaddr, l_stopaddr,
-                                         r_startaddr, r_stopaddr,
-                                         priority=10, policy=3,
-                                         is_outbound=0, sa_id=local_sa_id)
-        cls.vapi.ipsec_spd_add_del_entry(spd_id, l_startaddr, l_stopaddr,
-                                         r_startaddr, r_stopaddr, priority=10,
-                                         policy=3, sa_id=remote_sa_id)
-
-    def configure_scapy_sa_tun(self):
-        remote_tun_sa = SecurityAssociation(AH, spi=0x000003e8,
-                                            auth_algo='HMAC-SHA1-96',
-                                            auth_key='C91KUR9GYMm5GfkEvNjX',
-                                            tunnel_header=IP(
-                                                src=self.pg0.remote_ip4,
-                                                dst=self.pg0.local_ip4))
-        local_tun_sa = SecurityAssociation(AH, spi=0x000003e9,
-                                           auth_algo='HMAC-SHA1-96',
-                                           auth_key='C91KUR9GYMm5GfkEvNjX',
-                                           tunnel_header=IP(
-                                               dst=self.pg0.remote_ip4,
-                                               src=self.pg0.local_ip4))
-        return local_tun_sa, remote_tun_sa
-
-    def configure_scapy_sa_tra(self):
-        remote_tra_sa = SecurityAssociation(AH, spi=0x000007d0,
-                                            auth_algo='HMAC-SHA1-96',
-                                            auth_key='C91KUR9GYMm5GfkEvNjX')
-        local_tra_sa = SecurityAssociation(AH, spi=0x000007d1,
-                                           auth_algo='HMAC-SHA1-96',
-                                           auth_key='C91KUR9GYMm5GfkEvNjX')
-        return local_tra_sa, remote_tra_sa
+        cls.vapi.ipsec_spd_add_del_entry(cls.tra_spd_id, cls.scapy_tra_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, priority=10,
+                                         policy=3)
 
     def tearDown(self):
 
     def tearDown(self):
-        super(TestIpsecAh, self).tearDown()
+        super(TemplateIpsecAh, self).tearDown()
         if not self.vpp_dead:
             self.vapi.cli("show hardware")
 
         if not self.vpp_dead:
             self.vapi.cli("show hardware")
 
-    def send_and_expect(self, input, pkts, output, count=1):
-        input.add_stream(pkts)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        rx = output.get_capture(count)
-        return rx
-
-    def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1):
-        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
-                sa.encrypt(IP(src=src, dst=dst) / ICMP() / self.payload)
-                ] * count
-
-    def gen_pkts(self, sw_intf, src, dst, count=1):
-        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
-                IP(src=src, dst=dst) / ICMP() / self.payload
-                ] * count
-
-    def test_ipsec_ah_tra_basic(self, count=1):
-        """ ipsec ah v4 transport basic test """
-        try:
-            local_tra_sa, remote_tra_sa = self.configure_scapy_sa_tra()
-            send_pkts = self.gen_encrypt_pkts(remote_tra_sa, self.pg2,
-                                              src=self.pg2.remote_ip4,
-                                              dst=self.pg2.local_ip4,
-                                              count=count)
-            recv_pkts = self.send_and_expect(self.pg2, send_pkts, self.pg2,
-                                             count=count)
-            # ESP TRA VPP encryption/decryption verification
-            for Pkts in recv_pkts:
-                Pkts[AH].padding = Pkts[AH].icv[12:]
-                Pkts[AH].icv = Pkts[AH].icv[:12]
-                local_tra_sa.decrypt(Pkts[IP])
-        finally:
-            self.logger.info(self.vapi.ppcli("show error"))
-            self.logger.info(self.vapi.ppcli("show ipsec"))
-
-    def test_ipsec_ah_tra_burst(self):
-        """ ipsec ah v4 transport burst test """
-        try:
-            self.test_ipsec_ah_tra_basic(count=257)
-        finally:
-            self.logger.info(self.vapi.ppcli("show error"))
-            self.logger.info(self.vapi.ppcli("show ipsec"))
-
-    def test_ipsec_ah_tun_basic(self, count=1):
-        """ ipsec ah 4o4 tunnel basic test """
-        try:
-            local_tun_sa, remote_tun_sa = self.configure_scapy_sa_tun()
-            send_pkts = self.gen_encrypt_pkts(remote_tun_sa, self.pg0,
-                                              src=self.remote_pg0_lb_addr,
-                                              dst=self.remote_pg1_lb_addr,
-                                              count=count)
-            recv_pkts = self.send_and_expect(self.pg0, send_pkts, self.pg1,
-                                             count=count)
-            # ESP TUN VPP decryption verification
-            for recv_pkt in recv_pkts:
-                self.assert_equal(recv_pkt[IP].src, self.remote_pg0_lb_addr)
-                self.assert_equal(recv_pkt[IP].dst, self.remote_pg1_lb_addr)
-            send_pkts = self.gen_pkts(self.pg1, src=self.remote_pg1_lb_addr,
-                                      dst=self.remote_pg0_lb_addr,
-                                      count=count)
-            recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.pg0,
-                                             count=count)
-            # ESP TUN VPP encryption verification
-            for recv_pkt in recv_pkts:
-                decrypt_pkt = local_tun_sa.decrypt(recv_pkt[IP])
-                decrypt_pkt = IP(decrypt_pkt[Raw].load)
-                self.assert_equal(decrypt_pkt.src, self.remote_pg1_lb_addr)
-                self.assert_equal(decrypt_pkt.dst, self.remote_pg0_lb_addr)
-        finally:
-            self.logger.info(self.vapi.ppcli("show error"))
-            self.logger.info(self.vapi.ppcli("show ipsec"))
-
-    def test_ipsec_ah_tun_burst(self):
-        """ ipsec ah 4o4 tunnel burst test """
-        try:
-            self.test_ipsec_ah_tun_basic(count=257)
-        finally:
-            self.logger.info(self.vapi.ppcli("show error"))
-            self.logger.info(self.vapi.ppcli("show ipsec"))
+
+class TestIpsecAh1(TemplateIpsecAh, IpsecTraTests, IpsecTunTests):
+    """ Ipsec AH - TUN & TRA tests """
+    pass
+
+
+class TestIpsecAh2(TemplateIpsecAh, IpsecTcpTests):
+    """ Ipsec AH - TCP tests """
+    pass
 
 
 if __name__ == '__main__':
 
 
 if __name__ == '__main__':
index 15ce4a9..58d159a 100644 (file)
@@ -1,14 +1,13 @@
 import socket
 import unittest
 import socket
 import unittest
+from scapy.layers.ipsec import ESP
 
 
-from scapy.layers.inet import IP, ICMP
-from scapy.layers.l2 import Ether
-from scapy.layers.ipsec import SecurityAssociation, ESP
+from framework import VppTestRunner
+from template_ipsec import IpsecTraTests, IpsecTunTests
+from template_ipsec import TemplateIpsec, IpsecTcpTests
 
 
-from framework import VppTestCase, VppTestRunner
 
 
-
-class TestIpsecEsp(VppTestCase):
+class TemplateIpsecEsp(TemplateIpsec):
     """
     Basic test for ipsec esp sanity - tunnel and transport modes.
 
     """
     Basic test for ipsec esp sanity - tunnel and transport modes.
 
@@ -41,298 +40,121 @@ class TestIpsecEsp(VppTestCase):
     Note : IPv6 is not covered
     """
 
     Note : IPv6 is not covered
     """
 
-    remote_pg0_lb_addr = '1.1.1.1'
-    remote_pg1_lb_addr = '2.2.2.2'
+    encryption_type = ESP
 
     @classmethod
     def setUpClass(cls):
 
     @classmethod
     def setUpClass(cls):
-        super(TestIpsecEsp, cls).setUpClass()
-        try:
-            cls.create_pg_interfaces(range(3))
-            cls.interfaces = list(cls.pg_interfaces)
-            for i in cls.interfaces:
-                i.admin_up()
-                i.config_ip4()
-                i.resolve_arp()
-            cls.logger.info(cls.vapi.ppcli("show int addr"))
-            cls.configEspTra()
-            cls.logger.info(cls.vapi.ppcli("show ipsec"))
-            cls.configEspTun()
-            cls.logger.info(cls.vapi.ppcli("show ipsec"))
-        except Exception:
-            super(TestIpsecEsp, cls).tearDownClass()
-            raise
+        super(TemplateIpsecEsp, cls).setUpClass()
+        cls.tun_if = cls.pg0
+        cls.tra_if = cls.pg2
+        cls.logger.info(cls.vapi.ppcli("show int addr"))
+        cls.config_esp_tra()
+        cls.logger.info(cls.vapi.ppcli("show ipsec"))
+        cls.config_esp_tun()
+        cls.logger.info(cls.vapi.ppcli("show ipsec"))
+        src4 = socket.inet_pton(socket.AF_INET, cls.remote_tun_if_host)
+        cls.vapi.ip_add_del_route(src4, 32, cls.tun_if.remote_ip4n)
 
     @classmethod
 
     @classmethod
-    def configEspTun(cls):
-        try:
-            spd_id = 1
-            remote_sa_id = 10
-            local_sa_id = 20
-            remote_tun_spi = 1001
-            local_tun_spi = 1000
-            src4 = socket.inet_pton(socket.AF_INET, cls.remote_pg0_lb_addr)
-            cls.vapi.ip_add_del_route(src4, 32, cls.pg0.remote_ip4n)
-            dst4 = socket.inet_pton(socket.AF_INET, cls.remote_pg1_lb_addr)
-            cls.vapi.ip_add_del_route(dst4, 32, cls.pg1.remote_ip4n)
-            cls.vapi.ipsec_sad_add_del_entry(
-                remote_sa_id,
-                remote_tun_spi,
-                cls.pg0.local_ip4n,
-                cls.pg0.remote_ip4n,
-                integrity_key_length=20,
-                crypto_key_length=16,
-                protocol=1)
-            cls.vapi.ipsec_sad_add_del_entry(
-                local_sa_id,
-                local_tun_spi,
-                cls.pg0.remote_ip4n,
-                cls.pg0.local_ip4n,
-                integrity_key_length=20,
-                crypto_key_length=16,
-                protocol=1)
-            cls.vapi.ipsec_spd_add_del(spd_id)
-            cls.vapi.ipsec_interface_add_del_spd(spd_id, cls.pg0.sw_if_index)
-            l_startaddr = r_startaddr = socket.inet_pton(
-                socket.AF_INET, "0.0.0.0")
-            l_stopaddr = r_stopaddr = socket.inet_pton(
-                socket.AF_INET, "255.255.255.255")
-            cls.vapi.ipsec_spd_add_del_entry(
-                spd_id,
-                l_startaddr,
-                l_stopaddr,
-                r_startaddr,
-                r_stopaddr,
-                protocol=socket.IPPROTO_ESP)
-            cls.vapi.ipsec_spd_add_del_entry(
-                spd_id,
-                l_startaddr,
-                l_stopaddr,
-                r_startaddr,
-                r_stopaddr,
-                protocol=socket.IPPROTO_ESP,
-                is_outbound=0)
-            l_startaddr = l_stopaddr = socket.inet_pton(
-                socket.AF_INET, cls.remote_pg0_lb_addr)
-            r_startaddr = r_stopaddr = socket.inet_pton(
-                socket.AF_INET, cls.remote_pg1_lb_addr)
-            cls.vapi.ipsec_spd_add_del_entry(
-                spd_id,
-                l_startaddr,
-                l_stopaddr,
-                r_startaddr,
-                r_stopaddr,
-                priority=10,
-                policy=3,
-                is_outbound=0,
-                sa_id=local_sa_id)
-            cls.vapi.ipsec_spd_add_del_entry(
-                spd_id,
-                r_startaddr,
-                r_stopaddr,
-                l_startaddr,
-                l_stopaddr,
-                priority=10,
-                policy=3,
-                sa_id=remote_sa_id)
-        except Exception:
-            raise
+    def config_esp_tun(cls):
+        cls.vapi.ipsec_sad_add_del_entry(cls.scapy_tun_sa_id,
+                                         cls.scapy_tun_spi,
+                                         cls.auth_algo_vpp_id, cls.auth_key,
+                                         cls.crypt_algo_vpp_id,
+                                         cls.crypt_key, cls.vpp_esp_protocol,
+                                         cls.tun_if.local_ip4n,
+                                         cls.tun_if.remote_ip4n)
+        cls.vapi.ipsec_sad_add_del_entry(cls.vpp_tun_sa_id,
+                                         cls.vpp_tun_spi,
+                                         cls.auth_algo_vpp_id, cls.auth_key,
+                                         cls.crypt_algo_vpp_id,
+                                         cls.crypt_key, cls.vpp_esp_protocol,
+                                         cls.tun_if.remote_ip4n,
+                                         cls.tun_if.local_ip4n)
+        cls.vapi.ipsec_spd_add_del(cls.tun_spd_id)
+        cls.vapi.ipsec_interface_add_del_spd(cls.tun_spd_id,
+                                             cls.tun_if.sw_if_index)
+        l_startaddr = r_startaddr = socket.inet_pton(socket.AF_INET,
+                                                     "0.0.0.0")
+        l_stopaddr = r_stopaddr = socket.inet_pton(socket.AF_INET,
+                                                   "255.255.255.255")
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.scapy_tun_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr,
+                                         protocol=socket.IPPROTO_ESP)
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.scapy_tun_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, is_outbound=0,
+                                         protocol=socket.IPPROTO_ESP)
+        l_startaddr = l_stopaddr = socket.inet_pton(socket.AF_INET,
+                                                    cls.remote_tun_if_host)
+        r_startaddr = r_stopaddr = cls.pg1.remote_ip4n
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.vpp_tun_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, priority=10, policy=3,
+                                         is_outbound=0)
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.scapy_tun_sa_id,
+                                         r_startaddr, r_stopaddr, l_startaddr,
+                                         l_stopaddr, priority=10, policy=3)
+        l_startaddr = l_stopaddr = socket.inet_pton(socket.AF_INET,
+                                                    cls.remote_tun_if_host)
+        r_startaddr = r_stopaddr = cls.pg0.local_ip4n
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.vpp_tun_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, priority=20, policy=3,
+                                         is_outbound=0)
+        cls.vapi.ipsec_spd_add_del_entry(cls.tun_spd_id, cls.scapy_tun_sa_id,
+                                         r_startaddr, r_stopaddr, l_startaddr,
+                                         l_stopaddr, priority=20, policy=3)
 
     @classmethod
 
     @classmethod
-    def configEspTra(cls):
-        try:
-            spd_id = 2
-            remote_sa_id = 30
-            local_sa_id = 40
-            remote_tra_spi = 2001
-            local_tra_spi = 2000
-            cls.vapi.ipsec_sad_add_del_entry(
-                remote_sa_id,
-                remote_tra_spi,
-                integrity_key_length=20,
-                crypto_key_length=16,
-                protocol=1,
-                is_tunnel=0)
-            cls.vapi.ipsec_sad_add_del_entry(
-                local_sa_id,
-                local_tra_spi,
-                integrity_key_length=20,
-                crypto_key_length=16,
-                protocol=1,
-                is_tunnel=0)
-            cls.vapi.ipsec_spd_add_del(spd_id)
-            cls.vapi.ipsec_interface_add_del_spd(spd_id, cls.pg2.sw_if_index)
-            l_startaddr = r_startaddr = socket.inet_pton(
-                socket.AF_INET, "0.0.0.0")
-            l_stopaddr = r_stopaddr = socket.inet_pton(
-                socket.AF_INET, "255.255.255.255")
-            cls.vapi.ipsec_spd_add_del_entry(
-                spd_id,
-                l_startaddr,
-                l_stopaddr,
-                r_startaddr,
-                r_stopaddr,
-                protocol=socket.IPPROTO_ESP)
-            cls.vapi.ipsec_spd_add_del_entry(
-                spd_id,
-                l_startaddr,
-                l_stopaddr,
-                r_startaddr,
-                r_stopaddr,
-                protocol=socket.IPPROTO_ESP,
-                is_outbound=0)
-            l_startaddr = l_stopaddr = cls.pg2.local_ip4n
-            r_startaddr = r_stopaddr = cls.pg2.remote_ip4n
-            cls.vapi.ipsec_spd_add_del_entry(
-                spd_id,
-                l_startaddr,
-                l_stopaddr,
-                r_startaddr,
-                r_stopaddr,
-                priority=10,
-                policy=3,
-                is_outbound=0,
-                sa_id=local_sa_id)
-            cls.vapi.ipsec_spd_add_del_entry(
-                spd_id,
-                l_startaddr,
-                l_stopaddr,
-                r_startaddr,
-                r_stopaddr,
-                priority=10,
-                policy=3,
-                sa_id=remote_sa_id)
-        except Exception:
-            raise
-
-    def configScapySA(self, is_tun=False):
-        if is_tun:
-            self.remote_tun_sa = SecurityAssociation(
-                ESP,
-                spi=0x000003e8,
-                crypt_algo='AES-CBC',
-                crypt_key='JPjyOWBeVEQiMe7h',
-                auth_algo='HMAC-SHA1-96',
-                auth_key='C91KUR9GYMm5GfkEvNjX',
-                tunnel_header=IP(
-                    src=self.pg0.remote_ip4,
-                    dst=self.pg0.local_ip4))
-            self.local_tun_sa = SecurityAssociation(
-                ESP,
-                spi=0x000003e9,
-                crypt_algo='AES-CBC',
-                crypt_key='JPjyOWBeVEQiMe7h',
-                auth_algo='HMAC-SHA1-96',
-                auth_key='C91KUR9GYMm5GfkEvNjX',
-                tunnel_header=IP(
-                    dst=self.pg0.remote_ip4,
-                    src=self.pg0.local_ip4))
-        else:
-            self.remote_tra_sa = SecurityAssociation(
-                ESP,
-                spi=0x000007d0,
-                crypt_algo='AES-CBC',
-                crypt_key='JPjyOWBeVEQiMe7h',
-                auth_algo='HMAC-SHA1-96',
-                auth_key='C91KUR9GYMm5GfkEvNjX')
-            self.local_tra_sa = SecurityAssociation(
-                ESP,
-                spi=0x000007d1,
-                crypt_algo='AES-CBC',
-                crypt_key='JPjyOWBeVEQiMe7h',
-                auth_algo='HMAC-SHA1-96',
-                auth_key='C91KUR9GYMm5GfkEvNjX')
-
-    def tearDown(self):
-        super(TestIpsecEsp, self).tearDown()
-        if not self.vpp_dead:
-            self.vapi.cli("show hardware")
-
-    def send_and_expect(self, input, pkts, output, count=1):
-        input.add_stream(pkts)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        rx = output.get_capture(count)
-        return rx
-
-    def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1):
-        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
-                sa.encrypt(IP(src=src, dst=dst) / ICMP() /
-                "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
-                ] * count
-
-    def gen_pkts(self, sw_intf, src, dst, count=1):
-        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
-                IP(src=src, dst=dst) / ICMP() /
-                "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
-                ] * count
-
-    def test_ipsec_esp_tra_basic(self, count=1):
-        """ ipsec esp v4 transport basic test """
-        try:
-            self.configScapySA()
-            send_pkts = self.gen_encrypt_pkts(
-                self.remote_tra_sa,
-                self.pg2,
-                src=self.pg2.remote_ip4,
-                dst=self.pg2.local_ip4,
-                count=count)
-            recv_pkts = self.send_and_expect(
-                self.pg2, send_pkts, self.pg2, count=count)
-            # ESP TRA VPP encryption/decryption verification
-            for Pkts in recv_pkts:
-                self.local_tra_sa.decrypt(Pkts[IP])
-        finally:
-            self.logger.info(self.vapi.ppcli("show error"))
-            self.logger.info(self.vapi.ppcli("show ipsec"))
-
-    def test_ipsec_esp_tra_burst(self):
-        """ ipsec esp v4 transport burst test """
-        try:
-            self.test_ipsec_esp_tra_basic(count=257)
-        finally:
-            self.logger.info(self.vapi.ppcli("show error"))
-            self.logger.info(self.vapi.ppcli("show ipsec"))
-
-    def test_ipsec_esp_tun_basic(self, count=1):
-        """ ipsec esp 4o4 tunnel basic test """
-        try:
-            self.configScapySA(is_tun=True)
-            send_pkts = self.gen_encrypt_pkts(
-                self.remote_tun_sa,
-                self.pg0,
-                src=self.remote_pg0_lb_addr,
-                dst=self.remote_pg1_lb_addr,
-                count=count)
-            recv_pkts = self.send_and_expect(
-                self.pg0, send_pkts, self.pg1, count=count)
-            # ESP TUN VPP decryption verification
-            for recv_pkt in recv_pkts:
-                self.assert_equal(recv_pkt[IP].src, self.remote_pg0_lb_addr)
-                self.assert_equal(recv_pkt[IP].dst, self.remote_pg1_lb_addr)
-            send_pkts = self.gen_pkts(
-                self.pg1,
-                src=self.remote_pg1_lb_addr,
-                dst=self.remote_pg0_lb_addr,
-                count=count)
-            recv_pkts = self.send_and_expect(
-                self.pg1, send_pkts, self.pg0, count=count)
-            # ESP TUN VPP encryption verification
-            for recv_pkt in recv_pkts:
-                decrypt_pkt = self.local_tun_sa.decrypt(recv_pkt[IP])
-                self.assert_equal(decrypt_pkt.src, self.remote_pg1_lb_addr)
-                self.assert_equal(decrypt_pkt.dst, self.remote_pg0_lb_addr)
-        finally:
-            self.logger.info(self.vapi.ppcli("show error"))
-            self.logger.info(self.vapi.ppcli("show ipsec"))
-
-    def test_ipsec_esp_tun_burst(self):
-        """ ipsec esp 4o4 tunnel burst test """
-        try:
-            self.test_ipsec_esp_tun_basic(count=257)
-        finally:
-            self.logger.info(self.vapi.ppcli("show error"))
-            self.logger.info(self.vapi.ppcli("show ipsec"))
+    def config_esp_tra(cls):
+        cls.vapi.ipsec_sad_add_del_entry(cls.scapy_tra_sa_id,
+                                         cls.scapy_tra_spi,
+                                         cls.auth_algo_vpp_id, cls.auth_key,
+                                         cls.crypt_algo_vpp_id,
+                                         cls.crypt_key, cls.vpp_esp_protocol,
+                                         is_tunnel=0)
+        cls.vapi.ipsec_sad_add_del_entry(cls.vpp_tra_sa_id,
+                                         cls.vpp_tra_spi,
+                                         cls.auth_algo_vpp_id, cls.auth_key,
+                                         cls.crypt_algo_vpp_id,
+                                         cls.crypt_key, cls.vpp_esp_protocol,
+                                         is_tunnel=0)
+        cls.vapi.ipsec_spd_add_del(cls.tra_spd_id)
+        cls.vapi.ipsec_interface_add_del_spd(cls.tra_spd_id,
+                                             cls.tra_if.sw_if_index)
+        l_startaddr = r_startaddr = socket.inet_pton(socket.AF_INET,
+                                                     "0.0.0.0")
+        l_stopaddr = r_stopaddr = socket.inet_pton(socket.AF_INET,
+                                                   "255.255.255.255")
+        cls.vapi.ipsec_spd_add_del_entry(cls.tra_spd_id, cls.vpp_tra_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr,
+                                         protocol=socket.IPPROTO_ESP)
+        cls.vapi.ipsec_spd_add_del_entry(cls.tra_spd_id, cls.vpp_tra_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, is_outbound=0,
+                                         protocol=socket.IPPROTO_ESP)
+        l_startaddr = l_stopaddr = cls.tra_if.local_ip4n
+        r_startaddr = r_stopaddr = cls.tra_if.remote_ip4n
+        cls.vapi.ipsec_spd_add_del_entry(cls.tra_spd_id, cls.vpp_tra_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, priority=10, policy=3,
+                                         is_outbound=0)
+        cls.vapi.ipsec_spd_add_del_entry(cls.tra_spd_id, cls.scapy_tra_sa_id,
+                                         l_startaddr, l_stopaddr, r_startaddr,
+                                         r_stopaddr, priority=10, policy=3)
+
+
+class TestIpsecEsp1(TemplateIpsecEsp, IpsecTraTests, IpsecTunTests):
+    """ Ipsec ESP - TUN & TRA tests """
+    pass
+
+
+class TestIpsecEsp2(TemplateIpsecEsp, IpsecTcpTests):
+    """ Ipsec ESP - TCP tests """
+    pass
 
 
 if __name__ == '__main__':
 
 
 if __name__ == '__main__':
index cebbfc8..7a5aca6 100644 (file)
@@ -141,17 +141,17 @@ class IPSecNATTestCase(VppTestCase):
         spd_id = 1
         remote_sa_id = 10
         local_sa_id = 20
         spd_id = 1
         remote_sa_id = 10
         local_sa_id = 20
-        remote_tun_spi = 1001
-        local_tun_spi = 1000
+        scapy_tun_spi = 1001
+        vpp_tun_spi = 1000
         client = socket.inet_pton(socket.AF_INET, cls.remote_pg0_client_addr)
         cls.vapi.ip_add_del_route(client, 32, cls.pg0.remote_ip4n)
         client = socket.inet_pton(socket.AF_INET, cls.remote_pg0_client_addr)
         cls.vapi.ip_add_del_route(client, 32, cls.pg0.remote_ip4n)
-        cls.vapi.ipsec_sad_add_del_entry(remote_sa_id, remote_tun_spi,
+        cls.vapi.ipsec_sad_add_del_entry(remote_sa_id, scapy_tun_spi,
                                          cls.pg1.remote_ip4n,
                                          cls.pg0.remote_ip4n,
                                          integrity_key_length=20,
                                          crypto_key_length=16,
                                          protocol=1, udp_encap=1)
                                          cls.pg1.remote_ip4n,
                                          cls.pg0.remote_ip4n,
                                          integrity_key_length=20,
                                          crypto_key_length=16,
                                          protocol=1, udp_encap=1)
-        cls.vapi.ipsec_sad_add_del_entry(local_sa_id, local_tun_spi,
+        cls.vapi.ipsec_sad_add_del_entry(local_sa_id, vpp_tun_spi,
                                          cls.pg0.remote_ip4n,
                                          cls.pg1.remote_ip4n,
                                          integrity_key_length=20,
                                          cls.pg0.remote_ip4n,
                                          cls.pg1.remote_ip4n,
                                          integrity_key_length=20,
diff --git a/test/test_ipsec_tun_if_esp.py b/test/test_ipsec_tun_if_esp.py
new file mode 100644 (file)
index 0000000..c260f03
--- /dev/null
@@ -0,0 +1,52 @@
+import unittest
+import socket
+from scapy.layers.ipsec import ESP
+from framework import VppTestRunner
+from template_ipsec import TemplateIpsec, IpsecTunTests, IpsecTcpTests
+from vpp_ipsec_tun_interface import VppIpsecTunInterface
+
+
+class TemplateIpsecTunIfEsp(TemplateIpsec):
+    """ IPsec tunnel interface tests """
+
+    encryption_type = ESP
+
+    @classmethod
+    def setUpClass(cls):
+        super(TemplateIpsecTunIfEsp, cls).setUpClass()
+        cls.tun_if = cls.pg0
+
+    def setUp(self):
+        self.ipsec_tun_if = VppIpsecTunInterface(self, self.pg0,
+                                                 self.vpp_tun_spi,
+                                                 self.scapy_tun_spi,
+                                                 self.crypt_algo_vpp_id,
+                                                 self.crypt_key,
+                                                 self.crypt_key,
+                                                 self.auth_algo_vpp_id,
+                                                 self.auth_key,
+                                                 self.auth_key)
+        self.ipsec_tun_if.add_vpp_config()
+        self.ipsec_tun_if.admin_up()
+        self.ipsec_tun_if.config_ip4()
+        src4 = socket.inet_pton(socket.AF_INET, self.remote_tun_if_host)
+        self.vapi.ip_add_del_route(src4, 32, self.ipsec_tun_if.remote_ip4n)
+
+    def tearDown(self):
+        if not self.vpp_dead:
+            self.vapi.cli("show hardware")
+        super(TemplateIpsecTunIfEsp, self).tearDown()
+
+
+class TestIpsecTunIfEsp1(TemplateIpsecTunIfEsp, IpsecTunTests):
+    """ Ipsec ESP - TUN tests """
+    pass
+
+
+class TestIpsecTunIfEsp2(TemplateIpsecTunIfEsp, IpsecTcpTests):
+    """ Ipsec ESP - TCP tests """
+    pass
+
+
+if __name__ == '__main__':
+    unittest.main(testRunner=VppTestRunner)
index 194a0c4..e14a31e 100644 (file)
@@ -2,7 +2,6 @@ from abc import abstractmethod, ABCMeta
 import socket
 
 from util import Host, mk_ll_addr
 import socket
 
 from util import Host, mk_ll_addr
-from vpp_neighbor import VppNeighbor
 
 
 class VppInterface(object):
 
 
 class VppInterface(object):
@@ -171,6 +170,9 @@ class VppInterface(object):
         self._hosts_by_ip4 = {}
         self._hosts_by_ip6 = {}
 
         self._hosts_by_ip4 = {}
         self._hosts_by_ip6 = {}
 
+    def set_sw_if_index(self, sw_if_index):
+        self._sw_if_index = sw_if_index
+
         self.generate_remote_hosts()
 
         self._local_ip4 = "172.16.%u.1" % self.sw_if_index
         self.generate_remote_hosts()
 
         self._local_ip4 = "172.16.%u.1" % self.sw_if_index
diff --git a/test/vpp_ipsec_tun_interface.py b/test/vpp_ipsec_tun_interface.py
new file mode 100644 (file)
index 0000000..bd63541
--- /dev/null
@@ -0,0 +1,43 @@
+from vpp_tunnel_interface import VppTunnelInterface
+
+
+class VppIpsecTunInterface(VppTunnelInterface):
+    """
+    VPP IPsec Tunnel interface
+    """
+
+    def __init__(self, test, parent_if, local_spi,
+                 remote_spi, crypto_alg, local_crypto_key, remote_crypto_key,
+                 integ_alg, local_integ_key, remote_integ_key):
+        super(VppIpsecTunInterface, self).__init__(test, parent_if)
+        self.local_spi = local_spi
+        self.remote_spi = remote_spi
+        self.crypto_alg = crypto_alg
+        self.local_crypto_key = local_crypto_key
+        self.remote_crypto_key = remote_crypto_key
+        self.integ_alg = integ_alg
+        self.local_integ_key = local_integ_key
+        self.remote_integ_key = remote_integ_key
+
+    def add_vpp_config(self):
+        r = self.test.vapi.ipsec_tunnel_if_add_del(
+            self.parent_if.local_ip4n, self.parent_if.remote_ip4n,
+            self.remote_spi, self.local_spi, self.crypto_alg,
+            self.local_crypto_key, self.remote_crypto_key, self.integ_alg,
+            self.local_integ_key, self.remote_integ_key)
+        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_tunnel_if_add_del(
+            self.parent_if.local_ip4n, self.parent_if.remote_ip4n,
+            self.remote_spi, self.local_spi, self.crypto_alg,
+            self.local_crypto_key, self.remote_crypto_key, self.integ_alg,
+            self.local_integ_key, self.remote_integ_key, is_add=0)
+
+    def __str__(self):
+        return self.object_id()
+
+    def object_id(self):
+        return "ipsec-tun-if-%d" % self._sw_if_index
index 7869afa..29f07de 100644 (file)
@@ -3163,53 +3163,28 @@ class VppPapiProvider(object):
     def ipsec_sad_add_del_entry(self,
                                 sad_id,
                                 spi,
     def ipsec_sad_add_del_entry(self,
                                 sad_id,
                                 spi,
+                                integrity_algorithm,
+                                integrity_key,
+                                crypto_algorithm,
+                                crypto_key,
+                                protocol,
                                 tunnel_src_address='',
                                 tunnel_dst_address='',
                                 tunnel_src_address='',
                                 tunnel_dst_address='',
-                                protocol=0,
-                                integrity_algorithm=2,
-                                integrity_key_length=0,
-                                integrity_key='C91KUR9GYMm5GfkEvNjX',
-                                crypto_algorithm=1,
-                                crypto_key_length=0,
-                                crypto_key='JPjyOWBeVEQiMe7h',
-                                is_add=1,
                                 is_tunnel=1,
                                 is_tunnel=1,
+                                is_add=1,
                                 udp_encap=0):
         """ IPSEC SA add/del
                                 udp_encap=0):
         """ IPSEC SA add/del
-        Sample CLI : 'ipsec sa add 10 spi 1001 esp \
-            crypto-key 4a506a794f574265564551694d653768 \
-            crypto-alg aes-cbc-128 \
-            integ-key 4339314b55523947594d6d3547666b45764e6a58 \
-            integ-alg sha1-96 tunnel-src 192.168.100.3 \
-            tunnel-dst 192.168.100.2'
-        Sample CLI : 'ipsec sa add 20 spi 2001 \
-            integ-key 4339314b55523947594d6d3547666b45764e6a58 \
-            integ-alg sha1-96'
-
-        :param sad_id -  Security Association ID to be \
-            created or deleted. mandatory
-        :param spi - security param index of the SA in decimal. mandatory
-        :param tunnel_src_address - incase of tunnel mode outer src address .\
-             mandatory for tunnel mode
-        :param tunnel_dst_address - incase of transport mode \
-             outer dst address. mandatory for tunnel mode
-        :param protocol - AH(0) or ESP(1) protocol (Default 0 - AH). optional
-        :param integrity_algorithm - value range 1-6 Default(2 - SHA1_96).\
-             optional **
-        :param integrity_key - value in string \
-             (Default C91KUR9GYMm5GfkEvNjX).optional
-        :param integrity_key_length - length of the key string in bytes\
-             (Default 0 - integrity disabled). optional
-        :param crypto_algorithm - value range 1-11 Default \
-             (1- AES_CBC_128).optional **
-        :param crypto_key - value in string(Default JPjyOWBeVEQiMe7h).optional
-        :param crypto_key_length - length of the key string in bytes\
-             (Default 0 - crypto disabled). optional
-        :param is_add - add(1) or del(0) ipsec SA entry(Default 1 - add) .\
-             optional
-        :param is_tunnel - tunnel mode (1) or transport mode(0) \
-             (Default 1 - tunnel). optional
-        :returns: reply from the API
+        :param sad_id: security association ID
+        :param spi: security param index of the SA in decimal
+        :param integrity_algorithm:
+        :param integrity_key:
+        :param crypto_algorithm:
+        :param crypto_key:
+        :param protocol: AH(0) or ESP(1) protocol
+        :param tunnel_src_address: tunnel mode outer src address
+        :param tunnel_dst_address: tunnel mode outer dst address
+        :param is_add:
+        :param is_tunnel:
         :** reference /vpp/src/vnet/ipsec/ipsec.h file for enum values of
              crypto and ipsec algorithms
         """
         :** reference /vpp/src/vnet/ipsec/ipsec.h file for enum values of
              crypto and ipsec algorithms
         """
@@ -3221,10 +3196,11 @@ class VppPapiProvider(object):
              'tunnel_dst_address': tunnel_dst_address,
              'protocol': protocol,
              'integrity_algorithm': integrity_algorithm,
              'tunnel_dst_address': tunnel_dst_address,
              'protocol': protocol,
              'integrity_algorithm': integrity_algorithm,
-             'integrity_key_length': integrity_key_length,
+             'integrity_key_length': len(integrity_key),
              'integrity_key': integrity_key,
              'crypto_algorithm': crypto_algorithm,
              'integrity_key': integrity_key,
              'crypto_algorithm': crypto_algorithm,
-             'crypto_key_length': crypto_key_length,
+             'crypto_key_length': len(crypto_key) if crypto_key is not None
+             else 0,
              'crypto_key': crypto_key,
              'is_add': is_add,
              'is_tunnel': is_tunnel,
              'crypto_key': crypto_key,
              'is_add': is_add,
              'is_tunnel': is_tunnel,
@@ -3232,6 +3208,7 @@ class VppPapiProvider(object):
 
     def ipsec_spd_add_del_entry(self,
                                 spd_id,
 
     def ipsec_spd_add_del_entry(self,
                                 spd_id,
+                                sa_id,
                                 local_address_start,
                                 local_address_stop,
                                 remote_address_start,
                                 local_address_start,
                                 local_address_stop,
                                 remote_address_start,
@@ -3241,7 +3218,6 @@ class VppPapiProvider(object):
                                 remote_port_start=0,
                                 remote_port_stop=65535,
                                 protocol=0,
                                 remote_port_start=0,
                                 remote_port_stop=65535,
                                 protocol=0,
-                                sa_id=10,
                                 policy=0,
                                 priority=100,
                                 is_outbound=1,
                                 policy=0,
                                 priority=100,
                                 is_outbound=1,
@@ -3249,35 +3225,28 @@ class VppPapiProvider(object):
                                 is_ip_any=0):
         """ IPSEC policy SPD add/del   -
                     Wrapper to configure ipsec SPD policy entries in VPP
                                 is_ip_any=0):
         """ IPSEC policy SPD add/del   -
                     Wrapper to configure ipsec SPD policy entries in VPP
-        Sample CLI : 'ipsec policy add spd 1 inbound priority 10 action \
-                     protect sa 20 local-ip-range 192.168.4.4 - 192.168.4.4 \
-                     remote-ip-range 192.168.3.3 - 192.168.3.3'
-
-        :param spd_id -  SPD ID for the policy . mandatory
-        :param local_address_start - local-ip-range start address . mandatory
-        :param local_address_stop  - local-ip-range stop address . mandatory
-        :param remote_address_start - remote-ip-range start address . mandatory
-        :param remote_address_stop  - remote-ip-range stop address . mandatory
-        :param local_port_start - (Default 0) . optional
-        :param local_port_stop - (Default 65535). optional
-        :param remote_port_start - (Default 0). optional
-        :param remote_port_stop - (Default 65535). optional
-        :param protocol - Any(0), AH(51) & ESP(50) protocol (Default 0 - Any).
-               optional
-        :param sa_id -  Security Association ID for mapping it to SPD
-               (default 10).   optional
-        :param policy - bypass(0), discard(1), resolve(2) or protect(3)action
-               (Default 0 - bypass). optional
-        :param priotity - value for the spd action (Default 100). optional
-        :param is_outbound - flag for inbound(0) or outbound(1)
-               (Default 1 - outbound). optional
-        :param is_add flag - for addition(1) or deletion(0) of the spd
-               (Default 1 - addtion). optional
-        :returns: reply from the API
+        :param spd_id: SPD ID for the policy
+        :param local_address_start: local-ip-range start address
+        :param local_address_stop : local-ip-range stop address
+        :param remote_address_start: remote-ip-range start address
+        :param remote_address_stop : remote-ip-range stop address
+        :param local_port_start: (Default value = 0)
+        :param local_port_stop: (Default value = 65535)
+        :param remote_port_start: (Default value = 0)
+        :param remote_port_stop: (Default value = 65535)
+        :param protocol: Any(0), AH(51) & ESP(50) protocol (Default value = 0)
+        :param sa_id: Security Association ID for mapping it to SPD
+        :param policy: bypass(0), discard(1), resolve(2) or protect(3) action
+               (Default value = 0)
+        :param priority: value for the spd action (Default value = 100)
+        :param is_outbound: flag for inbound(0) or outbound(1)
+               (Default value = 1)
+        :param is_add: (Default value = 1)
         """
         return self.api(
             self.papi.ipsec_spd_add_del_entry,
             {'spd_id': spd_id,
         """
         return self.api(
             self.papi.ipsec_spd_add_del_entry,
             {'spd_id': spd_id,
+             'sa_id': sa_id,
              'local_address_start': local_address_start,
              'local_address_stop': local_address_stop,
              'remote_address_start': remote_address_start,
              'local_address_start': local_address_start,
              'local_address_stop': local_address_stop,
              'remote_address_start': remote_address_start,
@@ -3291,9 +3260,30 @@ class VppPapiProvider(object):
              'policy': policy,
              'priority': priority,
              'is_outbound': is_outbound,
              'policy': policy,
              'priority': priority,
              'is_outbound': is_outbound,
-             'sa_id': sa_id,
              'is_ip_any': is_ip_any})
 
              'is_ip_any': is_ip_any})
 
+    def ipsec_tunnel_if_add_del(self, local_ip, remote_ip, local_spi,
+                                remote_spi, crypto_alg, local_crypto_key,
+                                remote_crypto_key, integ_alg, local_integ_key,
+                                remote_integ_key, is_add=1, esn=0,
+                                anti_replay=1, renumber=0, show_instance=0):
+        return self.api(
+            self.papi.ipsec_tunnel_if_add_del,
+            {'local_ip': local_ip, 'remote_ip': remote_ip,
+             'local_spi': local_spi, 'remote_spi': remote_spi,
+             'crypto_alg': crypto_alg,
+             'local_crypto_key_len': len(local_crypto_key),
+             'local_crypto_key': local_crypto_key,
+             'remote_crypto_key_len': len(remote_crypto_key),
+             'remote_crypto_key': remote_crypto_key, 'integ_alg': integ_alg,
+             'local_integ_key_len': len(local_integ_key),
+             'local_integ_key': local_integ_key,
+             'remote_integ_key_len': len(remote_integ_key),
+             'remote_integ_key': remote_integ_key, 'is_add': is_add,
+             'esn': esn, 'anti_replay': anti_replay, 'renumber': renumber,
+             'show_instance': show_instance
+             })
+
     def app_namespace_add(self,
                           namespace_id,
                           ip4_fib_id=0,
     def app_namespace_add(self,
                           namespace_id,
                           ip4_fib_id=0,
index 81e9714..1300f1f 100644 (file)
@@ -84,11 +84,11 @@ class VppPGInterface(VppInterface):
 
     def __init__(self, test, pg_index):
         """ Create VPP packet-generator interface """
 
     def __init__(self, test, pg_index):
         """ Create VPP packet-generator interface """
-        r = test.vapi.pg_create_interface(pg_index)
-        self._sw_if_index = r.sw_if_index
-
         super(VppPGInterface, self).__init__(test)
 
         super(VppPGInterface, self).__init__(test)
 
+        r = test.vapi.pg_create_interface(pg_index)
+        self.set_sw_if_index(r.sw_if_index)
+
         self._in_history_counter = 0
         self._out_history_counter = 0
         self._out_assert_counter = 0
         self._in_history_counter = 0
         self._out_history_counter = 0
         self._out_assert_counter = 0
diff --git a/test/vpp_tunnel_interface.py b/test/vpp_tunnel_interface.py
new file mode 100644 (file)
index 0000000..c74f585
--- /dev/null
@@ -0,0 +1,32 @@
+from abc import abstractmethod, ABCMeta
+from vpp_pg_interface import is_ipv6_misc
+from vpp_interface import VppInterface
+
+
+class VppTunnelInterface(VppInterface):
+    """ VPP tunnel interface abstration """
+    __metaclass__ = ABCMeta
+
+    @abstractmethod
+    def __init__(self, test, parent_if):
+        super(VppTunnelInterface, self).__init__(test)
+        self.parent_if = parent_if
+
+    @property
+    def local_mac(self):
+        return self.parent_if.local_mac
+
+    @property
+    def remote_mac(self):
+        return self.parent_if.remote_mac
+
+    def enable_capture(self):
+        return self.parent_if.enable_capture()
+
+    def add_stream(self, pkts):
+        return self.parent_if.add_stream(pkts)
+
+    def get_capture(self, expected_count=None, remark=None, timeout=1,
+                    filter_out_fn=is_ipv6_misc):
+        return self.parent_if.get_capture(expected_count, remark, timeout,
+                                          filter_out_fn)