DVR: run L3 output features
[vpp.git] / src / vnet / fib / fib_test.c
index 1a9cce2..9a8febb 100644 (file)
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 
+#include <vnet/fib/fib_test.h>
 #include <vnet/fib/ip6_fib.h>
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/fib/mpls_fib.h>
 #include <vnet/dpo/drop_dpo.h>
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/dpo/ip_null_dpo.h>
+#include <vnet/bfd/bfd_main.h>
+#include <vnet/dpo/interface_rx_dpo.h>
+#include <vnet/dpo/replicate_dpo.h>
+#include <vnet/dpo/dvr_dpo.h>
+#include <vnet/dpo/mpls_disposition.h>
 
 #include <vnet/mpls/mpls.h>
 
+#include <vnet/fib/fib_test.h>
 #include <vnet/fib/fib_path_list.h>
 #include <vnet/fib/fib_entry_src.h>
 #include <vnet/fib/fib_walk.h>
 #include <vnet/fib/fib_node_list.h>
 #include <vnet/fib/fib_urpf_list.h>
 
+/*
+ * Add debugs for passing tests
+ */
+static int fib_test_do_debug;
+
 #define FIB_TEST_I(_cond, _comment, _args...)                  \
 ({                                                             \
     int _evald = (_cond);                                      \
@@ -40,8 +52,9 @@
        fformat(stderr, "FAIL:%d: " _comment "\n",              \
                __LINE__, ##_args);                             \
     } else {                                                   \
-       fformat(stderr, "PASS:%d: " _comment "\n",              \
-               __LINE__, ##_args);                             \
+       if (fib_test_do_debug)                                  \
+            fformat(stderr, "PASS:%d: " _comment "\n",          \
+                    __LINE__, ##_args);                                \
     }                                                          \
     _evald;                                                    \
 })
@@ -257,57 +270,6 @@ fib_test_build_rewrite (u8 *eth_addr)
     return (rewrite);
 }
 
-typedef enum fib_test_lb_bucket_type_t_ {
-    FT_LB_LABEL_O_ADJ,
-    FT_LB_LABEL_STACK_O_ADJ,
-    FT_LB_LABEL_O_LB,
-    FT_LB_O_LB,
-    FT_LB_SPECIAL,
-    FT_LB_ADJ,
-} fib_test_lb_bucket_type_t;
-
-typedef struct fib_test_lb_bucket_t_ {
-    fib_test_lb_bucket_type_t type;
-
-    union
-    {
-       struct
-       {
-           mpls_eos_bit_t eos;
-           mpls_label_t label;
-           u8 ttl;
-           adj_index_t adj;
-       } label_o_adj;
-       struct
-       {
-           mpls_eos_bit_t eos;
-           mpls_label_t label_stack[8];
-           u8 label_stack_size;
-           u8 ttl;
-           adj_index_t adj;
-       } label_stack_o_adj;
-       struct
-       {
-           mpls_eos_bit_t eos;
-           mpls_label_t label;
-           u8 ttl;
-           index_t lb;
-       } label_o_lb;
-       struct
-       {
-           index_t adj;
-       } adj;
-       struct
-       {
-           index_t lb;
-       } lb;
-       struct
-       {
-           index_t adj;
-       } special;
-    };
-} fib_test_lb_bucket_t;
-
 #define FIB_TEST_LB(_cond, _comment, _args...)                 \
 {                                                              \
     if (!FIB_TEST_I(_cond, _comment, ##_args)) {               \
@@ -315,10 +277,86 @@ typedef struct fib_test_lb_bucket_t_ {
     }                                                          \
 }
 
-static int
+int
+fib_test_validate_rep_v (const replicate_t *rep,
+                         u16 n_buckets,
+                         va_list *ap)
+{
+    const fib_test_rep_bucket_t *exp;
+    const dpo_id_t *dpo;
+    int bucket;
+
+    FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
+                "n_buckets = %d", rep->rep_n_buckets);
+
+    for (bucket = 0; bucket < n_buckets; bucket++)
+    {
+       exp = va_arg(*ap, fib_test_rep_bucket_t*);
+
+        dpo = replicate_get_bucket_i(rep, bucket);
+
+       switch (exp->type)
+       {
+       case FT_REP_LABEL_O_ADJ:
+           {
+               const mpls_label_dpo_t *mld;
+                mpls_label_t hdr;
+               FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
+                            "bucket %d stacks on %U",
+                            bucket,
+                            format_dpo_type, dpo->dpoi_type);
+           
+               mld = mpls_label_dpo_get(dpo->dpoi_index);
+                hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
+
+               FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
+                            exp->label_o_adj.label),
+                           "bucket %d stacks on label %d",
+                           bucket,
+                           exp->label_o_adj.label);
+
+               FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
+                            exp->label_o_adj.eos),
+                           "bucket %d stacks on label %d %U",
+                           bucket,
+                           exp->label_o_adj.label,
+                           format_mpls_eos_bit, exp->label_o_adj.eos);
+
+               FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
+                           "bucket %d label stacks on %U",
+                           bucket,
+                           format_dpo_type, mld->mld_dpo.dpoi_type);
+
+               FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
+                           "bucket %d label stacks on adj %d",
+                           bucket,
+                           exp->label_o_adj.adj);
+           }
+           break;
+       case FT_REP_INTF:
+            FIB_TEST_LB((DPO_INTERFACE_RX == dpo->dpoi_type),
+                        "bucket %d stacks on %U",
+                        bucket,
+                        format_dpo_type, dpo->dpoi_type);
+
+            FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
+                        "bucket %d stacks on adj %d",
+                        bucket,
+                        exp->adj.adj);
+           break;
+        case FT_REP_DISP_MFIB_LOOKUP:
+//            ASSERT(0);
+            break;
+        }
+    }
+
+    return (!0);
+}
+
+int
 fib_test_validate_lb_v (const load_balance_t *lb,
                        u16 n_buckets,
-                       va_list ap)
+                       va_list *ap)
 {
     const dpo_id_t *dpo;
     int bucket;
@@ -329,7 +367,7 @@ fib_test_validate_lb_v (const load_balance_t *lb,
     {
        const fib_test_lb_bucket_t *exp;
 
-       exp = va_arg(ap, fib_test_lb_bucket_t*);
+       exp = va_arg(*ap, fib_test_lb_bucket_t*);
        dpo = load_balance_get_bucket_i(lb, bucket);
 
        switch (exp->type)
@@ -477,39 +515,128 @@ fib_test_validate_lb_v (const load_balance_t *lb,
                        bucket,
                        exp->adj.adj);
            break;
+       case FT_LB_MPLS_DISP_O_ADJ:
+        {
+            const mpls_disp_dpo_t *mdd;
+
+            FIB_TEST_I((DPO_MPLS_DISPOSITION == dpo->dpoi_type),
+                      "bucket %d stacks on %U",
+                      bucket,
+                      format_dpo_type, dpo->dpoi_type);
+           
+            mdd = mpls_disp_dpo_get(dpo->dpoi_index);
+
+            dpo = &mdd->mdd_dpo;
+
+           FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
+                       (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
+                      "bucket %d stacks on %U",
+                      bucket,
+                      format_dpo_type, dpo->dpoi_type);
+           FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
+                       "bucket %d stacks on adj %d",
+                       bucket,
+                       exp->adj.adj);
+           break;
+        }
+       case FT_LB_INTF:
+           FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
+                      "bucket %d stacks on %U",
+                      bucket,
+                      format_dpo_type, dpo->dpoi_type);
+           FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
+                       "bucket %d stacks on adj %d",
+                       bucket,
+                       exp->adj.adj);
+           break;
+       case FT_LB_L2:
+           FIB_TEST_I((DPO_DVR == dpo->dpoi_type),
+                      "bucket %d stacks on %U",
+                      bucket,
+                      format_dpo_type, dpo->dpoi_type);
+           FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
+                       "bucket %d stacks on adj %d",
+                       bucket,
+                       exp->adj.adj);
+           break;
        case FT_LB_O_LB:
            FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
                        "bucket %d stacks on %U",
                        bucket,
                        format_dpo_type, dpo->dpoi_type);
            FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
-                       "bucket %d stacks on lb %d",
+                       "bucket %d stacks on lb %d not %d",
                        bucket,
-                       exp->lb.lb);
+                       dpo->dpoi_index,
+                        exp->lb.lb);
            break;
-       case FT_LB_SPECIAL:
-           FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
-                      "bucket %d stacks on %U",
-                      bucket,
-                      format_dpo_type, dpo->dpoi_type);
-           FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
-                       "bucket %d stacks on drop %d",
+       case FT_LB_BIER_TABLE:
+           FIB_TEST_LB((DPO_BIER_TABLE == dpo->dpoi_type),
+                        "bucket %d stacks on %U",
+                        bucket,
+                        format_dpo_type, dpo->dpoi_type);
+           FIB_TEST_LB((exp->bier.table == dpo->dpoi_index),
+                       "bucket %d stacks on lb %d",
+                       bucket,
+                       exp->bier.table);
+            break;
+       case FT_LB_BIER_FMASK:
+           FIB_TEST_LB((DPO_BIER_FMASK == dpo->dpoi_type),
+                        "bucket %d stacks on %U",
+                        bucket,
+                        format_dpo_type, dpo->dpoi_type);
+           FIB_TEST_LB((exp->bier.fmask == dpo->dpoi_index),
+                       "bucket %d stacks on lb %d",
                        bucket,
-                       exp->special.adj);
+                       exp->bier.fmask);
+            break;
+       case FT_LB_DROP:
+           FIB_TEST_LB((DPO_DROP == dpo->dpoi_type),
+                        "bucket %d stacks on %U",
+                        bucket,
+                        format_dpo_type, dpo->dpoi_type);
            break;
        }
     }
     return (!0);
 }
 
-static int
+int
+fib_test_validate_lb (const dpo_id_t *dpo,
+                     u16 n_buckets,
+                     ...)
+{
+    const load_balance_t *lb;
+    va_list ap;
+    int res;
+
+    va_start(ap, n_buckets);
+
+    if (FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
+                   "Entry links to %U",
+                   format_dpo_type, dpo->dpoi_type))
+    {
+        lb = load_balance_get(dpo->dpoi_index);
+
+        res = fib_test_validate_lb_v(lb, n_buckets, &ap);
+    }
+    else
+    {
+        res = !0;
+    }
+
+    va_end(ap);
+
+    return (res);
+}
+
+int
 fib_test_validate_entry (fib_node_index_t fei,
                         fib_forward_chain_type_t fct,
-                        u16 n_buckets,
+                        int n_buckets,
                         ...)
 {
     dpo_id_t dpo = DPO_INVALID;
-    const load_balance_t *lb;
     fib_prefix_t pfx;
     index_t fw_lbi;
     u32 fib_index;
@@ -522,47 +649,59 @@ fib_test_validate_entry (fib_node_index_t fei,
     fib_index = fib_entry_get_fib_index(fei);
     fib_entry_contribute_forwarding(fei, fct, &dpo);
 
-    FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
-               "Entry links to %U",
-               format_dpo_type, dpo.dpoi_type);
-    lb = load_balance_get(dpo.dpoi_index);
-
-    res = fib_test_validate_lb_v(lb, n_buckets, ap);
+    if (DPO_REPLICATE == dpo.dpoi_type)
+    {
+        const replicate_t *rep;
 
-    /*
-     * ensure that the LB contributed by the entry is the
-     * same as the LB in the forwarding tables
-     */
-    if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
+        rep = replicate_get(dpo.dpoi_index);
+        res = fib_test_validate_rep_v(rep, n_buckets, &ap);
+    }
+    else
     {
-        switch (pfx.fp_proto)
-        {
-        case FIB_PROTOCOL_IP4:
-            fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
-            break;
-        case FIB_PROTOCOL_IP6:
-            fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
-            break;
-        case FIB_PROTOCOL_MPLS:
-            {
-                mpls_unicast_header_t hdr = {
-                    .label_exp_s_ttl = 0,
-                };
+        const load_balance_t *lb;
 
-                vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
-                vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
-                hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
+        FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
+                    "Entry links to %U",
+                    format_dpo_type, dpo.dpoi_type);
 
-                fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
+        lb = load_balance_get(dpo.dpoi_index);
+        res = fib_test_validate_lb_v(lb, n_buckets, &ap);
+
+        /*
+         * ensure that the LB contributed by the entry is the
+         * same as the LB in the forwarding tables
+         */
+        if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
+        {
+            switch (pfx.fp_proto)
+            {
+            case FIB_PROTOCOL_IP4:
+                fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
+                break;
+            case FIB_PROTOCOL_IP6:
+                fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
                 break;
+            case FIB_PROTOCOL_MPLS:
+                {
+                    mpls_unicast_header_t hdr = {
+                        .label_exp_s_ttl = 0,
+                    };
+
+                    vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
+                    vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
+                    hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
+
+                    fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
+                    break;
+                }
+            default:
+                fw_lbi = 0;
             }
-        default:
-            fw_lbi = 0;
+            FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
+                        "Contributed LB = FW LB: %U\n %U",
+                        format_load_balance, fw_lbi, 0,
+                        format_load_balance, dpo.dpoi_index, 0);
         }
-        FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
-                    "Contributed LB = FW LB: %U\n %U",
-                    format_load_balance, fw_lbi, 0,
-                    format_load_balance, dpo.dpoi_index, 0);
     }
 
     dpo_reset(&dpo);
@@ -585,6 +724,7 @@ fib_test_v4 (void)
     const load_balance_t *lb;
     test_main_t *tm;
     u32 fib_index;
+    int lb_count;
     int ii;
 
     /* via 10.10.10.1 */
@@ -596,10 +736,17 @@ fib_test_v4 (void)
        .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
     };
 
+    FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
+            pool_elts(load_balance_map_pool));
+
     tm = &test_main;
 
+    /* record the nubmer of load-balances in use before we start */
+    lb_count = pool_elts(load_balance_pool);
+
     /* Find or create FIB table 11 */
