ipsec: add ipv6 support for ipsec tunnel interface 18/18418/4
authorKingwel Xie <kingwel.xie@ericsson.com>
Wed, 20 Mar 2019 11:21:58 +0000 (07:21 -0400)
committerNeale Ranns <nranns@cisco.com>
Thu, 21 Mar 2019 07:42:09 +0000 (07:42 +0000)
Change-Id: I6a76907dc7bed2a81282b63669bea2219d6903c9
Signed-off-by: Kingwel Xie <kingwel.xie@ericsson.com>
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
12 files changed:
src/vat/api_format.c
src/vnet/ipsec/ipsec.api
src/vnet/ipsec/ipsec.h
src/vnet/ipsec/ipsec_api.c
src/vnet/ipsec/ipsec_cli.c
src/vnet/ipsec/ipsec_if.c
src/vnet/ipsec/ipsec_if.h
src/vnet/ipsec/ipsec_if_in.c
test/template_ipsec.py
test/test_ipsec_tun_if_esp.py
test/vpp_ipsec_tun_interface.py
test/vpp_papi_provider.py

index cef60e0..46974d2 100644 (file)
@@ -15028,8 +15028,8 @@ api_ipsec_tunnel_if_add_del (vat_main_t * vam)
   u32 crypto_alg = 0, integ_alg = 0;
   u8 *lck = NULL, *rck = NULL;
   u8 *lik = NULL, *rik = NULL;
-  ip4_address_t local_ip = { {0} };
-  ip4_address_t remote_ip = { {0} };
+  vl_api_address_t local_ip = { 0 };
+  vl_api_address_t remote_ip = { 0 };
   u8 is_add = 1;
   u8 esn = 0;
   u8 anti_replay = 0;
@@ -15049,9 +15049,11 @@ api_ipsec_tunnel_if_add_del (vat_main_t * vam)
        ;
       else if (unformat (i, "remote_spi %d", &remote_spi))
        ;
-      else if (unformat (i, "local_ip %U", unformat_ip4_address, &local_ip))
+      else
+       if (unformat (i, "local_ip %U", unformat_vl_api_address, &local_ip))
        ;
-      else if (unformat (i, "remote_ip %U", unformat_ip4_address, &remote_ip))
+      else
+       if (unformat (i, "remote_ip %U", unformat_vl_api_address, &remote_ip))
        ;
       else if (unformat (i, "local_crypto_key %U", unformat_hex_string, &lck))
        ;
@@ -15099,8 +15101,8 @@ api_ipsec_tunnel_if_add_del (vat_main_t * vam)
   mp->esn = esn;
   mp->anti_replay = anti_replay;
 
-  clib_memcpy (mp->local_ip, &local_ip, sizeof (ip4_address_t));
-  clib_memcpy (mp->remote_ip, &remote_ip, sizeof (ip4_address_t));
+  clib_memcpy (&mp->local_ip, &local_ip, sizeof (local_ip));
+  clib_memcpy (&mp->remote_ip, &remote_ip, sizeof (remote_ip));
 
   mp->local_spi = htonl (local_spi);
   mp->remote_spi = htonl (remote_spi);
