gre: multipoint ingress lookup fix 42/24042/3
authorNeale Ranns <nranns@cisco.com>
Tue, 17 Dec 2019 20:15:03 +0000 (20:15 +0000)
committerJohn Lo <loj@cisco.com>
Thu, 19 Dec 2019 15:17:40 +0000 (15:17 +0000)
Type: fix

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

index 11bcddd..6989cf4 100644 (file)
@@ -95,6 +95,26 @@ typedef struct
   u32 next_index;
 } gre_protocol_info_t;
 
+/**
+ * Elements of the GRE key that are common for v6 and v6 addresses
+ */
+typedef struct gre_tunnel_key_common_t_
+{
+  union
+  {
+    struct
+    {
+      u32 fib_index;
+      u16 session_id;
+      gre_tunnel_type_t type;
+      gre_tunnel_mode_t mode;
+    };
+    u64 as_u64;
+  };
+} gre_tunnel_key_common_t;
+
+STATIC_ASSERT_SIZEOF (gre_tunnel_key_common_t, sizeof (u64));
+
 /**
  * @brief Key for a IPv4 GRE Tunnel
  */
@@ -113,15 +133,12 @@ typedef struct gre_tunnel_key4_t_
     u64 gtk_as_u64;
   };
 
-  /**
-   * FIB table index, ERSPAN session ID and tunnel type in u32 bit fields:
-   * - The FIB table index the src,dst addresses are in, top 20 bits
-   * - The Session ID for ERSPAN tunnel type and 0 otherwise, next 10 bits
-   * - Tunnel type, bottom 2 bits
-   */
-  u32 gtk_fidx_ssid_type;
+  /** address independent attributes */
+  gre_tunnel_key_common_t gtk_common;
 } __attribute__ ((packed)) gre_tunnel_key4_t;
 
+STATIC_ASSERT_SIZEOF (gre_tunnel_key4_t, 2 * sizeof (u64));
+
 /**
  * @brief Key for a IPv6 GRE Tunnel
  * We use a different type so that the V4 key hash is as small as possible
@@ -134,22 +151,11 @@ typedef struct gre_tunnel_key6_t_
   ip6_address_t gtk_src;
   ip6_address_t gtk_dst;
 
-  /**
-   * FIB table index, ERSPAN session ID and tunnel type in u32 bit fields:
-   * - The FIB table index the src,dst addresses are in, top 20 bits
-   * - The Session ID for ERSPAN tunnel type and 0 otherwise, next 10 bits
-   * - Tunnel type, bottom 2 bits
-   */
-  u32 gtk_fidx_ssid_type;
+  /** address independent attributes */
+  gre_tunnel_key_common_t gtk_common;
 } __attribute__ ((packed)) gre_tunnel_key6_t;
 
-#define GTK_FIB_INDEX_SHIFT    12
-#define GTK_FIB_INDEX_MASK     0xfffff000
-#define GTK_TYPE_SHIFT         0
-#define GTK_TYPE_MASK          0x3
-#define GTK_SESSION_ID_SHIFT   2
-#define GTK_SESSION_ID_MASK    0xffc
-#define GTK_SESSION_ID_MAX     (GTK_SESSION_ID_MASK >> GTK_SESSION_ID_SHIFT)
+STATIC_ASSERT_SIZEOF (gre_tunnel_key6_t, 5 * sizeof (u64));
 
 /**
  * Union of the two possible key types
@@ -160,6 +166,11 @@ typedef union gre_tunnel_key_t_
   gre_tunnel_key6_t gtk_v6;
 } gre_tunnel_key_t;
 
+/**
+ * The session ID is only a 10 bit value
+ */
+#define GTK_SESSION_ID_MAX (0x3ff)
+
 /**
  * Used for GRE header seq number generation for ERSPAN encap
  */
@@ -189,12 +200,6 @@ typedef struct
    */
   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
 
-  /**
-   * 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
    */