-    fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
+    fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
+                                                  FIB_SOURCE_API);
 
     for (ii = 0; ii < 4; ii++)
     {
@@ -693,7 +840,7 @@ fib_test_v4 (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_ATTACHED),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -707,7 +854,8 @@ fib_test_v4 (void)
             "Flags set on attached interface");
 
     ai = fib_entry_get_adj(fei);
-    FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
+    FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
+             "attached interface route adj present %d", ai);
     adj = adj_get(ai);
     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
             "attached interface adj is glean");
@@ -720,7 +868,7 @@ fib_test_v4 (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_LOCAL),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -770,7 +918,7 @@ fib_test_v4 (void)
     fib_table_entry_path_add(fib_index, &pfx,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -822,7 +970,7 @@ fib_test_v4 (void)
     pfx.fp_len = 0;
     fib_table_entry_path_remove(fib_index, &pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0, // non-recursive path, so no FIB index
@@ -888,7 +1036,7 @@ fib_test_v4 (void)
                                           &pfx_11_11_11_11_s_32,
                                           FIB_SOURCE_API,
                                           FIB_ENTRY_FLAG_ATTACHED,
-                                         FIB_PROTOCOL_IP4,
+                                         DPO_PROTO_IP4,
                                           &pfx_10_10_10_1_s_32.fp_addr,
                                           tm->hw[0]->sw_if_index,
                                           ~0, // invalid fib index
@@ -950,26 +1098,26 @@ fib_test_v4 (void)
     /*
      * add the adj fib
      */
-    fei = fib_table_entry_update_one_path(fib_index,
-                                          &pfx_10_10_10_1_s_32,
-                                          FIB_SOURCE_ADJ,
-                                          FIB_ENTRY_FLAG_ATTACHED,
-                                         FIB_PROTOCOL_IP4,
-                                          &pfx_10_10_10_1_s_32.fp_addr,
-                                          tm->hw[0]->sw_if_index,
-                                          ~0, // invalid fib index
-                                          1,
-                                          NULL,
-                                          FIB_ROUTE_PATH_FLAG_NONE);
+    fei = fib_table_entry_path_add(fib_index,
+                                   &pfx_10_10_10_1_s_32,
+                                   FIB_SOURCE_ADJ,
+                                   FIB_ENTRY_FLAG_ATTACHED,
+                                   DPO_PROTO_IP4,
+                                   &pfx_10_10_10_1_s_32.fp_addr,
+                                   tm->hw[0]->sw_if_index,
+                                   ~0, // invalid fib index
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED  == fib_entry_get_flags(fei)),
             "Flags set on adj-fib");
     ai = fib_entry_get_adj(fei);
-    FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
+    FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
 
     fib_table_entry_path_remove(fib_index,
                                 &pfx_11_11_11_11_s_32,
                                 FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                 &pfx_10_10_10_1_s_32.fp_addr,
                                 tm->hw[0]->sw_if_index,
                                 ~0, // invalid fib index
@@ -999,17 +1147,17 @@ fib_test_v4 (void)
              "adj nbr next-hop ok");
     FIB_TEST((ai_01 != ai_02), "ADJs are different");
 
-    fib_table_entry_update_one_path(fib_index,
-                                   &pfx_10_10_10_2_s_32,
-                                   FIB_SOURCE_ADJ,
-                                   FIB_ENTRY_FLAG_ATTACHED,
-                                   FIB_PROTOCOL_IP4,
-                                   &pfx_10_10_10_2_s_32.fp_addr,
-                                   tm->hw[0]->sw_if_index,
-                                   ~0, // invalid fib index
-                                   1,
-                                   NULL,
-                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fib_table_entry_path_add(fib_index,
+                             &pfx_10_10_10_2_s_32,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP4,
+                             &pfx_10_10_10_2_s_32.fp_addr,
+                             tm->hw[0]->sw_if_index,
+                             ~0, // invalid fib index
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
 
     fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
     ai = fib_entry_get_adj(fei);
@@ -1040,7 +1188,7 @@ fib_test_v4 (void)
                             &pfx_1_1_1_1_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -1073,7 +1221,7 @@ fib_test_v4 (void)
                             &pfx_1_1_2_0_s_24,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -1100,7 +1248,7 @@ fib_test_v4 (void)
                             &pfx_1_1_2_0_s_24,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_2,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -1139,7 +1287,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_2_0_s_24,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_2,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -1186,7 +1334,7 @@ fib_test_v4 (void)
                                   &bgp_100_pfx,
                                   FIB_SOURCE_API,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &nh_1_1_1_1,
                                   ~0, // no index provided.
                                   fib_index, // nexthop in same fib as route
@@ -1222,7 +1370,7 @@ fib_test_v4 (void)
                             &bgp_101_pfx,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_1_1_1_1,
                             ~0, // no index provided.
                             fib_index, // nexthop in same fib as route
@@ -1246,8 +1394,8 @@ fib_test_v4 (void)
             fib_entry_pool_size());
 
     /*
-     * An EXCLUSIVE route; one where the user (me) provides the exclusive
-     * adjacency through which the route will resovle
+     * An special route; one where the user (me) provides the
+     * adjacency through which the route will resovle by setting the flags
      */
     fib_prefix_t ex_pfx = {
        .fp_len = 32,
@@ -1261,11 +1409,12 @@ fib_test_v4 (void)
     fib_table_entry_special_add(fib_index,
                                &ex_pfx,
                                FIB_SOURCE_SPECIAL,
-                               FIB_ENTRY_FLAG_EXCLUSIVE,
-                               locked_ai);
+                               FIB_ENTRY_FLAG_LOCAL);
     fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
-    FIB_TEST((ai == fib_entry_get_adj(fei)),
-            "Exclusive route links to user adj");
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
+    FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
+            "local interface adj is local");
 
     fib_table_entry_special_remove(fib_index,
                                   &ex_pfx,
@@ -1282,6 +1431,7 @@ fib_test_v4 (void)
 
     lookup_dpo_add_or_lock_w_fib_index(fib_index,
                                        DPO_PROTO_IP4,
+                                       LOOKUP_UNICAST,
                                        LOOKUP_INPUT_DST_ADDR,
                                        LOOKUP_TABLE_FROM_CONFIG,
                                        &ex_dpo);
@@ -1340,19 +1490,20 @@ fib_test_v4 (void)
        },
     };
 
-    fib_table_entry_path_add(fib_index,
-                            &bgp_200_pfx,
-                            FIB_SOURCE_API,
-                            FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
-                            &pfx_1_1_1_2_s_32.fp_addr,
-                            ~0, // no index provided.
-                            fib_index, // nexthop in same fib as route
-                            1,
-                            NULL,
-                            FIB_ROUTE_PATH_FLAG_NONE);
+    fei = fib_table_entry_path_add(fib_index,
+                                   &bgp_200_pfx,
+                                   FIB_SOURCE_API,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &pfx_1_1_1_2_s_32.fp_addr,
+                                   ~0, // no index provided.
+                                   fib_index, // nexthop in same fib as route
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
 
-    FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
+    FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
+             "Recursive via unresolved is drop");
 
     /*
      * the adj should be recursive via drop, since the route resolves via
@@ -1390,7 +1541,7 @@ fib_test_v4 (void)
                             &pfx_1_2_3_4_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                              &nh_10_10_10_1,
                              tm->hw[0]->sw_if_index,
                              ~0,
@@ -1401,7 +1552,7 @@ fib_test_v4 (void)
                                    &pfx_1_2_3_4_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                    &nh_12_12_12_12,
                                    tm->hw[1]->sw_if_index,
                                    ~0,
@@ -1442,7 +1593,7 @@ fib_test_v4 (void)
                             &pfx_1_2_3_5_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                              &nh_12_12_12_12,
                              tm->hw[1]->sw_if_index,
                              ~0,
@@ -1453,7 +1604,7 @@ fib_test_v4 (void)
                                    &pfx_1_2_3_5_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                    &nh_10_10_10_1,
                                    tm->hw[0]->sw_if_index,
                                    ~0,
@@ -1503,13 +1654,13 @@ fib_test_v4 (void)
            .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
        },
     };
-    fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_1 = {
+    fib_test_lb_bucket_t ip_o_10_10_10_1 = {
        .type = FT_LB_ADJ,
        .adj = {
            .adj = ai_01,
        },
     };
-    fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_2 = {
+    fib_test_lb_bucket_t ip_o_10_10_10_2 = {
         .type = FT_LB_ADJ,
         .adj = {
             .adj = ai_02,
@@ -1525,7 +1676,7 @@ fib_test_v4 (void)
                                    &pfx_6_6_6_6_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &nh_10_10_10_1,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -1537,14 +1688,14 @@ fib_test_v4 (void)
     FIB_TEST(fib_test_validate_entry(fei,
                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
                                     1,
-                                    &ip_6_6_6_6_o_10_10_10_1),
+                                    &ip_o_10_10_10_1),
             "6.6.6.6/32 via 10.10.10.1");
 
     fib_table_entry_path_add(fib_index,
                              &pfx_6_6_6_6_s_32,
                              FIB_SOURCE_API,
                              FIB_ENTRY_FLAG_NONE,
-                             FIB_PROTOCOL_IP4,
+                             DPO_PROTO_IP4,
                              &nh_10_10_10_2,
                              tm->hw[0]->sw_if_index,
                              ~0, // invalid fib index
@@ -1556,77 +1707,77 @@ fib_test_v4 (void)
     FIB_TEST(fib_test_validate_entry(fei,
                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
                                     64,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_1),
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_1),
             "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
 
     fib_table_entry_path_add(fib_index,
                              &pfx_6_6_6_6_s_32,
                              FIB_SOURCE_API,
                              FIB_ENTRY_FLAG_NONE,
-                             FIB_PROTOCOL_IP4,
+                             DPO_PROTO_IP4,
                              &nh_12_12_12_12,
                              tm->hw[1]->sw_if_index,
                              ~0, // invalid fib index
@@ -1638,71 +1789,71 @@ fib_test_v4 (void)
     FIB_TEST(fib_test_validate_entry(fei,
                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
                                     128,
-                                    &ip_6_6_6_6_o_10_10_10_1,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
+                                    &ip_o_10_10_10_1,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
                                     &ip_6_6_6_6_o_12_12_12_12,
                                     &ip_6_6_6_6_o_12_12_12_12,
                                     &ip_6_6_6_6_o_12_12_12_12,
@@ -1771,7 +1922,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                 &pfx_6_6_6_6_s_32,
                                 FIB_SOURCE_API,
-                                FIB_PROTOCOL_IP4,
+                                DPO_PROTO_IP4,
                                 &nh_12_12_12_12,
                                 tm->hw[1]->sw_if_index,
                                 ~0, // invalid fib index
@@ -1782,76 +1933,76 @@ fib_test_v4 (void)
     FIB_TEST(fib_test_validate_entry(fei,
                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
                                     64,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_2,
-                                    &ip_6_6_6_6_o_10_10_10_1),
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_2,
+                                    &ip_o_10_10_10_1),
             "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
 
     fib_table_entry_path_remove(fib_index,
                                 &pfx_6_6_6_6_s_32,
                                 FIB_SOURCE_API,
-                                FIB_PROTOCOL_IP4,
+                                DPO_PROTO_IP4,
                                 &nh_10_10_10_2,
                                 tm->hw[0]->sw_if_index,
                                 ~0, // invalid fib index
@@ -1862,7 +2013,7 @@ fib_test_v4 (void)
     FIB_TEST(fib_test_validate_entry(fei,
                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
                                     1,
-                                    &ip_6_6_6_6_o_10_10_10_1),
+                                    &ip_o_10_10_10_1),
             "6.6.6.6/32 via 10.10.10.1");
 
     fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
@@ -1882,7 +2033,7 @@ fib_test_v4 (void)
                                    &bgp_44_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &pfx_1_2_3_4_s_32.fp_addr,
                                    ~0,
                                    fib_index,
@@ -1893,7 +2044,7 @@ fib_test_v4 (void)
                                    &bgp_44_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &pfx_1_2_3_5_s_32.fp_addr,
                                    ~0,
                                    fib_index,
@@ -1959,19 +2110,20 @@ fib_test_v4 (void)
        },
     };
 
-    fib_table_entry_path_add(fib_index,
-                            &bgp_201_pfx,
-                            FIB_SOURCE_API,
-                            FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
-                            &pfx_1_1_1_200_s_32.fp_addr,
-                            ~0, // no index provided.
-                            fib_index, // nexthop in same fib as route
-                            1,
-                            NULL,
-                            FIB_ROUTE_PATH_FLAG_NONE);
+    fei = fib_table_entry_path_add(fib_index,
+                                   &bgp_201_pfx,
+                                   FIB_SOURCE_API,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &pfx_1_1_1_200_s_32.fp_addr,
+                                   ~0, // no index provided.
+                                   fib_index, // nexthop in same fib as route
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
 
-    FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
+    FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
+             "Recursive via unresolved is drop");
 
     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
     FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
@@ -2006,7 +2158,7 @@ fib_test_v4 (void)
                             &pfx_1_1_1_0_s_24,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -2064,7 +2216,7 @@ fib_test_v4 (void)
                             &pfx_1_1_1_0_s_28,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_2,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -2099,7 +2251,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_0_s_28,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_2,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -2130,7 +2282,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_0_s_24,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -2143,12 +2295,16 @@ fib_test_v4 (void)
     fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
             "1.1.1.2/32 route is DROP");
-    fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
+    fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
             "1.1.1.200/32 route is DROP");
 
-    FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
-    FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
+    fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
+    FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
+             "201 is drop");
+    fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
+    FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
+             "200 is drop");
 
     /*
      * -1 entry
@@ -2167,7 +2323,7 @@ fib_test_v4 (void)
                                   &pfx_1_1_1_2_s_32,
                                   FIB_SOURCE_API,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &nh_10_10_10_1,
                                   tm->hw[0]->sw_if_index,
                                   ~0, // invalid fib index
@@ -2178,7 +2334,9 @@ fib_test_v4 (void)
     ai = fib_entry_get_adj(fei);
     FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
 
-    FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
+    fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
+    FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
+             "201 is drop");
     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
 
     /*
@@ -2191,13 +2349,40 @@ fib_test_v4 (void)
     FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
             fib_entry_pool_size());
 
+    /*
+     * give 201 a resolved path.
+     *  it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
+     *  only the latter contributes forwarding.
+     */
+    fei = fib_table_entry_path_add(fib_index,
+                                   &bgp_201_pfx,
+                                   FIB_SOURCE_API,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &pfx_1_1_1_2_s_32.fp_addr,
+                                   ~0,
+                                   fib_index,
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+    FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
+    fib_table_entry_path_remove(fib_index,
+                                &bgp_201_pfx,
+                                FIB_SOURCE_API,
+                                DPO_PROTO_IP4,
+                                &pfx_1_1_1_2_s_32.fp_addr,
+                                ~0,
+                                fib_index,
+                                1,
+                                FIB_ROUTE_PATH_FLAG_NONE);
+
     /*
      * remove 200.200.200.201/32 which does not have a valid via FIB
      */
     fib_table_entry_path_remove(fib_index,
                                &bgp_201_pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_1_1_1_200_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index,
@@ -2227,7 +2412,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_200_pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_1_1_1_2_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index,
@@ -2268,7 +2453,7 @@ fib_test_v4 (void)
                             &bgp_102,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &pfx_1_1_1_1_s_32.fp_addr,
                             ~0, // no index provided.
                             fib_index, // same as route
@@ -2279,7 +2464,7 @@ fib_test_v4 (void)
                             &bgp_102,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &pfx_1_1_1_2_s_32.fp_addr,
                             ~0, // no index provided.
                             fib_index, // same as route's FIB
@@ -2305,7 +2490,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_102,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_1_1_1_1_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2314,7 +2499,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_102,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_1_1_1_2_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2329,7 +2514,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_100_pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_1_1_1_1_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2338,7 +2523,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_101_pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_1_1_1_1_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2368,7 +2553,7 @@ fib_test_v4 (void)
                             &bgp_200_pfx,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             ~0, // no index provided.
                             fib_index, // Same as route's FIB
@@ -2415,7 +2600,7 @@ fib_test_v4 (void)
                             &bgp_201_pfx,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_3,
                             ~0, // no index provided.
                             fib_index,
@@ -2461,7 +2646,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_200_pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2470,7 +2655,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_201_pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_3,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2529,7 +2714,7 @@ fib_test_v4 (void)
                             &pfx_5_5_5_5_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &pfx_5_5_5_6_s_32.fp_addr,
                             ~0, // no index provided.
                             fib_index,
@@ -2540,7 +2725,7 @@ fib_test_v4 (void)
                             &pfx_5_5_5_6_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &pfx_5_5_5_7_s_32.fp_addr,
                             ~0, // no index provided.
                             fib_index,
@@ -2551,7 +2736,7 @@ fib_test_v4 (void)
                             &pfx_5_5_5_7_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &pfx_5_5_5_5_s_32.fp_addr,
                             ~0, // no index provided.
                             fib_index,
@@ -2590,7 +2775,7 @@ fib_test_v4 (void)
                             &pfx_5_5_5_6_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0,
@@ -2598,7 +2783,6 @@ fib_test_v4 (void)
                             NULL,
                             FIB_ROUTE_PATH_FLAG_NONE);
 
-
     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
     dpo1 = fib_entry_contribute_ip_forwarding(fei);
 
@@ -2624,7 +2808,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_5_5_5_6_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -2649,7 +2833,7 @@ fib_test_v4 (void)
                                    &pfx_5_5_5_5_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &nh_10_10_10_1,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -2691,7 +2875,7 @@ fib_test_v4 (void)
                                    &pfx_5_5_5_5_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &pfx_5_5_5_6_s_32.fp_addr,
                                    ~0, // no index provided.
                                    fib_index,
@@ -2715,7 +2899,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_5_5_5_5_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_5_5_5_6_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2724,7 +2908,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_5_5_5_6_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_5_5_5_7_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2733,7 +2917,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_5_5_5_7_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_5_5_5_5_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2742,7 +2926,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_5_5_5_6_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_2,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2766,7 +2950,7 @@ fib_test_v4 (void)
                             &pfx_5_5_5_6_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &pfx_5_5_5_6_s_32.fp_addr,
                             ~0, // no index provided.
                             fib_index,
@@ -2780,7 +2964,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_5_5_5_6_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_5_5_5_6_s_32.fp_addr,
                                ~0, // no index provided.
                                fib_index, // same as route's FIB
@@ -2814,7 +2998,7 @@ fib_test_v4 (void)
                                   &pfx_23_23_23_0_s_24,
                                   FIB_SOURCE_API,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &pfx_23_23_23_23_s_32.fp_addr,
                                   ~0, // recursive
                                   fib_index,
@@ -2837,14 +3021,44 @@ fib_test_v4 (void)
             fib_entry_pool_size());
 
     /*
-     * A recursive route with recursion constraints.
-     *  200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
+     * Make the default route recursive via a unknown next-hop. Thus the
+     * next hop's cover would be the default route
      */