index 4e53375..e6e1ce3 100644 (file)
@@ -353,6 +353,7 @@ define ipsec_spd_interface_details {
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param is_add - add IPsec tunnel interface if nonzero, else delete
+    @param is_ip6 - tunnel v6 or v4
     @param esn - enable extended sequence numbers if nonzero, else disable
     @param anti_replay - enable anti replay check if nonzero, else disable
     @param local_ip - local IP address
@@ -380,8 +381,8 @@ define ipsec_tunnel_if_add_del {
   u8 is_add;
   u8 esn;
   u8 anti_replay;
-  u8 local_ip[4];
-  u8 remote_ip[4];
+  vl_api_address_t local_ip;
+  vl_api_address_t remote_ip;
   u32 local_spi;
   u32 remote_spi;
   u8 crypto_alg;
index e38a4a8..cfb096f 100644 (file)
@@ -100,7 +100,8 @@ typedef struct
   uword *spd_index_by_spd_id;
   uword *spd_index_by_sw_if_index;
   uword *sa_index_by_sa_id;
-  uword *ipsec_if_pool_index_by_key;
+  uword *ipsec4_if_pool_index_by_key;
+  uword *ipsec6_if_pool_index_by_key;
   uword *ipsec_if_real_dev_by_show_dev;
 
   /* node indices */
@@ -158,7 +159,8 @@ extern vlib_node_registration_t esp6_encrypt_node;
 extern vlib_node_registration_t esp6_decrypt_node;
 extern vlib_node_registration_t ah6_encrypt_node;
 extern vlib_node_registration_t ah6_decrypt_node;
-extern vlib_node_registration_t ipsec_if_input_node;
+extern vlib_node_registration_t ipsec4_if_input_node;
+extern vlib_node_registration_t ipsec6_if_input_node;
 
 /*
  * functions
index e6f5bd3..4bb3a75 100644 (file)
@@ -616,6 +616,7 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
   ipsec_main_t *im = &ipsec_main;
   vnet_main_t *vnm = im->vnet_main;
   u32 sw_if_index = ~0;
+  ip46_type_t itype;
   int rv;
 
 #if WITH_LIBSSL > 0
@@ -636,8 +637,9 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
   tun.remote_integ_key_len = mp->remote_integ_key_len;
   tun.udp_encap = mp->udp_encap;
   tun.tx_table_id = ntohl (mp->tx_table_id);
-  memcpy (&tun.local_ip.ip4, mp->local_ip, 4);
-  memcpy (&tun.remote_ip.ip4, mp->remote_ip, 4);
+  itype = ip_address_decode (&mp->local_ip, &tun.local_ip);
+  itype = ip_address_decode (&mp->remote_ip, &tun.remote_ip);
+  tun.is_ip6 = (IP46_TYPE_IP6 == itype);
   memcpy (&tun.local_crypto_key, &mp->local_crypto_key,
          mp->local_crypto_key_len);
   memcpy (&tun.remote_crypto_key, &mp->remote_crypto_key,
index 2020e79..0f47c7b 100644 (file)
@@ -721,12 +721,11 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm,
       goto done;
     }
 
-  if (ipv6_set)
-    return clib_error_return (0, "currently only IPv4 supported");
-
   if (ipv4_set && ipv6_set)
     return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
 
+  a.is_ip6 = ipv6_set;
+
   clib_memcpy (a.local_crypto_key, lck.data, lck.len);
   a.local_crypto_key_len = lck.len;
   clib_memcpy (a.remote_crypto_key, rck.data, rck.len);
index 7a44456..41089b6 100644 (file)
@@ -272,14 +272,25 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
   u32 hw_if_index = ~0;
   uword *p;
   u32 dev_instance;
-  u32 slot;
   ipsec_key_t crypto_key, integ_key;
   ipsec_sa_flags_t flags;
   int rv;
+  int is_ip6 = args->is_ip6;
+  ipsec4_tunnel_key_t key4;
+  ipsec6_tunnel_key_t key6;
 
-  u64 key = ((u64) args->remote_ip.ip4.as_u32 << 32 |
-            (u64) clib_host_to_net_u32 (args->remote_spi));
-  p = hash_get (im->ipsec_if_pool_index_by_key, key);
+  if (!is_ip6)
+    {
+      key4.remote_ip = args->remote_ip.ip4.as_u32;
+      key4.spi = clib_host_to_net_u32 (args->remote_spi);
+      p = hash_get (im->ipsec4_if_pool_index_by_key, key4.as_u64);
+    }
+  else
+    {
+      key6.remote_ip = args->remote_ip.ip6;
+      key6.spi = clib_host_to_net_u32 (args->remote_spi);
+      p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key6);
+    }
 
   if (args->is_add)
     {
@@ -305,6 +316,8 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
                dev_instance);
 
       flags = IPSEC_SA_FLAG_IS_TUNNEL;
+      if (args->is_ip6)
+       flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6;
       if (args->udp_encap)
        flags |= IPSEC_SA_FLAG_UDP_ENCAP;
       if (args->esn)
@@ -352,8 +365,13 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
       if (rv)
        return VNET_API_ERROR_UNIMPLEMENTED;
 
-      hash_set (im->ipsec_if_pool_index_by_key, key,
-               t - im->tunnel_interfaces);
+      /* copy the key */
+      if (is_ip6)
+       hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key6,
+                           t - im->tunnel_interfaces);
+      else
+       hash_set (im->ipsec4_if_pool_index_by_key, key4.as_u64,
+                 t - im->tunnel_interfaces);
 
       hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index,
                                             t - im->tunnel_interfaces,
@@ -361,23 +379,30 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
                                             t - im->tunnel_interfaces);
 
       hi = vnet_get_hw_interface (vnm, hw_if_index);
-      /* add esp4 as the next-node-index of this tx-node */
 
-      slot = vlib_node_add_next_with_slot
-       (vnm->vlib_main, hi->tx_node_index, im->esp4_encrypt_node_index, 0);
+      /* add esp4/6 as the next-node-index of this tx-node */
+      uword slot = vlib_node_add_next_with_slot
+       (vnm->vlib_main, hi->tx_node_index,
+        is_ip6 ? im->esp6_encrypt_node_index : im->esp4_encrypt_node_index,
+        0);
 
       ASSERT (slot == 0);
 
       t->hw_if_index = hw_if_index;
       t->sw_if_index = hi->sw_if_index;
 
-      vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
-                                  hi->sw_if_index, 1, 0, 0);
-
+      vnet_feature_enable_disable ("interface-output",
+                                  args->is_ip6 ? "ipsec6-if-output" :
+                                  "ipsec4-if-output", hi->sw_if_index, 1, 0,
+                                  0);
       /*1st interface, register protocol */
       if (pool_elts (im->tunnel_interfaces) == 1)
-       ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
-                              ipsec_if_input_node.index);
+       {
+         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
+                                ipsec4_if_input_node.index);
+         ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
+                                ipsec6_if_input_node.index);
+       }
 
     }
   else
@@ -393,12 +418,17 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
       hi = vnet_get_hw_interface (vnm, t->hw_if_index);
       vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0);   /* admin down */
 