@@ -372,12 +377,16 @@ extern int vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t * a,
 static inline void
 gre_mk_key4 (ip4_address_t src,
             ip4_address_t dst,
-            u32 fib_index, u8 ttype, u16 session_id, gre_tunnel_key4_t * key)
+            u32 fib_index,
+            gre_tunnel_type_t ttype,
+            gre_tunnel_mode_t tmode, u16 session_id, gre_tunnel_key4_t * key)
 {
   key->gtk_src = src;
   key->gtk_dst = dst;
-  key->gtk_fidx_ssid_type = ttype |
-    (fib_index << GTK_FIB_INDEX_SHIFT) | (session_id << GTK_SESSION_ID_SHIFT);
+  key->gtk_common.type = ttype;
+  key->gtk_common.mode = tmode;
+  key->gtk_common.fib_index = fib_index;
+  key->gtk_common.session_id = session_id;
 }
 
 static inline int
@@ -385,29 +394,31 @@ 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_fidx_ssid_type == key2->gtk_fidx_ssid_type));
+         (key1->gtk_common.as_u64 == key2->gtk_common.as_u64));
 }
 
 static inline void
 gre_mk_key6 (const ip6_address_t * src,
             const ip6_address_t * dst,
-            u32 fib_index, u8 ttype, u16 session_id, gre_tunnel_key6_t * key)
+            u32 fib_index,
+            gre_tunnel_type_t ttype,
+            gre_tunnel_mode_t tmode, u16 session_id, gre_tunnel_key6_t * key)
 {
   key->gtk_src = *src;
   key->gtk_dst = *dst;
-  key->gtk_fidx_ssid_type = ttype |
-    (fib_index << GTK_FIB_INDEX_SHIFT) | (session_id << GTK_SESSION_ID_SHIFT);
+  key->gtk_common.type = ttype;
+  key->gtk_common.mode = tmode;
+  key->gtk_common.fib_index = fib_index;
+  key->gtk_common.session_id = session_id;
 }
 
 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_fidx_ssid_type == key2->gtk_fidx_ssid_type));
+  return (ip6_address_is_equal (&key1->gtk_src, &key2->gtk_src) &&
+         ip6_address_is_equal (&key1->gtk_dst, &key2->gtk_dst) &&
+         (key1->gtk_common.as_u64 == key2->gtk_common.as_u64));
 }
 
 static inline void
index 927f34e..fab12b4 100644 (file)
@@ -25,6 +25,7 @@
 #include <vnet/adj/adj_nbr.h>
 #include <vnet/mpls/mpls.h>
 #include <vnet/l2/l2_input.h>
+#include <vnet/nhrp/nhrp.h>
 
 u8 *
 format_gre_tunnel_type (u8 * s, va_list * args)
@@ -93,13 +94,13 @@ gre_tunnel_db_find (const vnet_gre_tunnel_add_del_args_t * a,
   if (!a->is_ipv6)
     {
       gre_mk_key4 (a->src.ip4, a->dst.ip4, outer_fib_index,
-                  a->type, a->session_id, &key->gtk_v4);
+                  a->type, a->mode, a->session_id, &key->gtk_v4);
       p = hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4);
     }
   else
     {
       gre_mk_key6 (&a->src.ip6, &a->dst.ip6, outer_fib_index,
-                  a->type, a->session_id, &key->gtk_v6);
+                  a->type, a->mode, a->session_id, &key->gtk_v6);
       p = hash_get_mem (gm->tunnel_by_key6, &key->gtk_v6);
     }
 
@@ -114,35 +115,29 @@ gre_tunnel_db_add (gre_tunnel_t * t, gre_tunnel_key_t * key)
 {
   gre_main_t *gm = &gre_main;
 
-  t->key = clib_mem_alloc (sizeof (*t->key));
-  clib_memcpy (t->key, key, sizeof (*key));
-
   if (t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6)
     {
-      hash_set_mem (gm->tunnel_by_key6, &t->key->gtk_v6, t->dev_instance);
+      hash_set_mem_alloc (&gm->tunnel_by_key6, &key->gtk_v6, t->dev_instance);
     }
   else
     {
-      hash_set_mem (gm->tunnel_by_key4, &t->key->gtk_v4, t->dev_instance);
+      hash_set_mem_alloc (&gm->tunnel_by_key4, &key->gtk_v4, t->dev_instance);
     }
 }
 
 static void