-    fib_table_entry_path_add(fib_index,
-                            &bgp_200_pfx,
-                            FIB_SOURCE_API,
-                            FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+    fei = fib_table_entry_path_add(fib_index,
+                                  &pfx_0_0_0_0_s_0,
+                                  FIB_SOURCE_API,
+                                  FIB_ENTRY_FLAG_NONE,
+                                  DPO_PROTO_IP4,
+                                  &pfx_23_23_23_23_s_32.fp_addr,
+                                  ~0, // recursive
+                                  fib_index,
+                                  1,
+                                  NULL,
+                                  FIB_ROUTE_PATH_FLAG_NONE);
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    FIB_TEST(load_balance_is_drop(dpo),
+            "0.0.0.0.0/0 via is DROP");
+    FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
+             "no resolving interface for looped 0.0.0.0/0");
+
+    fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    FIB_TEST(load_balance_is_drop(dpo),
+            "23.23.23.23/32 via is DROP");
+    FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
+             "no resolving interface for looped 23.23.23.23/32");
+
+    fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
+
+    /*
+     * A recursive route with recursion constraints.
+     *  200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
+     */
+    fib_table_entry_path_add(fib_index,
+                            &bgp_200_pfx,
+                            FIB_SOURCE_API,
+                            FIB_ENTRY_FLAG_NONE,
+                            DPO_PROTO_IP4,
                             &nh_1_1_1_1,
                             ~0,
                             fib_index,
@@ -2874,7 +3088,7 @@ fib_test_v4 (void)
                             &pfx_1_1_1_0_s_28,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -2892,7 +3106,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_1_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0, // invalid fib index
@@ -2909,7 +3123,7 @@ fib_test_v4 (void)
                             &pfx_1_1_1_1_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -2933,7 +3147,7 @@ fib_test_v4 (void)
                             &pfx_1_1_1_3_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_2,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -2945,7 +3159,7 @@ fib_test_v4 (void)
                             &bgp_200_pfx,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &pfx_1_1_1_3_s_32.fp_addr,
                             ~0,
                             fib_index,
@@ -2953,6 +3167,43 @@ fib_test_v4 (void)
                             NULL,
                             FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
 
+    /*
+     * add a bunch load more entries using this path combo so that we get
+     * an LB-map created.
+     */
+#define N_P 128
+    fib_prefix_t bgp_78s[N_P];
+    for (ii = 0; ii < N_P; ii++)
+    {
+        bgp_78s[ii].fp_len = 32;
+        bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
+        bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
+
+        
+        fib_table_entry_path_add(fib_index,
+                                 &bgp_78s[ii],
+                                 FIB_SOURCE_API,
+                                 FIB_ENTRY_FLAG_NONE,
+                                 DPO_PROTO_IP4,
+                                 &pfx_1_1_1_3_s_32.fp_addr,
+                                 ~0,
+                                 fib_index,
+                                 1,
+                                 NULL,
+                                 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
+        fib_table_entry_path_add(fib_index,
+                                 &bgp_78s[ii],
+                                 FIB_SOURCE_API,
+                                 FIB_ENTRY_FLAG_NONE,
+                                 DPO_PROTO_IP4,
+                                 &nh_1_1_1_1,
+                                 ~0,
+                                 fib_index,
+                                 1,
+                                 NULL,
+                                 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
+    }
+
     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
     dpo = fib_entry_contribute_ip_forwarding(fei);
 
@@ -2994,13 +3245,16 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_1_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0, // invalid fib index
                                1,
                                FIB_ROUTE_PATH_FLAG_NONE);
 
+    /* suspend so the update walk kicks int */
+    vlib_process_suspend(vlib_get_main(), 1e-5);
+
     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
     FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
             "post PIC 200.200.200.200/32 was inplace modified");
@@ -3021,7 +3275,7 @@ fib_test_v4 (void)
              "LB maps's bucket 1 is %d",
              lbm->lbm_buckets[1]);
 
-    load_balance_map_unlock(lb->lb_map);
+    load_balance_map_unlock(lbmi);
 
     /*
      * add it back. again 
@@ -3030,7 +3284,7 @@ fib_test_v4 (void)
                             &pfx_1_1_1_1_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -3038,6 +3292,9 @@ fib_test_v4 (void)
                             NULL,
                             FIB_ROUTE_PATH_FLAG_NONE);
 
+    /* suspend so the update walk kicks in */
+    vlib_process_suspend(vlib_get_main(), 1e-5);
+
     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
             "post PIC recovery adj for 200.200.200.200/32 is recursive "
             "via adj for 1.1.1.1");
@@ -3057,13 +3314,27 @@ fib_test_v4 (void)
                             &bgp_200_pfx,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
+                            &pfx_1_1_1_2_s_32.fp_addr,
+                            ~0,
+                            fib_index,
+                            1,
+                            NULL,
+                            FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
+    for (ii = 0; ii < N_P; ii++)
+    {
+        fib_table_entry_path_add(fib_index,
+                                 &bgp_78s[ii],
+                            FIB_SOURCE_API,
+                            FIB_ENTRY_FLAG_NONE,
+                            DPO_PROTO_IP4,
                             &pfx_1_1_1_2_s_32.fp_addr,
                             ~0,
                             fib_index,
                             1,
                             NULL,
                             FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
+    }
 
     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
     dpo = fib_entry_contribute_ip_forwarding(fei);
@@ -3090,12 +3361,14 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_1_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0,
                                1,
                                FIB_ROUTE_PATH_FLAG_NONE);
+    /* suspend so the update walk kicks int */
+    vlib_process_suspend(vlib_get_main(), 1e-5);
 
     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
     dpo = fib_entry_contribute_ip_forwarding(fei);
@@ -3116,7 +3389,7 @@ fib_test_v4 (void)
                  "LB Map for 200.200.200.200/32 at %d is %d",
                  ii, lbm->lbm_buckets[ii]);
     }
-
+    load_balance_map_unlock(lbmi);
 
     /*
      * tidy up
@@ -3125,7 +3398,7 @@ fib_test_v4 (void)
                              &pfx_1_1_1_1_s_32,
                              FIB_SOURCE_API,
                              FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                              &nh_10_10_10_1,
                              tm->hw[0]->sw_if_index,
                              ~0,
@@ -3133,10 +3406,20 @@ fib_test_v4 (void)
                              NULL,
                              FIB_ROUTE_PATH_FLAG_NONE);
 
+    for (ii = 0; ii < N_P; ii++)
+    {
+        fib_table_entry_delete(fib_index,
+                               &bgp_78s[ii],
+                               FIB_SOURCE_API);
+        FIB_TEST((FIB_NODE_INDEX_INVALID ==
+                  fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
+                 "%U removed",
+                 format_fib_prefix, &bgp_78s[ii]);
+    }
     fib_table_entry_path_remove(fib_index,
                                 &bgp_200_pfx,
                                 FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                 &pfx_1_1_1_2_s_32.fp_addr,
                                 ~0,
                                 fib_index,
@@ -3145,7 +3428,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_200_pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_1_1_1_1,
                                ~0,
                                fib_index,
@@ -3154,7 +3437,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &bgp_200_pfx,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &pfx_1_1_1_3_s_32.fp_addr,
                                ~0,
                                fib_index,
@@ -3166,6 +3449,8 @@ fib_test_v4 (void)
     fib_table_entry_delete(fib_index,
                           &pfx_1_1_1_0_s_28,
                           FIB_SOURCE_API);
+    /* suspend so the update walk kicks int */
+    vlib_process_suspend(vlib_get_main(), 1e-5);
     FIB_TEST((FIB_NODE_INDEX_INVALID ==
              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
             "1.1.1.1/28 removed");
@@ -3203,7 +3488,7 @@ fib_test_v4 (void)
                             &pfx_4_4_4_4_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0,
@@ -3214,7 +3499,7 @@ fib_test_v4 (void)
                             &pfx_4_4_4_4_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_2,
                             tm->hw[0]->sw_if_index,
                             ~0,
@@ -3225,7 +3510,7 @@ fib_test_v4 (void)
                             &pfx_4_4_4_4_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_3,
                             tm->hw[0]->sw_if_index,
                             ~0,
@@ -3261,7 +3546,7 @@ fib_test_v4 (void)
     for (ii = 0; ii < 4; ii++)
     {
        fib_route_path_t r_path = {
-           .frp_proto = FIB_PROTOCOL_IP4,
+           .frp_proto = DPO_PROTO_IP4,
            .frp_addr = {
                .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
            },
@@ -3310,7 +3595,7 @@ fib_test_v4 (void)
                             &pfx_4_4_4_4_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &zero_addr,
                             ~0,
                             fib_index,
@@ -3329,6 +3614,49 @@ fib_test_v4 (void)
             "4.4.4.4/32 is deag in %d %U",
              lkd->lkd_fib_index,
              format_dpo_id, dpo, 0);
+    FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
+            "4.4.4.4/32 is source deag in %d %U",
+             lkd->lkd_input,
+             format_dpo_id, dpo, 0);
+
+    fib_table_entry_delete(fib_index,
+                          &pfx_4_4_4_4_s_32,
+                          FIB_SOURCE_API);
+    FIB_TEST(FIB_NODE_INDEX_INVALID ==
+            fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
+            "4.4.4.4/32 removed");
+    vec_free(r_paths);
+
+    /*
+     * A route deag route in a source lookup table
+     */
+    fib_table_entry_path_add(fib_index,
+                            &pfx_4_4_4_4_s_32,
+                            FIB_SOURCE_API,
+                            FIB_ENTRY_FLAG_NONE,
+                            DPO_PROTO_IP4,
+                            &zero_addr,
+                            ~0,
+                            fib_index,
+                            1,
+                            NULL,
+                            FIB_ROUTE_PATH_SOURCE_LOOKUP);
+
+    fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
+    FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
+
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
+    lkd = lookup_dpo_get(dpo->dpoi_index);
+
+    FIB_TEST((fib_index == lkd->lkd_fib_index),
+            "4.4.4.4/32 is deag in %d %U",
+             lkd->lkd_fib_index,
+             format_dpo_id, dpo, 0);
+    FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
+            "4.4.4.4/32 is source deag in %d %U",
+             lkd->lkd_input,
+             format_dpo_id, dpo, 0);
 
     fib_table_entry_delete(fib_index,
                           &pfx_4_4_4_4_s_32,
@@ -3366,11 +3694,22 @@ fib_test_v4 (void)
            .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
        },
     };
