GRE tunnel key includes the FIB table 49/9849/2
authorNeale Ranns <nranns@cisco.com>
Thu, 14 Dec 2017 16:51:32 +0000 (08:51 -0800)
committerDamjan Marion <dmarion.lists@gmail.com>
Sat, 16 Dec 2017 19:39:26 +0000 (19:39 +0000)
- GRE tunnels with the same src,dst addresses are not the same tunnel
- Two data-plane improvements:
  - the cached key was never updated and so useless
  - no need to dereference the tunnel's HW interface to get the sw_if_index

Change-Id: I2f2ea6e08c759a810b753cec22c497e921a2ca01
Signed-off-by: Neale Ranns <nranns@cisco.com>
src/vnet/gre/gre.c
src/vnet/gre/gre.h
src/vnet/gre/interface.c
src/vnet/gre/node.c
test/test_gre.py
test/vpp_gre_interface.py

index 785476d..7660bbe 100644 (file)
@@ -516,8 +516,10 @@ gre_init (vlib_main_t * vm)
 
   gm->protocol_info_by_name = hash_create_string (0, sizeof (uword));
   gm->protocol_info_by_protocol = hash_create (0, sizeof (uword));
-  gm->tunnel_by_key4 = hash_create (0, sizeof (uword));
-  gm->tunnel_by_key6 = hash_create_mem (0, sizeof (u64[4]), sizeof (uword));
+  gm->tunnel_by_key4 =
+    hash_create_mem (0, sizeof (gre_tunnel_key4_t), sizeof (uword));
+  gm->tunnel_by_key6 =
+    hash_create_mem (0, sizeof (gre_tunnel_key6_t), sizeof (uword));
 
 #define _(n,s) add_protocol (gm, GRE_PROTOCOL_##s, #s);
   foreach_gre_protocol
index f597d42..83bab76 100644 (file)
@@ -75,6 +75,61 @@ typedef enum gre_tunnel_tyoe_t_
 
 #define GRE_TUNNEL_N_TYPES ((gre_tunnel_type_t)GRE_TUNNEL_TYPE_TEB+1)
 
+/**
+ * @brief Key for a IPv4 GRE Tunnel
+ */
+typedef struct gre_tunnel_key4_t_
+{
+  /**
+   * Source and destination IP addresses
+   */
+  union
+  {
+    struct
+    {
+      ip4_address_t gtk_src;
+      ip4_address_t gtk_dst;
+    };
+    u64 gtk_as_u64;
+  };
+
+  /**
+   * The FIB table the src,dst addresses are in.
+   * tunnels with the same IP addresses in different FIBs are not
+   * the same tunnel
+   */
+  u32 gtk_fib_index;
+} __attribute__ ((packed)) gre_tunnel_key4_t;
+
+/**
+ * @brief Key for a IPv6 GRE Tunnel
+ * We use a different type so that the V4 key hash is as small as possible
+ */
+typedef struct gre_tunnel_key6_t_
+{
+  /**
+   * Source and destination IP addresses
+   */
+  ip6_address_t gtk_src;
+  ip6_address_t gtk_dst;
+
+  /**
+   * The FIB table the src,dst addresses are in.
+   * tunnels with the same IP addresses in different FIBs are not
+   * the same tunnel
+   */
+  u32 gtk_fib_index;
+} __attribute__ ((packed)) gre_tunnel_key6_t;
+
+/**
+ * Union of the two possible key types
+ */
+typedef union gre_tunnel_key_t_
+{
+  gre_tunnel_key4_t gtk_v4;
+  gre_tunnel_key6_t gtk_v6;
+} gre_tunnel_key_t;
+
 /**
  * @brief A representation of a GRE tunnel
  */
@@ -85,6 +140,12 @@ typedef struct
    */
   fib_node_t node;
 
+  /**
+   * The hash table's key stored in separate memory since the tunnel_t
+   * memory can realloc.
+   */
+  gre_tunnel_key_t *key;
+
   /**
    * The tunnel's source/local address
    */
