ADJ: midchain delegate to performing stacking

this can be used by e.g. tunnels so it doesn't need to be
implemented for each tunnel type.

Change-Id: I0790f89aa49f83421612b35108cce67693285999
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt
index 822ad68..8e56ac3 100644
--- a/src/vnet/CMakeLists.txt
+++ b/src/vnet/CMakeLists.txt
@@ -1371,6 +1371,7 @@
   adj/adj_nbr.c
   adj/adj_glean.c
   adj/adj_midchain.c
+  adj/adj_midchain_delegate.c
   adj/adj_mcast.c
   adj/adj_l2.c
   adj/adj_nsh.c
diff --git a/src/vnet/adj/adj.c b/src/vnet/adj/adj.c
index 3ca3d60..9d18dbf 100644
--- a/src/vnet/adj/adj.c
+++ b/src/vnet/adj/adj.c
@@ -537,10 +537,32 @@
 adj_back_walk_notify (fib_node_t *node,
 		      fib_node_back_walk_ctx_t *ctx)
 {
-    /*
-     * Que pasa. yo soj en el final!
-     */
-    ASSERT(0);
+    ip_adjacency_t *adj;
+
+    adj = ADJ_FROM_NODE(node);
+
+    switch (adj->lookup_next_index)
+    {
+    case IP_LOOKUP_NEXT_MIDCHAIN:
+        adj_midchain_delegate_restack(adj_get_index(adj));
+        break;
+    case IP_LOOKUP_NEXT_ARP:
+    case IP_LOOKUP_NEXT_REWRITE:
+    case IP_LOOKUP_NEXT_BCAST:
+    case IP_LOOKUP_NEXT_GLEAN:
+    case IP_LOOKUP_NEXT_MCAST:
+    case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
+    case IP_LOOKUP_NEXT_DROP:
+    case IP_LOOKUP_NEXT_PUNT:
+    case IP_LOOKUP_NEXT_LOCAL:
+    case IP_LOOKUP_NEXT_ICMP_ERROR:
+    case IP_LOOKUP_N_NEXT:
+        /*
+         * Que pasa. yo soj en el final!
+         */
+        ASSERT(0);
+        break;
+    }
 
     return (FIB_NODE_BACK_WALK_CONTINUE);
 }
diff --git a/src/vnet/adj/adj_delegate.c b/src/vnet/adj/adj_delegate.c
index 15dcb02..cd5301c 100644
--- a/src/vnet/adj/adj_delegate.c
+++ b/src/vnet/adj/adj_delegate.c
@@ -25,7 +25,7 @@
 /**
  * The value of the last dynamically allocated delegeate value
  */
-static adj_delegate_type_t ad_max_id = ADJ_DELEGATE_BFD;
+static adj_delegate_type_t ad_max_id = ADJ_DELEGATE_LAST;
 
 static adj_delegate_t *
 adj_delegate_find_i (const ip_adjacency_t *adj,
diff --git a/src/vnet/adj/adj_delegate.h b/src/vnet/adj/adj_delegate.h
index 13bf911..f6da245 100644
--- a/src/vnet/adj/adj_delegate.h
+++ b/src/vnet/adj/adj_delegate.h
@@ -36,8 +36,14 @@
      * BFD session state
      */
     ADJ_DELEGATE_BFD,
+    /**
+     * Stacking of a midchain's nexthop
+     */
+    ADJ_DELEGATE_MIDCHAIN,
 } adj_delegate_type_t;
 
+#define ADJ_DELEGATE_LAST (ADJ_DELEGATE_MIDCHAIN)
+
 /**
  * Adj delegate. This object is attached to the adjacency.
  */
diff --git a/src/vnet/adj/adj_midchain.h b/src/vnet/adj/adj_midchain.h
index 24fea42..1f5deae 100644
--- a/src/vnet/adj/adj_midchain.h
+++ b/src/vnet/adj/adj_midchain.h
@@ -118,4 +118,25 @@
  */
 extern u8* format_adj_midchain(u8* s, va_list *ap);
 