+    fei = fib_table_entry_path_add(fib_index,
+                                   &pfx_34_34_1_1_s_32,
+                                   FIB_SOURCE_API,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &nh_10_10_10_1,
+                                   tm->hw[0]->sw_if_index,
+                                   0,
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
     fei = fib_table_entry_path_add(fib_index,
                                    &pfx_34_1_1_1_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &pfx_34_34_1_1_s_32.fp_addr,
                                    ~0,
                                    fib_index,
@@ -3381,7 +3720,7 @@ fib_test_v4 (void)
                                    &pfx_34_1_1_1_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &pfx_34_34_1_1_s_32.fp_addr,
                                    ~0,
                                    fib_index,
@@ -3390,6 +3729,9 @@ fib_test_v4 (void)
                                    FIB_ROUTE_PATH_FLAG_NONE);
     FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
+    fib_table_entry_delete(fib_index,
+                           &pfx_34_34_1_1_s_32,
+                           FIB_SOURCE_API);
 
     /*
      * CLEANUP
@@ -3399,7 +3741,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_2_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -3408,7 +3750,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_1_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -3417,7 +3759,7 @@ fib_test_v4 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_2_0_s_24,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -3459,7 +3801,7 @@ fib_test_v4 (void)
                             &pfx_4_1_1_1_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &zero_addr,
                             tm->hw[0]->sw_if_index,
                             fib_index,
@@ -3513,7 +3855,7 @@ fib_test_v4 (void)
                                   &pfx_2001_s_64,
                                   FIB_SOURCE_API,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &nh_10_10_10_1,
                                   tm->hw[0]->sw_if_index,
                                   fib_index,
@@ -3543,8 +3885,7 @@ fib_test_v4 (void)
     fei = fib_table_entry_special_add(fib_index,
                                      &pfx_4_1_1_1_s_32,
                                      FIB_SOURCE_URPF_EXEMPT,
-                                     FIB_ENTRY_FLAG_DROP,
-                                     ADJ_INDEX_INVALID);
+                                     FIB_ENTRY_FLAG_DROP);
     dpo = fib_entry_contribute_ip_forwarding(fei);
     FIB_TEST(load_balance_is_drop(dpo),
             "uRPF exempt 4.1.1.1/32 DROP");
@@ -3568,17 +3909,17 @@ fib_test_v4 (void)
        },
     };
 
-    fib_table_entry_update_one_path(fib_index,
-                                   &pfx_12_10_10_2_s_32,
-                                   FIB_SOURCE_ADJ,
-                                   FIB_ENTRY_FLAG_ATTACHED,
-                                   FIB_PROTOCOL_IP4,
-                                   &pfx_12_10_10_2_s_32.fp_addr,
-                                   tm->hw[0]->sw_if_index,
-                                   ~0, // invalid fib index
-                                   1,
-                                   NULL,
-                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fib_table_entry_path_add(fib_index,
+                             &pfx_12_10_10_2_s_32,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP4,
+                             &pfx_12_10_10_2_s_32.fp_addr,
+                             tm->hw[0]->sw_if_index,
+                             ~0, // invalid fib index
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
 
     fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
     dpo = fib_entry_contribute_ip_forwarding(fei);
@@ -3602,17 +3943,17 @@ fib_test_v4 (void)
        },
     };
 
-    fib_table_entry_update_one_path(fib_index,
-                                   &pfx_10_10_10_127_s_32,
-                                   FIB_SOURCE_ADJ,
-                                   FIB_ENTRY_FLAG_ATTACHED,
-                                   FIB_PROTOCOL_IP4,
-                                   &pfx_10_10_10_127_s_32.fp_addr,
-                                   tm->hw[1]->sw_if_index,
-                                   ~0, // invalid fib index
-                                   1,
-                                   NULL,
-                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fib_table_entry_path_add(fib_index,
+                             &pfx_10_10_10_127_s_32,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP4,
+                             &pfx_10_10_10_127_s_32.fp_addr,
+                             tm->hw[1]->sw_if_index,
+                             ~0, // invalid fib index
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
 
     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
     dpo = fib_entry_contribute_ip_forwarding(fei);
@@ -3623,6 +3964,196 @@ fib_test_v4 (void)
                           &pfx_10_10_10_127_s_32,
                           FIB_SOURCE_ADJ);
 
+    /*
+     * add a second path to an adj-fib
+     * this is a sumiluation of another ARP entry created
+     * on an interface on which the connected prefi does not exist.
+     * The second path fails refinement. Expect to forward through the
+     * first.
+     */
+    fib_prefix_t pfx_10_10_10_3_s_32 = {
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_addr = {
+            /* 10.10.10.3 */
+            .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
+        },
+    };
+
+    ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                VNET_LINK_IP4,
+                                &nh_10_10_10_3,
+                                tm->hw[0]->sw_if_index);
+
+    fib_test_lb_bucket_t ip_o_10_10_10_3 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_03,
+        },
+    };
+    fei = fib_table_entry_path_add(fib_index,
+                                   &pfx_10_10_10_3_s_32,
+                                   FIB_SOURCE_ADJ,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &nh_10_10_10_3,
+                                   tm->hw[0]->sw_if_index,
+                                   fib_index,
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fei = fib_table_entry_path_add(fib_index,
+                                   &pfx_10_10_10_3_s_32,
+                                   FIB_SOURCE_ADJ,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &nh_12_12_12_12,
+                                   tm->hw[1]->sw_if_index,
+                                   fib_index,
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &ip_o_10_10_10_3),
+             "10.10.10.3 via 10.10.10.3/Eth0 only");
+
+    /*
+     * remove the path that refines the cover, should go unresolved
+     */
+    fib_table_entry_path_remove(fib_index,
+                                &pfx_10_10_10_3_s_32,
+                                FIB_SOURCE_ADJ,
+                                DPO_PROTO_IP4,
+                                &nh_10_10_10_3,
+                                tm->hw[0]->sw_if_index,
+                                fib_index,
+                                1,
+                                FIB_ROUTE_PATH_FLAG_NONE);
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    FIB_TEST(!dpo_id_is_valid(dpo),
+             "wrong interface adj-fib fails refinement");
+
+    /*
+     * add back the path that refines the cover
+     */
+    fei = fib_table_entry_path_add(fib_index,
+                                   &pfx_10_10_10_3_s_32,
+                                   FIB_SOURCE_ADJ,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &nh_10_10_10_3,
+                                   tm->hw[0]->sw_if_index,
+                                   fib_index,
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &ip_o_10_10_10_3),
+             "10.10.10.3 via 10.10.10.3/Eth0 only");
+
+    /*
+     * remove the path that does not refine the cover
+     */
+    fib_table_entry_path_remove(fib_index,
+                                &pfx_10_10_10_3_s_32,
+                                FIB_SOURCE_ADJ,
+                                DPO_PROTO_IP4,
+                                &nh_12_12_12_12,
+                                tm->hw[1]->sw_if_index,
+                                fib_index,
+                                1,
+                                FIB_ROUTE_PATH_FLAG_NONE);
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &ip_o_10_10_10_3),
+             "10.10.10.3 via 10.10.10.3/Eth0 only");
+
+    /*
+     * remove the path that does refine, it's the last path, so
+     * the entry should be gone
+     */
+    fib_table_entry_path_remove(fib_index,
+                                &pfx_10_10_10_3_s_32,
+                                FIB_SOURCE_ADJ,
+                                DPO_PROTO_IP4,
+                                &nh_10_10_10_3,
+                                tm->hw[0]->sw_if_index,
+                                fib_index,
+                                1,
+                                FIB_ROUTE_PATH_FLAG_NONE);
+    fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
+    FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
+
+    adj_unlock(ai_03);
+
+    /*
+     * change the table's flow-hash config - expect the update to propagete to
+     * the entries' load-balance objects
+     */
+    flow_hash_config_t old_hash_config, new_hash_config;
+
+    old_hash_config = fib_table_get_flow_hash_config(fib_index,
+                                                     FIB_PROTOCOL_IP4);
+    new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
+                       IP_FLOW_HASH_DST_ADDR);
+
+    fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    lb = load_balance_get(dpo->dpoi_index);
+    FIB_TEST((lb->lb_hash_config == old_hash_config),
+             "Table and LB hash config match: %U",
+             format_ip_flow_hash_config, lb->lb_hash_config);
+
+    fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
+
+    FIB_TEST((lb->lb_hash_config == new_hash_config),
+             "Table and LB newhash config match: %U",
+             format_ip_flow_hash_config, lb->lb_hash_config);
+
+    /*
+     * A route via DVR DPO
+     */
+    fei = fib_table_entry_path_add(fib_index,
+                                   &pfx_10_10_10_3_s_32,
+                                   FIB_SOURCE_API,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &zero_addr,
+                                   tm->hw[0]->sw_if_index,
+                                   ~0,
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_DVR);
+    dpo_id_t dvr_dpo = DPO_INVALID;
+    dvr_dpo_add_or_lock(tm->hw[0]->sw_if_index, DPO_PROTO_IP4, &dvr_dpo);
+    fib_test_lb_bucket_t ip_o_l2 = {
+        .type = FT_LB_L2,
+        .adj = {
+            .adj = dvr_dpo.dpoi_index,
+        },
+    };
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &ip_o_l2),
+             "10.10.10.3 via L2 on Eth0");
+    fib_table_entry_path_remove(fib_index,
+                                &pfx_10_10_10_3_s_32,
+                                FIB_SOURCE_API,
+                                DPO_PROTO_IP4,
+                                &zero_addr,
+                                tm->hw[0]->sw_if_index,
+                                fib_index,
+                                1,
+                                FIB_ROUTE_PATH_DVR);
+    dpo_reset(&dvr_dpo);
+
     /*
      * CLEANUP
      *    remove adj-fibs: 
@@ -3685,7 +4216,7 @@ fib_test_v4 (void)
     /*
      * -2 entries and -2 non-shared path-list
      */
-    FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
+    FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
             fib_path_list_db_size());
     FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
             fib_path_list_pool_size());
@@ -3708,7 +4239,7 @@ fib_test_v4 (void)
                                              FIB_SOURCE_INTERFACE)),
              "NO INterface Source'd prefixes");
 
-    fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
+    fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
 
     FIB_TEST((0  == fib_path_list_db_size()), "path list DB population:%d",
             fib_path_list_db_size());
@@ -3718,6 +4249,12 @@ fib_test_v4 (void)
             fib_entry_pool_size());
     FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
             pool_elts(fib_urpf_list_pool));
+    FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
+            pool_elts(load_balance_map_pool));
+    FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
+             pool_elts(load_balance_pool));
+    FIB_TEST((0 == pool_elts(dvr_dpo_pool)), "L2 DPO pool size is %d",
+             pool_elts(dvr_dpo_pool));
 
     return 0;
 }
@@ -3755,7 +4292,8 @@ fib_test_v6 (void)
     dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
 
     /* Find or create FIB table 11 */
-    fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
+    fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
+                                                  FIB_SOURCE_API);
 
     for (ii = 0; ii < 4; ii++)
     {
@@ -3823,7 +4361,7 @@ fib_test_v6 (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_ATTACHED),
-                                   FIB_PROTOCOL_IP6,
+                                   DPO_PROTO_IP6,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0,
@@ -3854,7 +4392,7 @@ fib_test_v6 (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_LOCAL),
-                                   FIB_PROTOCOL_IP6,
+                                   DPO_PROTO_IP6,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -3899,7 +4437,7 @@ fib_test_v6 (void)
     fib_table_entry_path_add(fib_index, &pfx_0_0,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP6,
+                            DPO_PROTO_IP6,
                             &nh_2001_2,
                             tm->hw[0]->sw_if_index,
                             ~0,
@@ -3943,7 +4481,7 @@ fib_test_v6 (void)
      */
     fib_table_entry_path_remove(fib_index, &pfx_0_0,
                                FIB_SOURCE_API, 
-                               FIB_PROTOCOL_IP6,
+                               DPO_PROTO_IP6,
                                &nh_2001_2,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -4016,17 +4554,17 @@ fib_test_v6 (void)
                                    &adj->sub_type.nbr.next_hop)),
              "adj nbr next-hop ok");
 
