fib: contention with DP on deleting a route
[vpp.git] / src / vnet / fib / fib_entry_src.c
index cd4e470..c79b745 100644 (file)
 #include <vnet/fib/fib_table.h>
 #include <vnet/fib/fib_path_ext.h>
 #include <vnet/fib/fib_urpf_list.h>
+#include <vnet/fib/fib_entry_delegate.h>
 
 /*
  * per-source type vft
  */
-static fib_entry_src_vft_t fib_entry_src_vft[FIB_SOURCE_MAX];
+static fib_entry_src_vft_t fib_entry_src_bh_vft[FIB_SOURCE_BH_MAX];
 
 /**
  * Get the VFT for a given source. This is a combination of the source
@@ -36,12 +37,17 @@ static fib_entry_src_vft_t fib_entry_src_vft[FIB_SOURCE_MAX];
 const fib_entry_src_vft_t*
 fib_entry_src_get_vft (const fib_entry_src_t *esrc)
 {
+    fib_source_behaviour_t bh;
+
+    bh = fib_source_get_behaviour(esrc->fes_src);
+
     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_INTERPOSE)
     {
-        return (&fib_entry_src_vft[FIB_SOURCE_INTERPOSE]);
+        return (&fib_entry_src_bh_vft[FIB_SOURCE_BH_INTERPOSE]);
     }
 
-    return (&fib_entry_src_vft[esrc->fes_src]);
+    ASSERT(bh < FIB_SOURCE_BH_MAX);
+    return (&fib_entry_src_bh_vft[bh]);
 }
 
 static void
@@ -53,14 +59,14 @@ fib_entry_src_copy_default (const fib_entry_src_t *orig_src,
 }
 
 void
-fib_entry_src_register (fib_source_t source,
-                       const fib_entry_src_vft_t *vft)
+fib_entry_src_behaviour_register (fib_source_behaviour_t bh,
+                                  const fib_entry_src_vft_t *vft)
 {
-    fib_entry_src_vft[source] = *vft;
+    fib_entry_src_bh_vft[bh] = *vft;
 
-    if (NULL == fib_entry_src_vft[source].fesv_copy)
+    if (NULL == fib_entry_src_bh_vft[bh].fesv_copy)
     {
-        fib_entry_src_vft[source].fesv_copy = fib_entry_src_copy_default;
+        fib_entry_src_bh_vft[bh].fesv_copy = fib_entry_src_copy_default;
     }
 }
 
@@ -70,7 +76,8 @@ fib_entry_src_cmp_for_sort (void * v1,
 {
     fib_entry_src_t *esrc1 = v1, *esrc2 = v2;
 
-    return (esrc1->fes_src - esrc2->fes_src);
+    return (fib_source_get_prio(esrc1->fes_src) -
+            fib_source_get_prio(esrc2->fes_src));
 }
 
 static void
@@ -85,7 +92,7 @@ fib_entry_src_action_init (fib_entry_t *fib_entry,
         .fes_entry_flags = flags,
     };
 
-    FIB_ENTRY_SRC_VFT_INVOKE(&esrc, fesv_init, (&esrc));
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, &esrc, fesv_init, (&esrc));
 
     vec_add1(fib_entry->fe_srcs, esrc);
     vec_sort_with_function(fib_entry->fe_srcs,
@@ -121,7 +128,7 @@ fib_entry_src_find_i (const fib_entry_t *fib_entry,
     return (NULL);
 }
 
-static fib_entry_src_t *
+fib_entry_src_t *
 fib_entry_src_find (const fib_entry_t *fib_entry,
                    fib_source_t source)
 
@@ -140,6 +147,44 @@ fib_entry_is_sourced (fib_node_index_t fib_entry_index,
     return (NULL != fib_entry_src_find(fib_entry, source));
 }
 
+int
+fib_entry_is_marked (fib_node_index_t fib_entry_index,
+                      fib_source_t source)
+{
+    fib_entry_t *fib_entry;
+    fib_entry_src_t *esrc;
+
+    fib_entry = fib_entry_get(fib_entry_index);
+
+    esrc = fib_entry_src_find(fib_entry, source);
+
+    if (NULL == esrc)
+    {
+        return (0);
+    }
+    else
+    {
+        return (!!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_STALE));
+    }
+}
+
+void
+fib_entry_mark (fib_node_index_t fib_entry_index,
+                fib_source_t source)
+{
+    fib_entry_t *fib_entry;
+    fib_entry_src_t *esrc;
+
+    fib_entry = fib_entry_get(fib_entry_index);
+
+    esrc = fib_entry_src_find(fib_entry, source);
+
+    if (NULL != esrc)
+    {
+        esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_STALE;
+    }
+}
+
 static fib_entry_src_t *
 fib_entry_src_find_or_create (fib_entry_t *fib_entry,
                              fib_source_t source,
@@ -169,7 +214,7 @@ fib_entry_src_action_deinit (fib_entry_t *fib_entry,
 
     ASSERT(NULL != esrc);
 
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_deinit, (esrc));
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deinit, (esrc));
 
     fib_path_ext_list_flush(&esrc->fes_path_exts);
     vec_del1(fib_entry->fe_srcs, index);
@@ -209,25 +254,27 @@ typedef struct fib_entry_src_collect_forwarding_ctx_t_
 {
     load_balance_path_t *next_hops;
     const fib_entry_t *fib_entry;
-    const fib_entry_src_t *esrc;
+    i32 start_source_index, end_source_index;
     fib_forward_chain_type_t fct;
     int n_recursive_constrained;
     u16 preference;
+    dpo_proto_t payload_proto;
 } fib_entry_src_collect_forwarding_ctx_t;
 
 /**
  * @brief Determine whether this FIB entry should use a load-balance MAP
  * to support PIC edge fast convergence
  */