-      vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
-                                  hi->sw_if_index, 0, 0, 0);
-
+      vnet_feature_enable_disable ("interface-output",
+                                  args->is_ip6 ? "ipsec6-if-output" :
+                                  "ipsec4-if-output", hi->sw_if_index, 0, 0,
+                                  0);
       vnet_delete_hw_interface (vnm, t->hw_if_index);
 
-      hash_unset (im->ipsec_if_pool_index_by_key, key);
+      if (is_ip6)
+       hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key6);
+      else
+       hash_unset (im->ipsec4_if_pool_index_by_key, key4.as_u64);
+
       hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance);
 
       pool_put (im->tunnel_interfaces, t);
@@ -422,7 +452,7 @@ ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
   ipsec_main_t *im = &ipsec_main;
   uword *p;
   ipsec_sa_t *sa;
-  u64 key;
+  ipsec4_tunnel_key_t key;
   u32 isa, osa;
 
   p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
@@ -437,13 +467,17 @@ ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
   sa = pool_elt_at_index (im->sad, p[0]);
 
   if (sa->is_tunnel)
-    key = ((u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 |
-          (u64) clib_host_to_net_u32 (sa->spi));
+    {
+      key.remote_ip = sa->tunnel_dst_addr.ip4.as_u32;
+      key.spi = clib_host_to_net_u32 (sa->spi);
+    }
   else
-    key = ((u64) args->remote_ip.as_u32 << 32 |
-          (u64) clib_host_to_net_u32 (sa->spi));
+    {
+      key.remote_ip = args->remote_ip.as_u32;
+      key.spi = clib_host_to_net_u32 (sa->spi);
+    }
 
-  p = hash_get (im->ipsec_if_pool_index_by_key, key);
+  p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64);
 
   if (args->is_add)
     {
@@ -457,13 +491,20 @@ ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
       t->input_sa_index = isa;
       t->output_sa_index = osa;
       t->hw_if_index = ~0;
-      hash_set (im->ipsec_if_pool_index_by_key, key,
+      hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64,
                t - im->tunnel_interfaces);
 
       /*1st interface, register protocol */
       if (pool_elts (im->tunnel_interfaces) == 1)
-       ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
-                              ipsec_if_input_node.index);
+       {
+         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
+                                ipsec4_if_input_node.index);
+         /* TBD, GRE IPSec6
+          *
+          ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
+          ipsec6_if_input_node.index);
+          */
+       }
     }
   else
     {
@@ -472,7 +513,7 @@ ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
        return VNET_API_ERROR_INVALID_VALUE;
 
       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
-      hash_unset (im->ipsec_if_pool_index_by_key, key);
+      hash_unset (im->ipsec4_if_pool_index_by_key, key.as_u64);
       pool_put (im->tunnel_interfaces, t);
     }
   return 0;
@@ -552,36 +593,70 @@ ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
     }
 
   sa = pool_elt_at_index (im->sad, sa_index);
-  if (sa->is_tunnel_ip6)
-    {
-      clib_warning ("IPsec interface not supported with IPv6 endpoints");
-      return VNET_API_ERROR_UNIMPLEMENTED;
-    }
 
   if (!is_outbound)
     {
-      u64 key;
-
       old_sa_index = t->input_sa_index;
       old_sa = pool_elt_at_index (im->sad, old_sa_index);
 
-      /* unset old inbound hash entry. packets should stop arriving */
-      key = ((u64) old_sa->tunnel_src_addr.ip4.as_u32 << 32 |
-            (u64) clib_host_to_net_u32 (old_sa->spi));
-      p = hash_get (im->ipsec_if_pool_index_by_key, key);
-      if (p)
-       hash_unset (im->ipsec_if_pool_index_by_key, key);
+      if (sa->is_tunnel_ip6 ^ old_sa->is_tunnel_ip6)
+       {
+         clib_warning ("IPsec interface SA endpoints type can't be changed");
+         return VNET_API_ERROR_INVALID_VALUE;
+       }
+
+      if (sa->is_tunnel_ip6)
+       {
+         ipsec6_tunnel_key_t key;
+
+         /* unset old inbound hash entry. packets should stop arriving */
+         key.remote_ip = old_sa->tunnel_src_addr.ip6;
+         key.spi = clib_host_to_net_u32 (old_sa->spi);
+
+         p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key);
+         if (p)
+           hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key);
+
+         /* set new inbound SA, then set new hash entry */
+         t->input_sa_index = sa_index;
+         key.remote_ip = sa->tunnel_src_addr.ip6;
+         key.spi = clib_host_to_net_u32 (sa->spi);
+
+         hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key,
+                             hi->dev_instance);
+       }
+      else
+       {
+         ipsec4_tunnel_key_t key;
+
+         /* unset old inbound hash entry. packets should stop arriving */
+         key.remote_ip = old_sa->tunnel_src_addr.ip4.as_u32;
+         key.spi = clib_host_to_net_u32 (old_sa->spi);
+
+         p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64);
+         if (p)
+           hash_unset (im->ipsec4_if_pool_index_by_key, key.as_u64);
 