-gre_tunnel_db_remove (gre_tunnel_t * t)
+gre_tunnel_db_remove (gre_tunnel_t * t, gre_tunnel_key_t * key)
 {
   gre_main_t *gm = &gre_main;
 
   if (t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6)
     {
-      hash_unset_mem (gm->tunnel_by_key6, &t->key->gtk_v6);
+      hash_unset_mem_free (&gm->tunnel_by_key6, &key->gtk_v6);
     }
   else
     {
-      hash_unset_mem (gm->tunnel_by_key4, &t->key->gtk_v4);
+      hash_unset_mem_free (&gm->tunnel_by_key4, &key->gtk_v4);
     }
-
-  clib_mem_free (t->key);
-  t->key = NULL;
 }
 
 /**
@@ -204,6 +199,99 @@ gre_tunnel_restack (gre_tunnel_t * gt)
   }
 }
 
+static void
+gre_nhrp_mk_key (const gre_tunnel_t * t,
+                const nhrp_entry_t * ne, gre_tunnel_key_t * key)
+{
+  const fib_prefix_t *nh;
+
+  nh = nhrp_entry_get_nh (ne);
+
+  /* construct the key using mode P2P so it can be found in the DP */
+  if (FIB_PROTOCOL_IP4 == nh->fp_proto)
+    gre_mk_key4 (t->tunnel_src.ip4,
+                nh->fp_addr.ip4,
+                nhrp_entry_get_fib_index (ne),
+                t->type, GRE_TUNNEL_MODE_P2P, 0, &key->gtk_v4);
+  else
+    gre_mk_key6 (&t->tunnel_src.ip6,
+                &nh->fp_addr.ip6,
+                nhrp_entry_get_fib_index (ne),
+                t->type, GRE_TUNNEL_MODE_P2P, 0, &key->gtk_v6);
+}
+
+static void
+gre_nhrp_entry_added (const nhrp_entry_t * ne)
+{
+  gre_main_t *gm = &gre_main;
+  gre_tunnel_key_t key;
+  gre_tunnel_t *t;
+  u32 sw_if_index;
+  u32 t_idx;
+
+  sw_if_index = nhrp_entry_get_sw_if_index (ne);
+  if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
+    return;
+
+  t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
+
+  if (INDEX_INVALID == t_idx)
+    return;
+
+  t = pool_elt_at_index (gm->tunnels, t_idx);
+
+  gre_nhrp_mk_key (t, ne, &key);
+  gre_tunnel_db_add (t, &key);
+}
+
+static void
+gre_nhrp_entry_deleted (const nhrp_entry_t * ne)
+{
+  gre_main_t *gm = &gre_main;
+  gre_tunnel_key_t key;
+  gre_tunnel_t *t;
+  u32 sw_if_index;
+  u32 t_idx;
+
+  sw_if_index = nhrp_entry_get_sw_if_index (ne);
+  if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
+    return;
+
+  t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
+
+  if (INDEX_INVALID == t_idx)
+    return;
+
+  t = pool_elt_at_index (gm->tunnels, t_idx);
+
+  gre_nhrp_mk_key (t, ne, &key);
+  gre_tunnel_db_remove (t, &key);
+}
+
+static walk_rc_t
+gre_tunnel_delete_nhrp_walk (index_t nei, void *ctx)
+{
+  gre_tunnel_t *t = ctx;
+  gre_tunnel_key_t key;
+
+  gre_nhrp_mk_key (t, nhrp_entry_get (nei), &key);
+  gre_tunnel_db_remove (t, &key);
+
+  return (WALK_CONTINUE);
+}
+
+static walk_rc_t
+gre_tunnel_add_nhrp_walk (index_t nei, void *ctx)
+{
+  gre_tunnel_t *t = ctx;
+  gre_tunnel_key_t key;
+
+  gre_nhrp_mk_key (t, nhrp_entry_get (nei), &key);
+  gre_tunnel_db_add (t, &key);
+
+  return (WALK_CONTINUE);
+}
+
 static int
 vnet_gre_tunnel_add (vnet_gre_tunnel_add_del_args_t * a,
                     u32 outer_fib_index, u32 * sw_if_indexp)