-    fib_table_entry_update_one_path(fib_index,
-                                   &pfx_2001_1_2_s_128,
-                                   FIB_SOURCE_ADJ,
-                                   FIB_ENTRY_FLAG_ATTACHED,
-                                   FIB_PROTOCOL_IP6,
-                                   &pfx_2001_1_2_s_128.fp_addr,
-                                   tm->hw[0]->sw_if_index,
-                                   ~0,
-                                   1,
-                                   NULL,
-                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fib_table_entry_path_add(fib_index,
+                             &pfx_2001_1_2_s_128,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP6,
+                             &pfx_2001_1_2_s_128.fp_addr,
+                             tm->hw[0]->sw_if_index,
+                             ~0,
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
 
     fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
     ai = fib_entry_get_adj(fei);
@@ -4055,17 +4593,17 @@ fib_test_v6 (void)
              "adj nbr next-hop ok");
     FIB_TEST((ai_01 != ai_02), "ADJs are different");
 
-    fib_table_entry_update_one_path(fib_index,
-                                   &pfx_2001_1_3_s_128,
-                                   FIB_SOURCE_ADJ,
-                                   FIB_ENTRY_FLAG_ATTACHED,
-                                   FIB_PROTOCOL_IP6,
-                                   &pfx_2001_1_3_s_128.fp_addr,
-                                   tm->hw[0]->sw_if_index,
-                                   ~0,
-                                   1,
-                                   NULL,
-                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fib_table_entry_path_add(fib_index,
+                             &pfx_2001_1_3_s_128,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP6,
+                             &pfx_2001_1_3_s_128.fp_addr,
+                             tm->hw[0]->sw_if_index,
+                             ~0,
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
 
     fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
     ai = fib_entry_get_adj(fei);
@@ -4113,7 +4651,7 @@ fib_test_v6 (void)
                             &pfx_2001_a_s_64,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP6,
+                            DPO_PROTO_IP6,
                             &nh_2001_2,
                             tm->hw[0]->sw_if_index,
                             ~0,
@@ -4127,7 +4665,7 @@ fib_test_v6 (void)
                             &pfx_2001_b_s_64,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP6,
+                            DPO_PROTO_IP6,
                             &nh_2001_2,
                             tm->hw[0]->sw_if_index,
                             ~0,
@@ -4162,7 +4700,7 @@ fib_test_v6 (void)
                                   &pfx_1_1_1_1_s_32,
                                   FIB_SOURCE_API,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP6,
+                                  DPO_PROTO_IP6,
                                   &nh_2001_2,
                                   tm->hw[0]->sw_if_index,
                                   ~0,
@@ -4200,7 +4738,7 @@ fib_test_v6 (void)
                             &pfx_2001_c_s_64,
                             FIB_SOURCE_CLI,
                             FIB_ENTRY_FLAG_ATTACHED,
-                            FIB_PROTOCOL_IP6,
+                            DPO_PROTO_IP6,
                             NULL,
                             tm->hw[0]->sw_if_index,
                             ~0,
@@ -4217,7 +4755,7 @@ fib_test_v6 (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_2001_c_s_64,
                                FIB_SOURCE_CLI,
-                               FIB_PROTOCOL_IP6,
+                               DPO_PROTO_IP6,
                                NULL,
                                tm->hw[0]->sw_if_index,
                                ~0,
@@ -4302,7 +4840,7 @@ fib_test_v6 (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_ATTACHED),
-                                   FIB_PROTOCOL_IP6,
+                                   DPO_PROTO_IP6,
                                    NULL,
                                    tm->hw[1]->sw_if_index,
                                    ~0,
@@ -4321,7 +4859,7 @@ fib_test_v6 (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_LOCAL),
-                                   FIB_PROTOCOL_IP6,
+                                   DPO_PROTO_IP6,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -4579,7 +5117,7 @@ fib_test_v6 (void)
     /*
      * now remove the VRF
      */
-    fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
+    fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
 
     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
             fib_path_list_db_size());
@@ -4649,7 +5187,7 @@ fib_test_ae (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_ATTACHED),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0,
@@ -4665,7 +5203,7 @@ fib_test_ae (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_LOCAL),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -4690,17 +5228,17 @@ fib_test_ae (void)
     };
     fib_node_index_t ai;
 
-    fib_table_entry_update_one_path(fib_index,
-                                   &pfx_10_10_10_1_s_32,
-                                   FIB_SOURCE_ADJ,
-                                   FIB_ENTRY_FLAG_ATTACHED,
-                                   FIB_PROTOCOL_IP4,
-                                   &pfx_10_10_10_1_s_32.fp_addr,
-                                   tm->hw[0]->sw_if_index,
-                                   ~0, // invalid fib index
-                                   1,
-                                   NULL,
-                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fib_table_entry_path_add(fib_index,
+                             &pfx_10_10_10_1_s_32,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP4,
+                             &pfx_10_10_10_1_s_32.fp_addr,
+                             tm->hw[0]->sw_if_index,
+                             ~0, // invalid fib index
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
 
     fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
@@ -4711,7 +5249,9 @@ fib_test_ae (void)
      */
     u32 import_fib_index1;
 
-    import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
+    import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
+                                                          11,
+                                                          FIB_SOURCE_CLI);
 
     /*
      * Add an attached route in the import FIB
@@ -4721,7 +5261,7 @@ fib_test_ae (void)
                                    &local_pfx,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -4759,17 +5299,17 @@ fib_test_ae (void)
        },
     };
 
-    fib_table_entry_update_one_path(fib_index,
-                                   &pfx_10_10_10_2_s_32,
-                                   FIB_SOURCE_ADJ,
-                                   FIB_ENTRY_FLAG_ATTACHED,
-                                   FIB_PROTOCOL_IP4,
-                                   &pfx_10_10_10_2_s_32.fp_addr,
-                                   tm->hw[0]->sw_if_index,
-                                   ~0, // invalid fib index
-                                   1,
-                                   NULL,
-                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fib_table_entry_path_add(fib_index,
+                             &pfx_10_10_10_2_s_32,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP4,
+                             &pfx_10_10_10_2_s_32.fp_addr,
+                             tm->hw[0]->sw_if_index,
+                             ~0, // invalid fib index
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
     ai = fib_entry_get_adj(fei);
@@ -4787,7 +5327,8 @@ fib_test_ae (void)
      */
     u32 import_fib_index2;
 
-    import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
+    import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
+                                                          FIB_SOURCE_CLI);
 
     /*
      * Add an attached route in the import FIB
@@ -4797,7 +5338,7 @@ fib_test_ae (void)
                                    &local_pfx,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -4830,17 +5371,17 @@ fib_test_ae (void)
        },
     };
 
-    fib_table_entry_update_one_path(fib_index,
-                                   &pfx_10_10_10_3_s_32,
-                                   FIB_SOURCE_ADJ,
-                                   FIB_ENTRY_FLAG_ATTACHED,
-                                   FIB_PROTOCOL_IP4,
-                                   &pfx_10_10_10_3_s_32.fp_addr,
-                                   tm->hw[0]->sw_if_index,
-                                   ~0, // invalid fib index
-                                   1,
-                                   NULL,
-                                   FIB_ROUTE_PATH_FLAG_NONE);
+    fib_table_entry_path_add(fib_index,
+                             &pfx_10_10_10_3_s_32,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP4,
+                             &pfx_10_10_10_3_s_32.fp_addr,
+                             tm->hw[0]->sw_if_index,
+                             ~0, // invalid fib index
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
     ai = fib_entry_get_adj(fei);
@@ -4906,7 +5447,7 @@ fib_test_ae (void)
                                    &local_pfx,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &pfx_10_10_10_2_s_32.fp_addr,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -4929,7 +5470,7 @@ fib_test_ae (void)
                                    &local_pfx,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -4961,7 +5502,7 @@ fib_test_ae (void)
                                           &pfx_10_0_0_0_s_8,
                                           FIB_SOURCE_API,
                                           FIB_ENTRY_FLAG_NONE,
-                                         FIB_PROTOCOL_IP4,
+                                         DPO_PROTO_IP4,
                                           &pfx_10_10_10_3_s_32.fp_addr,
                                           tm->hw[0]->sw_if_index,
                                           ~0, // invalid fib index
@@ -5017,7 +5558,7 @@ fib_test_ae (void)
                                           &local_pfx,
                                           FIB_SOURCE_API,
                                           FIB_ENTRY_FLAG_NONE,
-                                         FIB_PROTOCOL_IP4,
+                                         DPO_PROTO_IP4,
                                           &pfx_10_10_10_1_s_32.fp_addr,
                                           tm->hw[0]->sw_if_index,
                                           ~0, // invalid fib index
@@ -5053,7 +5594,7 @@ fib_test_ae (void)
                                    &local_pfx,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -5092,7 +5633,7 @@ fib_test_ae (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_ATTACHED),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0,
@@ -5149,8 +5690,8 @@ fib_test_ae (void)
                           &local_pfx,
                           FIB_SOURCE_API);
 
-    fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
-    fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
+    fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
+    fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
 
     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
             adj_nbr_db_size());
@@ -5158,6 +5699,459 @@ fib_test_ae (void)
     return (0);
 }
 
+/*
+ * Test Path Preference
+ */
+static int
+fib_test_pref (void)
+{
+    test_main_t *tm = &test_main;
+
+    const fib_prefix_t pfx_1_1_1_1_s_32 = {
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_addr = {
+            .ip4 = {
+                .as_u32 = clib_host_to_net_u32(0x01010101),
+            },
+        },
+    };
+
+    /*
+     * 2 high, 2 medium and 2 low preference non-recursive paths
+     */
+    fib_route_path_t nr_path_hi_1 = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = tm->hw[0]->sw_if_index,
+        .frp_fib_index = ~0,
+        .frp_weight = 1,
+        .frp_preference = 0,
+        .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+        .frp_addr = {
+            .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
+        },
+    };
+    fib_route_path_t nr_path_hi_2 = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = tm->hw[0]->sw_if_index,
+        .frp_fib_index = ~0,
+        .frp_weight = 1,
+        .frp_preference = 0,
+        .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+        .frp_addr = {
+            .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
+        },
+    };
+    fib_route_path_t nr_path_med_1 = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = tm->hw[1]->sw_if_index,
+        .frp_fib_index = ~0,
+        .frp_weight = 1,
+        .frp_preference = 1,
+        .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+        .frp_addr = {
+            .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
+        },
+    };
+    fib_route_path_t nr_path_med_2 = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = tm->hw[1]->sw_if_index,
+        .frp_fib_index = ~0,
+        .frp_weight = 1,
+        .frp_preference = 1,
+        .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+        .frp_addr = {
+            .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
+        },
+    };
+    fib_route_path_t nr_path_low_1 = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = tm->hw[2]->sw_if_index,
+        .frp_fib_index = ~0,
+        .frp_weight = 1,
+        .frp_preference = 2,
+        .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+        .frp_addr = {
+            .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
+        },
+    };
+    fib_route_path_t nr_path_low_2 = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = tm->hw[2]->sw_if_index,
+        .frp_fib_index = ~0,
+        .frp_weight = 1,
+        .frp_preference = 2,
+        .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+        .frp_addr = {
+            .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
+        },
+    };
+    fib_route_path_t *nr_paths = NULL;
+
+    vec_add1(nr_paths, nr_path_hi_1);
+    vec_add1(nr_paths, nr_path_hi_2);
+    vec_add1(nr_paths, nr_path_med_1);
+    vec_add1(nr_paths, nr_path_med_2);
+    vec_add1(nr_paths, nr_path_low_1);
+    vec_add1(nr_paths, nr_path_low_2);
+
+    adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                              VNET_LINK_IP4,
+                                              &nr_path_hi_1.frp_addr,
+                                              nr_path_hi_1.frp_sw_if_index);
+    adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                              VNET_LINK_IP4,
+                                              &nr_path_hi_2.frp_addr,
+                                              nr_path_hi_2.frp_sw_if_index);
+    adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                               VNET_LINK_IP4,
+                                               &nr_path_med_1.frp_addr,
+                                               nr_path_med_1.frp_sw_if_index);
+    adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                               VNET_LINK_IP4,
+                                               &nr_path_med_2.frp_addr,
+                                               nr_path_med_2.frp_sw_if_index);
+    adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                               VNET_LINK_IP4,
+                                               &nr_path_low_1.frp_addr,
+                                               nr_path_low_1.frp_sw_if_index);
+    adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                               VNET_LINK_IP4,
+                                               &nr_path_low_2.frp_addr,
+                                               nr_path_low_2.frp_sw_if_index);
+
+    fib_test_lb_bucket_t ip_hi_1 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_hi_1,
+        },
+    };
+    fib_test_lb_bucket_t ip_hi_2 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_hi_2,
+        },
+    };
+    fib_test_lb_bucket_t ip_med_1 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_med_1,
+        },
+    };
+    fib_test_lb_bucket_t ip_med_2 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_med_2,
+        },
+    };
+    fib_test_lb_bucket_t ip_low_1 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_low_1,
+        },
+    };
+    fib_test_lb_bucket_t ip_low_2 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_low_2,
+        },
+    };
+
+    fib_node_index_t fei;
+
+    fei = fib_table_entry_path_add2(0,
+                                    &pfx_1_1_1_1_s_32,
+                                    FIB_SOURCE_API,
+                                    FIB_ENTRY_FLAG_NONE,
+                                    nr_paths);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &ip_hi_1,
+                                     &ip_hi_2),
+             "1.1.1.1/32 via high preference paths");
+
+    /*
+     * bring down the interface on which the high preference path lie
+     */
+    vnet_sw_interface_set_flags(vnet_get_main(),
+                                tm->hw[0]->sw_if_index,
+                                0);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &ip_med_1,
+                                     &ip_med_2),
+             "1.1.1.1/32 via medium preference paths");
+
+    /*
+     * bring down the interface on which the medium preference path lie
+     */
+    vnet_sw_interface_set_flags(vnet_get_main(),
+                                tm->hw[1]->sw_if_index,
+                                0);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &ip_low_1,
+                                     &ip_low_2),
+             "1.1.1.1/32 via low preference paths");
+
+    /*
+     * bring up the interface on which the high preference path lie
+     */
+    vnet_sw_interface_set_flags(vnet_get_main(),
+                                tm->hw[0]->sw_if_index,
+                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &ip_hi_1,
+                                     &ip_hi_2),
+             "1.1.1.1/32 via high preference paths");
+
+    /*
+     * bring up the interface on which the medium preference path lie
+     */
+    vnet_sw_interface_set_flags(vnet_get_main(),
+                                tm->hw[1]->sw_if_index,
+                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &ip_hi_1,
+                                     &ip_hi_2),
+             "1.1.1.1/32 via high preference paths");
+
+    dpo_id_t ip_1_1_1_1 = DPO_INVALID;
+    fib_entry_contribute_forwarding(fei,
+                                    FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                    &ip_1_1_1_1);
+
+    /*
+     * 3 recursive paths of different preference
+     */
+    const fib_prefix_t pfx_1_1_1_2_s_32 = {
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_addr = {
+            .ip4 = {
+                .as_u32 = clib_host_to_net_u32(0x01010102),
+            },
+        },
+    };
+    const fib_prefix_t pfx_1_1_1_3_s_32 = {
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_addr = {
+            .ip4 = {
+                .as_u32 = clib_host_to_net_u32(0x01010103),
+            },
+        },
+    };
+    fei = fib_table_entry_path_add2(0,
+                                    &pfx_1_1_1_2_s_32,
+                                    FIB_SOURCE_API,
+                                    FIB_ENTRY_FLAG_NONE,
+                                    nr_paths);
+    dpo_id_t ip_1_1_1_2 = DPO_INVALID;
+    fib_entry_contribute_forwarding(fei,
+                                    FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                    &ip_1_1_1_2);
+    fei = fib_table_entry_path_add2(0,
+                                    &pfx_1_1_1_3_s_32,
+                                    FIB_SOURCE_API,
+                                    FIB_ENTRY_FLAG_NONE,
+                                    nr_paths);
+    dpo_id_t ip_1_1_1_3 = DPO_INVALID;
+    fib_entry_contribute_forwarding(fei,
+                                    FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                    &ip_1_1_1_3);
+
+    fib_test_lb_bucket_t ip_o_1_1_1_1 = {
+        .type = FT_LB_O_LB,
+        .lb = {
+            .lb = ip_1_1_1_1.dpoi_index,
+        },
+    };
+    fib_test_lb_bucket_t ip_o_1_1_1_2 = {
+        .type = FT_LB_O_LB,
+        .lb = {
+            .lb = ip_1_1_1_2.dpoi_index,
+        },
+    };
+    fib_test_lb_bucket_t ip_o_1_1_1_3 = {
+        .type = FT_LB_O_LB,
+        .lb = {
+            .lb = ip_1_1_1_3.dpoi_index,
+        },
+    };
+    fib_route_path_t r_path_hi = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = ~0,
+        .frp_fib_index = 0,
+        .frp_weight = 1,
+        .frp_preference = 0,
+        .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
+        .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
+    };
+    fib_route_path_t r_path_med = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = ~0,
+        .frp_fib_index = 0,
+        .frp_weight = 1,
+        .frp_preference = 10,
+        .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+        .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
+    };
+    fib_route_path_t r_path_low = {
+        .frp_proto = DPO_PROTO_IP4,
+        .frp_sw_if_index = ~0,
+        .frp_fib_index = 0,
+        .frp_weight = 1,
+        .frp_preference = 255,
+        .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
+        .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
+    };
+    fib_route_path_t *r_paths = NULL;
+
+    vec_add1(r_paths, r_path_hi);
+    vec_add1(r_paths, r_path_low);
+    vec_add1(r_paths, r_path_med);
+
+    /*
+     * add many recursive so we get the LB MAp created
+     */
+    #define N_PFXS 64
+    fib_prefix_t pfx_r[N_PFXS];
+    unsigned int n_pfxs;
+    for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
+    {
+        pfx_r[n_pfxs].fp_len = 32;
+        pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
+        pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
+            clib_host_to_net_u32(0x02000000 + n_pfxs);
+
+        fei = fib_table_entry_path_add2(0,
+                                        &pfx_r[n_pfxs],
+                                        FIB_SOURCE_API,
+                                        FIB_ENTRY_FLAG_NONE,
+                                        r_paths);
+
+        FIB_TEST(fib_test_validate_entry(fei,
+                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                         1,
+                                         &ip_o_1_1_1_1),
+                 "recursive via high preference paths");
+
+        /*
+         * withdraw hig pref resolving entry
+         */
+        fib_table_entry_delete(0,
+                               &pfx_1_1_1_1_s_32,
+                               FIB_SOURCE_API);
+
+        /* suspend so the update walk kicks int */
+        vlib_process_suspend(vlib_get_main(), 1e-5);
+
+        FIB_TEST(fib_test_validate_entry(fei,
+                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                         1,
+                                         &ip_o_1_1_1_2),
+                 "recursive via medium preference paths");
+
+        /*
+         * withdraw medium pref resolving entry
+         */
+        fib_table_entry_delete(0,
+                               &pfx_1_1_1_2_s_32,
+                               FIB_SOURCE_API);
+
+        /* suspend so the update walk kicks int */
+        vlib_process_suspend(vlib_get_main(), 1e-5);
+
+        FIB_TEST(fib_test_validate_entry(fei,
+                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                         1,
+                                         &ip_o_1_1_1_3),
+                 "recursive via low preference paths");
+
+        /*
+         * add back paths for next iteration
+         */
+        fei = fib_table_entry_update(0,
+                                     &pfx_1_1_1_2_s_32,
+                                     FIB_SOURCE_API,
+                                     FIB_ENTRY_FLAG_NONE,
+                                     nr_paths);
+        fei = fib_table_entry_update(0,
+                                     &pfx_1_1_1_1_s_32,
+                                     FIB_SOURCE_API,
+                                     FIB_ENTRY_FLAG_NONE,
+                                     nr_paths);
+
+        /* suspend so the update walk kicks int */
+        vlib_process_suspend(vlib_get_main(), 1e-5);
+
+        fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
+        FIB_TEST(fib_test_validate_entry(fei,
+                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                         1,
+                                         &ip_o_1_1_1_1),
+                 "recursive via high preference paths");
+    }
+
+
+    fib_table_entry_delete(0,
+                           &pfx_1_1_1_1_s_32,
+                           FIB_SOURCE_API);
+
+    /* suspend so the update walk kicks int */
+    vlib_process_suspend(vlib_get_main(), 1e-5);
+
+    for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
+    {
+        fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
+
+        FIB_TEST(fib_test_validate_entry(fei,
+                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                         1,
+                                         &ip_o_1_1_1_2),
+                 "recursive via medium preference paths");
+    }
+    for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
+    {
+        fib_table_entry_delete(0,
+                               &pfx_r[n_pfxs],
+                               FIB_SOURCE_API);
+    }
+
+    /*
+     * Cleanup
+     */
+    fib_table_entry_delete(0,
+                           &pfx_1_1_1_2_s_32,
+                           FIB_SOURCE_API);
+    fib_table_entry_delete(0,
+                           &pfx_1_1_1_3_s_32,
+                           FIB_SOURCE_API);
+
+    dpo_reset(&ip_1_1_1_1);
+    dpo_reset(&ip_1_1_1_2);
+    dpo_reset(&ip_1_1_1_3);
+    adj_unlock(ai_low_2);
+    adj_unlock(ai_low_1);
+    adj_unlock(ai_med_2);
+    adj_unlock(ai_med_1);
+    adj_unlock(ai_hi_2);
+    adj_unlock(ai_hi_1);
+    return (0);
+}
 
 /*
  * Test the recursive route route handling for GRE tunnels
@@ -5200,7 +6194,7 @@ fib_test_label (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_ATTACHED),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0,
@@ -5216,7 +6210,7 @@ fib_test_label (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_LOCAL),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -5246,7 +6240,7 @@ fib_test_label (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_ATTACHED),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[1]->sw_if_index,
                                    ~0,
@@ -5262,7 +6256,7 @@ fib_test_label (void)
                                    FIB_SOURCE_INTERFACE,
                                    (FIB_ENTRY_FLAG_CONNECTED |
                                     FIB_ENTRY_FLAG_LOCAL),
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    NULL,
                                    tm->hw[1]->sw_if_index,
                                    ~0, // invalid fib index
@@ -5344,7 +6338,7 @@ fib_test_label (void)
                                    &pfx_1_1_1_1_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &nh_10_10_10_1,
                                    tm->hw[0]->sw_if_index,
                                    ~0, // invalid fib index
@@ -5383,7 +6377,7 @@ fib_test_label (void)
                                   &pfx_1_1_1_1_s_32,
                                   FIB_SOURCE_API,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &nh_10_10_11_1,
                                   tm->hw[1]->sw_if_index,
                                   ~0, // invalid fib index
@@ -5417,6 +6411,12 @@ fib_test_label (void)
        .fp_label = 24001,
        .fp_eos = MPLS_NON_EOS,
     };
+    fib_test_lb_bucket_t disp_o_10_10_11_1 = {
+       .type = FT_LB_MPLS_DISP_O_ADJ,
+       .adj = {
+           .adj = ai_v4_10_10_11_1,
+       },
+    };
 
     /*
      * The EOS entry should link to both the paths,
@@ -5430,10 +6430,10 @@ fib_test_label (void)
                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
                                     2,
                                     &l99_eos_o_10_10_10_1,
-                                    &a_o_10_10_11_1),
+                                    &disp_o_10_10_11_1),
             "24001/eos LB 2 buckets via: "
             "label 99 over 10.10.10.1, "
-            "adj over 10.10.11.1");
+            "mpls disp adj over 10.10.11.1");
 
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
@@ -5456,12 +6456,19 @@ fib_test_label (void)
            .adj = ai_v4_10_10_11_2,
        },
     };
+    fib_test_lb_bucket_t disp_o_10_10_11_2 = {
+       .type = FT_LB_MPLS_DISP_O_ADJ,
+       .adj = {
+           .adj = ai_v4_10_10_11_2,
+       },
+    };
+
 
     fei = fib_table_entry_path_add(fib_index,
                                   &pfx_1_1_1_1_s_32,
                                   FIB_SOURCE_API,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &nh_10_10_11_2,
                                   tm->hw[1]->sw_if_index,
                                   ~0, // invalid fib index
@@ -5541,7 +6548,7 @@ fib_test_label (void)
                                    &pfx_2_2_2_2_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &pfx_1_1_1_1_s_32.fp_addr,
                                    ~0,
                                    fib_index,
@@ -5604,11 +6611,11 @@ fib_test_label (void)
     FIB_TEST(fib_test_validate_entry(fei, 
                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
                                     2,
-                                    &a_o_10_10_11_1,
-                                    &adj_o_10_10_11_2),
+                                    &disp_o_10_10_11_1,
+                                    &disp_o_10_10_11_2),
             "24001/eos LB 2 buckets via: "
-            "adj over 10.10.11.1, ",
-            "adj-v4 over 10.10.11.2");
+            "mpls-disp adj over 10.10.11.1, ",
+            "mpls-disp adj-v4 over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
                           &pfx_24001_neos);
@@ -5681,20 +6688,20 @@ fib_test_label (void)
                                     &l99_eos_o_10_10_10_1,
                                     &l99_eos_o_10_10_10_1,
                                     &l99_eos_o_10_10_10_1,
-                                    &a_o_10_10_11_1,
-                                    &a_o_10_10_11_1,
-                                    &a_o_10_10_11_1,
-                                    &a_o_10_10_11_1,
-                                    &a_o_10_10_11_1,
-                                    &adj_o_10_10_11_2,
-                                    &adj_o_10_10_11_2,
-                                    &adj_o_10_10_11_2,
-                                    &adj_o_10_10_11_2,
-                                    &adj_o_10_10_11_2),
+                                    &disp_o_10_10_11_1,
+                                    &disp_o_10_10_11_1,
+                                    &disp_o_10_10_11_1,
+                                    &disp_o_10_10_11_1,
+                                    &disp_o_10_10_11_1,
+                                    &disp_o_10_10_11_2,
+                                    &disp_o_10_10_11_2,
+                                    &disp_o_10_10_11_2,
+                                    &disp_o_10_10_11_2,
+                                    &disp_o_10_10_11_2),
             "24001/eos LB 16 buckets via: "
             "label 99 over 10.10.10.1, "
-            "adj over 10.10.11.1",
-            "adj-v4 over 10.10.11.2");
+            "MPLS disp adj over 10.10.11.1",
+            "MPLS disp adj-v4 over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
                           &pfx_24001_neos);
@@ -5713,7 +6720,7 @@ fib_test_label (void)
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_1_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_10_1,
                                tm->hw[0]->sw_if_index,
                                ~0, // invalid fib index
@@ -5727,7 +6734,7 @@ fib_test_label (void)
                                     &a_o_10_10_11_1,
                                     &adj_o_10_10_11_2),
             "1.1.1.1/32 LB 2 buckets via: "
-            "adj over 10.10.11.1",
+            "adj over 10.10.11.1, "
             "adj-v4 over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
@@ -5735,11 +6742,11 @@ fib_test_label (void)
     FIB_TEST(fib_test_validate_entry(fei, 
                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
                                     2,
-                                    &a_o_10_10_11_1,
-                                    &adj_o_10_10_11_2),
+                                    &disp_o_10_10_11_1,
+                                    &disp_o_10_10_11_2),
             "24001/eos LB 2 buckets via: "
-            "adj over 10.10.11.1",
-            "adj-v4 over 10.10.11.2");
+            "MPLS disp adj over 10.10.11.1, "
+            "MPLS disp adj-v4 over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
                           &pfx_24001_neos);
@@ -5755,16 +6762,19 @@ fib_test_label (void)
      * remove the other path with a valid label
      */
     fib_test_lb_bucket_t bucket_drop = {
-       .type = FT_LB_SPECIAL,
+       .type = FT_LB_DROP,
+    };
+    fib_test_lb_bucket_t mpls_bucket_drop = {
+       .type = FT_LB_DROP,
        .special = {
-           .adj = DPO_PROTO_IP4,
+           .adj = DPO_PROTO_MPLS,
        },
     };
 
     fib_table_entry_path_remove(fib_index,
                                &pfx_1_1_1_1_s_32,
                                FIB_SOURCE_API,
-                               FIB_PROTOCOL_IP4,
+                               DPO_PROTO_IP4,
                                &nh_10_10_11_1,
                                tm->hw[1]->sw_if_index,
                                ~0, // invalid fib index
@@ -5784,17 +6794,17 @@ fib_test_label (void)
     FIB_TEST(fib_test_validate_entry(fei, 
                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
                                     1,
-                                    &adj_o_10_10_11_2),
+                                    &disp_o_10_10_11_2),
             "24001/eos LB 1 buckets via: "
-            "adj over 10.10.11.2");
+            "MPLS disp adj over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
                           &pfx_24001_neos);
     FIB_TEST(fib_test_validate_entry(fei, 
                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
-                                     1,
-                                     &bucket_drop),
-            "24001/eos LB 1 buckets via: DROP");
+                                     1,
+                                     &mpls_bucket_drop),
+            "24001/neos LB 1 buckets via: DROP");
 
     /*
      * add back the path with the valid label
@@ -5806,7 +6816,7 @@ fib_test_label (void)
                             &pfx_1_1_1_1_s_32,
                             FIB_SOURCE_API,
                             FIB_ENTRY_FLAG_NONE,
-                            FIB_PROTOCOL_IP4,
+                            DPO_PROTO_IP4,
                             &nh_10_10_10_1,
                             tm->hw[0]->sw_if_index,
                             ~0, // invalid fib index
@@ -5830,10 +6840,10 @@ fib_test_label (void)
                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
                                     2,
                                     &l99_eos_o_10_10_10_1,
-                                    &adj_o_10_10_11_2),
+                                    &disp_o_10_10_11_2),
             "24001/eos LB 2 buckets via: "
             "label 99 over 10.10.10.1, "
-            "adj over 10.10.11.2");
+            "MPLS disp adj over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
                           &pfx_24001_neos);
@@ -5875,10 +6885,10 @@ fib_test_label (void)
                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
                                     2,
                                     &l99_eos_o_10_10_10_1,
-                                    &adj_o_10_10_11_2),
+                                    &disp_o_10_10_11_2),
             "25005/eos LB 2 buckets via: "
             "label 99 over 10.10.10.1, "
-            "adj over 10.10.11.2");
+            "MPLS disp adj over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
                           &pfx_25005_neos);
@@ -5937,7 +6947,7 @@ fib_test_label (void)
                                          &pfx_1_1_1_2_s_32,
                                          FIB_SOURCE_API,
                                          FIB_ENTRY_FLAG_NONE,
-                                         FIB_PROTOCOL_IP4,
+                                         DPO_PROTO_IP4,
                                          &nh_10_10_10_1,
                                          tm->hw[0]->sw_if_index,
                                          ~0, // invalid fib index
@@ -5979,7 +6989,7 @@ fib_test_label (void)
                                   &pfx_2_2_2_2_s_32,
                                   FIB_SOURCE_API,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &pfx_1_1_1_2_s_32.fp_addr,
                                   ~0,
                                   fib_index,
@@ -6007,7 +7017,7 @@ fib_test_label (void)
                                          &pfx_1_1_1_2_s_32,
                                          FIB_SOURCE_API,
                                          FIB_ENTRY_FLAG_NONE,
-                                         FIB_PROTOCOL_IP4,
+                                         DPO_PROTO_IP4,
                                          &nh_10_10_11_1,
                                          tm->hw[1]->sw_if_index,
                                          ~0, // invalid fib index
@@ -6040,7 +7050,7 @@ fib_test_label (void)
                                          &pfx_1_1_1_2_s_32,
                                          FIB_SOURCE_API,
                                          FIB_ENTRY_FLAG_NONE,
-                                         FIB_PROTOCOL_IP4,
+                                         DPO_PROTO_IP4,
                                          &nh_10_10_11_1,
                                          tm->hw[1]->sw_if_index,
                                          ~0, // invalid fib index
@@ -6082,7 +7092,7 @@ fib_test_label (void)
                                    &pfx_2_2_2_3_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &pfx_1_1_1_1_s_32.fp_addr,
                                    ~0,
                                    fib_index,
@@ -6126,7 +7136,7 @@ fib_test_label (void)
                                    &pfx_2_2_2_4_s_32,
                                    FIB_SOURCE_API,
                                    FIB_ENTRY_FLAG_NONE,
-                                   FIB_PROTOCOL_IP4,
+                                   DPO_PROTO_IP4,
                                    &pfx_1_1_1_1_s_32.fp_addr,
                                    ~0,
                                    fib_index,
@@ -6176,7 +7186,7 @@ fib_test_label (void)
                                          &pfx_2_2_5_5_s_32,
                                          FIB_SOURCE_API,
                                          FIB_ENTRY_FLAG_NONE,
-                                         FIB_PROTOCOL_IP4,
+                                         DPO_PROTO_IP4,
                                          &nh_10_10_11_1,
                                          tm->hw[1]->sw_if_index,
                                          ~0, // invalid fib index
@@ -6737,6 +7747,509 @@ fib_test_walk (void)
     return (0);
 }
 
+/*
+ * declaration of the otherwise static callback functions
+ */
+void fib_bfd_notify (bfd_listen_event_e event,
+                     const bfd_session_t *session);
+void adj_bfd_notify (bfd_listen_event_e event,
+                     const bfd_session_t *session);
+
+/**
+ * Test BFD session interaction with FIB
+ */
+static int
+fib_test_bfd (void)
+{
+    fib_node_index_t fei;
+    test_main_t *tm;
+    int n_feis;
+
+    /* via 10.10.10.1 */
+    ip46_address_t nh_10_10_10_1 = {
+        .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
+    };
+    /* via 10.10.10.2 */
+    ip46_address_t nh_10_10_10_2 = {
+        .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
+    };
+    /* via 10.10.10.10 */
+    ip46_address_t nh_10_10_10_10 = {
+        .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
+    };
+    n_feis = fib_entry_pool_size();
+
+    tm = &test_main;
+
+    /*
+     * add interface routes. we'll assume this works. it's tested elsewhere
+     */
+    fib_prefix_t pfx_10_10_10_10_s_24 = {
+        .fp_len = 24,
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_addr = nh_10_10_10_10,
+    };
+
+    fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
+                                    FIB_SOURCE_INTERFACE,
+                                    (FIB_ENTRY_FLAG_CONNECTED |
+                                     FIB_ENTRY_FLAG_ATTACHED),
+                                    DPO_PROTO_IP4,
+                                    NULL,
+                                    tm->hw[0]->sw_if_index,
+                                    ~0, // invalid fib index
+                                    1, // weight
+                                    NULL,
+                                    FIB_ROUTE_PATH_FLAG_NONE);
+
+    fib_prefix_t pfx_10_10_10_10_s_32 = {
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_addr = nh_10_10_10_10,
+    };
+    fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
+                                    FIB_SOURCE_INTERFACE,
+                                    (FIB_ENTRY_FLAG_CONNECTED |
+                                     FIB_ENTRY_FLAG_LOCAL),
+                                    DPO_PROTO_IP4,
+                                    NULL,
+                                    tm->hw[0]->sw_if_index,
+                                    ~0, // invalid fib index
+                                    1, // weight
+                                    NULL,
+                                    FIB_ROUTE_PATH_FLAG_NONE);
+
+    /*
+     * A BFD session via a neighbour we do not yet know
+     */
+    bfd_session_t bfd_10_10_10_1 = {
+        .udp = {
+            .key = {
+                .fib_index = 0,
+                .peer_addr = nh_10_10_10_1,
+            },
+        },
+        .hop_type = BFD_HOP_TYPE_MULTI,
+        .local_state = BFD_STATE_init,
+    };
+
+    fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
+
+    /*
+     * A new entry will be created that forwards via the adj
+     */
+    adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                                    VNET_LINK_IP4,
+                                                    &nh_10_10_10_1,
+                                                    tm->hw[0]->sw_if_index);
+    fib_prefix_t pfx_10_10_10_1_s_32 = {
+        .fp_addr = nh_10_10_10_1,
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+    };
+    fib_test_lb_bucket_t adj_o_10_10_10_1 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_10_10_10_1,
+        },
+    };
+
+    fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &adj_o_10_10_10_1),
+             "BFD sourced %U via %U",
+             format_fib_prefix, &pfx_10_10_10_1_s_32,
+             format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
+
+    /*
+     * Delete the BFD session. Expect the fib_entry to be removed
+     */
+    fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
+
+    fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
+    FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
+             "BFD sourced %U removed",
+             format_fib_prefix, &pfx_10_10_10_1_s_32);
+
+    /*
+     * Add the BFD source back
+     */
+    fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
+
+    /*
+     * source the entry via the ADJ fib
+     */
+    fei = fib_table_entry_path_add(0,
+                                   &pfx_10_10_10_1_s_32,
+                                   FIB_SOURCE_ADJ,
+                                   FIB_ENTRY_FLAG_ATTACHED,
+                                   DPO_PROTO_IP4,
+                                   &nh_10_10_10_1,
+                                   tm->hw[0]->sw_if_index,
+                                   ~0, // invalid fib index
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+
+    /*
+     * Delete the BFD session. Expect the fib_entry to remain
+     */
+    fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
+
+    fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &adj_o_10_10_10_1),
+             "BFD sourced %U remains via %U",
+             format_fib_prefix, &pfx_10_10_10_1_s_32,
+             format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
+
+    /*
+     * Add the BFD source back
+     */
+    fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
+
+    /*
+     * Create another ADJ FIB
+     */
+    fib_prefix_t pfx_10_10_10_2_s_32 = {
+        .fp_addr = nh_10_10_10_2,
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+    };
+    fib_table_entry_path_add(0,
+                             &pfx_10_10_10_2_s_32,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP4,
+                             &nh_10_10_10_2,
+                             tm->hw[0]->sw_if_index,
+                             ~0, // invalid fib index
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
+    /*
+     * A BFD session for the new ADJ FIB
+     */
+    bfd_session_t bfd_10_10_10_2 = {
+        .udp = {
+            .key = {
+                .fib_index = 0,
+                .peer_addr = nh_10_10_10_2,
+            },
+        },
+        .hop_type = BFD_HOP_TYPE_MULTI,
+        .local_state = BFD_STATE_init,
+    };
+
+    fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
+
+    /*
+     * remove the adj-fib source whilst the session is present
+     * then add it back
+     */
+    fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
+    fib_table_entry_path_add(0,
+                             &pfx_10_10_10_2_s_32,
+                             FIB_SOURCE_ADJ,
+                             FIB_ENTRY_FLAG_ATTACHED,
+                             DPO_PROTO_IP4,
+                             &nh_10_10_10_2,
+                             tm->hw[0]->sw_if_index,
+                             ~0, // invalid fib index
+                             1,
+                             NULL,
+                             FIB_ROUTE_PATH_FLAG_NONE);
+
+    /*
+     * Before adding a recursive via the BFD tracked ADJ-FIBs,
+     * bring one of the sessions UP, leave the other down
+     */
+    bfd_10_10_10_1.local_state = BFD_STATE_up;
+    fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
+    bfd_10_10_10_2.local_state = BFD_STATE_down;
+    fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
+
+    /*
+     * A recursive prefix via both of the ADJ FIBs
+     */
+    fib_prefix_t pfx_200_0_0_0_s_24 = {
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_len = 32,
+        .fp_addr = {
+            .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
+        },
+    };
+    const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
+
+    dpo_10_10_10_1 =
+        fib_entry_contribute_ip_forwarding(
+            fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
+    dpo_10_10_10_2 =
+        fib_entry_contribute_ip_forwarding(
+            fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
+
+    fib_test_lb_bucket_t lb_o_10_10_10_1 = {
+        .type = FT_LB_O_LB,
+        .lb = {
+            .lb = dpo_10_10_10_1->dpoi_index,
+        },
+    };
+    fib_test_lb_bucket_t lb_o_10_10_10_2 = {
+        .type = FT_LB_O_LB,
+        .lb = {
+            .lb = dpo_10_10_10_2->dpoi_index,
+        },
+    };
+
+    /*
+     * A prefix via the adj-fib that is BFD down => DROP
+     */
+    fei = fib_table_entry_path_add(0,
+                                   &pfx_200_0_0_0_s_24,
+                                   FIB_SOURCE_API,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &nh_10_10_10_2,
+                                   ~0, // recursive
+                                   0, // default fib index
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+    FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
+             "%U resolves via drop",
+             format_fib_prefix, &pfx_200_0_0_0_s_24);
+
+    /*
+     * add a path via the UP BFD adj-fib.
+     *  we expect that the DOWN BFD ADJ FIB is not used.
+     */
+    fei = fib_table_entry_path_add(0,
+                                   &pfx_200_0_0_0_s_24,
+                                   FIB_SOURCE_API,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &nh_10_10_10_1,
+                                   ~0, // recursive
+                                   0, // default fib index
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &lb_o_10_10_10_1),
+             "Recursive %U only UP BFD adj-fibs",
+             format_fib_prefix, &pfx_200_0_0_0_s_24);
+
+    /*
+     * Send a BFD state change to UP - both sessions are now up
+     *  the recursive prefix should LB over both
+     */
+    bfd_10_10_10_2.local_state = BFD_STATE_up;
+    fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
+
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &lb_o_10_10_10_1,
+                                     &lb_o_10_10_10_2),
+             "Recursive %U via both UP BFD adj-fibs",
+             format_fib_prefix, &pfx_200_0_0_0_s_24);
+
+    /*
+     * Send a BFD state change to DOWN
+     *  the recursive prefix should exclude the down
+     */
+    bfd_10_10_10_2.local_state = BFD_STATE_down;
+    fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
+
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &lb_o_10_10_10_1),
+             "Recursive %U via only UP",
+             format_fib_prefix, &pfx_200_0_0_0_s_24);
+
+    /*
+     * Delete the BFD session while it is in the DOWN state.
+     *  FIB should consider the entry's state as back up
+     */
+    fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &lb_o_10_10_10_1,
+                                     &lb_o_10_10_10_2),
+             "Recursive %U via both UP BFD adj-fibs post down session delete",
+             format_fib_prefix, &pfx_200_0_0_0_s_24);
+
+    /*
+     * Delete the BFD other session while it is in the UP state.
+     */
+    fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &lb_o_10_10_10_1,
+                                     &lb_o_10_10_10_2),
+             "Recursive %U via both UP BFD adj-fibs post up session delete",
+             format_fib_prefix, &pfx_200_0_0_0_s_24);
+
+    /*
+     * cleaup
+     */
+    fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
+    fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
+    fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
+
+    fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
+    fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
+
+    adj_unlock(ai_10_10_10_1);
+     /*
+     * test no-one left behind
+     */
+    FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
+    FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
+
+    /*
+     * Single-hop BFD tests
+     */
+    bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
+    bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
+
+    adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
+
+    ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                        VNET_LINK_IP4,
+                                        &nh_10_10_10_1,
+                                        tm->hw[0]->sw_if_index);
+    /*
+     * whilst the BFD session is not signalled, the adj is up
+     */
+    FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
+
+    /*
+     * bring the BFD session up
+     */
+    bfd_10_10_10_1.local_state = BFD_STATE_up;
+    adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
+    FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
+
+    /*
+     * bring the BFD session down
+     */
+    bfd_10_10_10_1.local_state = BFD_STATE_down;
+    adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
+    FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
+
+
+    /*
+     * add an attached next hop FIB entry via the down adj
+     */
+    fib_prefix_t pfx_5_5_5_5_s_32 = {
+        .fp_addr = {
+            .ip4 = {
+                .as_u32 = clib_host_to_net_u32(0x05050505),
+            },
+        },
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+    };
+
+    fei = fib_table_entry_path_add(0,
+                                   &pfx_5_5_5_5_s_32,
+                                   FIB_SOURCE_CLI,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &nh_10_10_10_1,
+                                   tm->hw[0]->sw_if_index,
+                                   ~0, // invalid fib index
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+    FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
+             "%U resolves via drop",
+             format_fib_prefix, &pfx_5_5_5_5_s_32);
+
+    /*
+     * Add a path via an ADJ that is up
+     */
+    adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+                                                    VNET_LINK_IP4,
+                                                    &nh_10_10_10_2,
+                                                    tm->hw[0]->sw_if_index);
+
+    fib_test_lb_bucket_t adj_o_10_10_10_2 = {
+        .type = FT_LB_ADJ,
+        .adj = {
+            .adj = ai_10_10_10_2,
+        },
+    };
+    adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
+
+    fei = fib_table_entry_path_add(0,
+                                   &pfx_5_5_5_5_s_32,
+                                   FIB_SOURCE_CLI,
+                                   FIB_ENTRY_FLAG_NONE,
+                                   DPO_PROTO_IP4,
+                                   &nh_10_10_10_2,
+                                   tm->hw[0]->sw_if_index,
+                                   ~0, // invalid fib index
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     1,
+                                     &adj_o_10_10_10_2),
+             "BFD sourced %U via %U",
+             format_fib_prefix, &pfx_5_5_5_5_s_32,
+             format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
+
+    /*
+     * Bring up the down session - should now LB
+     */
+    bfd_10_10_10_1.local_state = BFD_STATE_up;
+    adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
+    FIB_TEST(fib_test_validate_entry(fei,
+                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
+                                     2,
+                                     &adj_o_10_10_10_1,
+                                     &adj_o_10_10_10_2),
+             "BFD sourced %U via noth adjs",
+             format_fib_prefix, &pfx_5_5_5_5_s_32);
+
+    /*
+     * remove the BFD session state from the adj
+     */
+    adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
+
+    /*
+     * clean-up
+     */
+    fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
+    adj_unlock(ai_10_10_10_1);
+    adj_unlock(ai_10_10_10_2);
+
+    /*
+     * test no-one left behind
+     */
+    FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
+    FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
+    return (0);
+}
+
 static int
 lfib_test (void)
 {
@@ -6760,9 +8273,10 @@ lfib_test (void)
     /*
      * MPLS enable an interface so we get the MPLS table created
      */
+    mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
     mpls_sw_interface_enable_disable(&mpls_main,
                                      tm->hw[0]->sw_if_index,
-                                     1);
+                                     1, 1);
 
     ip46_address_t nh_10_10_10_1 = {
        .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
@@ -6826,7 +8340,7 @@ lfib_test (void)
                                   &pfx,
                                   FIB_SOURCE_CLI,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &zero_addr,
                                   ~0,
                                   fib_index,
@@ -6877,7 +8391,7 @@ lfib_test (void)
                                   &pfx,
                                   FIB_SOURCE_CLI,
                                   FIB_ENTRY_FLAG_NONE,
-                                  FIB_PROTOCOL_IP4,
+                                  DPO_PROTO_IP4,
                                   &zero_addr,
                                   ~0,
                                   lfib_index,
@@ -6955,7 +8469,7 @@ lfib_test (void)
                                          &pfx_1200,
                                          FIB_SOURCE_API,
                                          FIB_ENTRY_FLAG_NONE,
-                                         FIB_PROTOCOL_IP4,
+                                         DPO_PROTO_IP4,
                                          &nh_10_10_10_1,
                                          tm->hw[0]->sw_if_index,
                                          ~0, // invalid fib index
@@ -6981,8 +8495,9 @@ lfib_test (void)
        },
     };
     fib_route_path_t *rpaths = NULL, rpath = {
-       .frp_proto = FIB_PROTOCOL_MPLS,
+        .frp_proto = DPO_PROTO_MPLS,
        .frp_local_label = 1200,
+        .frp_eos = MPLS_NON_EOS,
        .frp_sw_if_index = ~0, // recurive
        .frp_fib_index = 0, // Default MPLS fib
        .frp_weight = 1,
@@ -7063,7 +8578,13 @@ lfib_test (void)
      * A recursive via a label that does not exist
      */
     fib_test_lb_bucket_t bucket_drop = {
-       .type = FT_LB_SPECIAL,
+       .type = FT_LB_DROP,
+       .special = {
+           .adj = DPO_PROTO_IP4,
+       },
+    };
+    fib_test_lb_bucket_t mpls_bucket_drop = {
+       .type = FT_LB_DROP,
        .special = {
            .adj = DPO_PROTO_MPLS,
        },
@@ -7084,29 +8605,178 @@ lfib_test (void)
     FIB_TEST(fib_test_validate_entry(lfe,
                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
                                     1,
-                                    &ip_o_1200),
-            "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
+                                    &bucket_drop),
+            "2.2.2.2.4/32 LB 1 buckets via: drop");
     lfe = fib_table_lookup(fib_index, &pfx_1200);
     FIB_TEST(fib_test_validate_entry(lfe,
                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
                                     1,
                                     &bucket_drop),
-            "2.2.2.4/32 LB 1 buckets via: ip4-DROP");
+            "1200/neos LB 1 buckets via: ip4-DROP");
+    FIB_TEST(fib_test_validate_entry(lfe,
+                                    FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
+                                    1,
+                                    &mpls_bucket_drop),
+            "1200/neos LB 1 buckets via: mpls-DROP");
 
     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
 
     dpo_reset(&ip_1200);
 