-      /* set new inbound SA, then set new hash entry */
-      t->input_sa_index = sa_index;
-      key = ((u64) sa->tunnel_src_addr.ip4.as_u32 << 32 |
-            (u64) clib_host_to_net_u32 (sa->spi));
-      hash_set (im->ipsec_if_pool_index_by_key, key, hi->dev_instance);
+         /* set new inbound SA, then set new hash entry */
+         t->input_sa_index = sa_index;
+         key.remote_ip = sa->tunnel_src_addr.ip4.as_u32;
+         key.spi = clib_host_to_net_u32 (sa->spi);
+
+         hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64,
+                   hi->dev_instance);
+       }
     }
   else
     {
       old_sa_index = t->output_sa_index;
       old_sa = pool_elt_at_index (im->sad, old_sa_index);
+
+      if (sa->is_tunnel_ip6 ^ old_sa->is_tunnel_ip6)
+       {
+         clib_warning ("IPsec interface SA endpoints type can't be changed");
+         return VNET_API_ERROR_INVALID_VALUE;
+       }
+
       t->output_sa_index = sa_index;
     }
 
@@ -599,17 +674,24 @@ ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
   return 0;
 }
 
+
 clib_error_t *
 ipsec_tunnel_if_init (vlib_main_t * vm)
 {
   ipsec_main_t *im = &ipsec_main;
 
-  im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
+  /* initialize the ipsec-if ip4 hash */
+  im->ipsec4_if_pool_index_by_key =
+    hash_create (0, sizeof (ipsec4_tunnel_key_t));
+  /* initialize the ipsec-if ip6 hash */
+  im->ipsec6_if_pool_index_by_key = hash_create_mem (0,
+                                                    sizeof
+                                                    (ipsec6_tunnel_key_t),
+                                                    sizeof (uword));
   im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword));
 
-  udp_register_dst_port (vm, UDP_DST_PORT_ipsec, ipsec_if_input_node.index,
+  udp_register_dst_port (vm, UDP_DST_PORT_ipsec, ipsec4_if_input_node.index,
                         1);
-
   return 0;
 }
 
index 3d042f0..7f0eb08 100644 (file)
@@ -41,6 +41,7 @@ typedef struct
 typedef struct
 {
   u8 is_add;
+  u8 is_ip6;
   u8 esn;
   u8 anti_replay;
   ip46_address_t local_ip, remote_ip;
@@ -62,6 +63,35 @@ typedef struct
   u32 tx_table_id;
 } ipsec_add_del_tunnel_args_t;
 
+/* *INDENT-OFF* */
+typedef CLIB_PACKED
+(struct {
+  /*
+   * Key fields: remote ip and spi on incoming packet
+   * all fields in NET byte order
+   */
+  union {
+    struct {
+      u32 remote_ip;
+      u32 spi;
+    };
+    u64 as_u64;
+  };
+}) ipsec4_tunnel_key_t;
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+typedef CLIB_PACKED
+(struct {
+  /*
+   * Key fields: remote ip and spi on incoming packet
+   * all fields in NET byte order
+   */
+  ip6_address_t remote_ip;
+  u32 spi;
+}) ipsec6_tunnel_key_t;
+/* *INDENT-ON* */
+
 typedef struct
 {
   u8 is_add;
index b12e36c..63d463b 100644 (file)
@@ -63,8 +63,8 @@ format_ipsec_if_input_trace (u8 * s, va_list * args)
 
 
 always_inline uword
-ipsec_if_input_inline (vlib_main_t * vm,
-                      vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
+                      vlib_frame_t * from_frame, int is_ip6)
 {
   ipsec_main_t *im = &ipsec_main;
   vnet_main_t *vnm = im->vnet_main;
@@ -91,24 +91,32 @@ ipsec_if_input_inline (vlib_main_t * vm,
 
   u32 last_sw_if_index = ~0;
   u32 last_tunnel_id = ~0;
-  u64 last_key = ~0;
+  ipsec4_tunnel_key_t last_key4;
+  ipsec6_tunnel_key_t last_key6;
 
   vlib_combined_counter_main_t *rx_counter;
   vlib_combined_counter_main_t *drop_counter;
 
+  if (is_ip6)
+    clib_memset (&last_key6, 0xff, sizeof (last_key6));
+  else
+    last_key4.as_u64 = ~0;
+
   rx_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
   drop_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
 
   while (n_left_from >= 2)
     {
       u32 sw_if_index0, sw_if_index1;
-      ip4_header_t *ip0, *ip1;
+      ip4_header_t *ip40, *ip41;
+      ip6_header_t *ip60, *ip61;
       esp_header_t *esp0, *esp1;
       u32 len0, len1;
       u16 buf_adv0, buf_adv1;
       u32 tid0, tid1;
       ipsec_tunnel_if_t *t0, *t1;
-      u64 key0, key1;
+      ipsec4_tunnel_key_t key40, key41;
+      ipsec6_tunnel_key_t key60, key61;
 
       if (n_left_from >= 4)
        {
@@ -118,33 +126,48 @@ ipsec_if_input_inline (vlib_main_t * vm,
          CLIB_PREFETCH (b[3]->data, CLIB_CACHE_LINE_BYTES, LOAD);
        }
 
-      ip0 = (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset);
-      ip1 = (ip4_header_t *) (b[1]->data + vnet_buffer (b[1])->l3_hdr_offset);
+      ip40 =
+       (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset);
+      ip41 =
+       (ip4_header_t *) (b[1]->data + vnet_buffer (b[1])->l3_hdr_offset);
 
-      /* NAT UDP port 4500 case, don't advance any more */
-      if (ip0->protocol == IP_PROTOCOL_UDP)
-       {
-         esp0 =
-           (esp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0) +
-                             sizeof (udp_header_t));
-         buf_adv0 = 0;
-       }
-      else
-       {
-         esp0 = (esp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0));
-         buf_adv0 = ip4_header_bytes (ip0);
-       }
-      if (ip1->protocol == IP_PROTOCOL_UDP)
+      if (is_ip6)
        {
-         esp1 =
-           (esp_header_t *) ((u8 *) ip1 + ip4_header_bytes (ip1) +
-                             sizeof (udp_header_t));
-         buf_adv1 = 0;
+         ip60 = (ip6_header_t *) ip40;
+         ip61 = (ip6_header_t *) ip41;
+         esp0 = (esp_header_t *) ((u8 *) ip60 + sizeof (ip6_header_t));
+         esp1 = (esp_header_t *) ((u8 *) ip61 + sizeof (ip6_header_t));
+         buf_adv0 = sizeof (ip6_header_t);
+         buf_adv1 = sizeof (ip6_header_t);
        }
       else
        {
-         esp1 = (esp_header_t *) ((u8 *) ip1 + ip4_header_bytes (ip1));
-         buf_adv1 = ip4_header_bytes (ip1);
+         /* NAT UDP port 4500 case, don't advance any more */
+         if (ip40->protocol == IP_PROTOCOL_UDP)
+           {
+             esp0 =
+               (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) +
+                                 sizeof (udp_header_t));
+             buf_adv0 = 0;
+           }
+         else
+           {
+             esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40));
+             buf_adv0 = ip4_header_bytes (ip40);
+           }
+         /* NAT UDP port 4500 case, don't advance any more */
+         if (ip41->protocol == IP_PROTOCOL_UDP)
+           {
+             esp1 =
+               (esp_header_t *) ((u8 *) ip41 + ip4_header_bytes (ip41) +
+                                 sizeof (udp_header_t));
+             buf_adv1 = 0;
+           }
+         else
+           {
+             esp1 = (esp_header_t *) ((u8 *) ip41 + ip4_header_bytes (ip41));
+             buf_adv1 = ip4_header_bytes (ip41);
+           }
        }
 
       vlib_buffer_advance (b[0], buf_adv0);