@@ -315,6 +403,10 @@ vnet_gre_tunnel_add (vnet_gre_tunnel_add_del_args_t * a,
   t->tunnel_dst.fp_addr = a->dst;
 
   gre_tunnel_db_add (t, &key);
+
+  if (t->mode == GRE_TUNNEL_MODE_MP)
+    nhrp_walk_itf (t->sw_if_index, gre_tunnel_add_nhrp_walk, t);
+
   if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
     {
       gre_sn_key_t skey;
@@ -368,6 +460,9 @@ vnet_gre_tunnel_delete (vnet_gre_tunnel_add_del_args_t * a,
   if (NULL == t)
     return VNET_API_ERROR_NO_SUCH_ENTRY;
 
+  if (t->mode == GRE_TUNNEL_MODE_MP)
+    nhrp_walk_itf (t->sw_if_index, gre_tunnel_delete_nhrp_walk, t);
+
   sw_if_index = t->sw_if_index;
   vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
 
@@ -397,7 +492,7 @@ vnet_gre_tunnel_delete (vnet_gre_tunnel_add_del_args_t * a,
     }
 
   hash_unset (gm->instance_used, t->user_instance);
-  gre_tunnel_db_remove (t);
+  gre_tunnel_db_remove (t, &key);
   pool_put (gm->tunnels, t);
 
   if (sw_if_indexp)
@@ -423,6 +518,9 @@ vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t * a,
   if (a->session_id > GTK_SESSION_ID_MAX)
     return VNET_API_ERROR_INVALID_SESSION_ID;
 
+  if (a->mode == GRE_TUNNEL_MODE_MP && !ip46_address_is_zero (&a->dst))
+    return (VNET_API_ERROR_INVALID_DST_ADDRESS);
+
   if (a->is_add)
     return (vnet_gre_tunnel_add (a, outer_fib_index, sw_if_indexp));
   else
@@ -639,10 +737,17 @@ VLIB_CLI_COMMAND (show_gre_tunnel_command, static) = {
 };
 /* *INDENT-ON* */
 
+const static nhrp_vft_t gre_nhrp_vft = {
+  .nv_added = gre_nhrp_entry_added,
+  .nv_deleted = gre_nhrp_entry_deleted,
+};
+
 /* force inclusion from application's main.c */
 clib_error_t *
 gre_interface_init (vlib_main_t * vm)
 {
+  nhrp_register (&gre_nhrp_vft);
+
   return (NULL);
 }
 
index 891fc9c..14fb087 100644 (file)
@@ -239,16 +239,17 @@ gre_input (vlib_main_t * vm,
       len[0] = vlib_buffer_length_in_chain (vm, b[0]);
       len[1] = vlib_buffer_length_in_chain (vm, b[1]);
 
+      /* always search for P2P types in the DP */
       if (is_ipv6)
        {
          gre_mk_key6 (&ip6[0]->dst_address,
                       &ip6[0]->src_address,
                       vnet_buffer (b[0])->ip.fib_index,
-                      type[0], 0, &key[0].gtk_v6);
+                      type[0], GRE_TUNNEL_MODE_P2P, 0, &key[0].gtk_v6);
          gre_mk_key6 (&ip6[1]->dst_address,
                       &ip6[1]->src_address,
                       vnet_buffer (b[1])->ip.fib_index,
-                      type[1], 0, &key[1].gtk_v6);
+                      type[1], GRE_TUNNEL_MODE_P2P, 0, &key[1].gtk_v6);
          matched[0] = gre_match_key6 (&cached_key.gtk_v6, &key[0].gtk_v6);
          matched[1] = gre_match_key6 (&cached_key.gtk_v6, &key[1].gtk_v6);
        }
@@ -257,11 +258,11 @@ gre_input (vlib_main_t * vm,
          gre_mk_key4 (ip4[0]->dst_address,
                       ip4[0]->src_address,
                       vnet_buffer (b[0])->ip.fib_index,
-                      type[0], 0, &key[0].gtk_v4);
+                      type[0], GRE_TUNNEL_MODE_P2P, 0, &key[0].gtk_v4);
          gre_mk_key4 (ip4[1]->dst_address,
                       ip4[1]->src_address,
                       vnet_buffer (b[1])->ip.fib_index,
-                      type[1], 0, &key[1].gtk_v4);
+                      type[1], GRE_TUNNEL_MODE_P2P, 0, &key[1].gtk_v4);
          matched[0] = gre_match_key4 (&cached_key.gtk_v4, &key[0].gtk_v4);
          matched[1] = gre_match_key4 (&cached_key.gtk_v4, &key[1].gtk_v4);
        }