+    /*
+     * An rx-interface route.
+     *  like the tail of an mcast LSP
+     */
+    dpo_id_t idpo = DPO_INVALID;
+
+    interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
+                              tm->hw[0]->sw_if_index,
+                              &idpo);
+
+    fib_prefix_t pfx_2500 = {
+       .fp_len = 21,
+       .fp_proto = FIB_PROTOCOL_MPLS,
+       .fp_label = 2500,
+       .fp_eos = MPLS_EOS,
+       .fp_payload_proto = DPO_PROTO_IP4,
+    };
+    fib_test_lb_bucket_t rx_intf_0 = {
+        .type = FT_LB_INTF,
+        .adj = {
+            .adj = idpo.dpoi_index,
+        },
+    };
+
+    lfe = fib_table_entry_update_one_path(fib_index,
+                                         &pfx_2500,
+                                         FIB_SOURCE_API,
+                                         FIB_ENTRY_FLAG_NONE,
+                                         DPO_PROTO_IP4,
+                                         NULL,
+                                         tm->hw[0]->sw_if_index,
+                                         ~0, // invalid fib index
+                                         0,
+                                         NULL,
+                                         FIB_ROUTE_PATH_INTF_RX);
+    FIB_TEST(fib_test_validate_entry(lfe,
+                                    FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+                                    1,
+                                    &rx_intf_0),
+            "2500 rx-interface 0");
+    fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
+
+    /*
+     * An MPLS mulicast entry
+     */
+    fib_prefix_t pfx_3500 = {
+       .fp_len = 21,
+       .fp_proto = FIB_PROTOCOL_MPLS,
+       .fp_label = 3500,
+       .fp_eos = MPLS_EOS,
+       .fp_payload_proto = DPO_PROTO_IP4,
+    };
+    fib_test_rep_bucket_t mc_0 = {
+        .type = FT_REP_LABEL_O_ADJ,
+       .label_o_adj = {
+           .adj = ai_mpls_10_10_10_1,
+           .label = 3300,
+           .eos = MPLS_EOS,
+       },
+    };
+    fib_test_rep_bucket_t mc_intf_0 = {
+        .type = FT_REP_INTF,
+        .adj = {
+            .adj = idpo.dpoi_index,
+        },
+    };
+    mpls_label_t *l3300 = NULL;
+    vec_add1(l3300, 3300);
+
+    lfe = fib_table_entry_update_one_path(lfib_index,
+                                         &pfx_3500,
+                                         FIB_SOURCE_API,
+                                         FIB_ENTRY_FLAG_MULTICAST,
+                                         DPO_PROTO_IP4,
+                                         &nh_10_10_10_1,
+                                         tm->hw[0]->sw_if_index,
+                                         ~0, // invalid fib index
+                                         1,
+                                         l3300,
+                                         FIB_ROUTE_PATH_FLAG_NONE);
+    FIB_TEST(fib_test_validate_entry(lfe,
+                                    FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+                                    1,
+                                    &mc_0),
+            "3500 via replicate over 10.10.10.1");
+
+    /*
+     * MPLS Bud-node. Add a replication via an interface-receieve path
+     */
+    lfe = fib_table_entry_path_add(lfib_index,
+                                  &pfx_3500,
+                                  FIB_SOURCE_API,
+                                  FIB_ENTRY_FLAG_MULTICAST,
+                                  DPO_PROTO_IP4,
+                                   NULL,
+                                   tm->hw[0]->sw_if_index,
+                                   ~0, // invalid fib index
+                                   0,
+                                   NULL,
+                                   FIB_ROUTE_PATH_INTF_RX);
+    FIB_TEST(fib_test_validate_entry(lfe,
+                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+                                     2,
+                                     &mc_0,
+                                     &mc_intf_0),
+            "3500 via replicate over 10.10.10.1 and interface-rx");
+
+    /*
+     * Add a replication via an interface-free for-us path
+     */
+    fib_test_rep_bucket_t mc_disp = {
+        .type = FT_REP_DISP_MFIB_LOOKUP,
+        .adj = {
+            .adj = idpo.dpoi_index,
+        },
+    };
+    lfe = fib_table_entry_path_add(lfib_index,
+                                  &pfx_3500,
+                                  FIB_SOURCE_API,
+                                  FIB_ENTRY_FLAG_MULTICAST,
+                                  DPO_PROTO_IP4,
+                                   NULL,
+                                   5, // rpf-id
+                                   0, // default table
+                                   0,
+                                   NULL,
+                                   FIB_ROUTE_PATH_RPF_ID);
+    FIB_TEST(fib_test_validate_entry(lfe,
+                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+                                     3,
+                                     &mc_0,
+                                     &mc_disp,
+                                     &mc_intf_0),
+            "3500 via replicate over 10.10.10.1 and interface-rx");
+
+
+    
+    fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
+    dpo_reset(&idpo);
+
     /*
      * cleanup
      */
     mpls_sw_interface_enable_disable(&mpls_main,
                                      tm->hw[0]->sw_if_index,
-                                     0);
+                                     0, 1);
+    mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
 
     FIB_TEST(lb_count == pool_elts(load_balance_pool),
             "Load-balance resources freed %d of %d",
              lb_count, pool_elts(load_balance_pool));