-load_balance_flags_t
-fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx)
+static load_balance_flags_t
+fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx,
+                         const fib_entry_src_t *esrc)
 {
     /**
      * We'll use a LB map if the path-list has multiple recursive paths.
      * recursive paths implies BGP, and hence scale.
      */
     if (ctx->n_recursive_constrained > 1 &&
-        fib_path_list_is_popular(ctx->esrc->fes_pl))
+        fib_path_list_is_popular(esrc->fes_pl))
     {
         return (LOAD_BALANCE_FLAG_USES_MAP);
     }
@@ -244,47 +291,6 @@ fib_entry_src_valid_out_label (mpls_label_t label)
              MPLS_IETF_IMPLICIT_NULL_LABEL == label));
 }
 
-/**
- * @brief Turn the chain type requested by the client into the one they
- * really wanted
- */
-fib_forward_chain_type_t
-fib_entry_chain_type_fixup (const fib_entry_t *entry,
-                           fib_forward_chain_type_t fct)
-{
-    /*
-     * The EOS chain is a tricky since one cannot know the adjacency
-     * to link to without knowing what the packets payload protocol
-     * will be once the label is popped.
-     */
-    fib_forward_chain_type_t dfct;
-
-    if (FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct)
-    {
-        return (fct);
-    }
-
-    dfct = fib_entry_get_default_chain_type(entry);
-
-    if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
-    {
-        /*
-         * If the entry being asked is a eos-MPLS label entry,
-         * then use the payload-protocol field, that we stashed there
-         * for just this purpose
-         */
-        return (fib_forw_chain_type_from_dpo_proto(
-                    entry->fe_prefix.fp_payload_proto));
-    }
-    /*
-     * else give them what this entry would be by default. i.e. if it's a v6
-     * entry, then the label its local labelled should be carrying v6 traffic.
-     * If it's a non-EOS label entry, then there are more labels and we want
-     * a non-eos chain.
-     */
-    return (dfct);
-}
-
 static dpo_proto_t
 fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
 {
@@ -326,7 +332,8 @@ fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
 
         nh->path_index = path_index;
         nh->path_weight = fib_path_get_weight(path_index);
-        fib_path_contribute_forwarding(path_index, ctx->fct, &nh->path_dpo);
+        fib_path_contribute_forwarding(path_index, ctx->fct,
+                                       ctx->payload_proto, &nh->path_dpo);
 
         break;
     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
@@ -339,6 +346,7 @@ fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
             nh->path_weight = fib_path_get_weight(path_index);
             fib_path_contribute_forwarding(path_index,
                                            FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
+                                           ctx->payload_proto,
                                            &nh->path_dpo);
         }
         break;