@@ -153,27 +176,58 @@ ipsec_if_input_inline (vlib_main_t * vm,
       len0 = vlib_buffer_length_in_chain (vm, b[0]);
       len1 = vlib_buffer_length_in_chain (vm, b[1]);
 
-      key0 = (u64) ip0->src_address.as_u32 << 32 | (u64) esp0->spi;
-      key1 = (u64) ip1->src_address.as_u32 << 32 | (u64) esp1->spi;
-
-      if (key0 == last_key)
+      if (is_ip6)
        {
-         tid0 = last_tunnel_id;
+         key60.remote_ip = ip60->src_address;
+         key60.spi = esp0->spi;
+
+         if (memcmp (&key60, &last_key6, sizeof (last_key6)) == 0)
+           {
+             tid0 = last_tunnel_id;
+           }
+         else
+           {
+             uword *p =
+               hash_get_mem (im->ipsec6_if_pool_index_by_key, &key60);
+             if (p)
+               {
+                 tid0 = p[0];
+                 last_tunnel_id = tid0;
+                 clib_memcpy_fast (&last_key6, &key60, sizeof (key60));
+               }
+             else
+               {
+                 n_no_tunnel++;
+                 next[0] = IPSEC_INPUT_NEXT_DROP;
+                 goto pkt1;
+               }
+           }
        }
-      else
+      else                     /* !is_ip6 */
        {
-         uword *p = hash_get (im->ipsec_if_pool_index_by_key, key0);
-         if (p)
+         key40.remote_ip = ip40->src_address.as_u32;
+         key40.spi = esp0->spi;
+
+         if (key40.as_u64 == last_key4.as_u64)
            {
-             tid0 = p[0];
-             last_tunnel_id = tid0;
-             last_key = key0;
+             tid0 = last_tunnel_id;
            }
          else
            {
-             n_no_tunnel++;
-             next[0] = IPSEC_INPUT_NEXT_DROP;
-             goto pkt1;
+             uword *p =
+               hash_get (im->ipsec4_if_pool_index_by_key, key40.as_u64);
+             if (p)
+               {
+                 tid0 = p[0];
+                 last_tunnel_id = tid0;
+                 last_key4.as_u64 = key40.as_u64;
+               }
+             else
+               {
+                 n_no_tunnel++;
+                 next[0] = IPSEC_INPUT_NEXT_DROP;
+                 goto pkt1;
+               }
            }
        }
 
@@ -220,24 +274,58 @@ ipsec_if_input_inline (vlib_main_t * vm,
        }
 
     pkt1:
-      if (key1 == last_key)
+      if (is_ip6)
        {
-         tid1 = last_tunnel_id;
+         key61.remote_ip = ip61->src_address;
+         key61.spi = esp1->spi;
+
+         if (memcmp (&key61, &last_key6, sizeof (last_key6)) == 0)
+           {
+             tid1 = last_tunnel_id;
+           }
+         else
+           {
+             uword *p =
+               hash_get_mem (im->ipsec6_if_pool_index_by_key, &key61);
+             if (p)
+               {
+                 tid1 = p[0];
+                 last_tunnel_id = tid1;
+                 clib_memcpy_fast (&last_key6, &key61, sizeof (key61));
+               }
+             else
+               {
+                 n_no_tunnel++;
+                 next[1] = IPSEC_INPUT_NEXT_DROP;
+                 goto trace1;
+               }
+           }
        }
-      else
+      else                     /* !is_ip6 */
        {
-         uword *p = hash_get (im->ipsec_if_pool_index_by_key, key1);
-         if (p)
+         key41.remote_ip = ip41->src_address.as_u32;
+         key41.spi = esp1->spi;
+
+         if (key41.as_u64 == last_key4.as_u64)
            {
-             tid1 = p[0];
-             last_tunnel_id = tid1;
-             last_key = key1;
+             tid1 = last_tunnel_id;
            }
          else
            {
-             n_no_tunnel++;
-             next[1] = IPSEC_INPUT_NEXT_DROP;
-             goto trace1;
+             uword *p =
+               hash_get (im->ipsec4_if_pool_index_by_key, key41.as_u64);
+             if (p)
+               {
+                 tid1 = p[0];
+                 last_tunnel_id = tid1;
+                 last_key4.as_u64 = key41.as_u64;
+               }
+             else
+               {
+                 n_no_tunnel++;
+                 next[1] = IPSEC_INPUT_NEXT_DROP;
+                 goto trace1;
+               }
            }
        }
 
@@ -284,16 +372,16 @@ ipsec_if_input_inline (vlib_main_t * vm,
        }
 
     trace1:
-      if (is_trace)
+      if (PREDICT_FALSE (is_trace))
        {
-         if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
+         if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
            {
              ipsec_if_input_trace_t *tr =
                vlib_add_trace (vm, node, b[0], sizeof (*tr));
              tr->spi = clib_host_to_net_u32 (esp0->spi);
              tr->seq = clib_host_to_net_u32 (esp0->seq);
            }
-         if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
+         if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
            {
              ipsec_if_input_trace_t *tr =
                vlib_add_trace (vm, node, b[1], sizeof (*tr));
@@ -310,28 +398,40 @@ ipsec_if_input_inline (vlib_main_t * vm,
   while (n_left_from > 0)
     {
       u32 sw_if_index0;
-      ip4_header_t *ip0;
+      ip4_header_t *ip40;
+      ip6_header_t *ip60;
       esp_header_t *esp0;
       u32 len0;
       u16 buf_adv0;
       u32 tid0;
       ipsec_tunnel_if_t *t0;
-      u64 key0;
+      ipsec4_tunnel_key_t key40;
+      ipsec6_tunnel_key_t key60;
 
-      ip0 = (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset);
+      ip40 =
+       (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset);
 
-      /* NAT UDP port 4500 case, don't advance any more */
-      if (ip0->protocol == IP_PROTOCOL_UDP)
+      if (is_ip6)
        {
-         esp0 =
-           (esp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0) +
-                             sizeof (udp_header_t));
-         buf_adv0 = 0;
+         ip60 = (ip6_header_t *) ip40;
+         esp0 = (esp_header_t *) ((u8 *) ip60 + sizeof (ip6_header_t));
+         buf_adv0 = sizeof (ip6_header_t);
        }
       else
        {
-         esp0 = (esp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0));
-         buf_adv0 = ip4_header_bytes (ip0);
+         /* NAT UDP port 4500 case, don't advance any more */
+         if (ip40->protocol == IP_PROTOCOL_UDP)
+           {
+             esp0 =
+               (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) +
+                                 sizeof (udp_header_t));
+             buf_adv0 = 0;
+           }
+         else
+           {
+             esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40));
+             buf_adv0 = ip4_header_bytes (ip40);
+           }
        }
 
       /* stats for the tunnel include all the data after the IP header
@@ -339,25 +439,58 @@ ipsec_if_input_inline (vlib_main_t * vm,
       vlib_buffer_advance (b[0], buf_adv0);
       len0 = vlib_buffer_length_in_chain (vm, b[0]);
 
-      key0 = (u64) ip0->src_address.as_u32 << 32 | (u64) esp0->spi;
-      if (key0 == last_key)
+      if (is_ip6)
        {
-         tid0 = last_tunnel_id;
+         key60.remote_ip = ip60->src_address;
+         key60.spi = esp0->spi;
+
+         if (memcmp (&key60, &last_key6, sizeof (last_key6)) == 0)
+           {
+             tid0 = last_tunnel_id;
+           }
+         else
+           {
+             uword *p =
+               hash_get_mem (im->ipsec6_if_pool_index_by_key, &key60);
+             if (p)
+               {
+                 tid0 = p[0];
+                 last_tunnel_id = tid0;
+                 clib_memcpy_fast (&last_key6, &key60, sizeof (key60));
+               }
+             else
+               {
+                 n_no_tunnel++;
+                 next[0] = IPSEC_INPUT_NEXT_DROP;
+                 goto trace00;
+               }
+           }
        }
-      else
+      else                     /* !is_ip6 */
        {
-         uword *p = hash_get (im->ipsec_if_pool_index_by_key, key0);
-         if (p)
+         key40.remote_ip = ip40->src_address.as_u32;
+         key40.spi = esp0->spi;
+
+         if (key40.as_u64 == last_key4.as_u64)
            {
-             tid0 = p[0];
-             last_tunnel_id = tid0;
-             last_key = key0;
+             tid0 = last_tunnel_id;
            }
          else
            {
-             n_no_tunnel++;
-             next[0] = IPSEC_INPUT_NEXT_DROP;
-             goto trace00;
+             uword *p =
+               hash_get (im->ipsec4_if_pool_index_by_key, key40.as_u64);
+             if (p)
+               {
+                 tid0 = p[0];
+                 last_tunnel_id = tid0;
+                 last_key4.as_u64 = key40.as_u64;
+               }
+             else
+               {
+                 n_no_tunnel++;
+                 next[0] = IPSEC_INPUT_NEXT_DROP;
+                 goto trace00;
+               }
            }
        }
 