@@ -151,8 +212,8 @@ typedef struct
   uword *tunnel_by_key4;
 
   /**
-     * Hash mapping ipv6 src/dst addr pair to tunnel
-     */
+   * Hash mapping ipv6 src/dst addr pair to tunnel
+   */
   uword *tunnel_by_key6;
 
   /**
@@ -255,6 +316,45 @@ typedef struct
 int vnet_gre_add_del_tunnel
   (vnet_gre_add_del_tunnel_args_t * a, u32 * sw_if_indexp);
 
+static inline void
+gre_mk_key4 (const ip4_address_t * src,
+            const ip4_address_t * dst,
+            u32 fib_index, gre_tunnel_key4_t * key)
+{
+  key->gtk_src = *src;
+  key->gtk_dst = *dst;
+  key->gtk_fib_index = fib_index;
+}
+
+static inline int
+gre_match_key4 (const gre_tunnel_key4_t * key1,
+               const gre_tunnel_key4_t * key2)
+{
+  return ((key1->gtk_as_u64 == key2->gtk_as_u64) &&
+         (key1->gtk_fib_index == key2->gtk_fib_index));
+}
+
+static inline void
+gre_mk_key6 (const ip6_address_t * src,
+            const ip6_address_t * dst,
+            u32 fib_index, gre_tunnel_key6_t * key)
+{
+  key->gtk_src = *src;
+  key->gtk_dst = *dst;
+  key->gtk_fib_index = fib_index;
+}
+
+static inline int
+gre_match_key6 (const gre_tunnel_key6_t * key1,
+               const gre_tunnel_key6_t * key2)
+{
+  return ((key1->gtk_src.as_u64[0] == key2->gtk_src.as_u64[0]) &&
+         (key1->gtk_src.as_u64[1] == key2->gtk_src.as_u64[1]) &&
+         (key1->gtk_dst.as_u64[0] == key2->gtk_dst.as_u64[0]) &&
+         (key1->gtk_dst.as_u64[1] == key2->gtk_dst.as_u64[1]) &&
+         (key1->gtk_fib_index == key2->gtk_fib_index));
+}
+
 #endif /* included_gre_h */
 
 /*
index c17d22e..f103537 100644 (file)
 
 static const char *gre_tunnel_type_names[] = GRE_TUNNEL_TYPE_NAMES;
 
-static inline u64
-gre4_mk_key (const ip4_address_t * src,
-            const ip4_address_t * dst, u32 out_fib_index)
-{
-  // FIXME. the fib index should be part of the key
-  return ((u64) src->as_u32 << 32 | (u64) dst->as_u32);
-}
-
 static u8 *
 format_gre_tunnel_type (u8 * s, va_list * args)
 {
@@ -70,24 +62,21 @@ format_gre_tunnel (u8 * s, va_list * args)
 
 static gre_tunnel_t *
 gre_tunnel_db_find (const ip46_address_t * src,
-                   const ip46_address_t * dst, u32 out_fib_index, u8 is_ipv6)
+                   const ip46_address_t * dst,
+                   u32 out_fib_index, u8 is_ipv6, gre_tunnel_key_t * key)
 {
   gre_main_t *gm = &gre_main;
   uword *p;
-  u64 key4, key6[4];
 
   if (!is_ipv6)
     {
-      key4 = gre4_mk_key (&src->ip4, &dst->ip4, out_fib_index);
-      p = hash_get (gm->tunnel_by_key4, key4);
+      gre_mk_key4 (&src->ip4, &dst->ip4, out_fib_index, &key->gtk_v4);
+      p = hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4);
     }
   else
     {
-      key6[0] = src->ip6.as_u64[0];
-      key6[1] = src->ip6.as_u64[1];
-      key6[2] = dst->ip6.as_u64[0];
-      key6[3] = dst->ip6.as_u64[1];
-      p = hash_get_mem (gm->tunnel_by_key6, key6);
+      gre_mk_key6 (&src->ip6, &dst->ip6, out_fib_index, &key->gtk_v6);
+      p = hash_get_mem (gm->tunnel_by_key6, &key->gtk_v6);
     }
 
   if (NULL == p)
@@ -97,52 +86,39 @@ gre_tunnel_db_find (const ip46_address_t * src,
 }
 
 static void
-gre_tunnel_db_add (const gre_tunnel_t * t)
+gre_tunnel_db_add (gre_tunnel_t * t, gre_tunnel_key_t * key)
 {
   gre_main_t *gm = &gre_main;
-  u64 key4, key6[4], *key6_copy;
-  u8 is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
 
-  if (!is_ipv6)
+  t->key = clib_mem_alloc (sizeof (*t->key));
+  clib_memcpy (t->key, key, sizeof (*key));
+
+  if (t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6)
     {
-      key4 = gre4_mk_key (&t->tunnel_src.ip4, &t->tunnel_dst.fp_addr.ip4,
-                         t->outer_fib_index);
-      hash_set (gm->tunnel_by_key4, key4, t - gm->tunnels);
+      hash_set_mem (gm->tunnel_by_key6, &t->key->gtk_v6, t - gm->tunnels);
     }
   else
     {
-      key6[0] = t->tunnel_src.ip6.as_u64[0];
-      key6[1] = t->tunnel_src.ip6.as_u64[1];
-      key6[2] = t->tunnel_dst.fp_addr.ip6.as_u64[0];
-      key6[3] = t->tunnel_dst.fp_addr.ip6.as_u64[1];
-      key6_copy = clib_mem_alloc (sizeof (key6));
-      clib_memcpy (key6_copy, key6, sizeof (key6));
-      hash_set_mem (gm->tunnel_by_key6, key6_copy, t - gm->tunnels);
+      hash_set_mem (gm->tunnel_by_key4, &t->key->gtk_v4, t - gm->tunnels);
     }
 }
 
 static void
-gre_tunnel_db_remove (const gre_tunnel_t * t)
+gre_tunnel_db_remove (gre_tunnel_t * t)
 {
   gre_main_t *gm = &gre_main;
-  u64 key4, key6[4];
-  u8 is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
 
-  if (!is_ipv6)
+  if (t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6)
     {
-      key4 = gre4_mk_key (&t->tunnel_src.ip4, &t->tunnel_dst.fp_addr.ip4,
-                         t->outer_fib_index);
-      hash_unset (gm->tunnel_by_key4, key4);
+      hash_unset_mem (gm->tunnel_by_key6, &t->key->gtk_v6);
     }
   else
     {
-      key6[0] = t->tunnel_src.ip6.as_u64[0];
-      key6[1] = t->tunnel_src.ip6.as_u64[1];
-      key6[2] = t->tunnel_dst.fp_addr.ip6.as_u64[0];
-      key6[3] = t->tunnel_dst.fp_addr.ip6.as_u64[1];
-      hash_unset_mem (gm->tunnel_by_key6, key6);
+      hash_unset_mem (gm->tunnel_by_key4, &t->key->gtk_v4);
     }
 
+  clib_mem_free (t->key);
+  t->key = NULL;
 }
 
 static gre_tunnel_t *
@@ -283,6 +259,7 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t * a, u32 * sw_if_indexp)
   u8 address[6];
   clib_error_t *error;
   u8 is_ipv6 = a->is_ipv6;
+  gre_tunnel_key_t key;
 
   if (!is_ipv6)
     outer_fib_index = ip4_fib_index_from_table_id (a->outer_fib_id);
@@ -292,7 +269,8 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t * a, u32 * sw_if_indexp)
   if (~0 == outer_fib_index)
     return VNET_API_ERROR_NO_SUCH_FIB;
 
-  t = gre_tunnel_db_find (&a->src, &a->dst, a->outer_fib_id, a->is_ipv6);
+  t =
+    gre_tunnel_db_find (&a->src, &a->dst, a->outer_fib_id, a->is_ipv6, &key);
 
   if (NULL != t)
     return VNET_API_ERROR_INVALID_VALUE;
@@ -415,7 +393,7 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t * a, u32 * sw_if_indexp)
   t->tunnel_dst.fp_proto = !is_ipv6 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
   t->tunnel_dst.fp_addr = a->dst;
 
-  gre_tunnel_db_add (t);
+  gre_tunnel_db_add (t, &key);
 
   t->fib_entry_index =
     fib_table_entry_special_add (outer_fib_index,
@@ -446,9 +424,11 @@ vnet_gre_tunnel_delete (vnet_gre_add_del_tunnel_args_t * a,
   gre_main_t *gm = &gre_main;
   vnet_main_t *vnm = gm->vnet_main;
   gre_tunnel_t *t;
+  gre_tunnel_key_t key;
   u32 sw_if_index;
 
-  t = gre_tunnel_db_find (&a->src, &a->dst, a->outer_fib_id, a->is_ipv6);
+  t =
+    gre_tunnel_db_find (&a->src, &a->dst, a->outer_fib_id, a->is_ipv6, &key);
 
   if (NULL == t)
     return VNET_API_ERROR_NO_SUCH_ENTRY;
index 1a5fc87..7223b01 100644 (file)
@@ -73,18 +73,20 @@ gre_input (vlib_main_t * vm,
 {
   gre_main_t *gm = &gre_main;
   __attribute__ ((unused)) u32 n_left_from, next_index, *from, *to_next;
-  u64 cached_tunnel_key4;
-  u64 cached_tunnel_key6[4];
-  u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index = 0;
+  gre_tunnel_key_t cached_tunnel_key;
+
+  u32 cached_tunnel_sw_if_index = ~0, tunnel_sw_if_index = ~0;
 
   u32 thread_index = vlib_get_thread_index ();
   u32 len;
   vnet_interface_main_t *im = &gm->vnet_main->interface_main;
 
   if (!is_ipv6)
-    memset (&cached_tunnel_key4, 0xff, sizeof (cached_tunnel_key4));
+    memset (&cached_tunnel_key.gtk_v4, 0xff,
+           sizeof (cached_tunnel_key.gtk_v4));
   else
-    memset (&cached_tunnel_key6, 0xff, sizeof (cached_tunnel_key6));
+    memset (&cached_tunnel_key.gtk_v6, 0xff,
+           sizeof (cached_tunnel_key.gtk_v6));
 
   from = vlib_frame_vector_args (from_frame);
   n_left_from = from_frame->n_vectors;
@@ -107,10 +109,7 @@ gre_input (vlib_main_t * vm,
          u32 i0, i1, next0, next1, protocol0, protocol1;
          ip4_header_t *ip4_0, *ip4_1;
          ip6_header_t *ip6_0, *ip6_1;
-         u32 ip4_tun_src0, ip4_tun_dst0;
-         u32 ip4_tun_src1, ip4_tun_dst1;
-         u64 ip6_tun_src0[2], ip6_tun_dst0[2];
-         u64 ip6_tun_src1[2], ip6_tun_dst1[2];
+         gre_tunnel_key_t key0, key1;
 
          /* Prefetch next iteration. */
          {
@@ -143,11 +142,6 @@ gre_input (vlib_main_t * vm,
              /* ip4_local hands us the ip header, not the gre header */
              ip4_0 = vlib_buffer_get_current (b0);
              ip4_1 = vlib_buffer_get_current (b1);
-             /* Save src + dst ip4 address, e.g. for mpls-o-gre */
-             ip4_tun_src0 = ip4_0->src_address.as_u32;
-             ip4_tun_dst0 = ip4_0->dst_address.as_u32;
-             ip4_tun_src1 = ip4_1->src_address.as_u32;
-             ip4_tun_dst1 = ip4_1->dst_address.as_u32;
 
              vlib_buffer_advance (b0, sizeof (*ip4_0));
              vlib_buffer_advance (b1, sizeof (*ip4_1));
@@ -157,15 +151,6 @@ gre_input (vlib_main_t * vm,
              /* ip6_local hands us the ip header, not the gre header */
              ip6_0 = vlib_buffer_get_current (b0);
              ip6_1 = vlib_buffer_get_current (b1);
-             /* Save src + dst ip6 address, e.g. for mpls-o-gre */
-             ip6_tun_src0[0] = ip6_0->src_address.as_u64[0];
-             ip6_tun_src0[1] = ip6_0->src_address.as_u64[1];
-             ip6_tun_dst0[0] = ip6_0->dst_address.as_u64[0];
-             ip6_tun_dst0[1] = ip6_0->dst_address.as_u64[1];
-             ip6_tun_src1[0] = ip6_1->src_address.as_u64[0];
-             ip6_tun_src1[1] = ip6_1->src_address.as_u64[1];
-             ip6_tun_dst1[0] = ip6_1->dst_address.as_u64[0];
-             ip6_tun_dst1[1] = ip6_1->dst_address.as_u64[1];
 
              vlib_buffer_advance (b0, sizeof (*ip6_0));
              vlib_buffer_advance (b1, sizeof (*ip6_1));
@@ -210,34 +195,35 @@ gre_input (vlib_main_t * vm,
                            || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT
                            || next0 == GRE_INPUT_NEXT_MPLS_INPUT))
            {
-
-             u64 key4, key6[4];
-             if (!is_ipv6)
+             if (is_ipv6)
                {
-                 key4 = ((u64) (ip4_tun_dst0) << 32) | (u64) (ip4_tun_src0);
+                 gre_mk_key6 (&ip6_0->dst_address,
+                              &ip6_0->src_address,
+                              vnet_buffer (b0)->ip.fib_index, &key0.gtk_v6);
                }
              else
                {
-                 key6[0] = ip6_tun_dst0[0];
-                 key6[1] = ip6_tun_dst0[1];
-                 key6[2] = ip6_tun_src0[0];
-                 key6[3] = ip6_tun_src0[1];
+                 gre_mk_key4 (&ip4_0->dst_address,
+                              &ip4_0->src_address,
+                              vnet_buffer (b0)->ip.fib_index, &key0.gtk_v4);
                }
 
-             if ((!is_ipv6 && cached_tunnel_key4 != key4) ||
-                 (is_ipv6 && cached_tunnel_key6[0] != key6[0] &&
-                  cached_tunnel_key6[1] != key6[1] &&
-                  cached_tunnel_key6[2] != key6[2] &&
-                  cached_tunnel_key6[3] != key6[3]))
+             if ((!is_ipv6 && !gre_match_key4 (&cached_tunnel_key.gtk_v4,
+                                               &key0.gtk_v4)) ||
+                 (is_ipv6 && !gre_match_key6 (&cached_tunnel_key.gtk_v6,
+                                              &key0.gtk_v6)))
                {
-                 vnet_hw_interface_t *hi;
                  gre_tunnel_t *t;
                  uword *p;
 
                  if (!is_ipv6)
-                   p = hash_get (gm->tunnel_by_key4, key4);
+                   {
+                     p = hash_get_mem (gm->tunnel_by_key4, &key0.gtk_v4);
+                   }
                  else
-                   p = hash_get_mem (gm->tunnel_by_key6, key6);
+                   {
+                     p = hash_get_mem (gm->tunnel_by_key6, &key0.gtk_v6);
+                   }
                  if (!p)
                    {
                      next0 = GRE_INPUT_NEXT_DROP;
@@ -245,10 +231,17 @@ gre_input (vlib_main_t * vm,
                      goto drop0;
                    }
                  t = pool_elt_at_index (gm->tunnels, p[0]);
-                 hi = vnet_get_hw_interface (gm->vnet_main, t->hw_if_index);
-                 tunnel_sw_if_index = hi->sw_if_index;
+                 tunnel_sw_if_index = t->sw_if_index;
 
                  cached_tunnel_sw_if_index = tunnel_sw_if_index;
+                 if (!is_ipv6)
+                   {
+                     cached_tunnel_key.gtk_v4 = key0.gtk_v4;
+                   }
+                 else
+                   {
+                     cached_tunnel_key.gtk_v6 = key0.gtk_v6;
+                   }
                }
              else
                {
@@ -276,34 +269,35 @@ gre_input (vlib_main_t * vm,
                            || next1 == GRE_INPUT_NEXT_ETHERNET_INPUT
                            || next1 == GRE_INPUT_NEXT_MPLS_INPUT))
            {
-             u64 key4, key6[4];
-             if (!is_ipv6)
+             if (is_ipv6)
                {
-                 key4 = ((u64) (ip4_tun_dst1) << 32) | (u64) (ip4_tun_src1);
+                 gre_mk_key6 (&ip6_1->dst_address,
+                              &ip6_1->src_address,
+                              vnet_buffer (b1)->ip.fib_index, &key1.gtk_v6);
                }
              else
                {
-                 key6[0] = ip6_tun_dst1[0];
-                 key6[1] = ip6_tun_dst1[1];
-                 key6[2] = ip6_tun_src1[0];
-                 key6[3] = ip6_tun_src1[1];
+                 gre_mk_key4 (&ip4_1->dst_address,
+                              &ip4_1->src_address,
+                              vnet_buffer (b1)->ip.fib_index, &key1.gtk_v4);
                }
 
-             if ((!is_ipv6 && cached_tunnel_key4 != key4) ||
-                 (is_ipv6 && cached_tunnel_key6[0] != key6[0] &&
-                  cached_tunnel_key6[1] != key6[1] &&
-                  cached_tunnel_key6[2] != key6[2] &&
-                  cached_tunnel_key6[3] != key6[3]))
+             if ((!is_ipv6 && !gre_match_key4 (&cached_tunnel_key.gtk_v4,
+                                               &key1.gtk_v4)) ||
+                 (is_ipv6 && !gre_match_key6 (&cached_tunnel_key.gtk_v6,
+                                              &key1.gtk_v6)))
                {
-                 vnet_hw_interface_t *hi;
                  gre_tunnel_t *t;
                  uword *p;
 
                  if (!is_ipv6)
-                   p = hash_get (gm->tunnel_by_key4, key4);
+                   {
+                     p = hash_get_mem (gm->tunnel_by_key4, &key1.gtk_v4);
+                   }
                  else
-                   p = hash_get_mem (gm->tunnel_by_key6, key6);
-
+                   {
+                     p = hash_get_mem (gm->tunnel_by_key6, &key1.gtk_v6);
+                   }
                  if (!p)
                    {
                      next1 = GRE_INPUT_NEXT_DROP;
@@ -311,10 +305,17 @@ gre_input (vlib_main_t * vm,
                      goto drop1;
                    }
                  t = pool_elt_at_index (gm->tunnels, p[0]);
-                 hi = vnet_get_hw_interface (gm->vnet_main, t->hw_if_index);
-                 tunnel_sw_if_index = hi->sw_if_index;
+                 tunnel_sw_if_index = t->sw_if_index;
 
                  cached_tunnel_sw_if_index = tunnel_sw_if_index;
+                 if (!is_ipv6)
+                   {
+                     cached_tunnel_key.gtk_v4 = key1.gtk_v4;
+                   }
+                 else
+                   {
+                     cached_tunnel_key.gtk_v6 = key1.gtk_v6;
+                   }
                }
              else
                {
@@ -397,8 +398,7 @@ gre_input (vlib_main_t * vm,
          u16 version0;
          int verr0;
          u32 i0, next0;
-         u32 ip4_tun_src0, ip4_tun_dst0;
-         u64 ip6_tun_src0[2], ip6_tun_dst0[2];
+         gre_tunnel_key_t key0;
 
          bi0 = from[0];
          to_next[0] = bi0;
@@ -413,18 +413,10 @@ gre_input (vlib_main_t * vm,
 
          if (!is_ipv6)
            {
-             ip4_tun_src0 = ip4_0->src_address.as_u32;
-             ip4_tun_dst0 = ip4_0->dst_address.as_u32;
-
              vlib_buffer_advance (b0, sizeof (*ip4_0));
            }
          else
            {
-             ip6_tun_src0[0] = ip6_0->src_address.as_u64[0];
-             ip6_tun_src0[1] = ip6_0->src_address.as_u64[1];
-             ip6_tun_dst0[0] = ip6_0->dst_address.as_u64[0];
-             ip6_tun_dst0[1] = ip6_0->dst_address.as_u64[1];
-
              vlib_buffer_advance (b0, sizeof (*ip6_0));
            }
 
@@ -453,34 +445,35 @@ gre_input (vlib_main_t * vm,
                            || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT
                            || next0 == GRE_INPUT_NEXT_MPLS_INPUT))
            {
-             u64 key4, key6[4];
-             if (!is_ipv6)
+             if (is_ipv6)
                {
-                 key4 = ((u64) (ip4_tun_dst0) << 32) | (u64) (ip4_tun_src0);
+                 gre_mk_key6 (&ip6_0->dst_address,
+                              &ip6_0->src_address,
+                              vnet_buffer (b0)->ip.fib_index, &key0.gtk_v6);
                }
              else
                {
-                 key6[0] = ip6_tun_dst0[0];
-                 key6[1] = ip6_tun_dst0[1];
-                 key6[2] = ip6_tun_src0[0];
-                 key6[3] = ip6_tun_src0[1];
+                 gre_mk_key4 (&ip4_0->dst_address,
+                              &ip4_0->src_address,
+                              vnet_buffer (b0)->ip.fib_index, &key0.gtk_v4);
                }
 
-             if ((!is_ipv6 && cached_tunnel_key4 != key4) ||
-                 (is_ipv6 && cached_tunnel_key6[0] != key6[0] &&
-                  cached_tunnel_key6[1] != key6[1] &&
-                  cached_tunnel_key6[2] != key6[2] &&
-                  cached_tunnel_key6[3] != key6[3]))
+             if ((!is_ipv6 && !gre_match_key4 (&cached_tunnel_key.gtk_v4,
+                                               &key0.gtk_v4)) ||
+                 (is_ipv6 && !gre_match_key6 (&cached_tunnel_key.gtk_v6,
+                                              &key0.gtk_v6)))
                {
-                 vnet_hw_interface_t *hi;
                  gre_tunnel_t *t;
                  uword *p;
 
                  if (!is_ipv6)
-                   p = hash_get (gm->tunnel_by_key4, key4);
+                   {
+                     p = hash_get_mem (gm->tunnel_by_key4, &key0.gtk_v4);
+                   }
                  else
-                   p = hash_get_mem (gm->tunnel_by_key6, key6);
-
+                   {
+                     p = hash_get_mem (gm->tunnel_by_key6, &key0.gtk_v6);
+                   }
                  if (!p)
                    {
                      next0 = GRE_INPUT_NEXT_DROP;
@@ -488,10 +481,17 @@ gre_input (vlib_main_t * vm,
                      goto drop;
                    }
                  t = pool_elt_at_index (gm->tunnels, p[0]);
-                 hi = vnet_get_hw_interface (gm->vnet_main, t->hw_if_index);
-                 tunnel_sw_if_index = hi->sw_if_index;
+                 tunnel_sw_if_index = t->sw_if_index;
 
                  cached_tunnel_sw_if_index = tunnel_sw_if_index;
+                 if (!is_ipv6)
+                   {
+                     cached_tunnel_key.gtk_v4 = key0.gtk_v4;
+                   }
+                 else
+                   {
+                     cached_tunnel_key.gtk_v6 = key0.gtk_v6;
+                   }
                }
              else
                {
index 5cdc063..7032940 100644 (file)
@@ -673,6 +673,25 @@ class TestGRE(VppTestCase):
         rx = self.pg0.get_capture(len(tx))
         self.verify_decapped_4o4(self.pg0, rx, tx)
 
+        #
+        # Send tunneled packets that match the created tunnel and
+        # but arrive on an interface that is not in the tunnel's
+        # encap VRF, these are dropped
+        #
+        self.vapi.cli("clear trace")
+        tx = self.create_tunnel_stream_4o4(self.pg2,
+                                           "2.2.2.2",
+                                           self.pg1.local_ip4,
+                                           self.pg0.local_ip4,
+                                           self.pg0.remote_ip4)
+        self.pg1.add_stream(tx)
+
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        self.pg0.assert_nothing_captured(
+            remark="GRE decap packets in wrong VRF")
+
         #
         # test case cleanup
         #
index 1c71875..acfd348 100644 (file)
@@ -9,7 +9,7 @@ class VppGreInterface(VppInterface):
     """
 
     def __init__(self, test, src_ip, dst_ip, outer_fib_id=0, is_teb=0):
-        """ Create VPP loopback interface """
+        """ Create VPP GRE interface """
         self._sw_if_index = 0
         super(VppGreInterface, self).__init__(test)
         self._test = test
@@ -42,7 +42,7 @@ class VppGre6Interface(VppInterface):
     """
 
     def __init__(self, test, src_ip, dst_ip, outer_fib_id=0, is_teb=0):
-        """ Create VPP loopback interface """
+        """ Create VPP GRE interface """
         self._sw_if_index = 0
         super(VppGre6Interface, self).__init__(test)
         self._test = test