@@ -352,11 +360,11 @@ fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
             nh->path_index = path_index;
             nh->path_weight = fib_path_get_weight(path_index);
             fib_path_contribute_forwarding(path_index,
-                                           fib_entry_chain_type_fixup(ctx->fib_entry,
-                                                                      ctx->fct),
+                                           ctx->fct,
+                                           ctx->payload_proto,
                                            &nh->path_dpo);
             fib_path_stack_mpls_disp(path_index,
-                                     fib_prefix_get_payload_proto(&ctx->fib_entry->fe_prefix),
+                                     ctx->payload_proto,
                                      FIB_MPLS_LSP_MODE_PIPE,
                                      &nh->path_dpo);
 
@@ -375,12 +383,18 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
                                   void *arg)
 {
     fib_entry_src_collect_forwarding_ctx_t *ctx;
+    const fib_entry_src_t *esrc;
     fib_path_ext_t *path_ext;
     u32 n_nhs;
 
     ctx = arg;
     n_nhs = vec_len(ctx->next_hops);
 
+    /*
+     * walk the paths and extension of the best non-interpose source
+     */
+    esrc = &ctx->fib_entry->fe_srcs[ctx->end_source_index];
+
     /*
      * if the path is not resolved, don't include it.
      */
@@ -413,7 +427,7 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
     /*
      * get the matching path-extension for the path being visited.
      */
-    path_ext = fib_path_ext_list_find_by_path_index(&ctx->esrc->fes_path_exts,
+    path_ext = fib_path_ext_list_find_by_path_index(&esrc->fes_path_exts,
                                                     path_index);
 
     if (NULL != path_ext)
@@ -429,9 +443,8 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
                  */
                 ctx->next_hops =
                     fib_path_ext_stack(path_ext,
+                                       ctx->payload_proto,
                                        ctx->fct,
-                                       fib_entry_chain_type_fixup(ctx->fib_entry,
-                                                                  ctx->fct),
                                        ctx->next_hops);
             }
             else
@@ -470,14 +483,26 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
          */
         const fib_entry_src_vft_t *vft;
 
-        vft = fib_entry_src_get_vft(ctx->esrc);
+        /*
+         * roll up the sources that are interposes
+         */
+        i32 index;
 
-        if (NULL != vft->fesv_contribute_interpose)
+        for (index = ctx->end_source_index;
+             index >= ctx->start_source_index;
+             index--)
         {
             const dpo_id_t *interposer;
 
-            interposer = vft->fesv_contribute_interpose(ctx->esrc,
-                                                        ctx->fib_entry);
+            esrc = &ctx->fib_entry->fe_srcs[index];
+            vft = fib_entry_src_get_vft(esrc);
+
+            if (!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_CONTRIBUTING) ||
+                !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_INTERPOSE))
+                continue;
+
+            ASSERT(vft->fesv_contribute_interpose);
+            interposer = vft->fesv_contribute_interpose(esrc, ctx->fib_entry);
 
             if (NULL != interposer)
             {
@@ -498,11 +523,40 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
 
 void
 fib_entry_src_mk_lb (fib_entry_t *fib_entry,
-                    const fib_entry_src_t *esrc,
+                     fib_source_t source,
                     fib_forward_chain_type_t fct,
                     dpo_id_t *dpo_lb)
 {
+    const fib_entry_src_t *esrc;
     dpo_proto_t lb_proto;
+    u32 start, end;
+
+    /*
+     * The source passed here is the 'best', i.e. the one the client
+     * wants. however, if it's an interpose then it does not contribute
+     * the forwarding, the next best source that is not an interpose does.
+     * So roll down the sources, to find the best non-interpose
+     */
+    vec_foreach_index (start, fib_entry->fe_srcs)
+    {
+        if (source == fib_entry->fe_srcs[start].fes_src)
+            break;
+    }
+    for (end = start; end < vec_len (fib_entry->fe_srcs); end++)
+    {
+        if (!(fib_entry->fe_srcs[end].fes_entry_flags &
+              FIB_ENTRY_FLAG_INTERPOSE) &&
+            (fib_entry->fe_srcs[end].fes_flags &
+             FIB_ENTRY_SRC_FLAG_CONTRIBUTING))
+            break;
+    }
+    if (end == vec_len(fib_entry->fe_srcs))
+    {
+        /* didn't find any contributing non-interpose sources */
+        end = start;
+    }
+
+    esrc = &fib_entry->fe_srcs[end];
 
     /*
      * If the entry has path extensions then we construct a load-balance
@@ -510,12 +564,14 @@ fib_entry_src_mk_lb (fib_entry_t *fib_entry,
      * Otherwise we use the load-balance of the path-list
      */
     fib_entry_src_collect_forwarding_ctx_t ctx = {
-        .esrc = esrc,
         .fib_entry = fib_entry,
         .next_hops = NULL,
         .n_recursive_constrained = 0,
         .fct = fct,
         .preference = 0xffff,
+        .start_source_index = start,
+        .end_source_index = end,
+        .payload_proto = fib_prefix_get_payload_proto(&fib_entry->fe_prefix),
     };
 
     /*
@@ -600,7 +656,7 @@ fib_entry_src_mk_lb (fib_entry_t *fib_entry,
     {
         load_balance_multipath_update(dpo_lb,
                                       ctx.next_hops,
-                                      fib_entry_calc_lb_flags(&ctx));
+                                      fib_entry_calc_lb_flags(&ctx, esrc));
         vec_free(ctx.next_hops);
 
         /*
@@ -644,11 +700,9 @@ fib_entry_src_action_install (fib_entry_t *fib_entry,
      * tables
      */
     fib_forward_chain_type_t fct;
-    fib_entry_src_t *esrc;
     int insert;
 
     fct = fib_entry_get_default_chain_type(fib_entry);
-    esrc = fib_entry_src_find(fib_entry, source);
 
     /*
      * Every entry has its own load-balance object. All changes to the entry's
@@ -658,7 +712,7 @@ fib_entry_src_action_install (fib_entry_t *fib_entry,
      */
     insert = !dpo_id_is_valid(&fib_entry->fe_lb);
 
-    fib_entry_src_mk_lb(fib_entry, esrc, fct, &fib_entry->fe_lb);
+    fib_entry_src_mk_lb(fib_entry, source, fct, &fib_entry->fe_lb);
 
     ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
     FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
@@ -682,7 +736,7 @@ fib_entry_src_action_install (fib_entry_t *fib_entry,
 
     FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
     {
-        fib_entry_src_mk_lb(fib_entry, esrc,
+        fib_entry_src_mk_lb(fib_entry, source,
                             fib_entry_delegate_type_to_chain_type(fdt),
                             &fed->fd_dpo);
     });
@@ -703,6 +757,7 @@ fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
            &fib_entry->fe_prefix,
            &fib_entry->fe_lb);
 
+       vlib_worker_wait_one_loop();
        dpo_reset(&fib_entry->fe_lb);
     }
 }