+/**
+ * @brief
+ *  create/attach a midchain delegate and stack it on the prefix passed
+ * @param ai - the index of the adjacency to stack
+ * @param fib_index - The FIB index of the prefix on which to stack
+ * @param pfx - The prefix on which to stack
+ */
+extern void adj_midchain_delegate_stack(adj_index_t ai,
+                                        u32 fib_index,
+                                        const fib_prefix_t *pfx);
+
+/**
+ * @brief restack a midchain delegate
+ */
+extern void adj_midchain_delegate_restack(adj_index_t ai);
+
+/**
+ * @brief unstack a midchain delegate (this stacks it on a drop)
+ */
+extern void adj_midchain_delegate_unstack(adj_index_t ai);
+
 #endif
diff --git a/src/vnet/adj/adj_midchain_delegate.c b/src/vnet/adj/adj_midchain_delegate.c
new file mode 100644
index 0000000..922283e
--- /dev/null
+++ b/src/vnet/adj/adj_midchain_delegate.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016 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/adj/adj_delegate.h>
+#include <vnet/adj/adj_midchain.h>
+#include <vnet/fib/fib_table.h>
+
+/**
+ * Midchain stacker delegate
+ */
+typedef struct adj_midchain_delegate_t_
+{
+    /**
+     * the Fib Entry we are stacked on
+     */
+    fib_node_index_t amd_fei;
+
+    /**
+     * The sibling entry on the FIB entry
+     */
+    u32 amd_sibling;
+} adj_midchain_delegate_t;
+
+/**
+ * Pool of delegates
+ */
+static adj_midchain_delegate_t *amd_pool;
+
+static inline const adj_midchain_delegate_t*
+adj_midchain_from_const_base (const adj_delegate_t *ad)
+{
+    if (NULL != ad)
+    {
+        return (pool_elt_at_index(amd_pool, ad->ad_index));
+    }
+    return (NULL);
+}
+
+static void
+adj_midchain_delegate_restack_i (adj_index_t ai,
+                                 adj_midchain_delegate_t *amd)
+{
+    if (vnet_sw_interface_is_admin_up (vnet_get_main (),
+                                       adj_get_sw_if_index(ai)) &&
+        (FIB_NODE_INDEX_INVALID != amd->amd_fei))
+    {
+        const fib_prefix_t *pfx;
+
+        pfx = fib_entry_get_prefix(amd->amd_fei);
+
+        adj_nbr_midchain_stack_on_fib_entry (
+            ai,
+            amd->amd_fei,
+            fib_forw_chain_type_from_fib_proto(pfx->fp_proto));
+    }
+    else
+    {
+        adj_nbr_midchain_unstack (ai);
+    }
+}
+
+void
+adj_midchain_delegate_restack (adj_index_t ai)
+{
+    adj_midchain_delegate_t *amd;
+    ip_adjacency_t *adj;
+    adj_delegate_t *ad;
+
+    /*
+     * if there's a delegate already use that
+     */
+    adj = adj_get(ai);
+    ad = adj_delegate_get(adj, ADJ_DELEGATE_MIDCHAIN);
+
+    if (NULL != ad)
+    {
+        amd = pool_elt_at_index(amd_pool, ad->ad_index);
+
+        adj_midchain_delegate_restack_i(ai, amd);
+    }
+    /*
+     * else
+     *  nothing to stack
+     */
+}
+
+void
+adj_midchain_delegate_stack (adj_index_t ai,
+                             u32 fib_index,
+                             const fib_prefix_t *pfx)
+{
+    adj_midchain_delegate_t *amd;
+    ip_adjacency_t *adj;
+    adj_delegate_t *ad;
+
+    /*
+     * if there's a delegate already use that
+     */
+    adj = adj_get(ai);
+    ad = adj_delegate_get(adj, ADJ_DELEGATE_MIDCHAIN);
+
+    if (NULL != ad)
+    {
+        amd = pool_elt_at_index(amd_pool, ad->ad_index);
+    }
+    else
+    {
+        pool_get(amd_pool, amd);
+        amd->amd_fei = FIB_NODE_INDEX_INVALID;
+        adj_delegate_add(adj, ADJ_DELEGATE_MIDCHAIN, amd - amd_pool);
+
+        amd->amd_fei = fib_table_entry_special_add(fib_index,
+                                                   pfx,
+                                                   FIB_SOURCE_RR,
+                                                   FIB_ENTRY_FLAG_NONE);
+        amd->amd_sibling = fib_entry_child_add(amd->amd_fei,
+                                               FIB_NODE_TYPE_ADJ,
+                                               ai);
+    }
+    adj_midchain_delegate_restack_i(ai, amd);
+}
+
+void
+adj_midchain_delegate_unstack (adj_index_t ai)
+{
+    adj_nbr_midchain_unstack(ai);
+}
+
+static void
+adj_midchain_delegate_adj_deleted (adj_delegate_t *ad)
+{
+    adj_midchain_delegate_t *amd;
+
+    amd = pool_elt_at_index(amd_pool, ad->ad_index);
+
+    fib_entry_child_remove (amd->amd_fei, amd->amd_sibling);
+    fib_table_entry_delete_index (amd->amd_fei, FIB_SOURCE_RR);
+
+    pool_put(amd_pool, amd);
+}
+
+/**
+ * Print a delegate that represents MIDCHAIN tracking
+ */
+static u8 *
+adj_midchain_delegate_fmt (const adj_delegate_t *aed, u8 *s)
+{
+    const adj_midchain_delegate_t *amd = adj_midchain_from_const_base(aed);
+
+    s = format(s, "MIDCHAIN:[fib-entry:%d]", amd->amd_fei);
+
+    return (s);
+}
+
+const static adj_delegate_vft_t adj_delegate_vft = {
+  .adv_format = adj_midchain_delegate_fmt,
+  .adv_adj_deleted = adj_midchain_delegate_adj_deleted,
+};
+
+static clib_error_t *
+adj_midchain_delegate_module_init (vlib_main_t * vm)
+{
+    clib_error_t * error = NULL;
+
+    adj_delegate_register_type (ADJ_DELEGATE_MIDCHAIN, &adj_delegate_vft);
+
+    return (error);
+}
+
+VLIB_INIT_FUNCTION (adj_midchain_delegate_module_init);
+
diff --git a/src/vnet/fib/fib_node.h b/src/vnet/fib/fib_node.h
index e9c45c5..de366f2 100644
--- a/src/vnet/fib/fib_node.h
+++ b/src/vnet/fib/fib_node.h
@@ -39,7 +39,6 @@
     FIB_NODE_TYPE_MPLS_TUNNEL,
     FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY,
     FIB_NODE_TYPE_LISP_ADJ,