@@ -380,7 +381,7 @@ gre_input (vlib_main_t * vm,
          gre_mk_key6 (&ip6[0]->dst_address,
                       &ip6[0]->src_address,
                       vnet_buffer (b[0])->ip.fib_index,
-                      type[0], 0, &key[0].gtk_v6);
+                      type[0], GRE_TUNNEL_MODE_P2P, 0, &key[0].gtk_v6);
          matched[0] = gre_match_key6 (&cached_key.gtk_v6, &key[0].gtk_v6);
        }
       else
@@ -388,7 +389,7 @@ gre_input (vlib_main_t * vm,
          gre_mk_key4 (ip4[0]->dst_address,
                       ip4[0]->src_address,
                       vnet_buffer (b[0])->ip.fib_index,
-                      type[0], 0, &key[0].gtk_v4);
+                      type[0], GRE_TUNNEL_MODE_P2P, 0, &key[0].gtk_v4);
          matched[0] = gre_match_key4 (&cached_key.gtk_v4, &key[0].gtk_v4);
        }
 
index a89f6cd..e97fbe0 100644 (file)
 #include <vnet/fib/fib_table.h>
 #include <vnet/adj/adj_midchain.h>
 
+typedef struct nhrp_key_t_
+{
+  ip46_address_t nk_peer;
+  u32 nk_sw_if_index;
+} nhrp_key_t;
+
+struct nhrp_entry_t_
+{
+  nhrp_key_t *ne_key;
+  fib_prefix_t ne_nh;
+  u32 ne_fib_index;
+};
+
 static uword *nhrp_db;
 static nhrp_entry_t *nhrp_pool;
+static nhrp_vft_t *nhrp_vfts;
+
+#define NHRP_NOTIFY(_ne, _fn) {                 \
+  nhrp_vft_t *_vft;                             \
+  vec_foreach(_vft, nhrp_vfts) {                \
+    if (_vft->_fn) {                             \
+      _vft->_fn(_ne);                            \
+    }                                           \
+  }                                             \
+}
+
+u32
+nhrp_entry_get_sw_if_index (const nhrp_entry_t * ne)
+{
+  return (ne->ne_key->nk_sw_if_index);
+}
+
+u32
+nhrp_entry_get_fib_index (const nhrp_entry_t * ne)
+{
+  return (ne->ne_fib_index);
+}
+
+const ip46_address_t *
+nhrp_entry_get_peer (const nhrp_entry_t * ne)
+{
+  return (&ne->ne_key->nk_peer);
+}
+
+const fib_prefix_t *
+nhrp_entry_get_nh (const nhrp_entry_t * ne)
+{
+  return (&ne->ne_nh);
+}
 
 void
 nhrp_entry_adj_stack (const nhrp_entry_t * ne, adj_index_t ai)