@@ -732,7 +787,7 @@ fib_entry_src_action_copy (fib_entry_t *fib_entry,
                                         orig_src->fes_src,
                                         orig_src->fes_entry_flags);
 
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_copy,
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_copy,
                              (orig_src, fib_entry, esrc));
 
     fib_path_list_unlock(esrc->fes_pl);
@@ -1051,7 +1106,7 @@ fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
 
     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
 
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_deactivate,
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deactivate,
                              (esrc, fib_entry));
 
     esrc->fes_flags &= ~(FIB_ENTRY_SRC_FLAG_ACTIVE |
@@ -1090,7 +1145,7 @@ fib_entry_src_action_fwd_update (const fib_entry_t *fib_entry,
 
     vec_foreach(esrc, fib_entry->fe_srcs)
     {
-       FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_fwd_update,
+       FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_fwd_update,
                                  (esrc, fib_entry, source));
     }
 }
@@ -1179,18 +1234,20 @@ fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
     fib_entry_src_action_fwd_update(fib_entry, source);
 }
 
-void
-fib_entry_src_action_installed (const fib_entry_t *fib_entry,
+fib_entry_t *
+fib_entry_src_action_installed (fib_entry_t *fib_entry,
                                fib_source_t source)
 {
     fib_entry_src_t *esrc;
 
     esrc = fib_entry_src_find(fib_entry, source);
 
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_installed,
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_installed,
                              (esrc, fib_entry));
 
     fib_entry_src_action_fwd_update(fib_entry, source);
+
+    return (fib_entry);
 }
 
 /*
@@ -1207,7 +1264,6 @@ fib_entry_src_action_add (fib_entry_t *fib_entry,
                          fib_entry_flag_t flags,
                          const dpo_id_t *dpo)
 {
-    fib_node_index_t fib_entry_index;
     fib_entry_src_t *esrc;
 
     esrc = fib_entry_src_find_or_create(fib_entry, source, flags);
@@ -1217,7 +1273,7 @@ fib_entry_src_action_add (fib_entry_t *fib_entry,
 
     if (flags != esrc->fes_entry_flags)
     {
-        FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_flags_change,
+        FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_flags_change,
                                  (esrc, fib_entry, flags));
     }
     esrc->fes_entry_flags = flags;
@@ -1230,20 +1286,13 @@ fib_entry_src_action_add (fib_entry_t *fib_entry,
         return (fib_entry);
     }
 
-    /*
-     * save variable so we can recover from a fib_entry realloc.
-     */
-    fib_entry_index = fib_entry_get_index(fib_entry);
-
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_add,
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_add,
                              (esrc,
                               fib_entry,
                               flags,
                               fib_entry_get_dpo_proto(fib_entry),
                               dpo));
 