-    FIB_NODE_TYPE_GRE_TUNNEL,
     FIB_NODE_TYPE_VXLAN_TUNNEL,
     FIB_NODE_TYPE_MAP_E,
     FIB_NODE_TYPE_VXLAN_GPE_TUNNEL,
@@ -69,7 +68,6 @@
     [FIB_NODE_TYPE_ADJ] = "adj",				\
     [FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY] = "lisp-gpe-fwd-entry",	\
     [FIB_NODE_TYPE_LISP_ADJ] = "lisp-adj",			\
-    [FIB_NODE_TYPE_GRE_TUNNEL] = "gre-tunnel",			\
     [FIB_NODE_TYPE_VXLAN_TUNNEL] = "vxlan-tunnel",		\
     [FIB_NODE_TYPE_MAP_E] = "map-e",				\
     [FIB_NODE_TYPE_VXLAN_GPE_TUNNEL] = "vxlan-gpe-tunnel",	\
diff --git a/src/vnet/gre/gre.h b/src/vnet/gre/gre.h
index 416ab30..a1a03df 100644
--- a/src/vnet/gre/gre.h
+++ b/src/vnet/gre/gre.h
@@ -181,11 +181,6 @@
   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
 
   /**
-   * Linkage into the FIB object graph
-   */
-  fib_node_t node;
-
-  /**
    * The hash table's key stored in separate memory since the tunnel_t
    * memory can realloc.
    */
@@ -208,19 +203,6 @@
   gre_tunnel_type_t type;
 
   /**
-   * The FIB entry sourced by the tunnel for its destination prefix
-   */
-  fib_node_index_t fib_entry_index;
-
-  /**
-   * The tunnel is a child of the FIB entry for its desintion. This is
-   * so it receives updates when the forwarding information for that entry
-   * changes.
-   * The tunnels sibling index on the FIB entry's dependency list.
-   */
-  u32 sibling_index;
-
-  /**
    * an L2 tunnel always rquires an L2 midchain. cache here for DP.
    */
   adj_index_t l2_adj_index;