@@ -113,6 +160,8 @@ nhrp_entry_add (u32 sw_if_index,
       adj_nbr_walk_nh (sw_if_index,
                       ne->ne_nh.fp_proto,
                       &ne->ne_key->nk_peer, nhrp_entry_add_adj_walk, ne);
+
+      NHRP_NOTIFY (ne, nv_added);
     }
   else
     return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
@@ -135,6 +184,8 @@ nhrp_entry_del (u32 sw_if_index, const ip46_address_t * peer)
                       ne->ne_nh.fp_proto,
                       &ne->ne_key->nk_peer, nhrp_entry_del_adj_walk, ne);
 
+      NHRP_NOTIFY (ne, nv_deleted);
+
       clib_mem_free (ne->ne_key);
       pool_put (nhrp_pool, ne);
     }
@@ -178,6 +229,26 @@ nhrp_walk (nhrp_walk_cb_t fn, void *ctx)
   /* *INDENT-ON* */
 }
 
+void
+nhrp_walk_itf (u32 sw_if_index, nhrp_walk_cb_t fn, void *ctx)
+{
+  index_t nei;
+
+  /* *INDENT-OFF* */
+  pool_foreach_index(nei, nhrp_pool,
+  ({
+    if (sw_if_index == nhrp_entry_get_sw_if_index(nhrp_entry_get(nei)))
+      fn(nei, ctx);
+  }));
+  /* *INDENT-ON* */
+}
+
+void
+nhrp_register (const nhrp_vft_t * vft)
+{
+  vec_add1 (nhrp_vfts, *vft);
+}
+
 static clib_error_t *
 nhrp_init (vlib_main_t * vm)
 {
index fa842fe..5b46b0d 100644 (file)
 
 #include <vnet/ip/ip.h>
 
-typedef struct nhrp_key_t_
-{
-  ip46_address_t nk_peer;
-  u32 nk_sw_if_index;
-} nhrp_key_t;
-
-typedef struct nhrp_entry_t_
-{
-  nhrp_key_t *ne_key;
-  fib_prefix_t ne_nh;
-  u32 ne_fib_index;
-} nhrp_entry_t;
+/**
+ * An NHRP entry represents the mapping between a peer on an interface in the overlay
+ * and a next-hop address in the underlay.
+ *  i.e. there's a multipoint tunnel providing the overlay (henace a peer on
+ *   that tunnel) which is reachable via 'tunnel destination' address in the
+ *   underlay.
+ */
+typedef struct nhrp_entry_t_ nhrp_entry_t;
 
+/** accessors for the opaque struct */
+extern u32 nhrp_entry_get_sw_if_index (const nhrp_entry_t * ne);
+extern u32 nhrp_entry_get_fib_index (const nhrp_entry_t * ne);
+extern const ip46_address_t *nhrp_entry_get_peer (const nhrp_entry_t * ne);
+extern const fib_prefix_t *nhrp_entry_get_nh (const nhrp_entry_t * ne);
 extern u8 *format_nhrp_entry (u8 * s, va_list * args);
 
+/**
+ * Create a new NHRP entry
+ */
 extern int nhrp_entry_add (u32 sw_if_index,
                           const ip46_address_t * peer,
                           u32 nh_table_id, const ip46_address_t * nh);
@@ -50,6 +54,21 @@ extern void nhrp_entry_adj_stack (const nhrp_entry_t * ne, adj_index_t ai);
 typedef walk_rc_t (*nhrp_walk_cb_t) (index_t nei, void *ctx);
 
 extern void nhrp_walk (nhrp_walk_cb_t fn, void *ctx);
+extern void nhrp_walk_itf (u32 sw_if_index, nhrp_walk_cb_t fn, void *ctx);
+
+/**
+ * Notifications for the creation and deletion of NHRP entries
+ */
+typedef void (*nhrp_entry_added_t) (const nhrp_entry_t * ne);
+typedef void (*nhrp_entry_deleted_t) (const nhrp_entry_t * ne);
+
+typedef struct nhrp_vft_t_
+{
+  nhrp_entry_added_t nv_added;
+  nhrp_entry_deleted_t nv_deleted;
+} nhrp_vft_t;
+
+extern void nhrp_register (const nhrp_vft_t * vft);
 
 #endif
 
index 6f07eb7..d36adf9 100644 (file)
@@ -70,6 +70,7 @@ vl_api_nhrp_send_one (index_t nei, void *arg)
   vl_api_nhrp_details_t *mp;
   vl_api_nhrp_send_t *ctx = arg;
   const nhrp_entry_t *ne;
+  const fib_prefix_t *pfx;
 
   mp = vl_msg_api_alloc (sizeof (*mp));
   clib_memset (mp, 0, sizeof (*mp));
@@ -77,12 +78,15 @@ vl_api_nhrp_send_one (index_t nei, void *arg)
   mp->context = ctx->context;
 
   ne = nhrp_entry_get (nei);
+  pfx = nhrp_entry_get_nh (ne);
 
-  ip_address_encode (&ne->ne_key->nk_peer, IP46_TYPE_ANY, &mp->entry.peer);
-  ip_address_encode (&ne->ne_nh.fp_addr, IP46_TYPE_ANY, &mp->entry.nh);
+  ip_address_encode (nhrp_entry_get_peer (ne), IP46_TYPE_ANY,
+                    &mp->entry.peer);
+  ip_address_encode (&pfx->fp_addr, IP46_TYPE_ANY, &mp->entry.nh);
   mp->entry.nh_table_id =
-    htonl (fib_table_get_table_id (ne->ne_fib_index, ne->ne_nh.fp_proto));
-  mp->entry.sw_if_index = htonl (ne->ne_key->nk_sw_if_index);
+    htonl (fib_table_get_table_id
+          (nhrp_entry_get_fib_index (ne), pfx->fp_proto));
+  mp->entry.sw_if_index = htonl (nhrp_entry_get_sw_if_index (ne));
 
   vl_api_send_msg (ctx->reg, (u8 *) mp);
 
index 96fe304..f4b4ee2 100644 (file)
@@ -451,6 +451,28 @@ class TestGRE(VppTestCase):
                 self.logger.error(ppp("Tx:", tx))
                 raise
 
+    def verify_decapped_6o6(self, src_if, capture, sent):
+        self.assertEqual(len(capture), len(sent))
+
+        for i in range(len(capture)):
+            try:
+                tx = sent[i]
+                rx = capture[i]
+
+                tx_ip = tx[IPv6]
+                rx_ip = rx[IPv6]
+                tx_gre = tx[GRE]
+                tx_ip = tx_gre[IPv6]
+
+                self.assertEqual(rx_ip.src, tx_ip.src)
+                self.assertEqual(rx_ip.dst, tx_ip.dst)
+                self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
+
+            except:
+                self.logger.error(ppp("Rx:", rx))
+                self.logger.error(ppp("Tx:", tx))
+                raise
+
     def test_gre(self):
         """ GRE IPv4 tunnel Tests """
 
@@ -1002,6 +1024,17 @@ class TestGRE(VppTestCase):
             self.logger.info(self.vapi.cli("sh adj"))
             self.logger.info(self.vapi.cli("sh ip fib"))
 
+            #
+            # ensure we don't match to the tunnel if the source address
+            # is all zeros
+            #
+            tx = self.create_tunnel_stream_4o4(self.pg0,
+                                               "0.0.0.0",
+                                               itf.local_ip4,
+                                               self.pg0.local_ip4,
+                                               self.pg0.remote_ip4)
+            self.send_and_assert_no_replies(self.pg0, tx)
+
             #
             # for-each peer
             #
@@ -1029,23 +1062,34 @@ class TestGRE(VppTestCase):
                 # Send a packet stream that is routed into the tunnel
                 #  - packets are GRE encapped
                 #
-                tx = self.create_stream_ip4(self.pg0, "5.5.5.5", route_addr)
-                rx = self.send_and_expect(self.pg0, tx, itf)
-                self.verify_tunneled_4o4(self.pg0, rx, tx,
+                tx_e = self.create_stream_ip4(self.pg0, "5.5.5.5", route_addr)
+                rx = self.send_and_expect(self.pg0, tx_e, itf)
+                self.verify_tunneled_4o4(self.pg0, rx, tx_e,
                                          itf.local_ip4,
                                          gre_if._remote_hosts[ii].ip4)
 
+                tx_i = self.create_tunnel_stream_4o4(self.pg0,
+                                                     itf._remote_hosts[ii].ip4,
+                                                     itf.local_ip4,
+                                                     self.pg0.local_ip4,
+                                                     self.pg0.remote_ip4)
+                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
+                self.verify_decapped_4o4(self.pg0, rx, tx_i)
+
                 #
                 # delete and re-add the NHRP
                 #
                 nhrp.remove_vpp_config()
-                self.send_and_assert_no_replies(self.pg0, tx)
+                self.send_and_assert_no_replies(self.pg0, tx_e)
+                self.send_and_assert_no_replies(self.pg0, tx_i)
 
                 nhrp.add_vpp_config()
-                rx = self.send_and_expect(self.pg0, tx, itf)
-                self.verify_tunneled_4o4(self.pg0, rx, tx,
+                rx = self.send_and_expect(self.pg0, tx_e, itf)
+                self.verify_tunneled_4o4(self.pg0, rx, tx_e,
                                          itf.local_ip4,
                                          gre_if._remote_hosts[ii].ip4)
+                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
+                self.verify_decapped_4o4(self.pg0, rx, tx_i)
 
             gre_if.admin_down()
             gre_if.unconfig_ip4()
@@ -1053,7 +1097,8 @@ class TestGRE(VppTestCase):
     def test_mgre6(self):
         """ mGRE IPv6 tunnel Tests """
 
-        self.pg0.ip6_enable()
+        self.pg0.config_ip6()
+        self.pg0.resolve_ndp()
 
         for itf in self.pg_interfaces[3:]:
             #
@@ -1106,27 +1151,37 @@ class TestGRE(VppTestCase):
                 # Send a packet stream that is routed into the tunnel
                 #  - packets are GRE encapped
                 #
-                tx = self.create_stream_ip6(self.pg0, "5::5", route_addr)
-                rx = self.send_and_expect(self.pg0, tx, itf)
-                self.verify_tunneled_6o6(self.pg0, rx, tx,
+                tx_e = self.create_stream_ip6(self.pg0, "5::5", route_addr)
+                rx = self.send_and_expect(self.pg0, tx_e, itf)
+                self.verify_tunneled_6o6(self.pg0, rx, tx_e,
                                          itf.local_ip6,
                                          gre_if._remote_hosts[ii].ip6)
+                tx_i = self.create_tunnel_stream_6o6(self.pg0,
+                                                     itf._remote_hosts[ii].ip6,
+                                                     itf.local_ip6,
+                                                     self.pg0.local_ip6,
+                                                     self.pg0.remote_ip6)
+                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
+                self.verify_decapped_6o6(self.pg0, rx, tx_i)
 
                 #
                 # delete and re-add the NHRP
                 #
                 nhrp.remove_vpp_config()
-                self.send_and_assert_no_replies(self.pg0, tx)
+                self.send_and_assert_no_replies(self.pg0, tx_e)
 
                 nhrp.add_vpp_config()
-                rx = self.send_and_expect(self.pg0, tx, itf)
-                self.verify_tunneled_6o6(self.pg0, rx, tx,
+                rx = self.send_and_expect(self.pg0, tx_e, itf)
+                self.verify_tunneled_6o6(self.pg0, rx, tx_e,
                                          itf.local_ip6,
                                          gre_if._remote_hosts[ii].ip6)
+                rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
+                self.verify_decapped_6o6(self.pg0, rx, tx_i)
+
             gre_if.admin_down()
             gre_if.unconfig_ip4()
             itf.unconfig_ip6()
-        self.pg0.ip6_disable()
+        self.pg0.unconfig_ip6()
 
 
 if __name__ == '__main__':