-    fib_entry = fib_entry_get(fib_entry_index);
-
     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
 
     fib_path_list_lock(esrc->fes_pl);
@@ -1270,7 +1319,7 @@ fib_entry_src_action_update (fib_entry_t *fib_entry,
                             fib_entry_flag_t flags,
                             const dpo_id_t *dpo)
 {
-    fib_node_index_t fib_entry_index, old_path_list_index;
+    fib_node_index_t old_path_list_index;
     fib_entry_src_t *esrc;
 
     esrc = fib_entry_src_find_or_create(fib_entry, source, flags);
@@ -1283,20 +1332,13 @@ fib_entry_src_action_update (fib_entry_t *fib_entry,
     old_path_list_index = esrc->fes_pl;
     esrc->fes_entry_flags = flags;
 
-    /*
-     * save variable so we can recover from a fib_entry realloc.
-     */
-    fib_entry_index = fib_entry_get_index(fib_entry);
-
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_add,
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_add,
                              (esrc,
                               fib_entry,
                               flags,
                               fib_entry_get_dpo_proto(fib_entry),
                               dpo));
 
-    fib_entry = fib_entry_get(fib_entry_index);
-
     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
 
     fib_path_list_lock(esrc->fes_pl);
@@ -1391,14 +1433,14 @@ fib_entry_src_action_remove (fib_entry_t *fib_entry,
     }
     else if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_CONTRIBUTING)
     {
-        FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_deactivate,
+        FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deactivate,
                                  (esrc, fib_entry));
         esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_CONTRIBUTING;
     }
 
     old_path_list = esrc->fes_pl;
 
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_remove, (esrc));
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_remove, (esrc));
 
     fib_path_list_unlock(old_path_list);
     fib_entry_unlock(fib_entry_get_index(fib_entry));