diff --git a/src/vnet/gre/interface.c b/src/vnet/gre/interface.c
index b9bfb79..4f5f528 100644
--- a/src/vnet/gre/interface.c
+++ b/src/vnet/gre/interface.c
@@ -112,14 +112,6 @@
   t->key = NULL;
 }
 
-static gre_tunnel_t *
-gre_tunnel_from_fib_node (fib_node_t * node)
-{
-  ASSERT (FIB_NODE_TYPE_GRE_TUNNEL == node->fn_type);
-  return ((gre_tunnel_t *) (((char *) node) -
-			    STRUCT_OFFSET_OF (gre_tunnel_t, node)));
-}
-
 /**
  * gre_tunnel_stack
  *
@@ -146,14 +138,11 @@
   if ((vnet_hw_interface_get_flags (vnet_get_main (), gt->hw_if_index) &
        VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
     {
-      adj_nbr_midchain_unstack (ai);
+      adj_midchain_delegate_unstack (ai);
     }
   else
     {
-      adj_nbr_midchain_stack_on_fib_entry (ai,
-					   gt->fib_entry_index,
-					   fib_forw_chain_type_from_fib_proto
-					   (gt->tunnel_dst.fp_proto));
+      adj_midchain_delegate_stack (ai, gt->outer_fib_index, &gt->tunnel_dst);
     }
 }
 
@@ -182,55 +171,6 @@
   }
 }
 
-/**
- * Function definition to backwalk a FIB node
- */
-static fib_node_back_walk_rc_t
-gre_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
-{
-  gre_tunnel_restack (gre_tunnel_from_fib_node (node));
-
-  return (FIB_NODE_BACK_WALK_CONTINUE);
-}
-
-/**
- * Function definition to get a FIB node from its index
- */
-static fib_node_t *
-gre_tunnel_fib_node_get (fib_node_index_t index)
-{
-  gre_tunnel_t *gt;
-  gre_main_t *gm;
-
-  gm = &gre_main;
-  gt = pool_elt_at_index (gm->tunnels, index);
-
-  return (&gt->node);
-}
-
-/**
- * Function definition to inform the FIB node that its last lock has gone.
- */
-static void
-gre_tunnel_last_lock_gone (fib_node_t * node)
-{
-  /*
-   * The MPLS GRE tunnel is a root of the graph. As such
-   * it never has children and thus is never locked.
-   */
-  ASSERT (0);
-}
-
-/*
- * Virtual function table registered by MPLS GRE tunnels
- * for participation in the FIB object graph.
- */
-const static fib_node_vft_t gre_vft = {
-  .fnv_get = gre_tunnel_fib_node_get,
-  .fnv_last_lock = gre_tunnel_last_lock_gone,
-  .fnv_back_walk = gre_tunnel_back_walk,
-};
-
 static int
 vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t * a,
 		     u32 outer_fib_index, u32 * sw_if_indexp)
@@ -267,7 +207,6 @@
 
   t->dev_instance = t_idx;	/* actual */
   t->user_instance = u_idx;	/* name */
-  fib_node_init (&t->node, FIB_NODE_TYPE_GRE_TUNNEL);
 
   t->type = a->tunnel_type;
   if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
@@ -357,11 +296,6 @@
 	}
     }
 