+    FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
+            "interface_rx_dpo resources freed %d of %d",
+             0, pool_elts(interface_rx_dpo_pool));
 
     return (0);
 }
@@ -7121,6 +8791,11 @@ fib_test (vlib_main_t * vm,
     res = 0;
     fib_test_mk_intf(4);
 
+    if (unformat (input, "debug"))
+    {
+        fib_test_do_debug = 1;
+    }
+
     if (unformat (input, "ip"))
     {
        res += fib_test_v4();
@@ -7134,6 +8809,10 @@ fib_test (vlib_main_t * vm,
     {
        res += fib_test_ae();
     }
+    else if (unformat (input, "pref"))
+    {
+       res += fib_test_pref();
+    }
     else if (unformat (input, "lfib"))
     {
        res += lfib_test();
@@ -7142,19 +8821,26 @@ fib_test (vlib_main_t * vm,
     {
        res += fib_test_walk();
     }
+    else if (unformat (input, "bfd"))
+    {
+       res += fib_test_bfd();
+    }
     else
     {
-        /*
-         * These walk UT aren't run as part of the full suite, since the
-         * fib-walk process must be disabled in order for the tests to work
-         *
-         * fib_test_walk();
-         */
        res += fib_test_v4();
        res += fib_test_v6();
        res += fib_test_ae();
+       res += fib_test_bfd();
+       res += fib_test_pref();
        res += fib_test_label();
        res += lfib_test();
+
+        /*
+         * fib-walk process must be disabled in order for the walk tests to work
+         */
+        fib_walk_process_disable();
+        res += fib_test_walk();
+        fib_walk_process_enable();
     }
 
     if (res)