@@ -1415,55 +1457,38 @@ fib_entry_src_action_remove (fib_entry_t *fib_entry,
  * Return true the the route is attached via an interface that
  * is not in the same table as the route
  */
-static inline int
+static int
 fib_route_attached_cross_table (const fib_entry_t *fib_entry,
                                const fib_route_path_t *rpath)
 {
-    /*
-     * - All zeros next-hop
-     * - a valid interface
-     * - entry's fib index not equeal to interface's index
-     */
-    if (ip46_address_is_zero(&rpath->frp_addr) &&
-       (~0 != rpath->frp_sw_if_index) &&
-        !(rpath->frp_flags & FIB_ROUTE_PATH_DVR) &&
-       (fib_entry->fe_fib_index != 
-        fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
-                                            rpath->frp_sw_if_index)))
-    {
-       return (!0);
-    }
-    return (0);
-}
+    const fib_prefix_t *pfx = &fib_entry->fe_prefix;
 
-/*
- * Return true if the path is attached
- */
-static inline int
-fib_path_is_attached (const fib_route_path_t *rpath)
-{
-    /*
-     * DVR paths are not attached, since we are not playing the
-     * L3 game with these
-     */
-    if (rpath->frp_flags & FIB_ROUTE_PATH_DVR)
+    switch (pfx->fp_proto)
     {
-        return (0);
+    case FIB_PROTOCOL_MPLS:
+        /* MPLS routes are never imported/exported */
+       return (0);
+    case FIB_PROTOCOL_IP6:
+        /* Ignore link local addresses these also can't be imported/exported */
+        if (ip6_address_is_link_local_unicast (&pfx->fp_addr.ip6))
+        {
+            return (0);
+        }
+        break;
+    case FIB_PROTOCOL_IP4:
+        break;
     }
 
     /*
-     * - All zeros next-hop
-     * - a valid interface
+     * an attached path and entry's fib index not equal to interface's index
      */
-    if (ip46_address_is_zero(&rpath->frp_addr) &&
-       (~0 != rpath->frp_sw_if_index))
+    if (fib_route_path_is_attached(rpath) &&
+       fib_entry->fe_fib_index !=
+        fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
+                                            rpath->frp_sw_if_index))
     {
        return (!0);
     }
-    else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
-    {
-        return (!0);
-    }
     return (0);
 }
 