@@ -404,9 +537,9 @@ ipsec_if_input_inline (vlib_main_t * vm,
        }
 
     trace00:
-      if (is_trace)
+      if (PREDICT_FALSE (is_trace))
        {
-         if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
+         if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
            {
              ipsec_if_input_trace_t *tr =
                vlib_add_trace (vm, node, b[0], sizeof (*tr));
@@ -428,12 +561,12 @@ ipsec_if_input_inline (vlib_main_t * vm,
                                       last_sw_if_index, n_packets, n_bytes);
     }
 
-  vlib_node_increment_counter (vm, ipsec_if_input_node.index,
+  vlib_node_increment_counter (vm, node->node_index,
                               IPSEC_IF_INPUT_ERROR_RX,
                               from_frame->n_vectors - n_disabled);
-  vlib_node_increment_counter (vm, ipsec_if_input_node.index,
+  vlib_node_increment_counter (vm, node->node_index,
                               IPSEC_IF_INPUT_ERROR_DISABLED, n_disabled);
-  vlib_node_increment_counter (vm, ipsec_if_input_node.index,
+  vlib_node_increment_counter (vm, node->node_index,
                               IPSEC_IF_INPUT_ERROR_NO_TUNNEL, n_no_tunnel);
 
   vlib_buffer_enqueue_to_next (vm, node, from, nexts, from_frame->n_vectors);
@@ -441,16 +574,16 @@ ipsec_if_input_inline (vlib_main_t * vm,
   return from_frame->n_vectors;
 }
 
-VLIB_NODE_FN (ipsec_if_input_node) (vlib_main_t * vm,
-                                   vlib_node_runtime_t * node,
-                                   vlib_frame_t * from_frame)
+VLIB_NODE_FN (ipsec4_if_input_node) (vlib_main_t * vm,
+                                    vlib_node_runtime_t * node,
+                                    vlib_frame_t * from_frame)
 {
-  return ipsec_if_input_inline (vm, node, from_frame);
+  return ipsec_if_input_inline (vm, node, from_frame, 0 /* is_ip6 */ );
 }
 
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ipsec_if_input_node) = {
-  .name = "ipsec-if-input",
+VLIB_REGISTER_NODE (ipsec4_if_input_node) = {
+  .name = "ipsec4-if-input",
   .vector_size = sizeof (u32),
   .format_trace = format_ipsec_if_input_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
@@ -460,6 +593,25 @@ VLIB_REGISTER_NODE (ipsec_if_input_node) = {
 };
 /* *INDENT-ON* */
 
+VLIB_NODE_FN (ipsec6_if_input_node) (vlib_main_t * vm,
+                                    vlib_node_runtime_t * node,
+                                    vlib_frame_t * from_frame)
+{
+  return ipsec_if_input_inline (vm, node, from_frame, 1 /* is_ip6 */ );
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ipsec6_if_input_node) = {
+  .name = "ipsec6-if-input",
+  .vector_size = sizeof (u32),
+  .format_trace = format_ipsec_if_input_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(ipsec_if_input_error_strings),
+  .error_strings = ipsec_if_input_error_strings,
+  .sibling_of = "ipsec6-input-feature",
+};
+/* *INDENT-ON* */
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index 68f1183..483699c 100644 (file)
@@ -477,14 +477,15 @@ class IpsecTun6Tests(object):
             self.logger.info(self.vapi.ppcli("show error"))
             self.logger.info(self.vapi.ppcli("show ipsec"))
 
-        pkts = p.tun_sa_in.get_stats()['packets']
-        self.assertEqual(pkts, count,
-                         "incorrect SA in counts: expected %d != %d" %
-                         (count, pkts))
-        pkts = p.tun_sa_out.get_stats()['packets']
-        self.assertEqual(pkts, count,
-                         "incorrect SA out counts: expected %d != %d" %
-                         (count, pkts))
+        if (hasattr(p, "tun_sa_in")):
+            pkts = p.tun_sa_in.get_stats()['packets']
+            self.assertEqual(pkts, count,
+                             "incorrect SA in counts: expected %d != %d" %
+                             (count, pkts))
+            pkts = p.tun_sa_out.get_stats()['packets']
+            self.assertEqual(pkts, count,
+                             "incorrect SA out counts: expected %d != %d" %
+                             (count, pkts))
         self.assert_packet_counter_equal(self.tun6_encrypt_node_name, count)
         self.assert_packet_counter_equal(self.tun6_decrypt_node_name, count)
 
index 2734908..06d2c89 100644 (file)
@@ -2,18 +2,19 @@ import unittest
 import socket
 from scapy.layers.ipsec import ESP
 from framework import VppTestRunner
-from template_ipsec import TemplateIpsec, IpsecTun4Tests, IpsecTcpTests
+from template_ipsec import TemplateIpsec, IpsecTun4Tests, IpsecTun6Tests, \
+    IpsecTcpTests
 from vpp_ipsec_tun_interface import VppIpsecTunInterface
-from vpp_ip_route import VppIpRoute, VppRoutePath
+from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
 
 
-class TemplateIpsecTunIfEsp(TemplateIpsec):
+class TemplateIpsec4TunIfEsp(TemplateIpsec):
     """ IPsec tunnel interface tests """
 
     encryption_type = ESP
 
     def setUp(self):
-        super(TemplateIpsecTunIfEsp, self).setUp()
+        super(TemplateIpsec4TunIfEsp, self).setUp()
 
         self.tun_if = self.pg0
 
@@ -34,19 +35,57 @@ class TemplateIpsecTunIfEsp(TemplateIpsec):
     def tearDown(self):
         if not self.vpp_dead:
             self.vapi.cli("show hardware")
-        super(TemplateIpsecTunIfEsp, self).tearDown()
+        super(TemplateIpsec4TunIfEsp, self).tearDown()
 
 
-class TestIpsecTunIfEsp1(TemplateIpsecTunIfEsp, IpsecTun4Tests):
+class TestIpsec4TunIfEsp1(TemplateIpsec4TunIfEsp, IpsecTun4Tests):
     """ Ipsec ESP - TUN tests """
     tun4_encrypt_node_name = "esp4-encrypt"
     tun4_decrypt_node_name = "esp4-decrypt"
 
 
-class TestIpsecTunIfEsp2(TemplateIpsecTunIfEsp, IpsecTcpTests):
+class TestIpsec4TunIfEsp2(TemplateIpsec4TunIfEsp, IpsecTcpTests):
     """ Ipsec ESP - TCP tests """
     pass
 
 
+class TemplateIpsec6TunIfEsp(TemplateIpsec):
+    """ IPsec tunnel interface tests """
+
+    encryption_type = ESP
+
+    def setUp(self):
+        super(TemplateIpsec6TunIfEsp, self).setUp()
+
+        self.tun_if = self.pg0
+
+        p = self.ipv6_params
+        tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
+                                      p.scapy_tun_spi, p.crypt_algo_vpp_id,
+                                      p.crypt_key, p.crypt_key,
+                                      p.auth_algo_vpp_id, p.auth_key,
+                                      p.auth_key, is_ip6=True)
+        tun_if.add_vpp_config()
+        tun_if.admin_up()
+        tun_if.config_ip6()
+
+        VppIpRoute(self,  p.remote_tun_if_host, 32,
+                   [VppRoutePath(tun_if.remote_ip6,
+                                 0xffffffff,
+                                 proto=DpoProto.DPO_PROTO_IP6)],
+                   is_ip6=1).add_vpp_config()
+
+    def tearDown(self):
+        if not self.vpp_dead:
+            self.vapi.cli("show hardware")
+        super(TemplateIpsec6TunIfEsp, self).tearDown()
+
+
+class TestIpsec6TunIfEsp1(TemplateIpsec6TunIfEsp, IpsecTun6Tests):
+    """ Ipsec ESP - TUN tests """
+    tun6_encrypt_node_name = "esp6-encrypt"
+    tun6_decrypt_node_name = "esp6-decrypt"
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index bd63541..5c014ea 100644 (file)
@@ -8,7 +8,7 @@ class VppIpsecTunInterface(VppTunnelInterface):
 
     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):
+                 integ_alg, local_integ_key, remote_integ_key, is_ip6=False):
         super(VppIpsecTunInterface, self).__init__(test, parent_if)
         self.local_spi = local_spi
         self.remote_spi = remote_spi
@@ -18,23 +18,30 @@ class VppIpsecTunInterface(VppTunnelInterface):
         self.integ_alg = integ_alg
         self.local_integ_key = local_integ_key
         self.remote_integ_key = remote_integ_key
+        if is_ip6:
+            self.local_ip = self.parent_if.local_ip6
+            self.remote_ip = self.parent_if.remote_ip6
+        else:
+            self.local_ip = self.parent_if.local_ip4
+            self.remote_ip = self.parent_if.remote_ip4
 
     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.local_ip, self.remote_ip,
+            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)
+            self.local_ip, self.remote_ip,
+            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()
index 9133683..d393ce1 100644 (file)
@@ -2485,20 +2485,27 @@ class VppPapiProvider(object):
                                 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
-             })
+            {
+                '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 ipsec_select_backend(self, protocol, index):
         return self.api(self.papi.ipsec_select_backend,