-  t->fib_entry_index = fib_table_entry_special_add
-    (outer_fib_index, &t->tunnel_dst, FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE);
-  t->sibling_index = fib_entry_child_add
-    (t->fib_entry_index, FIB_NODE_TYPE_GRE_TUNNEL, t_idx);
-
   if (t->type != GRE_TUNNEL_TYPE_L3)
     {
       t->l2_adj_index = adj_nbr_add_or_lock
@@ -403,10 +337,10 @@
     ethernet_delete_interface (vnm, t->hw_if_index);
 
   if (t->l2_adj_index != ADJ_INDEX_INVALID)
-    adj_unlock (t->l2_adj_index);
-
-  fib_entry_child_remove (t->fib_entry_index, t->sibling_index);
-  fib_table_entry_delete_index (t->fib_entry_index, FIB_SOURCE_RR);
+    {
+      adj_midchain_delegate_unstack (t->l2_adj_index);
+      adj_unlock (t->l2_adj_index);
+    }
 
   ASSERT ((t->type != GRE_TUNNEL_TYPE_ERSPAN) || (t->gre_sn != NULL));
   if ((t->type == GRE_TUNNEL_TYPE_ERSPAN) && (t->gre_sn->ref_count-- == 1))
@@ -419,7 +353,6 @@
 
   hash_unset (gm->instance_used, t->user_instance);
   gre_tunnel_db_remove (t);
-  fib_node_deinit (&t->node);
   pool_put (gm->tunnels, t);
 
   if (sw_if_indexp)
@@ -690,9 +623,7 @@
 clib_error_t *
 gre_interface_init (vlib_main_t * vm)
 {
-  fib_node_register_type (FIB_NODE_TYPE_GRE_TUNNEL, &gre_vft);
-
-  return 0;
+  return (NULL);
 }
 
 VLIB_INIT_FUNCTION (gre_interface_init);
diff --git a/src/vnet/ipip/ipip.c b/src/vnet/ipip/ipip.c
index a5e46c4..5d40708 100644
--- a/src/vnet/ipip/ipip.c
+++ b/src/vnet/ipip/ipip.c
@@ -20,6 +20,7 @@
 #include <vnet/ipip/ipip.h>
 #include <vnet/vnet.h>
 #include <vnet/adj/adj_nbr.h>
+#include <vnet/adj/adj_midchain.h>
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/fib/ip6_fib.h>
 #include <vnet/ip/format.h>
@@ -185,15 +186,21 @@
   if ((vnet_hw_interface_get_flags (vnet_get_main (), t->hw_if_index) &
        VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
     {
-      adj_nbr_midchain_unstack (ai);
+      adj_midchain_delegate_unstack (ai);
     }
   else
     {
-      adj_nbr_midchain_stack_on_fib_entry
-	(ai,
-	 t->p2p.fib_entry_index,
-	 (t->transport == IPIP_TRANSPORT_IP6) ?
-	 FIB_FORW_CHAIN_TYPE_UNICAST_IP6 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
+      /* *INDENT-OFF* */
+      fib_prefix_t dst = {
+        .fp_len = t->transport == IPIP_TRANSPORT_IP6 ? 128 : 32,
+        .fp_proto = (t->transport == IPIP_TRANSPORT_IP6 ?
+                     FIB_PROTOCOL_IP6 :
+                     FIB_PROTOCOL_IP4),
+        .fp_addr = t->tunnel_dst
+      };
+      /* *INDENT-ON* */
+
+      adj_midchain_delegate_stack (ai, t->fib_index, &dst);
     }
 }
 
@@ -356,82 +363,6 @@
   t->key = NULL;
 }
 
-static ipip_tunnel_t *
-ipip_tunnel_from_fib_node (fib_node_t * node)
-{
-  ipip_main_t *gm = &ipip_main;
-  ASSERT (gm->fib_node_type == node->fn_type);
-  return ((ipip_tunnel_t *) (((char *) node) -
-			     offsetof (ipip_tunnel_t, p2p.node)));
-}
-
-static fib_node_back_walk_rc_t
-ipip_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
-{
-  ipip_tunnel_restack (ipip_tunnel_from_fib_node (node));
-
-  return (FIB_NODE_BACK_WALK_CONTINUE);
-}
-
-static fib_node_t *
-ipip_tunnel_fib_node_get (fib_node_index_t index)
-{
-  ipip_tunnel_t *gt;
-  ipip_main_t *gm;
-
-  gm = &ipip_main;
-  gt = pool_elt_at_index (gm->tunnels, index);
-
-  return (&gt->p2p.node);
-}
-
-static void
-ipip_tunnel_last_lock_gone (fib_node_t * node)
-{
-  /*
-   * The MPLS IPIP tunnel is a root of the graph. As such
-   * it never has children and thus is never locked.
-   */
-  ASSERT (0);
-}
-
-/*
- * Virtual function table registered by IPIP tunnels
- * for participation in the FIB object graph.
- */
-const static fib_node_vft_t ipip_vft = {
-  .fnv_get = ipip_tunnel_fib_node_get,
-  .fnv_last_lock = ipip_tunnel_last_lock_gone,
-  .fnv_back_walk = ipip_tunnel_back_walk,
-};
-
-static void
-ipip_fib_add (ipip_tunnel_t * t)
-{
-  ipip_main_t *gm = &ipip_main;
-  fib_prefix_t dst = {.fp_len = t->transport == IPIP_TRANSPORT_IP6 ? 128 : 32,
-    .fp_proto =
-      t->transport ==
-      IPIP_TRANSPORT_IP6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4,
-    .fp_addr = t->tunnel_dst
-  };
-
-  t->p2p.fib_entry_index =
-    fib_table_entry_special_add (t->fib_index, &dst, FIB_SOURCE_RR,
-				 FIB_ENTRY_FLAG_NONE);
-  t->p2p.sibling_index =
-    fib_entry_child_add (t->p2p.fib_entry_index, gm->fib_node_type,
-			 t->dev_instance);
-}
-
-static void
-ipip_fib_delete (ipip_tunnel_t * t)
-{
-  fib_entry_child_remove (t->p2p.fib_entry_index, t->p2p.sibling_index);
-  fib_table_entry_delete_index (t->p2p.fib_entry_index, FIB_SOURCE_RR);
-  fib_node_deinit (&t->p2p.node);
-}
-
 int
 ipip_add_tunnel (ipip_transport_t transport,
 		 u32 instance, ip46_address_t * src, ip46_address_t * dst,
@@ -470,7 +401,6 @@
 
   t->dev_instance = t_idx;	/* actual */
   t->user_instance = u_idx;	/* name */
-  fib_node_init (&t->p2p.node, gm->fib_node_type);
 
   hw_if_index = vnet_register_interface (vnm, ipip_device_class.index, t_idx,
 					 ipip_hw_interface_class.index,
@@ -507,12 +437,6 @@
 
   ipip_tunnel_db_add (t, &key);
 
-  /*
-   * Source the FIB entry for the tunnel's destination and become a
-   * child thereof. The tunnel will then get poked when the forwarding
-   * for the entry updates, and the tunnel can re-stack accordingly
-   */
-  ipip_fib_add (t);
   if (sw_if_indexp)
     *sw_if_indexp = sw_if_index;
 
@@ -546,7 +470,6 @@
   vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
   gm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
   vnet_delete_hw_interface (vnm, t->hw_if_index);
-  ipip_fib_delete (t);
   hash_unset (gm->instance_used, t->user_instance);
   ipip_tunnel_db_remove (t);
   pool_put (gm->tunnels, t);
@@ -564,7 +487,6 @@
   gm->vnet_main = vnet_get_main ();
   gm->tunnel_by_key =
     hash_create_mem (0, sizeof (ipip_tunnel_key_t), sizeof (uword));
-  gm->fib_node_type = fib_node_register_new_type (&ipip_vft);
 
   return 0;
 }
diff --git a/src/vnet/ipip/ipip.h b/src/vnet/ipip/ipip.h
index 93930aa..7eecebb 100644
--- a/src/vnet/ipip/ipip.h
+++ b/src/vnet/ipip/ipip.h
@@ -84,25 +84,16 @@
   u32 user_instance;		/* Instance name being shown to user */
   u8 tc_tos;
 
-  union
+  struct
   {
-    struct
-    {
-      fib_node_t node;
-      fib_node_index_t fib_entry_index;
-      u32 sibling_index;
-    } p2p;
-    struct
-    {
-      ip6_address_t ip6_prefix;
-      ip4_address_t ip4_prefix;
-      u8 ip6_prefix_len;
-      u8 ip4_prefix_len;
-      u8 shift;
-      bool security_check;
-      u32 ip6_fib_index;
-    } sixrd;
-  };
+    ip6_address_t ip6_prefix;
+    ip4_address_t ip4_prefix;
+    u8 ip6_prefix_len;
+    u8 ip4_prefix_len;
+    u8 shift;
+    bool security_check;
+    u32 ip6_fib_index;
+  } sixrd;
 } ipip_tunnel_t;
 
 typedef struct
@@ -110,7 +101,6 @@
   ipip_tunnel_t *tunnels;
   uword *tunnel_by_key;
   u32 *tunnel_index_by_sw_if_index;
-  fib_node_type_t fib_node_type;
 
   /* convenience */
   vlib_main_t *vlib_main;