@@ -1501,7 +1526,7 @@ fib_entry_flags_update (const fib_entry_t *fib_entry,
         if ((esrc->fes_src == FIB_SOURCE_API) ||
             (esrc->fes_src == FIB_SOURCE_CLI))
         {
-            if (fib_path_is_attached(rpath))
+            if (fib_route_path_is_attached(rpath))
             {
                 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
             }
@@ -1540,15 +1565,10 @@ fib_entry_src_action_path_add (fib_entry_t *fib_entry,
                               fib_entry_flag_t flags,
                               const fib_route_path_t *rpaths)
 {
-    fib_node_index_t old_path_list, fib_entry_index;
+    fib_node_index_t old_path_list;
     fib_path_list_flags_t pl_flags;
     fib_entry_src_t *esrc;
 
-    /*
-     * save variable so we can recover from a fib_entry realloc.
-     */
-    fib_entry_index = fib_entry_get_index(fib_entry);
-
     esrc = fib_entry_src_find(fib_entry, source);
     if (NULL == esrc)
     {
@@ -1581,9 +1601,8 @@ fib_entry_src_action_path_add (fib_entry_t *fib_entry,
     pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
     fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
 
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_path_add,
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_add,
                              (esrc, fib_entry, pl_flags, rpaths));
-    fib_entry = fib_entry_get(fib_entry_index);
 
     fib_path_list_lock(esrc->fes_pl);
     fib_path_list_unlock(old_path_list);
@@ -1606,17 +1625,12 @@ fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
                                fib_entry_flag_t flags,
                                const fib_route_path_t *rpaths)
 {
-    fib_node_index_t old_path_list, fib_entry_index;
+    fib_node_index_t old_path_list;
     fib_path_list_flags_t pl_flags;
     fib_entry_src_t *esrc;
 
     esrc = fib_entry_src_find(fib_entry, source);
 
-    /*
-     * save variable so we can recover from a fib_entry realloc.
-     */
-    fib_entry_index = fib_entry_get_index(fib_entry);
-
     if (NULL == esrc)
     {
        const dpo_id_t *dpo;
@@ -1637,7 +1651,7 @@ fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
     {
         if (flags != esrc->fes_entry_flags)
         {
-            FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_flags_change,
+            FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_flags_change,
                                      (esrc, fib_entry, flags));
         }
         esrc->fes_entry_flags = flags;
@@ -1656,12 +1670,10 @@ fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
 
     fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
 
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_path_swap,
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_swap,
                              (esrc, fib_entry,
                               pl_flags, rpaths));
 
-    fib_entry = fib_entry_get(fib_entry_index);
-
     fib_path_list_lock(esrc->fes_pl);
     fib_path_list_unlock(old_path_list);
 
@@ -1695,7 +1707,7 @@ fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
     pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
     fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
 
-    FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_path_remove,
+    FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_remove,
                              (esrc, pl_flags, rpaths));
 
     /*
@@ -1786,6 +1798,25 @@ fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
     return (0);
 }
 
+fib_node_index_t
+fib_entry_get_path_list_for_source (fib_node_index_t fib_entry_index,
+                                   fib_source_t source)
+{
+  fib_entry_t *fib_entry;
+  fib_entry_src_t *esrc;
+
+  if (FIB_NODE_INDEX_INVALID == fib_entry_index)
+    return FIB_NODE_INDEX_INVALID;
+
+  fib_entry = fib_entry_get(fib_entry_index);
+  esrc = fib_entry_src_find(fib_entry, source);
+
+  if (esrc)
+    return esrc->fes_pl;
+
+  return FIB_NODE_INDEX_INVALID;
+}
+
 u32
 fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
                                              fib_source_t source)
@@ -1826,27 +1857,22 @@ fib_entry_get_flags_for_source (fib_node_index_t entry_index,
     return (FIB_ENTRY_FLAG_NONE);
 }
 
+fib_source_t
+fib_entry_get_source_i (const fib_entry_t *fib_entry)
+{
+    /* the vector of sources is deliberately arranged in priority order */
+    if (0 == vec_len(fib_entry->fe_srcs))
+        return (FIB_SOURCE_INVALID);
+    return (vec_elt(fib_entry->fe_srcs, 0).fes_src);
+}
+
 fib_entry_flag_t
 fib_entry_get_flags_i (const fib_entry_t *fib_entry)
 {
-    fib_entry_flag_t flags;
-
-    /*
-     * the vector of sources is deliberately arranged in priority order
-     */
+    /* the vector of sources is deliberately arranged in priority order */
     if (0 == vec_len(fib_entry->fe_srcs))
-    {
-       flags = FIB_ENTRY_FLAG_NONE;
-    }
-    else
-    {
-       fib_entry_src_t *esrc;
-
-       esrc = vec_elt_at_index(fib_entry->fe_srcs, 0);
-       flags = esrc->fes_entry_flags;
-    }
-
-    return (flags);
+        return (FIB_ENTRY_FLAG_NONE);
+    return (vec_elt(fib_entry->fe_srcs, 0).fes_entry_flags);
 }
 
 void
@@ -1862,7 +1888,7 @@ fib_entry_set_source_data (fib_node_index_t fib_entry_index,
 
     if (NULL != esrc)
     {
-        FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_set_data,
+        FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_set_data,
                                  (esrc, fib_entry, data));
     }
 }
@@ -1891,8 +1917,8 @@ fib_entry_src_module_init (void)
     fib_entry_src_rr_register();
     fib_entry_src_interface_register();
     fib_entry_src_interpose_register();
-    fib_entry_src_default_route_register();
-    fib_entry_src_special_register();
+    fib_entry_src_drop_register();
+    fib_entry_src_simple_register();
     fib_entry_src_api_register();
     fib_entry_src_adj_register();
     fib_entry_src_mpls_register();