LCOV - code coverage report
Current view: top level - plugins/unittest - fib_test.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 2855 2957 96.6 %
Date: 2023-07-05 22:20:52 Functions: 31 32 96.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vnet/fib/fib_test.h>
      17             : #include <vnet/fib/ip6_fib.h>
      18             : #include <vnet/fib/ip4_fib.h>
      19             : #include <vnet/fib/mpls_fib.h>
      20             : #include <vnet/adj/adj.h>
      21             : #include <vnet/dpo/load_balance.h>
      22             : #include <vnet/dpo/load_balance_map.h>
      23             : #include <vnet/dpo/mpls_label_dpo.h>
      24             : #include <vnet/dpo/lookup_dpo.h>
      25             : #include <vnet/dpo/drop_dpo.h>
      26             : #include <vnet/dpo/receive_dpo.h>
      27             : #include <vnet/dpo/ip_null_dpo.h>
      28             : #include <vnet/bfd/bfd_main.h>
      29             : #include <vnet/dpo/interface_rx_dpo.h>
      30             : #include <vnet/dpo/replicate_dpo.h>
      31             : #include <vnet/dpo/dvr_dpo.h>
      32             : #include <vnet/dpo/mpls_disposition.h>
      33             : #include <vnet/dpo/punt_dpo.h>
      34             : 
      35             : #include <vnet/mpls/mpls.h>
      36             : 
      37             : #include <vnet/fib/fib_test.h>
      38             : #include <vnet/fib/fib_path_list.h>
      39             : #include <vnet/fib/fib_entry_src.h>
      40             : #include <vnet/fib/fib_walk.h>
      41             : #include <vnet/fib/fib_node_list.h>
      42             : #include <vnet/fib/fib_urpf_list.h>
      43             : 
      44             : #include <vlib/unix/plugin.h>
      45             : 
      46             : // clang-format off
      47             : 
      48             : /*
      49             :  * Add debugs for passing tests
      50             :  */
      51             : static int fib_test_do_debug;
      52             : 
      53             : #define FIB_TEST_I(_cond, _comment, _args...)                   \
      54             : ({                                                              \
      55             :     int _evald = (_cond);                                       \
      56             :     if (!(_evald)) {                                            \
      57             :         fformat(stderr, "FAIL:%d: " _comment "\n",          \
      58             :                 __LINE__, ##_args);                             \
      59             :         res = 1;                                                \
      60             :     } else {                                                    \
      61             :         if (fib_test_do_debug)                                  \
      62             :             fformat(stderr, "PASS:%d: " _comment "\n",          \
      63             :                     __LINE__, ##_args);                         \
      64             :     }                                                           \
      65             :     res;                                                        \
      66             : })
      67             : #define FIB_TEST(_cond, _comment, _args...)                     \
      68             : {                                                               \
      69             :     if (FIB_TEST_I(_cond, _comment, ##_args)) {                 \
      70             :         return 1;                                               \
      71             :         ASSERT(!("FAIL: " _comment));                         \
      72             :     }                                                           \
      73             : }
      74             : 
      75             : /**
      76             :  * A 'i'm not fussed is this is not efficient' store of test data
      77             :  */
      78             : typedef struct test_main_t_ {
      79             :     /**
      80             :      * HW if indicies
      81             :      */
      82             :     u32 hw_if_indicies[4];
      83             :     /**
      84             :      * HW interfaces
      85             :      */
      86             :     vnet_hw_interface_t * hw[4];
      87             : 
      88             : } test_main_t;
      89             : static test_main_t test_main;
      90             : 
      91             : /* fake ethernet device class, distinct from "fake-ethX" */
      92           9 : static u8 * format_test_interface_name (u8 * s, va_list * args)
      93             : {
      94           9 :   u32 dev_instance = va_arg (*args, u32);
      95           9 :   return format (s, "test-eth%d", dev_instance);
      96             : }
      97             : 
      98           4 : static uword placeholder_interface_tx (vlib_main_t * vm,
      99             :                                  vlib_node_runtime_t * node,
     100             :                                  vlib_frame_t * frame)
     101             : {
     102           4 :     clib_warning ("you shouldn't be here, leaking buffers...");
     103           4 :     return frame->n_vectors;
     104             : }
     105             : 
     106             : static clib_error_t *
     107          16 : test_interface_admin_up_down (vnet_main_t * vnm,
     108             :                               u32 hw_if_index,
     109             :                               u32 flags)
     110             : {
     111          16 :     u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
     112             :         VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
     113          16 :     vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
     114          16 :     return 0;
     115             : }
     116             : 
     117        2799 : VNET_DEVICE_CLASS (test_interface_device_class,static) = {
     118             :     .name = "Test interface",
     119             :     .format_device_name = format_test_interface_name,
     120             :     .tx_function = placeholder_interface_tx,
     121             :     .admin_up_down_function = test_interface_admin_up_down,
     122             : };
     123             : 
     124             : static u8 *hw_address;
     125             : 
     126             : static int
     127           1 : fib_test_mk_intf (u32 ninterfaces)
     128             : {
     129           1 :     clib_error_t * error = NULL;
     130           1 :     test_main_t *tm = &test_main;
     131             :     u32 i, res;
     132             :     u8 byte;
     133             : 
     134           1 :     res = 0;
     135           1 :     ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
     136             : 
     137           7 :     for (i=0; i<6; i++)
     138             :     {
     139           6 :         byte = 0xd0+i;
     140           6 :         vec_add1(hw_address, byte);
     141             :     }
     142             : 
     143           5 :     for (i = 0; i < ninterfaces; i++)
     144             :     {
     145           4 :       vnet_eth_interface_registration_t eir = {};
     146           4 :       vnet_main_t *vnm = vnet_get_main();
     147             : 
     148           4 :         hw_address[5] = i;
     149             : 
     150           4 :        eir.dev_class_index = test_interface_device_class.index;
     151           4 :        eir.dev_instance = i;
     152           4 :        eir.address = hw_address;
     153           4 :        tm->hw_if_indicies[i] = vnet_eth_register_interface (vnm, &eir);
     154             : 
     155           4 :         error = vnet_hw_interface_set_flags(vnet_get_main(),
     156             :                                             tm->hw_if_indicies[i],
     157             :                                             VNET_HW_INTERFACE_FLAG_LINK_UP);
     158           4 :         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
     159             :                                           tm->hw_if_indicies[i]);
     160             : 
     161           4 :         error = vnet_sw_interface_set_flags(vnet_get_main(),
     162           4 :                                             tm->hw[i]->sw_if_index,
     163             :                                             VNET_SW_INTERFACE_FLAG_ADMIN_UP);
     164           4 :         FIB_TEST((NULL == error), "UP interface %d", i);
     165             :     }
     166             :     /*
     167             :      * re-eval after the inevitable realloc
     168             :      */
     169           5 :     for (i = 0; i < ninterfaces; i++)
     170             :     {
     171           4 :         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
     172             :                                           tm->hw_if_indicies[i]);
     173             :     }
     174             : 
     175           1 :     return (res);
     176             : }
     177             : 
     178             : #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket)            \
     179             :     {                                                                   \
     180             :         const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding(  \
     181             :             fib_table_lookup_exact_match(fib_index, (_rec_prefix)));    \
     182             :         const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding(  \
     183             :             fib_table_lookup(fib_index, (_via_prefix)));                \
     184             :         FIB_TEST(!dpo_cmp(_via_dpo,                                     \
     185             :                           load_balance_get_bucket(_rec_dpo->dpoi_index,      \
     186             :                                                   _bucket)),            \
     187             :                  "%U is recursive via %U",                              \
     188             :                  format_fib_prefix, (_rec_prefix),                      \
     189             :                  format_fib_prefix, _via_prefix);                       \
     190             :     }
     191             : 
     192             : #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai)               \
     193             :     {                                                                   \
     194             :      const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding(         \
     195             :                                                                fib_table_lookup_exact_match(fib_index, (_prefix))); \
     196             :      const dpo_id_t *_dpo1 =                                            \
     197             :          load_balance_get_bucket(_dpo->dpoi_index, _bucket);            \
     198             :      FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U",          \
     199             :                   format_dpo_type, _dpo1->dpoi_type);                   \
     200             :      FIB_TEST((_ai == _dpo1->dpoi_index),                               \
     201             :                   "%U bucket %d resolves via %U",                       \
     202             :                   format_fib_prefix, (_prefix),                         \
     203             :                   _bucket,                                              \
     204             :                   format_dpo_id, _dpo1, 0);                             \
     205             :      }
     206             : 
     207             : #define FIB_TEST_RPF(_cond, _comment, _args...)         \
     208             :     {                                                   \
     209             :         if (FIB_TEST_I(_cond, _comment, ##_args)) {     \
     210             :             res = 1;                                    \
     211             :             goto cleanup;                               \
     212             :         }                                               \
     213             :     }
     214             : 
     215             : static int
     216          14 : fib_test_urpf_is_equal (fib_node_index_t fei,
     217             :                         fib_forward_chain_type_t fct,
     218             :                         u32 num, ...)
     219             : {
     220          14 :     dpo_id_t dpo = DPO_INVALID;
     221             :     fib_urpf_list_t *urpf;
     222             :     int ii, res;
     223             :     index_t ui;
     224             :     va_list ap;
     225             : 
     226          14 :     va_start(ap, num);
     227             : 
     228          14 :     res = 0;
     229          14 :     fib_entry_contribute_forwarding(fei, fct, &dpo);
     230          14 :     ui = load_balance_get_urpf(dpo.dpoi_index);
     231             : 
     232          14 :     urpf = fib_urpf_list_get(ui);
     233             : 
     234          14 :     FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
     235             :                  "RPF:%U len %d == %d",
     236             :                  format_fib_urpf_list, ui,
     237             :                  num, vec_len(urpf->furpf_itfs));
     238          14 :     FIB_TEST_RPF(num == fib_urpf_check_size(ui),
     239             :                  "RPF:%U check-size %d == %d",
     240             :                  format_fib_urpf_list, ui,
     241             :                  num, vec_len(urpf->furpf_itfs));
     242             : 
     243          27 :     for (ii = 0; ii < num; ii++)
     244             :     {
     245          13 :         adj_index_t ai = va_arg(ap, adj_index_t);
     246             : 
     247          13 :         FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
     248             :                      "RPF:%d item:%d - %d == %d",
     249             :                      ui, ii, ai, urpf->furpf_itfs[ii]);
     250          13 :         FIB_TEST_RPF(fib_urpf_check(ui, ai),
     251             :                      "RPF:%d %d found",
     252             :                      ui, ai);
     253             :     }
     254             : 
     255          14 :     dpo_reset(&dpo);
     256             : 
     257          14 : cleanup:
     258          14 :     va_end(ap);
     259             : 
     260          14 :     return (res);
     261             : }
     262             : 
     263             : static u8*
     264           5 : fib_test_build_rewrite (u8 *eth_addr)
     265             : {
     266           5 :     u8* rewrite = NULL;
     267             : 
     268           5 :     vec_validate(rewrite, 13);
     269             : 
     270           5 :     memcpy(rewrite, eth_addr, 6);
     271           5 :     memcpy(rewrite+6, eth_addr, 6);
     272             : 
     273           5 :     return (rewrite);
     274             : }
     275             : 
     276             : #define FIB_TEST_LB(_cond, _comment, _args...)          \
     277             :     {                                                   \
     278             :         if (FIB_TEST_I(_cond, _comment, ##_args)) {     \
     279             :             return (1);                                 \
     280             :         }                                               \
     281             :     }
     282             : 
     283             : int
     284           5 : fib_test_validate_rep_v (const replicate_t *rep,
     285             :                          u16 n_buckets,
     286             :                          va_list *ap)
     287             : {
     288             :     const fib_test_rep_bucket_t *exp;
     289             :     const dpo_id_t *dpo;
     290             :     int bucket, res;
     291             : 
     292           5 :     res = 0;
     293           5 :     FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
     294             :                 "n_buckets = %d", rep->rep_n_buckets);
     295             : 
     296          13 :     for (bucket = 0; bucket < n_buckets; bucket++)
     297             :     {
     298           8 :         exp = va_arg(*ap, fib_test_rep_bucket_t*);
     299             : 
     300           8 :         dpo = replicate_get_bucket_i(rep, bucket);
     301             : 
     302           8 :         switch (exp->type)
     303             :         {
     304           5 :         case FT_REP_LABEL_O_ADJ:
     305             :             {
     306             :                 const mpls_label_dpo_t *mld;
     307             :                 mpls_label_t hdr;
     308             : 
     309           5 :                 FIB_TEST_LB((mpls_label_dpo_get_type(MPLS_LABEL_DPO_FLAG_NONE)
     310             :                              == dpo->dpoi_type),
     311             :                             "bucket %d stacks on %U",
     312             :                             bucket,
     313             :                             format_dpo_type, dpo->dpoi_type);
     314             : 
     315           5 :                 mld = mpls_label_dpo_get(dpo->dpoi_index);
     316           5 :                 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
     317             : 
     318           5 :                 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
     319             :                              exp->label_o_adj.label),
     320             :                             "bucket %d stacks on label %d",
     321             :                             bucket,
     322             :                             exp->label_o_adj.label);
     323             : 
     324           5 :                 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
     325             :                              exp->label_o_adj.eos),
     326             :                             "bucket %d stacks on label %d %U",
     327             :                             bucket,
     328             :                             exp->label_o_adj.label,
     329             :                             format_mpls_eos_bit, exp->label_o_adj.eos);
     330             : 
     331           5 :                 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
     332             :                             "bucket %d label stacks on %U",
     333             :                             bucket,
     334             :                             format_dpo_type, mld->mld_dpo.dpoi_type);
     335             : 
     336           5 :                 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
     337             :                             "bucket %d label stacks on adj %d",
     338             :                             bucket,
     339             :                             exp->label_o_adj.adj);
     340             :             }
     341           5 :             break;
     342           2 :         case FT_REP_INTF:
     343           2 :             FIB_TEST_LB((DPO_INTERFACE_RX == dpo->dpoi_type),
     344             :                         "bucket %d stacks on %U",
     345             :                         bucket,
     346             :                         format_dpo_type, dpo->dpoi_type);
     347             : 
     348           2 :             FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
     349             :                         "bucket %d stacks on adj %d",
     350             :                         bucket,
     351             :                         exp->adj.adj);
     352           2 :             break;
     353           1 :         case FT_REP_DISP_MFIB_LOOKUP:
     354             : //            ASSERT(0);
     355           1 :             break;
     356             :         }
     357           8 :     }
     358             : 
     359           5 :     return (res);
     360             : }
     361             : 
     362             : int
     363         458 : fib_test_validate_lb_v (const load_balance_t *lb,
     364             :                         int n_buckets,
     365             :                         va_list *ap)
     366             : {
     367             :     const dpo_id_t *dpo;
     368             :     int bucket, res;
     369             : 
     370         458 :     res = 0;
     371         458 :     FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
     372             : 
     373        1271 :     for (bucket = 0; bucket < n_buckets; bucket++)
     374             :     {
     375             :         const fib_test_lb_bucket_t *exp;
     376             : 
     377         813 :         exp = va_arg(*ap, fib_test_lb_bucket_t*);
     378         813 :         dpo = load_balance_get_bucket_i(lb, bucket);
     379             : 
     380         813 :         switch (exp->type)
     381             :         {
     382           2 :         case FT_LB_LABEL_STACK_O_ADJ:
     383             :             {
     384             :                 const mpls_label_dpo_t *mld;
     385             :                 mpls_label_dpo_flags_t mf;
     386             :                 mpls_label_t hdr;
     387             :                 u32 ii;
     388             : 
     389           4 :                 mf = ((exp->label_stack_o_adj.mode ==
     390             :                        FIB_MPLS_LSP_MODE_UNIFORM) ?
     391           2 :                       MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
     392             :                       MPLS_LABEL_DPO_FLAG_NONE);
     393           2 :                 FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
     394             :                            "bucket %d stacks on %U",
     395             :                            bucket,
     396             :                            format_dpo_type, dpo->dpoi_type);
     397             : 
     398           2 :                 mld = mpls_label_dpo_get(dpo->dpoi_index);
     399             : 
     400           2 :                 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
     401             :                             "label stack size",
     402             :                             mld->mld_n_labels);
     403             : 
     404          14 :                 for (ii = 0; ii < mld->mld_n_labels; ii++)
     405             :                 {
     406          12 :                     hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
     407          12 :                     FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
     408             :                                  exp->label_stack_o_adj.label_stack[ii]),
     409             :                                 "bucket %d stacks on label %d",
     410             :                                 bucket,
     411             :                                 exp->label_stack_o_adj.label_stack[ii]);
     412             : 
     413          12 :                     if (ii == mld->mld_n_labels-1)
     414             :                     {
     415           2 :                         FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
     416             :                                      exp->label_o_adj.eos),
     417             :                                     "bucket %d stacks on label %d %U!=%U",
     418             :                                     bucket,
     419             :                                     exp->label_stack_o_adj.label_stack[ii],
     420             :                                     format_mpls_eos_bit, exp->label_o_adj.eos,
     421             :                                     format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
     422             :                     }
     423             :                     else
     424             :                     {
     425          10 :                         FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
     426             :                                     "bucket %d stacks on label %d %U",
     427             :                                     bucket,
     428             :                                     exp->label_stack_o_adj.label_stack[ii],
     429             :                                     format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
     430             :                     }
     431             :                 }
     432             : 
     433           2 :                 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
     434             :                             "bucket %d label stacks on %U",
     435             :                             bucket,
     436             :                             format_dpo_type, mld->mld_dpo.dpoi_type);
     437             : 
     438           2 :                 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
     439             :                             "bucket %d label stacks on adj %d",
     440             :                             bucket,
     441             :                             exp->label_stack_o_adj.adj);
     442             :             }
     443           2 :             break;
     444           3 :         case FT_LB_LABEL_CHAIN_O_ADJ:
     445             :             {
     446           3 :                 const mpls_label_dpo_t *mld = NULL;
     447             :                 mpls_label_dpo_flags_t mf;
     448             :                 mpls_label_t hdr;
     449             :                 u32 ii;
     450             : 
     451           6 :                 mf = ((exp->label_chain_o_adj.mode ==
     452             :                        FIB_MPLS_LSP_MODE_UNIFORM) ?
     453           3 :                       MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
     454             :                       MPLS_LABEL_DPO_FLAG_NONE);
     455             : 
     456           9 :                 for (ii = 0; ii < exp->label_chain_o_adj.label_chain_size; ii++)
     457             :                 {
     458           6 :                     FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
     459             :                                 "bucket %d stacks on %U",
     460             :                                 bucket,
     461             :                                 format_dpo_type, dpo->dpoi_type);
     462           6 :                     mld = mpls_label_dpo_get(dpo->dpoi_index);
     463             : 
     464           6 :                     hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
     465           6 :                     FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
     466             :                                  exp->label_chain_o_adj.label_chain[ii]),
     467             :                                 "bucket %d stacks on label %d",
     468             :                                 bucket,
     469             :                                 exp->label_chain_o_adj.label_chain[ii]);
     470           6 :                     dpo = &mld->mld_dpo;
     471             :                 }
     472             : 
     473           3 :                 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
     474             :                             "bucket %d label stacks on %U",
     475             :                             bucket,
     476             :                             format_dpo_type, mld->mld_dpo.dpoi_type);
     477             : 
     478           3 :                 FIB_TEST_LB((exp->label_chain_o_adj.adj == mld->mld_dpo.dpoi_index),
     479             :                             "bucket %d label stacks on adj %d",
     480             :                             bucket,
     481             :                             exp->label_chain_o_adj.adj);
     482             :             }
     483           3 :             break;
     484          44 :         case FT_LB_LABEL_O_ADJ:
     485             :             {
     486             :                 const mpls_label_dpo_t *mld;
     487             :                 mpls_label_t hdr;
     488          44 :                 FIB_TEST_LB((mpls_label_dpo_get_type(MPLS_LABEL_DPO_FLAG_NONE)
     489             :                              == dpo->dpoi_type),
     490             :                            "bucket %d stacks on %U",
     491             :                            bucket,
     492             :                            format_dpo_type, dpo->dpoi_type);
     493             : 
     494          44 :                 mld = mpls_label_dpo_get(dpo->dpoi_index);
     495          44 :                 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
     496             : 
     497          44 :                 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
     498             :                              exp->label_o_adj.label),
     499             :                             "bucket %d stacks on label %d not %d",
     500             :                             bucket,
     501             :                             vnet_mpls_uc_get_label(hdr),
     502             :                             exp->label_o_adj.label);
     503             : 
     504          44 :                 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
     505             :                              exp->label_o_adj.eos),
     506             :                             "bucket %d stacks on label %d %U",
     507             :                             bucket,
     508             :                             exp->label_o_adj.label,
     509             :                             format_mpls_eos_bit, exp->label_o_adj.eos);
     510             : 
     511          44 :                 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
     512             :                             "bucket %d label stacks on %U",
     513             :                             bucket,
     514             :                             format_dpo_type, mld->mld_dpo.dpoi_type);
     515             : 
     516          44 :                 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
     517             :                             "bucket %d label stacks on adj %d",
     518             :                             bucket,
     519             :                             exp->label_o_adj.adj);
     520             :             }
     521          44 :             break;
     522           8 :         case FT_LB_LABEL_O_LB:
     523             :             {
     524             :                 const mpls_label_dpo_t *mld;
     525             :                 mpls_label_dpo_flags_t mf;
     526             :                 mpls_label_t hdr;
     527             : 
     528          16 :                 mf = ((exp->label_o_lb.mode ==
     529             :                        FIB_MPLS_LSP_MODE_UNIFORM) ?
     530           8 :                       MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
     531             :                       MPLS_LABEL_DPO_FLAG_NONE);
     532           8 :                 FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
     533             :                            "bucket %d stacks on %U",
     534             :                            bucket,
     535             :                            format_dpo_type, dpo->dpoi_type);
     536             : 
     537           8 :                 mld = mpls_label_dpo_get(dpo->dpoi_index);
     538           8 :                 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
     539             : 
     540           8 :                 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
     541             :                             mld->mld_n_labels);
     542           8 :                 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
     543             :                              exp->label_o_lb.label),
     544             :                             "bucket %d stacks on label %d",
     545             :                             bucket,
     546             :                             exp->label_o_lb.label);
     547             : 
     548           8 :                 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
     549             :                              exp->label_o_lb.eos),
     550             :                             "bucket %d stacks on label %d %U",
     551             :                             bucket,
     552             :                             exp->label_o_lb.label,
     553             :                             format_mpls_eos_bit, exp->label_o_lb.eos);
     554             : 
     555           8 :                 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
     556             :                             "bucket %d label stacks on %U",
     557             :                             bucket,
     558             :                             format_dpo_type, mld->mld_dpo.dpoi_type);
     559             : 
     560           8 :                 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
     561             :                             "bucket %d label stacks on LB %d",
     562             :                             bucket,
     563             :                             exp->label_o_lb.lb);
     564             :             }
     565           8 :             break;
     566         360 :         case FT_LB_ADJ:
     567         360 :             res = FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
     568             :                               (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
     569             :                              "bucket %d stacks on %U",
     570             :                              bucket,
     571             :                              format_dpo_type, dpo->dpoi_type);
     572         360 :             FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
     573             :                         "bucket %d stacks on adj %d",
     574             :                         bucket,
     575             :                         exp->adj.adj);
     576         360 :             break;
     577          18 :         case FT_LB_MPLS_DISP_PIPE_O_ADJ:
     578             :         {
     579             :             const mpls_disp_dpo_t *mdd;
     580             : 
     581          18 :             res = FIB_TEST_I((DPO_MPLS_DISPOSITION_PIPE == dpo->dpoi_type),
     582             :                        "bucket %d stacks on %U",
     583             :                        bucket,
     584             :                        format_dpo_type, dpo->dpoi_type);
     585             : 
     586          18 :             mdd = mpls_disp_dpo_get(dpo->dpoi_index);
     587             : 
     588          18 :             dpo = &mdd->mdd_dpo;
     589             : 
     590          18 :             res = FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
     591             :                               (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
     592             :                             "bucket %d stacks on %U",
     593             :                              bucket,
     594             :                              format_dpo_type, dpo->dpoi_type);
     595          18 :             FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
     596             :                         "bucket %d stacks on adj %d",
     597             :                         bucket,
     598             :                         exp->adj.adj);
     599          18 :             break;
     600             :         }
     601           1 :         case FT_LB_INTF:
     602           1 :             res = FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
     603             :                              "bucket %d stacks on %U",
     604             :                              bucket,
     605             :                              format_dpo_type, dpo->dpoi_type);
     606           1 :             FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
     607             :                         "bucket %d stacks on adj %d",
     608             :                         bucket,
     609             :                         exp->adj.adj);
     610           1 :             break;
     611           1 :         case FT_LB_L2:
     612           1 :             res = FIB_TEST_I((DPO_DVR == dpo->dpoi_type),
     613             :                              "bucket %d stacks on %U",
     614             :                              bucket,
     615             :                              format_dpo_type, dpo->dpoi_type);
     616           1 :             FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
     617             :                         "bucket %d stacks on adj %d",
     618             :                         bucket,
     619             :                         exp->adj.adj);
     620           1 :             break;
     621         331 :         case FT_LB_O_LB:
     622         331 :             res = FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
     623             :                              "bucket %d stacks on %U",
     624             :                              bucket,
     625             :                              format_dpo_type, dpo->dpoi_type);
     626         331 :             FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
     627             :                         "bucket %d stacks on lb %d not %d",
     628             :                         bucket,
     629             :                         dpo->dpoi_index,
     630             :                         exp->lb.lb);
     631         331 :             break;
     632          32 :         case FT_LB_BIER_TABLE:
     633          32 :             FIB_TEST_LB((DPO_BIER_TABLE == dpo->dpoi_type),
     634             :                         "bucket %d stacks on %U",
     635             :                         bucket,
     636             :                         format_dpo_type, dpo->dpoi_type);
     637          32 :             FIB_TEST_LB((exp->bier.table == dpo->dpoi_index),
     638             :                         "bucket %d stacks on lb %d",
     639             :                         bucket,
     640             :                         exp->bier.table);
     641          32 :             break;
     642           4 :         case FT_LB_BIER_FMASK:
     643           4 :             FIB_TEST_LB((DPO_BIER_FMASK == dpo->dpoi_type),
     644             :                         "bucket %d stacks on %U",
     645             :                         bucket,
     646             :                         format_dpo_type, dpo->dpoi_type);
     647           4 :             FIB_TEST_LB((exp->bier.fmask == dpo->dpoi_index),
     648             :                         "bucket %d stacks on lb %d",
     649             :                         bucket,
     650             :                         exp->bier.fmask);
     651           4 :             break;
     652           9 :         case FT_LB_DROP:
     653           9 :             FIB_TEST_LB((DPO_DROP == dpo->dpoi_type),
     654             :                         "bucket %d stacks on %U",
     655             :                         bucket,
     656             :                         format_dpo_type, dpo->dpoi_type);
     657           9 :             break;
     658           0 :         case FT_LB_PUNT:
     659           0 :             FIB_TEST_LB((DPO_PUNT == dpo->dpoi_type),
     660             :                         "bucket %d stacks on %U",
     661             :                         bucket,
     662             :                         format_dpo_type, dpo->dpoi_type);
     663           0 :             break;
     664             :         }
     665         813 :     }
     666         458 :     return (res);
     667             : }
     668             : 
     669             : int
     670           2 : fib_test_validate_lb (const dpo_id_t *dpo,
     671             :                       int n_buckets,
     672             :                       ...)
     673             : {
     674             :     const load_balance_t *lb;
     675             :     va_list ap;
     676             :     int res;
     677             : 
     678           2 :     res = 0;
     679           2 :     va_start(ap, n_buckets);
     680             : 
     681           2 :     if (!FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
     682             :                     "Entry links to %U",
     683             :                     format_dpo_type, dpo->dpoi_type))
     684             :     {
     685           2 :         lb = load_balance_get(dpo->dpoi_index);
     686             : 
     687           2 :         res = fib_test_validate_lb_v(lb, n_buckets, &ap);
     688             :     }
     689             :     else
     690             :     {
     691           0 :         res = 1;
     692             :     }
     693             : 
     694           2 :     va_end(ap);
     695             : 
     696           2 :     return (res);
     697             : }
     698             : 
     699             : int
     700         459 : fib_test_validate_entry (fib_node_index_t fei,
     701             :                          fib_forward_chain_type_t fct,
     702             :                          int n_buckets,
     703             :                          ...)
     704             : {
     705         459 :     dpo_id_t dpo = DPO_INVALID;
     706             :     const fib_prefix_t *pfx;
     707             :     index_t fw_lbi;
     708             :     u32 fib_index;
     709             :     va_list ap;
     710             :     int res;
     711             : 
     712             : 
     713         459 :     res = 0;
     714         459 :     pfx = fib_entry_get_prefix(fei);
     715         459 :     fib_index = fib_entry_get_fib_index(fei);
     716         459 :     fib_entry_contribute_forwarding(fei, fct, &dpo);
     717             : 
     718         459 :     if (DPO_REPLICATE == dpo.dpoi_type)
     719             :     {
     720             :         const replicate_t *rep;
     721             : 
     722           5 :         va_start(ap, n_buckets);
     723           5 :         rep = replicate_get(dpo.dpoi_index);
     724           5 :         res = fib_test_validate_rep_v(rep, n_buckets, &ap);
     725           5 :         va_end (ap);
     726             :     }
     727             :     else
     728             :     {
     729             :         const load_balance_t *lb;
     730             : 
     731         454 :         FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
     732             :                     "%U Entry links to %U",
     733             :                     format_fib_prefix, pfx,
     734             :                     format_dpo_type, dpo.dpoi_type);
     735             : 
     736         454 :         va_start(ap, n_buckets);
     737         454 :         lb = load_balance_get(dpo.dpoi_index);
     738         454 :         res = fib_test_validate_lb_v(lb, n_buckets, &ap);
     739         454 :         va_end(ap);
     740             : 
     741             :         /*
     742             :          * ensure that the LB contributed by the entry is the
     743             :          * same as the LB in the forwarding tables
     744             :          */
     745         454 :         if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
     746             :         {
     747         453 :             switch (pfx->fp_proto)
     748             :             {
     749         427 :             case FIB_PROTOCOL_IP4:
     750         427 :                 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx->fp_addr.ip4);
     751         427 :                 break;
     752           6 :             case FIB_PROTOCOL_IP6:
     753           6 :                 fw_lbi = ip6_fib_table_fwding_lookup(fib_index, &pfx->fp_addr.ip6);
     754           6 :                 break;
     755          20 :             case FIB_PROTOCOL_MPLS:
     756             :                 {
     757          20 :                     mpls_unicast_header_t hdr = {
     758             :                         .label_exp_s_ttl = 0,
     759             :                     };
     760             : 
     761          20 :                     vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx->fp_label);
     762          20 :                     vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx->fp_eos);
     763          20 :                     hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
     764             : 
     765          20 :                     fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
     766          20 :                     break;
     767             :                 }
     768           0 :             default:
     769           0 :                 fw_lbi = 0;
     770             :             }
     771         453 :             FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
     772             :                         "Contributed LB = FW LB:\n fwd:%U\n cont:%U",
     773             :                         format_load_balance, fw_lbi, 0,
     774             :                         format_load_balance, dpo.dpoi_index, 0);
     775             :         }
     776             :     }
     777             : 
     778         459 :     dpo_reset(&dpo);
     779             : 
     780         459 :     return (res);
     781             : }
     782             : 
     783             : static int
     784           3 : fib_test_multipath_v4 (const test_main_t *tm, const u32 fib_index,
     785             :                        const fib_prefix_t *pfx, const int n_paths,
     786             :                        const int expected_n_buckets)
     787             : {
     788           3 :     const int path_list_pool_size = fib_path_list_pool_size();
     789           3 :     const int path_list_db_size = fib_path_list_db_size();
     790           3 :     const int entry_pool_size = fib_entry_pool_size();
     791           3 :     fib_route_path_t *r_paths = NULL;
     792             :     const load_balance_t *lb;
     793             :     const dpo_id_t *dpo;
     794             :     u32 fei;
     795           3 :     int res = 0;
     796             :     int i;
     797             : 
     798       12331 :     for (i = 0; i < n_paths; i++)
     799             :     {
     800       24656 :         fib_route_path_t r_path = {
     801             :             .frp_proto = DPO_PROTO_IP4,
     802             :             .frp_addr = {
     803       12328 :                 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + i),
     804             :             },
     805       12328 :             .frp_sw_if_index = tm->hw[0]->sw_if_index,
     806             :             .frp_weight = 1,
     807             :             .frp_fib_index = ~0,
     808             :             .frp_flags = FIB_ROUTE_PATH_ATTACHED,
     809             :         };
     810       12328 :         vec_add1(r_paths, r_path);
     811             :     }
     812             : 
     813           3 :     fib_table_entry_update(fib_index,
     814             :                            pfx,
     815             :                            FIB_SOURCE_API,
     816             :                            FIB_ENTRY_FLAG_NONE,
     817             :                            r_paths);
     818             : 
     819           3 :     fei = fib_table_lookup_exact_match(fib_index, pfx);
     820           3 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "prefix present");
     821           3 :     dpo = fib_entry_contribute_ip_forwarding(fei);
     822             : 
     823           3 :     lb = load_balance_get(dpo->dpoi_index);
     824           3 :     FIB_TEST((lb->lb_n_buckets == expected_n_buckets),
     825             :              "prefix lb over %d paths", lb->lb_n_buckets);
     826             : 
     827           3 :     fib_table_entry_delete(fib_index,
     828             :                            pfx,
     829             :                            FIB_SOURCE_API);
     830           3 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
     831             :              fib_table_lookup_exact_match(fib_index, pfx), "prefix removed");
     832           3 :     vec_free(r_paths);
     833             : 
     834             :     /*
     835             :      * add-remove test. no change.
     836             :      */
     837           3 :     FIB_TEST((path_list_db_size == fib_path_list_db_size()),
     838             :              "path list DB population:%d", fib_path_list_db_size());
     839           3 :     FIB_TEST((path_list_pool_size == fib_path_list_pool_size()),
     840             :              "path list pool size is %d", fib_path_list_pool_size());
     841           3 :     FIB_TEST((entry_pool_size == fib_entry_pool_size()),
     842             :              "entry pool size is %d", fib_entry_pool_size());
     843           3 :     return res;
     844             : }
     845             : 
     846             : static int
     847           1 : fib_test_v4 (void)
     848             : {
     849             :     /*
     850             :      * In the default table check for the presence and correct forwarding
     851             :      * of the special entries
     852             :      */
     853             :     fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
     854             :     const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
     855             :     const ip_adjacency_t *adj;
     856             :     const load_balance_t *lb;
     857             :     test_main_t *tm;
     858             :     u32 fib_index;
     859             :     int lb_count;
     860             :     int ii, res;
     861             : 
     862           1 :     res = 0;
     863             :     /* via 10.10.10.1 */
     864           2 :     ip46_address_t nh_10_10_10_1 = {
     865           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
     866             :     };
     867             :     /* via 10.10.10.2 */
     868           2 :     ip46_address_t nh_10_10_10_2 = {
     869           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
     870             :     };
     871             : 
     872           1 :     FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
     873             :              pool_elts(load_balance_map_pool));
     874             : 
     875           1 :     tm = &test_main;
     876             : 
     877             :     /* record the nubmer of load-balances in use before we start */
     878           1 :     lb_count = pool_elts(load_balance_pool);
     879             : 
     880             :     /* Find or create FIB table 11 */
     881           1 :     fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
     882             :                                                   FIB_SOURCE_API);
     883             : 
     884           5 :     for (ii = 0; ii < 4; ii++)
     885           4 :       fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[ii]->sw_if_index, fib_index);
     886             : 
     887           1 :     fib_prefix_t pfx_0_0_0_0_s_0 = {
     888             :         .fp_len = 0,
     889             :         .fp_proto = FIB_PROTOCOL_IP4,
     890             :         .fp_addr = {
     891             :             .ip4 = {
     892             :                 {0}
     893             :             },
     894             :         },
     895             :     };
     896             : 
     897           1 :     fib_prefix_t pfx = {
     898             :         .fp_len = 0,
     899             :         .fp_proto = FIB_PROTOCOL_IP4,
     900             :         .fp_addr = {
     901             :             .ip4 = {
     902             :                 {0}
     903             :             },
     904             :         },
     905             :     };
     906             : 
     907           1 :     dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
     908             : 
     909           1 :     dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
     910           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
     911           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
     912             :              "Default route is DROP");
     913             : 
     914           1 :     pfx.fp_len = 32;
     915           1 :     fei = fib_table_lookup(fib_index, &pfx);
     916           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
     917           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
     918             :              "all 0s route is DROP");
     919             : 
     920           1 :     pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
     921           1 :     pfx.fp_len = 32;
     922           1 :     fei = fib_table_lookup(fib_index, &pfx);
     923           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
     924           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
     925             :              "all 1s route is DROP");
     926             : 
     927           1 :     pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
     928           1 :     pfx.fp_len = 8;
     929           1 :     fei = fib_table_lookup(fib_index, &pfx);
     930           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
     931           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
     932             :              "all-mcast route is DROP");
     933             : 
     934           1 :     pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
     935           1 :     pfx.fp_len = 8;
     936           1 :     fei = fib_table_lookup(fib_index, &pfx);
     937           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
     938           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
     939             :              "class-e route is DROP");
     940             : 
     941             :     /*
     942             :      * at this stage there are 5 entries in the test FIB (plus 5 in the default),
     943             :      * all of which are special sourced and so none of which share path-lists.
     944             :      * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
     945             :      * table, and 4 path-lists in the v6 MFIB table and 2 in v4.
     946             :      */
     947             : #define ENBR (5+5+2)
     948             : 
     949           1 :     u32 PNBR = 5+5+2+4+2;
     950             : 
     951             :     /*
     952             :      * if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
     953             :      */
     954           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
     955           1 :     FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
     956             :              fib_path_list_pool_size());
     957           1 :     FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
     958             :              fib_entry_pool_size());
     959             : 
     960             :     /*
     961             :      * add interface routes.
     962             :      *  validate presence of /24 attached and /32 recieve.
     963             :      *  test for the presence of the receive address in the glean and local adj
     964             :      */
     965           2 :     fib_prefix_t local_pfx = {
     966             :         .fp_len = 24,
     967             :         .fp_proto = FIB_PROTOCOL_IP4,
     968             :         .fp_addr = {
     969             :             .ip4 = {
     970           1 :                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
     971             :             },
     972             :         },
     973             :     };
     974             : 
     975           1 :     fib_table_entry_update_one_path(fib_index, &local_pfx,
     976             :                                     FIB_SOURCE_INTERFACE,
     977             :                                     (FIB_ENTRY_FLAG_CONNECTED |
     978             :                                      FIB_ENTRY_FLAG_ATTACHED),
     979             :                                     DPO_PROTO_IP4,
     980             :                                     NULL,
     981           1 :                                     tm->hw[0]->sw_if_index,
     982             :                                     ~0, // invalid fib index
     983             :                                     1, // weight
     984             :                                     NULL,
     985             :                                     FIB_ROUTE_PATH_FLAG_NONE);
     986           1 :     fei = fib_table_lookup(fib_index, &local_pfx);
     987           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
     988           1 :     FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
     989             :               fib_entry_get_flags(fei)),
     990             :              "Flags set on attached interface");
     991             : 
     992           1 :     ai = fib_entry_get_adj(fei);
     993           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
     994             :              "attached interface route adj present %d", ai);
     995           1 :     adj = adj_get(ai);
     996           1 :     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
     997             :              "attached interface adj is glean");
     998             : 
     999           1 :     local_pfx.fp_len = 32;
    1000           1 :     fib_table_entry_update_one_path(fib_index, &local_pfx,
    1001             :                                     FIB_SOURCE_INTERFACE,
    1002             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    1003             :                                      FIB_ENTRY_FLAG_LOCAL),
    1004             :                                     DPO_PROTO_IP4,
    1005             :                                     NULL,
    1006           1 :                                     tm->hw[0]->sw_if_index,
    1007             :                                     ~0, // invalid fib index
    1008             :                                     1, // weight
    1009             :                                     NULL,
    1010             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    1011           1 :     fei = fib_table_lookup(fib_index, &local_pfx);
    1012           1 :     FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
    1013             :               fib_entry_get_flags(fei)),
    1014             :              "Flags set on local interface");
    1015             : 
    1016           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
    1017             : 
    1018           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1019           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
    1020             :              "RPF list for local length 0");
    1021           1 :     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
    1022           1 :     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
    1023             :              "local interface adj is local");
    1024           1 :     receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
    1025             : 
    1026           1 :     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
    1027             :                                     &rd->rd_addr)),
    1028             :              "local interface adj is receive ok");
    1029             : 
    1030           1 :     FIB_TEST((2 == fib_table_get_num_entries(fib_index,
    1031             :                                              FIB_PROTOCOL_IP4,
    1032             :                                              FIB_SOURCE_INTERFACE)),
    1033             :              "2 Interface Source'd prefixes");
    1034           1 :     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
    1035             :                                     &adj->sub_type.glean.rx_pfx.fp_addr)),
    1036             :              "attached interface adj is receive ok");
    1037             : 
    1038             :     /*
    1039             :      * +2 interface routes +2 non-shared path-lists
    1040             :      */
    1041           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
    1042           1 :     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
    1043             :              fib_path_list_pool_size());
    1044           1 :     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
    1045             :              fib_entry_pool_size());
    1046             : 
    1047             :     /*
    1048             :      * Modify the default route to be via an adj not yet known.
    1049             :      * this sources the defalut route with the API source, which is
    1050             :      * a higher preference to the DEFAULT_ROUTE source
    1051             :      */
    1052           1 :     pfx.fp_addr.ip4.as_u32 = 0;
    1053           1 :     pfx.fp_len = 0;
    1054           1 :     fib_table_entry_path_add(fib_index, &pfx,
    1055             :                              FIB_SOURCE_API,
    1056             :                              FIB_ENTRY_FLAG_NONE,
    1057             :                              DPO_PROTO_IP4,
    1058             :                              &nh_10_10_10_1,
    1059           1 :                              tm->hw[0]->sw_if_index,
    1060             :                              ~0, // invalid fib index
    1061             :                              1,
    1062             :                              NULL,
    1063             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1064           1 :     fei = fib_table_lookup(fib_index, &pfx);
    1065           1 :     FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
    1066             :              "Flags set on API route");
    1067             : 
    1068           1 :     FIB_TEST((fei == dfrt), "default route same index");
    1069           1 :     ai = fib_entry_get_adj(fei);
    1070           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
    1071           1 :     adj = adj_get(ai);
    1072           1 :     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
    1073             :              "adj is incomplete");
    1074           1 :     FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
    1075             :              "adj nbr next-hop ok");
    1076           1 :     FIB_TEST((1 == fib_table_get_num_entries(fib_index,
    1077             :                                              FIB_PROTOCOL_IP4,
    1078             :                                              FIB_SOURCE_API)),
    1079             :              "1 API Source'd prefixes");
    1080             : 
    1081             :     /*
    1082             :      * find the adj in the shared db
    1083             :      */
    1084           1 :     locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    1085             :                                     VNET_LINK_IP4,
    1086             :                                     &nh_10_10_10_1,
    1087           1 :                                     tm->hw[0]->sw_if_index);
    1088           1 :     FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
    1089           1 :     adj_unlock(locked_ai);
    1090             : 
    1091             :     /*
    1092             :      * +1 shared path-list
    1093             :      */
    1094           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
    1095             :              fib_path_list_db_size());
    1096           1 :     FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
    1097             :              fib_path_list_pool_size());
    1098           1 :     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
    1099             :              fib_entry_pool_size());
    1100             : 
    1101             :     /*
    1102             :      * remove the API source from the default route. We expected
    1103             :      * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
    1104             :      */
    1105           1 :     pfx.fp_addr.ip4.as_u32 = 0;
    1106           1 :     pfx.fp_len = 0;
    1107           1 :     fib_table_entry_path_remove(fib_index, &pfx,
    1108             :                                 FIB_SOURCE_API,
    1109             :                                 DPO_PROTO_IP4,
    1110             :                                 &nh_10_10_10_1,
    1111           1 :                                 tm->hw[0]->sw_if_index,
    1112             :                                 ~0, // non-recursive path, so no FIB index
    1113             :                                 1,
    1114             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    1115             : 
    1116           1 :     fei = fib_table_lookup(fib_index, &pfx);
    1117             : 
    1118           1 :     FIB_TEST((fei == dfrt), "default route same index");
    1119           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    1120             :              "Default route is DROP");
    1121             : 
    1122             :     /*
    1123             :      * -1 shared-path-list
    1124             :      */
    1125           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
    1126           1 :     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
    1127             :              fib_path_list_pool_size());
    1128           1 :     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
    1129             :              fib_entry_pool_size());
    1130             : 
    1131             :     /*
    1132             :      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
    1133             :      */
    1134           2 :     fib_prefix_t pfx_10_10_10_1_s_32 = {
    1135             :         .fp_len = 32,
    1136             :         .fp_proto = FIB_PROTOCOL_IP4,
    1137             :         .fp_addr = {
    1138             :             /* 10.10.10.1 */
    1139           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
    1140             :         },
    1141             :     };
    1142           2 :     fib_prefix_t pfx_10_10_10_2_s_32 = {
    1143             :         .fp_len = 32,
    1144             :         .fp_proto = FIB_PROTOCOL_IP4,
    1145             :         .fp_addr = {
    1146             :             /* 10.10.10.2 */
    1147           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
    1148             :         },
    1149             :     };
    1150           2 :     fib_prefix_t pfx_11_11_11_11_s_32 = {
    1151             :         .fp_len = 32,
    1152             :         .fp_proto = FIB_PROTOCOL_IP4,
    1153             :         .fp_addr = {
    1154             :             /* 11.11.11.11 */
    1155           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
    1156             :         },
    1157             :     };
    1158           1 :     u8 eth_addr[] = {
    1159             :         0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
    1160             :     };
    1161             : 
    1162           2 :     ip46_address_t nh_12_12_12_12 = {
    1163           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
    1164             :     };
    1165             :     adj_index_t ai_12_12_12_12;
    1166             : 
    1167             :     /*
    1168             :      * Add a route via an incomplete ADJ. then complete the ADJ
    1169             :      * Expect the route LB is updated to use complete adj type.
    1170             :      */
    1171           1 :     fei = fib_table_entry_update_one_path(fib_index,
    1172             :                                           &pfx_11_11_11_11_s_32,
    1173             :                                           FIB_SOURCE_API,
    1174             :                                           FIB_ENTRY_FLAG_ATTACHED,
    1175             :                                           DPO_PROTO_IP4,
    1176             :                                           &pfx_10_10_10_1_s_32.fp_addr,
    1177           1 :                                           tm->hw[0]->sw_if_index,
    1178             :                                           ~0, // invalid fib index
    1179             :                                           1,
    1180             :                                           NULL,
    1181             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    1182             : 
    1183           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1184           1 :     dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
    1185           1 :     FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
    1186             :              "11.11.11.11/32 via incomplete adj");
    1187             : 
    1188           1 :     ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    1189             :                                 VNET_LINK_IP4,
    1190             :                                 &pfx_10_10_10_1_s_32.fp_addr,
    1191           1 :                                 tm->hw[0]->sw_if_index);
    1192           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
    1193           1 :     adj = adj_get(ai_01);
    1194           1 :     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
    1195             :              "adj is incomplete");
    1196           1 :     FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
    1197             :                                     &adj->sub_type.nbr.next_hop)),
    1198             :              "adj nbr next-hop ok");
    1199             : 
    1200           1 :     adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
    1201             :                            fib_test_build_rewrite(eth_addr));
    1202           1 :     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
    1203             :              "adj is complete");
    1204           1 :     FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
    1205             :                                     &adj->sub_type.nbr.next_hop)),
    1206             :              "adj nbr next-hop ok");
    1207           1 :     ai = fib_entry_get_adj(fei);
    1208           1 :     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
    1209             : 
    1210           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1211           1 :     dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
    1212           1 :     FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
    1213             :              "11.11.11.11/32 via complete adj");
    1214           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
    1215             :                                     tm->hw[0]->sw_if_index),
    1216             :              "RPF list for adj-fib contains adj");
    1217             : 
    1218           1 :     ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    1219             :                                          VNET_LINK_IP4,
    1220             :                                          &nh_12_12_12_12,
    1221           1 :                                          tm->hw[1]->sw_if_index);
    1222           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
    1223           1 :     adj = adj_get(ai_12_12_12_12);
    1224           1 :     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
    1225             :              "adj is incomplete");
    1226           1 :     FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
    1227             :                                     &adj->sub_type.nbr.next_hop)),
    1228             :              "adj nbr next-hop ok");
    1229           1 :     adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
    1230             :                            fib_test_build_rewrite(eth_addr));
    1231           1 :     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
    1232             :              "adj is complete");
    1233             : 
    1234             :     /*
    1235             :      * add the adj fib
    1236             :      */
    1237           1 :     fei = fib_table_entry_path_add(fib_index,
    1238             :                                    &pfx_10_10_10_1_s_32,
    1239             :                                    FIB_SOURCE_ADJ,
    1240             :                                    FIB_ENTRY_FLAG_ATTACHED,
    1241             :                                    DPO_PROTO_IP4,
    1242             :                                    &pfx_10_10_10_1_s_32.fp_addr,
    1243           1 :                                    tm->hw[0]->sw_if_index,
    1244             :                                    ~0, // invalid fib index
    1245             :                                    1,
    1246             :                                    NULL,
    1247             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    1248           1 :     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED  == fib_entry_get_flags(fei)),
    1249             :              "Flags set on adj-fib");
    1250           1 :     ai = fib_entry_get_adj(fei);
    1251           1 :     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
    1252             : 
    1253           1 :     fib_table_entry_path_remove(fib_index,
    1254             :                                 &pfx_11_11_11_11_s_32,
    1255             :                                 FIB_SOURCE_API,
    1256             :                                 DPO_PROTO_IP4,
    1257             :                                 &pfx_10_10_10_1_s_32.fp_addr,
    1258           1 :                                 tm->hw[0]->sw_if_index,
    1259             :                                 ~0, // invalid fib index
    1260             :                                 1,
    1261             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    1262             : 
    1263           1 :     eth_addr[5] = 0xb2;
    1264             : 
    1265           1 :     ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    1266             :                                 VNET_LINK_IP4,
    1267             :                                 &pfx_10_10_10_2_s_32.fp_addr,
    1268           1 :                                 tm->hw[0]->sw_if_index);
    1269           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
    1270           1 :     adj = adj_get(ai_02);
    1271           1 :     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
    1272             :              "adj is incomplete");
    1273           1 :     FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
    1274             :                                     &adj->sub_type.nbr.next_hop)),
    1275             :              "adj nbr next-hop ok");
    1276             : 
    1277           1 :     adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
    1278             :                            fib_test_build_rewrite(eth_addr));
    1279           1 :     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
    1280             :              "adj is complete");
    1281           1 :     FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
    1282             :                                     &adj->sub_type.nbr.next_hop)),
    1283             :              "adj nbr next-hop ok");
    1284           1 :     FIB_TEST((ai_01 != ai_02), "ADJs are different");
    1285             : 
    1286           1 :     fib_table_entry_path_add(fib_index,
    1287             :                              &pfx_10_10_10_2_s_32,
    1288             :                              FIB_SOURCE_ADJ,
    1289             :                              FIB_ENTRY_FLAG_ATTACHED,
    1290             :                              DPO_PROTO_IP4,
    1291             :                              &pfx_10_10_10_2_s_32.fp_addr,
    1292           1 :                              tm->hw[0]->sw_if_index,
    1293             :                              ~0, // invalid fib index
    1294             :                              1,
    1295             :                              NULL,
    1296             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1297             : 
    1298           1 :     fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
    1299           1 :     ai = fib_entry_get_adj(fei);
    1300           1 :     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
    1301             : 
    1302             :     /*
    1303             :      * +2 adj-fibs, and their non-shared path-lists
    1304             :      */
    1305           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
    1306           1 :     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
    1307             :              fib_path_list_pool_size());
    1308           1 :     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
    1309             :              fib_entry_pool_size());
    1310             : 
    1311             :     /*
    1312             :      * Add 2 routes via the first ADJ. ensure path-list sharing
    1313             :      */
    1314           2 :     fib_prefix_t pfx_1_1_1_1_s_32 = {
    1315             :         .fp_len = 32,
    1316             :         .fp_proto = FIB_PROTOCOL_IP4,
    1317             :         .fp_addr = {
    1318             :             /* 1.1.1.1/32 */
    1319           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
    1320             :         },
    1321             :     };
    1322             : 
    1323           1 :     fib_table_entry_path_add(fib_index,
    1324             :                              &pfx_1_1_1_1_s_32,
    1325             :                              FIB_SOURCE_API,
    1326             :                              FIB_ENTRY_FLAG_NONE,
    1327             :                              DPO_PROTO_IP4,
    1328             :                              &nh_10_10_10_1,
    1329           1 :                              tm->hw[0]->sw_if_index,
    1330             :                              ~0, // invalid fib index
    1331             :                              1,
    1332             :                              NULL,
    1333             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1334           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
    1335           1 :     ai = fib_entry_get_adj(fei);
    1336           1 :     FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
    1337             : 
    1338             :     /*
    1339             :      * +1 entry and a shared path-list
    1340             :      */
    1341           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB is empty");
    1342           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    1343             :              fib_path_list_pool_size());
    1344           1 :     FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
    1345             :              fib_entry_pool_size());
    1346             : 
    1347             :     /* 1.1.2.0/24 */
    1348           2 :     fib_prefix_t pfx_1_1_2_0_s_24 = {
    1349             :         .fp_len = 24,
    1350             :         .fp_proto = FIB_PROTOCOL_IP4,
    1351             :         .fp_addr = {
    1352           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
    1353             :         }
    1354             :     };
    1355             : 
    1356           1 :     fib_table_entry_path_add(fib_index,
    1357             :                              &pfx_1_1_2_0_s_24,
    1358             :                              FIB_SOURCE_API,
    1359             :                              FIB_ENTRY_FLAG_NONE,
    1360             :                              DPO_PROTO_IP4,
    1361             :                              &nh_10_10_10_1,
    1362           1 :                              tm->hw[0]->sw_if_index,
    1363             :                              ~0, // invalid fib index
    1364             :                              1,
    1365             :                              NULL,
    1366             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1367           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
    1368           1 :     ai = fib_entry_get_adj(fei);
    1369           1 :     FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
    1370             : 
    1371             :     /*
    1372             :      * +1 entry only
    1373             :      */
    1374           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB is empty");
    1375           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    1376             :              fib_path_list_pool_size());
    1377           1 :     FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
    1378             :              fib_entry_pool_size());
    1379             : 
    1380             :     /*
    1381             :      * modify 1.1.2.0/24 to use multipath.
    1382             :      */
    1383           1 :     fib_table_entry_path_add(fib_index,
    1384             :                              &pfx_1_1_2_0_s_24,
    1385             :                              FIB_SOURCE_API,
    1386             :                              FIB_ENTRY_FLAG_NONE,
    1387             :                              DPO_PROTO_IP4,
    1388             :                              &nh_10_10_10_2,
    1389           1 :                              tm->hw[0]->sw_if_index,
    1390             :                              ~0, // invalid fib index
    1391             :                              1,
    1392             :                              NULL,
    1393             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1394           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
    1395           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1396           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    1397             :                                     1, tm->hw[0]->sw_if_index),
    1398             :              "RPF list for 1.1.2.0/24 contains both adjs");
    1399             : 
    1400           1 :     dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
    1401           1 :     FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
    1402           1 :     FIB_TEST((ai_01 == dpo1->dpoi_index),
    1403             :              "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
    1404             :              ai_01, dpo1->dpoi_index);
    1405             : 
    1406           1 :     dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
    1407           1 :     FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
    1408           1 :     FIB_TEST((ai_02 == dpo1->dpoi_index),
    1409             :              "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
    1410             : 
    1411             :     /*
    1412             :      * +1 shared-pathlist
    1413             :      */
    1414           1 :     FIB_TEST((2 == fib_path_list_db_size()),   "path list DB is empty");
    1415           1 :     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
    1416             :              fib_path_list_pool_size());
    1417           1 :     FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
    1418             :              fib_entry_pool_size());
    1419             : 
    1420             :     /*
    1421             :      * revert the modify
    1422             :      */
    1423           1 :     fib_table_entry_path_remove(fib_index,
    1424             :                                 &pfx_1_1_2_0_s_24,
    1425             :                                 FIB_SOURCE_API,
    1426             :                                 DPO_PROTO_IP4,
    1427             :                                 &nh_10_10_10_2,
    1428           1 :                                 tm->hw[0]->sw_if_index,
    1429             :                                 ~0,
    1430             :                                 1,
    1431             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    1432           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
    1433           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1434           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    1435             :                                     1, tm->hw[0]->sw_if_index),
    1436             :              "RPF list for 1.1.2.0/24 contains one adj");
    1437             : 
    1438           1 :     ai = fib_entry_get_adj(fei);
    1439           1 :     FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
    1440             : 
    1441             :     /*
    1442             :      * +1 shared-pathlist
    1443             :      */
    1444           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB is %d",
    1445             :              fib_path_list_db_size());
    1446           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    1447             :              fib_path_list_pool_size());
    1448           1 :     FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
    1449             :              fib_entry_pool_size());
    1450             : 
    1451             :     /*
    1452             :      * Add 2 recursive routes:
    1453             :      *   100.100.100.100/32 via 1.1.1.1/32  => the via entry is installed.
    1454             :      *   100.100.100.101/32 via 1.1.1.1/32  => the via entry is installed.
    1455             :      */
    1456           2 :     fib_prefix_t bgp_100_pfx = {
    1457             :         .fp_len = 32,
    1458             :         .fp_proto = FIB_PROTOCOL_IP4,
    1459             :         .fp_addr = {
    1460             :             /* 100.100.100.100/32 */
    1461           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
    1462             :         },
    1463             :     };
    1464             :     /* via 1.1.1.1 */
    1465           2 :     ip46_address_t nh_1_1_1_1 = {
    1466           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
    1467             :     };
    1468             : 
    1469           1 :     fei = fib_table_entry_path_add(fib_index,
    1470             :                                    &bgp_100_pfx,
    1471             :                                    FIB_SOURCE_API,
    1472             :                                    FIB_ENTRY_FLAG_NONE,
    1473             :                                    DPO_PROTO_IP4,
    1474             :                                    &nh_1_1_1_1,
    1475             :                                    ~0, // no index provided.
    1476             :                                    fib_index, // nexthop in same fib as route
    1477             :                                    1,
    1478             :                                    NULL,
    1479             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    1480             : 
    1481           1 :     FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
    1482           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
    1483             :                                     tm->hw[0]->sw_if_index),
    1484             :              "RPF list for adj-fib contains adj");
    1485             : 
    1486             :     /*
    1487             :      * +1 entry and +1 shared-path-list
    1488             :      */
    1489           1 :     FIB_TEST((2  == fib_path_list_db_size()),   "path list DB population:%d",
    1490             :              fib_path_list_db_size());
    1491           1 :     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
    1492             :              fib_path_list_pool_size());
    1493           1 :     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
    1494             :              fib_entry_pool_size());
    1495             : 
    1496           2 :     fib_prefix_t bgp_101_pfx = {
    1497             :         .fp_len = 32,
    1498             :         .fp_proto = FIB_PROTOCOL_IP4,
    1499             :         .fp_addr = {
    1500             :             /* 100.100.100.101/32 */
    1501           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
    1502             :         },
    1503             :     };
    1504             : 
    1505           1 :     fib_table_entry_path_add(fib_index,
    1506             :                              &bgp_101_pfx,
    1507             :                              FIB_SOURCE_API,
    1508             :                              FIB_ENTRY_FLAG_NONE,
    1509             :                              DPO_PROTO_IP4,
    1510             :                              &nh_1_1_1_1,
    1511             :                              ~0, // no index provided.
    1512             :                              fib_index, // nexthop in same fib as route
    1513             :                              1,
    1514             :                              NULL,
    1515             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1516             : 
    1517           1 :     FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
    1518           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
    1519             :                                     tm->hw[0]->sw_if_index),
    1520             :              "RPF list for adj-fib contains adj");
    1521             : 
    1522             :     /*
    1523             :      * +1 entry, but the recursive path-list is shared.
    1524             :      */
    1525           1 :     FIB_TEST((2  == fib_path_list_db_size()),   "path list DB population:%d",
    1526             :              fib_path_list_db_size());
    1527           1 :     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
    1528             :              fib_path_list_pool_size());
    1529           1 :     FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
    1530             :              fib_entry_pool_size());
    1531             : 
    1532             :     /*
    1533             :      * An special route; one where the user (me) provides the
    1534             :      * adjacency through which the route will resovle by setting the flags
    1535             :      */
    1536           2 :     fib_prefix_t ex_pfx = {
    1537             :         .fp_len = 32,
    1538             :         .fp_proto = FIB_PROTOCOL_IP4,
    1539             :         .fp_addr = {
    1540             :             /* 4.4.4.4/32 */
    1541           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
    1542             :         },
    1543             :     };
    1544             : 
    1545           1 :     fib_table_entry_special_add(fib_index,
    1546             :                                 &ex_pfx,
    1547             :                                 FIB_SOURCE_SPECIAL,
    1548             :                                 FIB_ENTRY_FLAG_LOCAL);
    1549           1 :     fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
    1550           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1551           1 :     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
    1552           1 :     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
    1553             :              "local interface adj is local");
    1554             : 
    1555           1 :     fib_table_entry_special_remove(fib_index,
    1556             :                                    &ex_pfx,
    1557             :                                    FIB_SOURCE_SPECIAL);
    1558           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    1559             :              fib_table_lookup_exact_match(fib_index, &ex_pfx),
    1560             :              "Exclusive reoute removed");
    1561             : 
    1562             :     /*
    1563             :      * An EXCLUSIVE route; one where the user (me) provides the exclusive
    1564             :      * adjacency through which the route will resovle
    1565             :      */
    1566           1 :     dpo_id_t ex_dpo = DPO_INVALID;
    1567             : 
    1568           1 :     lookup_dpo_add_or_lock_w_fib_index(fib_index,
    1569             :                                        DPO_PROTO_IP4,
    1570             :                                        LOOKUP_UNICAST,
    1571             :                                        LOOKUP_INPUT_DST_ADDR,
    1572             :                                        LOOKUP_TABLE_FROM_CONFIG,
    1573             :                                        &ex_dpo);
    1574             : 
    1575           1 :     fib_table_entry_special_dpo_add(fib_index,
    1576             :                                     &ex_pfx,
    1577             :                                     FIB_SOURCE_SPECIAL,
    1578             :                                     FIB_ENTRY_FLAG_EXCLUSIVE,
    1579             :                                     &ex_dpo);
    1580           1 :     fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
    1581           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1582           1 :     FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
    1583             :              "exclusive remote uses lookup DPO");
    1584             : 
    1585             :     /*
    1586             :      * update the exclusive to use a different DPO
    1587             :      */
    1588           1 :     ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
    1589             :                              IP_NULL_ACTION_SEND_ICMP_UNREACH,
    1590             :                              &ex_dpo);
    1591           1 :     fib_table_entry_special_dpo_update(fib_index,
    1592             :                                        &ex_pfx,
    1593             :                                        FIB_SOURCE_SPECIAL,
    1594             :                                        FIB_ENTRY_FLAG_EXCLUSIVE,
    1595             :                                        &ex_dpo);
    1596           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1597           1 :     FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
    1598             :              "exclusive remote uses now uses NULL DPO");
    1599             : 
    1600           1 :     fib_table_entry_special_remove(fib_index,
    1601             :                                    &ex_pfx,
    1602             :                                    FIB_SOURCE_SPECIAL);
    1603           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    1604             :              fib_table_lookup_exact_match(fib_index, &ex_pfx),
    1605             :              "Exclusive reoute removed");
    1606           1 :     dpo_reset(&ex_dpo);
    1607             : 
    1608             :     /*
    1609             :      * Add a recursive route:
    1610             :      *   200.200.200.200/32 via 1.1.1.2/32  => the via entry is NOT installed.
    1611             :      */
    1612           2 :     fib_prefix_t bgp_200_pfx = {
    1613             :         .fp_len = 32,
    1614             :         .fp_proto = FIB_PROTOCOL_IP4,
    1615             :         .fp_addr = {
    1616             :             /* 200.200.200.200/32 */
    1617           1 :             .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
    1618             :         },
    1619             :     };
    1620             :     /* via 1.1.1.2 */
    1621           2 :     fib_prefix_t pfx_1_1_1_2_s_32 = {
    1622             :         .fp_len = 32,
    1623             :         .fp_proto = FIB_PROTOCOL_IP4,
    1624             :         .fp_addr = {
    1625           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
    1626             :         },
    1627             :     };
    1628             : 
    1629           1 :     fei = fib_table_entry_path_add(fib_index,
    1630             :                                    &bgp_200_pfx,
    1631             :                                    FIB_SOURCE_API,
    1632             :                                    FIB_ENTRY_FLAG_NONE,
    1633             :                                    DPO_PROTO_IP4,
    1634             :                                    &pfx_1_1_1_2_s_32.fp_addr,
    1635             :                                    ~0, // no index provided.
    1636             :                                    fib_index, // nexthop in same fib as route
    1637             :                                    1,
    1638             :                                    NULL,
    1639             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    1640             : 
    1641           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    1642             :              "Recursive via unresolved is drop");
    1643             : 
    1644             :     /*
    1645             :      * the adj should be recursive via drop, since the route resolves via
    1646             :      * the default route, which is itself a DROP
    1647             :      */
    1648           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
    1649           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    1650           1 :     FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
    1651           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
    1652             :              "RPF list for 1.1.1.2/32 contains 0 adjs");
    1653             : 
    1654             :     /*
    1655             :      * +2 entry and +1 shared-path-list
    1656             :      */
    1657           1 :     FIB_TEST((3  == fib_path_list_db_size()),   "path list DB population:%d",
    1658             :              fib_path_list_db_size());
    1659           1 :     FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
    1660             :              fib_path_list_pool_size());
    1661           1 :     FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
    1662             :              fib_entry_pool_size());
    1663             : 
    1664             :     /*
    1665             :      * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
    1666             :      * The paths are sort by NH first. in this case the the path with greater
    1667             :      * weight is first in the set. This ordering is to test the RPF sort|uniq logic
    1668             :      */
    1669           2 :     fib_prefix_t pfx_1_2_3_4_s_32 = {
    1670             :         .fp_len = 32,
    1671             :         .fp_proto = FIB_PROTOCOL_IP4,
    1672             :         .fp_addr = {
    1673           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
    1674             :         },
    1675             :     };
    1676           1 :     fib_table_entry_path_add(fib_index,
    1677             :                              &pfx_1_2_3_4_s_32,
    1678             :                              FIB_SOURCE_API,
    1679             :                              FIB_ENTRY_FLAG_NONE,
    1680             :                              DPO_PROTO_IP4,
    1681             :                              &nh_10_10_10_1,
    1682           1 :                              tm->hw[0]->sw_if_index,
    1683             :                              ~0,
    1684             :                              1,
    1685             :                              NULL,
    1686             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1687           1 :     fei = fib_table_entry_path_add(fib_index,
    1688             :                                    &pfx_1_2_3_4_s_32,
    1689             :                                    FIB_SOURCE_API,
    1690             :                                    FIB_ENTRY_FLAG_NONE,
    1691             :                                    DPO_PROTO_IP4,
    1692             :                                    &nh_12_12_12_12,
    1693           1 :                                    tm->hw[1]->sw_if_index,
    1694             :                                    ~0,
    1695             :                                    3,
    1696             :                                    NULL,
    1697             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    1698             : 
    1699           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
    1700           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1701           1 :     lb = load_balance_get(dpo->dpoi_index);
    1702           1 :     FIB_TEST((lb->lb_n_buckets == 4),
    1703             :              "1.2.3.4/32 LB has %d bucket",
    1704             :              lb->lb_n_buckets);
    1705             : 
    1706           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
    1707           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
    1708           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
    1709           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
    1710             : 
    1711           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
    1712             :                                     tm->hw[0]->sw_if_index,
    1713             :                                     tm->hw[1]->sw_if_index),
    1714             :              "RPF list for 1.2.3.4/32 contains both adjs");
    1715             : 
    1716             : 
    1717             :     /*
    1718             :      * Unequal Cost load-balance. 4:1 ratio.
    1719             :      *  fits in a 16 bucket LB with ratio 13:3
    1720             :      */
    1721           2 :     fib_prefix_t pfx_1_2_3_5_s_32 = {
    1722             :         .fp_len = 32,
    1723             :         .fp_proto = FIB_PROTOCOL_IP4,
    1724             :         .fp_addr = {
    1725           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
    1726             :         },
    1727             :     };
    1728           1 :     fib_table_entry_path_add(fib_index,
    1729             :                              &pfx_1_2_3_5_s_32,
    1730             :                              FIB_SOURCE_API,
    1731             :                              FIB_ENTRY_FLAG_NONE,
    1732             :                              DPO_PROTO_IP4,
    1733             :                              &nh_12_12_12_12,
    1734           1 :                              tm->hw[1]->sw_if_index,
    1735             :                              ~0,
    1736             :                              1,
    1737             :                              NULL,
    1738             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1739           1 :     fei = fib_table_entry_path_add(fib_index,
    1740             :                                    &pfx_1_2_3_5_s_32,
    1741             :                                    FIB_SOURCE_API,
    1742             :                                    FIB_ENTRY_FLAG_NONE,
    1743             :                                    DPO_PROTO_IP4,
    1744             :                                    &nh_10_10_10_1,
    1745           1 :                                    tm->hw[0]->sw_if_index,
    1746             :                                    ~0,
    1747             :                                    4,
    1748             :                                    NULL,
    1749             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    1750             : 
    1751           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
    1752           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    1753           1 :     lb = load_balance_get(dpo->dpoi_index);
    1754           1 :     FIB_TEST((lb->lb_n_buckets == 16),
    1755             :              "1.2.3.5/32 LB has %d bucket",
    1756             :              lb->lb_n_buckets);
    1757             : 
    1758           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
    1759           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
    1760           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
    1761           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
    1762           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
    1763           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
    1764           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
    1765           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
    1766           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
    1767           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
    1768           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
    1769           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
    1770           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
    1771           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
    1772           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
    1773           1 :     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
    1774             : 
    1775           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
    1776             :                                     tm->hw[0]->sw_if_index,
    1777             :                                     tm->hw[1]->sw_if_index),
    1778             :              "RPF list for 1.2.3.4/32 contains both adjs");
    1779             : 
    1780             :     /*
    1781             :      * Test UCMP with a large weight skew - this produces load-balance objects with large
    1782             :      * numbers of buckets to accommodate the skew. By updating said load-balances we are
    1783             :      * laso testing the LB in placce modify code when number of buckets is large.
    1784             :      */
    1785           2 :     fib_prefix_t pfx_6_6_6_6_s_32 = {
    1786             :         .fp_len = 32,
    1787             :         .fp_proto = FIB_PROTOCOL_IP4,
    1788             :         .fp_addr = {
    1789             :             /* 1.1.1.1/32 */
    1790           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
    1791             :         },
    1792             :     };
    1793           1 :     fib_test_lb_bucket_t ip_o_10_10_10_1 = {
    1794             :         .type = FT_LB_ADJ,
    1795             :         .adj = {
    1796             :             .adj = ai_01,
    1797             :         },
    1798             :     };
    1799           1 :     fib_test_lb_bucket_t ip_o_10_10_10_2 = {
    1800             :         .type = FT_LB_ADJ,
    1801             :         .adj = {
    1802             :             .adj = ai_02,
    1803             :         },
    1804             :     };
    1805           1 :     fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
    1806             :         .type = FT_LB_ADJ,
    1807             :         .adj = {
    1808             :             .adj = ai_12_12_12_12,
    1809             :         },
    1810             :     };
    1811           1 :     fib_table_entry_update_one_path(fib_index,
    1812             :                                     &pfx_6_6_6_6_s_32,
    1813             :                                     FIB_SOURCE_API,
    1814             :                                     FIB_ENTRY_FLAG_NONE,
    1815             :                                     DPO_PROTO_IP4,
    1816             :                                     &nh_10_10_10_1,
    1817           1 :                                     tm->hw[0]->sw_if_index,
    1818             :                                     ~0, // invalid fib index
    1819             :                                     0,  // zero weigth
    1820             :                                     NULL,
    1821             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    1822             : 
    1823           1 :     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
    1824           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    1825             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    1826             :                                       1,
    1827             :                                       &ip_o_10_10_10_1),
    1828             :              "6.6.6.6/32 via 10.10.10.1");
    1829             : 
    1830           1 :     fib_table_entry_path_add(fib_index,
    1831             :                              &pfx_6_6_6_6_s_32,
    1832             :                              FIB_SOURCE_API,
    1833             :                              FIB_ENTRY_FLAG_NONE,
    1834             :                              DPO_PROTO_IP4,
    1835             :                              &nh_10_10_10_2,
    1836           1 :                              tm->hw[0]->sw_if_index,
    1837             :                              ~0, // invalid fib index
    1838             :                              100,
    1839             :                              NULL,
    1840             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1841             : 
    1842           1 :     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
    1843           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    1844             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    1845             :                                       64,
    1846             :                                       &ip_o_10_10_10_2,
    1847             :                                       &ip_o_10_10_10_2,
    1848             :                                       &ip_o_10_10_10_2,
    1849             :                                       &ip_o_10_10_10_2,
    1850             :                                       &ip_o_10_10_10_2,
    1851             :                                       &ip_o_10_10_10_2,
    1852             :                                       &ip_o_10_10_10_2,
    1853             :                                       &ip_o_10_10_10_2,
    1854             :                                       &ip_o_10_10_10_2,
    1855             :                                       &ip_o_10_10_10_2,
    1856             :                                       &ip_o_10_10_10_2,
    1857             :                                       &ip_o_10_10_10_2,
    1858             :                                       &ip_o_10_10_10_2,
    1859             :                                       &ip_o_10_10_10_2,
    1860             :                                       &ip_o_10_10_10_2,
    1861             :                                       &ip_o_10_10_10_2,
    1862             :                                       &ip_o_10_10_10_2,
    1863             :                                       &ip_o_10_10_10_2,
    1864             :                                       &ip_o_10_10_10_2,
    1865             :                                       &ip_o_10_10_10_2,
    1866             :                                       &ip_o_10_10_10_2,
    1867             :                                       &ip_o_10_10_10_2,
    1868             :                                       &ip_o_10_10_10_2,
    1869             :                                       &ip_o_10_10_10_2,
    1870             :                                       &ip_o_10_10_10_2,
    1871             :                                       &ip_o_10_10_10_2,
    1872             :                                       &ip_o_10_10_10_2,
    1873             :                                       &ip_o_10_10_10_2,
    1874             :                                       &ip_o_10_10_10_2,
    1875             :                                       &ip_o_10_10_10_2,
    1876             :                                       &ip_o_10_10_10_2,
    1877             :                                       &ip_o_10_10_10_2,
    1878             :                                       &ip_o_10_10_10_2,
    1879             :                                       &ip_o_10_10_10_2,
    1880             :                                       &ip_o_10_10_10_2,
    1881             :                                       &ip_o_10_10_10_2,
    1882             :                                       &ip_o_10_10_10_2,
    1883             :                                       &ip_o_10_10_10_2,
    1884             :                                       &ip_o_10_10_10_2,
    1885             :                                       &ip_o_10_10_10_2,
    1886             :                                       &ip_o_10_10_10_2,
    1887             :                                       &ip_o_10_10_10_2,
    1888             :                                       &ip_o_10_10_10_2,
    1889             :                                       &ip_o_10_10_10_2,
    1890             :                                       &ip_o_10_10_10_2,
    1891             :                                       &ip_o_10_10_10_2,
    1892             :                                       &ip_o_10_10_10_2,
    1893             :                                       &ip_o_10_10_10_2,
    1894             :                                       &ip_o_10_10_10_2,
    1895             :                                       &ip_o_10_10_10_2,
    1896             :                                       &ip_o_10_10_10_2,
    1897             :                                       &ip_o_10_10_10_2,
    1898             :                                       &ip_o_10_10_10_2,
    1899             :                                       &ip_o_10_10_10_2,
    1900             :                                       &ip_o_10_10_10_2,
    1901             :                                       &ip_o_10_10_10_2,
    1902             :                                       &ip_o_10_10_10_2,
    1903             :                                       &ip_o_10_10_10_2,
    1904             :                                       &ip_o_10_10_10_2,
    1905             :                                       &ip_o_10_10_10_2,
    1906             :                                       &ip_o_10_10_10_2,
    1907             :                                       &ip_o_10_10_10_2,
    1908             :                                       &ip_o_10_10_10_2,
    1909             :                                       &ip_o_10_10_10_1),
    1910             :              "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
    1911             : 
    1912           1 :     fib_table_entry_path_add(fib_index,
    1913             :                              &pfx_6_6_6_6_s_32,
    1914             :                              FIB_SOURCE_API,
    1915             :                              FIB_ENTRY_FLAG_NONE,
    1916             :                              DPO_PROTO_IP4,
    1917             :                              &nh_12_12_12_12,
    1918           1 :                              tm->hw[1]->sw_if_index,
    1919             :                              ~0, // invalid fib index
    1920             :                              100,
    1921             :                              NULL,
    1922             :                              FIB_ROUTE_PATH_FLAG_NONE);
    1923             : 
    1924           1 :     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
    1925           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    1926             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    1927             :                                       128,
    1928             :                                       &ip_o_10_10_10_1,
    1929             :                                       &ip_o_10_10_10_2,
    1930             :                                       &ip_o_10_10_10_2,
    1931             :                                       &ip_o_10_10_10_2,
    1932             :                                       &ip_o_10_10_10_2,
    1933             :                                       &ip_o_10_10_10_2,
    1934             :                                       &ip_o_10_10_10_2,
    1935             :                                       &ip_o_10_10_10_2,
    1936             :                                       &ip_o_10_10_10_2,
    1937             :                                       &ip_o_10_10_10_2,
    1938             :                                       &ip_o_10_10_10_2,
    1939             :                                       &ip_o_10_10_10_2,
    1940             :                                       &ip_o_10_10_10_2,
    1941             :                                       &ip_o_10_10_10_2,
    1942             :                                       &ip_o_10_10_10_2,
    1943             :                                       &ip_o_10_10_10_2,
    1944             :                                       &ip_o_10_10_10_2,
    1945             :                                       &ip_o_10_10_10_2,
    1946             :                                       &ip_o_10_10_10_2,
    1947             :                                       &ip_o_10_10_10_2,
    1948             :                                       &ip_o_10_10_10_2,
    1949             :                                       &ip_o_10_10_10_2,
    1950             :                                       &ip_o_10_10_10_2,
    1951             :                                       &ip_o_10_10_10_2,
    1952             :                                       &ip_o_10_10_10_2,
    1953             :                                       &ip_o_10_10_10_2,
    1954             :                                       &ip_o_10_10_10_2,
    1955             :                                       &ip_o_10_10_10_2,
    1956             :                                       &ip_o_10_10_10_2,
    1957             :                                       &ip_o_10_10_10_2,
    1958             :                                       &ip_o_10_10_10_2,
    1959             :                                       &ip_o_10_10_10_2,
    1960             :                                       &ip_o_10_10_10_2,
    1961             :                                       &ip_o_10_10_10_2,
    1962             :                                       &ip_o_10_10_10_2,
    1963             :                                       &ip_o_10_10_10_2,
    1964             :                                       &ip_o_10_10_10_2,
    1965             :                                       &ip_o_10_10_10_2,
    1966             :                                       &ip_o_10_10_10_2,
    1967             :                                       &ip_o_10_10_10_2,
    1968             :                                       &ip_o_10_10_10_2,
    1969             :                                       &ip_o_10_10_10_2,
    1970             :                                       &ip_o_10_10_10_2,
    1971             :                                       &ip_o_10_10_10_2,
    1972             :                                       &ip_o_10_10_10_2,
    1973             :                                       &ip_o_10_10_10_2,
    1974             :                                       &ip_o_10_10_10_2,
    1975             :                                       &ip_o_10_10_10_2,
    1976             :                                       &ip_o_10_10_10_2,
    1977             :                                       &ip_o_10_10_10_2,
    1978             :                                       &ip_o_10_10_10_2,
    1979             :                                       &ip_o_10_10_10_2,
    1980             :                                       &ip_o_10_10_10_2,
    1981             :                                       &ip_o_10_10_10_2,
    1982             :                                       &ip_o_10_10_10_2,
    1983             :                                       &ip_o_10_10_10_2,
    1984             :                                       &ip_o_10_10_10_2,
    1985             :                                       &ip_o_10_10_10_2,
    1986             :                                       &ip_o_10_10_10_2,
    1987             :                                       &ip_o_10_10_10_2,
    1988             :                                       &ip_o_10_10_10_2,
    1989             :                                       &ip_o_10_10_10_2,
    1990             :                                       &ip_o_10_10_10_2,
    1991             :                                       &ip_o_10_10_10_2,
    1992             :                                       &ip_o_10_10_10_2,
    1993             :                                       &ip_6_6_6_6_o_12_12_12_12,
    1994             :                                       &ip_6_6_6_6_o_12_12_12_12,
    1995             :                                       &ip_6_6_6_6_o_12_12_12_12,
    1996             :                                       &ip_6_6_6_6_o_12_12_12_12,
    1997             :                                       &ip_6_6_6_6_o_12_12_12_12,
    1998             :                                       &ip_6_6_6_6_o_12_12_12_12,
    1999             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2000             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2001             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2002             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2003             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2004             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2005             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2006             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2007             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2008             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2009             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2010             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2011             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2012             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2013             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2014             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2015             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2016             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2017             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2018             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2019             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2020             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2021             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2022             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2023             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2024             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2025             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2026             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2027             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2028             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2029             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2030             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2031             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2032             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2033             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2034             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2035             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2036             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2037             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2038             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2039             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2040             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2041             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2042             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2043             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2044             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2045             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2046             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2047             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2048             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2049             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2050             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2051             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2052             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2053             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2054             :                                       &ip_6_6_6_6_o_12_12_12_12,
    2055             :                                       &ip_6_6_6_6_o_12_12_12_12),
    2056             :              "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
    2057             : 
    2058           1 :     fib_table_entry_path_remove(fib_index,
    2059             :                                 &pfx_6_6_6_6_s_32,
    2060             :                                 FIB_SOURCE_API,
    2061             :                                 DPO_PROTO_IP4,
    2062             :                                 &nh_12_12_12_12,
    2063           1 :                                 tm->hw[1]->sw_if_index,
    2064             :                                 ~0, // invalid fib index
    2065             :                                 100,
    2066             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2067             : 
    2068           1 :     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
    2069           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    2070             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    2071             :                                       64,
    2072             :                                       &ip_o_10_10_10_2,
    2073             :                                       &ip_o_10_10_10_2,
    2074             :                                       &ip_o_10_10_10_2,
    2075             :                                       &ip_o_10_10_10_2,
    2076             :                                       &ip_o_10_10_10_2,
    2077             :                                       &ip_o_10_10_10_2,
    2078             :                                       &ip_o_10_10_10_2,
    2079             :                                       &ip_o_10_10_10_2,
    2080             :                                       &ip_o_10_10_10_2,
    2081             :                                       &ip_o_10_10_10_2,
    2082             :                                       &ip_o_10_10_10_2,
    2083             :                                       &ip_o_10_10_10_2,
    2084             :                                       &ip_o_10_10_10_2,
    2085             :                                       &ip_o_10_10_10_2,
    2086             :                                       &ip_o_10_10_10_2,
    2087             :                                       &ip_o_10_10_10_2,
    2088             :                                       &ip_o_10_10_10_2,
    2089             :                                       &ip_o_10_10_10_2,
    2090             :                                       &ip_o_10_10_10_2,
    2091             :                                       &ip_o_10_10_10_2,
    2092             :                                       &ip_o_10_10_10_2,
    2093             :                                       &ip_o_10_10_10_2,
    2094             :                                       &ip_o_10_10_10_2,
    2095             :                                       &ip_o_10_10_10_2,
    2096             :                                       &ip_o_10_10_10_2,
    2097             :                                       &ip_o_10_10_10_2,
    2098             :                                       &ip_o_10_10_10_2,
    2099             :                                       &ip_o_10_10_10_2,
    2100             :                                       &ip_o_10_10_10_2,
    2101             :                                       &ip_o_10_10_10_2,
    2102             :                                       &ip_o_10_10_10_2,
    2103             :                                       &ip_o_10_10_10_2,
    2104             :                                       &ip_o_10_10_10_2,
    2105             :                                       &ip_o_10_10_10_2,
    2106             :                                       &ip_o_10_10_10_2,
    2107             :                                       &ip_o_10_10_10_2,
    2108             :                                       &ip_o_10_10_10_2,
    2109             :                                       &ip_o_10_10_10_2,
    2110             :                                       &ip_o_10_10_10_2,
    2111             :                                       &ip_o_10_10_10_2,
    2112             :                                       &ip_o_10_10_10_2,
    2113             :                                       &ip_o_10_10_10_2,
    2114             :                                       &ip_o_10_10_10_2,
    2115             :                                       &ip_o_10_10_10_2,
    2116             :                                       &ip_o_10_10_10_2,
    2117             :                                       &ip_o_10_10_10_2,
    2118             :                                       &ip_o_10_10_10_2,
    2119             :                                       &ip_o_10_10_10_2,
    2120             :                                       &ip_o_10_10_10_2,
    2121             :                                       &ip_o_10_10_10_2,
    2122             :                                       &ip_o_10_10_10_2,
    2123             :                                       &ip_o_10_10_10_2,
    2124             :                                       &ip_o_10_10_10_2,
    2125             :                                       &ip_o_10_10_10_2,
    2126             :                                       &ip_o_10_10_10_2,
    2127             :                                       &ip_o_10_10_10_2,
    2128             :                                       &ip_o_10_10_10_2,
    2129             :                                       &ip_o_10_10_10_2,
    2130             :                                       &ip_o_10_10_10_2,
    2131             :                                       &ip_o_10_10_10_2,
    2132             :                                       &ip_o_10_10_10_2,
    2133             :                                       &ip_o_10_10_10_2,
    2134             :                                       &ip_o_10_10_10_2,
    2135             :                                       &ip_o_10_10_10_1),
    2136             :              "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
    2137             : 
    2138           1 :     fib_table_entry_path_remove(fib_index,
    2139             :                                 &pfx_6_6_6_6_s_32,
    2140             :                                 FIB_SOURCE_API,
    2141             :                                 DPO_PROTO_IP4,
    2142             :                                 &nh_10_10_10_2,
    2143           1 :                                 tm->hw[0]->sw_if_index,
    2144             :                                 ~0, // invalid fib index
    2145             :                                 100,
    2146             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2147             : 
    2148           1 :     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
    2149           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    2150             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    2151             :                                       1,
    2152             :                                       &ip_o_10_10_10_1),
    2153             :              "6.6.6.6/32 via 10.10.10.1");
    2154             : 
    2155           1 :     fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
    2156             : 
    2157             :     /*
    2158             :      * A recursive via the two unequal cost entries
    2159             :      */
    2160           2 :     fib_prefix_t bgp_44_s_32 = {
    2161             :         .fp_len = 32,
    2162             :         .fp_proto = FIB_PROTOCOL_IP4,
    2163             :         .fp_addr = {
    2164             :             /* 200.200.200.201/32 */
    2165           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
    2166             :         },
    2167             :     };
    2168           1 :     fei = fib_table_entry_path_add(fib_index,
    2169             :                                    &bgp_44_s_32,
    2170             :                                    FIB_SOURCE_API,
    2171             :                                    FIB_ENTRY_FLAG_NONE,
    2172             :                                    DPO_PROTO_IP4,
    2173             :                                    &pfx_1_2_3_4_s_32.fp_addr,
    2174             :                                    ~0,
    2175             :                                    fib_index,
    2176             :                                    1,
    2177             :                                    NULL,
    2178             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    2179           1 :     fei = fib_table_entry_path_add(fib_index,
    2180             :                                    &bgp_44_s_32,
    2181             :                                    FIB_SOURCE_API,
    2182             :                                    FIB_ENTRY_FLAG_NONE,
    2183             :                                    DPO_PROTO_IP4,
    2184             :                                    &pfx_1_2_3_5_s_32.fp_addr,
    2185             :                                    ~0,
    2186             :                                    fib_index,
    2187             :                                    1,
    2188             :                                    NULL,
    2189             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    2190             : 
    2191           1 :     FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
    2192           1 :     FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
    2193           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
    2194             :                                     tm->hw[0]->sw_if_index,
    2195             :                                     tm->hw[1]->sw_if_index),
    2196             :              "RPF list for 1.2.3.4/32 contains both adjs");
    2197             : 
    2198             :     /*
    2199             :      * test the uRPF check functions
    2200             :      */
    2201           1 :     dpo_id_t dpo_44 = DPO_INVALID;
    2202             :     index_t urpfi;
    2203             : 
    2204           1 :     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
    2205           1 :     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
    2206             : 
    2207           1 :     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
    2208             :              "uRPF check for 68.68.68.68/32 on %d OK",
    2209             :              tm->hw[0]->sw_if_index);
    2210           1 :     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
    2211             :              "uRPF check for 68.68.68.68/32 on %d OK",
    2212             :              tm->hw[1]->sw_if_index);
    2213           1 :     FIB_TEST(!fib_urpf_check(urpfi, 99),
    2214             :              "uRPF check for 68.68.68.68/32 on 99 not-OK",
    2215             :              99);
    2216           1 :     dpo_reset(&dpo_44);
    2217             : 
    2218           1 :     fib_table_entry_delete(fib_index,
    2219             :                            &bgp_44_s_32,
    2220             :                            FIB_SOURCE_API);
    2221           1 :     fib_table_entry_delete(fib_index,
    2222             :                            &pfx_1_2_3_5_s_32,
    2223             :                            FIB_SOURCE_API);
    2224           1 :     fib_table_entry_delete(fib_index,
    2225             :                            &pfx_1_2_3_4_s_32,
    2226             :                            FIB_SOURCE_API);
    2227             : 
    2228             :     /*
    2229             :      * Add a recursive route:
    2230             :      *   200.200.200.201/32 via 1.1.1.200/32  => the via entry is NOT installed.
    2231             :      */
    2232           2 :     fib_prefix_t bgp_201_pfx = {
    2233             :         .fp_len = 32,
    2234             :         .fp_proto = FIB_PROTOCOL_IP4,
    2235             :         .fp_addr = {
    2236             :             /* 200.200.200.201/32 */
    2237           1 :             .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
    2238             :         },
    2239             :     };
    2240             :     /* via 1.1.1.200 */
    2241           2 :     fib_prefix_t pfx_1_1_1_200_s_32 = {
    2242             :         .fp_len = 32,
    2243             :         .fp_proto = FIB_PROTOCOL_IP4,
    2244             :         .fp_addr = {
    2245           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
    2246             :         },
    2247             :     };
    2248             : 
    2249           1 :     fei = fib_table_entry_path_add(fib_index,
    2250             :                                    &bgp_201_pfx,
    2251             :                                    FIB_SOURCE_API,
    2252             :                                    FIB_ENTRY_FLAG_NONE,
    2253             :                                    DPO_PROTO_IP4,
    2254             :                                    &pfx_1_1_1_200_s_32.fp_addr,
    2255             :                                    ~0, // no index provided.
    2256             :                                    fib_index, // nexthop in same fib as route
    2257             :                                    1,
    2258             :                                    NULL,
    2259             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    2260             : 
    2261           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2262             :              "Recursive via unresolved is drop");
    2263             : 
    2264           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
    2265           1 :     FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
    2266             :              "Flags set on RR via non-attached");
    2267           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
    2268             :              "RPF list for BGP route empty");
    2269             : 
    2270             :     /*
    2271             :      * +2 entry (BGP & RR) and +1 shared-path-list
    2272             :      */
    2273           1 :     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
    2274             :              fib_path_list_db_size());
    2275           1 :     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
    2276             :              fib_path_list_pool_size());
    2277           1 :     FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
    2278             :              fib_entry_pool_size());
    2279             : 
    2280             :     /*
    2281             :      * insert a route that covers the missing 1.1.1.2/32. we epxect
    2282             :      * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
    2283             :      */
    2284           2 :     fib_prefix_t pfx_1_1_1_0_s_24 = {
    2285             :         .fp_len = 24,
    2286             :         .fp_proto = FIB_PROTOCOL_IP4,
    2287             :         .fp_addr = {
    2288             :             /* 1.1.1.0/24 */
    2289           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
    2290             :         },
    2291             :     };
    2292             : 
    2293           1 :     fib_table_entry_path_add(fib_index,
    2294             :                              &pfx_1_1_1_0_s_24,
    2295             :                              FIB_SOURCE_API,
    2296             :                              FIB_ENTRY_FLAG_NONE,
    2297             :                              DPO_PROTO_IP4,
    2298             :                              &nh_10_10_10_1,
    2299           1 :                              tm->hw[0]->sw_if_index,
    2300             :                              ~0, // invalid fib index
    2301             :                              1,
    2302             :                              NULL,
    2303             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2304           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
    2305           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2306           1 :     ai = fib_entry_get_adj(fei);
    2307           1 :     FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
    2308           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
    2309           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2310           1 :     ai = fib_entry_get_adj(fei);
    2311           1 :     FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
    2312           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
    2313           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2314           1 :     ai = fib_entry_get_adj(fei);
    2315           1 :     FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
    2316             : 
    2317             :     /*
    2318             :      * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
    2319             :      */
    2320           1 :     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
    2321             :              fib_path_list_db_size());
    2322           1 :     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
    2323             :              fib_path_list_pool_size());
    2324           1 :     FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
    2325             :              fib_entry_pool_size());
    2326             : 
    2327             :     /*
    2328             :      * the recursive adj for 200.200.200.200 should be updated.
    2329             :      */
    2330           1 :     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
    2331           1 :     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
    2332           1 :     fei = fib_table_lookup(fib_index, &bgp_200_pfx);
    2333           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
    2334             :                                     tm->hw[0]->sw_if_index),
    2335             :              "RPF list for BGP route has itf index 0");
    2336             : 
    2337             :     /*
    2338             :      * insert a more specific route than 1.1.1.0/24 that also covers the
    2339             :      * missing 1.1.1.2/32, but not 1.1.1.200/32. we expect
    2340             :      * 200.200.200.200 to resolve through it.
    2341             :      */
    2342           2 :     fib_prefix_t pfx_1_1_1_0_s_28 = {
    2343             :         .fp_len = 28,
    2344             :         .fp_proto = FIB_PROTOCOL_IP4,
    2345             :         .fp_addr = {
    2346             :             /* 1.1.1.0/24 */
    2347           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
    2348             :         },
    2349             :     };
    2350             : 
    2351           1 :     fib_table_entry_path_add(fib_index,
    2352             :                              &pfx_1_1_1_0_s_28,
    2353             :                              FIB_SOURCE_API,
    2354             :                              FIB_ENTRY_FLAG_NONE,
    2355             :                              DPO_PROTO_IP4,
    2356             :                              &nh_10_10_10_2,
    2357           1 :                              tm->hw[0]->sw_if_index,
    2358             :                              ~0, // invalid fib index
    2359             :                              1,
    2360             :                              NULL,
    2361             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2362           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
    2363           1 :     dpo2 = fib_entry_contribute_ip_forwarding(fei);
    2364           1 :     ai = fib_entry_get_adj(fei);
    2365           1 :     FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
    2366             : 
    2367             :     /*
    2368             :      * +1 entry. +1 shared path-list
    2369             :      */
    2370           1 :     FIB_TEST((5  == fib_path_list_db_size()),   "path list DB population:%d",
    2371             :              fib_path_list_db_size());
    2372           1 :     FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
    2373             :              fib_path_list_pool_size());
    2374           1 :     FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
    2375             :              fib_entry_pool_size());
    2376             : 
    2377             :     /*
    2378             :      * the recursive adj for 200.200.200.200 should be updated.
    2379             :      * 200.200.200.201 remains unchanged.
    2380             :      */
    2381           1 :     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
    2382           1 :     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
    2383             : 
    2384             :     /*
    2385             :      * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
    2386             :      */
    2387           1 :     fib_table_entry_path_remove(fib_index,
    2388             :                                 &pfx_1_1_1_0_s_28,
    2389             :                                 FIB_SOURCE_API,
    2390             :                                 DPO_PROTO_IP4,
    2391             :                                 &nh_10_10_10_2,
    2392           1 :                                 tm->hw[0]->sw_if_index,
    2393             :                                 ~0,
    2394             :                                 1,
    2395             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2396           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
    2397             :               FIB_NODE_INDEX_INVALID),
    2398             :              "1.1.1.0/28 removed");
    2399           1 :     FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
    2400             :               fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
    2401             :              "1.1.1.0/28 lookup via /24");
    2402           1 :     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
    2403           1 :     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
    2404             : 
    2405             :     /*
    2406             :      * -1 entry. -1 shared path-list
    2407             :      */
    2408           1 :     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
    2409             :              fib_path_list_db_size());
    2410           1 :     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
    2411             :              fib_path_list_pool_size());
    2412           1 :     FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
    2413             :              fib_entry_pool_size());
    2414             : 
    2415             :     /*
    2416             :      * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
    2417             :      */
    2418           1 :     fib_table_entry_path_remove(fib_index,
    2419             :                                 &pfx_1_1_1_0_s_24,
    2420             :                                 FIB_SOURCE_API,
    2421             :                                 DPO_PROTO_IP4,
    2422             :                                 &nh_10_10_10_1,
    2423           1 :                                 tm->hw[0]->sw_if_index,
    2424             :                                 ~0,
    2425             :                                 1,
    2426             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2427           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
    2428             :               FIB_NODE_INDEX_INVALID),
    2429             :              "1.1.1.0/24 removed");
    2430             : 
    2431           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
    2432           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2433             :              "1.1.1.2/32 route is DROP");
    2434           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
    2435           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2436             :              "1.1.1.200/32 route is DROP");
    2437             : 
    2438           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
    2439           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2440             :              "201 is drop");
    2441           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
    2442           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2443             :              "200 is drop");
    2444             : 
    2445             :     /*
    2446             :      * -1 entry
    2447             :      */
    2448           1 :     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
    2449             :              fib_path_list_db_size());
    2450           1 :     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
    2451             :              fib_path_list_pool_size());
    2452           1 :     FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
    2453             :              fib_entry_pool_size());
    2454             : 
    2455             :     /*
    2456             :      * insert the missing 1.1.1.2/32
    2457             :      */
    2458           1 :     fei = fib_table_entry_path_add(fib_index,
    2459             :                                    &pfx_1_1_1_2_s_32,
    2460             :                                    FIB_SOURCE_API,
    2461             :                                    FIB_ENTRY_FLAG_NONE,
    2462             :                                    DPO_PROTO_IP4,
    2463             :                                    &nh_10_10_10_1,
    2464           1 :                                    tm->hw[0]->sw_if_index,
    2465             :                                    ~0, // invalid fib index
    2466             :                                    1,
    2467             :                                    NULL,
    2468             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    2469           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2470           1 :     ai = fib_entry_get_adj(fei);
    2471           1 :     FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
    2472             : 
    2473           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
    2474           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2475             :              "201 is drop");
    2476           1 :     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
    2477             : 
    2478             :     /*
    2479             :      * no change. 1.1.1.2/32 was already there RR sourced.
    2480             :      */
    2481           1 :     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
    2482             :              fib_path_list_db_size());
    2483           1 :     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
    2484             :              fib_path_list_pool_size());
    2485           1 :     FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
    2486             :              fib_entry_pool_size());
    2487             : 
    2488             :     /*
    2489             :      * give 201 a resolved path.
    2490             :      *  it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
    2491             :      *  only the latter contributes forwarding.
    2492             :      */
    2493           1 :     fei = fib_table_entry_path_add(fib_index,
    2494             :                                    &bgp_201_pfx,
    2495             :                                    FIB_SOURCE_API,
    2496             :                                    FIB_ENTRY_FLAG_NONE,
    2497             :                                    DPO_PROTO_IP4,
    2498             :                                    &pfx_1_1_1_2_s_32.fp_addr,
    2499             :                                    ~0,
    2500             :                                    fib_index,
    2501             :                                    1,
    2502             :                                    NULL,
    2503             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    2504           1 :     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
    2505           1 :     fib_table_entry_path_remove(fib_index,
    2506             :                                 &bgp_201_pfx,
    2507             :                                 FIB_SOURCE_API,
    2508             :                                 DPO_PROTO_IP4,
    2509             :                                 &pfx_1_1_1_2_s_32.fp_addr,
    2510             :                                 ~0,
    2511             :                                 fib_index,
    2512             :                                 1,
    2513             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2514             : 
    2515             :     /*
    2516             :      * remove 200.200.200.201/32 which does not have a valid via FIB
    2517             :      */
    2518           1 :     fib_table_entry_path_remove(fib_index,
    2519             :                                 &bgp_201_pfx,
    2520             :                                 FIB_SOURCE_API,
    2521             :                                 DPO_PROTO_IP4,
    2522             :                                 &pfx_1_1_1_200_s_32.fp_addr,
    2523             :                                 ~0, // no index provided.
    2524             :                                 fib_index,
    2525             :                                 1,
    2526             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2527             : 
    2528             :     /*
    2529             :      * -2 entries (BGP and RR). -1 shared path-list;
    2530             :      */
    2531           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
    2532             :               FIB_NODE_INDEX_INVALID),
    2533             :              "200.200.200.201/32 removed");
    2534           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
    2535             :               FIB_NODE_INDEX_INVALID),
    2536             :              "1.1.1.200/32 removed");
    2537             : 
    2538           1 :     FIB_TEST((3  == fib_path_list_db_size()),   "path list DB population:%d",
    2539             :              fib_path_list_db_size());
    2540           1 :     FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
    2541             :              fib_path_list_pool_size());
    2542           1 :     FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
    2543             :              fib_entry_pool_size());
    2544             : 
    2545             :     /*
    2546             :      * remove 200.200.200.200/32 which does have a valid via FIB
    2547             :      */
    2548           1 :     fib_table_entry_path_remove(fib_index,
    2549             :                                 &bgp_200_pfx,
    2550             :                                 FIB_SOURCE_API,
    2551             :                                 DPO_PROTO_IP4,
    2552             :                                 &pfx_1_1_1_2_s_32.fp_addr,
    2553             :                                 ~0, // no index provided.
    2554             :                                 fib_index,
    2555             :                                 1,
    2556             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2557             : 
    2558           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
    2559             :               FIB_NODE_INDEX_INVALID),
    2560             :              "200.200.200.200/32 removed");
    2561           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
    2562             :               FIB_NODE_INDEX_INVALID),
    2563             :              "1.1.1.2/32 still present");
    2564             : 
    2565             :     /*
    2566             :      * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
    2567             :      */
    2568           1 :     FIB_TEST((2  == fib_path_list_db_size()),   "path list DB population:%d",
    2569             :              fib_path_list_db_size());
    2570           1 :     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
    2571             :              fib_path_list_pool_size());
    2572           1 :     FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
    2573             :              fib_entry_pool_size());
    2574             : 
    2575             :     /*
    2576             :      * A recursive prefix that has a 2 path  load-balance.
    2577             :      * It also shares a next-hop with other BGP prefixes and hence
    2578             :      * test the ref counting of RR sourced prefixes and 2 level LB.
    2579             :      */
    2580           2 :     const fib_prefix_t bgp_102 = {
    2581             :         .fp_len = 32,
    2582             :         .fp_proto = FIB_PROTOCOL_IP4,
    2583             :         .fp_addr = {
    2584             :             /* 100.100.100.101/32 */
    2585           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
    2586             :         },
    2587             :     };
    2588           1 :     fib_table_entry_path_add(fib_index,
    2589             :                              &bgp_102,
    2590             :                              FIB_SOURCE_API,
    2591             :                              FIB_ENTRY_FLAG_NONE,
    2592             :                              DPO_PROTO_IP4,
    2593             :                              &pfx_1_1_1_1_s_32.fp_addr,
    2594             :                              ~0, // no index provided.
    2595             :                              fib_index, // same as route
    2596             :                              1,
    2597             :                              NULL,
    2598             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2599           1 :     fib_table_entry_path_add(fib_index,
    2600             :                              &bgp_102,
    2601             :                              FIB_SOURCE_API,
    2602             :                              FIB_ENTRY_FLAG_NONE,
    2603             :                              DPO_PROTO_IP4,
    2604             :                              &pfx_1_1_1_2_s_32.fp_addr,
    2605             :                              ~0, // no index provided.
    2606             :                              fib_index, // same as route's FIB
    2607             :                              1,
    2608             :                              NULL,
    2609             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2610           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
    2611           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
    2612           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    2613             : 
    2614           1 :     fei  = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
    2615           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2616           1 :     fei  = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
    2617           1 :     dpo2 = fib_entry_contribute_ip_forwarding(fei);
    2618             : 
    2619           1 :     lb = load_balance_get(dpo->dpoi_index);
    2620           1 :     FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
    2621           1 :     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
    2622             :              "First via 10.10.10.1");
    2623           1 :     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
    2624             :              "Second via 10.10.10.1");
    2625             : 
    2626           1 :     fib_table_entry_path_remove(fib_index,
    2627             :                                 &bgp_102,
    2628             :                                 FIB_SOURCE_API,
    2629             :                                 DPO_PROTO_IP4,
    2630             :                                 &pfx_1_1_1_1_s_32.fp_addr,
    2631             :                                 ~0, // no index provided.
    2632             :                                 fib_index, // same as route's FIB
    2633             :                                 1,
    2634             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2635           1 :     fib_table_entry_path_remove(fib_index,
    2636             :                                 &bgp_102,
    2637             :                                 FIB_SOURCE_API,
    2638             :                                 DPO_PROTO_IP4,
    2639             :                                 &pfx_1_1_1_2_s_32.fp_addr,
    2640             :                                 ~0, // no index provided.
    2641             :                                 fib_index, // same as route's FIB
    2642             :                                 1,
    2643             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2644           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
    2645           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
    2646             : 
    2647             :     /*
    2648             :      * remove the remaining recursives
    2649             :      */
    2650           1 :     fib_table_entry_path_remove(fib_index,
    2651             :                                 &bgp_100_pfx,
    2652             :                                 FIB_SOURCE_API,
    2653             :                                 DPO_PROTO_IP4,
    2654             :                                 &pfx_1_1_1_1_s_32.fp_addr,
    2655             :                                 ~0, // no index provided.
    2656             :                                 fib_index, // same as route's FIB
    2657             :                                 1,
    2658             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2659           1 :     fib_table_entry_path_remove(fib_index,
    2660             :                                 &bgp_101_pfx,
    2661             :                                 FIB_SOURCE_API,
    2662             :                                 DPO_PROTO_IP4,
    2663             :                                 &pfx_1_1_1_1_s_32.fp_addr,
    2664             :                                 ~0, // no index provided.
    2665             :                                 fib_index, // same as route's FIB
    2666             :                                 1,
    2667             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2668           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
    2669             :               FIB_NODE_INDEX_INVALID),
    2670             :              "100.100.100.100/32 removed");
    2671           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
    2672             :               FIB_NODE_INDEX_INVALID),
    2673             :              "100.100.100.101/32 removed");
    2674             : 
    2675             :     /*
    2676             :      * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
    2677             :      */
    2678           1 :     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
    2679             :              fib_path_list_db_size());
    2680           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    2681             :              fib_path_list_pool_size());
    2682           1 :     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
    2683             :              fib_entry_pool_size());
    2684             : 
    2685             :     /*
    2686             :      * Add a recursive route via a connected cover, using an adj-fib that does exist
    2687             :      */
    2688           1 :     fib_table_entry_path_add(fib_index,
    2689             :                              &bgp_200_pfx,
    2690             :                              FIB_SOURCE_API,
    2691             :                              FIB_ENTRY_FLAG_NONE,
    2692             :                              DPO_PROTO_IP4,
    2693             :                              &nh_10_10_10_1,
    2694             :                              ~0, // no index provided.
    2695             :                              fib_index, // Same as route's FIB
    2696             :                              1,
    2697             :                              NULL,
    2698             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2699             : 
    2700             :     /*
    2701             :      * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
    2702             :      */
    2703           1 :     FIB_TEST((2  == fib_path_list_db_size()),   "path list DB population:%d",
    2704             :              fib_path_list_db_size());
    2705           1 :     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
    2706             :              fib_path_list_pool_size());
    2707           1 :     FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
    2708             :              fib_entry_pool_size());
    2709             : 
    2710           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
    2711           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    2712             : 
    2713           1 :     fei  = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
    2714           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2715             : 
    2716           1 :     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
    2717             :              "200.200.200.200/32 is recursive via adj for 10.10.10.1");
    2718             : 
    2719           1 :     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED  == fib_entry_get_flags(fei)),
    2720             :              "Flags set on RR via existing attached");
    2721             : 
    2722             :     /*
    2723             :      * Add a recursive route via a connected cover, using and adj-fib that does
    2724             :      * not exist
    2725             :      */
    2726           2 :     ip46_address_t nh_10_10_10_3 = {
    2727           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
    2728             :     };
    2729           1 :     fib_prefix_t pfx_10_10_10_3 = {
    2730             :         .fp_len = 32,
    2731             :         .fp_proto = FIB_PROTOCOL_IP4,
    2732             :         .fp_addr = nh_10_10_10_3,
    2733             :     };
    2734             : 
    2735           1 :     fib_table_entry_path_add(fib_index,
    2736             :                              &bgp_201_pfx,
    2737             :                              FIB_SOURCE_API,
    2738             :                              FIB_ENTRY_FLAG_NONE,
    2739             :                              DPO_PROTO_IP4,
    2740             :                              &nh_10_10_10_3,
    2741             :                              ~0, // no index provided.
    2742             :                              fib_index,
    2743             :                              1,
    2744             :                              NULL,
    2745             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2746             : 
    2747             :     /*
    2748             :      * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
    2749             :      * one unshared non-recursive via 10.10.10.3
    2750             :      */
    2751           1 :     FIB_TEST((3  == fib_path_list_db_size()),   "path list DB population:%d",
    2752             :              fib_path_list_db_size());
    2753           1 :     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
    2754             :              fib_path_list_pool_size());
    2755           1 :     FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
    2756             :              fib_entry_pool_size());
    2757             : 
    2758           1 :     ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    2759             :                                 VNET_LINK_IP4,
    2760             :                                 &nh_10_10_10_3,
    2761           1 :                                 tm->hw[0]->sw_if_index);
    2762             : 
    2763           1 :     fei  = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
    2764           1 :     dpo  = fib_entry_contribute_ip_forwarding(fei);
    2765           1 :     fei  = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
    2766           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2767             : 
    2768           1 :     ai = fib_entry_get_adj(fei);
    2769           1 :     FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
    2770           1 :     FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
    2771             :               fib_entry_get_flags(fei)),
    2772             :              "Flags set on RR via non-existing attached");
    2773             : 
    2774           1 :     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
    2775             :              "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
    2776             : 
    2777           1 :     adj_unlock(ai_03);
    2778             : 
    2779             :     /*
    2780             :      * remove the recursives
    2781             :      */
    2782           1 :     fib_table_entry_path_remove(fib_index,
    2783             :                                 &bgp_200_pfx,
    2784             :                                 FIB_SOURCE_API,
    2785             :                                 DPO_PROTO_IP4,
    2786             :                                 &nh_10_10_10_1,
    2787             :                                 ~0, // no index provided.
    2788             :                                 fib_index, // same as route's FIB
    2789             :                                 1,
    2790             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2791           1 :     fib_table_entry_path_remove(fib_index,
    2792             :                                 &bgp_201_pfx,
    2793             :                                 FIB_SOURCE_API,
    2794             :                                 DPO_PROTO_IP4,
    2795             :                                 &nh_10_10_10_3,
    2796             :                                 ~0, // no index provided.
    2797             :                                 fib_index, // same as route's FIB
    2798             :                                 1,
    2799             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2800             : 
    2801           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
    2802             :               FIB_NODE_INDEX_INVALID),
    2803             :              "200.200.200.201/32 removed");
    2804           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
    2805             :               FIB_NODE_INDEX_INVALID),
    2806             :              "200.200.200.200/32 removed");
    2807           1 :     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
    2808             :               FIB_NODE_INDEX_INVALID),
    2809             :              "10.10.10.3/32 removed");
    2810             : 
    2811             :     /*
    2812             :      * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
    2813             :      *  10.10.10.1) and one unshared non-recursive via 10.10.10.3
    2814             :      */
    2815           1 :     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
    2816             :              fib_path_list_db_size());
    2817           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    2818             :              fib_path_list_pool_size());
    2819           1 :     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
    2820             :              fib_entry_pool_size());
    2821             : 
    2822             : 
    2823             :     /*
    2824             :      * RECURSION LOOPS
    2825             :      *  Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
    2826             :      */
    2827           2 :     fib_prefix_t pfx_5_5_5_5_s_32 = {
    2828             :         .fp_len = 32,
    2829             :         .fp_proto = FIB_PROTOCOL_IP4,
    2830             :         .fp_addr = {
    2831           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
    2832             :         },
    2833             :     };
    2834           2 :     fib_prefix_t pfx_5_5_5_6_s_32 = {
    2835             :         .fp_len = 32,
    2836             :         .fp_proto = FIB_PROTOCOL_IP4,
    2837             :         .fp_addr = {
    2838           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
    2839             :         },
    2840             :     };
    2841           2 :     fib_prefix_t pfx_5_5_5_7_s_32 = {
    2842             :         .fp_len = 32,
    2843             :         .fp_proto = FIB_PROTOCOL_IP4,
    2844             :         .fp_addr = {
    2845           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
    2846             :         },
    2847             :     };
    2848             : 
    2849           1 :     fib_table_entry_path_add(fib_index,
    2850             :                              &pfx_5_5_5_5_s_32,
    2851             :                              FIB_SOURCE_API,
    2852             :                              FIB_ENTRY_FLAG_NONE,
    2853             :                              DPO_PROTO_IP4,
    2854             :                              &pfx_5_5_5_6_s_32.fp_addr,
    2855             :                              ~0, // no index provided.
    2856             :                              fib_index,
    2857             :                              1,
    2858             :                              NULL,
    2859             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2860           1 :     fib_table_entry_path_add(fib_index,
    2861             :                              &pfx_5_5_5_6_s_32,
    2862             :                              FIB_SOURCE_API,
    2863             :                              FIB_ENTRY_FLAG_NONE,
    2864             :                              DPO_PROTO_IP4,
    2865             :                              &pfx_5_5_5_7_s_32.fp_addr,
    2866             :                              ~0, // no index provided.
    2867             :                              fib_index,
    2868             :                              1,
    2869             :                              NULL,
    2870             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2871           1 :     fib_table_entry_path_add(fib_index,
    2872             :                              &pfx_5_5_5_7_s_32,
    2873             :                              FIB_SOURCE_API,
    2874             :                              FIB_ENTRY_FLAG_NONE,
    2875             :                              DPO_PROTO_IP4,
    2876             :                              &pfx_5_5_5_5_s_32.fp_addr,
    2877             :                              ~0, // no index provided.
    2878             :                              fib_index,
    2879             :                              1,
    2880             :                              NULL,
    2881             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2882             :     /*
    2883             :      * +3 entries, +3 shared path-list
    2884             :      */
    2885           1 :     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
    2886             :              fib_path_list_db_size());
    2887           1 :     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
    2888             :              fib_path_list_pool_size());
    2889           1 :     FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
    2890             :              fib_entry_pool_size());
    2891             : 
    2892             :     /*
    2893             :      * All the entries have only looped paths, so they are all drop
    2894             :      */
    2895           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
    2896           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2897             :              "LB for 5.5.5.7/32 is via adj for DROP");
    2898           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
    2899           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2900             :              "LB for 5.5.5.5/32 is via adj for DROP");
    2901           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
    2902           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2903             :              "LB for 5.5.5.6/32 is via adj for DROP");
    2904             : 
    2905             :     /*
    2906             :      * provide 5.5.5.6/32 with alternate path.
    2907             :      * this will allow only 5.5.5.6/32 to forward with this path, the others
    2908             :      * are still drop since the loop is still present.
    2909             :      */
    2910           1 :     fib_table_entry_path_add(fib_index,
    2911             :                              &pfx_5_5_5_6_s_32,
    2912             :                              FIB_SOURCE_API,
    2913             :                              FIB_ENTRY_FLAG_NONE,
    2914             :                              DPO_PROTO_IP4,
    2915             :                              &nh_10_10_10_1,
    2916           1 :                              tm->hw[0]->sw_if_index,
    2917             :                              ~0,
    2918             :                              1,
    2919             :                              NULL,
    2920             :                              FIB_ROUTE_PATH_FLAG_NONE);
    2921             : 
    2922           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
    2923           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2924             : 
    2925           1 :     lb = load_balance_get(dpo1->dpoi_index);
    2926           1 :     FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
    2927             : 
    2928           1 :     dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
    2929           1 :     FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
    2930           1 :     FIB_TEST((ai_01 == dpo2->dpoi_index),
    2931             :              "5.5.5.6 bucket 0 resolves via 10.10.10.2");
    2932             : 
    2933           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
    2934           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2935             :              "LB for 5.5.5.7/32 is via adj for DROP");
    2936           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
    2937           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2938             :              "LB for 5.5.5.5/32 is via adj for DROP");
    2939             : 
    2940             :     /*
    2941             :      * remove the alternate path for 5.5.5.6/32
    2942             :      * back to all drop
    2943             :      */
    2944           1 :     fib_table_entry_path_remove(fib_index,
    2945             :                                 &pfx_5_5_5_6_s_32,
    2946             :                                 FIB_SOURCE_API,
    2947             :                                 DPO_PROTO_IP4,
    2948             :                                 &nh_10_10_10_1,
    2949           1 :                                 tm->hw[0]->sw_if_index,
    2950             :                                 ~0,
    2951             :                                 1,
    2952             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    2953             : 
    2954           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
    2955           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2956             :              "LB for 5.5.5.7/32 is via adj for DROP");
    2957           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
    2958           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2959             :              "LB for 5.5.5.5/32 is via adj for DROP");
    2960           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
    2961           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    2962             :              "LB for 5.5.5.6/32 is via adj for DROP");
    2963             : 
    2964             :     /*
    2965             :      * break the loop by giving 5.5.5.5/32 a new set of paths
    2966             :      * expect all to forward via this new path.
    2967             :      */
    2968           1 :     fib_table_entry_update_one_path(fib_index,
    2969             :                                     &pfx_5_5_5_5_s_32,
    2970             :                                     FIB_SOURCE_API,
    2971             :                                     FIB_ENTRY_FLAG_NONE,
    2972             :                                     DPO_PROTO_IP4,
    2973             :                                     &nh_10_10_10_1,
    2974           1 :                                     tm->hw[0]->sw_if_index,
    2975             :                                     ~0, // invalid fib index
    2976             :                                     1,
    2977             :                                     NULL,
    2978             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    2979             : 
    2980           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
    2981           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    2982           1 :     lb = load_balance_get(dpo1->dpoi_index);
    2983           1 :     FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
    2984             : 
    2985           1 :     dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
    2986           1 :     FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
    2987           1 :     FIB_TEST((ai_01 == dpo2->dpoi_index),
    2988             :              "5.5.5.5 bucket 0 resolves via 10.10.10.2");
    2989             : 
    2990           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
    2991           1 :     dpo2 = fib_entry_contribute_ip_forwarding(fei);
    2992             : 
    2993           1 :     lb = load_balance_get(dpo2->dpoi_index);
    2994           1 :     FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
    2995           1 :     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
    2996             :              "5.5.5.5.7 via 5.5.5.5");
    2997             : 
    2998           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
    2999           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    3000             : 
    3001           1 :     lb = load_balance_get(dpo1->dpoi_index);
    3002           1 :     FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
    3003           1 :     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
    3004             :              "5.5.5.5.6 via 5.5.5.7");
    3005             : 
    3006             :     /*
    3007             :      * revert back to the loop. so we can remove the prefixes with
    3008             :      * the loop intact
    3009             :      */
    3010           1 :     fib_table_entry_update_one_path(fib_index,
    3011             :                                     &pfx_5_5_5_5_s_32,
    3012             :                                     FIB_SOURCE_API,
    3013             :                                     FIB_ENTRY_FLAG_NONE,
    3014             :                                     DPO_PROTO_IP4,
    3015             :                                     &pfx_5_5_5_6_s_32.fp_addr,
    3016             :                                     ~0, // no index provided.
    3017             :                                     fib_index,
    3018             :                                     1,
    3019             :                                     NULL,
    3020             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    3021             : 
    3022           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
    3023           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    3024             :              "LB for 5.5.5.7/32 is via adj for DROP");
    3025           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
    3026           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    3027             :              "LB for 5.5.5.5/32 is via adj for DROP");
    3028           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
    3029           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    3030             :              "LB for 5.5.5.6/32 is via adj for DROP");
    3031             : 
    3032             :     /*
    3033             :      * remove all the 5.5.5.x/32 prefixes
    3034             :      */
    3035           1 :     fib_table_entry_path_remove(fib_index,
    3036             :                                 &pfx_5_5_5_5_s_32,
    3037             :                                 FIB_SOURCE_API,
    3038             :                                 DPO_PROTO_IP4,
    3039             :                                 &pfx_5_5_5_6_s_32.fp_addr,
    3040             :                                 ~0, // no index provided.
    3041             :                                 fib_index, // same as route's FIB
    3042             :                                 1,
    3043             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3044           1 :     fib_table_entry_path_remove(fib_index,
    3045             :                                 &pfx_5_5_5_6_s_32,
    3046             :                                 FIB_SOURCE_API,
    3047             :                                 DPO_PROTO_IP4,
    3048             :                                 &pfx_5_5_5_7_s_32.fp_addr,
    3049             :                                 ~0, // no index provided.
    3050             :                                 fib_index, // same as route's FIB
    3051             :                                 1,
    3052             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3053           1 :     fib_table_entry_path_remove(fib_index,
    3054             :                                 &pfx_5_5_5_7_s_32,
    3055             :                                 FIB_SOURCE_API,
    3056             :                                 DPO_PROTO_IP4,
    3057             :                                 &pfx_5_5_5_5_s_32.fp_addr,
    3058             :                                 ~0, // no index provided.
    3059             :                                 fib_index, // same as route's FIB
    3060             :                                 1,
    3061             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3062           1 :     fib_table_entry_path_remove(fib_index,
    3063             :                                 &pfx_5_5_5_6_s_32,
    3064             :                                 FIB_SOURCE_API,
    3065             :                                 DPO_PROTO_IP4,
    3066             :                                 &nh_10_10_10_2,
    3067             :                                 ~0, // no index provided.
    3068             :                                 fib_index, // same as route's FIB
    3069             :                                 1,
    3070             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3071             : 
    3072             :     /*
    3073             :      * -3 entries, -3 shared path-list
    3074             :      */
    3075           1 :     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
    3076             :              fib_path_list_db_size());
    3077           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    3078             :              fib_path_list_pool_size());
    3079           1 :     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
    3080             :              fib_entry_pool_size());
    3081             : 
    3082             :     /*
    3083             :      * Single level loop 5.5.5.5/32 via 5.5.5.5/32
    3084             :      */
    3085           1 :     fib_table_entry_path_add(fib_index,
    3086             :                              &pfx_5_5_5_6_s_32,
    3087             :                              FIB_SOURCE_API,
    3088             :                              FIB_ENTRY_FLAG_NONE,
    3089             :                              DPO_PROTO_IP4,
    3090             :                              &pfx_5_5_5_6_s_32.fp_addr,
    3091             :                              ~0, // no index provided.
    3092             :                              fib_index,
    3093             :                              1,
    3094             :                              NULL,
    3095             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3096           1 :     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
    3097           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    3098             :              "1-level 5.5.5.6/32 loop is via adj for DROP");
    3099             : 
    3100           1 :     fib_table_entry_path_remove(fib_index,
    3101             :                                 &pfx_5_5_5_6_s_32,
    3102             :                                 FIB_SOURCE_API,
    3103             :                                 DPO_PROTO_IP4,
    3104             :                                 &pfx_5_5_5_6_s_32.fp_addr,
    3105             :                                 ~0, // no index provided.
    3106             :                                 fib_index, // same as route's FIB
    3107             :                                 1,
    3108             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3109           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    3110             :              fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
    3111             :              "1-level 5.5.5.6/32 loop is removed");
    3112             : 
    3113             :     /*
    3114             :      * A recursive route whose next-hop is covered by the prefix.
    3115             :      * This would mean the via-fib, which inherits forwarding from its
    3116             :      * cover, thus picks up forwarding from the prfix, which is via the
    3117             :      * via-fib, and we have a loop.
    3118             :      */
    3119           2 :     fib_prefix_t pfx_23_23_23_0_s_24 = {
    3120             :         .fp_len = 24,
    3121             :         .fp_proto = FIB_PROTOCOL_IP4,
    3122             :         .fp_addr = {
    3123           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
    3124             :         },
    3125             :     };
    3126           2 :     fib_prefix_t pfx_23_23_23_23_s_32 = {
    3127             :         .fp_len = 32,
    3128             :         .fp_proto = FIB_PROTOCOL_IP4,
    3129             :         .fp_addr = {
    3130           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
    3131             :         },
    3132             :     };
    3133           1 :     fei = fib_table_entry_path_add(fib_index,
    3134             :                                    &pfx_23_23_23_0_s_24,
    3135             :                                    FIB_SOURCE_API,
    3136             :                                    FIB_ENTRY_FLAG_NONE,
    3137             :                                    DPO_PROTO_IP4,
    3138             :                                    &pfx_23_23_23_23_s_32.fp_addr,
    3139             :                                    ~0, // recursive
    3140             :                                    fib_index,
    3141             :                                    1,
    3142             :                                    NULL,
    3143             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    3144           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3145           1 :     FIB_TEST(load_balance_is_drop(dpo),
    3146             :              "23.23.23.0/24 via covered is DROP");
    3147           1 :     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
    3148             : 
    3149             :     /*
    3150             :      * add-remove test. no change.
    3151             :      */
    3152           1 :     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
    3153             :              fib_path_list_db_size());
    3154           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    3155             :              fib_path_list_pool_size());
    3156           1 :     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
    3157             :              fib_entry_pool_size());
    3158             : 
    3159             :     /*
    3160             :      * Make the default route recursive via a unknown next-hop. Thus the
    3161             :      * next hop's cover would be the default route
    3162             :      */
    3163           1 :     fei = fib_table_entry_path_add(fib_index,
    3164             :                                    &pfx_0_0_0_0_s_0,
    3165             :                                    FIB_SOURCE_API,
    3166             :                                    FIB_ENTRY_FLAG_NONE,
    3167             :                                    DPO_PROTO_IP4,
    3168             :                                    &pfx_23_23_23_23_s_32.fp_addr,
    3169             :                                    ~0, // recursive
    3170             :                                    fib_index,
    3171             :                                    1,
    3172             :                                    NULL,
    3173             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    3174           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3175           1 :     FIB_TEST(load_balance_is_drop(dpo),
    3176             :              "0.0.0.0.0/0 via is DROP");
    3177           1 :     FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
    3178             :              "no resolving interface for looped 0.0.0.0/0");
    3179             : 
    3180           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
    3181           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3182           1 :     FIB_TEST(load_balance_is_drop(dpo),
    3183             :              "23.23.23.23/32 via is DROP");
    3184           1 :     FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
    3185             :              "no resolving interface for looped 23.23.23.23/32");
    3186             : 
    3187           1 :     fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
    3188             : 
    3189             :     /*
    3190             :      * A recursive route with recursion constraints.
    3191             :      *  200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
    3192             :      */
    3193           1 :     fib_table_entry_path_add(fib_index,
    3194             :                              &bgp_200_pfx,
    3195             :                              FIB_SOURCE_API,
    3196             :                              FIB_ENTRY_FLAG_NONE,
    3197             :                              DPO_PROTO_IP4,
    3198             :                              &nh_1_1_1_1,
    3199             :                              ~0,
    3200             :                              fib_index,
    3201             :                              1,
    3202             :                              NULL,
    3203             :                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
    3204             : 
    3205           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
    3206           1 :     dpo2 = fib_entry_contribute_ip_forwarding(fei);
    3207             : 
    3208           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
    3209           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    3210             : 
    3211           1 :     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
    3212             :              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
    3213             : 
    3214             :     /*
    3215             :      * save the load-balance. we expect it to be inplace modified
    3216             :      */
    3217           1 :     lb = load_balance_get(dpo1->dpoi_index);
    3218             : 
    3219             :     /*
    3220             :      * add a covering prefix for the via fib that would otherwise serve
    3221             :      * as the resolving route when the host is removed
    3222             :      */
    3223           1 :     fib_table_entry_path_add(fib_index,
    3224             :                              &pfx_1_1_1_0_s_28,
    3225             :                              FIB_SOURCE_API,
    3226             :                              FIB_ENTRY_FLAG_NONE,
    3227             :                              DPO_PROTO_IP4,
    3228             :                              &nh_10_10_10_1,
    3229           1 :                              tm->hw[0]->sw_if_index,
    3230             :                              ~0, // invalid fib index
    3231             :                              1,
    3232             :                              NULL,
    3233             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3234           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
    3235           1 :     ai = fib_entry_get_adj(fei);
    3236           1 :     FIB_TEST((ai == ai_01),
    3237             :              "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
    3238             : 
    3239             :     /*
    3240             :      * remove the host via FIB - expect the BGP prefix to be drop
    3241             :      */
    3242           1 :     fib_table_entry_path_remove(fib_index,
    3243             :                                 &pfx_1_1_1_1_s_32,
    3244             :                                 FIB_SOURCE_API,
    3245             :                                 DPO_PROTO_IP4,
    3246             :                                 &nh_10_10_10_1,
    3247           1 :                                 tm->hw[0]->sw_if_index,
    3248             :                                 ~0, // invalid fib index
    3249             :                                 1,
    3250             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3251             : 
    3252           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
    3253             :              "adj for 200.200.200.200/32 is recursive via adj for DROP");
    3254             : 
    3255             :     /*
    3256             :      * add the via-entry host reoute back. expect to resolve again
    3257             :      */
    3258           1 :     fib_table_entry_path_add(fib_index,
    3259             :                              &pfx_1_1_1_1_s_32,
    3260             :                              FIB_SOURCE_API,
    3261             :                              FIB_ENTRY_FLAG_NONE,
    3262             :                              DPO_PROTO_IP4,
    3263             :                              &nh_10_10_10_1,
    3264           1 :                              tm->hw[0]->sw_if_index,
    3265             :                              ~0, // invalid fib index
    3266             :                              1,
    3267             :                              NULL,
    3268             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3269           1 :     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
    3270             :              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
    3271             : 
    3272             :     /*
    3273             :      * add another path for the recursive. it will then have 2.
    3274             :      */
    3275           2 :     fib_prefix_t pfx_1_1_1_3_s_32 = {
    3276             :         .fp_len = 32,
    3277             :         .fp_proto = FIB_PROTOCOL_IP4,
    3278             :         .fp_addr = {
    3279           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
    3280             :         },
    3281             :     };
    3282           1 :     fib_table_entry_path_add(fib_index,
    3283             :                              &pfx_1_1_1_3_s_32,
    3284             :                              FIB_SOURCE_API,
    3285             :                              FIB_ENTRY_FLAG_NONE,
    3286             :                              DPO_PROTO_IP4,
    3287             :                              &nh_10_10_10_2,
    3288           1 :                              tm->hw[0]->sw_if_index,
    3289             :                              ~0, // invalid fib index
    3290             :                              1,
    3291             :                              NULL,
    3292             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3293             : 
    3294           1 :     fib_table_entry_path_add(fib_index,
    3295             :                              &bgp_200_pfx,
    3296             :                              FIB_SOURCE_API,
    3297             :                              FIB_ENTRY_FLAG_NONE,
    3298             :                              DPO_PROTO_IP4,
    3299             :                              &pfx_1_1_1_3_s_32.fp_addr,
    3300             :                              ~0,
    3301             :                              fib_index,
    3302             :                              1,
    3303             :                              NULL,
    3304             :                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
    3305             : 
    3306             :     /*
    3307             :      * add a bunch load more entries using this path combo so that we get
    3308             :      * an LB-map created.
    3309             :      */
    3310             : #define N_P 128
    3311             :     fib_prefix_t bgp_78s[N_P];
    3312         129 :     for (ii = 0; ii < N_P; ii++)
    3313             :     {
    3314         128 :         bgp_78s[ii].fp_len = 32;
    3315         128 :         bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
    3316         128 :         bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
    3317             : 
    3318             : 
    3319         128 :         fib_table_entry_path_add(fib_index,
    3320         128 :                                  &bgp_78s[ii],
    3321             :                                  FIB_SOURCE_API,
    3322             :                                  FIB_ENTRY_FLAG_NONE,
    3323             :                                  DPO_PROTO_IP4,
    3324             :                                  &pfx_1_1_1_3_s_32.fp_addr,
    3325             :                                  ~0,
    3326             :                                  fib_index,
    3327             :                                  1,
    3328             :                                  NULL,
    3329             :                                  FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
    3330         128 :         fib_table_entry_path_add(fib_index,
    3331         128 :                                  &bgp_78s[ii],
    3332             :                                  FIB_SOURCE_API,
    3333             :                                  FIB_ENTRY_FLAG_NONE,
    3334             :                                  DPO_PROTO_IP4,
    3335             :                                  &nh_1_1_1_1,
    3336             :                                  ~0,
    3337             :                                  fib_index,
    3338             :                                  1,
    3339             :                                  NULL,
    3340             :                                  FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
    3341             :     }
    3342             : 
    3343           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
    3344           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3345             : 
    3346           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
    3347           1 :     dpo2 = fib_entry_contribute_ip_forwarding(fei);
    3348           1 :     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
    3349             :              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
    3350           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
    3351           1 :     dpo1 = fib_entry_contribute_ip_forwarding(fei);
    3352           1 :     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
    3353             :              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
    3354             : 
    3355             :     /*
    3356             :      * expect the lb-map used by the recursive's load-balance is using both buckets
    3357             :      */
    3358             :     load_balance_map_t *lbm;
    3359             :     index_t lbmi;
    3360             : 
    3361           1 :     lb = load_balance_get(dpo->dpoi_index);
    3362           1 :     lbmi = lb->lb_map;
    3363           1 :     load_balance_map_lock(lbmi);
    3364           1 :     lbm = load_balance_map_get(lbmi);
    3365             : 
    3366           1 :     FIB_TEST(lbm->lbm_buckets[0] == 0,
    3367             :              "LB maps's bucket 0 is %d",
    3368             :              lbm->lbm_buckets[0]);
    3369           1 :     FIB_TEST(lbm->lbm_buckets[1] == 1,
    3370             :              "LB maps's bucket 1 is %d",
    3371             :              lbm->lbm_buckets[1]);
    3372             : 
    3373             :     /*
    3374             :      * withdraw one of the /32 via-entrys.
    3375             :      * that ECMP path will be unresolved and forwarding should continue on the
    3376             :      * other available path. this is an iBGP PIC edge failover.
    3377             :      * Test the forwarding changes without re-fetching the adj from the
    3378             :      * recursive entry. this ensures its the same one that is updated; i.e. an
    3379             :      * inplace-modify.
    3380             :      */
    3381           1 :     fib_table_entry_path_remove(fib_index,
    3382             :                                 &pfx_1_1_1_1_s_32,
    3383             :                                 FIB_SOURCE_API,
    3384             :                                 DPO_PROTO_IP4,
    3385             :                                 &nh_10_10_10_1,
    3386           1 :                                 tm->hw[0]->sw_if_index,
    3387             :                                 ~0, // invalid fib index
    3388             :                                 1,
    3389             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3390             : 
    3391             :     /* suspend so the update walk kicks int */
    3392           1 :     vlib_process_suspend(vlib_get_main(), 1e-5);
    3393             : 
    3394           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
    3395           1 :     FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
    3396             :              "post PIC 200.200.200.200/32 was inplace modified");
    3397             : 
    3398           1 :     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
    3399             :              "post PIC adj for 200.200.200.200/32 is recursive"
    3400             :              " via adj for 1.1.1.3");
    3401             : 
    3402             :     /*
    3403             :      * the LB maps that was locked above should have been modified to remove
    3404             :      * the path that was down, and thus its bucket points to a path that is
    3405             :      * still up.
    3406             :      */
    3407           1 :     FIB_TEST(lbm->lbm_buckets[0] == 1,
    3408             :              "LB maps's bucket 0 is %d",
    3409             :              lbm->lbm_buckets[0]);
    3410           1 :     FIB_TEST(lbm->lbm_buckets[1] == 1,
    3411             :              "LB maps's bucket 1 is %d",
    3412             :              lbm->lbm_buckets[1]);
    3413             : 
    3414           1 :     load_balance_map_unlock(lbmi);
    3415             : 
    3416             :     /*
    3417             :      * add it back. again
    3418             :      */
    3419           1 :     fib_table_entry_path_add(fib_index,
    3420             :                              &pfx_1_1_1_1_s_32,
    3421             :                              FIB_SOURCE_API,
    3422             :                              FIB_ENTRY_FLAG_NONE,
    3423             :                              DPO_PROTO_IP4,
    3424             :                              &nh_10_10_10_1,
    3425           1 :                              tm->hw[0]->sw_if_index,
    3426             :                              ~0, // invalid fib index
    3427             :                              1,
    3428             :                              NULL,
    3429             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3430             : 
    3431             :     /* suspend so the update walk kicks in */
    3432           1 :     vlib_process_suspend(vlib_get_main(), 1e-5);
    3433             : 
    3434           1 :     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
    3435             :              "post PIC recovery adj for 200.200.200.200/32 is recursive "
    3436             :              "via adj for 1.1.1.1");
    3437           1 :     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
    3438             :              "post PIC recovery adj for 200.200.200.200/32 is recursive "
    3439             :              "via adj for 1.1.1.3");
    3440             : 
    3441           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
    3442           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3443           1 :     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
    3444             :              "post PIC 200.200.200.200/32 was inplace modified");
    3445             : 
    3446             :     /*
    3447             :      * add a 3rd path. this makes the LB 16 buckets.
    3448             :      */
    3449           1 :     fib_table_entry_path_add(fib_index,
    3450             :                              &bgp_200_pfx,
    3451             :                              FIB_SOURCE_API,
    3452             :                              FIB_ENTRY_FLAG_NONE,
    3453             :                              DPO_PROTO_IP4,
    3454             :                              &pfx_1_1_1_2_s_32.fp_addr,
    3455             :                              ~0,
    3456             :                              fib_index,
    3457             :                              1,
    3458             :                              NULL,
    3459             :                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
    3460         129 :     for (ii = 0; ii < N_P; ii++)
    3461             :     {
    3462         128 :         fib_table_entry_path_add(fib_index,
    3463         128 :                                  &bgp_78s[ii],
    3464             :                                  FIB_SOURCE_API,
    3465             :                                  FIB_ENTRY_FLAG_NONE,
    3466             :                                  DPO_PROTO_IP4,
    3467             :                                  &pfx_1_1_1_2_s_32.fp_addr,
    3468             :                                  ~0,
    3469             :                                  fib_index,
    3470             :                                  1,
    3471             :                                  NULL,
    3472             :                                  FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
    3473             :     }
    3474             : 
    3475           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
    3476           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3477           1 :     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
    3478             :              "200.200.200.200/32 was inplace modified for 3rd path");
    3479           1 :     FIB_TEST(16 == lb->lb_n_buckets,
    3480             :              "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
    3481             : 
    3482           1 :     lbmi = lb->lb_map;
    3483           1 :     load_balance_map_lock(lbmi);
    3484           1 :     lbm = load_balance_map_get(lbmi);
    3485             : 
    3486          17 :     for (ii = 0; ii < 16; ii++)
    3487             :     {
    3488          16 :         FIB_TEST(lbm->lbm_buckets[ii] == ii,
    3489             :                  "LB Map for 200.200.200.200/32 at %d is %d",
    3490             :                  ii, lbm->lbm_buckets[ii]);
    3491             :     }
    3492             : 
    3493             :     /*
    3494             :      * trigger PIC by removing the first via-entry
    3495             :      * the first 6 buckets of the map should map to the next 6
    3496             :      */
    3497           1 :     fib_table_entry_path_remove(fib_index,
    3498             :                                 &pfx_1_1_1_1_s_32,
    3499             :                                 FIB_SOURCE_API,
    3500             :                                 DPO_PROTO_IP4,
    3501             :                                 &nh_10_10_10_1,
    3502           1 :                                 tm->hw[0]->sw_if_index,
    3503             :                                 ~0,
    3504             :                                 1,
    3505             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3506             :     /* suspend so the update walk kicks int */
    3507           1 :     vlib_process_suspend(vlib_get_main(), 1e-5);
    3508             : 
    3509           1 :     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
    3510           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3511           1 :     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
    3512             :              "200.200.200.200/32 was inplace modified for 3rd path");
    3513           1 :     FIB_TEST(2 == lb->lb_n_buckets,
    3514             :              "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
    3515             : 
    3516           7 :     for (ii = 0; ii < 6; ii++)
    3517             :     {
    3518           6 :         FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
    3519             :                  "LB Map for 200.200.200.200/32 at %d is %d",
    3520             :                  ii, lbm->lbm_buckets[ii]);
    3521             :     }
    3522          11 :     for (ii = 6; ii < 16; ii++)
    3523             :     {
    3524          10 :         FIB_TEST(lbm->lbm_buckets[ii] == ii,
    3525             :                  "LB Map for 200.200.200.200/32 at %d is %d",
    3526             :                  ii, lbm->lbm_buckets[ii]);
    3527             :     }
    3528           1 :     load_balance_map_unlock(lbmi);
    3529             : 
    3530             :     /*
    3531             :      * tidy up
    3532             :      */
    3533           1 :     fib_table_entry_path_add(fib_index,
    3534             :                              &pfx_1_1_1_1_s_32,
    3535             :                              FIB_SOURCE_API,
    3536             :                              FIB_ENTRY_FLAG_NONE,
    3537             :                              DPO_PROTO_IP4,
    3538             :                              &nh_10_10_10_1,
    3539           1 :                              tm->hw[0]->sw_if_index,
    3540             :                              ~0,
    3541             :                              1,
    3542             :                              NULL,
    3543             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3544             : 
    3545         129 :     for (ii = 0; ii < N_P; ii++)
    3546             :     {
    3547         128 :         fib_table_entry_delete(fib_index,
    3548         128 :                                &bgp_78s[ii],
    3549             :                                FIB_SOURCE_API);
    3550         128 :         FIB_TEST((FIB_NODE_INDEX_INVALID ==
    3551             :                   fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
    3552             :                  "%U removed",
    3553             :                  format_fib_prefix, &bgp_78s[ii]);
    3554             :     }
    3555           1 :     fib_table_entry_path_remove(fib_index,
    3556             :                                 &bgp_200_pfx,
    3557             :                                 FIB_SOURCE_API,
    3558             :                                 DPO_PROTO_IP4,
    3559             :                                 &pfx_1_1_1_2_s_32.fp_addr,
    3560             :                                 ~0,
    3561             :                                 fib_index,
    3562             :                                 1,
    3563             :                                 MPLS_LABEL_INVALID);
    3564           1 :     fib_table_entry_path_remove(fib_index,
    3565             :                                 &bgp_200_pfx,
    3566             :                                 FIB_SOURCE_API,
    3567             :                                 DPO_PROTO_IP4,
    3568             :                                 &nh_1_1_1_1,
    3569             :                                 ~0,
    3570             :                                 fib_index,
    3571             :                                 1,
    3572             :                                 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
    3573           1 :     fib_table_entry_path_remove(fib_index,
    3574             :                                 &bgp_200_pfx,
    3575             :                                 FIB_SOURCE_API,
    3576             :                                 DPO_PROTO_IP4,
    3577             :                                 &pfx_1_1_1_3_s_32.fp_addr,
    3578             :                                 ~0,
    3579             :                                 fib_index,
    3580             :                                 1,
    3581             :                                 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
    3582           1 :     fib_table_entry_delete(fib_index,
    3583             :                            &pfx_1_1_1_3_s_32,
    3584             :                            FIB_SOURCE_API);
    3585           1 :     fib_table_entry_delete(fib_index,
    3586             :                            &pfx_1_1_1_0_s_28,
    3587             :                            FIB_SOURCE_API);
    3588             :     /* suspend so the update walk kicks int */
    3589           1 :     vlib_process_suspend(vlib_get_main(), 1e-5);
    3590           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    3591             :               fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
    3592             :              "1.1.1.1/28 removed");
    3593           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    3594             :               fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
    3595             :              "1.1.1.3/32 removed");
    3596           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    3597             :               fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
    3598             :              "200.200.200.200/32 removed");
    3599             : 
    3600             :     /*
    3601             :      * add-remove test. no change.
    3602             :      */
    3603           1 :     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
    3604             :              fib_path_list_db_size());
    3605           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    3606             :              fib_path_list_pool_size());
    3607           1 :     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
    3608             :              fib_entry_pool_size());
    3609             : 
    3610             :     /*
    3611             :      * A route whose paths are built up iteratively and then removed
    3612             :      * all at once
    3613             :      */
    3614           2 :     fib_prefix_t pfx_4_4_4_4_s_32 = {
    3615             :         .fp_len = 32,
    3616             :         .fp_proto = FIB_PROTOCOL_IP4,
    3617             :         .fp_addr = {
    3618             :             /* 4.4.4.4/32 */
    3619           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
    3620             :         },
    3621             :     };
    3622             : 
    3623           1 :     fib_table_entry_path_add(fib_index,
    3624             :                              &pfx_4_4_4_4_s_32,
    3625             :                              FIB_SOURCE_API,
    3626             :                              FIB_ENTRY_FLAG_NONE,
    3627             :                              DPO_PROTO_IP4,
    3628             :                              &nh_10_10_10_1,
    3629           1 :                              tm->hw[0]->sw_if_index,
    3630             :                              ~0,
    3631             :                              1,
    3632             :                              NULL,
    3633             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3634           1 :     fib_table_entry_path_add(fib_index,
    3635             :                              &pfx_4_4_4_4_s_32,
    3636             :                              FIB_SOURCE_API,
    3637             :                              FIB_ENTRY_FLAG_NONE,
    3638             :                              DPO_PROTO_IP4,
    3639             :                              &nh_10_10_10_2,
    3640           1 :                              tm->hw[0]->sw_if_index,
    3641             :                              ~0,
    3642             :                              1,
    3643             :                              NULL,
    3644             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3645           1 :     fib_table_entry_path_add(fib_index,
    3646             :                              &pfx_4_4_4_4_s_32,
    3647             :                              FIB_SOURCE_API,
    3648             :                              FIB_ENTRY_FLAG_NONE,
    3649             :                              DPO_PROTO_IP4,
    3650             :                              &nh_10_10_10_3,
    3651           1 :                              tm->hw[0]->sw_if_index,
    3652             :                              ~0,
    3653             :                              1,
    3654             :                              NULL,
    3655             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3656           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID !=
    3657             :              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
    3658             :              "4.4.4.4/32 present");
    3659             : 
    3660           1 :     fib_table_entry_delete(fib_index,
    3661             :                            &pfx_4_4_4_4_s_32,
    3662             :                            FIB_SOURCE_API);
    3663           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    3664             :              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
    3665             :              "4.4.4.4/32 removed");
    3666             : 
    3667             :     /*
    3668             :      * add-remove test. no change.
    3669             :      */
    3670           1 :     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
    3671             :              fib_path_list_db_size());
    3672           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    3673             :              fib_path_list_pool_size());
    3674           1 :     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
    3675             :              fib_entry_pool_size());
    3676             : 
    3677             :     /*
    3678             :      * A route with multiple paths at once
    3679             :      */
    3680           1 :     FIB_TEST(0 ==
    3681             :              fib_test_multipath_v4(tm, fib_index, &pfx_4_4_4_4_s_32, 4, 4),
    3682             :              "multipath with 4 nexthops");
    3683             : 
    3684             :     /*
    3685             :      * A route with lots of multiple paths that will overflow max supported
    3686             :      * lb buckets because of normalization
    3687             :      */
    3688           1 :     FIB_TEST(0 ==
    3689             :              fib_test_multipath_v4(tm, fib_index, &pfx_4_4_4_4_s_32,
    3690             :                                    LB_MAX_BUCKETS / 2 + 23, LB_MAX_BUCKETS),
    3691             :              "multipath with too many nexthops");
    3692             : 
    3693             :     /*
    3694             :      * A route with more paths than max supported lb buckets
    3695             :      */
    3696           1 :     FIB_TEST(0 ==
    3697             :              fib_test_multipath_v4 (tm, fib_index, &pfx_4_4_4_4_s_32,
    3698             :                                     LB_MAX_BUCKETS + 13, LB_MAX_BUCKETS),
    3699             :              "multipath with too many nexthops");
    3700             : 
    3701             :     /*
    3702             :      * A route deag route
    3703             :      */
    3704           1 :     fib_table_entry_path_add(fib_index,
    3705             :                              &pfx_4_4_4_4_s_32,
    3706             :                              FIB_SOURCE_API,
    3707             :                              FIB_ENTRY_FLAG_NONE,
    3708             :                              DPO_PROTO_IP4,
    3709             :                              &zero_addr,
    3710             :                              ~0,
    3711             :                              fib_index,
    3712             :                              1,
    3713             :                              NULL,
    3714             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3715             : 
    3716           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
    3717           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
    3718             : 
    3719           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3720           1 :     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
    3721           1 :     lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
    3722             : 
    3723           1 :     FIB_TEST((fib_index == lkd->lkd_fib_index),
    3724             :              "4.4.4.4/32 is deag in %d %U",
    3725             :              lkd->lkd_fib_index,
    3726             :              format_dpo_id, dpo, 0);
    3727           1 :     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
    3728             :              "4.4.4.4/32 is source deag in %d %U",
    3729             :              lkd->lkd_input,
    3730             :              format_dpo_id, dpo, 0);
    3731             : 
    3732           1 :     fib_table_entry_delete(fib_index,
    3733             :                            &pfx_4_4_4_4_s_32,
    3734             :                            FIB_SOURCE_API);
    3735           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    3736             :              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
    3737             :              "4.4.4.4/32 removed");
    3738             : 
    3739             :     /*
    3740             :      * A route deag route in a source lookup table
    3741             :      */
    3742           1 :     fib_table_entry_path_add(fib_index,
    3743             :                              &pfx_4_4_4_4_s_32,
    3744             :                              FIB_SOURCE_API,
    3745             :                              FIB_ENTRY_FLAG_NONE,
    3746             :                              DPO_PROTO_IP4,
    3747             :                              &zero_addr,
    3748             :                              ~0,
    3749             :                              fib_index,
    3750             :                              1,
    3751             :                              NULL,
    3752             :                              FIB_ROUTE_PATH_SOURCE_LOOKUP);
    3753             : 
    3754           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
    3755           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
    3756             : 
    3757           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3758           1 :     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
    3759           1 :     lkd = lookup_dpo_get(dpo->dpoi_index);
    3760             : 
    3761           1 :     FIB_TEST((fib_index == lkd->lkd_fib_index),
    3762             :              "4.4.4.4/32 is deag in %d %U",
    3763             :              lkd->lkd_fib_index,
    3764             :              format_dpo_id, dpo, 0);
    3765           1 :     FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
    3766             :              "4.4.4.4/32 is source deag in %d %U",
    3767             :              lkd->lkd_input,
    3768             :              format_dpo_id, dpo, 0);
    3769             : 
    3770           1 :     fib_table_entry_delete(fib_index,
    3771             :                            &pfx_4_4_4_4_s_32,
    3772             :                            FIB_SOURCE_API);
    3773           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    3774             :              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
    3775             :              "4.4.4.4/32 removed");
    3776             : 
    3777             :     /*
    3778             :      * add-remove test. no change.
    3779             :      */
    3780           1 :     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
    3781             :              fib_path_list_db_size());
    3782           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    3783             :              fib_path_list_pool_size());
    3784           1 :     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
    3785             :              fib_entry_pool_size());
    3786             : 
    3787             :     /*
    3788             :      * Duplicate paths:
    3789             :      *  add a recursive with duplicate paths. Expect the duplicate to be ignored.
    3790             :      */
    3791           2 :     fib_prefix_t pfx_34_1_1_1_s_32 = {
    3792             :         .fp_len = 32,
    3793             :         .fp_proto = FIB_PROTOCOL_IP4,
    3794             :         .fp_addr = {
    3795           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
    3796             :         },
    3797             :     };
    3798           2 :     fib_prefix_t pfx_34_34_1_1_s_32 = {
    3799             :         .fp_len = 32,
    3800             :         .fp_proto = FIB_PROTOCOL_IP4,
    3801             :         .fp_addr = {
    3802           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
    3803             :         },
    3804             :     };
    3805           1 :     fei = fib_table_entry_path_add(fib_index,
    3806             :                                    &pfx_34_34_1_1_s_32,
    3807             :                                    FIB_SOURCE_API,
    3808             :                                    FIB_ENTRY_FLAG_NONE,
    3809             :                                    DPO_PROTO_IP4,
    3810             :                                    &nh_10_10_10_1,
    3811           1 :                                    tm->hw[0]->sw_if_index,
    3812             :                                    0,
    3813             :                                    1,
    3814             :                                    NULL,
    3815             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    3816           1 :     fei = fib_table_entry_path_add(fib_index,
    3817             :                                    &pfx_34_1_1_1_s_32,
    3818             :                                    FIB_SOURCE_API,
    3819             :                                    FIB_ENTRY_FLAG_NONE,
    3820             :                                    DPO_PROTO_IP4,
    3821             :                                    &pfx_34_34_1_1_s_32.fp_addr,
    3822             :                                    ~0,
    3823             :                                    fib_index,
    3824             :                                    1,
    3825             :                                    NULL,
    3826             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    3827           1 :     fei = fib_table_entry_path_add(fib_index,
    3828             :                                    &pfx_34_1_1_1_s_32,
    3829             :                                    FIB_SOURCE_API,
    3830             :                                    FIB_ENTRY_FLAG_NONE,
    3831             :                                    DPO_PROTO_IP4,
    3832             :                                    &pfx_34_34_1_1_s_32.fp_addr,
    3833             :                                    ~0,
    3834             :                                    fib_index,
    3835             :                                    1,
    3836             :                                    NULL,
    3837             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    3838           1 :     FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
    3839           1 :     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
    3840           1 :     fib_table_entry_delete(fib_index,
    3841             :                            &pfx_34_34_1_1_s_32,
    3842             :                            FIB_SOURCE_API);
    3843             : 
    3844             :     /*
    3845             :      * CLEANUP
    3846             :      *   remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
    3847             :      *           all of which are via 10.10.10.1, Itf1
    3848             :      */
    3849           1 :     fib_table_entry_path_remove(fib_index,
    3850             :                                 &pfx_1_1_1_2_s_32,
    3851             :                                 FIB_SOURCE_API,
    3852             :                                 DPO_PROTO_IP4,
    3853             :                                 &nh_10_10_10_1,
    3854           1 :                                 tm->hw[0]->sw_if_index,
    3855             :                                 ~0,
    3856             :                                 1,
    3857             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3858           1 :     fib_table_entry_path_remove(fib_index,
    3859             :                                 &pfx_1_1_1_1_s_32,
    3860             :                                 FIB_SOURCE_API,
    3861             :                                 DPO_PROTO_IP4,
    3862             :                                 &nh_10_10_10_1,
    3863           1 :                                 tm->hw[0]->sw_if_index,
    3864             :                                 ~0,
    3865             :                                 1,
    3866             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3867           1 :     fib_table_entry_path_remove(fib_index,
    3868             :                                 &pfx_1_1_2_0_s_24,
    3869             :                                 FIB_SOURCE_API,
    3870             :                                 DPO_PROTO_IP4,
    3871             :                                 &nh_10_10_10_1,
    3872           1 :                                 tm->hw[0]->sw_if_index,
    3873             :                                 ~0,
    3874             :                                 1,
    3875             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    3876             : 
    3877           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    3878             :              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
    3879             :              "1.1.1.1/32 removed");
    3880           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    3881             :              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
    3882             :              "1.1.1.2/32 removed");
    3883           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    3884             :              fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
    3885             :              "1.1.2.0/24 removed");
    3886             : 
    3887             :     /*
    3888             :      * -3 entries and -1 shared path-list
    3889             :      */
    3890           1 :     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
    3891             :              fib_path_list_db_size());
    3892           1 :     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
    3893             :              fib_path_list_pool_size());
    3894           1 :     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
    3895             :              fib_entry_pool_size());
    3896             : 
    3897             :     /*
    3898             :      * An attached-host route. Expect to link to the incomplete adj
    3899             :      */
    3900           2 :     fib_prefix_t pfx_4_1_1_1_s_32 = {
    3901             :         .fp_len = 32,
    3902             :         .fp_proto = FIB_PROTOCOL_IP4,
    3903             :         .fp_addr = {
    3904             :             /* 4.1.1.1/32 */
    3905           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
    3906             :         },
    3907             :     };
    3908           1 :     fib_table_entry_path_add(fib_index,
    3909             :                              &pfx_4_1_1_1_s_32,
    3910             :                              FIB_SOURCE_API,
    3911             :                              FIB_ENTRY_FLAG_NONE,
    3912             :                              DPO_PROTO_IP4,
    3913             :                              &zero_addr,
    3914           1 :                              tm->hw[0]->sw_if_index,
    3915             :                              fib_index,
    3916             :                              1,
    3917             :                              NULL,
    3918             :                              FIB_ROUTE_PATH_FLAG_NONE);
    3919             : 
    3920           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
    3921           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
    3922           1 :     ai = fib_entry_get_adj(fei);
    3923             : 
    3924           1 :     ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    3925             :                               VNET_LINK_IP4,
    3926             :                               &pfx_4_1_1_1_s_32.fp_addr,
    3927           1 :                               tm->hw[0]->sw_if_index);
    3928           1 :     FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
    3929           1 :     adj_unlock(ai2);
    3930             : 
    3931             :     /*
    3932             :      * +1 entry and +1 shared path-list
    3933             :      */
    3934           1 :     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
    3935             :              fib_path_list_db_size());
    3936           1 :     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
    3937             :              fib_path_list_pool_size());
    3938           1 :     FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
    3939             :              fib_entry_pool_size());
    3940             : 
    3941           1 :     fib_table_entry_delete(fib_index,
    3942             :                            &pfx_4_1_1_1_s_32,
    3943             :                            FIB_SOURCE_API);
    3944             : 
    3945           1 :     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
    3946             :              fib_path_list_db_size());
    3947           1 :     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
    3948             :              fib_path_list_pool_size());
    3949           1 :     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
    3950             :              fib_entry_pool_size());
    3951             : 
    3952             :     /*
    3953             :      * add a v6 prefix via v4 next-hops
    3954             :      */
    3955           2 :     fib_prefix_t pfx_2001_s_64 = {
    3956             :         .fp_len = 64,
    3957             :         .fp_proto = FIB_PROTOCOL_IP6,
    3958             :         .fp_addr = {
    3959           1 :             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
    3960             :         },
    3961             :     };
    3962           1 :     fei = fib_table_entry_path_add(0, //default v6 table
    3963             :                                    &pfx_2001_s_64,
    3964             :                                    FIB_SOURCE_API,
    3965             :                                    FIB_ENTRY_FLAG_NONE,
    3966             :                                    DPO_PROTO_IP4,
    3967             :                                    &nh_10_10_10_1,
    3968           1 :                                    tm->hw[0]->sw_if_index,
    3969             :                                    fib_index,
    3970             :                                    1,
    3971             :                                    NULL,
    3972             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    3973             : 
    3974           1 :     fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
    3975           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
    3976           1 :     ai = fib_entry_get_adj(fei);
    3977           1 :     adj = adj_get(ai);
    3978           1 :     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
    3979             :              "2001::/64 via ARP-adj");
    3980           1 :     FIB_TEST((adj->ia_link == VNET_LINK_IP6),
    3981             :              "2001::/64 is link type v6");
    3982           1 :     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
    3983             :              "2001::/64 ADJ-adj is NH proto v4");
    3984           1 :     fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
    3985             : 
    3986             :     /*
    3987             :      * add a uRPF exempt prefix:
    3988             :      *  test:
    3989             :      *   - it's forwarding is drop
    3990             :      *   - it's uRPF list is not empty
    3991             :      *   - the uRPF list for the default route (it's cover) is empty
    3992             :      */
    3993           1 :     fei = fib_table_entry_special_add(fib_index,
    3994             :                                       &pfx_4_1_1_1_s_32,
    3995             :                                       FIB_SOURCE_URPF_EXEMPT,
    3996             :                                       FIB_ENTRY_FLAG_DROP);
    3997           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    3998           1 :     FIB_TEST(load_balance_is_drop(dpo),
    3999             :              "uRPF exempt 4.1.1.1/32 DROP");
    4000           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
    4001             :              "uRPF list for exempt prefix has itf index 0");
    4002           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
    4003           1 :     FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
    4004             :              "uRPF list for 0.0.0.0/0 empty");
    4005             : 
    4006           1 :     fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
    4007             : 
    4008             :     /*
    4009             :      * An adj-fib that fails the refinement criteria - no connected cover
    4010             :      */
    4011           2 :     fib_prefix_t pfx_12_10_10_2_s_32 = {
    4012             :         .fp_len = 32,
    4013             :         .fp_proto = FIB_PROTOCOL_IP4,
    4014             :         .fp_addr = {
    4015             :             /* 12.10.10.2 */
    4016           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
    4017             :         },
    4018             :     };
    4019             : 
    4020           1 :     fib_table_entry_path_add(fib_index,
    4021             :                              &pfx_12_10_10_2_s_32,
    4022             :                              FIB_SOURCE_ADJ,
    4023             :                              FIB_ENTRY_FLAG_ATTACHED,
    4024             :                              DPO_PROTO_IP4,
    4025             :                              &pfx_12_10_10_2_s_32.fp_addr,
    4026           1 :                              tm->hw[0]->sw_if_index,
    4027             :                              ~0, // invalid fib index
    4028             :                              1,
    4029             :                              NULL,
    4030             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4031             : 
    4032           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
    4033           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4034           1 :     FIB_TEST(dpo_is_drop(dpo),
    4035             :              "no connected cover adj-fib fails refinement: %U",
    4036             :              format_dpo_id, dpo, 0);
    4037             : 
    4038           1 :     fib_table_entry_delete(fib_index,
    4039             :                            &pfx_12_10_10_2_s_32,
    4040             :                            FIB_SOURCE_ADJ);
    4041             : 
    4042             :     /*
    4043             :      * An adj-fib that fails the refinement criteria - cover is connected
    4044             :      * but on a different interface
    4045             :      */
    4046           2 :     fib_prefix_t pfx_10_10_10_127_s_32 = {
    4047             :         .fp_len = 32,
    4048             :         .fp_proto = FIB_PROTOCOL_IP4,
    4049             :         .fp_addr = {
    4050             :             /* 10.10.10.127 */
    4051           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
    4052             :         },
    4053             :     };
    4054             : 
    4055           1 :     fib_table_entry_path_add(fib_index,
    4056             :                              &pfx_10_10_10_127_s_32,
    4057             :                              FIB_SOURCE_ADJ,
    4058             :                              FIB_ENTRY_FLAG_ATTACHED,
    4059             :                              DPO_PROTO_IP4,
    4060             :                              &pfx_10_10_10_127_s_32.fp_addr,
    4061           1 :                              tm->hw[1]->sw_if_index,
    4062             :                              ~0, // invalid fib index
    4063             :                              1,
    4064             :                              NULL,
    4065             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4066             : 
    4067           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
    4068           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4069           1 :     FIB_TEST(dpo_is_drop(dpo),
    4070             :              "wrong interface adj-fib fails refinement");
    4071             : 
    4072           1 :     fib_table_entry_delete(fib_index,
    4073             :                            &pfx_10_10_10_127_s_32,
    4074             :                            FIB_SOURCE_ADJ);
    4075             : 
    4076             :     /*
    4077             :      * add a second path to an adj-fib
    4078             :      * this is a sumiluation of another ARP entry created
    4079             :      * on an interface on which the connected prefix does not exist.
    4080             :      * The second path fails refinement. Expect to forward through the
    4081             :      * first.
    4082             :      */
    4083           2 :     fib_prefix_t pfx_10_10_10_3_s_32 = {
    4084             :         .fp_len = 32,
    4085             :         .fp_proto = FIB_PROTOCOL_IP4,
    4086             :         .fp_addr = {
    4087             :             /* 10.10.10.3 */
    4088           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
    4089             :         },
    4090             :     };
    4091             : 
    4092           1 :     ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    4093             :                                 VNET_LINK_IP4,
    4094             :                                 &nh_10_10_10_3,
    4095           1 :                                 tm->hw[0]->sw_if_index);
    4096             : 
    4097           1 :     fib_test_lb_bucket_t ip_o_10_10_10_3 = {
    4098             :         .type = FT_LB_ADJ,
    4099             :         .adj = {
    4100             :             .adj = ai_03,
    4101             :         },
    4102             :     };
    4103           1 :     fei = fib_table_entry_path_add(fib_index,
    4104             :                                    &pfx_10_10_10_3_s_32,
    4105             :                                    FIB_SOURCE_ADJ,
    4106             :                                    FIB_ENTRY_FLAG_NONE,
    4107             :                                    DPO_PROTO_IP4,
    4108             :                                    &nh_10_10_10_3,
    4109           1 :                                    tm->hw[0]->sw_if_index,
    4110             :                                    fib_index,
    4111             :                                    1,
    4112             :                                    NULL,
    4113             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    4114           1 :     fei = fib_table_entry_path_add(fib_index,
    4115             :                                    &pfx_10_10_10_3_s_32,
    4116             :                                    FIB_SOURCE_ADJ,
    4117             :                                    FIB_ENTRY_FLAG_NONE,
    4118             :                                    DPO_PROTO_IP4,
    4119             :                                    &nh_12_12_12_12,
    4120           1 :                                    tm->hw[1]->sw_if_index,
    4121             :                                    fib_index,
    4122             :                                    1,
    4123             :                                    NULL,
    4124             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    4125           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    4126             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    4127             :                                       1,
    4128             :                                       &ip_o_10_10_10_3),
    4129             :              "10.10.10.3 via 10.10.10.3/Eth0 only");
    4130             : 
    4131             :     /*
    4132             :      * remove the path that refines the cover, should go unresolved
    4133             :      */
    4134           1 :     fib_table_entry_path_remove(fib_index,
    4135             :                                 &pfx_10_10_10_3_s_32,
    4136             :                                 FIB_SOURCE_ADJ,
    4137             :                                 DPO_PROTO_IP4,
    4138             :                                 &nh_10_10_10_3,
    4139           1 :                                 tm->hw[0]->sw_if_index,
    4140             :                                 fib_index,
    4141             :                                 1,
    4142             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    4143           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4144           1 :     FIB_TEST(dpo_is_drop(dpo),
    4145             :              "wrong interface adj-fib fails refinement");
    4146             : 
    4147             :     /*
    4148             :      * add back the path that refines the cover
    4149             :      */
    4150           1 :     fei = fib_table_entry_path_add(fib_index,
    4151             :                                    &pfx_10_10_10_3_s_32,
    4152             :                                    FIB_SOURCE_ADJ,
    4153             :                                    FIB_ENTRY_FLAG_NONE,
    4154             :                                    DPO_PROTO_IP4,
    4155             :                                    &nh_10_10_10_3,
    4156           1 :                                    tm->hw[0]->sw_if_index,
    4157             :                                    fib_index,
    4158             :                                    1,
    4159             :                                    NULL,
    4160             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    4161           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    4162             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    4163             :                                       1,
    4164             :                                       &ip_o_10_10_10_3),
    4165             :              "10.10.10.3 via 10.10.10.3/Eth0 only");
    4166             : 
    4167             :     /*
    4168             :      * remove the path that does not refine the cover
    4169             :      */
    4170           1 :     fib_table_entry_path_remove(fib_index,
    4171             :                                 &pfx_10_10_10_3_s_32,
    4172             :                                 FIB_SOURCE_ADJ,
    4173             :                                 DPO_PROTO_IP4,
    4174             :                                 &nh_12_12_12_12,
    4175           1 :                                 tm->hw[1]->sw_if_index,
    4176             :                                 fib_index,
    4177             :                                 1,
    4178             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    4179           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    4180             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    4181             :                                       1,
    4182             :                                       &ip_o_10_10_10_3),
    4183             :              "10.10.10.3 via 10.10.10.3/Eth0 only");
    4184             : 
    4185             :     /*
    4186             :      * remove the path that does refine, it's the last path, so
    4187             :      * the entry should be gone
    4188             :      */
    4189           1 :     fib_table_entry_path_remove(fib_index,
    4190             :                                 &pfx_10_10_10_3_s_32,
    4191             :                                 FIB_SOURCE_ADJ,
    4192             :                                 DPO_PROTO_IP4,
    4193             :                                 &nh_10_10_10_3,
    4194           1 :                                 tm->hw[0]->sw_if_index,
    4195             :                                 fib_index,
    4196             :                                 1,
    4197             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    4198           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
    4199           1 :     FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
    4200             : 
    4201           1 :     adj_unlock(ai_03);
    4202             : 
    4203             :     /*
    4204             :      * change the table's flow-hash config - expect the update to propagete to
    4205             :      * the entries' load-balance objects
    4206             :      */
    4207             :     flow_hash_config_t old_hash_config, new_hash_config;
    4208             : 
    4209           1 :     old_hash_config = fib_table_get_flow_hash_config(fib_index,
    4210             :                                                      FIB_PROTOCOL_IP4);
    4211           1 :     new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
    4212             :                        IP_FLOW_HASH_DST_ADDR);
    4213             : 
    4214           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
    4215           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4216           1 :     lb = load_balance_get(dpo->dpoi_index);
    4217           1 :     FIB_TEST((lb->lb_hash_config == old_hash_config),
    4218             :              "Table and LB hash config match: %U",
    4219             :              format_ip_flow_hash_config, lb->lb_hash_config);
    4220             : 
    4221           1 :     fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
    4222             : 
    4223           1 :     FIB_TEST((lb->lb_hash_config == new_hash_config),
    4224             :              "Table and LB newhash config match: %U",
    4225             :              format_ip_flow_hash_config, lb->lb_hash_config);
    4226             : 
    4227             :     /*
    4228             :      * A route via DVR DPO
    4229             :      */
    4230           1 :     fei = fib_table_entry_path_add(fib_index,
    4231             :                                    &pfx_10_10_10_3_s_32,
    4232             :                                    FIB_SOURCE_API,
    4233             :                                    FIB_ENTRY_FLAG_NONE,
    4234             :                                    DPO_PROTO_IP4,
    4235             :                                    &zero_addr,
    4236           1 :                                    tm->hw[0]->sw_if_index,
    4237             :                                    ~0,
    4238             :                                    1,
    4239             :                                    NULL,
    4240             :                                    FIB_ROUTE_PATH_DVR);
    4241           1 :     dpo_id_t dvr_dpo = DPO_INVALID;
    4242           1 :     dvr_dpo_add_or_lock(tm->hw[0]->sw_if_index, DPO_PROTO_IP4, &dvr_dpo);
    4243           1 :     fib_test_lb_bucket_t ip_o_l2 = {
    4244             :         .type = FT_LB_L2,
    4245             :         .adj = {
    4246           1 :             .adj = dvr_dpo.dpoi_index,
    4247             :         },
    4248             :     };
    4249             : 
    4250           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    4251             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    4252             :                                       1,
    4253             :                                       &ip_o_l2),
    4254             :              "10.10.10.3 via L2 on Eth0");
    4255           1 :     fib_table_entry_path_remove(fib_index,
    4256             :                                 &pfx_10_10_10_3_s_32,
    4257             :                                 FIB_SOURCE_API,
    4258             :                                 DPO_PROTO_IP4,
    4259             :                                 &zero_addr,
    4260           1 :                                 tm->hw[0]->sw_if_index,
    4261             :                                 fib_index,
    4262             :                                 1,
    4263             :                                 FIB_ROUTE_PATH_DVR);
    4264           1 :     dpo_reset(&dvr_dpo);
    4265             : 
    4266             :     /*
    4267             :      * add the default route via a next-hop that will form a loop
    4268             :      */
    4269           2 :     fib_prefix_t pfx_conn = {
    4270             :         .fp_len = 24,
    4271             :         .fp_proto = FIB_PROTOCOL_IP4,
    4272             :         .fp_addr = {
    4273             :             /* 30.30.30.30 */
    4274           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x1e1e1e1e),
    4275             :         },
    4276             :     };
    4277             : 
    4278           1 :     dfrt = fib_table_entry_path_add(fib_index,
    4279             :                                     &pfx_0_0_0_0_s_0,
    4280             :                                     FIB_SOURCE_API,
    4281             :                                     FIB_ENTRY_FLAG_NONE,
    4282             :                                     DPO_PROTO_IP4,
    4283             :                                     &pfx_conn.fp_addr,
    4284             :                                     ~0,
    4285             :                                     fib_index,
    4286             :                                     1,
    4287             :                                     NULL,
    4288             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    4289             :     /*
    4290             :      * the default route is a drop, since it's looped
    4291             :      */
    4292           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
    4293             :              "Default route is DROP");
    4294             : 
    4295             :     /*
    4296             :      * add a connected cover for the next-hop, this breaks the recursion loop
    4297             :      * for the default route
    4298             :      */
    4299           1 :     fib_table_entry_path_add(fib_index,
    4300             :                              &pfx_conn,
    4301             :                              FIB_SOURCE_API,
    4302             :                              (FIB_ENTRY_FLAG_CONNECTED |
    4303             :                               FIB_ENTRY_FLAG_ATTACHED),
    4304             :                              DPO_PROTO_IP4,
    4305             :                              NULL,
    4306           1 :                              tm->hw[0]->sw_if_index,
    4307             :                              ~0,
    4308             :                              1,
    4309             :                              NULL,
    4310             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4311           1 :     pfx_conn.fp_len = 32;
    4312           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_conn);
    4313             : 
    4314           1 :     u32 ai_30 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    4315             :                                     VNET_LINK_IP4,
    4316             :                                     &pfx_conn.fp_addr,
    4317           1 :                                     tm->hw[0]->sw_if_index);
    4318             : 
    4319           1 :     fib_test_lb_bucket_t ip_o_30_30_30_30 = {
    4320             :         .type = FT_LB_ADJ,
    4321             :         .adj = {
    4322             :             .adj = ai_30,
    4323             :         },
    4324             :     };
    4325           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    4326             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    4327             :                                       1,
    4328             :                                       &ip_o_30_30_30_30),
    4329             :              "30.30.30.30 via adj");
    4330           1 :     FIB_TEST_REC_FORW(&pfx_0_0_0_0_s_0, &pfx_conn, 0);
    4331             : 
    4332           1 :     pfx_conn.fp_len = 24;
    4333           1 :     fib_table_entry_delete(fib_index,
    4334             :                            &pfx_conn,
    4335             :                            FIB_SOURCE_API);
    4336           1 :     fib_table_entry_delete(fib_index,
    4337             :                            &pfx_0_0_0_0_s_0,
    4338             :                            FIB_SOURCE_API);
    4339           1 :     adj_unlock(ai_30);
    4340             : 
    4341             :     /*
    4342             :      * CLEANUP
    4343             :      *    remove adj-fibs:
    4344             :      */
    4345           1 :     fib_table_entry_delete(fib_index,
    4346             :                            &pfx_10_10_10_1_s_32,
    4347             :                            FIB_SOURCE_ADJ);
    4348           1 :     fib_table_entry_delete(fib_index,
    4349             :                            &pfx_10_10_10_2_s_32,
    4350             :                            FIB_SOURCE_ADJ);
    4351           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    4352             :              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
    4353             :              "10.10.10.1/32 adj-fib removed");
    4354           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    4355             :              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
    4356             :              "10.10.10.2/32 adj-fib removed");
    4357             : 
    4358             :     /*
    4359             :      * -2 entries and -2 non-shared path-list
    4360             :      */
    4361           1 :     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
    4362             :              fib_path_list_db_size());
    4363           1 :     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
    4364             :              fib_path_list_pool_size());
    4365           1 :     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
    4366             :              fib_entry_pool_size());
    4367             : 
    4368             :     /*
    4369             :      * unlock the adjacencies for which this test provided a rewrite.
    4370             :      * These are the last locks on these adjs. they should thus go away.
    4371             :      */
    4372           1 :     adj_unlock(ai_02);
    4373           1 :     adj_unlock(ai_01);
    4374           1 :     adj_unlock(ai_12_12_12_12);
    4375             : 
    4376           1 :     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
    4377             :              adj_nbr_db_size());
    4378             : 
    4379             :     /*
    4380             :      * CLEANUP
    4381             :      *   remove the interface prefixes
    4382             :      */
    4383           1 :     local_pfx.fp_len = 32;
    4384           1 :     fib_table_entry_special_remove(fib_index, &local_pfx,
    4385             :                                    FIB_SOURCE_INTERFACE);
    4386           1 :     fei = fib_table_lookup(fib_index, &local_pfx);
    4387             : 
    4388           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    4389             :              fib_table_lookup_exact_match(fib_index, &local_pfx),
    4390             :              "10.10.10.10/32 adj-fib removed");
    4391             : 
    4392           1 :     local_pfx.fp_len = 24;
    4393           1 :     fib_table_entry_delete(fib_index, &local_pfx,
    4394             :                            FIB_SOURCE_INTERFACE);
    4395             : 
    4396           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID ==
    4397             :              fib_table_lookup_exact_match(fib_index, &local_pfx),
    4398             :              "10.10.10.10/24 adj-fib removed");
    4399             : 
    4400             :     /*
    4401             :      * -2 entries and -2 non-shared path-list
    4402             :      */
    4403           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
    4404             :              fib_path_list_db_size());
    4405           1 :     FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
    4406             :              fib_path_list_pool_size());
    4407           1 :     FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
    4408             :              fib_entry_pool_size());
    4409             : 
    4410             :     /*
    4411             :      * Last but not least, remove the VRF
    4412             :      */
    4413           1 :     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
    4414             :                                              FIB_PROTOCOL_IP4,
    4415             :                                              FIB_SOURCE_API)),
    4416             :              "NO API Source'd prefixes");
    4417           1 :     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
    4418             :                                              FIB_PROTOCOL_IP4,
    4419             :                                              FIB_SOURCE_RR)),
    4420             :              "NO RR Source'd prefixes");
    4421           1 :     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
    4422             :                                              FIB_PROTOCOL_IP4,
    4423             :                                              FIB_SOURCE_INTERFACE)),
    4424             :              "NO INterface Source'd prefixes");
    4425             : 
    4426           5 :     for (ii = 0; ii < 4; ii++)
    4427           4 :       fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[ii]->sw_if_index, 0);
    4428             : 
    4429           1 :     fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
    4430             : 
    4431           1 :     FIB_TEST((0  == fib_path_list_db_size()), "path list DB population:%d",
    4432             :              fib_path_list_db_size());
    4433           1 :     FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
    4434             :              fib_path_list_pool_size());
    4435           1 :     FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
    4436             :              fib_entry_pool_size());
    4437           1 :     FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
    4438             :              pool_elts(fib_urpf_list_pool));
    4439           1 :     FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
    4440             :              pool_elts(load_balance_map_pool));
    4441           1 :     FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
    4442             :              pool_elts(load_balance_pool));
    4443           1 :     FIB_TEST((0 == pool_elts(dvr_dpo_pool)), "L2 DPO pool size is %d",
    4444             :              pool_elts(dvr_dpo_pool));
    4445             : 
    4446           1 :     return (res);
    4447             : }
    4448             : 
    4449             : static int
    4450           1 : fib_test_v6 (void)
    4451             : {
    4452             :     /*
    4453             :      * In the default table check for the presence and correct forwarding
    4454             :      * of the special entries
    4455             :      */
    4456             :     fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
    4457             :     const dpo_id_t *dpo, *dpo_drop;
    4458             :     const ip_adjacency_t *adj;
    4459             :     const receive_dpo_t *rd;
    4460             :     test_main_t *tm;
    4461             :     u32 fib_index;
    4462             :     int ii, res;
    4463             : 
    4464           1 :     res = 0;
    4465           1 :     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
    4466             :              adj_nbr_db_size());
    4467             : 
    4468             :     /* via 2001:0:0:1::2 */
    4469           2 :     ip46_address_t nh_2001_2 = {
    4470             :         .ip6 = {
    4471             :             .as_u64 = {
    4472           1 :                 [0] = clib_host_to_net_u64(0x2001000000000001),
    4473           1 :                 [1] = clib_host_to_net_u64(0x0000000000000002),
    4474             :             },
    4475             :         },
    4476             :     };
    4477             : 
    4478           1 :     tm = &test_main;
    4479             : 
    4480           1 :     dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
    4481             : 
    4482             :     /* Find or create FIB table 11 */
    4483           1 :     fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
    4484             :                                                   FIB_SOURCE_API);
    4485             : 
    4486           5 :     for (ii = 0; ii < 4; ii++)
    4487           4 :       fib_table_bind (FIB_PROTOCOL_IP6, tm->hw[ii]->sw_if_index, fib_index);
    4488             : 
    4489           1 :     fib_prefix_t pfx_0_0 = {
    4490             :         .fp_len = 0,
    4491             :         .fp_proto = FIB_PROTOCOL_IP6,
    4492             :         .fp_addr = {
    4493             :             .ip6 = {
    4494             :                 {0, 0},
    4495             :             },
    4496             :         },
    4497             :     };
    4498             : 
    4499           1 :     dfrt = fib_table_lookup(fib_index, &pfx_0_0);
    4500           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
    4501           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
    4502             :              "Default route is DROP");
    4503             : 
    4504           1 :     dpo = fib_entry_contribute_ip_forwarding(dfrt);
    4505           1 :     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
    4506             :                   1,
    4507             :                   &pfx_0_0.fp_addr.ip6)),
    4508             :              "default-route; fwd and non-fwd tables match");
    4509             : 
    4510             :     // FIXME - check specials.
    4511             : 
    4512             :     /*
    4513             :      * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
    4514             :      * each with 2 entries and a v6 mfib with 4 path-lists and v4 mfib with 2.
    4515             :      * All entries are special so no path-list sharing.
    4516             :      */
    4517             : #define ENPS (5+4)
    4518           1 :     u32 PNPS = (5+4+4+2);
    4519             :     /*
    4520             :      * if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
    4521             :      */
    4522           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
    4523           1 :     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
    4524             :              fib_path_list_pool_size());
    4525           1 :     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
    4526             :              fib_entry_pool_size());
    4527             : 
    4528             :     /*
    4529             :      * add interface routes.
    4530             :      *  validate presence of /64 attached and /128 recieve.
    4531             :      *  test for the presence of the receive address in the glean and local adj
    4532             :      *
    4533             :      * receive on 2001:0:0:1::1/128
    4534             :      */
    4535           3 :     fib_prefix_t local_pfx = {
    4536             :         .fp_len = 64,
    4537             :         .fp_proto = FIB_PROTOCOL_IP6,
    4538             :         .fp_addr = {
    4539             :             .ip6 = {
    4540             :                 .as_u64 = {
    4541           1 :                     [0] = clib_host_to_net_u64(0x2001000000000001),
    4542           1 :                     [1] = clib_host_to_net_u64(0x0000000000000001),
    4543             :                 },
    4544             :             },
    4545             :         }
    4546             :     };
    4547             : 
    4548           1 :     fib_table_entry_update_one_path(fib_index, &local_pfx,
    4549             :                                     FIB_SOURCE_INTERFACE,
    4550             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    4551             :                                      FIB_ENTRY_FLAG_ATTACHED),
    4552             :                                     DPO_PROTO_IP6,
    4553             :                                     NULL,
    4554           1 :                                     tm->hw[0]->sw_if_index,
    4555             :                                     ~0,
    4556             :                                     1,
    4557             :                                     NULL,
    4558             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    4559           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    4560             : 
    4561           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
    4562             : 
    4563           1 :     ai = fib_entry_get_adj(fei);
    4564           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
    4565           1 :     adj = adj_get(ai);
    4566           1 :     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
    4567             :              "attached interface adj is glean");
    4568           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4569           1 :     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
    4570             :                   1,
    4571             :                   &local_pfx.fp_addr.ip6)),
    4572             :              "attached-route; fwd and non-fwd tables match");
    4573             : 
    4574           1 :     local_pfx.fp_len = 128;
    4575           1 :     fib_table_entry_update_one_path(fib_index, &local_pfx,
    4576             :                                     FIB_SOURCE_INTERFACE,
    4577             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    4578             :                                      FIB_ENTRY_FLAG_LOCAL),
    4579             :                                     DPO_PROTO_IP6,
    4580             :                                     NULL,
    4581           1 :                                     tm->hw[0]->sw_if_index,
    4582             :                                     ~0, // invalid fib index
    4583             :                                     1,
    4584             :                                     NULL,
    4585             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    4586           1 :     fei = fib_table_lookup(fib_index, &local_pfx);
    4587             : 
    4588           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
    4589             : 
    4590           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4591           1 :     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
    4592           1 :     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
    4593             :              "local interface adj is local");
    4594           1 :     rd = receive_dpo_get(dpo->dpoi_index);
    4595             : 
    4596           1 :     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
    4597             :                                     &rd->rd_addr)),
    4598             :              "local interface adj is receive ok");
    4599             : 
    4600           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4601           1 :     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
    4602             :                   1,
    4603             :                   &local_pfx.fp_addr.ip6)),
    4604             :              "local-route; fwd and non-fwd tables match");
    4605           1 :     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
    4606             :                                     &adj->sub_type.glean.rx_pfx.fp_addr)),
    4607             :              "attached interface adj is receive ok");
    4608             : 
    4609             :     /*
    4610             :      * +2 entries. +2 unshared path-lists
    4611             :      */
    4612           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
    4613           1 :     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
    4614             :              fib_path_list_pool_size());
    4615           1 :     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
    4616             :              fib_entry_pool_size());
    4617             : 
    4618             :     /*
    4619             :      * Modify the default route to be via an adj not yet known.
    4620             :      * this sources the defalut route with the API source, which is
    4621             :      * a higher preference to the DEFAULT_ROUTE source
    4622             :      */
    4623           1 :     fib_table_entry_path_add(fib_index, &pfx_0_0,
    4624             :                              FIB_SOURCE_API,
    4625             :                              FIB_ENTRY_FLAG_NONE,
    4626             :                              DPO_PROTO_IP6,
    4627             :                              &nh_2001_2,
    4628           1 :                              tm->hw[0]->sw_if_index,
    4629             :                              ~0,
    4630             :                              1,
    4631             :                              NULL,
    4632             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4633           1 :     fei = fib_table_lookup(fib_index, &pfx_0_0);
    4634             : 
    4635           1 :     FIB_TEST((fei == dfrt), "default route same index");
    4636           1 :     ai = fib_entry_get_adj(fei);
    4637           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
    4638           1 :     adj = adj_get(ai);
    4639           1 :     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
    4640             :              "adj is incomplete");
    4641           1 :     FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
    4642             :              "adj nbr next-hop ok");
    4643             : 
    4644             :     /*
    4645             :      * find the adj in the shared db
    4646             :      */
    4647           1 :     locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
    4648             :                                     VNET_LINK_IP6,
    4649             :                                     &nh_2001_2,
    4650           1 :                                     tm->hw[0]->sw_if_index);
    4651           1 :     FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
    4652           1 :     adj_unlock(locked_ai);
    4653             : 
    4654             :     /*
    4655             :      * no more entries. +1 shared path-list
    4656             :      */
    4657           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
    4658             :              fib_path_list_db_size());
    4659           1 :     FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
    4660             :              fib_path_list_pool_size());
    4661           1 :     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
    4662             :              fib_entry_pool_size());
    4663             : 
    4664             :     /*
    4665             :      * remove the API source from the default route. We expected
    4666             :      * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
    4667             :      */
    4668           1 :     fib_table_entry_path_remove(fib_index, &pfx_0_0,
    4669             :                                 FIB_SOURCE_API,
    4670             :                                 DPO_PROTO_IP6,
    4671             :                                 &nh_2001_2,
    4672           1 :                                 tm->hw[0]->sw_if_index,
    4673             :                                 ~0,
    4674             :                                 1,
    4675             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    4676           1 :     fei = fib_table_lookup(fib_index, &pfx_0_0);
    4677             : 
    4678           1 :     FIB_TEST((fei == dfrt), "default route same index");
    4679           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
    4680             :              "Default route is DROP");
    4681             : 
    4682             :     /*
    4683             :      * no more entries. -1 shared path-list
    4684             :      */
    4685           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
    4686             :              fib_path_list_db_size());
    4687           1 :     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
    4688             :              fib_path_list_pool_size());
    4689           1 :     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
    4690             :              fib_entry_pool_size());
    4691             : 
    4692             :     /*
    4693             :      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
    4694             :      */
    4695           3 :     fib_prefix_t pfx_2001_1_2_s_128 = {
    4696             :         .fp_len   = 128,
    4697             :         .fp_proto = FIB_PROTOCOL_IP6,
    4698             :         .fp_addr  = {
    4699             :             .ip6 = {
    4700             :                 .as_u64 = {
    4701           1 :                     [0] = clib_host_to_net_u64(0x2001000000000001),
    4702           1 :                     [1] = clib_host_to_net_u64(0x0000000000000002),
    4703             :                 },
    4704             :             },
    4705             :         }
    4706             :     };
    4707           3 :     fib_prefix_t pfx_2001_1_3_s_128 = {
    4708             :         .fp_len   = 128,
    4709             :         .fp_proto = FIB_PROTOCOL_IP6,
    4710             :         .fp_addr  = {
    4711             :             .ip6 = {
    4712             :                 .as_u64 = {
    4713           1 :                     [0] = clib_host_to_net_u64(0x2001000000000001),
    4714           1 :                     [1] = clib_host_to_net_u64(0x0000000000000003),
    4715             :                 },
    4716             :             },
    4717             :         }
    4718             :     };
    4719           1 :     u8 eth_addr[] = {
    4720             :         0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
    4721             :     };
    4722             : 
    4723           1 :     ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
    4724             :                                 VNET_LINK_IP6,
    4725             :                                 &pfx_2001_1_2_s_128.fp_addr,
    4726           1 :                                 tm->hw[0]->sw_if_index);
    4727           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
    4728           1 :     adj = adj_get(ai_01);
    4729           1 :     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
    4730             :              "adj is incomplete");
    4731           1 :     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
    4732             :                                     &adj->sub_type.nbr.next_hop)),
    4733             :              "adj nbr next-hop ok");
    4734             : 
    4735           1 :     adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
    4736             :                            fib_test_build_rewrite(eth_addr));
    4737           1 :     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
    4738             :              "adj is complete");
    4739           1 :     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
    4740             :                                     &adj->sub_type.nbr.next_hop)),
    4741             :              "adj nbr next-hop ok");
    4742             : 
    4743           1 :     fib_table_entry_path_add(fib_index,
    4744             :                              &pfx_2001_1_2_s_128,
    4745             :                              FIB_SOURCE_ADJ,
    4746             :                              FIB_ENTRY_FLAG_ATTACHED,
    4747             :                              DPO_PROTO_IP6,
    4748             :                              &pfx_2001_1_2_s_128.fp_addr,
    4749           1 :                              tm->hw[0]->sw_if_index,
    4750             :                              ~0,
    4751             :                              1,
    4752             :                              NULL,
    4753             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4754             : 
    4755           1 :     fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
    4756           1 :     ai = fib_entry_get_adj(fei);
    4757           1 :     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
    4758             : 
    4759           1 :     eth_addr[5] = 0xb2;
    4760             : 
    4761           1 :     ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
    4762             :                                 VNET_LINK_IP6,
    4763             :                                 &pfx_2001_1_3_s_128.fp_addr,
    4764           1 :                                 tm->hw[0]->sw_if_index);
    4765           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
    4766           1 :     adj = adj_get(ai_02);
    4767           1 :     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
    4768             :              "adj is incomplete");
    4769           1 :     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
    4770             :                                     &adj->sub_type.nbr.next_hop)),
    4771             :              "adj nbr next-hop ok");
    4772             : 
    4773           1 :     adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
    4774             :                            fib_test_build_rewrite(eth_addr));
    4775           1 :     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
    4776             :              "adj is complete");
    4777           1 :     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
    4778             :                                     &adj->sub_type.nbr.next_hop)),
    4779             :              "adj nbr next-hop ok");
    4780           1 :     FIB_TEST((ai_01 != ai_02), "ADJs are different");
    4781             : 
    4782           1 :     fib_table_entry_path_add(fib_index,
    4783             :                              &pfx_2001_1_3_s_128,
    4784             :                              FIB_SOURCE_ADJ,
    4785             :                              FIB_ENTRY_FLAG_ATTACHED,
    4786             :                              DPO_PROTO_IP6,
    4787             :                              &pfx_2001_1_3_s_128.fp_addr,
    4788           1 :                              tm->hw[0]->sw_if_index,
    4789             :                              ~0,
    4790             :                              1,
    4791             :                              NULL,
    4792             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4793             : 
    4794           1 :     fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
    4795           1 :     ai = fib_entry_get_adj(fei);
    4796           1 :     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
    4797             : 
    4798             :     /*
    4799             :      * +2 entries, +2 unshread path-lists.
    4800             :      */
    4801           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
    4802             :              fib_path_list_db_size());
    4803           1 :     FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
    4804             :              fib_path_list_pool_size());
    4805           1 :     FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
    4806             :              fib_entry_pool_size());
    4807             : 
    4808             :     /*
    4809             :      * Add a 2 routes via the first ADJ. ensure path-list sharing
    4810             :      */
    4811           3 :     fib_prefix_t pfx_2001_a_s_64 = {
    4812             :         .fp_len   = 64,
    4813             :         .fp_proto = FIB_PROTOCOL_IP6,
    4814             :         .fp_addr  = {
    4815             :             .ip6 = {
    4816             :                 .as_u64 = {
    4817           1 :                     [0] = clib_host_to_net_u64(0x200100000000000a),
    4818           1 :                     [1] = clib_host_to_net_u64(0x0000000000000000),
    4819             :                 },
    4820             :             },
    4821             :         }
    4822             :     };
    4823           3 :     fib_prefix_t pfx_2001_b_s_64 = {
    4824             :         .fp_len   = 64,
    4825             :         .fp_proto = FIB_PROTOCOL_IP6,
    4826             :         .fp_addr  = {
    4827             :             .ip6 = {
    4828             :                 .as_u64 = {
    4829           1 :                     [0] = clib_host_to_net_u64(0x200100000000000b),
    4830           1 :                     [1] = clib_host_to_net_u64(0x0000000000000000),
    4831             :                 },
    4832             :             },
    4833             :         }
    4834             :     };
    4835             : 
    4836           1 :     fib_table_entry_path_add(fib_index,
    4837             :                              &pfx_2001_a_s_64,
    4838             :                              FIB_SOURCE_API,
    4839             :                              FIB_ENTRY_FLAG_NONE,
    4840             :                              DPO_PROTO_IP6,
    4841             :                              &nh_2001_2,
    4842           1 :                              tm->hw[0]->sw_if_index,
    4843             :                              ~0,
    4844             :                              1,
    4845             :                              NULL,
    4846             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4847           1 :     fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
    4848           1 :     ai = fib_entry_get_adj(fei);
    4849           1 :     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
    4850           1 :     fib_table_entry_path_add(fib_index,
    4851             :                              &pfx_2001_b_s_64,
    4852             :                              FIB_SOURCE_API,
    4853             :                              FIB_ENTRY_FLAG_NONE,
    4854             :                              DPO_PROTO_IP6,
    4855             :                              &nh_2001_2,
    4856           1 :                              tm->hw[0]->sw_if_index,
    4857             :                              ~0,
    4858             :                              1,
    4859             :                              NULL,
    4860             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4861           1 :     fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
    4862           1 :     ai = fib_entry_get_adj(fei);
    4863           1 :     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
    4864             : 
    4865             :     /*
    4866             :      * +2 entries, +1 shared path-list.
    4867             :      */
    4868           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
    4869             :              fib_path_list_db_size());
    4870           1 :     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
    4871             :              fib_path_list_pool_size());
    4872           1 :     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
    4873             :              fib_entry_pool_size());
    4874             : 
    4875             :     /*
    4876             :      * add a v4 prefix via a v6 next-hop
    4877             :      */
    4878           1 :     fib_prefix_t pfx_1_1_1_1_s_32 = {
    4879             :         .fp_len = 32,
    4880             :         .fp_proto = FIB_PROTOCOL_IP4,
    4881             :         .fp_addr = {
    4882             :             .ip4.as_u32 = 0x01010101,
    4883             :         },
    4884             :     };
    4885           1 :     fei = fib_table_entry_path_add(0, // default table
    4886             :                                    &pfx_1_1_1_1_s_32,
    4887             :                                    FIB_SOURCE_API,
    4888             :                                    FIB_ENTRY_FLAG_NONE,
    4889             :                                    DPO_PROTO_IP6,
    4890             :                                    &nh_2001_2,
    4891           1 :                                    tm->hw[0]->sw_if_index,
    4892             :                                    ~0,
    4893             :                                    1,
    4894             :                                    NULL,
    4895             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    4896           1 :     FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
    4897             :              "1.1.1.1/32 o v6 route present");
    4898           1 :     ai = fib_entry_get_adj(fei);
    4899           1 :     adj = adj_get(ai);
    4900           1 :     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
    4901             :              "1.1.1.1/32 via ARP-adj");
    4902           1 :     FIB_TEST((adj->ia_link == VNET_LINK_IP4),
    4903             :              "1.1.1.1/32 ADJ-adj is link type v4");
    4904           1 :     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
    4905             :              "1.1.1.1/32 ADJ-adj is NH proto v6");
    4906           1 :     fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
    4907             : 
    4908             :     /*
    4909             :      * An attached route
    4910             :      */
    4911           3 :     fib_prefix_t pfx_2001_c_s_64 = {
    4912             :         .fp_len   = 64,
    4913             :         .fp_proto = FIB_PROTOCOL_IP6,
    4914             :         .fp_addr  = {
    4915             :             .ip6 = {
    4916             :                 .as_u64 = {
    4917           1 :                     [0] = clib_host_to_net_u64(0x200100000000000c),
    4918           1 :                     [1] = clib_host_to_net_u64(0x0000000000000000),
    4919             :                 },
    4920             :             },
    4921             :         }
    4922             :     };
    4923           1 :     fib_table_entry_path_add(fib_index,
    4924             :                              &pfx_2001_c_s_64,
    4925             :                              FIB_SOURCE_CLI,
    4926             :                              FIB_ENTRY_FLAG_ATTACHED,
    4927             :                              DPO_PROTO_IP6,
    4928             :                              NULL,
    4929           1 :                              tm->hw[0]->sw_if_index,
    4930             :                              ~0,
    4931             :                              1,
    4932             :                              NULL,
    4933             :                              FIB_ROUTE_PATH_FLAG_NONE);
    4934           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
    4935           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
    4936           1 :     ai = fib_entry_get_adj(fei);
    4937           1 :     adj = adj_get(ai);
    4938           1 :     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
    4939             :              "2001:0:0:c/64 attached resolves via glean");
    4940             : 
    4941           1 :     fib_table_entry_path_remove(fib_index,
    4942             :                                 &pfx_2001_c_s_64,
    4943             :                                 FIB_SOURCE_CLI,
    4944             :                                 DPO_PROTO_IP6,
    4945             :                                 NULL,
    4946           1 :                                 tm->hw[0]->sw_if_index,
    4947             :                                 ~0,
    4948             :                                 1,
    4949             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    4950           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
    4951           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
    4952             : 
    4953             :     /*
    4954             :      * Shutdown the interface on which we have a connected and through
    4955             :      * which the routes are reachable.
    4956             :      * This will result in the connected, adj-fibs, and routes linking to drop
    4957             :      * The local/for-us prefix continues to receive.
    4958             :      */
    4959             :     clib_error_t * error;
    4960             : 
    4961           1 :     error = vnet_sw_interface_set_flags(vnet_get_main(),
    4962           1 :                                         tm->hw[0]->sw_if_index,
    4963             :                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    4964           1 :     FIB_TEST((NULL == error), "Interface shutdown OK");
    4965             : 
    4966           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
    4967           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4968           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    4969             :              "2001::b/64 resolves via drop");
    4970             : 
    4971           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
    4972           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4973           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    4974             :              "2001::a/64 resolves via drop");
    4975           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
    4976           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4977           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    4978             :              "2001:0:0:1::3/64 resolves via drop");
    4979           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
    4980           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4981           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    4982             :              "2001:0:0:1::2/64 resolves via drop");
    4983           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    4984           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4985           1 :     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    4986             :              "2001:0:0:1::1/128 not drop");
    4987           1 :     local_pfx.fp_len = 64;
    4988           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    4989           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    4990           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    4991             :              "2001:0:0:1/64 resolves via drop");
    4992             : 
    4993             :     /*
    4994             :      * no change
    4995             :      */
    4996           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
    4997             :              fib_path_list_db_size());
    4998           1 :     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
    4999             :              fib_path_list_pool_size());
    5000           1 :     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
    5001             :              fib_entry_pool_size());
    5002             : 
    5003             :     /*
    5004             :      * shutdown one of the other interfaces, then add a connected.
    5005             :      * and swap one of the routes to it.
    5006             :      */
    5007           1 :     error = vnet_sw_interface_set_flags(vnet_get_main(),
    5008           1 :                                         tm->hw[1]->sw_if_index,
    5009             :                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    5010           1 :     FIB_TEST((NULL == error), "Interface 1 shutdown OK");
    5011             : 
    5012           3 :     fib_prefix_t connected_pfx = {
    5013             :         .fp_len = 64,
    5014             :         .fp_proto = FIB_PROTOCOL_IP6,
    5015             :         .fp_addr = {
    5016             :             .ip6 = {
    5017             :                 /* 2001:0:0:2::1/64 */
    5018             :                 .as_u64 = {
    5019           1 :                     [0] = clib_host_to_net_u64(0x2001000000000002),
    5020           1 :                     [1] = clib_host_to_net_u64(0x0000000000000001),
    5021             :                 },
    5022             :             },
    5023             :         }
    5024             :     };
    5025           1 :     fib_table_entry_update_one_path(fib_index, &connected_pfx,
    5026             :                                     FIB_SOURCE_INTERFACE,
    5027             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    5028             :                                      FIB_ENTRY_FLAG_ATTACHED),
    5029             :                                     DPO_PROTO_IP6,
    5030             :                                     NULL,
    5031           1 :                                     tm->hw[1]->sw_if_index,
    5032             :                                     ~0,
    5033             :                                     1,
    5034             :                                     NULL,
    5035             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5036           1 :     fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
    5037           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
    5038           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5039           1 :     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
    5040           1 :     FIB_TEST(!dpo_cmp(dpo, dpo_drop),
    5041             :              "2001:0:0:2/64 not resolves via drop");
    5042             : 
    5043           1 :     connected_pfx.fp_len = 128;
    5044           1 :     fib_table_entry_update_one_path(fib_index, &connected_pfx,
    5045             :                                     FIB_SOURCE_INTERFACE,
    5046             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    5047             :                                      FIB_ENTRY_FLAG_LOCAL),
    5048             :                                     DPO_PROTO_IP6,
    5049             :                                     NULL,
    5050           1 :                                     tm->hw[0]->sw_if_index,
    5051             :                                     ~0, // invalid fib index
    5052             :                                     1,
    5053             :                                     NULL,
    5054             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5055           1 :     fei = fib_table_lookup(fib_index, &connected_pfx);
    5056             : 
    5057           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
    5058           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5059           1 :     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
    5060           1 :     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
    5061             :              "local interface adj is local");
    5062           1 :     rd = receive_dpo_get(dpo->dpoi_index);
    5063           1 :     FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
    5064             :                                     &rd->rd_addr)),
    5065             :              "local interface adj is receive ok");
    5066             : 
    5067             :     /*
    5068             :      * +2 entries, +2 unshared path-lists
    5069             :      */
    5070           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
    5071             :              fib_path_list_db_size());
    5072           1 :     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
    5073             :              fib_path_list_pool_size());
    5074           1 :     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
    5075             :              fib_entry_pool_size());
    5076             : 
    5077             : 
    5078             :     /*
    5079             :      * bring the interface back up. we expected the routes to return
    5080             :      * to normal forwarding.
    5081             :      */
    5082           1 :     error = vnet_sw_interface_set_flags(vnet_get_main(),
    5083           1 :                                         tm->hw[0]->sw_if_index,
    5084             :                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    5085           1 :     FIB_TEST((NULL == error), "Interface bring-up OK");
    5086           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
    5087           1 :     ai = fib_entry_get_adj(fei);
    5088           1 :     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
    5089           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
    5090           1 :     ai = fib_entry_get_adj(fei);
    5091           1 :     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
    5092           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
    5093           1 :     ai = fib_entry_get_adj(fei);
    5094           1 :     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
    5095           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
    5096           1 :     ai = fib_entry_get_adj(fei);
    5097           1 :     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
    5098           1 :     local_pfx.fp_len = 64;
    5099           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5100           1 :     ai = fib_entry_get_adj(fei);
    5101           1 :     adj = adj_get(ai);
    5102           1 :     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
    5103             :              "attached interface adj is glean");
    5104             : 
    5105             :     /*
    5106             :      * Same test as above, but this time the HW interface goes down
    5107             :      */
    5108           1 :     error = vnet_hw_interface_set_flags(vnet_get_main(),
    5109             :                                         tm->hw_if_indicies[0],
    5110             :                                         ~VNET_HW_INTERFACE_FLAG_LINK_UP);
    5111           1 :     FIB_TEST((NULL == error), "Interface shutdown OK");
    5112             : 
    5113           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
    5114           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5115           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5116             :              "2001::b/64 resolves via drop");
    5117           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
    5118           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5119           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5120             :              "2001::a/64 resolves via drop");
    5121           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
    5122           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5123           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5124             :              "2001:0:0:1::3/128 resolves via drop");
    5125           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
    5126           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5127           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5128             :              "2001:0:0:1::2/128 resolves via drop");
    5129           1 :     local_pfx.fp_len = 128;
    5130           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5131           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5132           1 :     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5133             :              "2001:0:0:1::1/128 not drop");
    5134           1 :     local_pfx.fp_len = 64;
    5135           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5136           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5137           1 :     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5138             :              "2001:0:0:1/64 resolves via drop");
    5139             : 
    5140           1 :     error = vnet_hw_interface_set_flags(vnet_get_main(),
    5141             :                                         tm->hw_if_indicies[0],
    5142             :                                         VNET_HW_INTERFACE_FLAG_LINK_UP);
    5143           1 :     FIB_TEST((NULL == error), "Interface bring-up OK");
    5144           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
    5145           1 :     ai = fib_entry_get_adj(fei);
    5146           1 :     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
    5147           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
    5148           1 :     ai = fib_entry_get_adj(fei);
    5149           1 :     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
    5150           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
    5151           1 :     ai = fib_entry_get_adj(fei);
    5152           1 :     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
    5153           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
    5154           1 :     ai = fib_entry_get_adj(fei);
    5155           1 :     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
    5156           1 :     local_pfx.fp_len = 64;
    5157           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5158           1 :     ai = fib_entry_get_adj(fei);
    5159           1 :     adj = adj_get(ai);
    5160           1 :     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
    5161             :              "attached interface adj is glean");
    5162             : 
    5163             :     /*
    5164             :      * Delete the interface that the routes reolve through.
    5165             :      * Again no routes are removed. They all point to drop.
    5166             :      *
    5167             :      * This is considered an error case. The control plane should
    5168             :      * not remove interfaces through which routes resolve, but
    5169             :      * such things can happen. ALL affected routes will drop.
    5170             :      */
    5171           1 :     vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
    5172             : 
    5173           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
    5174           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5175             :              "2001::b/64 resolves via drop");
    5176           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
    5177           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5178             :              "2001::b/64 resolves via drop");
    5179           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
    5180           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5181             :              "2001:0:0:1::3/64 resolves via drop");
    5182           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
    5183           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5184             :              "2001:0:0:1::2/64 resolves via drop");
    5185           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5186           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5187             :              "2001:0:0:1::1/128 is drop");
    5188           1 :     local_pfx.fp_len = 64;
    5189           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5190           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5191             :              "2001:0:0:1/64 resolves via drop");
    5192             : 
    5193             :     /*
    5194             :      * no change
    5195             :      */
    5196           1 :     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
    5197             :              fib_path_list_db_size());
    5198           1 :     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
    5199             :              fib_path_list_pool_size());
    5200           1 :     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
    5201             :              fib_entry_pool_size());
    5202             : 
    5203             :     /*
    5204             :      * Add the interface back. routes stay unresolved.
    5205             :      */
    5206           1 :     vnet_eth_interface_registration_t eir = {};
    5207           1 :     eir.dev_class_index = test_interface_device_class.index;
    5208           1 :     eir.dev_instance = 0;
    5209           1 :     eir.address = hw_address;
    5210           1 :     tm->hw_if_indicies[0] = vnet_eth_register_interface (vnet_get_main(), &eir);
    5211             : 
    5212           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
    5213           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5214             :              "2001::b/64 resolves via drop");
    5215           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
    5216           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5217             :              "2001::b/64 resolves via drop");
    5218           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
    5219           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5220             :              "2001:0:0:1::3/64 resolves via drop");
    5221           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
    5222           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5223             :              "2001:0:0:1::2/64 resolves via drop");
    5224           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5225           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5226             :              "2001:0:0:1::1/128 is drop");
    5227           1 :     local_pfx.fp_len = 64;
    5228           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5229           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    5230             :              "2001:0:0:1/64 resolves via drop");
    5231             : 
    5232             :     /*
    5233             :      * CLEANUP ALL the routes
    5234             :      */
    5235           1 :     fib_table_entry_delete(fib_index,
    5236             :                            &pfx_2001_c_s_64,
    5237             :                            FIB_SOURCE_API);
    5238           1 :     fib_table_entry_delete(fib_index,
    5239             :                            &pfx_2001_a_s_64,
    5240             :                            FIB_SOURCE_API);
    5241           1 :     fib_table_entry_delete(fib_index,
    5242             :                            &pfx_2001_b_s_64,
    5243             :                            FIB_SOURCE_API);
    5244           1 :     fib_table_entry_delete(fib_index,
    5245             :                            &pfx_2001_1_3_s_128,
    5246             :                            FIB_SOURCE_ADJ);
    5247           1 :     fib_table_entry_delete(fib_index,
    5248             :                            &pfx_2001_1_2_s_128,
    5249             :                            FIB_SOURCE_ADJ);
    5250           1 :     local_pfx.fp_len = 64;
    5251           1 :     fib_table_entry_delete(fib_index, &local_pfx,
    5252             :                            FIB_SOURCE_INTERFACE);
    5253           1 :     local_pfx.fp_len = 128;
    5254           1 :     fib_table_entry_special_remove(fib_index, &local_pfx,
    5255             :                                    FIB_SOURCE_INTERFACE);
    5256           1 :     connected_pfx.fp_len = 64;
    5257           1 :     fib_table_entry_delete(fib_index, &connected_pfx,
    5258             :                            FIB_SOURCE_INTERFACE);
    5259           1 :     connected_pfx.fp_len = 128;
    5260           1 :     fib_table_entry_special_remove(fib_index, &connected_pfx,
    5261             :                                    FIB_SOURCE_INTERFACE);
    5262             : 
    5263           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    5264             :               fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
    5265             :              "2001::a/64 removed");
    5266           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    5267             :               fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
    5268             :              "2001::b/64 removed");
    5269           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    5270             :               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
    5271             :              "2001:0:0:1::3/128 removed");
    5272           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    5273             :               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
    5274             :              "2001:0:0:1::3/128 removed");
    5275           1 :     local_pfx.fp_len = 64;
    5276           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    5277             :               fib_table_lookup_exact_match(fib_index, &local_pfx)),
    5278             :              "2001:0:0:1/64 removed");
    5279           1 :     local_pfx.fp_len = 128;
    5280           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    5281             :               fib_table_lookup_exact_match(fib_index, &local_pfx)),
    5282             :              "2001:0:0:1::1/128 removed");
    5283           1 :     connected_pfx.fp_len = 64;
    5284           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    5285             :               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
    5286             :              "2001:0:0:2/64 removed");
    5287           1 :     connected_pfx.fp_len = 128;
    5288           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    5289             :               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
    5290             :              "2001:0:0:2::1/128 removed");
    5291             : 
    5292             :     /*
    5293             :      * -8 entries. -7 path-lists (1 was shared).
    5294             :      */
    5295           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
    5296             :              fib_path_list_db_size());
    5297           1 :     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
    5298             :              fib_path_list_pool_size());
    5299           1 :     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
    5300             :              fib_entry_pool_size());
    5301             : 
    5302             :     /*
    5303             :      * now remove the VRF
    5304             :      */
    5305             : 
    5306           5 :     for (ii = 0; ii < 4; ii++)
    5307           4 :       fib_table_bind (FIB_PROTOCOL_IP6, tm->hw[ii]->sw_if_index, 0);
    5308             : 
    5309           1 :     fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
    5310             : 
    5311           1 :     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
    5312             :              fib_path_list_db_size());
    5313           1 :     FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
    5314             :              fib_path_list_pool_size());
    5315           1 :     FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
    5316             :              fib_entry_pool_size());
    5317             : 
    5318           1 :     adj_unlock(ai_02);
    5319           1 :     adj_unlock(ai_01);
    5320             : 
    5321             :     /*
    5322             :      * return the interfaces to up state
    5323             :      */
    5324           1 :     error = vnet_sw_interface_set_flags(vnet_get_main(),
    5325           1 :                                         tm->hw[0]->sw_if_index,
    5326             :                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    5327           1 :     error = vnet_sw_interface_set_flags(vnet_get_main(),
    5328           1 :                                         tm->hw[1]->sw_if_index,
    5329             :                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    5330             : 
    5331           1 :     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
    5332             :              adj_nbr_db_size());
    5333           1 :     FIB_TEST((0 == adj_glean_db_size()), "ADJ DB size is %d",
    5334             :              adj_glean_db_size());
    5335             : 
    5336           1 :     return (res);
    5337             : }
    5338             : 
    5339             : /*
    5340             :  * Test Attached Exports
    5341             :  */
    5342             : static int
    5343           1 : fib_test_ae (void)
    5344             : {
    5345             :     const dpo_id_t *dpo, *dpo_drop;
    5346           1 :     const u32 fib_index = 0;
    5347             :     fib_node_index_t dfrt, fei;
    5348             :     test_main_t *tm;
    5349             :     int res;
    5350             : 
    5351           1 :     res = 0;
    5352           1 :     tm = &test_main;
    5353             : 
    5354           1 :     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
    5355             :              adj_nbr_db_size());
    5356             : 
    5357             :     /*
    5358             :      * add interface routes. We'll assume this works. It's more rigorously
    5359             :      * tested elsewhere.
    5360             :      */
    5361           2 :     fib_prefix_t local_pfx = {
    5362             :         .fp_len = 24,
    5363             :         .fp_proto = FIB_PROTOCOL_IP4,
    5364             :         .fp_addr = {
    5365             :             .ip4 = {
    5366             :                 /* 10.10.10.10 */
    5367           1 :                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
    5368             :             },
    5369             :         },
    5370             :     };
    5371             : 
    5372           1 :     fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[0]->sw_if_index, fib_index);
    5373             : 
    5374           1 :     dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
    5375             : 
    5376           1 :     fib_table_entry_update_one_path(fib_index, &local_pfx,
    5377             :                                     FIB_SOURCE_INTERFACE,
    5378             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    5379             :                                      FIB_ENTRY_FLAG_ATTACHED),
    5380             :                                     DPO_PROTO_IP4,
    5381             :                                     NULL,
    5382           1 :                                     tm->hw[0]->sw_if_index,
    5383             :                                     ~0,
    5384             :                                     1,
    5385             :                                     NULL,
    5386             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5387           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5388           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
    5389             :              "attached interface route present");
    5390             : 
    5391           1 :     local_pfx.fp_len = 32;
    5392           1 :     fib_table_entry_update_one_path(fib_index, &local_pfx,
    5393             :                                     FIB_SOURCE_INTERFACE,
    5394             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    5395             :                                      FIB_ENTRY_FLAG_LOCAL),
    5396             :                                     DPO_PROTO_IP4,
    5397             :                                     NULL,
    5398           1 :                                     tm->hw[0]->sw_if_index,
    5399             :                                     ~0, // invalid fib index
    5400             :                                     1,
    5401             :                                     NULL,
    5402             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5403           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5404             : 
    5405           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
    5406             :              "local interface route present");
    5407             : 
    5408             :     /*
    5409             :      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
    5410             :      */
    5411           2 :     fib_prefix_t pfx_10_10_10_1_s_32 = {
    5412             :         .fp_len = 32,
    5413             :         .fp_proto = FIB_PROTOCOL_IP4,
    5414             :         .fp_addr = {
    5415             :             /* 10.10.10.1 */
    5416           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
    5417             :         },
    5418             :     };
    5419             :     fib_node_index_t ai;
    5420             : 
    5421           1 :     fib_table_entry_path_add(fib_index,
    5422             :                              &pfx_10_10_10_1_s_32,
    5423             :                              FIB_SOURCE_ADJ,
    5424             :                              FIB_ENTRY_FLAG_ATTACHED,
    5425             :                              DPO_PROTO_IP4,
    5426             :                              &pfx_10_10_10_1_s_32.fp_addr,
    5427           1 :                              tm->hw[0]->sw_if_index,
    5428             :                              ~0, // invalid fib index
    5429             :                              1,
    5430             :                              NULL,
    5431             :                              FIB_ROUTE_PATH_FLAG_NONE);
    5432             : 
    5433           1 :     fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
    5434           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
    5435           1 :     ai = fib_entry_get_adj(fei);
    5436             : 
    5437             :     /*
    5438             :      * create another FIB table into which routes will be imported
    5439             :      */
    5440             :     u32 import_fib_index1;
    5441             : 
    5442           1 :     import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
    5443             :                                                           11,
    5444             :                                                           FIB_SOURCE_CLI);
    5445             :     /*
    5446             :      * Add default route in the import FIB
    5447             :      */
    5448           1 :     fib_prefix_t pfx_0_0_0_0_s_0 = {
    5449             :         .fp_len = 0,
    5450             :         .fp_proto = FIB_PROTOCOL_IP4,
    5451             :         .fp_addr = {
    5452             :             .ip4 = {
    5453             :                 {0}
    5454             :             },
    5455             :         },
    5456             :     };
    5457             : 
    5458           1 :     dfrt = fib_table_lookup(import_fib_index1, &pfx_0_0_0_0_s_0);
    5459           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
    5460             : 
    5461           1 :     fib_table_entry_path_add(import_fib_index1,
    5462             :                              &pfx_0_0_0_0_s_0,
    5463             :                              FIB_SOURCE_API,
    5464             :                              FIB_ENTRY_FLAG_NONE,
    5465             :                              DPO_PROTO_IP4,
    5466             :                              NULL,
    5467           1 :                              tm->hw[0]->sw_if_index,
    5468             :                              ~0, // invalid fib index
    5469             :                              1,
    5470             :                              NULL,
    5471             :                              FIB_ROUTE_PATH_FLAG_NONE);
    5472           1 :     fei = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
    5473           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "default route present");
    5474           1 :     FIB_TEST((fei != dfrt), "default route added");
    5475             : 
    5476             :     /*
    5477             :      * delete default route and check for the presence in the import table
    5478             :      */
    5479           1 :     fib_table_entry_delete(import_fib_index1, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
    5480           1 :     fei = fib_table_lookup(import_fib_index1, &pfx_0_0_0_0_s_0);
    5481           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "default route present");
    5482           1 :     FIB_TEST((fei == dfrt), "default route removed");
    5483             : 
    5484             :     /*
    5485             :      * Add an attached route in the import FIB
    5486             :      */
    5487           1 :     local_pfx.fp_len = 24;
    5488           1 :     fib_table_entry_update_one_path(import_fib_index1,
    5489             :                                     &local_pfx,
    5490             :                                     FIB_SOURCE_API,
    5491             :                                     FIB_ENTRY_FLAG_NONE,
    5492             :                                     DPO_PROTO_IP4,
    5493             :                                     NULL,
    5494           1 :                                     tm->hw[0]->sw_if_index,
    5495             :                                     ~0, // invalid fib index
    5496             :                                     1,
    5497             :                                     NULL,
    5498             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5499           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5500           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
    5501             : 
    5502             :     /*
    5503             :      * check for the presence of the adj-fibs in the import table
    5504             :      */
    5505           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5506           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
    5507           1 :     FIB_TEST((ai == fib_entry_get_adj(fei)),
    5508             :              "adj-fib1 Import uses same adj as export");
    5509             : 
    5510             :     /*
    5511             :      * check for the presence of the local in the import table
    5512             :      */
    5513           1 :     local_pfx.fp_len = 32;
    5514           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5515           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
    5516             : 
    5517             :     /*
    5518             :      * Add another adj-fin in the export table. Expect this
    5519             :      * to get magically exported;
    5520             :      */
    5521           2 :     fib_prefix_t pfx_10_10_10_2_s_32 = {
    5522             :         .fp_len = 32,
    5523             :         .fp_proto = FIB_PROTOCOL_IP4,
    5524             :         .fp_addr = {
    5525             :             /* 10.10.10.2 */
    5526           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
    5527             :         },
    5528             :     };
    5529             : 
    5530           1 :     fib_table_entry_path_add(fib_index,
    5531             :                              &pfx_10_10_10_2_s_32,
    5532             :                              FIB_SOURCE_ADJ,
    5533             :                              FIB_ENTRY_FLAG_ATTACHED,
    5534             :                              DPO_PROTO_IP4,
    5535             :                              &pfx_10_10_10_2_s_32.fp_addr,
    5536           1 :                              tm->hw[0]->sw_if_index,
    5537             :                              ~0, // invalid fib index
    5538             :                              1,
    5539             :                              NULL,
    5540             :                              FIB_ROUTE_PATH_FLAG_NONE);
    5541           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
    5542           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
    5543           1 :     ai = fib_entry_get_adj(fei);
    5544             : 
    5545           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
    5546           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
    5547           1 :     FIB_TEST((ai == fib_entry_get_adj(fei)),
    5548             :              "Import uses same adj as export");
    5549           1 :     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
    5550             :              "ADJ-fib2 imported flags %d",
    5551             :              fib_entry_get_flags(fei));
    5552             : 
    5553             :     /*
    5554             :      * create a 2nd FIB table into which routes will be imported
    5555             :      */
    5556             :     u32 import_fib_index2;
    5557             : 
    5558           1 :     import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
    5559             :                                                           FIB_SOURCE_CLI);
    5560             : 
    5561             :     /*
    5562             :      * Add an attached route in the import FIB
    5563             :      */
    5564           1 :     local_pfx.fp_len = 24;
    5565           1 :     fib_table_entry_update_one_path(import_fib_index2,
    5566             :                                     &local_pfx,
    5567             :                                     FIB_SOURCE_API,
    5568             :                                     FIB_ENTRY_FLAG_NONE,
    5569             :                                     DPO_PROTO_IP4,
    5570             :                                     NULL,
    5571           1 :                                     tm->hw[0]->sw_if_index,
    5572             :                                     ~0, // invalid fib index
    5573             :                                     1,
    5574             :                                     NULL,
    5575             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5576           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5577           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
    5578             : 
    5579             :     /*
    5580             :      * check for the presence of all the adj-fibs and local in the import table
    5581             :      */
    5582           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
    5583           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
    5584           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
    5585           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
    5586           1 :     local_pfx.fp_len = 32;
    5587           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
    5588           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
    5589             : 
    5590             :     /*
    5591             :      * add a 3rd adj-fib. expect it to be exported to both tables.
    5592             :      */
    5593           2 :     fib_prefix_t pfx_10_10_10_3_s_32 = {
    5594             :         .fp_len = 32,
    5595             :         .fp_proto = FIB_PROTOCOL_IP4,
    5596             :         .fp_addr = {
    5597             :             /* 10.10.10.3 */
    5598           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
    5599             :         },
    5600             :     };
    5601             : 
    5602           1 :     fib_table_entry_path_add(fib_index,
    5603             :                              &pfx_10_10_10_3_s_32,
    5604             :                              FIB_SOURCE_ADJ,
    5605             :                              FIB_ENTRY_FLAG_ATTACHED,
    5606             :                              DPO_PROTO_IP4,
    5607             :                              &pfx_10_10_10_3_s_32.fp_addr,
    5608           1 :                              tm->hw[0]->sw_if_index,
    5609             :                              ~0, // invalid fib index
    5610             :                              1,
    5611             :                              NULL,
    5612             :                              FIB_ROUTE_PATH_FLAG_NONE);
    5613           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
    5614           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
    5615           1 :     ai = fib_entry_get_adj(fei);
    5616             : 
    5617           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
    5618           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
    5619           1 :     FIB_TEST((ai == fib_entry_get_adj(fei)),
    5620             :              "Import uses same adj as export");
    5621           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
    5622           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
    5623           1 :     FIB_TEST((ai == fib_entry_get_adj(fei)),
    5624             :              "Import uses same adj as export");
    5625             : 
    5626             :     /*
    5627             :      * remove the 3rd adj fib. we expect it to be removed from both FIBs
    5628             :      */
    5629           1 :     fib_table_entry_delete(fib_index,
    5630             :                            &pfx_10_10_10_3_s_32,
    5631             :                            FIB_SOURCE_ADJ);
    5632             : 
    5633           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
    5634           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
    5635             : 
    5636           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
    5637           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
    5638             : 
    5639           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
    5640           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
    5641             : 
    5642             :     /*
    5643             :      * remove the attached route from the 2nd FIB. expect the imported
    5644             :      * entries to be removed
    5645             :      */
    5646           1 :     local_pfx.fp_len = 24;
    5647           1 :     fib_table_entry_delete(import_fib_index2,
    5648             :                            &local_pfx,
    5649             :                            FIB_SOURCE_API);
    5650           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
    5651           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
    5652             : 
    5653           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
    5654           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
    5655           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
    5656           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
    5657           1 :     local_pfx.fp_len = 32;
    5658           1 :     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
    5659           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
    5660             : 
    5661           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5662           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
    5663           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
    5664           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
    5665           1 :     local_pfx.fp_len = 32;
    5666           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5667           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
    5668             : 
    5669             :     /*
    5670             :      * modify the route in FIB1 so it is no longer attached. expect the imported
    5671             :      * entries to be removed
    5672             :      */
    5673           1 :     local_pfx.fp_len = 24;
    5674           1 :     fib_table_entry_update_one_path(import_fib_index1,
    5675             :                                     &local_pfx,
    5676             :                                     FIB_SOURCE_API,
    5677             :                                     FIB_ENTRY_FLAG_NONE,
    5678             :                                     DPO_PROTO_IP4,
    5679             :                                     &pfx_10_10_10_2_s_32.fp_addr,
    5680           1 :                                     tm->hw[0]->sw_if_index,
    5681             :                                     ~0, // invalid fib index
    5682             :                                     1,
    5683             :                                     NULL,
    5684             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5685           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5686           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
    5687           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
    5688           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
    5689           1 :     local_pfx.fp_len = 32;
    5690           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5691           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
    5692             : 
    5693             :     /*
    5694             :      * modify it back to attached. expect the adj-fibs back
    5695             :      */
    5696           1 :     local_pfx.fp_len = 24;
    5697           1 :     fib_table_entry_update_one_path(import_fib_index1,
    5698             :                                     &local_pfx,
    5699             :                                     FIB_SOURCE_API,
    5700             :                                     FIB_ENTRY_FLAG_NONE,
    5701             :                                     DPO_PROTO_IP4,
    5702             :                                     NULL,
    5703           1 :                                     tm->hw[0]->sw_if_index,
    5704             :                                     ~0, // invalid fib index
    5705             :                                     1,
    5706             :                                     NULL,
    5707             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5708           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5709           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
    5710           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
    5711           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
    5712           1 :     local_pfx.fp_len = 32;
    5713           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5714           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
    5715             : 
    5716             :     /*
    5717             :      * add a covering attached next-hop for the interface address, so we have
    5718             :      * a valid adj to find when we check the forwarding tables
    5719             :      */
    5720           2 :     fib_prefix_t pfx_10_0_0_0_s_8 = {
    5721             :         .fp_len = 8,
    5722             :         .fp_proto = FIB_PROTOCOL_IP4,
    5723             :         .fp_addr = {
    5724             :             /* 10.0.0.0 */
    5725           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
    5726             :         },
    5727             :     };
    5728             : 
    5729           1 :     fei = fib_table_entry_update_one_path(fib_index,
    5730             :                                           &pfx_10_0_0_0_s_8,
    5731             :                                           FIB_SOURCE_API,
    5732             :                                           FIB_ENTRY_FLAG_NONE,
    5733             :                                           DPO_PROTO_IP4,
    5734             :                                           &pfx_10_10_10_3_s_32.fp_addr,
    5735           1 :                                           tm->hw[0]->sw_if_index,
    5736             :                                           ~0, // invalid fib index
    5737             :                                           1,
    5738             :                                           NULL,
    5739             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    5740           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5741             : 
    5742             :     /*
    5743             :      * remove the route in the export fib. expect the adj-fibs to be removed
    5744             :      */
    5745           1 :     local_pfx.fp_len = 24;
    5746           1 :     fib_table_entry_delete(fib_index,
    5747             :                            &local_pfx,
    5748             :                            FIB_SOURCE_INTERFACE);
    5749             : 
    5750           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5751           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
    5752           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
    5753           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
    5754           1 :     local_pfx.fp_len = 32;
    5755           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5756           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
    5757             : 
    5758             :     /*
    5759             :      * the adj-fibs in the export VRF are present in the FIB table,
    5760             :      * but not installed in forwarding, since they have no attached cover.
    5761             :      * Consequently a lookup in the MTRIE gives the adj for the covering
    5762             :      * route 10.0.0.0/8.
    5763             :      */
    5764           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
    5765           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
    5766             : 
    5767             :     index_t lbi;
    5768           1 :     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
    5769           1 :     FIB_TEST(lbi == dpo->dpoi_index,
    5770             :              "10.10.10.1 forwards on \n%U not \n%U",
    5771             :              format_load_balance, lbi, 0,
    5772             :              format_dpo_id, dpo, 0);
    5773           1 :     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
    5774           1 :     FIB_TEST(lbi == dpo->dpoi_index,
    5775             :              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
    5776           1 :     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
    5777           1 :     FIB_TEST(lbi == dpo->dpoi_index,
    5778             :              "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
    5779             : 
    5780             :     /*
    5781             :      * add the export prefix back, but not as attached.
    5782             :      * No adj-fibs in export nor import tables
    5783             :      */
    5784           1 :     local_pfx.fp_len = 24;
    5785           1 :     fei = fib_table_entry_update_one_path(fib_index,
    5786             :                                           &local_pfx,
    5787             :                                           FIB_SOURCE_API,
    5788             :                                           FIB_ENTRY_FLAG_NONE,
    5789             :                                           DPO_PROTO_IP4,
    5790             :                                           &pfx_10_10_10_1_s_32.fp_addr,
    5791           1 :                                           tm->hw[0]->sw_if_index,
    5792             :                                           ~0, // invalid fib index
    5793             :                                           1,
    5794             :                                           NULL,
    5795             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    5796           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5797             : 
    5798           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
    5799           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
    5800           1 :     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
    5801           1 :     FIB_TEST(lbi == dpo->dpoi_index,
    5802             :              "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
    5803           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
    5804           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
    5805           1 :     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
    5806           1 :     FIB_TEST(lbi == dpo->dpoi_index,
    5807             :              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
    5808             : 
    5809           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5810           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
    5811           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
    5812           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
    5813           1 :     local_pfx.fp_len = 32;
    5814           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5815           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
    5816             : 
    5817             :     /*
    5818             :      * modify the export prefix so it is attached. expect all covereds to return
    5819             :      */
    5820           1 :     local_pfx.fp_len = 24;
    5821           1 :     fib_table_entry_update_one_path(fib_index,
    5822             :                                     &local_pfx,
    5823             :                                     FIB_SOURCE_API,
    5824             :                                     FIB_ENTRY_FLAG_NONE,
    5825             :                                     DPO_PROTO_IP4,
    5826             :                                     NULL,
    5827           1 :                                     tm->hw[0]->sw_if_index,
    5828             :                                     ~0, // invalid fib index
    5829             :                                     1,
    5830             :                                     NULL,
    5831             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5832             : 
    5833           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
    5834           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
    5835           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5836           1 :     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5837             :              "Adj-fib1 is not drop in export");
    5838           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
    5839           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
    5840           1 :     local_pfx.fp_len = 32;
    5841           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5842           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
    5843           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5844           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
    5845           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5846           1 :     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5847             :              "Adj-fib1 is not drop in export: %U %U",
    5848             :              format_dpo_id, dpo, 0,
    5849             :              format_dpo_id, load_balance_get_bucket(dpo->dpoi_index, 0), 0);
    5850           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5851           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
    5852           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
    5853           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
    5854           1 :     local_pfx.fp_len = 32;
    5855           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5856           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
    5857             : 
    5858             :     /*
    5859             :      * modify the export prefix so connected. no change.
    5860             :      */
    5861           1 :     local_pfx.fp_len = 24;
    5862           1 :     fib_table_entry_update_one_path(fib_index, &local_pfx,
    5863             :                                     FIB_SOURCE_INTERFACE,
    5864             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    5865             :                                      FIB_ENTRY_FLAG_ATTACHED),
    5866             :                                     DPO_PROTO_IP4,
    5867             :                                     NULL,
    5868           1 :                                     tm->hw[0]->sw_if_index,
    5869             :                                     ~0,
    5870             :                                     1,
    5871             :                                     NULL,
    5872             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    5873             : 
    5874           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
    5875           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
    5876           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5877           1 :     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5878             :              "Adj-fib1 is not drop in export");
    5879           1 :     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
    5880           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
    5881           1 :     local_pfx.fp_len = 32;
    5882           1 :     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
    5883           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
    5884           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
    5885           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
    5886           1 :     dpo = fib_entry_contribute_ip_forwarding(fei);
    5887           1 :     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
    5888             :              "Adj-fib1 is not drop in export");
    5889           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
    5890           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
    5891           1 :     local_pfx.fp_len = 32;
    5892           1 :     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
    5893           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
    5894             : 
    5895             :     /*
    5896             :      * CLEANUP
    5897             :      */
    5898           1 :     fib_table_entry_delete(fib_index,
    5899             :                            &pfx_10_0_0_0_s_8,
    5900             :                            FIB_SOURCE_API);
    5901           1 :     fib_table_entry_delete(fib_index,
    5902             :                            &pfx_10_10_10_1_s_32,
    5903             :                            FIB_SOURCE_ADJ);
    5904           1 :     fib_table_entry_delete(fib_index,
    5905             :                            &pfx_10_10_10_2_s_32,
    5906             :                            FIB_SOURCE_ADJ);
    5907           1 :     local_pfx.fp_len = 32;
    5908           1 :     fib_table_entry_delete(fib_index,
    5909             :                            &local_pfx,
    5910             :                            FIB_SOURCE_INTERFACE);
    5911           1 :     local_pfx.fp_len = 24;
    5912           1 :     fib_table_entry_delete(fib_index,
    5913             :                            &local_pfx,
    5914             :                            FIB_SOURCE_API);
    5915           1 :     fib_table_entry_delete(fib_index,
    5916             :                            &local_pfx,
    5917             :                            FIB_SOURCE_INTERFACE);
    5918           1 :     local_pfx.fp_len = 24;
    5919           1 :     fib_table_entry_delete(import_fib_index1,
    5920             :                            &local_pfx,
    5921             :                            FIB_SOURCE_API);
    5922             : 
    5923           1 :     fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
    5924           1 :     fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
    5925             : 
    5926           1 :     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
    5927             :              adj_nbr_db_size());
    5928             : 
    5929           1 :     return (res);
    5930             : }
    5931             : 
    5932             : /*
    5933             :  * Test Path Preference
    5934             :  */
    5935             : static int
    5936           1 : fib_test_pref (void)
    5937             : {
    5938             :     test_main_t *tm;
    5939             :     int res, i;
    5940             : 
    5941           1 :     tm = &test_main;
    5942           1 :     res = 0;
    5943             : 
    5944           2 :     const fib_prefix_t pfx_1_1_1_1_s_32 = {
    5945             :         .fp_len = 32,
    5946             :         .fp_proto = FIB_PROTOCOL_IP4,
    5947             :         .fp_addr = {
    5948             :             .ip4 = {
    5949           1 :                 .as_u32 = clib_host_to_net_u32(0x01010101),
    5950             :             },
    5951             :         },
    5952             :     };
    5953             : 
    5954           4 :     for (i = 0; i <= 2; i++)
    5955           3 :       fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[i]->sw_if_index, 0);
    5956             : 
    5957             :     /*
    5958             :      * 2 high, 2 medium and 2 low preference non-recursive paths
    5959             :      */
    5960           2 :     fib_route_path_t nr_path_hi_1 = {
    5961             :         .frp_proto = DPO_PROTO_IP4,
    5962           1 :         .frp_sw_if_index = tm->hw[0]->sw_if_index,
    5963             :         .frp_fib_index = ~0,
    5964             :         .frp_weight = 1,
    5965             :         .frp_preference = 0,
    5966             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
    5967             :         .frp_addr = {
    5968           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
    5969             :         },
    5970             :     };
    5971           2 :     fib_route_path_t nr_path_hi_2 = {
    5972             :         .frp_proto = DPO_PROTO_IP4,
    5973           1 :         .frp_sw_if_index = tm->hw[0]->sw_if_index,
    5974             :         .frp_fib_index = ~0,
    5975             :         .frp_weight = 1,
    5976             :         .frp_preference = 0,
    5977             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
    5978             :         .frp_addr = {
    5979           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
    5980             :         },
    5981             :     };
    5982           2 :     fib_route_path_t nr_path_med_1 = {
    5983             :         .frp_proto = DPO_PROTO_IP4,
    5984           1 :         .frp_sw_if_index = tm->hw[1]->sw_if_index,
    5985             :         .frp_fib_index = ~0,
    5986             :         .frp_weight = 1,
    5987             :         .frp_preference = 1,
    5988             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
    5989             :         .frp_addr = {
    5990           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
    5991             :         },
    5992             :     };
    5993           2 :     fib_route_path_t nr_path_med_2 = {
    5994             :         .frp_proto = DPO_PROTO_IP4,
    5995           1 :         .frp_sw_if_index = tm->hw[1]->sw_if_index,
    5996             :         .frp_fib_index = ~0,
    5997             :         .frp_weight = 1,
    5998             :         .frp_preference = 1,
    5999             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
    6000             :         .frp_addr = {
    6001           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
    6002             :         },
    6003             :     };
    6004           2 :     fib_route_path_t nr_path_low_1 = {
    6005             :         .frp_proto = DPO_PROTO_IP4,
    6006           1 :         .frp_sw_if_index = tm->hw[2]->sw_if_index,
    6007             :         .frp_fib_index = ~0,
    6008             :         .frp_weight = 1,
    6009             :         .frp_preference = 2,
    6010             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
    6011             :         .frp_addr = {
    6012           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
    6013             :         },
    6014             :     };
    6015           2 :     fib_route_path_t nr_path_low_2 = {
    6016             :         .frp_proto = DPO_PROTO_IP4,
    6017           1 :         .frp_sw_if_index = tm->hw[2]->sw_if_index,
    6018             :         .frp_fib_index = ~0,
    6019             :         .frp_weight = 1,
    6020             :         .frp_preference = 2,
    6021             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
    6022             :         .frp_addr = {
    6023           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
    6024             :         },
    6025             :     };
    6026           1 :     fib_route_path_t *nr_paths = NULL;
    6027             : 
    6028           1 :     vec_add1(nr_paths, nr_path_hi_1);
    6029           1 :     vec_add1(nr_paths, nr_path_hi_2);
    6030           1 :     vec_add1(nr_paths, nr_path_med_1);
    6031           1 :     vec_add1(nr_paths, nr_path_med_2);
    6032           1 :     vec_add1(nr_paths, nr_path_low_1);
    6033           1 :     vec_add1(nr_paths, nr_path_low_2);
    6034             : 
    6035           1 :     adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6036             :                                               VNET_LINK_IP4,
    6037             :                                               &nr_path_hi_1.frp_addr,
    6038             :                                               nr_path_hi_1.frp_sw_if_index);
    6039           1 :     adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6040             :                                               VNET_LINK_IP4,
    6041             :                                               &nr_path_hi_2.frp_addr,
    6042             :                                               nr_path_hi_2.frp_sw_if_index);
    6043           1 :     adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6044             :                                                VNET_LINK_IP4,
    6045             :                                                &nr_path_med_1.frp_addr,
    6046             :                                                nr_path_med_1.frp_sw_if_index);
    6047           1 :     adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6048             :                                                VNET_LINK_IP4,
    6049             :                                                &nr_path_med_2.frp_addr,
    6050             :                                                nr_path_med_2.frp_sw_if_index);
    6051           1 :     adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6052             :                                                VNET_LINK_IP4,
    6053             :                                                &nr_path_low_1.frp_addr,
    6054             :                                                nr_path_low_1.frp_sw_if_index);
    6055           1 :     adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6056             :                                                VNET_LINK_IP4,
    6057             :                                                &nr_path_low_2.frp_addr,
    6058             :                                                nr_path_low_2.frp_sw_if_index);
    6059             : 
    6060           1 :     fib_test_lb_bucket_t ip_hi_1 = {
    6061             :         .type = FT_LB_ADJ,
    6062             :         .adj = {
    6063             :             .adj = ai_hi_1,
    6064             :         },
    6065             :     };
    6066           1 :     fib_test_lb_bucket_t ip_hi_2 = {
    6067             :         .type = FT_LB_ADJ,
    6068             :         .adj = {
    6069             :             .adj = ai_hi_2,
    6070             :         },
    6071             :     };
    6072           1 :     fib_test_lb_bucket_t ip_med_1 = {
    6073             :         .type = FT_LB_ADJ,
    6074             :         .adj = {
    6075             :             .adj = ai_med_1,
    6076             :         },
    6077             :     };
    6078           1 :     fib_test_lb_bucket_t ip_med_2 = {
    6079             :         .type = FT_LB_ADJ,
    6080             :         .adj = {
    6081             :             .adj = ai_med_2,
    6082             :         },
    6083             :     };
    6084           1 :     fib_test_lb_bucket_t ip_low_1 = {
    6085             :         .type = FT_LB_ADJ,
    6086             :         .adj = {
    6087             :             .adj = ai_low_1,
    6088             :         },
    6089             :     };
    6090           1 :     fib_test_lb_bucket_t ip_low_2 = {
    6091             :         .type = FT_LB_ADJ,
    6092             :         .adj = {
    6093             :             .adj = ai_low_2,
    6094             :         },
    6095             :     };
    6096             : 
    6097             :     fib_node_index_t fei;
    6098             : 
    6099           1 :     fei = fib_table_entry_path_add2(0,
    6100             :                                     &pfx_1_1_1_1_s_32,
    6101             :                                     FIB_SOURCE_API,
    6102             :                                     FIB_ENTRY_FLAG_NONE,
    6103             :                                     nr_paths);
    6104             : 
    6105           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6106             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6107             :                                       2,
    6108             :                                       &ip_hi_1,
    6109             :                                       &ip_hi_2),
    6110             :              "1.1.1.1/32 via high preference paths");
    6111             : 
    6112             :     /*
    6113             :      * bring down the interface on which the high preference path lie
    6114             :      */
    6115           1 :     vnet_sw_interface_set_flags(vnet_get_main(),
    6116           1 :                                 tm->hw[0]->sw_if_index,
    6117             :                                 0);
    6118             : 
    6119           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6120             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6121             :                                       2,
    6122             :                                       &ip_med_1,
    6123             :                                       &ip_med_2),
    6124             :              "1.1.1.1/32 via medium preference paths");
    6125             : 
    6126             :     /*
    6127             :      * bring down the interface on which the medium preference path lie
    6128             :      */
    6129           1 :     vnet_sw_interface_set_flags(vnet_get_main(),
    6130           1 :                                 tm->hw[1]->sw_if_index,
    6131             :                                 0);
    6132             : 
    6133           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6134             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6135             :                                       2,
    6136             :                                       &ip_low_1,
    6137             :                                       &ip_low_2),
    6138             :              "1.1.1.1/32 via low preference paths");
    6139             : 
    6140             :     /*
    6141             :      * bring up the interface on which the high preference path lie
    6142             :      */
    6143           1 :     vnet_sw_interface_set_flags(vnet_get_main(),
    6144           1 :                                 tm->hw[0]->sw_if_index,
    6145             :                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    6146             : 
    6147           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6148             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6149             :                                       2,
    6150             :                                       &ip_hi_1,
    6151             :                                       &ip_hi_2),
    6152             :              "1.1.1.1/32 via high preference paths");
    6153             : 
    6154             :     /*
    6155             :      * bring up the interface on which the medium preference path lie
    6156             :      */
    6157           1 :     vnet_sw_interface_set_flags(vnet_get_main(),
    6158           1 :                                 tm->hw[1]->sw_if_index,
    6159             :                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    6160             : 
    6161           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6162             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6163             :                                       2,
    6164             :                                       &ip_hi_1,
    6165             :                                       &ip_hi_2),
    6166             :              "1.1.1.1/32 via high preference paths");
    6167             : 
    6168           1 :     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
    6169           1 :     fib_entry_contribute_forwarding(fei,
    6170             :                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6171             :                                     &ip_1_1_1_1);
    6172             : 
    6173             :     /*
    6174             :      * 3 recursive paths of different preference
    6175             :      */
    6176           2 :     const fib_prefix_t pfx_1_1_1_2_s_32 = {
    6177             :         .fp_len = 32,
    6178             :         .fp_proto = FIB_PROTOCOL_IP4,
    6179             :         .fp_addr = {
    6180             :             .ip4 = {
    6181           1 :                 .as_u32 = clib_host_to_net_u32(0x01010102),
    6182             :             },
    6183             :         },
    6184             :     };
    6185           2 :     const fib_prefix_t pfx_1_1_1_3_s_32 = {
    6186             :         .fp_len = 32,
    6187             :         .fp_proto = FIB_PROTOCOL_IP4,
    6188             :         .fp_addr = {
    6189             :             .ip4 = {
    6190           1 :                 .as_u32 = clib_host_to_net_u32(0x01010103),
    6191             :             },
    6192             :         },
    6193             :     };
    6194           1 :     fei = fib_table_entry_path_add2(0,
    6195             :                                     &pfx_1_1_1_2_s_32,
    6196             :                                     FIB_SOURCE_API,
    6197             :                                     FIB_ENTRY_FLAG_NONE,
    6198             :                                     nr_paths);
    6199           1 :     dpo_id_t ip_1_1_1_2 = DPO_INVALID;
    6200           1 :     fib_entry_contribute_forwarding(fei,
    6201             :                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6202             :                                     &ip_1_1_1_2);
    6203           1 :     fei = fib_table_entry_path_add2(0,
    6204             :                                     &pfx_1_1_1_3_s_32,
    6205             :                                     FIB_SOURCE_API,
    6206             :                                     FIB_ENTRY_FLAG_NONE,
    6207             :                                     nr_paths);
    6208           1 :     dpo_id_t ip_1_1_1_3 = DPO_INVALID;
    6209           1 :     fib_entry_contribute_forwarding(fei,
    6210             :                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6211             :                                     &ip_1_1_1_3);
    6212             : 
    6213           1 :     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
    6214             :         .type = FT_LB_O_LB,
    6215             :         .lb = {
    6216           1 :             .lb = ip_1_1_1_1.dpoi_index,
    6217             :         },
    6218             :     };
    6219           1 :     fib_test_lb_bucket_t ip_o_1_1_1_2 = {
    6220             :         .type = FT_LB_O_LB,
    6221             :         .lb = {
    6222           1 :             .lb = ip_1_1_1_2.dpoi_index,
    6223             :         },
    6224             :     };
    6225           1 :     fib_test_lb_bucket_t ip_o_1_1_1_3 = {
    6226             :         .type = FT_LB_O_LB,
    6227             :         .lb = {
    6228           1 :             .lb = ip_1_1_1_3.dpoi_index,
    6229             :         },
    6230             :     };
    6231           1 :     fib_route_path_t r_path_hi = {
    6232             :         .frp_proto = DPO_PROTO_IP4,
    6233             :         .frp_sw_if_index = ~0,
    6234             :         .frp_fib_index = 0,
    6235             :         .frp_weight = 1,
    6236             :         .frp_preference = 0,
    6237             :         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
    6238             :         .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
    6239             :     };
    6240           1 :     fib_route_path_t r_path_med = {
    6241             :         .frp_proto = DPO_PROTO_IP4,
    6242             :         .frp_sw_if_index = ~0,
    6243             :         .frp_fib_index = 0,
    6244             :         .frp_weight = 1,
    6245             :         .frp_preference = 10,
    6246             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
    6247             :         .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
    6248             :     };
    6249           1 :     fib_route_path_t r_path_low = {
    6250             :         .frp_proto = DPO_PROTO_IP4,
    6251             :         .frp_sw_if_index = ~0,
    6252             :         .frp_fib_index = 0,
    6253             :         .frp_weight = 1,
    6254             :         .frp_preference = 255,
    6255             :         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
    6256             :         .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
    6257             :     };
    6258           1 :     fib_route_path_t *r_paths = NULL;
    6259             : 
    6260           1 :     vec_add1(r_paths, r_path_hi);
    6261           1 :     vec_add1(r_paths, r_path_low);
    6262           1 :     vec_add1(r_paths, r_path_med);
    6263             : 
    6264             :     /*
    6265             :      * add many recursive so we get the LB MAp created
    6266             :      */
    6267             : #define N_PFXS 64
    6268             :     fib_prefix_t pfx_r[N_PFXS];
    6269             :     unsigned int n_pfxs;
    6270          65 :     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
    6271             :     {
    6272          64 :         pfx_r[n_pfxs].fp_len = 32;
    6273          64 :         pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
    6274          64 :         pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
    6275          64 :             clib_host_to_net_u32(0x02000000 + n_pfxs);
    6276             : 
    6277          64 :         fei = fib_table_entry_path_add2(0,
    6278          64 :                                         &pfx_r[n_pfxs],
    6279             :                                         FIB_SOURCE_API,
    6280             :                                         FIB_ENTRY_FLAG_NONE,
    6281             :                                         r_paths);
    6282             : 
    6283          64 :         FIB_TEST(!fib_test_validate_entry(fei,
    6284             :                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6285             :                                           1,
    6286             :                                           &ip_o_1_1_1_1),
    6287             :                  "recursive via high preference paths");
    6288             : 
    6289             :         /*
    6290             :          * withdraw hig pref resolving entry
    6291             :          */
    6292          64 :         fib_table_entry_delete(0,
    6293             :                                &pfx_1_1_1_1_s_32,
    6294             :                                FIB_SOURCE_API);
    6295             : 
    6296             :         /* suspend so the update walk kicks int */
    6297          64 :         vlib_process_suspend(vlib_get_main(), 1e-5);
    6298             : 
    6299          64 :         FIB_TEST(!fib_test_validate_entry(fei,
    6300             :                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6301             :                                           1,
    6302             :                                           &ip_o_1_1_1_2),
    6303             :                  "recursive via medium preference paths");
    6304             : 
    6305             :         /*
    6306             :          * withdraw medium pref resolving entry
    6307             :          */
    6308          64 :         fib_table_entry_delete(0,
    6309             :                                &pfx_1_1_1_2_s_32,
    6310             :                                FIB_SOURCE_API);
    6311             : 
    6312             :         /* suspend so the update walk kicks int */
    6313          64 :         vlib_process_suspend(vlib_get_main(), 1e-5);
    6314             : 
    6315          64 :         FIB_TEST(!fib_test_validate_entry(fei,
    6316             :                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6317             :                                           1,
    6318             :                                           &ip_o_1_1_1_3),
    6319             :                  "recursive via low preference paths");
    6320             : 
    6321             :         /*
    6322             :          * add back paths for next iteration
    6323             :          */
    6324          64 :         fei = fib_table_entry_update(0,
    6325             :                                      &pfx_1_1_1_2_s_32,
    6326             :                                      FIB_SOURCE_API,
    6327             :                                      FIB_ENTRY_FLAG_NONE,
    6328             :                                      nr_paths);
    6329          64 :         fei = fib_table_entry_update(0,
    6330             :                                      &pfx_1_1_1_1_s_32,
    6331             :                                      FIB_SOURCE_API,
    6332             :                                      FIB_ENTRY_FLAG_NONE,
    6333             :                                      nr_paths);
    6334             : 
    6335             :         /* suspend so the update walk kicks int */
    6336          64 :         vlib_process_suspend(vlib_get_main(), 1e-5);
    6337             : 
    6338          64 :         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
    6339          64 :         FIB_TEST(!fib_test_validate_entry(fei,
    6340             :                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6341             :                                           1,
    6342             :                                           &ip_o_1_1_1_1),
    6343             :                  "recursive via high preference paths");
    6344             :     }
    6345             : 
    6346             : 
    6347           1 :     fib_table_entry_delete(0,
    6348             :                            &pfx_1_1_1_1_s_32,
    6349             :                            FIB_SOURCE_API);
    6350             : 
    6351             :     /* suspend so the update walk kicks int */
    6352           1 :     vlib_process_suspend(vlib_get_main(), 1e-5);
    6353             : 
    6354          65 :     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
    6355             :     {
    6356          64 :         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
    6357             : 
    6358          64 :         FIB_TEST(!fib_test_validate_entry(fei,
    6359             :                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6360             :                                           1,
    6361             :                                           &ip_o_1_1_1_2),
    6362             :                  "recursive via medium preference paths");
    6363             :     }
    6364          65 :     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
    6365             :     {
    6366          64 :         fib_table_entry_delete(0,
    6367          64 :                                &pfx_r[n_pfxs],
    6368             :                                FIB_SOURCE_API);
    6369             :     }
    6370             : 
    6371             :     /*
    6372             :      * Cleanup
    6373             :      */
    6374           1 :     fib_table_entry_delete(0,
    6375             :                            &pfx_1_1_1_2_s_32,
    6376             :                            FIB_SOURCE_API);
    6377           1 :     fib_table_entry_delete(0,
    6378             :                            &pfx_1_1_1_3_s_32,
    6379             :                            FIB_SOURCE_API);
    6380             : 
    6381           1 :     dpo_reset(&ip_1_1_1_1);
    6382           1 :     dpo_reset(&ip_1_1_1_2);
    6383           1 :     dpo_reset(&ip_1_1_1_3);
    6384           1 :     adj_unlock(ai_low_2);
    6385           1 :     adj_unlock(ai_low_1);
    6386           1 :     adj_unlock(ai_med_2);
    6387           1 :     adj_unlock(ai_med_1);
    6388           1 :     adj_unlock(ai_hi_2);
    6389           1 :     adj_unlock(ai_hi_1);
    6390             : 
    6391           1 :     return (res);
    6392             : }
    6393             : 
    6394             : /*
    6395             :  * Test the recursive route route handling for GRE tunnels
    6396             :  */
    6397             : static int
    6398           1 : fib_test_label (void)
    6399             : {
    6400             :     fib_node_index_t fei, ai_mpls_10_10_10_1, ai_v4_10_10_11_1, ai_v4_10_10_11_2, ai_mpls_10_10_11_2, ai_mpls_10_10_11_1;
    6401           1 :     const u32 fib_index = 0;
    6402             :     int lb_count, ii, res;
    6403             :     test_main_t *tm;
    6404             : 
    6405           1 :     res = 0;
    6406           1 :     lb_count = pool_elts(load_balance_pool);
    6407           1 :     tm = &test_main;
    6408             : 
    6409             :     /*
    6410             :      * add interface routes. We'll assume this works. It's more rigorously
    6411             :      * tested elsewhere.
    6412             :      */
    6413           2 :     fib_prefix_t local0_pfx = {
    6414             :         .fp_len = 24,
    6415             :         .fp_proto = FIB_PROTOCOL_IP4,
    6416             :         .fp_addr = {
    6417             :             .ip4 = {
    6418             :                 /* 10.10.10.10 */
    6419           1 :                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
    6420             :             },
    6421             :         },
    6422             :     };
    6423             : 
    6424           1 :     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
    6425             :              adj_nbr_db_size());
    6426             : 
    6427           1 :     fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[0]->sw_if_index, fib_index);
    6428             : 
    6429           1 :     fib_table_entry_update_one_path(fib_index, &local0_pfx,
    6430             :                                     FIB_SOURCE_INTERFACE,
    6431             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    6432             :                                      FIB_ENTRY_FLAG_ATTACHED),
    6433             :                                     DPO_PROTO_IP4,
    6434             :                                     NULL,
    6435           1 :                                     tm->hw[0]->sw_if_index,
    6436             :                                     ~0,
    6437             :                                     1,
    6438             :                                     NULL,
    6439             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    6440           1 :     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
    6441           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
    6442             :              "attached interface route present");
    6443             : 
    6444           1 :     local0_pfx.fp_len = 32;
    6445           1 :     fib_table_entry_update_one_path(fib_index, &local0_pfx,
    6446             :                                     FIB_SOURCE_INTERFACE,
    6447             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    6448             :                                      FIB_ENTRY_FLAG_LOCAL),
    6449             :                                     DPO_PROTO_IP4,
    6450             :                                     NULL,
    6451           1 :                                     tm->hw[0]->sw_if_index,
    6452             :                                     ~0, // invalid fib index
    6453             :                                     1,
    6454             :                                     NULL,
    6455             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    6456           1 :     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
    6457             : 
    6458           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
    6459             :              "local interface route present");
    6460             : 
    6461           2 :     fib_prefix_t local1_pfx = {
    6462             :         .fp_len = 24,
    6463             :         .fp_proto = FIB_PROTOCOL_IP4,
    6464             :         .fp_addr = {
    6465             :             .ip4 = {
    6466             :                 /* 10.10.11.10 */
    6467           1 :                 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
    6468             :             },
    6469             :         },
    6470             :     };
    6471             : 
    6472           1 :     fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[1]->sw_if_index, fib_index);
    6473             : 
    6474           1 :     fib_table_entry_update_one_path(fib_index, &local1_pfx,
    6475             :                                     FIB_SOURCE_INTERFACE,
    6476             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    6477             :                                      FIB_ENTRY_FLAG_ATTACHED),
    6478             :                                     DPO_PROTO_IP4,
    6479             :                                     NULL,
    6480           1 :                                     tm->hw[1]->sw_if_index,
    6481             :                                     ~0,
    6482             :                                     1,
    6483             :                                     NULL,
    6484             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    6485           1 :     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
    6486           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
    6487             :              "attached interface route present");
    6488             : 
    6489           1 :     local1_pfx.fp_len = 32;
    6490           1 :     fib_table_entry_update_one_path(fib_index, &local1_pfx,
    6491             :                                     FIB_SOURCE_INTERFACE,
    6492             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    6493             :                                      FIB_ENTRY_FLAG_LOCAL),
    6494             :                                     DPO_PROTO_IP4,
    6495             :                                     NULL,
    6496           1 :                                     tm->hw[1]->sw_if_index,
    6497             :                                     ~0, // invalid fib index
    6498             :                                     1,
    6499             :                                     NULL,
    6500             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    6501           1 :     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
    6502             : 
    6503           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
    6504             :              "local interface route present");
    6505             : 
    6506           2 :     ip46_address_t nh_10_10_10_1 = {
    6507             :         .ip4 = {
    6508           1 :             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
    6509             :         },
    6510             :     };
    6511           2 :     ip46_address_t nh_10_10_11_1 = {
    6512             :         .ip4 = {
    6513           1 :             .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
    6514             :         },
    6515             :     };
    6516           2 :     ip46_address_t nh_10_10_11_2 = {
    6517             :         .ip4 = {
    6518           1 :             .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
    6519             :         },
    6520             :     };
    6521             : 
    6522           1 :     ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6523             :                                            VNET_LINK_IP4,
    6524             :                                            &nh_10_10_11_1,
    6525           1 :                                            tm->hw[1]->sw_if_index);
    6526           1 :     ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6527             :                                            VNET_LINK_IP4,
    6528             :                                            &nh_10_10_11_2,
    6529           1 :                                            tm->hw[1]->sw_if_index);
    6530           1 :     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6531             :                                              VNET_LINK_MPLS,
    6532             :                                              &nh_10_10_10_1,
    6533           1 :                                              tm->hw[0]->sw_if_index);
    6534           1 :     ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6535             :                                              VNET_LINK_MPLS,
    6536             :                                              &nh_10_10_11_2,
    6537           1 :                                              tm->hw[1]->sw_if_index);
    6538           1 :     ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    6539             :                                              VNET_LINK_MPLS,
    6540             :                                              &nh_10_10_11_1,
    6541           1 :                                              tm->hw[1]->sw_if_index);
    6542             : 
    6543             :     /*
    6544             :      * Add an etry with one path with a real out-going label
    6545             :      */
    6546           2 :     fib_prefix_t pfx_1_1_1_1_s_32 = {
    6547             :         .fp_len = 32,
    6548             :         .fp_proto = FIB_PROTOCOL_IP4,
    6549             :         .fp_addr = {
    6550           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
    6551             :         },
    6552             :     };
    6553           1 :     fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
    6554             :         .type = FT_LB_LABEL_O_ADJ,
    6555             :         .label_o_adj = {
    6556             :             .adj = ai_mpls_10_10_10_1,
    6557             :             .label = 99,
    6558             :             .eos = MPLS_EOS,
    6559             :         },
    6560             :     };
    6561           1 :     fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
    6562             :         .type = FT_LB_LABEL_O_ADJ,
    6563             :         .label_o_adj = {
    6564             :             .adj = ai_mpls_10_10_10_1,
    6565             :             .label = 99,
    6566             :             .eos = MPLS_NON_EOS,
    6567             :         },
    6568             :     };
    6569           1 :     fib_mpls_label_t *l99 = NULL, fml99 = {
    6570             :         .fml_value = 99,
    6571             :     };
    6572           1 :     vec_add1(l99, fml99);
    6573             : 
    6574           1 :     fib_table_entry_update_one_path(fib_index,
    6575             :                                     &pfx_1_1_1_1_s_32,
    6576             :                                     FIB_SOURCE_API,
    6577             :                                     FIB_ENTRY_FLAG_NONE,
    6578             :                                     DPO_PROTO_IP4,
    6579             :                                     &nh_10_10_10_1,
    6580           1 :                                     tm->hw[0]->sw_if_index,
    6581             :                                     ~0, // invalid fib index
    6582             :                                     1,
    6583             :                                     l99,
    6584             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    6585             : 
    6586           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
    6587           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
    6588             : 
    6589           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6590             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6591             :                                       1,
    6592             :                                       &l99_eos_o_10_10_10_1),
    6593             :              "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
    6594             : 
    6595             :     /*
    6596             :      * add a path with an implicit NULL label
    6597             :      */
    6598           1 :     fib_test_lb_bucket_t a_o_10_10_11_1 = {
    6599             :         .type = FT_LB_ADJ,
    6600             :         .adj = {
    6601             :             .adj = ai_v4_10_10_11_1,
    6602             :         },
    6603             :     };
    6604           1 :     fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
    6605             :         .type = FT_LB_ADJ,
    6606             :         .adj = {
    6607             :             .adj = ai_mpls_10_10_11_1,
    6608             :         },
    6609             :     };
    6610           1 :     fib_mpls_label_t *l_imp_null = NULL, fml_imp_null = {
    6611             :         .fml_value =  MPLS_IETF_IMPLICIT_NULL_LABEL,
    6612             :     };
    6613           1 :     vec_add1(l_imp_null, fml_imp_null);
    6614             : 
    6615           1 :     fei = fib_table_entry_path_add(fib_index,
    6616             :                                    &pfx_1_1_1_1_s_32,
    6617             :                                    FIB_SOURCE_API,
    6618             :                                    FIB_ENTRY_FLAG_NONE,
    6619             :                                    DPO_PROTO_IP4,
    6620             :                                    &nh_10_10_11_1,
    6621           1 :                                    tm->hw[1]->sw_if_index,
    6622             :                                    ~0, // invalid fib index
    6623             :                                    1,
    6624             :                                    l_imp_null,
    6625             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    6626             : 
    6627           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6628             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6629             :                                       2,
    6630             :                                       &l99_eos_o_10_10_10_1,
    6631             :                                       &a_o_10_10_11_1),
    6632             :              "1.1.1.1/32 LB 2 buckets via: "
    6633             :              "label 99 over 10.10.10.1, "
    6634             :              "adj over 10.10.11.1");
    6635             : 
    6636             :     /*
    6637             :      * assign the route a local label
    6638             :      */
    6639           1 :     fib_table_entry_local_label_add(fib_index,
    6640             :                                     &pfx_1_1_1_1_s_32,
    6641             :                                     24001);
    6642             : 
    6643           1 :     fib_prefix_t pfx_24001_eos = {
    6644             :         .fp_proto = FIB_PROTOCOL_MPLS,
    6645             :         .fp_label = 24001,
    6646             :         .fp_eos = MPLS_EOS,
    6647             :     };
    6648           1 :     fib_prefix_t pfx_24001_neos = {
    6649             :         .fp_proto = FIB_PROTOCOL_MPLS,
    6650             :         .fp_label = 24001,
    6651             :         .fp_eos = MPLS_NON_EOS,
    6652             :     };
    6653           1 :     fib_test_lb_bucket_t disp_o_10_10_11_1 = {
    6654             :         .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
    6655             :         .adj = {
    6656             :             .adj = ai_v4_10_10_11_1,
    6657             :         },
    6658             :     };
    6659             : 
    6660             :     /*
    6661             :      * The EOS entry should link to both the paths,
    6662             :      *  and use an ip adj for the imp-null
    6663             :      * The NON-EOS entry should link to both the paths,
    6664             :      *  and use an mpls adj for the imp-null
    6665             :      */
    6666           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6667             :                            &pfx_24001_eos);
    6668           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6669             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    6670             :                                       2,
    6671             :                                       &l99_eos_o_10_10_10_1,
    6672             :                                       &disp_o_10_10_11_1),
    6673             :              "24001/eos LB 2 buckets via: "
    6674             :              "label 99 over 10.10.10.1, "
    6675             :              "mpls disp adj over 10.10.11.1");
    6676             : 
    6677             : 
    6678           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6679             :                            &pfx_24001_neos);
    6680           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6681             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    6682             :                                       2,
    6683             :                                       &l99_neos_o_10_10_10_1,
    6684             :                                       &a_mpls_o_10_10_11_1),
    6685             :              "24001/neos LB 1 bucket via: "
    6686             :              "label 99 over 10.10.10.1 ",
    6687             :              "mpls-adj via 10.10.11.1");
    6688             : 
    6689             :     /*
    6690             :      * add an unlabelled path, this is excluded from the neos chains,
    6691             :      */
    6692           1 :     fib_test_lb_bucket_t adj_o_10_10_11_2 = {
    6693             :         .type = FT_LB_ADJ,
    6694             :         .adj = {
    6695             :             .adj = ai_v4_10_10_11_2,
    6696             :         },
    6697             :     };
    6698           1 :     fib_test_lb_bucket_t disp_o_10_10_11_2 = {
    6699             :         .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
    6700             :         .adj = {
    6701             :             .adj = ai_v4_10_10_11_2,
    6702             :         },
    6703             :     };
    6704             : 
    6705             : 
    6706           1 :     fei = fib_table_entry_path_add(fib_index,
    6707             :                                    &pfx_1_1_1_1_s_32,
    6708             :                                    FIB_SOURCE_API,
    6709             :                                    FIB_ENTRY_FLAG_NONE,
    6710             :                                    DPO_PROTO_IP4,
    6711             :                                    &nh_10_10_11_2,
    6712           1 :                                    tm->hw[1]->sw_if_index,
    6713             :                                    ~0, // invalid fib index
    6714             :                                    1,
    6715             :                                    NULL,
    6716             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    6717             : 
    6718           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6719             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6720             :                                       16, // 3 choices spread over 16 buckets
    6721             :                                       &l99_eos_o_10_10_10_1,
    6722             :                                       &l99_eos_o_10_10_10_1,
    6723             :                                       &l99_eos_o_10_10_10_1,
    6724             :                                       &l99_eos_o_10_10_10_1,
    6725             :                                       &l99_eos_o_10_10_10_1,
    6726             :                                       &l99_eos_o_10_10_10_1,
    6727             :                                       &a_o_10_10_11_1,
    6728             :                                       &a_o_10_10_11_1,
    6729             :                                       &a_o_10_10_11_1,
    6730             :                                       &a_o_10_10_11_1,
    6731             :                                       &a_o_10_10_11_1,
    6732             :                                       &adj_o_10_10_11_2,
    6733             :                                       &adj_o_10_10_11_2,
    6734             :                                       &adj_o_10_10_11_2,
    6735             :                                       &adj_o_10_10_11_2,
    6736             :                                       &adj_o_10_10_11_2),
    6737             :              "1.1.1.1/32 LB 16 buckets via: "
    6738             :              "label 99 over 10.10.10.1, "
    6739             :              "adj over 10.10.11.1",
    6740             :              "adj over 10.10.11.2");
    6741             : 
    6742             :     /*
    6743             :      * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
    6744             :      */
    6745           1 :     dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
    6746           1 :     fib_entry_contribute_forwarding(fei,
    6747             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    6748             :                                     &non_eos_1_1_1_1);
    6749             : 
    6750             :     /*
    6751             :      * n-eos has only the 2 labelled paths
    6752             :      */
    6753           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6754             :                            &pfx_24001_neos);
    6755             : 
    6756           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6757             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    6758             :                                       2,
    6759             :                                       &l99_neos_o_10_10_10_1,
    6760             :                                       &a_mpls_o_10_10_11_1),
    6761             :              "24001/neos LB 2 buckets via: "
    6762             :              "label 99 over 10.10.10.1, "
    6763             :              "adj-mpls over 10.10.11.2");
    6764             : 
    6765             :     /*
    6766             :      * A labelled recursive
    6767             :      */
    6768           2 :     fib_prefix_t pfx_2_2_2_2_s_32 = {
    6769             :         .fp_len = 32,
    6770             :         .fp_proto = FIB_PROTOCOL_IP4,
    6771             :         .fp_addr = {
    6772           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
    6773             :         },
    6774             :     };
    6775           1 :     fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
    6776             :         .type = FT_LB_LABEL_O_LB,
    6777             :         .label_o_lb = {
    6778           1 :             .lb = non_eos_1_1_1_1.dpoi_index,
    6779             :             .label = 1600,
    6780             :             .eos = MPLS_EOS,
    6781             :             .mode = FIB_MPLS_LSP_MODE_UNIFORM,
    6782             :         },
    6783             :     };
    6784           1 :     fib_mpls_label_t *l1600 = NULL, fml1600 = {
    6785             :         .fml_value = 1600,
    6786             :         .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
    6787             :     };
    6788           1 :     vec_add1(l1600, fml1600);
    6789             : 
    6790           1 :     fei = fib_table_entry_update_one_path(fib_index,
    6791             :                                           &pfx_2_2_2_2_s_32,
    6792             :                                           FIB_SOURCE_API,
    6793             :                                           FIB_ENTRY_FLAG_NONE,
    6794             :                                           DPO_PROTO_IP4,
    6795             :                                           &pfx_1_1_1_1_s_32.fp_addr,
    6796             :                                           ~0,
    6797             :                                           fib_index,
    6798             :                                           1,
    6799             :                                           l1600,
    6800             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    6801             : 
    6802           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6803             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6804             :                                       1,
    6805             :                                       &l1600_eos_o_1_1_1_1),
    6806             :              "2.2.2.2.2/32 LB 1 buckets via: "
    6807             :              "label 1600 over 1.1.1.1");
    6808             : 
    6809           1 :     dpo_id_t dpo_44 = DPO_INVALID;
    6810             :     index_t urpfi;
    6811             : 
    6812           1 :     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
    6813           1 :     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
    6814             : 
    6815           1 :     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
    6816             :              "uRPF check for 2.2.2.2/32 on %d OK",
    6817             :              tm->hw[0]->sw_if_index);
    6818           1 :     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
    6819             :              "uRPF check for 2.2.2.2/32 on %d OK",
    6820             :              tm->hw[1]->sw_if_index);
    6821           1 :     FIB_TEST(!fib_urpf_check(urpfi, 99),
    6822             :              "uRPF check for 2.2.2.2/32 on 99 not-OK",
    6823             :              99);
    6824             : 
    6825           1 :     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
    6826           1 :     FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
    6827             :              "Shared uRPF on IP and non-EOS chain");
    6828             : 
    6829           1 :     dpo_reset(&dpo_44);
    6830             : 
    6831             :     /*
    6832             :      * we are holding a lock on the non-eos LB of the via-entry.
    6833             :      * do a PIC-core failover by shutting the link of the via-entry.
    6834             :      *
    6835             :      * shut down the link with the valid label
    6836             :      */
    6837           1 :     vnet_sw_interface_set_flags(vnet_get_main(),
    6838           1 :                                 tm->hw[0]->sw_if_index,
    6839             :                                 0);
    6840             : 
    6841           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
    6842           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6843             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6844             :                                       2,
    6845             :                                       &a_o_10_10_11_1,
    6846             :                                       &adj_o_10_10_11_2),
    6847             :              "1.1.1.1/32 LB 2 buckets via: "
    6848             :              "adj over 10.10.11.1, ",
    6849             :              "adj-v4 over 10.10.11.2");
    6850             : 
    6851           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6852             :                            &pfx_24001_eos);
    6853           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6854             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    6855             :                                       2,
    6856             :                                       &disp_o_10_10_11_1,
    6857             :                                       &disp_o_10_10_11_2),
    6858             :              "24001/eos LB 2 buckets via: "
    6859             :              "mpls-disp adj over 10.10.11.1, ",
    6860             :              "mpls-disp adj-v4 over 10.10.11.2");
    6861             : 
    6862           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6863             :                            &pfx_24001_neos);
    6864           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6865             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    6866             :                                       1,
    6867             :                                       &a_mpls_o_10_10_11_1),
    6868             :              "24001/neos LB 1 buckets via: "
    6869             :              "adj-mpls over 10.10.11.2");
    6870             : 
    6871             :     /*
    6872             :      * test that the pre-failover load-balance has been in-place
    6873             :      * modified
    6874             :      */
    6875           1 :     dpo_id_t current = DPO_INVALID;
    6876           1 :     fib_entry_contribute_forwarding(fei,
    6877             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    6878             :                                     &current);
    6879             : 
    6880           1 :     FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
    6881             :                       &current),
    6882             :              "PIC-core LB inplace modified %U %U",
    6883             :              format_dpo_id, &non_eos_1_1_1_1, 0,
    6884             :              format_dpo_id, &current, 0);
    6885             : 
    6886           1 :     dpo_reset(&non_eos_1_1_1_1);
    6887           1 :     dpo_reset(&current);
    6888             : 
    6889             :     /*
    6890             :      * no-shut the link with the valid label
    6891             :      */
    6892           1 :     vnet_sw_interface_set_flags(vnet_get_main(),
    6893           1 :                                 tm->hw[0]->sw_if_index,
    6894             :                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    6895             : 
    6896           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
    6897           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6898             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6899             :                                       16, // 3 choices spread over 16 buckets
    6900             :                                       &l99_eos_o_10_10_10_1,
    6901             :                                       &l99_eos_o_10_10_10_1,
    6902             :                                       &l99_eos_o_10_10_10_1,
    6903             :                                       &l99_eos_o_10_10_10_1,
    6904             :                                       &l99_eos_o_10_10_10_1,
    6905             :                                       &l99_eos_o_10_10_10_1,
    6906             :                                       &a_o_10_10_11_1,
    6907             :                                       &a_o_10_10_11_1,
    6908             :                                       &a_o_10_10_11_1,
    6909             :                                       &a_o_10_10_11_1,
    6910             :                                       &a_o_10_10_11_1,
    6911             :                                       &adj_o_10_10_11_2,
    6912             :                                       &adj_o_10_10_11_2,
    6913             :                                       &adj_o_10_10_11_2,
    6914             :                                       &adj_o_10_10_11_2,
    6915             :                                       &adj_o_10_10_11_2),
    6916             :              "1.1.1.1/32 LB 16 buckets via: "
    6917             :              "label 99 over 10.10.10.1, "
    6918             :              "adj over 10.10.11.1",
    6919             :              "adj-v4 over 10.10.11.2");
    6920             : 
    6921             : 
    6922           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6923             :                            &pfx_24001_eos);
    6924           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6925             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    6926             :                                       16, // 3 choices spread over 16 buckets
    6927             :                                       &l99_eos_o_10_10_10_1,
    6928             :                                       &l99_eos_o_10_10_10_1,
    6929             :                                       &l99_eos_o_10_10_10_1,
    6930             :                                       &l99_eos_o_10_10_10_1,
    6931             :                                       &l99_eos_o_10_10_10_1,
    6932             :                                       &l99_eos_o_10_10_10_1,
    6933             :                                       &disp_o_10_10_11_1,
    6934             :                                       &disp_o_10_10_11_1,
    6935             :                                       &disp_o_10_10_11_1,
    6936             :                                       &disp_o_10_10_11_1,
    6937             :                                       &disp_o_10_10_11_1,
    6938             :                                       &disp_o_10_10_11_2,
    6939             :                                       &disp_o_10_10_11_2,
    6940             :                                       &disp_o_10_10_11_2,
    6941             :                                       &disp_o_10_10_11_2,
    6942             :                                       &disp_o_10_10_11_2),
    6943             :              "24001/eos LB 16 buckets via: "
    6944             :              "label 99 over 10.10.10.1, "
    6945             :              "MPLS disp adj over 10.10.11.1",
    6946             :              "MPLS disp adj-v4 over 10.10.11.2");
    6947             : 
    6948           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6949             :                            &pfx_24001_neos);
    6950           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6951             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    6952             :                                       2,
    6953             :                                       &l99_neos_o_10_10_10_1,
    6954             :                                       &a_mpls_o_10_10_11_1),
    6955             :              "24001/neos LB 2 buckets via: "
    6956             :              "label 99 over 10.10.10.1, "
    6957             :              "adj-mpls over 10.10.11.2");
    6958             : 
    6959             :     /*
    6960             :      * remove the first path with the valid label
    6961             :      */
    6962           1 :     fib_table_entry_path_remove(fib_index,
    6963             :                                 &pfx_1_1_1_1_s_32,
    6964             :                                 FIB_SOURCE_API,
    6965             :                                 DPO_PROTO_IP4,
    6966             :                                 &nh_10_10_10_1,
    6967           1 :                                 tm->hw[0]->sw_if_index,
    6968             :                                 ~0, // invalid fib index
    6969             :                                 1,
    6970             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    6971             : 
    6972           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
    6973           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6974             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    6975             :                                       2,
    6976             :                                       &a_o_10_10_11_1,
    6977             :                                       &adj_o_10_10_11_2),
    6978             :              "1.1.1.1/32 LB 2 buckets via: "
    6979             :              "adj over 10.10.11.1, "
    6980             :              "adj-v4 over 10.10.11.2");
    6981             : 
    6982           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6983             :                            &pfx_24001_eos);
    6984           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6985             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    6986             :                                       2,
    6987             :                                       &disp_o_10_10_11_1,
    6988             :                                       &disp_o_10_10_11_2),
    6989             :              "24001/eos LB 2 buckets via: "
    6990             :              "MPLS disp adj over 10.10.11.1, "
    6991             :              "MPLS disp adj-v4 over 10.10.11.2");
    6992             : 
    6993           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    6994             :                            &pfx_24001_neos);
    6995             : 
    6996           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    6997             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    6998             :                                       1,
    6999             :                                       &a_mpls_o_10_10_11_1),
    7000             :              "24001/neos LB 1 buckets via: "
    7001             :              "adj-mpls over 10.10.11.2");
    7002             : 
    7003             :     /*
    7004             :      * remove the other path with a valid label
    7005             :      */
    7006           1 :     fib_test_lb_bucket_t bucket_drop = {
    7007             :         .type = FT_LB_DROP,
    7008             :     };
    7009           1 :     fib_test_lb_bucket_t mpls_bucket_drop = {
    7010             :         .type = FT_LB_DROP,
    7011             :         .special = {
    7012             :             .adj = DPO_PROTO_MPLS,
    7013             :         },
    7014             :     };
    7015             : 
    7016           1 :     fib_table_entry_path_remove(fib_index,
    7017             :                                 &pfx_1_1_1_1_s_32,
    7018             :                                 FIB_SOURCE_API,
    7019             :                                 DPO_PROTO_IP4,
    7020             :                                 &nh_10_10_11_1,
    7021           1 :                                 tm->hw[1]->sw_if_index,
    7022             :                                 ~0, // invalid fib index
    7023             :                                 1,
    7024             :                                 FIB_ROUTE_PATH_FLAG_NONE);
    7025             : 
    7026           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
    7027           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7028             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7029             :                                       1,
    7030             :                                       &adj_o_10_10_11_2),
    7031             :              "1.1.1.1/32 LB 1 buckets via: "
    7032             :              "adj over 10.10.11.2");
    7033             : 
    7034           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    7035             :                            &pfx_24001_eos);
    7036           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7037             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    7038             :                                       1,
    7039             :                                       &disp_o_10_10_11_2),
    7040             :              "24001/eos LB 1 buckets via: "
    7041             :              "MPLS disp adj over 10.10.11.2");
    7042             : 
    7043           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    7044             :                            &pfx_24001_neos);
    7045           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7046             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    7047             :                                       1,
    7048             :                                       &mpls_bucket_drop),
    7049             :              "24001/neos LB 1 buckets via: DROP");
    7050             : 
    7051             :     /*
    7052             :      * add back the path with the valid label
    7053             :      */
    7054           1 :     l99 = NULL;
    7055           1 :     vec_add1(l99, fml99);
    7056             : 
    7057           1 :     fib_table_entry_path_add(fib_index,
    7058             :                              &pfx_1_1_1_1_s_32,
    7059             :                              FIB_SOURCE_API,
    7060             :                              FIB_ENTRY_FLAG_NONE,
    7061             :                              DPO_PROTO_IP4,
    7062             :                              &nh_10_10_10_1,
    7063           1 :                              tm->hw[0]->sw_if_index,
    7064             :                              ~0, // invalid fib index
    7065             :                              1,
    7066             :                              l99,
    7067             :                              FIB_ROUTE_PATH_FLAG_NONE);
    7068             : 
    7069           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
    7070           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7071             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7072             :                                       2,
    7073             :                                       &l99_eos_o_10_10_10_1,
    7074             :                                       &adj_o_10_10_11_2),
    7075             :              "1.1.1.1/32 LB 2 buckets via: "
    7076             :              "label 99 over 10.10.10.1, "
    7077             :              "adj over 10.10.11.2");
    7078             : 
    7079           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    7080             :                            &pfx_24001_eos);
    7081           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7082             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    7083             :                                       2,
    7084             :                                       &l99_eos_o_10_10_10_1,
    7085             :                                       &disp_o_10_10_11_2),
    7086             :              "24001/eos LB 2 buckets via: "
    7087             :              "label 99 over 10.10.10.1, "
    7088             :              "MPLS disp adj over 10.10.11.2");
    7089             : 
    7090           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    7091             :                            &pfx_24001_neos);
    7092           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7093             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    7094             :                                       1,
    7095             :                                       &l99_neos_o_10_10_10_1),
    7096             :              "24001/neos LB 1 buckets via: "
    7097             :              "label 99 over 10.10.10.1");
    7098             : 
    7099             :     /*
    7100             :      * change the local label
    7101             :      */
    7102           1 :     fib_table_entry_local_label_add(fib_index,
    7103             :                                     &pfx_1_1_1_1_s_32,
    7104             :                                     25005);
    7105             : 
    7106           1 :     fib_prefix_t pfx_25005_eos = {
    7107             :         .fp_proto = FIB_PROTOCOL_MPLS,
    7108             :         .fp_label = 25005,
    7109             :         .fp_eos = MPLS_EOS,
    7110             :     };
    7111           1 :     fib_prefix_t pfx_25005_neos = {
    7112             :         .fp_proto = FIB_PROTOCOL_MPLS,
    7113             :         .fp_label = 25005,
    7114             :         .fp_eos = MPLS_NON_EOS,
    7115             :     };
    7116             : 
    7117           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    7118             :               fib_table_lookup(fib_index, &pfx_24001_eos)),
    7119             :              "24001/eos removed after label change");
    7120           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    7121             :               fib_table_lookup(fib_index, &pfx_24001_neos)),
    7122             :              "24001/eos removed after label change");
    7123             : 
    7124           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    7125             :                            &pfx_25005_eos);
    7126           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7127             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    7128             :                                       2,
    7129             :                                       &l99_eos_o_10_10_10_1,
    7130             :                                       &disp_o_10_10_11_2),
    7131             :              "25005/eos LB 2 buckets via: "
    7132             :              "label 99 over 10.10.10.1, "
    7133             :              "MPLS disp adj over 10.10.11.2");
    7134             : 
    7135           1 :     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
    7136             :                            &pfx_25005_neos);
    7137           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7138             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    7139             :                                       1,
    7140             :                                       &l99_neos_o_10_10_10_1),
    7141             :              "25005/neos LB 1 buckets via: "
    7142             :              "label 99 over 10.10.10.1");
    7143             : 
    7144             :     /*
    7145             :      * remove the local label.
    7146             :      * the check that the MPLS entries are gone is done by the fact the
    7147             :      * MPLS table is no longer present.
    7148             :      */
    7149           1 :     fib_table_entry_local_label_remove(fib_index,
    7150             :                                        &pfx_1_1_1_1_s_32,
    7151             :                                        25005);
    7152             : 
    7153           1 :     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
    7154           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7155             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7156             :                                       2,
    7157             :                                       &l99_eos_o_10_10_10_1,
    7158             :                                       &adj_o_10_10_11_2),
    7159             :              "24001/eos LB 2 buckets via: "
    7160             :              "label 99 over 10.10.10.1, "
    7161             :              "adj over 10.10.11.2");
    7162             : 
    7163           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID ==
    7164             :               mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
    7165             :              "No more MPLS FIB entries => table removed");
    7166             : 
    7167             :     /*
    7168             :      * add another via-entry for the recursive
    7169             :      */
    7170           2 :     fib_prefix_t pfx_1_1_1_2_s_32 = {
    7171             :         .fp_len = 32,
    7172             :         .fp_proto = FIB_PROTOCOL_IP4,
    7173             :         .fp_addr = {
    7174           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
    7175             :         },
    7176             :     };
    7177           1 :     fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
    7178             :         .type = FT_LB_LABEL_O_ADJ,
    7179             :         .label_o_adj = {
    7180             :             .adj = ai_mpls_10_10_10_1,
    7181             :             .label = 101,
    7182             :             .eos = MPLS_EOS,
    7183             :         },
    7184             :     };
    7185           1 :     fib_mpls_label_t *l101 = NULL, fml101 = {
    7186             :         .fml_value = 101,
    7187             :     };
    7188           1 :     vec_add1(l101, fml101);
    7189             : 
    7190           1 :     fei = fib_table_entry_update_one_path(fib_index,
    7191             :                                           &pfx_1_1_1_2_s_32,
    7192             :                                           FIB_SOURCE_API,
    7193             :                                           FIB_ENTRY_FLAG_NONE,
    7194             :                                           DPO_PROTO_IP4,
    7195             :                                           &nh_10_10_10_1,
    7196           1 :                                           tm->hw[0]->sw_if_index,
    7197             :                                           ~0, // invalid fib index
    7198             :                                           1,
    7199             :                                           l101,
    7200             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    7201             : 
    7202           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7203             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7204             :                                       1,
    7205             :                                       &l101_eos_o_10_10_10_1),
    7206             :              "1.1.1.2/32 LB 1 buckets via: "
    7207             :              "label 101 over 10.10.10.1");
    7208             : 
    7209           1 :     dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
    7210           1 :     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
    7211             :                                                      &pfx_1_1_1_1_s_32),
    7212             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    7213             :                                     &non_eos_1_1_1_1);
    7214           1 :     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
    7215             :                                                      &pfx_1_1_1_2_s_32),
    7216             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    7217             :                                     &non_eos_1_1_1_2);
    7218             : 
    7219           1 :     fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
    7220             :         .type = FT_LB_LABEL_O_LB,
    7221             :         .label_o_lb = {
    7222           1 :             .lb = non_eos_1_1_1_2.dpoi_index,
    7223             :             .label = 1601,
    7224             :             .eos = MPLS_EOS,
    7225             :         },
    7226             :     };
    7227           1 :     fib_mpls_label_t *l1601 = NULL, fml1601 = {
    7228             :         .fml_value = 1601,
    7229             :     };
    7230           1 :     vec_add1(l1601, fml1601);
    7231             : 
    7232           1 :     l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
    7233             : 
    7234           1 :     fei = fib_table_entry_path_add(fib_index,
    7235             :                                    &pfx_2_2_2_2_s_32,
    7236             :                                    FIB_SOURCE_API,
    7237             :                                    FIB_ENTRY_FLAG_NONE,
    7238             :                                    DPO_PROTO_IP4,
    7239             :                                    &pfx_1_1_1_2_s_32.fp_addr,
    7240             :                                    ~0,
    7241             :                                    fib_index,
    7242             :                                    1,
    7243             :                                    l1601,
    7244             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    7245             : 
    7246           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7247             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7248             :                                       2,
    7249             :                                       &l1600_eos_o_1_1_1_1,
    7250             :                                       &l1601_eos_o_1_1_1_2),
    7251             :              "2.2.2.2/32 LB 2 buckets via: "
    7252             :              "label 1600 via 1.1,1.1, "
    7253             :              "label 16001 via 1.1.1.2");
    7254             : 
    7255             :     /*
    7256             :      * update the via-entry so it no longer has an imp-null path.
    7257             :      * the LB for the recursive can use an imp-null
    7258             :      */
    7259           1 :     l_imp_null = NULL;
    7260           1 :     vec_add1(l_imp_null, fml_imp_null);
    7261             : 
    7262           1 :     fei = fib_table_entry_update_one_path(fib_index,
    7263             :                                           &pfx_1_1_1_2_s_32,
    7264             :                                           FIB_SOURCE_API,
    7265             :                                           FIB_ENTRY_FLAG_NONE,
    7266             :                                           DPO_PROTO_IP4,
    7267             :                                           &nh_10_10_11_1,
    7268           1 :                                           tm->hw[1]->sw_if_index,
    7269             :                                           ~0, // invalid fib index
    7270             :                                           1,
    7271             :                                           l_imp_null,
    7272             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    7273             : 
    7274           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7275             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7276             :                                       1,
    7277             :                                       &a_o_10_10_11_1),
    7278             :              "1.1.1.2/32 LB 1 buckets via: "
    7279             :              "adj 10.10.11.1");
    7280             : 
    7281           1 :     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
    7282           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7283             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7284             :                                       2,
    7285             :                                       &l1600_eos_o_1_1_1_1,
    7286             :                                       &l1601_eos_o_1_1_1_2),
    7287             :              "2.2.2.2/32 LB 2 buckets via: "
    7288             :              "label 1600 via 1.1,1.1, "
    7289             :              "label 16001 via 1.1.1.2");
    7290             : 
    7291             :     /*
    7292             :      * update the via-entry so it no longer has labelled paths.
    7293             :      * the LB for the recursive should exclue this via form its LB
    7294             :      */
    7295           1 :     fei = fib_table_entry_update_one_path(fib_index,
    7296             :                                           &pfx_1_1_1_2_s_32,
    7297             :                                           FIB_SOURCE_API,
    7298             :                                           FIB_ENTRY_FLAG_NONE,
    7299             :                                           DPO_PROTO_IP4,
    7300             :                                           &nh_10_10_11_1,
    7301           1 :                                           tm->hw[1]->sw_if_index,
    7302             :                                           ~0, // invalid fib index
    7303             :                                           1,
    7304             :                                           NULL,
    7305             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    7306             : 
    7307           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7308             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7309             :                                       1,
    7310             :                                       &a_o_10_10_11_1),
    7311             :              "1.1.1.2/32 LB 1 buckets via: "
    7312             :              "adj 10.10.11.1");
    7313             : 
    7314           1 :     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
    7315           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7316             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7317             :                                       1,
    7318             :                                       &l1600_eos_o_1_1_1_1),
    7319             :              "2.2.2.2/32 LB 1 buckets via: "
    7320             :              "label 1600 via 1.1,1.1");
    7321             : 
    7322           1 :     dpo_reset(&non_eos_1_1_1_1);
    7323           1 :     dpo_reset(&non_eos_1_1_1_2);
    7324             : 
    7325             :     /*
    7326             :      * Add a recursive with no out-labels. We expect to use the IP of the via
    7327             :      */
    7328           2 :     fib_prefix_t pfx_2_2_2_3_s_32 = {
    7329             :         .fp_len = 32,
    7330             :         .fp_proto = FIB_PROTOCOL_IP4,
    7331             :         .fp_addr = {
    7332           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
    7333             :         },
    7334             :     };
    7335           1 :     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
    7336             : 
    7337           1 :     fib_table_entry_update_one_path(fib_index,
    7338             :                                     &pfx_2_2_2_3_s_32,
    7339             :                                     FIB_SOURCE_API,
    7340             :                                     FIB_ENTRY_FLAG_NONE,
    7341             :                                     DPO_PROTO_IP4,
    7342             :                                     &pfx_1_1_1_1_s_32.fp_addr,
    7343             :                                     ~0,
    7344             :                                     fib_index,
    7345             :                                     1,
    7346             :                                     NULL,
    7347             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    7348             : 
    7349           1 :     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
    7350             :                                                      &pfx_1_1_1_1_s_32),
    7351             :                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7352             :                                     &ip_1_1_1_1);
    7353             : 
    7354           1 :     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
    7355             :         .type = FT_LB_O_LB,
    7356             :         .lb = {
    7357           1 :             .lb = ip_1_1_1_1.dpoi_index,
    7358             :         },
    7359             :     };
    7360             : 
    7361           1 :     fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
    7362           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7363             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7364             :                                       1,
    7365             :                                       &ip_o_1_1_1_1),
    7366             :              "2.2.2.2.3/32 LB 1 buckets via: "
    7367             :              "ip 1.1.1.1");
    7368             : 
    7369             :     /*
    7370             :      * Add a recursive with an imp-null out-label.
    7371             :      * We expect to use the IP of the via
    7372             :      */
    7373           2 :     fib_prefix_t pfx_2_2_2_4_s_32 = {
    7374             :         .fp_len = 32,
    7375             :         .fp_proto = FIB_PROTOCOL_IP4,
    7376             :         .fp_addr = {
    7377           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
    7378             :         },
    7379             :     };
    7380             : 
    7381           1 :     fib_table_entry_update_one_path(fib_index,
    7382             :                                     &pfx_2_2_2_4_s_32,
    7383             :                                     FIB_SOURCE_API,
    7384             :                                     FIB_ENTRY_FLAG_NONE,
    7385             :                                     DPO_PROTO_IP4,
    7386             :                                     &pfx_1_1_1_1_s_32.fp_addr,
    7387             :                                     ~0,
    7388             :                                     fib_index,
    7389             :                                     1,
    7390             :                                     NULL,
    7391             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    7392             : 
    7393           1 :     fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
    7394           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7395             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7396             :                                       1,
    7397             :                                       &ip_o_1_1_1_1),
    7398             :              "2.2.2.2.4/32 LB 1 buckets via: "
    7399             :              "ip 1.1.1.1");
    7400             : 
    7401           1 :     dpo_reset(&ip_1_1_1_1);
    7402             : 
    7403             :     /*
    7404             :      * Create an entry with a deep label stack
    7405             :      */
    7406           2 :     fib_prefix_t pfx_2_2_5_5_s_32 = {
    7407             :         .fp_len = 32,
    7408             :         .fp_proto = FIB_PROTOCOL_IP4,
    7409             :         .fp_addr = {
    7410           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
    7411             :         },
    7412             :     };
    7413           1 :     fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
    7414             :         .type = FT_LB_LABEL_STACK_O_ADJ,
    7415             :         .label_stack_o_adj = {
    7416             :             .adj = ai_mpls_10_10_11_1,
    7417             :             .label_stack_size = 8,
    7418             :             .label_stack = {
    7419             :                 200, 201, 202, 203, 204, 205, 206, 207
    7420             :             },
    7421             :             .eos = MPLS_EOS,
    7422             :         },
    7423             :     };
    7424           1 :     fib_mpls_label_t *label_stack = NULL;
    7425           1 :     vec_validate(label_stack, 7);
    7426           9 :     for (ii = 0; ii < 8; ii++)
    7427             :     {
    7428           8 :         label_stack[ii].fml_value = ii + 200;
    7429             :     }
    7430             : 
    7431           1 :     fei = fib_table_entry_update_one_path(fib_index,
    7432             :                                           &pfx_2_2_5_5_s_32,
    7433             :                                           FIB_SOURCE_API,
    7434             :                                           FIB_ENTRY_FLAG_NONE,
    7435             :                                           DPO_PROTO_IP4,
    7436             :                                           &nh_10_10_11_1,
    7437           1 :                                           tm->hw[1]->sw_if_index,
    7438             :                                           ~0, // invalid fib index
    7439             :                                           1,
    7440             :                                           label_stack,
    7441             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    7442             : 
    7443           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7444             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7445             :                                       1,
    7446             :                                       &ls_eos_o_10_10_10_1),
    7447             :              "2.2.5.5/32 LB 1 buckets via: "
    7448             :              "adj 10.10.11.1");
    7449           1 :     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
    7450             : 
    7451             :     /*
    7452             :      * A prefix with outgoing labels. We'll RR source a /32 it covers
    7453             :      * and test that the RR source picks up the out-going labels
    7454             :      */
    7455           2 :     fib_prefix_t pfx_100_s_8 = {
    7456             :         .fp_len = 8,
    7457             :         .fp_proto = FIB_PROTOCOL_IP4,
    7458             :         .fp_addr = {
    7459           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x64000000),
    7460             :         },
    7461             :     };
    7462           1 :     fib_test_lb_bucket_t l_100_eos_o_10_10_10_1 = {
    7463             :         .type = FT_LB_LABEL_O_ADJ,
    7464             :         .label_o_adj = {
    7465             :             .adj = ai_mpls_10_10_11_1,
    7466             :             .label = 1602,
    7467             :             .eos = MPLS_EOS,
    7468             :         },
    7469             :     };
    7470           1 :     fib_mpls_label_t *l1602 = NULL, fml1602 = {
    7471             :         .fml_value = 1602,
    7472             :     };
    7473           1 :     vec_add1(l1602, fml1602);
    7474           1 :     fei = fib_table_entry_update_one_path(fib_index,
    7475             :                                           &pfx_100_s_8,
    7476             :                                           FIB_SOURCE_API,
    7477             :                                           FIB_ENTRY_FLAG_NONE,
    7478             :                                           DPO_PROTO_IP4,
    7479             :                                           &nh_10_10_11_1,
    7480           1 :                                           tm->hw[1]->sw_if_index,
    7481             :                                           ~0, // invalid fib index
    7482             :                                           1,
    7483             :                                           l1602,
    7484             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    7485             : 
    7486           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7487             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7488             :                                       1,
    7489             :                                       &l_100_eos_o_10_10_10_1),
    7490             :              "100.0.0.0/8 LB 1 buckets via: lbl 101 "
    7491             :              "adj 10.10.11.1");
    7492             : 
    7493           2 :     fib_prefix_t pfx_100_1_1_1_s_32 = {
    7494             :         .fp_len = 32,
    7495             :         .fp_proto = FIB_PROTOCOL_IP4,
    7496             :         .fp_addr = {
    7497           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x64010101),
    7498             :         },
    7499             :     };
    7500             : 
    7501           1 :     fei = fib_table_entry_special_add(fib_index,
    7502             :                                       &pfx_100_1_1_1_s_32,
    7503             :                                       FIB_SOURCE_RR,
    7504             :                                       FIB_ENTRY_FLAG_NONE);
    7505             : 
    7506           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7507             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7508             :                                       1,
    7509             :                                       &l_100_eos_o_10_10_10_1),
    7510             :              "100.1.1.1/32 LB 1 buckets via: "
    7511             :              "adj 10.10.11.1");
    7512             : 
    7513           1 :     fib_table_entry_delete(fib_index,
    7514             :                            &pfx_100_s_8,
    7515             :                            FIB_SOURCE_API);
    7516           1 :     fib_table_entry_delete_index(fei, FIB_SOURCE_RR);
    7517             : 
    7518             :     /*
    7519             :      * cleanup
    7520             :      */
    7521           1 :     fib_table_entry_delete(fib_index,
    7522             :                            &pfx_1_1_1_2_s_32,
    7523             :                            FIB_SOURCE_API);
    7524             : 
    7525           1 :     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
    7526           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7527             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7528             :                                       1,
    7529             :                                       &l1600_eos_o_1_1_1_1),
    7530             :              "2.2.2.2/32 LB 1 buckets via: "
    7531             :              "label 1600 via 1.1,1.1");
    7532             : 
    7533           1 :     fib_table_entry_delete(fib_index,
    7534             :                            &pfx_1_1_1_1_s_32,
    7535             :                            FIB_SOURCE_API);
    7536             : 
    7537           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    7538             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    7539             :                                       1,
    7540             :                                       &bucket_drop),
    7541             :              "2.2.2.2/32 LB 1 buckets via: DROP");
    7542             : 
    7543           1 :     fib_table_entry_delete(fib_index,
    7544             :                            &pfx_2_2_2_2_s_32,
    7545             :                            FIB_SOURCE_API);
    7546           1 :     fib_table_entry_delete(fib_index,
    7547             :                            &pfx_2_2_2_3_s_32,
    7548             :                            FIB_SOURCE_API);
    7549           1 :     fib_table_entry_delete(fib_index,
    7550             :                            &pfx_2_2_2_4_s_32,
    7551             :                            FIB_SOURCE_API);
    7552             : 
    7553           1 :     adj_unlock(ai_mpls_10_10_10_1);
    7554           1 :     adj_unlock(ai_mpls_10_10_11_2);
    7555           1 :     adj_unlock(ai_v4_10_10_11_1);
    7556           1 :     adj_unlock(ai_v4_10_10_11_2);
    7557           1 :     adj_unlock(ai_mpls_10_10_11_1);
    7558             : 
    7559           1 :     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
    7560             :              adj_nbr_db_size());
    7561             : 
    7562           1 :     local0_pfx.fp_len = 32;
    7563           1 :     fib_table_entry_delete(fib_index,
    7564             :                            &local0_pfx,
    7565             :                            FIB_SOURCE_INTERFACE);
    7566           1 :     local0_pfx.fp_len = 24;
    7567           1 :     fib_table_entry_delete(fib_index,
    7568             :                            &local0_pfx,
    7569             :                            FIB_SOURCE_INTERFACE);
    7570           1 :     local1_pfx.fp_len = 32;
    7571           1 :     fib_table_entry_delete(fib_index,
    7572             :                            &local1_pfx,
    7573             :                            FIB_SOURCE_INTERFACE);
    7574           1 :     local1_pfx.fp_len = 24;
    7575           1 :     fib_table_entry_delete(fib_index,
    7576             :                            &local1_pfx,
    7577             :                            FIB_SOURCE_INTERFACE);
    7578             : 
    7579             :     /*
    7580             :      * +1 for the drop LB in the MPLS tables.
    7581             :      */
    7582           1 :     FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
    7583             :              "Load-balance resources freed %d of %d",
    7584             :              lb_count+1, pool_elts(load_balance_pool));
    7585             : 
    7586           1 :     return (res);
    7587             : }
    7588             : 
    7589             : #define N_TEST_CHILDREN 4
    7590             : #define PARENT_INDEX 0
    7591             : 
    7592             : typedef struct fib_node_test_t_
    7593             : {
    7594             :     fib_node_t node;
    7595             :     u32 sibling;
    7596             :     u32 index;
    7597             :     fib_node_back_walk_ctx_t *ctxs;
    7598             :     u32 destroyed;
    7599             : } fib_node_test_t;
    7600             : 
    7601             : static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
    7602             : 
    7603             : #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
    7604             : 
    7605             : #define FOR_EACH_TEST_CHILD(_tc)                \
    7606             :     for (ii = 1, (_tc) = &fib_test_nodes[1];    \
    7607             :          ii < N_TEST_CHILDREN+1;                \
    7608             :          ii++, (_tc) = &fib_test_nodes[ii])
    7609             : 
    7610             : static fib_node_t *
    7611         349 : fib_test_child_get_node (fib_node_index_t index)
    7612             : {
    7613         349 :     return (&fib_test_nodes[index].node);
    7614             : }
    7615             : 
    7616             : static int fib_test_walk_spawns_walks;
    7617             : static fib_node_type_t test_node_type;
    7618             : 
    7619             : static fib_node_back_walk_rc_t
    7620         132 : fib_test_child_back_walk_notify (fib_node_t *node,
    7621             :                                  fib_node_back_walk_ctx_t *ctx)
    7622             : {
    7623         132 :     fib_node_test_t *tc = (fib_node_test_t*) node;
    7624             : 
    7625         132 :     vec_add1(tc->ctxs, *ctx);
    7626             : 
    7627         132 :     if (1 == fib_test_walk_spawns_walks)
    7628          16 :         fib_walk_sync(test_node_type, tc->index, ctx);
    7629         132 :     if (2 == fib_test_walk_spawns_walks)
    7630          80 :         fib_walk_async(test_node_type, tc->index,
    7631             :                        FIB_WALK_PRIORITY_HIGH, ctx);
    7632             : 
    7633         132 :     return (FIB_NODE_BACK_WALK_CONTINUE);
    7634             : }
    7635             : 
    7636             : static void
    7637           5 : fib_test_child_last_lock_gone (fib_node_t *node)
    7638             : {
    7639           5 :     fib_node_test_t *tc = (fib_node_test_t *)node;
    7640             : 
    7641           5 :     tc->destroyed = 1;
    7642           5 : }
    7643             : 
    7644             : /**
    7645             :  * The FIB walk's graph node virtual function table
    7646             :  */
    7647             : static const fib_node_vft_t fib_test_child_vft = {
    7648             :     .fnv_get = fib_test_child_get_node,
    7649             :     .fnv_last_lock = fib_test_child_last_lock_gone,
    7650             :     .fnv_back_walk = fib_test_child_back_walk_notify,
    7651             : };
    7652             : 
    7653             : /*
    7654             :  * the function (that should have been static but isn't so I can do this)
    7655             :  * that processes the walk from the async queue,
    7656             :  */
    7657             : f64 fib_walk_process_queues(vlib_main_t * vm,
    7658             :                             const f64 quota);
    7659             : u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
    7660             : 
    7661             : static int
    7662           1 : fib_test_walk (void)
    7663             : {
    7664           1 :     fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
    7665             :     fib_node_test_t *tc;
    7666             :     vlib_main_t *vm;
    7667             :     u32 ii, res;
    7668             : 
    7669           1 :     res = 0;
    7670           1 :     vm = vlib_get_main();
    7671           1 :     test_node_type = fib_node_register_new_type("fib-test", &fib_test_child_vft);
    7672             : 
    7673             :     /*
    7674             :      * init a fake node on which we will add children
    7675             :      */
    7676           1 :     fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
    7677             :                   test_node_type);
    7678             : 
    7679           5 :     FOR_EACH_TEST_CHILD(tc)
    7680             :     {
    7681           4 :         fib_node_init(&tc->node, test_node_type);
    7682           4 :         fib_node_lock(&tc->node);
    7683           4 :         tc->ctxs = NULL;
    7684           4 :         tc->index = ii;
    7685           4 :         tc->sibling = fib_node_child_add(test_node_type,
    7686             :                                          PARENT_INDEX,
    7687             :                                          test_node_type, ii);
    7688             :     }
    7689             : 
    7690             :     /*
    7691             :      * enqueue a walk across the parents children.
    7692             :      */
    7693           1 :     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
    7694             : 
    7695           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7696             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    7697           1 :     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
    7698             :              "Parent has %d children pre-walk",
    7699             :              fib_node_list_get_size(PARENT()->fn_children));
    7700             : 
    7701             :     /*
    7702             :      * give the walk a large amount of time so it gets to the end
    7703             :      */
    7704           1 :     fib_walk_process_queues(vm, 1);
    7705             : 
    7706           5 :     FOR_EACH_TEST_CHILD(tc)
    7707             :     {
    7708           4 :         FIB_TEST(1 == vec_len(tc->ctxs),
    7709             :                  "%d child visitsed %d times",
    7710             :                  ii, vec_len(tc->ctxs));
    7711           4 :         vec_free(tc->ctxs);
    7712             :     }
    7713           1 :     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
    7714             :              "Queue is empty post walk");
    7715           1 :     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
    7716             :              "Parent has %d children post walk",
    7717             :              fib_node_list_get_size(PARENT()->fn_children));
    7718             : 
    7719             :     /*
    7720             :      * walk again. should be no increase in the number of visits, since
    7721             :      * the walk will have terminated.
    7722             :      */
    7723           1 :     fib_walk_process_queues(vm, 1);
    7724             : 
    7725           5 :     FOR_EACH_TEST_CHILD(tc)
    7726             :     {
    7727           4 :         FIB_TEST(0 == vec_len(tc->ctxs),
    7728             :                  "%d child visitsed %d times",
    7729             :                  ii, vec_len(tc->ctxs));
    7730             :     }
    7731             : 
    7732             :     /*
    7733             :      * schedule a low and hig priority walk. expect the high to be performed
    7734             :      * before the low.
    7735             :      * schedule the high prio walk first so that it is further from the head
    7736             :      * of the dependency list. that way it won't merge with the low one.
    7737             :      */
    7738           1 :     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
    7739           1 :     low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
    7740             : 
    7741           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7742             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    7743           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7744             :                    FIB_WALK_PRIORITY_LOW, &low_ctx);
    7745             : 
    7746           1 :     fib_walk_process_queues(vm, 1);
    7747             : 
    7748           5 :     FOR_EACH_TEST_CHILD(tc)
    7749             :     {
    7750           4 :         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
    7751             :                  "%d child visitsed by high prio walk", ii);
    7752           4 :         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
    7753             :                  "%d child visitsed by low prio walk", ii);
    7754           4 :         vec_free(tc->ctxs);
    7755             :     }
    7756           1 :     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
    7757             :              "Queue is empty post prio walk");
    7758           1 :     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
    7759             :              "Parent has %d children post prio walk",
    7760             :              fib_node_list_get_size(PARENT()->fn_children));
    7761             : 
    7762             :     /*
    7763             :      * schedule 2 walks of the same priority that can be megred.
    7764             :      * expect that each child is thus visited only once.
    7765             :      */
    7766           1 :     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
    7767           1 :     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_RESOLVE;
    7768             : 
    7769           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7770             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    7771           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7772             :                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
    7773             : 
    7774           1 :     fib_walk_process_queues(vm, 1);
    7775             : 
    7776           5 :     FOR_EACH_TEST_CHILD(tc)
    7777             :     {
    7778           4 :         FIB_TEST(1 == vec_len(tc->ctxs),
    7779             :                  "%d child visitsed %d times during merge walk",
    7780             :                  ii, vec_len(tc->ctxs));
    7781           4 :         vec_free(tc->ctxs);
    7782             :     }
    7783           1 :     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
    7784             :              "Queue is empty post merge walk");
    7785           1 :     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
    7786             :              "Parent has %d children post merge walk",
    7787             :              fib_node_list_get_size(PARENT()->fn_children));
    7788             : 
    7789             :     /*
    7790             :      * schedule 2 walks of the same priority that cannot be megred.
    7791             :      * expect that each child is thus visited twice and in the order
    7792             :      * in which the walks were scheduled.
    7793             :      */
    7794           1 :     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
    7795           1 :     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
    7796             : 
    7797           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7798             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    7799           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7800             :                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
    7801             : 
    7802           1 :     fib_walk_process_queues(vm, 1);
    7803             : 
    7804           5 :     FOR_EACH_TEST_CHILD(tc)
    7805             :     {
    7806           4 :         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
    7807             :                  "%d child visitsed by high prio walk", ii);
    7808           4 :         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
    7809             :                  "%d child visitsed by low prio walk", ii);
    7810           4 :         vec_free(tc->ctxs);
    7811             :     }
    7812           1 :     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
    7813             :              "Queue is empty post no-merge walk");
    7814           1 :     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
    7815             :              "Parent has %d children post no-merge walk",
    7816             :              fib_node_list_get_size(PARENT()->fn_children));
    7817             : 
    7818             :     /*
    7819             :      * schedule a walk that makes one one child progress.
    7820             :      * we do this by giving the queue draining process zero
    7821             :      * time quanta. it's a do..while loop, so it does something.
    7822             :      */
    7823           1 :     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
    7824             : 
    7825           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7826             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    7827           1 :     fib_walk_process_queues(vm, 0);
    7828             : 
    7829           5 :     FOR_EACH_TEST_CHILD(tc)
    7830             :     {
    7831           4 :         if (ii == N_TEST_CHILDREN)
    7832             :         {
    7833           1 :             FIB_TEST(1 == vec_len(tc->ctxs),
    7834             :                      "%d child visitsed %d times in zero quanta walk",
    7835             :                      ii, vec_len(tc->ctxs));
    7836             :         }
    7837             :         else
    7838             :         {
    7839           3 :             FIB_TEST(0 == vec_len(tc->ctxs),
    7840             :                      "%d child visitsed %d times in 0 quanta walk",
    7841             :                      ii, vec_len(tc->ctxs));
    7842             :         }
    7843             :     }
    7844           1 :     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
    7845             :              "Queue is not empty post zero quanta walk");
    7846           1 :     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
    7847             :              "Parent has %d children post zero qunta walk",
    7848             :              fib_node_list_get_size(PARENT()->fn_children));
    7849             : 
    7850             :     /*
    7851             :      * another one step
    7852             :      */
    7853           1 :     fib_walk_process_queues(vm, 0);
    7854             : 
    7855           5 :     FOR_EACH_TEST_CHILD(tc)
    7856             :     {
    7857           4 :         if (ii >= N_TEST_CHILDREN-1)
    7858             :         {
    7859           2 :             FIB_TEST(1 == vec_len(tc->ctxs),
    7860             :                      "%d child visitsed %d times in 2nd zero quanta walk",
    7861             :                      ii, vec_len(tc->ctxs));
    7862             :         }
    7863             :         else
    7864             :         {
    7865           2 :             FIB_TEST(0 == vec_len(tc->ctxs),
    7866             :                      "%d child visitsed %d times in 2nd 0 quanta walk",
    7867             :                      ii, vec_len(tc->ctxs));
    7868             :         }
    7869             :     }
    7870           1 :     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
    7871             :              "Queue is not empty post zero quanta walk");
    7872           1 :     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
    7873             :              "Parent has %d children post zero qunta walk",
    7874             :              fib_node_list_get_size(PARENT()->fn_children));
    7875             : 
    7876             :     /*
    7877             :      * schedule another walk that will catch-up and merge.
    7878             :      */
    7879           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7880             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    7881           1 :     fib_walk_process_queues(vm, 1);
    7882             : 
    7883           5 :     FOR_EACH_TEST_CHILD(tc)
    7884             :     {
    7885           4 :         if (ii >= N_TEST_CHILDREN-1)
    7886             :         {
    7887           2 :             FIB_TEST(2 == vec_len(tc->ctxs),
    7888             :                      "%d child visitsed %d times in 2nd zero quanta merge walk",
    7889             :                      ii, vec_len(tc->ctxs));
    7890           2 :             vec_free(tc->ctxs);
    7891             :         }
    7892             :         else
    7893             :         {
    7894           2 :             FIB_TEST(1 == vec_len(tc->ctxs),
    7895             :                      "%d child visitsed %d times in 2nd 0 quanta merge walk",
    7896             :                      ii, vec_len(tc->ctxs));
    7897           2 :             vec_free(tc->ctxs);
    7898             :         }
    7899             :     }
    7900           1 :     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
    7901             :              "Queue is not empty post 2nd zero quanta merge walk");
    7902           1 :     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
    7903             :              "Parent has %d children post 2nd zero qunta merge walk",
    7904             :              fib_node_list_get_size(PARENT()->fn_children));
    7905             : 
    7906             :     /*
    7907             :      * park a async walk in the middle of the list, then have an sync walk catch
    7908             :      * it. same expectations as async catches async.
    7909             :      */
    7910           1 :     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
    7911             : 
    7912           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    7913             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    7914             : 
    7915           1 :     fib_walk_process_queues(vm, 0);
    7916           1 :     fib_walk_process_queues(vm, 0);
    7917             : 
    7918           1 :     fib_walk_sync(test_node_type, PARENT_INDEX, &high_ctx);
    7919             : 
    7920           5 :     FOR_EACH_TEST_CHILD(tc)
    7921             :     {
    7922           4 :         if (ii >= N_TEST_CHILDREN-1)
    7923             :         {
    7924           2 :             FIB_TEST(2 == vec_len(tc->ctxs),
    7925             :                      "%d child visitsed %d times in sync catches async walk",
    7926             :                      ii, vec_len(tc->ctxs));
    7927           2 :             vec_free(tc->ctxs);
    7928             :         }
    7929             :         else
    7930             :         {
    7931           2 :             FIB_TEST(1 == vec_len(tc->ctxs),
    7932             :                      "%d child visitsed %d times in sync catches async walk",
    7933             :                      ii, vec_len(tc->ctxs));
    7934           2 :             vec_free(tc->ctxs);
    7935             :         }
    7936             :     }
    7937           1 :     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
    7938             :              "Queue is not empty post 2nd zero quanta merge walk");
    7939           1 :     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
    7940             :              "Parent has %d children post 2nd zero qunta merge walk",
    7941             :              fib_node_list_get_size(PARENT()->fn_children));
    7942             : 
    7943             :     /*
    7944             :      * make the parent a child of one of its children, thus inducing a routing loop.
    7945             :      */
    7946           1 :     fib_test_nodes[PARENT_INDEX].sibling =
    7947           1 :         fib_node_child_add(test_node_type,
    7948             :                            1, // the first child
    7949             :                            test_node_type,
    7950             :                            PARENT_INDEX);
    7951             : 
    7952             :     /*
    7953             :      * execute a sync walk from the parent. each child visited spawns more sync
    7954             :      * walks. we expect the walk to terminate.
    7955             :      */
    7956           1 :     fib_test_walk_spawns_walks = 1;
    7957             : 
    7958           1 :     fib_walk_sync(test_node_type, PARENT_INDEX, &high_ctx);
    7959             : 
    7960           5 :     FOR_EACH_TEST_CHILD(tc)
    7961             :     {
    7962             :         /*
    7963             :          * child 1 - which is last in the list - has the loop.
    7964             :          * the other children a re thus visitsed first. the we meet
    7965             :          * child 1. we go round the loop again, visting the other children.
    7966             :          * then we meet the walk in the dep list and bail. child 1 is not visitsed
    7967             :          * again.
    7968             :          */
    7969           4 :         if (1 == ii)
    7970             :         {
    7971           1 :             FIB_TEST(1 == vec_len(tc->ctxs),
    7972             :                      "child %d visitsed %d times during looped sync walk",
    7973             :                      ii, vec_len(tc->ctxs));
    7974             :         }
    7975             :         else
    7976             :         {
    7977           3 :             FIB_TEST(2 == vec_len(tc->ctxs),
    7978             :                      "child %d visitsed %d times during looped sync walk",
    7979             :                      ii, vec_len(tc->ctxs));
    7980             :         }
    7981           4 :         vec_free(tc->ctxs);
    7982             :     }
    7983           1 :     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
    7984             :              "Parent has %d children post sync loop walk",
    7985             :              fib_node_list_get_size(PARENT()->fn_children));
    7986             : 
    7987             :     /*
    7988             :      * the walk doesn't reach the max depth because the infra knows that sync
    7989             :      * meets sync implies a loop and bails early.
    7990             :      */
    7991           1 :     FIB_TEST(high_ctx.fnbw_depth == 9,
    7992             :              "Walk context depth %d post sync loop walk",
    7993             :              high_ctx.fnbw_depth);
    7994             : 
    7995             :     /*
    7996             :      * execute an async walk of the graph loop, with each child spawns sync walks
    7997             :      */
    7998           1 :     high_ctx.fnbw_depth = 0;
    7999           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    8000             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    8001             : 
    8002           1 :     fib_walk_process_queues(vm, 1);
    8003             : 
    8004           5 :     FOR_EACH_TEST_CHILD(tc)
    8005             :     {
    8006             :         /*
    8007             :          * we don't really care how many times the children are visited, as long as
    8008             :          * it is more than once.
    8009             :          */
    8010           4 :         FIB_TEST(1 <= vec_len(tc->ctxs),
    8011             :                  "child %d visitsed %d times during looped aync spawns sync walk",
    8012             :                  ii, vec_len(tc->ctxs));
    8013           4 :         vec_free(tc->ctxs);
    8014             :     }
    8015             : 
    8016             :     /*
    8017             :      * execute an async walk of the graph loop, with each child spawns async walks
    8018             :      */
    8019           1 :     fib_test_walk_spawns_walks = 2;
    8020           1 :     high_ctx.fnbw_depth = 0;
    8021           1 :     fib_walk_async(test_node_type, PARENT_INDEX,
    8022             :                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
    8023             : 
    8024           1 :     fib_walk_process_queues(vm, 1);
    8025             : 
    8026           5 :     FOR_EACH_TEST_CHILD(tc)
    8027             :     {
    8028             :         /*
    8029             :          * we don't really care how many times the children are visited, as long as
    8030             :          * it is more than once.
    8031             :          */
    8032           4 :         FIB_TEST(1 <= vec_len(tc->ctxs),
    8033             :                  "child %d visitsed %d times during looped async spawns async walk",
    8034             :                  ii, vec_len(tc->ctxs));
    8035           4 :         vec_free(tc->ctxs);
    8036             :     }
    8037             : 
    8038             : 
    8039           1 :     fib_node_child_remove(test_node_type,
    8040             :                           1, // the first child
    8041             :                           fib_test_nodes[PARENT_INDEX].sibling);
    8042             : 
    8043             :     /*
    8044             :      * cleanup
    8045             :      */
    8046           5 :     FOR_EACH_TEST_CHILD(tc)
    8047             :     {
    8048           4 :         fib_node_child_remove(test_node_type, PARENT_INDEX,
    8049             :                               tc->sibling);
    8050           4 :         fib_node_deinit(&tc->node);
    8051           4 :         fib_node_unlock(&tc->node);
    8052             :     }
    8053           1 :     fib_node_deinit(PARENT());
    8054             : 
    8055             :     /*
    8056             :      * The parent will be destroyed when the last lock on it goes.
    8057             :      * this test ensures all the walk objects are unlocking it.
    8058             :      */
    8059           1 :     FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
    8060             :              "Parent was destroyed");
    8061             : 
    8062           1 :     return (res);
    8063             : }
    8064             : 
    8065             : /*
    8066             :  * declaration of the otherwise static callback functions
    8067             :  */
    8068             : void fib_bfd_notify (bfd_listen_event_e event,
    8069             :                      const bfd_session_t *session);
    8070             : void adj_bfd_notify (bfd_listen_event_e event,
    8071             :                      const bfd_session_t *session);
    8072             : 
    8073             : /**
    8074             :  * Test BFD session interaction with FIB
    8075             :  */
    8076             : static int
    8077           1 : fib_test_bfd (void)
    8078             : {
    8079             :     fib_node_index_t fei;
    8080             :     test_main_t *tm;
    8081             :     int n_feis, res;
    8082             : 
    8083           1 :     res = 0;
    8084             :     /* via 10.10.10.1 */
    8085           2 :     ip46_address_t nh_10_10_10_1 = {
    8086           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
    8087             :     };
    8088             :     /* via 10.10.10.2 */
    8089           2 :     ip46_address_t nh_10_10_10_2 = {
    8090           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
    8091             :     };
    8092             :     /* via 10.10.10.10 */
    8093           2 :     ip46_address_t nh_10_10_10_10 = {
    8094           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
    8095             :     };
    8096           1 :     n_feis = fib_entry_pool_size();
    8097             : 
    8098           1 :     tm = &test_main;
    8099             : 
    8100             :     /*
    8101             :      * add interface routes. we'll assume this works. it's tested elsewhere
    8102             :      */
    8103           1 :     fib_prefix_t pfx_10_10_10_10_s_24 = {
    8104             :         .fp_len = 24,
    8105             :         .fp_proto = FIB_PROTOCOL_IP4,
    8106             :         .fp_addr = nh_10_10_10_10,
    8107             :     };
    8108             : 
    8109           1 :     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
    8110             :                                     FIB_SOURCE_INTERFACE,
    8111             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    8112             :                                      FIB_ENTRY_FLAG_ATTACHED),
    8113             :                                     DPO_PROTO_IP4,
    8114             :                                     NULL,
    8115           1 :                                     tm->hw[0]->sw_if_index,
    8116             :                                     ~0, // invalid fib index
    8117             :                                     1, // weight
    8118             :                                     NULL,
    8119             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    8120             : 
    8121           1 :     fib_prefix_t pfx_10_10_10_10_s_32 = {
    8122             :         .fp_len = 32,
    8123             :         .fp_proto = FIB_PROTOCOL_IP4,
    8124             :         .fp_addr = nh_10_10_10_10,
    8125             :     };
    8126           1 :     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
    8127             :                                     FIB_SOURCE_INTERFACE,
    8128             :                                     (FIB_ENTRY_FLAG_CONNECTED |
    8129             :                                      FIB_ENTRY_FLAG_LOCAL),
    8130             :                                     DPO_PROTO_IP4,
    8131             :                                     NULL,
    8132           1 :                                     tm->hw[0]->sw_if_index,
    8133             :                                     ~0, // invalid fib index
    8134             :                                     1, // weight
    8135             :                                     NULL,
    8136             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    8137             : 
    8138             :     /*
    8139             :      * A BFD session via a neighbour we do not yet know
    8140             :      */
    8141           1 :     bfd_session_t bfd_10_10_10_1 = {
    8142             :         .udp = {
    8143             :             .key = {
    8144             :                 .fib_index = 0,
    8145             :                 .peer_addr = nh_10_10_10_1,
    8146             :             },
    8147             :         },
    8148             :         .hop_type = BFD_HOP_TYPE_MULTI,
    8149             :         .local_state = BFD_STATE_init,
    8150             :     };
    8151             : 
    8152           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
    8153             : 
    8154             :     /*
    8155             :      * A new entry will be created that forwards via the adj
    8156             :      */
    8157           1 :     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    8158             :                                                     VNET_LINK_IP4,
    8159             :                                                     &nh_10_10_10_1,
    8160           1 :                                                     tm->hw[0]->sw_if_index);
    8161           1 :     fib_prefix_t pfx_10_10_10_1_s_32 = {
    8162             :         .fp_addr = nh_10_10_10_1,
    8163             :         .fp_len = 32,
    8164             :         .fp_proto = FIB_PROTOCOL_IP4,
    8165             :     };
    8166           1 :     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
    8167             :         .type = FT_LB_ADJ,
    8168             :         .adj = {
    8169             :             .adj = ai_10_10_10_1,
    8170             :         },
    8171             :     };
    8172             : 
    8173           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
    8174           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8175             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8176             :                                       1,
    8177             :                                       &adj_o_10_10_10_1),
    8178             :              "BFD sourced %U via %U",
    8179             :              format_fib_prefix, &pfx_10_10_10_1_s_32,
    8180             :              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
    8181             : 
    8182             :     /*
    8183             :      * Delete the BFD session. Expect the fib_entry to be removed
    8184             :      */
    8185           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
    8186             : 
    8187           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
    8188           1 :     FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
    8189             :              "BFD sourced %U removed",
    8190             :              format_fib_prefix, &pfx_10_10_10_1_s_32);
    8191             : 
    8192             :     /*
    8193             :      * Add the BFD source back
    8194             :      */
    8195           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
    8196             : 
    8197             :     /*
    8198             :      * source the entry via the ADJ fib
    8199             :      */
    8200           1 :     fei = fib_table_entry_path_add(0,
    8201             :                                    &pfx_10_10_10_1_s_32,
    8202             :                                    FIB_SOURCE_ADJ,
    8203             :                                    FIB_ENTRY_FLAG_ATTACHED,
    8204             :                                    DPO_PROTO_IP4,
    8205             :                                    &nh_10_10_10_1,
    8206           1 :                                    tm->hw[0]->sw_if_index,
    8207             :                                    ~0, // invalid fib index
    8208             :                                    1,
    8209             :                                    NULL,
    8210             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    8211             : 
    8212             :     /*
    8213             :      * Delete the BFD session. Expect the fib_entry to remain
    8214             :      */
    8215           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
    8216             : 
    8217           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
    8218           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8219             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8220             :                                       1,
    8221             :                                       &adj_o_10_10_10_1),
    8222             :              "BFD sourced %U remains via %U",
    8223             :              format_fib_prefix, &pfx_10_10_10_1_s_32,
    8224             :              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
    8225             : 
    8226             :     /*
    8227             :      * Add the BFD source back
    8228             :      */
    8229           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
    8230             : 
    8231             :     /*
    8232             :      * Create another ADJ FIB
    8233             :      */
    8234           1 :     fib_prefix_t pfx_10_10_10_2_s_32 = {
    8235             :         .fp_addr = nh_10_10_10_2,
    8236             :         .fp_len = 32,
    8237             :         .fp_proto = FIB_PROTOCOL_IP4,
    8238             :     };
    8239           1 :     fib_table_entry_path_add(0,
    8240             :                              &pfx_10_10_10_2_s_32,
    8241             :                              FIB_SOURCE_ADJ,
    8242             :                              FIB_ENTRY_FLAG_ATTACHED,
    8243             :                              DPO_PROTO_IP4,
    8244             :                              &nh_10_10_10_2,
    8245           1 :                              tm->hw[0]->sw_if_index,
    8246             :                              ~0, // invalid fib index
    8247             :                              1,
    8248             :                              NULL,
    8249             :                              FIB_ROUTE_PATH_FLAG_NONE);
    8250             :     /*
    8251             :      * A BFD session for the new ADJ FIB
    8252             :      */
    8253           1 :     bfd_session_t bfd_10_10_10_2 = {
    8254             :         .udp = {
    8255             :             .key = {
    8256             :                 .fib_index = 0,
    8257             :                 .peer_addr = nh_10_10_10_2,
    8258             :             },
    8259             :         },
    8260             :         .hop_type = BFD_HOP_TYPE_MULTI,
    8261             :         .local_state = BFD_STATE_init,
    8262             :     };
    8263             : 
    8264           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
    8265             : 
    8266             :     /*
    8267             :      * remove the adj-fib source whilst the session is present
    8268             :      * then add it back
    8269             :      */
    8270           1 :     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
    8271           1 :     fib_table_entry_path_add(0,
    8272             :                              &pfx_10_10_10_2_s_32,
    8273             :                              FIB_SOURCE_ADJ,
    8274             :                              FIB_ENTRY_FLAG_ATTACHED,
    8275             :                              DPO_PROTO_IP4,
    8276             :                              &nh_10_10_10_2,
    8277           1 :                              tm->hw[0]->sw_if_index,
    8278             :                              ~0, // invalid fib index
    8279             :                              1,
    8280             :                              NULL,
    8281             :                              FIB_ROUTE_PATH_FLAG_NONE);
    8282             : 
    8283             :     /*
    8284             :      * Before adding a recursive via the BFD tracked ADJ-FIBs,
    8285             :      * bring one of the sessions UP, leave the other down
    8286             :      */
    8287           1 :     bfd_10_10_10_1.local_state = BFD_STATE_up;
    8288           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
    8289           1 :     bfd_10_10_10_2.local_state = BFD_STATE_down;
    8290           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
    8291             : 
    8292             :     /*
    8293             :      * A recursive prefix via both of the ADJ FIBs
    8294             :      */
    8295           2 :     fib_prefix_t pfx_200_0_0_0_s_24 = {
    8296             :         .fp_proto = FIB_PROTOCOL_IP4,
    8297             :         .fp_len = 32,
    8298             :         .fp_addr = {
    8299           1 :             .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
    8300             :         },
    8301             :     };
    8302             :     const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
    8303             : 
    8304             :     dpo_10_10_10_1 =
    8305           1 :         fib_entry_contribute_ip_forwarding(
    8306             :             fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
    8307             :     dpo_10_10_10_2 =
    8308           1 :         fib_entry_contribute_ip_forwarding(
    8309             :             fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
    8310             : 
    8311           1 :     fib_test_lb_bucket_t lb_o_10_10_10_1 = {
    8312             :         .type = FT_LB_O_LB,
    8313             :         .lb = {
    8314           1 :             .lb = dpo_10_10_10_1->dpoi_index,
    8315             :         },
    8316             :     };
    8317           1 :     fib_test_lb_bucket_t lb_o_10_10_10_2 = {
    8318             :         .type = FT_LB_O_LB,
    8319             :         .lb = {
    8320           1 :             .lb = dpo_10_10_10_2->dpoi_index,
    8321             :         },
    8322             :     };
    8323             : 
    8324             :     /*
    8325             :      * A prefix via the adj-fib that is BFD down => DROP
    8326             :      */
    8327           1 :     fei = fib_table_entry_path_add(0,
    8328             :                                    &pfx_200_0_0_0_s_24,
    8329             :                                    FIB_SOURCE_API,
    8330             :                                    FIB_ENTRY_FLAG_NONE,
    8331             :                                    DPO_PROTO_IP4,
    8332             :                                    &nh_10_10_10_2,
    8333             :                                    ~0, // recursive
    8334             :                                    0, // default fib index
    8335             :                                    1,
    8336             :                                    NULL,
    8337             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    8338           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    8339             :              "%U resolves via drop",
    8340             :              format_fib_prefix, &pfx_200_0_0_0_s_24);
    8341             : 
    8342             :     /*
    8343             :      * add a path via the UP BFD adj-fib.
    8344             :      *  we expect that the DOWN BFD ADJ FIB is not used.
    8345             :      */
    8346           1 :     fei = fib_table_entry_path_add(0,
    8347             :                                    &pfx_200_0_0_0_s_24,
    8348             :                                    FIB_SOURCE_API,
    8349             :                                    FIB_ENTRY_FLAG_NONE,
    8350             :                                    DPO_PROTO_IP4,
    8351             :                                    &nh_10_10_10_1,
    8352             :                                    ~0, // recursive
    8353             :                                    0, // default fib index
    8354             :                                    1,
    8355             :                                    NULL,
    8356             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    8357             : 
    8358           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8359             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8360             :                                       1,
    8361             :                                       &lb_o_10_10_10_1),
    8362             :              "Recursive %U only UP BFD adj-fibs",
    8363             :              format_fib_prefix, &pfx_200_0_0_0_s_24);
    8364             : 
    8365             :     /*
    8366             :      * Send a BFD state change to UP - both sessions are now up
    8367             :      *  the recursive prefix should LB over both
    8368             :      */
    8369           1 :     bfd_10_10_10_2.local_state = BFD_STATE_up;
    8370           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
    8371             : 
    8372             : 
    8373           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8374             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8375             :                                       2,
    8376             :                                       &lb_o_10_10_10_1,
    8377             :                                       &lb_o_10_10_10_2),
    8378             :              "Recursive %U via both UP BFD adj-fibs",
    8379             :              format_fib_prefix, &pfx_200_0_0_0_s_24);
    8380             : 
    8381             :     /*
    8382             :      * Send a BFD state change to DOWN
    8383             :      *  the recursive prefix should exclude the down
    8384             :      */
    8385           1 :     bfd_10_10_10_2.local_state = BFD_STATE_down;
    8386           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
    8387             : 
    8388             : 
    8389           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8390             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8391             :                                       1,
    8392             :                                       &lb_o_10_10_10_1),
    8393             :              "Recursive %U via only UP",
    8394             :              format_fib_prefix, &pfx_200_0_0_0_s_24);
    8395             : 
    8396             :     /*
    8397             :      * Delete the BFD session while it is in the DOWN state.
    8398             :      *  FIB should consider the entry's state as back up
    8399             :      */
    8400           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
    8401             : 
    8402           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8403             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8404             :                                       2,
    8405             :                                       &lb_o_10_10_10_1,
    8406             :                                       &lb_o_10_10_10_2),
    8407             :              "Recursive %U via both UP BFD adj-fibs post down session delete",
    8408             :              format_fib_prefix, &pfx_200_0_0_0_s_24);
    8409             : 
    8410             :     /*
    8411             :      * Delete the BFD other session while it is in the UP state.
    8412             :      */
    8413           1 :     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
    8414             : 
    8415           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8416             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8417             :                                       2,
    8418             :                                       &lb_o_10_10_10_1,
    8419             :                                       &lb_o_10_10_10_2),
    8420             :              "Recursive %U via both UP BFD adj-fibs post up session delete",
    8421             :              format_fib_prefix, &pfx_200_0_0_0_s_24);
    8422             : 
    8423             :     /*
    8424             :      * cleaup
    8425             :      */
    8426           1 :     fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
    8427           1 :     fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
    8428           1 :     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
    8429             : 
    8430           1 :     fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
    8431           1 :     fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
    8432             : 
    8433           1 :     adj_unlock(ai_10_10_10_1);
    8434             :     /*
    8435             :      * test no-one left behind
    8436             :      */
    8437           1 :     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
    8438           1 :     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
    8439             : 
    8440             :     /*
    8441             :      * Single-hop BFD tests
    8442             :      */
    8443           1 :     bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
    8444           1 :     bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
    8445             : 
    8446           1 :     ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    8447             :                                         VNET_LINK_IP4,
    8448             :                                         &nh_10_10_10_1,
    8449           1 :                                         tm->hw[0]->sw_if_index);
    8450           1 :     bfd_10_10_10_1.udp.adj_index = ai_10_10_10_1;
    8451             : 
    8452           1 :     adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
    8453             : 
    8454             :     /*
    8455             :      * whilst the BFD session is not signalled, the adj is up
    8456             :      */
    8457           1 :     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on uninit session");
    8458             : 
    8459             :     /*
    8460             :      * bring the BFD session up
    8461             :      */
    8462           1 :     bfd_10_10_10_1.local_state = BFD_STATE_up;
    8463           1 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
    8464           1 :     FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
    8465             : 
    8466             :     /*
    8467             :      * bring the BFD session down
    8468             :      */
    8469           1 :     bfd_10_10_10_1.local_state = BFD_STATE_down;
    8470           1 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
    8471           1 :     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
    8472             : 
    8473             :     /*
    8474             :      * add an attached next hop FIB entry via the down adj
    8475             :      */
    8476           2 :     fib_prefix_t pfx_5_5_5_5_s_32 = {
    8477             :         .fp_addr = {
    8478             :             .ip4 = {
    8479           1 :                 .as_u32 = clib_host_to_net_u32(0x05050505),
    8480             :             },
    8481             :         },
    8482             :         .fp_len = 32,
    8483             :         .fp_proto = FIB_PROTOCOL_IP4,
    8484             :     };
    8485             : 
    8486           1 :     fei = fib_table_entry_path_add(0,
    8487             :                                    &pfx_5_5_5_5_s_32,
    8488             :                                    FIB_SOURCE_CLI,
    8489             :                                    FIB_ENTRY_FLAG_NONE,
    8490             :                                    DPO_PROTO_IP4,
    8491             :                                    &nh_10_10_10_1,
    8492           1 :                                    tm->hw[0]->sw_if_index,
    8493             :                                    ~0, // invalid fib index
    8494             :                                    1,
    8495             :                                    NULL,
    8496             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    8497           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    8498             :              "%U resolves via drop",
    8499             :              format_fib_prefix, &pfx_5_5_5_5_s_32);
    8500             : 
    8501             :     /*
    8502             :      * Add a path via an ADJ that is up
    8503             :      */
    8504           1 :     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    8505             :                                                     VNET_LINK_IP4,
    8506             :                                                     &nh_10_10_10_2,
    8507           1 :                                                     tm->hw[0]->sw_if_index);
    8508             : 
    8509           1 :     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
    8510             :         .type = FT_LB_ADJ,
    8511             :         .adj = {
    8512             :             .adj = ai_10_10_10_2,
    8513             :         },
    8514             :     };
    8515           1 :     adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
    8516             : 
    8517           1 :     fei = fib_table_entry_path_add(0,
    8518             :                                    &pfx_5_5_5_5_s_32,
    8519             :                                    FIB_SOURCE_CLI,
    8520             :                                    FIB_ENTRY_FLAG_NONE,
    8521             :                                    DPO_PROTO_IP4,
    8522             :                                    &nh_10_10_10_2,
    8523           1 :                                    tm->hw[0]->sw_if_index,
    8524             :                                    ~0, // invalid fib index
    8525             :                                    1,
    8526             :                                    NULL,
    8527             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    8528             : 
    8529           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8530             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8531             :                                       1,
    8532             :                                       &adj_o_10_10_10_2),
    8533             :              "BFD sourced %U via %U",
    8534             :              format_fib_prefix, &pfx_5_5_5_5_s_32,
    8535             :              format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
    8536             : 
    8537             :     /*
    8538             :      * Bring up the down session - should now LB
    8539             :      */
    8540           1 :     bfd_10_10_10_1.local_state = BFD_STATE_up;
    8541           1 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
    8542           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    8543             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8544             :                                       2,
    8545             :                                       &adj_o_10_10_10_1,
    8546             :                                       &adj_o_10_10_10_2),
    8547             :              "BFD sourced %U via noth adjs",
    8548             :              format_fib_prefix, &pfx_5_5_5_5_s_32);
    8549             : 
    8550             :     /*
    8551             :      * remove the BFD session state from the adj
    8552             :      */
    8553           1 :     adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
    8554             : 
    8555             :     /*
    8556             :      * clean-up
    8557             :      */
    8558           1 :     fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
    8559           1 :     adj_unlock(ai_10_10_10_1);
    8560           1 :     adj_unlock(ai_10_10_10_2);
    8561             : 
    8562             :     /*
    8563             :      * test no-one left behind
    8564             :      */
    8565           1 :     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
    8566           1 :     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
    8567             : 
    8568           1 :     return (res);
    8569             : }
    8570             : 
    8571             : static int
    8572           1 : lfib_test (void)
    8573             : {
    8574           1 :     const mpls_label_t deag_label = 50;
    8575             :     adj_index_t ai_mpls_10_10_10_1;
    8576           1 :     dpo_id_t dpo = DPO_INVALID;
    8577           1 :     const u32 lfib_index = 0;
    8578           1 :     const u32 fib_index = 0;
    8579             :     const dpo_id_t *dpo1;
    8580             :     fib_node_index_t lfe;
    8581             :     lookup_dpo_t *lkd;
    8582             :     int lb_count, res;
    8583             :     test_main_t *tm;
    8584             : 
    8585           1 :     res = 0;
    8586           1 :     tm = &test_main;
    8587           1 :     lb_count = pool_elts(load_balance_pool);
    8588             : 
    8589           1 :     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
    8590             :              adj_nbr_db_size());
    8591             : 
    8592             :     /*
    8593             :      * MPLS enable an interface so we get the MPLS table created
    8594             :      */
    8595           1 :     mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
    8596           1 :     mpls_sw_interface_enable_disable(&mpls_main,
    8597           1 :                                      tm->hw[0]->sw_if_index,
    8598             :                                      1);
    8599             : 
    8600           2 :     ip46_address_t nh_10_10_10_1 = {
    8601           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
    8602             :     };
    8603           1 :     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    8604             :                                              VNET_LINK_MPLS,
    8605             :                                              &nh_10_10_10_1,
    8606           1 :                                              tm->hw[0]->sw_if_index);
    8607             : 
    8608             :     /*
    8609             :      * Test the specials stack properly.
    8610             :      */
    8611           1 :     fib_prefix_t exp_null_v6_pfx = {
    8612             :         .fp_proto = FIB_PROTOCOL_MPLS,
    8613             :         .fp_eos = MPLS_EOS,
    8614             :         .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
    8615             :         .fp_payload_proto = DPO_PROTO_IP6,
    8616             :     };
    8617           1 :     lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
    8618           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
    8619             :              "%U/%U present",
    8620             :              format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
    8621             :              format_mpls_eos_bit, MPLS_EOS);
    8622           1 :     fib_entry_contribute_forwarding(lfe,
    8623             :                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    8624             :                                     &dpo);
    8625           1 :     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
    8626           1 :     lkd = lookup_dpo_get(dpo1->dpoi_index);
    8627             : 
    8628           1 :     FIB_TEST((fib_index == lkd->lkd_fib_index),
    8629             :              "%U/%U is deag in %d %U",
    8630             :              format_mpls_unicast_label, deag_label,
    8631             :              format_mpls_eos_bit, MPLS_EOS,
    8632             :              lkd->lkd_fib_index,
    8633             :              format_dpo_id, &dpo, 0);
    8634           1 :     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
    8635             :              "%U/%U is dst deag",
    8636             :              format_mpls_unicast_label, deag_label,
    8637             :              format_mpls_eos_bit, MPLS_EOS);
    8638           1 :     FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
    8639             :              "%U/%U is lookup in interface's table",
    8640             :              format_mpls_unicast_label, deag_label,
    8641             :              format_mpls_eos_bit, MPLS_EOS);
    8642           1 :     FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
    8643             :              "%U/%U is %U dst deag",
    8644             :              format_mpls_unicast_label, deag_label,
    8645             :              format_mpls_eos_bit, MPLS_EOS,
    8646             :              format_dpo_proto, lkd->lkd_proto);
    8647             : 
    8648             :     /*
    8649             :      * A route deag route for EOS
    8650             :      */
    8651           1 :     fib_prefix_t pfx = {
    8652             :         .fp_proto = FIB_PROTOCOL_MPLS,
    8653             :         .fp_eos = MPLS_EOS,
    8654             :         .fp_label = deag_label,
    8655             :         .fp_payload_proto = DPO_PROTO_IP4,
    8656             :     };
    8657             :     mpls_disp_dpo_t *mdd;
    8658           1 :     lfe = fib_table_entry_path_add(lfib_index,
    8659             :                                    &pfx,
    8660             :                                    FIB_SOURCE_CLI,
    8661             :                                    FIB_ENTRY_FLAG_NONE,
    8662             :                                    DPO_PROTO_IP4,
    8663             :                                    &zero_addr,
    8664             :                                    ~0,
    8665             :                                    fib_index,
    8666             :                                    1,
    8667             :                                    NULL,
    8668             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    8669             : 
    8670           1 :     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
    8671             :              "%U/%U present",
    8672             :              format_mpls_unicast_label, deag_label,
    8673             :              format_mpls_eos_bit, MPLS_EOS);
    8674             : 
    8675           1 :     fib_entry_contribute_forwarding(lfe,
    8676             :                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    8677             :                                     &dpo);
    8678           1 :     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
    8679           1 :     mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
    8680             : 
    8681           1 :     FIB_TEST((FIB_MPLS_LSP_MODE_PIPE == mdd->mdd_mode),
    8682             :              "%U/%U disp is pipe mode",
    8683             :              format_mpls_unicast_label, deag_label,
    8684             :              format_mpls_eos_bit, MPLS_EOS);
    8685             : 
    8686           1 :     lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
    8687             : 
    8688           1 :     FIB_TEST((fib_index == lkd->lkd_fib_index),
    8689             :              "%U/%U is deag in %d %U",
    8690             :              format_mpls_unicast_label, deag_label,
    8691             :              format_mpls_eos_bit, MPLS_EOS,
    8692             :              lkd->lkd_fib_index,
    8693             :              format_dpo_id, &dpo, 0);
    8694           1 :     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
    8695             :              "%U/%U is dst deag",
    8696             :              format_mpls_unicast_label, deag_label,
    8697             :              format_mpls_eos_bit, MPLS_EOS);
    8698           1 :     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
    8699             :              "%U/%U is %U dst deag",
    8700             :              format_mpls_unicast_label, deag_label,
    8701             :              format_mpls_eos_bit, MPLS_EOS,
    8702             :              format_dpo_proto, lkd->lkd_proto);
    8703             : 
    8704           1 :     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
    8705             : 
    8706           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
    8707             :                                                          &pfx)),
    8708             :               "%U/%U not present",
    8709             :               format_mpls_unicast_label, deag_label,
    8710             :               format_mpls_eos_bit, MPLS_EOS);
    8711           1 :     dpo_reset(&dpo);
    8712             : 
    8713             :     /*
    8714             :      * A route deag route for EOS with LSP mode uniform
    8715             :      */
    8716           1 :     fib_mpls_label_t *l_pops = NULL, l_pop = {
    8717             :         .fml_value = MPLS_LABEL_POP,
    8718             :         .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
    8719             :     };
    8720           1 :     vec_add1(l_pops, l_pop);
    8721           1 :     lfe = fib_table_entry_path_add(lfib_index,
    8722             :                                    &pfx,
    8723             :                                    FIB_SOURCE_CLI,
    8724             :                                    FIB_ENTRY_FLAG_NONE,
    8725             :                                    DPO_PROTO_IP4,
    8726             :                                    &zero_addr,
    8727             :                                    ~0,
    8728             :                                    fib_index,
    8729             :                                    1,
    8730             :                                    l_pops,
    8731             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    8732             : 
    8733           1 :     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
    8734             :               "%U/%U present",
    8735             :               format_mpls_unicast_label, deag_label,
    8736             :               format_mpls_eos_bit, MPLS_EOS);
    8737             : 
    8738           1 :     fib_entry_contribute_forwarding(lfe,
    8739             :                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    8740             :                                     &dpo);
    8741           1 :     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
    8742           1 :     mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
    8743             : 
    8744           1 :     FIB_TEST((FIB_MPLS_LSP_MODE_UNIFORM == mdd->mdd_mode),
    8745             :              "%U/%U disp is uniform mode",
    8746             :              format_mpls_unicast_label, deag_label,
    8747             :              format_mpls_eos_bit, MPLS_EOS);
    8748             : 
    8749           1 :     lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
    8750             : 
    8751           1 :     FIB_TEST((fib_index == lkd->lkd_fib_index),
    8752             :               "%U/%U is deag in %d %U",
    8753             :              format_mpls_unicast_label, deag_label,
    8754             :              format_mpls_eos_bit, MPLS_EOS,
    8755             :              lkd->lkd_fib_index,
    8756             :              format_dpo_id, &dpo, 0);
    8757           1 :     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
    8758             :              "%U/%U is dst deag",
    8759             :              format_mpls_unicast_label, deag_label,
    8760             :              format_mpls_eos_bit, MPLS_EOS);
    8761           1 :     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
    8762             :              "%U/%U is %U dst deag",
    8763             :              format_mpls_unicast_label, deag_label,
    8764             :              format_mpls_eos_bit, MPLS_EOS,
    8765             :              format_dpo_proto, lkd->lkd_proto);
    8766             : 
    8767           1 :     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
    8768             : 
    8769           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
    8770             :                                                          &pfx)),
    8771             :               "%U/%U not present",
    8772             :               format_mpls_unicast_label, deag_label,
    8773             :               format_mpls_eos_bit, MPLS_EOS);
    8774           1 :     dpo_reset(&dpo);
    8775             : 
    8776             :     /*
    8777             :      * A route deag route for non-EOS
    8778             :      */
    8779           1 :     pfx.fp_eos = MPLS_NON_EOS;
    8780           1 :     lfe = fib_table_entry_path_add(lfib_index,
    8781             :                                    &pfx,
    8782             :                                    FIB_SOURCE_CLI,
    8783             :                                    FIB_ENTRY_FLAG_NONE,
    8784             :                                    DPO_PROTO_IP4,
    8785             :                                    &zero_addr,
    8786             :                                    ~0,
    8787             :                                    lfib_index,
    8788             :                                    1,
    8789             :                                    NULL,
    8790             :                                    FIB_ROUTE_PATH_FLAG_NONE);
    8791             : 
    8792           1 :     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
    8793             :              "%U/%U present",
    8794             :              format_mpls_unicast_label, deag_label,
    8795             :              format_mpls_eos_bit, MPLS_NON_EOS);
    8796             : 
    8797           1 :     fib_entry_contribute_forwarding(lfe,
    8798             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    8799             :                                     &dpo);
    8800           1 :     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
    8801           1 :     lkd = lookup_dpo_get(dpo1->dpoi_index);
    8802             : 
    8803           1 :     FIB_TEST((fib_index == lkd->lkd_fib_index),
    8804             :              "%U/%U is deag in %d %U",
    8805             :              format_mpls_unicast_label, deag_label,
    8806             :              format_mpls_eos_bit, MPLS_NON_EOS,
    8807             :              lkd->lkd_fib_index,
    8808             :              format_dpo_id, &dpo, 0);
    8809           1 :     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
    8810             :              "%U/%U is dst deag",
    8811             :              format_mpls_unicast_label, deag_label,
    8812             :              format_mpls_eos_bit, MPLS_NON_EOS);
    8813             : 
    8814           1 :     FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
    8815             :              "%U/%U is %U dst deag",
    8816             :              format_mpls_unicast_label, deag_label,
    8817             :              format_mpls_eos_bit, MPLS_NON_EOS,
    8818             :              format_dpo_proto, lkd->lkd_proto);
    8819             : 
    8820           1 :     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
    8821             : 
    8822           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
    8823             :                                                          &pfx)),
    8824             :              "%U/%U not present",
    8825             :              format_mpls_unicast_label, deag_label,
    8826             :              format_mpls_eos_bit, MPLS_EOS);
    8827             : 
    8828           1 :     dpo_reset(&dpo);
    8829             : 
    8830             :     /*
    8831             :      * An MPLS x-connect
    8832             :      */
    8833           1 :     fib_prefix_t pfx_1200 = {
    8834             :         .fp_len = 21,
    8835             :         .fp_proto = FIB_PROTOCOL_MPLS,
    8836             :         .fp_label = 1200,
    8837             :         .fp_eos = MPLS_NON_EOS,
    8838             :     };
    8839           1 :     fib_test_lb_bucket_t neos_o_10_10_10_1 = {
    8840             :         .type = FT_LB_LABEL_STACK_O_ADJ,
    8841             :         .label_stack_o_adj = {
    8842             :             .adj = ai_mpls_10_10_10_1,
    8843             :             .label_stack_size = 4,
    8844             :             .label_stack = {
    8845             :                 200, 300, 400, 500,
    8846             :             },
    8847             :             .eos = MPLS_NON_EOS,
    8848             :         },
    8849             :     };
    8850           1 :     dpo_id_t neos_1200 = DPO_INVALID;
    8851           1 :     dpo_id_t ip_1200 = DPO_INVALID;
    8852           1 :     fib_mpls_label_t *l200 = NULL;
    8853             :     u32 ii;
    8854           5 :     for (ii = 0; ii < 4; ii++)
    8855             :     {
    8856           4 :         fib_mpls_label_t fml = {
    8857           4 :             .fml_value = 200 + (ii * 100),
    8858             :         };
    8859           4 :         vec_add1(l200, fml);
    8860             :     };
    8861             : 
    8862           1 :     lfe = fib_table_entry_update_one_path(fib_index,
    8863             :                                           &pfx_1200,
    8864             :                                           FIB_SOURCE_API,
    8865             :                                           FIB_ENTRY_FLAG_NONE,
    8866             :                                           DPO_PROTO_IP4,
    8867             :                                           &nh_10_10_10_1,
    8868           1 :                                           tm->hw[0]->sw_if_index,
    8869             :                                           ~0, // invalid fib index
    8870             :                                           1,
    8871             :                                           l200,
    8872             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    8873             : 
    8874           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    8875             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    8876             :                                       1,
    8877             :                                       &neos_o_10_10_10_1),
    8878             :              "1200/0 LB 1 buckets via: "
    8879             :              "adj 10.10.11.1");
    8880             : 
    8881             :     /*
    8882             :      * A recursive route via the MPLS x-connect
    8883             :      */
    8884           2 :     fib_prefix_t pfx_2_2_2_3_s_32 = {
    8885             :         .fp_len = 32,
    8886             :         .fp_proto = FIB_PROTOCOL_IP4,
    8887             :         .fp_addr = {
    8888           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
    8889             :         },
    8890             :     };
    8891           1 :     fib_route_path_t *rpaths = NULL, rpath = {
    8892             :         .frp_proto = DPO_PROTO_MPLS,
    8893             :         .frp_local_label = 1200,
    8894             :         .frp_eos = MPLS_NON_EOS,
    8895             :         .frp_sw_if_index = ~0, // recurive
    8896             :         .frp_fib_index = 0, // Default MPLS fib
    8897             :         .frp_weight = 1,
    8898             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
    8899             :         .frp_label_stack = NULL,
    8900             :     };
    8901           1 :     vec_add1(rpaths, rpath);
    8902             : 
    8903           1 :     fib_table_entry_path_add2(fib_index,
    8904             :                               &pfx_2_2_2_3_s_32,
    8905             :                               FIB_SOURCE_API,
    8906             :                               FIB_ENTRY_FLAG_NONE,
    8907             :                               rpaths);
    8908             : 
    8909             :     /*
    8910             :      * A labelled recursive route via the MPLS x-connect
    8911             :      */
    8912           2 :     fib_prefix_t pfx_2_2_2_4_s_32 = {
    8913             :         .fp_len = 32,
    8914             :         .fp_proto = FIB_PROTOCOL_IP4,
    8915             :         .fp_addr = {
    8916           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
    8917             :         },
    8918             :     };
    8919           1 :     fib_mpls_label_t *l999 = NULL, fml_999 = {
    8920             :         .fml_value = 999,
    8921             :     };
    8922           1 :     vec_add1(l999, fml_999);
    8923           1 :     rpaths[0].frp_label_stack = l999,
    8924             : 
    8925           1 :         fib_table_entry_path_add2(fib_index,
    8926             :                                   &pfx_2_2_2_4_s_32,
    8927             :                                   FIB_SOURCE_API,
    8928             :                                   FIB_ENTRY_FLAG_NONE,
    8929             :                                   rpaths);
    8930             : 
    8931           1 :     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
    8932             :                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8933             :                                     &ip_1200);
    8934           1 :     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
    8935             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    8936             :                                     &neos_1200);
    8937             : 
    8938           1 :     fib_test_lb_bucket_t ip_o_1200 = {
    8939             :         .type = FT_LB_O_LB,
    8940             :         .lb = {
    8941           1 :             .lb = ip_1200.dpoi_index,
    8942             :         },
    8943             :     };
    8944           1 :     fib_test_lb_bucket_t mpls_o_1200 = {
    8945             :         .type = FT_LB_LABEL_O_LB,
    8946             :         .label_o_lb = {
    8947           1 :             .lb = neos_1200.dpoi_index,
    8948             :             .label = 999,
    8949             :             .eos = MPLS_EOS,
    8950             :         },
    8951             :     };
    8952             : 
    8953           1 :     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
    8954           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    8955             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8956             :                                       1,
    8957             :                                       &ip_o_1200),
    8958             :              "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
    8959           1 :     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
    8960           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    8961             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8962             :                                       1,
    8963             :                                       &mpls_o_1200),
    8964             :              "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
    8965             : 
    8966           1 :     fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
    8967           1 :     fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
    8968           1 :     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
    8969             : 
    8970           1 :     dpo_reset(&neos_1200);
    8971           1 :     dpo_reset(&ip_1200);
    8972             : 
    8973             :     /*
    8974             :      * A recursive via a label that does not exist
    8975             :      */
    8976           1 :     fib_test_lb_bucket_t bucket_drop = {
    8977             :         .type = FT_LB_DROP,
    8978             :         .special = {
    8979             :             .adj = DPO_PROTO_IP4,
    8980             :         },
    8981             :     };
    8982           1 :     fib_test_lb_bucket_t mpls_bucket_drop = {
    8983             :         .type = FT_LB_DROP,
    8984             :         .special = {
    8985             :             .adj = DPO_PROTO_MPLS,
    8986             :         },
    8987             :     };
    8988             : 
    8989           1 :     rpaths[0].frp_label_stack = NULL;
    8990           1 :     lfe = fib_table_entry_path_add2(fib_index,
    8991             :                                     &pfx_2_2_2_4_s_32,
    8992             :                                     FIB_SOURCE_API,
    8993             :                                     FIB_ENTRY_FLAG_NONE,
    8994             :                                     rpaths);
    8995             : 
    8996           1 :     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
    8997             :                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    8998             :                                     &ip_1200);
    8999           1 :     ip_o_1200.lb.lb = ip_1200.dpoi_index;
    9000             : 
    9001           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    9002             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9003             :                                       1,
    9004             :                                       &bucket_drop),
    9005             :              "2.2.2.2.4/32 LB 1 buckets via: drop");
    9006           1 :     lfe = fib_table_lookup(fib_index, &pfx_1200);
    9007           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    9008             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9009             :                                       1,
    9010             :                                       &bucket_drop),
    9011             :              "1200/neos LB 1 buckets via: ip4-DROP");
    9012           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    9013             :                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
    9014             :                                       1,
    9015             :                                       &mpls_bucket_drop),
    9016             :              "1200/neos LB 1 buckets via: mpls-DROP");
    9017             : 
    9018           1 :     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
    9019             : 
    9020           1 :     dpo_reset(&ip_1200);
    9021             : 
    9022             :     /*
    9023             :      * An rx-interface route.
    9024             :      *  like the tail of an mcast LSP
    9025             :      */
    9026           1 :     dpo_id_t idpo = DPO_INVALID;
    9027             : 
    9028           1 :     interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
    9029           1 :                                  tm->hw[0]->sw_if_index,
    9030             :                                  &idpo);
    9031             : 
    9032           1 :     fib_prefix_t pfx_2500 = {
    9033             :         .fp_len = 21,
    9034             :         .fp_proto = FIB_PROTOCOL_MPLS,
    9035             :         .fp_label = 2500,
    9036             :         .fp_eos = MPLS_EOS,
    9037             :         .fp_payload_proto = DPO_PROTO_IP4,
    9038             :     };
    9039           1 :     fib_test_lb_bucket_t rx_intf_0 = {
    9040             :         .type = FT_LB_INTF,
    9041             :         .adj = {
    9042           1 :             .adj = idpo.dpoi_index,
    9043             :         },
    9044             :     };
    9045             : 
    9046           1 :     lfe = fib_table_entry_update_one_path(fib_index,
    9047             :                                           &pfx_2500,
    9048             :                                           FIB_SOURCE_API,
    9049             :                                           FIB_ENTRY_FLAG_NONE,
    9050             :                                           DPO_PROTO_IP4,
    9051             :                                           NULL,
    9052           1 :                                           tm->hw[0]->sw_if_index,
    9053             :                                           ~0, // invalid fib index
    9054             :                                           0,
    9055             :                                           NULL,
    9056             :                                           FIB_ROUTE_PATH_INTF_RX);
    9057           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    9058             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    9059             :                                       1,
    9060             :                                       &rx_intf_0),
    9061             :              "2500 rx-interface 0");
    9062           1 :     fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
    9063             : 
    9064             :     /*
    9065             :      * An MPLS mulicast entry
    9066             :      */
    9067           1 :     fib_prefix_t pfx_3500 = {
    9068             :         .fp_len = 21,
    9069             :         .fp_proto = FIB_PROTOCOL_MPLS,
    9070             :         .fp_label = 3500,
    9071             :         .fp_eos = MPLS_EOS,
    9072             :         .fp_payload_proto = DPO_PROTO_IP4,
    9073             :     };
    9074           1 :     fib_test_rep_bucket_t mc_0 = {
    9075             :         .type = FT_REP_LABEL_O_ADJ,
    9076             :         .label_o_adj = {
    9077             :             .adj = ai_mpls_10_10_10_1,
    9078             :             .label = 3300,
    9079             :             .eos = MPLS_EOS,
    9080             :         },
    9081             :     };
    9082           1 :     fib_test_rep_bucket_t mc_intf_0 = {
    9083             :         .type = FT_REP_INTF,
    9084             :         .adj = {
    9085           1 :             .adj = idpo.dpoi_index,
    9086             :         },
    9087             :     };
    9088           1 :     fib_mpls_label_t *l3300 = NULL, fml_3300 = {
    9089             :         .fml_value = 3300,
    9090             :     };
    9091           1 :     vec_add1(l3300, fml_3300);
    9092             : 
    9093           1 :     lfe = fib_table_entry_update_one_path(lfib_index,
    9094             :                                           &pfx_3500,
    9095             :                                           FIB_SOURCE_API,
    9096             :                                           FIB_ENTRY_FLAG_MULTICAST,
    9097             :                                           DPO_PROTO_IP4,
    9098             :                                           &nh_10_10_10_1,
    9099           1 :                                           tm->hw[0]->sw_if_index,
    9100             :                                           ~0, // invalid fib index
    9101             :                                           1,
    9102             :                                           l3300,
    9103             :                                           FIB_ROUTE_PATH_FLAG_NONE);
    9104           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    9105             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    9106             :                                       1,
    9107             :                                       &mc_0),
    9108             :              "3500 via replicate over 10.10.10.1");
    9109             : 
    9110             :     /*
    9111             :      * MPLS Bud-node. Add a replication via an interface-receieve path
    9112             :      */
    9113           1 :     lfe = fib_table_entry_path_add(lfib_index,
    9114             :                                    &pfx_3500,
    9115             :                                    FIB_SOURCE_API,
    9116             :                                    FIB_ENTRY_FLAG_MULTICAST,
    9117             :                                    DPO_PROTO_IP4,
    9118             :                                    NULL,
    9119           1 :                                    tm->hw[0]->sw_if_index,
    9120             :                                    ~0, // invalid fib index
    9121             :                                    0,
    9122             :                                    NULL,
    9123             :                                    FIB_ROUTE_PATH_INTF_RX);
    9124           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    9125             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    9126             :                                       2,
    9127             :                                       &mc_0,
    9128             :                                       &mc_intf_0),
    9129             :              "3500 via replicate over 10.10.10.1 and interface-rx");
    9130             : 
    9131             :     /*
    9132             :      * Add a replication via an interface-free for-us path
    9133             :      */
    9134           1 :     fib_test_rep_bucket_t mc_disp = {
    9135             :         .type = FT_REP_DISP_MFIB_LOOKUP,
    9136             :         .adj = {
    9137           1 :             .adj = idpo.dpoi_index,
    9138             :         },
    9139             :     };
    9140           1 :     lfe = fib_table_entry_path_add(lfib_index,
    9141             :                                    &pfx_3500,
    9142             :                                    FIB_SOURCE_API,
    9143             :                                    FIB_ENTRY_FLAG_MULTICAST,
    9144             :                                    DPO_PROTO_IP4,
    9145             :                                    NULL,
    9146             :                                    5, // rpf-id
    9147             :                                    0, // default table
    9148             :                                    0,
    9149             :                                    NULL,
    9150             :                                    FIB_ROUTE_PATH_RPF_ID);
    9151           1 :     FIB_TEST(!fib_test_validate_entry(lfe,
    9152             :                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
    9153             :                                       3,
    9154             :                                       &mc_0,
    9155             :                                       &mc_disp,
    9156             :                                       &mc_intf_0),
    9157             :              "3500 via replicate over 10.10.10.1 and interface-rx");
    9158             : 
    9159             : 
    9160             : 
    9161           1 :     fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
    9162           1 :     dpo_reset(&idpo);
    9163             : 
    9164             :     /*
    9165             :      * cleanup
    9166             :      */
    9167           1 :     mpls_sw_interface_enable_disable(&mpls_main,
    9168           1 :                                      tm->hw[0]->sw_if_index,
    9169             :                                      0);
    9170           1 :     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
    9171             : 
    9172           1 :     FIB_TEST(0 == pool_elts(mpls_disp_dpo_pool),
    9173             :              "mpls_disp_dpo resources freed %d of %d",
    9174             :              0, pool_elts(mpls_disp_dpo_pool));
    9175           1 :     FIB_TEST(lb_count == pool_elts(load_balance_pool),
    9176             :              "Load-balance resources freed %d of %d",
    9177             :              lb_count, pool_elts(load_balance_pool));
    9178           1 :     FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
    9179             :              "interface_rx_dpo resources freed %d of %d",
    9180             :              0, pool_elts(interface_rx_dpo_pool));
    9181             : 
    9182           1 :     return (res);
    9183             : }
    9184             : 
    9185             : static int
    9186           1 : fib_test_inherit (void)
    9187             : {
    9188             :     fib_node_index_t fei;
    9189             :     int n_feis, res, i;
    9190             :     test_main_t *tm;
    9191             : 
    9192           1 :     tm = &test_main;
    9193           1 :     res = 0;
    9194             : 
    9195           4 :     for (i = 0; i <= 2; i++)
    9196             :       {
    9197           3 :         fib_table_bind (FIB_PROTOCOL_IP4, tm->hw[i]->sw_if_index, 0);
    9198           3 :         fib_table_bind (FIB_PROTOCOL_IP6, tm->hw[i]->sw_if_index, 0);
    9199             :       }
    9200           1 :     n_feis = fib_entry_pool_size();
    9201             : 
    9202           2 :     const ip46_address_t nh_10_10_10_1 = {
    9203           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
    9204             :     };
    9205           2 :     const ip46_address_t nh_10_10_10_2 = {
    9206           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
    9207             :     };
    9208           2 :     const ip46_address_t nh_10_10_10_3 = {
    9209           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
    9210             :     };
    9211           2 :     const ip46_address_t nh_10_10_10_16 = {
    9212           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a10),
    9213             :     };
    9214           2 :     const ip46_address_t nh_10_10_10_20 = {
    9215           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a14),
    9216             :     };
    9217           2 :     const ip46_address_t nh_10_10_10_21 = {
    9218           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a15),
    9219             :     };
    9220           2 :     const ip46_address_t nh_10_10_10_22 = {
    9221           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a16),
    9222             :     };
    9223           2 :     const ip46_address_t nh_10_10_10_255 = {
    9224           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0aff),
    9225             :     };
    9226           2 :     const ip46_address_t nh_10_10_10_0 = {
    9227           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a00),
    9228             :     };
    9229           2 :     const ip46_address_t nh_10_10_0_0 = {
    9230           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0000),
    9231             :     };
    9232           2 :     const ip46_address_t nh_11_11_11_11 = {
    9233           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
    9234             :     };
    9235           2 :     const ip46_address_t nh_11_11_11_0 = {
    9236           1 :         .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b00),
    9237             :     };
    9238             : 
    9239             :     /*
    9240             :      * prefixes at the base of a sub-tree
    9241             :      */
    9242           1 :     const fib_prefix_t pfx_10_10_10_21_s_32 = {
    9243             :         .fp_len = 32,
    9244             :         .fp_proto = FIB_PROTOCOL_IP4,
    9245             :         .fp_addr = nh_10_10_10_21,
    9246             :     };
    9247           1 :     const fib_prefix_t pfx_10_10_10_22_s_32 = {
    9248             :         .fp_len = 32,
    9249             :         .fp_proto = FIB_PROTOCOL_IP4,
    9250             :         .fp_addr = nh_10_10_10_22,
    9251             :     };
    9252           1 :     const fib_prefix_t pfx_10_10_10_255_s_32 = {
    9253             :         .fp_len = 32,
    9254             :         .fp_proto = FIB_PROTOCOL_IP4,
    9255             :         .fp_addr = nh_10_10_10_255,
    9256             :     };
    9257           1 :     const u32 N_PLS = fib_path_list_pool_size();
    9258             : 
    9259           1 :     fib_table_entry_special_add(0,
    9260             :                                 &pfx_10_10_10_21_s_32,
    9261             :                                 FIB_SOURCE_CLI,
    9262             :                                 FIB_ENTRY_FLAG_DROP);
    9263           1 :     fib_table_entry_special_add(0,
    9264             :                                 &pfx_10_10_10_22_s_32,
    9265             :                                 FIB_SOURCE_CLI,
    9266             :                                 FIB_ENTRY_FLAG_DROP);
    9267           1 :     fib_table_entry_special_add(0,
    9268             :                                 &pfx_10_10_10_255_s_32,
    9269             :                                 FIB_SOURCE_CLI,
    9270             :                                 FIB_ENTRY_FLAG_DROP);
    9271             : 
    9272             :     /*
    9273             :      * source an entry that pushes its state down the sub-tree
    9274             :      */
    9275           1 :     const fib_prefix_t pfx_10_10_10_16_s_28 = {
    9276             :         .fp_len = 28,
    9277             :         .fp_proto = FIB_PROTOCOL_IP4,
    9278             :         .fp_addr = nh_10_10_10_16,
    9279             :     };
    9280           1 :     fib_table_entry_update_one_path(0,
    9281             :                                     &pfx_10_10_10_16_s_28,
    9282             :                                     FIB_SOURCE_API,
    9283             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
    9284             :                                     DPO_PROTO_IP4,
    9285             :                                     &nh_10_10_10_1,
    9286           1 :                                     tm->hw[0]->sw_if_index,
    9287             :                                     ~0,
    9288             :                                     1,
    9289             :                                     NULL,
    9290             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9291             : 
    9292             :     /*
    9293             :      * this covering entry and all those below it should have
    9294             :      * the same forwarding information.
    9295             :      */
    9296           1 :     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    9297             :                                                     VNET_LINK_IP4,
    9298             :                                                     &nh_10_10_10_1,
    9299           1 :                                                     tm->hw[0]->sw_if_index);
    9300           1 :     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
    9301             :         .type = FT_LB_ADJ,
    9302             :         .adj = {
    9303             :             .adj = ai_10_10_10_1,
    9304             :         },
    9305             :     };
    9306             : 
    9307           1 :     fei = fib_table_lookup(0, &pfx_10_10_10_16_s_28);
    9308           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9309             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9310             :                                       1,
    9311             :                                       &adj_o_10_10_10_1),
    9312             :              "%U via 10.10.10.1",
    9313             :              format_fib_prefix, &pfx_10_10_10_16_s_28);
    9314           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9315           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9316             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9317             :                                       1,
    9318             :                                       &adj_o_10_10_10_1),
    9319             :              "%U via 10.10.10.1",
    9320             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9321           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9322           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9323             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9324             :                                       1,
    9325             :                                       &adj_o_10_10_10_1),
    9326             :              "%U via 10.10.10.1",
    9327             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9328           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9329           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    9330             :              "%U resolves via drop",
    9331             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9332             : 
    9333             :     /*
    9334             :      * remove the inherting cover - covereds go back to drop
    9335             :      */
    9336           1 :     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
    9337             : 
    9338           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9339           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    9340             :              "%U resolves via drop",
    9341             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9342             : 
    9343             :     /*
    9344             :      * source an entry that pushes its state down the sub-tree
    9345             :      */
    9346           1 :     const fib_prefix_t pfx_10_10_10_0_s_24 = {
    9347             :         .fp_len = 24,
    9348             :         .fp_proto = FIB_PROTOCOL_IP4,
    9349             :         .fp_addr = nh_10_10_10_0,
    9350             :     };
    9351           1 :     fib_table_entry_update_one_path(0,
    9352             :                                     &pfx_10_10_10_0_s_24,
    9353             :                                     FIB_SOURCE_API,
    9354             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
    9355             :                                     DPO_PROTO_IP4,
    9356             :                                     &nh_10_10_10_1,
    9357           1 :                                     tm->hw[0]->sw_if_index,
    9358             :                                     ~0,
    9359             :                                     1,
    9360             :                                     NULL,
    9361             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9362             : 
    9363             :     /*
    9364             :      * whole sub-tree now covered
    9365             :      */
    9366           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
    9367           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9368             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9369             :                                       1,
    9370             :                                       &adj_o_10_10_10_1),
    9371             :              "%U via 10.10.10.1",
    9372             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
    9373           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9374           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9375             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9376             :                                       1,
    9377             :                                       &adj_o_10_10_10_1),
    9378             :              "%U via 10.10.10.1",
    9379             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9380           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9381           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9382             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9383             :                                       1,
    9384             :                                       &adj_o_10_10_10_1),
    9385             :              "%U via 10.10.10.1",
    9386             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9387           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9388           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9389             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9390             :                                       1,
    9391             :                                       &adj_o_10_10_10_1),
    9392             :              "%U via 10.10.10.1",
    9393             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9394             : 
    9395             :     /*
    9396             :      * insert a more specific into the sub-tree - expect inheritance
    9397             :      *  this one is directly covered by the root
    9398             :      */
    9399           1 :     fib_table_entry_special_add(0,
    9400             :                                 &pfx_10_10_10_16_s_28,
    9401             :                                 FIB_SOURCE_CLI,
    9402             :                                 FIB_ENTRY_FLAG_DROP);
    9403           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
    9404           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9405             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9406             :                                       1,
    9407             :                                       &adj_o_10_10_10_1),
    9408             :              "%U via 10.10.10.1",
    9409             :              format_fib_prefix, &pfx_10_10_10_16_s_28);
    9410             : 
    9411             :     /*
    9412             :      * insert a more specific into the sub-tree - expect inheritance
    9413             :      *  this one is indirectly covered by the root
    9414             :      */
    9415           1 :     const fib_prefix_t pfx_10_10_10_20_s_30 = {
    9416             :         .fp_len = 30,
    9417             :         .fp_proto = FIB_PROTOCOL_IP4,
    9418             :         .fp_addr = nh_10_10_10_20,
    9419             :     };
    9420           1 :     fib_table_entry_special_add(0,
    9421             :                                 &pfx_10_10_10_20_s_30,
    9422             :                                 FIB_SOURCE_CLI,
    9423             :                                 FIB_ENTRY_FLAG_DROP);
    9424           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
    9425           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9426             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9427             :                                       1,
    9428             :                                       &adj_o_10_10_10_1),
    9429             :              "%U via 10.10.10.1",
    9430             :              format_fib_prefix, &pfx_10_10_10_20_s_30);
    9431             : 
    9432             :     /*
    9433             :      * remove the prefix from the middle of the sub-tree
    9434             :      *  the inherited source will be the only one remaining - expect
    9435             :      *  it to be withdrawn and hence the prefix is removed.
    9436             :      */
    9437           1 :     fib_table_entry_special_remove(0,
    9438             :                                    &pfx_10_10_10_20_s_30,
    9439             :                                    FIB_SOURCE_CLI);
    9440           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
    9441           1 :     FIB_TEST((FIB_NODE_INDEX_INVALID == fei),
    9442             :              "%U gone",
    9443             :              format_fib_prefix, &pfx_10_10_10_20_s_30);
    9444             : 
    9445             :     /*
    9446             :      * inheriting source is modifed - expect the modification to be present
    9447             :      *  throughout the sub-tree
    9448             :      */
    9449           1 :     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    9450             :                                                     VNET_LINK_IP4,
    9451             :                                                     &nh_10_10_10_2,
    9452           1 :                                                     tm->hw[0]->sw_if_index);
    9453           1 :     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
    9454             :         .type = FT_LB_ADJ,
    9455             :         .adj = {
    9456             :             .adj = ai_10_10_10_2,
    9457             :         },
    9458             :     };
    9459             : 
    9460           1 :     fib_table_entry_update_one_path(0,
    9461             :                                     &pfx_10_10_10_0_s_24,
    9462             :                                     FIB_SOURCE_API,
    9463             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
    9464             :                                     DPO_PROTO_IP4,
    9465             :                                     &nh_10_10_10_2,
    9466           1 :                                     tm->hw[0]->sw_if_index,
    9467             :                                     ~0,
    9468             :                                     1,
    9469             :                                     NULL,
    9470             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9471           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9472           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9473             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9474             :                                       1,
    9475             :                                       &adj_o_10_10_10_2),
    9476             :              "%U via 10.10.10.2",
    9477             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9478           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9479           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9480             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9481             :                                       1,
    9482             :                                       &adj_o_10_10_10_2),
    9483             :              "%U via 10.10.10.2",
    9484             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9485           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9486           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9487             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9488             :                                       1,
    9489             :                                       &adj_o_10_10_10_2),
    9490             :              "%U via 10.10.10.2",
    9491             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9492           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
    9493           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9494             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9495             :                                       1,
    9496             :                                       &adj_o_10_10_10_2),
    9497             :              "%U via 10.10.10.2",
    9498             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
    9499             : 
    9500           1 :     fib_source_t hi_src = fib_source_allocate("test", 0x50,
    9501             :                                               FIB_SOURCE_BH_SIMPLE);
    9502             : 
    9503             :     /*
    9504             :      * add the source that replaces inherited state.
    9505             :      * inheriting source is not the best, so it doesn't push state.
    9506             :      */
    9507           1 :     fib_table_entry_update_one_path(0,
    9508             :                                     &pfx_10_10_10_0_s_24,
    9509             :                                     hi_src,
    9510             :                                     FIB_ENTRY_FLAG_NONE,
    9511             :                                     DPO_PROTO_IP4,
    9512             :                                     &nh_10_10_10_1,
    9513           1 :                                     tm->hw[0]->sw_if_index,
    9514             :                                     ~0,
    9515             :                                     1,
    9516             :                                     NULL,
    9517             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9518           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
    9519           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9520             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9521             :                                       1,
    9522             :                                       &adj_o_10_10_10_1),
    9523             :              "%U via 10.10.10.1",
    9524             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
    9525             : 
    9526           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9527           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    9528             :              "%U resolves via drop",
    9529             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9530           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9531           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    9532             :              "%U resolves via drop",
    9533             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9534           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9535           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    9536             :              "%U resolves via drop",
    9537             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9538           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
    9539           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
    9540             :              "%U resolves via drop",
    9541             :              format_fib_prefix, &pfx_10_10_10_16_s_28);
    9542             : 
    9543             :     /*
    9544             :      * withdraw the higher priority source and expect the inherited to return
    9545             :      * throughout the sub-tree
    9546             :      */
    9547           1 :     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, hi_src);
    9548             : 
    9549           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9550           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9551             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9552             :                                       1,
    9553             :                                       &adj_o_10_10_10_2),
    9554             :              "%U via 10.10.10.2",
    9555             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9556           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9557           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9558             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9559             :                                       1,
    9560             :                                       &adj_o_10_10_10_2),
    9561             :              "%U via 10.10.10.2",
    9562             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9563           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9564           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9565             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9566             :                                       1,
    9567             :                                       &adj_o_10_10_10_2),
    9568             :              "%U via 10.10.10.2",
    9569             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9570           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
    9571           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9572             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9573             :                                       1,
    9574             :                                       &adj_o_10_10_10_2),
    9575             :              "%U via 10.10.10.2",
    9576             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
    9577           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
    9578           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9579             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9580             :                                       1,
    9581             :                                       &adj_o_10_10_10_2),
    9582             :              "%U via 10.10.10.2",
    9583             :              format_fib_prefix, &pfx_10_10_10_16_s_28);
    9584             : 
    9585             :     /*
    9586             :      * source a covered entry in the sub-tree with the same inherting source
    9587             :      *  - expect that it now owns the sub-tree and thus over-rides its cover
    9588             :      */
    9589           1 :     fib_table_entry_update_one_path(0,
    9590             :                                     &pfx_10_10_10_16_s_28,
    9591             :                                     FIB_SOURCE_API,
    9592             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
    9593             :                                     DPO_PROTO_IP4,
    9594             :                                     &nh_10_10_10_1,
    9595           1 :                                     tm->hw[0]->sw_if_index,
    9596             :                                     ~0,
    9597             :                                     1,
    9598             :                                     NULL,
    9599             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9600           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
    9601           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9602             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9603             :                                       1,
    9604             :                                       &adj_o_10_10_10_1),
    9605             :              "%U via 10.10.10.1",
    9606             :              format_fib_prefix, &pfx_10_10_10_16_s_28);
    9607           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9608           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9609             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9610             :                                       1,
    9611             :                                       &adj_o_10_10_10_1),
    9612             :              "%U via 10.10.10.2",
    9613             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9614           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9615           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9616             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9617             :                                       1,
    9618             :                                       &adj_o_10_10_10_1),
    9619             :              "%U via 10.10.10.2",
    9620             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9621             : 
    9622             :     /* these two unaffected by the sub-tree change */
    9623           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9624           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9625             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9626             :                                       1,
    9627             :                                       &adj_o_10_10_10_2),
    9628             :              "%U via 10.10.10.2",
    9629             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9630           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
    9631           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9632             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9633             :                                       1,
    9634             :                                       &adj_o_10_10_10_2),
    9635             :              "%U via 10.10.10.2",
    9636             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
    9637             : 
    9638             :     /*
    9639             :      * removes the more specific, expect the /24 to now re-owns the sub-tree
    9640             :      */
    9641           1 :     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
    9642             : 
    9643           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9644           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9645             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9646             :                                       1,
    9647             :                                       &adj_o_10_10_10_2),
    9648             :              "%U via 10.10.10.2",
    9649             :              format_fib_prefix, &pfx_10_10_10_16_s_28);
    9650           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9651             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9652             :                                       1,
    9653             :                                       &adj_o_10_10_10_2),
    9654             :              "%U via 10.10.10.2",
    9655             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9656           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9657           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9658             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9659             :                                       1,
    9660             :                                       &adj_o_10_10_10_2),
    9661             :              "%U via 10.10.10.2",
    9662             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9663           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9664           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9665             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9666             :                                       1,
    9667             :                                       &adj_o_10_10_10_2),
    9668             :              "%U via 10.10.10.2",
    9669             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9670           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
    9671           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9672             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9673             :                                       1,
    9674             :                                       &adj_o_10_10_10_2),
    9675             :              "%U via 10.10.10.2",
    9676             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
    9677             :     /*
    9678             :      * modify the /24. expect the new forwarding to be pushed down
    9679             :      */
    9680           1 :     fib_table_entry_update_one_path(0,
    9681             :                                     &pfx_10_10_10_0_s_24,
    9682             :                                     FIB_SOURCE_API,
    9683             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
    9684             :                                     DPO_PROTO_IP4,
    9685             :                                     &nh_10_10_10_1,
    9686           1 :                                     tm->hw[0]->sw_if_index,
    9687             :                                     ~0,
    9688             :                                     1,
    9689             :                                     NULL,
    9690             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9691           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9692           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9693             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9694             :                                       1,
    9695             :                                       &adj_o_10_10_10_1),
    9696             :              "%U via 10.10.10.1",
    9697             :              format_fib_prefix, &pfx_10_10_10_16_s_28);
    9698           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9699             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9700             :                                       1,
    9701             :                                       &adj_o_10_10_10_1),
    9702             :              "%U via 10.10.10.1",
    9703             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
    9704           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9705           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9706             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9707             :                                       1,
    9708             :                                       &adj_o_10_10_10_1),
    9709             :              "%U via 10.10.10.1",
    9710             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9711           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9712           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9713             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9714             :                                       1,
    9715             :                                       &adj_o_10_10_10_1),
    9716             :              "%U via 10.10.10.1",
    9717             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9718           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
    9719           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9720             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9721             :                                       1,
    9722             :                                       &adj_o_10_10_10_1),
    9723             :              "%U via 10.10.10.1",
    9724             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
    9725             : 
    9726             :     /*
    9727             :      * add an entry less specific to /24. it should not own the /24's tree
    9728             :      */
    9729           1 :     const fib_prefix_t pfx_10_10_0_0_s_16 = {
    9730             :         .fp_len = 16,
    9731             :         .fp_proto = FIB_PROTOCOL_IP4,
    9732             :         .fp_addr = nh_10_10_0_0,
    9733             :     };
    9734           1 :     fib_table_entry_update_one_path(0,
    9735             :                                     &pfx_10_10_0_0_s_16,
    9736             :                                     FIB_SOURCE_API,
    9737             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
    9738             :                                     DPO_PROTO_IP4,
    9739             :                                     &nh_10_10_10_2,
    9740           1 :                                     tm->hw[0]->sw_if_index,
    9741             :                                     ~0,
    9742             :                                     1,
    9743             :                                     NULL,
    9744             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9745           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
    9746           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9747             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9748             :                                       1,
    9749             :                                       &adj_o_10_10_10_1),
    9750             :              "%U via 10.10.10.1",
    9751             :              format_fib_prefix, &pfx_10_10_10_16_s_28);
    9752           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
    9753           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9754             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9755             :                                       1,
    9756             :                                       &adj_o_10_10_10_1),
    9757             :              "%U via 10.10.10.1",
    9758             :              format_fib_prefix, &pfx_10_10_10_22_s_32);
    9759           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
    9760           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9761             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9762             :                                       1,
    9763             :                                       &adj_o_10_10_10_1),
    9764             :              "%U via 10.10.10.1",
    9765             :              format_fib_prefix, &pfx_10_10_10_255_s_32);
    9766           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
    9767           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9768             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9769             :                                       1,
    9770             :                                       &adj_o_10_10_10_1),
    9771             :              "%U via 10.10.10.1",
    9772             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
    9773           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_0_0_s_16);
    9774           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9775             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9776             :                                       1,
    9777             :                                       &adj_o_10_10_10_2),
    9778             :              "%U via 10.10.10.2",
    9779             :              format_fib_prefix, &pfx_10_10_0_0_s_16);
    9780             : 
    9781             :     /*
    9782             :      * Add/remove an interposer source to a new /32
    9783             :      */
    9784           1 :     const fib_prefix_t pfx_11_11_11_11_s_32 = {
    9785             :         .fp_len = 32,
    9786             :         .fp_proto = FIB_PROTOCOL_IP4,
    9787             :         .fp_addr = nh_11_11_11_11,
    9788             :     };
    9789             : 
    9790           1 :     fib_table_entry_update_one_path(0,
    9791             :                                     &pfx_11_11_11_11_s_32,
    9792             :                                     FIB_SOURCE_API,
    9793             :                                     FIB_ENTRY_FLAG_NONE,
    9794             :                                     DPO_PROTO_IP4,
    9795             :                                     &nh_10_10_10_3,
    9796           1 :                                     tm->hw[0]->sw_if_index,
    9797             :                                     ~0,
    9798             :                                     1,
    9799             :                                     NULL,
    9800             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9801             : 
    9802           1 :     dpo_id_t interposer = DPO_INVALID;
    9803           1 :     fib_mpls_label_t *l99 = NULL, fml_99 = {
    9804             :         .fml_value = 99,
    9805             :     };
    9806           1 :     vec_add1(l99, fml_99);
    9807             : 
    9808           1 :     mpls_label_dpo_create(l99,
    9809             :                           MPLS_EOS,
    9810             :                           DPO_PROTO_IP4,
    9811             :                           MPLS_LABEL_DPO_FLAG_NONE,
    9812             :                           punt_dpo_get(DPO_PROTO_MPLS),
    9813             :                           &interposer);
    9814             : 
    9815           1 :     adj_index_t ai_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    9816             :                                                     VNET_LINK_IP4,
    9817             :                                                     &nh_10_10_10_3,
    9818           1 :                                                     tm->hw[0]->sw_if_index);
    9819           1 :     fib_test_lb_bucket_t adj_o_10_10_10_3 = {
    9820             :         .type = FT_LB_ADJ,
    9821             :         .adj = {
    9822             :             .adj = ai_10_10_10_3,
    9823             :         },
    9824             :     };
    9825           1 :     fib_test_lb_bucket_t l99_o_10_10_10_3 = {
    9826             :         .type = FT_LB_LABEL_O_ADJ,
    9827             :         .label_o_adj = {
    9828             :             .adj = ai_10_10_10_3,
    9829             :             .label = 99,
    9830             :             .eos = MPLS_EOS,
    9831             :         },
    9832             :     };
    9833             : 
    9834           1 :     fei = fib_table_entry_special_dpo_add(0,
    9835             :                                           &pfx_11_11_11_11_s_32,
    9836             :                                           FIB_SOURCE_SPECIAL,
    9837             :                                           FIB_ENTRY_FLAG_INTERPOSE,
    9838             :                                           &interposer);
    9839           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9840             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9841             :                                       1,
    9842             :                                       &l99_o_10_10_10_3),
    9843             :              "%U via interposer adj",
    9844             :              format_fib_prefix,&pfx_11_11_11_11_s_32);
    9845             : 
    9846           1 :     fib_table_entry_special_remove(0,
    9847             :                                    &pfx_11_11_11_11_s_32,
    9848             :                                    FIB_SOURCE_SPECIAL);
    9849           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9850             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9851             :                                       1,
    9852             :                                       &adj_o_10_10_10_3),
    9853             :              "%U via 10.10.10.1",
    9854             :              format_fib_prefix, &pfx_11_11_11_11_s_32);
    9855           1 :     dpo_reset(&interposer);
    9856           1 :     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
    9857             : 
    9858             :     /*
    9859             :      * add an interposer to a source with path-extensions
    9860             :      */
    9861           1 :     fib_mpls_label_t *l3300 = NULL, fml_3300 = {
    9862             :         .fml_value = 3300,
    9863             :     };
    9864           1 :     vec_add1(l3300, fml_3300);
    9865           1 :     fib_table_entry_update_one_path(0,
    9866             :                                     &pfx_11_11_11_11_s_32,
    9867             :                                     FIB_SOURCE_API,
    9868             :                                     FIB_ENTRY_FLAG_NONE,
    9869             :                                     DPO_PROTO_IP4,
    9870             :                                     &nh_10_10_10_3,
    9871           1 :                                     tm->hw[0]->sw_if_index,
    9872             :                                     ~0,
    9873             :                                     1,
    9874             :                                     l3300,
    9875             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9876             : 
    9877           1 :     mpls_label_dpo_create(l99,
    9878             :                           MPLS_EOS,
    9879             :                           DPO_PROTO_IP4,
    9880             :                           MPLS_LABEL_DPO_FLAG_NONE,
    9881             :                           punt_dpo_get(DPO_PROTO_MPLS),
    9882             :                           &interposer);
    9883             : 
    9884           1 :     adj_index_t ai_mpls_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
    9885             :                                                          VNET_LINK_MPLS,
    9886             :                                                          &nh_10_10_10_3,
    9887           1 :                                                          tm->hw[0]->sw_if_index);
    9888           1 :     fib_test_lb_bucket_t l3300_o_10_10_10_3 = {
    9889             :         .type = FT_LB_LABEL_O_ADJ,
    9890             :         .label_o_adj = {
    9891             :             .adj = ai_mpls_10_10_10_3,
    9892             :             .label = 3300,
    9893             :             .eos = MPLS_EOS,
    9894             :         },
    9895             :     };
    9896           1 :     fib_test_lb_bucket_t lchain_o_10_10_10_3 = {
    9897             :         .type = FT_LB_LABEL_CHAIN_O_ADJ,
    9898             :         .label_chain_o_adj = {
    9899             :             .adj = ai_mpls_10_10_10_3,
    9900             :             .label_chain_size = 2,
    9901             :             .label_chain = {
    9902             :                 99, 3300
    9903             :             },
    9904             :             .eos = MPLS_EOS,
    9905             :         },
    9906             :     };
    9907             : 
    9908           1 :     fei = fib_table_entry_special_dpo_add(0,
    9909             :                                           &pfx_11_11_11_11_s_32,
    9910             :                                           FIB_SOURCE_SPECIAL,
    9911             :                                           FIB_ENTRY_FLAG_INTERPOSE,
    9912             :                                           &interposer);
    9913             : 
    9914           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9915             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9916             :                                       1,
    9917             :                                       &lchain_o_10_10_10_3),
    9918             :              "%U via interposer & mpls on adj",
    9919             :              format_fib_prefix, &pfx_11_11_11_11_s_32);
    9920             : 
    9921           1 :     fib_table_entry_special_remove(0,
    9922             :                                    &pfx_11_11_11_11_s_32,
    9923             :                                    FIB_SOURCE_SPECIAL);
    9924           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9925             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9926             :                                       1,
    9927             :                                       &l3300_o_10_10_10_3),
    9928             :              "%U via 10.10.10.1",
    9929             :              format_fib_prefix, &pfx_11_11_11_11_s_32);
    9930           1 :     adj_unlock(ai_mpls_10_10_10_3);
    9931             : 
    9932             :     /*
    9933             :      * remove and re-add the second best API source while the interpose
    9934             :      * is present
    9935             :      */
    9936           1 :     fei = fib_table_entry_special_dpo_add(0,
    9937             :                                           &pfx_11_11_11_11_s_32,
    9938             :                                           FIB_SOURCE_SPECIAL,
    9939             :                                           FIB_ENTRY_FLAG_INTERPOSE,
    9940             :                                           &interposer);
    9941           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9942             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9943             :                                       1,
    9944             :                                       &lchain_o_10_10_10_3),
    9945             :              "%U via interposer adj",
    9946             :              format_fib_prefix,&pfx_11_11_11_11_s_32);
    9947             : 
    9948           1 :     FIB_TEST(3 == pool_elts(mpls_label_dpo_pool),
    9949             :              "MPLS label pool: %d",
    9950             :              pool_elts(mpls_label_dpo_pool));
    9951             : 
    9952           1 :     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
    9953             : 
    9954             :     /*
    9955             :      * the interpose does not get stacked when there are not valid paths
    9956             :      */
    9957           1 :     fib_test_lb_bucket_t bucket_drop = {
    9958             :         .type = FT_LB_DROP,
    9959             :         .special = {
    9960             :             .adj = DPO_PROTO_IP4,
    9961             :         },
    9962             :     };
    9963           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9964             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9965             :                                       1,
    9966             :                                       &bucket_drop),
    9967             :              "%U via drop",
    9968             :              format_fib_prefix,&pfx_11_11_11_11_s_32);
    9969             : 
    9970           1 :     fib_table_entry_update_one_path(0,
    9971             :                                     &pfx_11_11_11_11_s_32,
    9972             :                                     FIB_SOURCE_API,
    9973             :                                     FIB_ENTRY_FLAG_NONE,
    9974             :                                     DPO_PROTO_IP4,
    9975             :                                     &nh_10_10_10_3,
    9976           1 :                                     tm->hw[0]->sw_if_index,
    9977             :                                     ~0,
    9978             :                                     1,
    9979             :                                     NULL,
    9980             :                                     FIB_ROUTE_PATH_FLAG_NONE);
    9981           1 :     FIB_TEST(!fib_test_validate_entry(fei,
    9982             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
    9983             :                                       1,
    9984             :                                       &l99_o_10_10_10_3),
    9985             :              "%U via interposer adj",
    9986             :              format_fib_prefix,&pfx_11_11_11_11_s_32);
    9987           1 :     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
    9988             : 
    9989             :     /*
    9990             :      * add a cover for the interposed entry, so that we test it selects
    9991             :      * the covers forwarding.
    9992             :      */
    9993           1 :     const fib_prefix_t pfx_11_11_11_0_s_24 = {
    9994             :         .fp_len = 24,
    9995             :         .fp_proto = FIB_PROTOCOL_IP4,
    9996             :         .fp_addr = nh_11_11_11_0,
    9997             :     };
    9998           1 :     fib_table_entry_update_one_path(0,
    9999             :                                     &pfx_11_11_11_0_s_24,
   10000             :                                     FIB_SOURCE_API,
   10001             :                                     FIB_ENTRY_FLAG_NONE,
   10002             :                                     DPO_PROTO_IP4,
   10003             :                                     &nh_10_10_10_3,
   10004           1 :                                     tm->hw[0]->sw_if_index,
   10005             :                                     ~0,
   10006             :                                     1,
   10007             :                                     NULL,
   10008             :                                     FIB_ROUTE_PATH_FLAG_NONE);
   10009           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10010             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10011             :                                       1,
   10012             :                                       &l99_o_10_10_10_3),
   10013             :              "%U via interposer adj",
   10014             :              format_fib_prefix,&pfx_11_11_11_11_s_32);
   10015             : 
   10016             :     /*
   10017             :      * multiple interpose sources on the same entry. Only the high
   10018             :      * priority source gets to add the interpose.
   10019             :      */
   10020           1 :     fib_table_entry_update_one_path(0,
   10021             :                                     &pfx_11_11_11_11_s_32,
   10022             :                                     FIB_SOURCE_API,
   10023             :                                     FIB_ENTRY_FLAG_NONE,
   10024             :                                     DPO_PROTO_IP4,
   10025             :                                     &nh_10_10_10_3,
   10026           1 :                                     tm->hw[0]->sw_if_index,
   10027             :                                     ~0,
   10028             :                                     1,
   10029             :                                     NULL,
   10030             :                                     FIB_ROUTE_PATH_FLAG_NONE);
   10031             : 
   10032           1 :     dpo_id_t interposer2 = DPO_INVALID;
   10033           1 :     fib_mpls_label_t *l100 = NULL, fml_100 = {
   10034             :         .fml_value = 100,
   10035             :     };
   10036           1 :     vec_add1(l100, fml_100);
   10037             : 
   10038           1 :     mpls_label_dpo_create(l100,
   10039             :                           MPLS_EOS,
   10040             :                           DPO_PROTO_IP4,
   10041             :                           MPLS_LABEL_DPO_FLAG_NONE,
   10042             :                           punt_dpo_get(DPO_PROTO_MPLS),
   10043             :                           &interposer2);
   10044             : 
   10045           1 :     fei = fib_table_entry_special_dpo_add(0,
   10046             :                                           &pfx_11_11_11_11_s_32,
   10047             :                                           FIB_SOURCE_CLASSIFY,
   10048             :                                           FIB_ENTRY_FLAG_INTERPOSE,
   10049             :                                           &interposer2);
   10050             : 
   10051           1 :     fib_test_lb_bucket_t lc100_o_10_10_10_3 = {
   10052             :         .type = FT_LB_LABEL_CHAIN_O_ADJ,
   10053             :         .label_chain_o_adj = {
   10054             :             .adj = ai_10_10_10_3,
   10055             :             .label_chain_size = 2,
   10056             :             .label_chain = {
   10057             :                 99, 100
   10058             :             },
   10059             :             .eos = MPLS_EOS,
   10060             :         },
   10061             :     };
   10062             : 
   10063           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10064             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10065             :                                       1,
   10066             :                                       &lc100_o_10_10_10_3),
   10067             :              "%U via interposer label 99",
   10068             :              format_fib_prefix,&pfx_11_11_11_11_s_32);
   10069             : 
   10070           1 :     fib_test_lb_bucket_t l100_o_10_10_10_3 = {
   10071             :         .type = FT_LB_LABEL_O_ADJ,
   10072             :         .label_o_adj = {
   10073             :             .adj = ai_10_10_10_3,
   10074             :             .label = 100,
   10075             :             .eos = MPLS_EOS,
   10076             :         },
   10077             :     };
   10078             : 
   10079           1 :     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_SPECIAL);
   10080             : 
   10081           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10082             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10083             :                                       1,
   10084             :                                       &l100_o_10_10_10_3),
   10085             :              "%U via interposer label 99",
   10086             :              format_fib_prefix,&pfx_11_11_11_11_s_32);
   10087             : 
   10088           1 :     fib_table_entry_delete(0, &pfx_11_11_11_0_s_24, FIB_SOURCE_API);
   10089           1 :     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
   10090           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10091             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10092             :                                       1,
   10093             :                                       &bucket_drop),
   10094             :              "%U via drop",
   10095             :              format_fib_prefix,&pfx_11_11_11_11_s_32);
   10096           1 :     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_CLASSIFY);
   10097             : 
   10098             :     /*
   10099             :      * update a source to/from interpose.
   10100             :      */
   10101             :     /* fib_table_entry_update_one_path(0, */
   10102             :     /*                                 &pfx_11_11_11_0_s_24, */
   10103             :     /*                              FIB_SOURCE_API, */
   10104             :     /*                              FIB_ENTRY_FLAG_NONE, */
   10105             :     /*                              DPO_PROTO_IP4, */
   10106             :     /*                                 &nh_10_10_10_3, */
   10107             :     /*                              tm->hw[0]->sw_if_index, */
   10108             :     /*                              ~0, */
   10109             :     /*                              1, */
   10110             :     /*                              NULL, */
   10111             :     /*                              FIB_ROUTE_PATH_FLAG_NONE); */
   10112             :     /* fei = fib_table_entry_special_dpo_add(0, */
   10113             :     /*                                       &pfx_11_11_11_11_s_32, */
   10114             :     /*                                       FIB_SOURCE_API, */
   10115             :     /*                                       FIB_ENTRY_FLAG_INTERPOSE, */
   10116             :     /*                                       &interposer); */
   10117             :     /* FIB_TEST(!fib_test_validate_entry(fei, */
   10118             :     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
   10119             :     /*                                   1, */
   10120             :     /*                                   &l99_o_10_10_10_3), */
   10121             :     /*          "%U via interposer label 99", */
   10122             :     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
   10123             : 
   10124             :     /* FIB_TEST(3 == pool_elts(mpls_label_dpo_pool), */
   10125             :     /*          "MPLS label pool: %d", */
   10126             :     /*          pool_elts(mpls_label_dpo_pool)); */
   10127             :     /* FIB_TEST((2 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
   10128             :     /*          "Interposer %d locks", */
   10129             :     /*          mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
   10130             : 
   10131             :     /* fib_table_entry_update_one_path(0, */
   10132             :     /*                                 &pfx_11_11_11_11_s_32, */
   10133             :     /*                              FIB_SOURCE_API, */
   10134             :     /*                              FIB_ENTRY_FLAG_NONE, */
   10135             :     /*                              DPO_PROTO_IP4, */
   10136             :     /*                                 &nh_10_10_10_2, */
   10137             :     /*                              tm->hw[0]->sw_if_index, */
   10138             :     /*                              ~0, */
   10139             :     /*                              1, */
   10140             :     /*                              NULL, */
   10141             :     /*                              FIB_ROUTE_PATH_FLAG_NONE); */
   10142             :     /* FIB_TEST(!fib_test_validate_entry(fei, */
   10143             :     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
   10144             :     /*                                   1, */
   10145             :     /*                                   &adj_o_10_10_10_2), */
   10146             :     /*          "%U via 10.10.10.2", */
   10147             :     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
   10148             : 
   10149             :     /* FIB_TEST((1 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
   10150             :     /*          "Interposer %d locks", */
   10151             :     /*          mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
   10152             :     /* FIB_TEST(2 == pool_elts(mpls_label_dpo_pool), */
   10153             :     /*          "MPLS label pool: %d", */
   10154             :     /*          pool_elts(mpls_label_dpo_pool)); */
   10155             : 
   10156             :     /* fei = fib_table_entry_special_dpo_add(0, */
   10157             :     /*                                       &pfx_11_11_11_11_s_32, */
   10158             :     /*                                       FIB_SOURCE_API, */
   10159             :     /*                                       FIB_ENTRY_FLAG_INTERPOSE, */
   10160             :     /*                                       &interposer); */
   10161             :     /* FIB_TEST(!fib_test_validate_entry(fei, */
   10162             :     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
   10163             :     /*                                   1, */
   10164             :     /*                                   &l99_o_10_10_10_3), */
   10165             :     /*          "%U via interposer label 99", */
   10166             :     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
   10167             : 
   10168             :     /* fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API); */
   10169             : 
   10170             :     /*
   10171             :      * Add/remove an interposer source from the top of the subtrie. The
   10172             :      * interposer source is not inherited.
   10173             :      */
   10174           1 :     fib_table_entry_update_one_path(0,
   10175             :                                     &pfx_10_10_10_0_s_24,
   10176             :                                     FIB_SOURCE_API,
   10177             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
   10178             :                                     DPO_PROTO_IP4,
   10179             :                                     &nh_10_10_10_3,
   10180           1 :                                     tm->hw[0]->sw_if_index,
   10181             :                                     ~0,
   10182             :                                     1,
   10183             :                                     NULL,
   10184             :                                     FIB_ROUTE_PATH_FLAG_NONE);
   10185           1 :     fei = fib_table_entry_special_dpo_add(0,
   10186             :                                           &pfx_10_10_10_0_s_24,
   10187             :                                           FIB_SOURCE_SPECIAL,
   10188             :                                           FIB_ENTRY_FLAG_INTERPOSE,
   10189             :                                           &interposer);
   10190           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10191             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10192             :                                       1,
   10193             :                                       &l99_o_10_10_10_3),
   10194             :              "%U via interposer label",
   10195             :              format_fib_prefix,&pfx_10_10_10_0_s_24);
   10196           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
   10197           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10198             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10199             :                                       1,
   10200             :                                       &bucket_drop),
   10201             :              "%U via drop",
   10202             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
   10203             : 
   10204           1 :     fib_table_entry_special_remove(0,
   10205             :                                    &pfx_10_10_10_0_s_24,
   10206             :                                    FIB_SOURCE_SPECIAL);
   10207           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
   10208           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10209             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10210             :                                       1,
   10211             :                                       &adj_o_10_10_10_3),
   10212             :              "%U via 10.10.10.1",
   10213             :              format_fib_prefix, &pfx_10_10_10_0_s_24);
   10214           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
   10215           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10216             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10217             :                                       1,
   10218             :                                       &adj_o_10_10_10_3),
   10219             :              "%U via via 10.10.10.1",
   10220             :              format_fib_prefix, &pfx_10_10_10_21_s_32);
   10221             : 
   10222             :     /*
   10223             :      * Add/remove an interposer source from the top of the subtrie. The
   10224             :      * interposer source is inherited.
   10225             :      */
   10226           1 :     fei = fib_table_entry_special_dpo_add(0,
   10227             :                                           &pfx_10_10_10_0_s_24,
   10228             :                                           FIB_SOURCE_SPECIAL,
   10229             :                                           (FIB_ENTRY_FLAG_COVERED_INHERIT |
   10230             :                                            FIB_ENTRY_FLAG_INTERPOSE),
   10231             :                                           &interposer);
   10232           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10233             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10234             :                                       1,
   10235             :                                       &l99_o_10_10_10_3),
   10236             :              "%U via interposer label",
   10237             :              format_fib_prefix,&pfx_10_10_10_0_s_24);
   10238             : 
   10239             :     /* interposer gets forwarding from the drop cli source */
   10240           1 :     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
   10241           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10242             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10243             :                                       1,
   10244             :                                       &bucket_drop),
   10245             :              "%U via drop",
   10246             :              format_fib_prefix,&pfx_10_10_10_21_s_32);
   10247             : 
   10248           1 :     fib_table_entry_update_one_path(0,
   10249             :                                     &pfx_10_10_10_21_s_32,
   10250             :                                     FIB_SOURCE_API,
   10251             :                                     FIB_ENTRY_FLAG_NONE,
   10252             :                                     DPO_PROTO_IP4,
   10253             :                                     &nh_10_10_10_3,
   10254           1 :                                     tm->hw[0]->sw_if_index,
   10255             :                                     ~0,
   10256             :                                     1,
   10257             :                                     NULL,
   10258             :                                     FIB_ROUTE_PATH_FLAG_NONE);
   10259           1 :     fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_CLI);
   10260             :     /* interposer gets forwarding from the API source */
   10261           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10262             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10263             :                                       1,
   10264             :                                       &l99_o_10_10_10_3),
   10265             :              "%U via interposer label",
   10266             :              format_fib_prefix,&pfx_10_10_10_21_s_32);
   10267             : 
   10268             :     /*
   10269             :      * cleanup
   10270             :      */
   10271           1 :     fib_table_entry_delete(0, &pfx_10_10_10_22_s_32, FIB_SOURCE_CLI);
   10272           1 :     fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_API);
   10273           1 :     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_CLI);
   10274           1 :     fib_table_entry_delete(0, &pfx_10_10_10_255_s_32, FIB_SOURCE_CLI);
   10275           1 :     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_API);
   10276           1 :     fib_table_entry_delete(0, &pfx_10_10_0_0_s_16, FIB_SOURCE_API);
   10277           1 :     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_SPECIAL);
   10278           1 :     adj_unlock(ai_10_10_10_1);
   10279           1 :     adj_unlock(ai_10_10_10_2);
   10280           1 :     adj_unlock(ai_10_10_10_3);
   10281           1 :     dpo_reset(&interposer);
   10282           1 :     dpo_reset(&interposer2);
   10283           1 :     FIB_TEST(0 == pool_elts(mpls_label_dpo_pool),
   10284             :              "MPLS label pool empty: %d",
   10285             :              pool_elts(mpls_label_dpo_pool));
   10286           1 :     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
   10287           1 :     FIB_TEST(N_PLS == fib_path_list_pool_size(),
   10288             :              "number of path-lists: %d = %d",
   10289             :              N_PLS, fib_path_list_pool_size());
   10290             : 
   10291             :     /*
   10292             :      * test the v6 tree walk.
   10293             :      * a /64 that covers everything. a /96 that covers one /128
   10294             :      * a second /128 covered only by the /64.
   10295             :      */
   10296           3 :     const fib_prefix_t pfx_2001_s_64 = {
   10297             :         .fp_len = 64,
   10298             :         .fp_proto = FIB_PROTOCOL_IP6,
   10299             :         .fp_addr = {
   10300             :             .ip6 = {
   10301             :                 .as_u64 = {
   10302           1 :                     [0] = clib_host_to_net_u64(0x2001000000000000),
   10303           1 :                     [1] = clib_host_to_net_u64(0x0000000000000000),
   10304             :                 },
   10305             :             },
   10306             :         },
   10307             :     };
   10308           3 :     const fib_prefix_t pfx_2001_1_s_96 = {
   10309             :         .fp_len = 96,
   10310             :         .fp_proto = FIB_PROTOCOL_IP6,
   10311             :         .fp_addr = {
   10312             :             .ip6 = {
   10313             :                 .as_u64 = {
   10314           1 :                     [0] = clib_host_to_net_u64(0x2001000000000000),
   10315           1 :                     [1] = clib_host_to_net_u64(0x1000000000000000),
   10316             :                 },
   10317             :             },
   10318             :         },
   10319             :     };
   10320           3 :     const fib_prefix_t pfx_2001_1_1_s_128 = {
   10321             :         .fp_len = 128,
   10322             :         .fp_proto = FIB_PROTOCOL_IP6,
   10323             :         .fp_addr = {
   10324             :             .ip6 = {
   10325             :                 .as_u64 = {
   10326           1 :                     [0] = clib_host_to_net_u64(0x2001000000000000),
   10327           1 :                     [1] = clib_host_to_net_u64(0x1000000000000001),
   10328             :                 },
   10329             :             },
   10330             :         },
   10331             :     };
   10332           3 :     const fib_prefix_t pfx_2001_0_1_s_128 = {
   10333             :         .fp_len = 128,
   10334             :         .fp_proto = FIB_PROTOCOL_IP6,
   10335             :         .fp_addr = {
   10336             :             .ip6 = {
   10337             :                 .as_u64 = {
   10338           1 :                     [0] = clib_host_to_net_u64(0x2001000000000000),
   10339           1 :                     [1] = clib_host_to_net_u64(0x0000000000000001),
   10340             :                 },
   10341             :             },
   10342             :         },
   10343             :     };
   10344           2 :     const ip46_address_t nh_3000_1 = {
   10345             :         .ip6 = {
   10346             :             .as_u64 = {
   10347           1 :                 [0] = clib_host_to_net_u64(0x3000000000000000),
   10348           1 :                 [1] = clib_host_to_net_u64(0x0000000000000001),
   10349             :             },
   10350             :         },
   10351             :     };
   10352           2 :     const ip46_address_t nh_3000_2 = {
   10353             :         .ip6 = {
   10354             :             .as_u64 = {
   10355           1 :                 [0] = clib_host_to_net_u64(0x3000000000000000),
   10356           1 :                 [1] = clib_host_to_net_u64(0x0000000000000002),
   10357             :             },
   10358             :         },
   10359             :     };
   10360           1 :     adj_index_t ai_3000_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
   10361             :                                                 VNET_LINK_IP6,
   10362             :                                                 &nh_3000_1,
   10363           1 :                                                 tm->hw[0]->sw_if_index);
   10364           1 :     adj_index_t ai_3000_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
   10365             :                                                 VNET_LINK_IP6,
   10366             :                                                 &nh_3000_2,
   10367           1 :                                                 tm->hw[0]->sw_if_index);
   10368           1 :     fib_test_lb_bucket_t adj_o_3000_1 = {
   10369             :         .type = FT_LB_ADJ,
   10370             :         .adj = {
   10371             :             .adj = ai_3000_1,
   10372             :         },
   10373             :     };
   10374           1 :     fib_test_lb_bucket_t adj_o_3000_2 = {
   10375             :         .type = FT_LB_ADJ,
   10376             :         .adj = {
   10377             :             .adj = ai_3000_2,
   10378             :         },
   10379             :     };
   10380             : 
   10381           1 :     fib_table_entry_special_add(0,
   10382             :                                 &pfx_2001_0_1_s_128,
   10383             :                                 FIB_SOURCE_CLI,
   10384             :                                 FIB_ENTRY_FLAG_DROP);
   10385           1 :     fib_table_entry_special_add(0,
   10386             :                                 &pfx_2001_1_1_s_128,
   10387             :                                 FIB_SOURCE_CLI,
   10388             :                                 FIB_ENTRY_FLAG_DROP);
   10389             : 
   10390             :     /*
   10391             :      * /96 has inherited forwarding pushed down to its covered /128
   10392             :      */
   10393           1 :     fib_table_entry_update_one_path(0,
   10394             :                                     &pfx_2001_1_s_96,
   10395             :                                     FIB_SOURCE_API,
   10396             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
   10397             :                                     DPO_PROTO_IP6,
   10398             :                                     &nh_3000_1,
   10399           1 :                                     tm->hw[0]->sw_if_index,
   10400             :                                     ~0,
   10401             :                                     1,
   10402             :                                     NULL,
   10403             :                                     FIB_ROUTE_PATH_FLAG_NONE);
   10404           1 :     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
   10405           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10406             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
   10407             :                                       1,
   10408             :                                       &adj_o_3000_1),
   10409             :              "%U via 3000::1",
   10410             :              format_fib_prefix, &pfx_2001_1_s_96);
   10411           1 :     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
   10412           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10413             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
   10414             :                                       1,
   10415             :                                       &adj_o_3000_1),
   10416             :              "%U via 3000::1",
   10417             :              format_fib_prefix, &pfx_2001_1_1_s_128);
   10418           1 :     fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
   10419           1 :     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
   10420             :              "%U resolves via drop",
   10421             :              format_fib_prefix, &pfx_2001_0_1_s_128);
   10422             : 
   10423             :     /*
   10424             :      * /64 has inherited forwarding pushed down to all, but the /96
   10425             :      * and its sub-tree remain unaffected.
   10426             :      */
   10427           1 :     fib_table_entry_update_one_path(0,
   10428             :                                     &pfx_2001_s_64,
   10429             :                                     FIB_SOURCE_API,
   10430             :                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
   10431             :                                     DPO_PROTO_IP6,
   10432             :                                     &nh_3000_2,
   10433           1 :                                     tm->hw[0]->sw_if_index,
   10434             :                                     ~0,
   10435             :                                     1,
   10436             :                                     NULL,
   10437             :                                     FIB_ROUTE_PATH_FLAG_NONE);
   10438             : 
   10439           1 :     fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
   10440           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10441             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
   10442             :                                       1,
   10443             :                                       &adj_o_3000_2),
   10444             :              "%U via 3000::2",
   10445             :              format_fib_prefix, &pfx_2001_s_64);
   10446           1 :     fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
   10447           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10448             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
   10449             :                                       1,
   10450             :                                       &adj_o_3000_2),
   10451             :              "%U via 3000::1",
   10452             :              format_fib_prefix, &pfx_2001_0_1_s_128);
   10453             : 
   10454           1 :     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
   10455           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10456             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
   10457             :                                       1,
   10458             :                                       &adj_o_3000_1),
   10459             :              "%U via 3000::1",
   10460             :              format_fib_prefix, &pfx_2001_1_s_96);
   10461           1 :     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
   10462           1 :     FIB_TEST(!fib_test_validate_entry(fei,
   10463             :                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
   10464             :                                       1,
   10465             :                                       &adj_o_3000_1),
   10466             :              "%U via 3000::1",
   10467             :              format_fib_prefix, &pfx_2001_1_1_s_128);
   10468             : 
   10469             :     /*
   10470             :      * Cleanup
   10471             :      */
   10472           1 :     fib_table_entry_delete(0, &pfx_2001_0_1_s_128, FIB_SOURCE_CLI);
   10473           1 :     fib_table_entry_delete(0, &pfx_2001_1_1_s_128, FIB_SOURCE_CLI);
   10474           1 :     fib_table_entry_delete(0, &pfx_2001_s_64,      FIB_SOURCE_API);
   10475           1 :     fib_table_entry_delete(0, &pfx_2001_1_s_96,    FIB_SOURCE_API);
   10476           1 :     adj_unlock(ai_3000_1);
   10477           1 :     adj_unlock(ai_3000_2);
   10478             : 
   10479             :     /*
   10480             :      * test no-one left behind
   10481             :      */
   10482           1 :     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
   10483           1 :     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
   10484             : 
   10485           1 :     return (res);
   10486             : }
   10487             : 
   10488             : static int
   10489           0 : fib_test_sticky (void)
   10490             : {
   10491           0 :     fib_route_path_t *r_paths = NULL;
   10492           0 :     test_main_t *tm = &test_main;
   10493             :     u32 ii, lb_count, pl_count;
   10494           0 :     dpo_id_t dpo = DPO_INVALID;
   10495             :     fib_node_index_t pl_index;
   10496           0 :     int res = 0;
   10497             : #define N_PATHS 16
   10498             : 
   10499             :     fib_test_lb_bucket_t buckets[N_PATHS];
   10500           0 :     bfd_session_t bfds[N_PATHS] = {{0}};
   10501             : 
   10502           0 :     lb_count = pool_elts(load_balance_pool);
   10503           0 :     pl_count = fib_path_list_pool_size();
   10504             : 
   10505           0 :     for (ii = 0; ii < N_PATHS; ii++)
   10506             :     {
   10507           0 :         ip46_address_t nh = {
   10508           0 :             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
   10509             :         };
   10510             :         adj_index_t ai;
   10511             : 
   10512           0 :         ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
   10513             :                                  VNET_LINK_IP4,
   10514           0 :                                  &nh, tm->hw[0]->sw_if_index);
   10515             : 
   10516           0 :         buckets[ii].type = FT_LB_ADJ;
   10517           0 :         buckets[ii].adj.adj = ai;
   10518             : 
   10519           0 :         bfds[ii].udp.key.peer_addr = nh;
   10520           0 :         bfds[ii].udp.key.sw_if_index = tm->hw[0]->sw_if_index;
   10521           0 :         bfds[ii].hop_type = BFD_HOP_TYPE_SINGLE;
   10522           0 :         bfds[ii].local_state = BFD_STATE_init;
   10523           0 :         adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfds[ii]);
   10524           0 :         bfds[ii].local_state = BFD_STATE_up;
   10525           0 :         adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[ii]);
   10526             :     }
   10527             : 
   10528           0 :     for (ii = 0; ii < N_PATHS; ii++)
   10529             :     {
   10530           0 :         fib_route_path_t r_path = {
   10531             :             .frp_proto = DPO_PROTO_IP4,
   10532             :             .frp_addr = {
   10533           0 :                 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
   10534             :             },
   10535           0 :             .frp_sw_if_index = tm->hw[0]->sw_if_index,
   10536             :             .frp_weight = 1,
   10537             :             .frp_fib_index = ~0,
   10538             :         };
   10539           0 :         vec_add1(r_paths, r_path);
   10540             :     };
   10541             : 
   10542           0 :     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths);
   10543           0 :     fib_path_list_lock(pl_index);
   10544             : 
   10545           0 :     fib_path_list_contribute_forwarding(pl_index,
   10546             :                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10547             :                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
   10548             :                                         &dpo);
   10549             : 
   10550           0 :     FIB_TEST(!fib_test_validate_lb(&dpo,
   10551             :                                    16,
   10552             :                                    &buckets[0],
   10553             :                                    &buckets[1],
   10554             :                                    &buckets[2],
   10555             :                                    &buckets[3],
   10556             :                                    &buckets[4],
   10557             :                                    &buckets[5],
   10558             :                                    &buckets[6],
   10559             :                                    &buckets[7],
   10560             :                                    &buckets[8],
   10561             :                                    &buckets[9],
   10562             :                                    &buckets[10],
   10563             :                                    &buckets[11],
   10564             :                                    &buckets[12],
   10565             :                                    &buckets[13],
   10566             :                                    &buckets[14],
   10567             :                                    &buckets[15]),
   10568             :              "Setup OK");
   10569             : 
   10570             :     /* take down paths */
   10571           0 :     bfds[0].local_state = BFD_STATE_down;
   10572           0 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
   10573             : 
   10574           0 :     fib_path_list_contribute_forwarding(pl_index,
   10575             :                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10576             :                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
   10577             :                                         &dpo);
   10578             : 
   10579           0 :     FIB_TEST(!fib_test_validate_lb(&dpo,
   10580             :                                    16,
   10581             :                                    &buckets[1],
   10582             :                                    &buckets[1],
   10583             :                                    &buckets[2],
   10584             :                                    &buckets[3],
   10585             :                                    &buckets[4],
   10586             :                                    &buckets[5],
   10587             :                                    &buckets[6],
   10588             :                                    &buckets[7],
   10589             :                                    &buckets[8],
   10590             :                                    &buckets[9],
   10591             :                                    &buckets[10],
   10592             :                                    &buckets[11],
   10593             :                                    &buckets[12],
   10594             :                                    &buckets[13],
   10595             :                                    &buckets[14],
   10596             :                                    &buckets[15]),
   10597             :              "Failed at shut-down path 0");
   10598             : 
   10599           0 :     bfds[7].local_state = BFD_STATE_down;
   10600           0 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
   10601             : 
   10602           0 :     fib_path_list_contribute_forwarding(pl_index,
   10603             :                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10604             :                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
   10605             :                                         &dpo);
   10606             : 
   10607           0 :     FIB_TEST(!fib_test_validate_lb(&dpo,
   10608             :                                    16,
   10609             :                                    &buckets[1],
   10610             :                                    &buckets[1],
   10611             :                                    &buckets[2],
   10612             :                                    &buckets[3],
   10613             :                                    &buckets[4],
   10614             :                                    &buckets[5],
   10615             :                                    &buckets[6],
   10616             :                                    &buckets[2],
   10617             :                                    &buckets[8],
   10618             :                                    &buckets[9],
   10619             :                                    &buckets[10],
   10620             :                                    &buckets[11],
   10621             :                                    &buckets[12],
   10622             :                                    &buckets[13],
   10623             :                                    &buckets[14],
   10624             :                                    &buckets[15]),
   10625             :              "Failed at shut-down path 7");
   10626             : 
   10627             :     /* paths back up */
   10628           0 :     bfds[0].local_state = BFD_STATE_up;
   10629           0 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
   10630           0 :     bfds[7].local_state = BFD_STATE_up;
   10631           0 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
   10632             : 
   10633           0 :     fib_path_list_contribute_forwarding(pl_index,
   10634             :                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10635             :                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
   10636             :                                         &dpo);
   10637             : 
   10638           0 :     FIB_TEST(!fib_test_validate_lb(&dpo,
   10639             :                                    16,
   10640             :                                    &buckets[0],
   10641             :                                    &buckets[1],
   10642             :                                    &buckets[2],
   10643             :                                    &buckets[3],
   10644             :                                    &buckets[4],
   10645             :                                    &buckets[5],
   10646             :                                    &buckets[6],
   10647             :                                    &buckets[7],
   10648             :                                    &buckets[8],
   10649             :                                    &buckets[9],
   10650             :                                    &buckets[10],
   10651             :                                    &buckets[11],
   10652             :                                    &buckets[12],
   10653             :                                    &buckets[13],
   10654             :                                    &buckets[14],
   10655             :                                    &buckets[15]),
   10656             :              "recovery OK");
   10657             : 
   10658           0 :     fib_path_list_unlock(pl_index);
   10659             : 
   10660             :     /*
   10661             :      * non-power of 2 number of buckets
   10662             :      */
   10663           0 :     fib_route_path_t *r_paths2 = NULL;
   10664             : 
   10665           0 :     r_paths2 = vec_dup(r_paths);
   10666           0 :     vec_set_len (r_paths2, 3);
   10667             : 
   10668           0 :     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths2);
   10669           0 :     fib_path_list_lock(pl_index);
   10670             : 
   10671           0 :     fib_path_list_contribute_forwarding(pl_index,
   10672             :                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10673             :                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
   10674             :                                         &dpo);
   10675             : 
   10676           0 :     FIB_TEST(!fib_test_validate_lb(&dpo,
   10677             :                                    16,
   10678             :                                    &buckets[0],
   10679             :                                    &buckets[0],
   10680             :                                    &buckets[0],
   10681             :                                    &buckets[0],
   10682             :                                    &buckets[0],
   10683             :                                    &buckets[0],
   10684             :                                    &buckets[1],
   10685             :                                    &buckets[1],
   10686             :                                    &buckets[1],
   10687             :                                    &buckets[1],
   10688             :                                    &buckets[1],
   10689             :                                    &buckets[2],
   10690             :                                    &buckets[2],
   10691             :                                    &buckets[2],
   10692             :                                    &buckets[2],
   10693             :                                    &buckets[2]),
   10694             :              "non-power of 2");
   10695             : 
   10696           0 :     bfds[1].local_state = BFD_STATE_down;
   10697           0 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
   10698             : 
   10699           0 :     fib_path_list_contribute_forwarding(pl_index,
   10700             :                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10701             :                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
   10702             :                                         &dpo);
   10703             : 
   10704             :     /*
   10705             :      * path 1's buckets alternate between path 0 and 2
   10706             :      */
   10707           0 :     FIB_TEST(!fib_test_validate_lb(&dpo,
   10708             :                                    16,
   10709             :                                    &buckets[0],
   10710             :                                    &buckets[0],
   10711             :                                    &buckets[0],
   10712             :                                    &buckets[0],
   10713             :                                    &buckets[0],
   10714             :                                    &buckets[0],
   10715             :                                    &buckets[0],
   10716             :                                    &buckets[2],
   10717             :                                    &buckets[0],
   10718             :                                    &buckets[2],
   10719             :                                    &buckets[0],
   10720             :                                    &buckets[2],
   10721             :                                    &buckets[2],
   10722             :                                    &buckets[2],
   10723             :                                    &buckets[2],
   10724             :                                    &buckets[2]),
   10725             :              "non-power of 2");
   10726           0 :     bfds[1].local_state = BFD_STATE_up;
   10727           0 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
   10728             : 
   10729           0 :     fib_path_list_unlock(pl_index);
   10730             : 
   10731             :     /*
   10732             :      * unequal cost
   10733             :      */
   10734           0 :     fib_route_path_t *r_paths3 = NULL;
   10735             : 
   10736           0 :     r_paths3 = vec_dup(r_paths);
   10737           0 :     vec_set_len (r_paths3, 3);
   10738             : 
   10739           0 :     r_paths3[0].frp_weight = 3;
   10740             : 
   10741           0 :     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths3);
   10742           0 :     fib_path_list_lock(pl_index);
   10743             : 
   10744           0 :     fib_path_list_contribute_forwarding(pl_index,
   10745             :                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10746             :                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
   10747             :                                         &dpo);
   10748             : 
   10749           0 :     FIB_TEST(!fib_test_validate_lb(&dpo,
   10750             :                                    16,
   10751             :                                    &buckets[1],
   10752             :                                    &buckets[1],
   10753             :                                    &buckets[1],
   10754             :                                    &buckets[2],
   10755             :                                    &buckets[2],
   10756             :                                    &buckets[2],
   10757             :                                    &buckets[0],
   10758             :                                    &buckets[0],
   10759             :                                    &buckets[0],
   10760             :                                    &buckets[0],
   10761             :                                    &buckets[0],
   10762             :                                    &buckets[0],
   10763             :                                    &buckets[0],
   10764             :                                    &buckets[0],
   10765             :                                    &buckets[0],
   10766             :                                    &buckets[0]),
   10767             :              "UCMP");
   10768             : 
   10769           0 :     bfds[1].local_state = BFD_STATE_down;
   10770           0 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
   10771             : 
   10772           0 :     fib_path_list_contribute_forwarding(pl_index,
   10773             :                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
   10774             :                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
   10775             :                                         &dpo);
   10776             :     /* No attempt to Un-equal distribute the down path's buckets */
   10777           0 :     FIB_TEST(!fib_test_validate_lb(&dpo,
   10778             :                                    16,
   10779             :                                    &buckets[2],
   10780             :                                    &buckets[0],
   10781             :                                    &buckets[2],
   10782             :                                    &buckets[2],
   10783             :                                    &buckets[2],
   10784             :                                    &buckets[2],
   10785             :                                    &buckets[0],
   10786             :                                    &buckets[0],
   10787             :                                    &buckets[0],
   10788             :                                    &buckets[0],
   10789             :                                    &buckets[0],
   10790             :                                    &buckets[0],
   10791             :                                    &buckets[0],
   10792             :                                    &buckets[0],
   10793             :                                    &buckets[0],
   10794             :                                    &buckets[0]),
   10795             :              "UCMP");
   10796           0 :     bfds[1].local_state = BFD_STATE_up;
   10797           0 :     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
   10798             : 
   10799           0 :     dpo_reset(&dpo);
   10800           0 :     fib_path_list_unlock(pl_index);
   10801             : 
   10802           0 :     vec_free(r_paths);
   10803           0 :     vec_free(r_paths2);
   10804           0 :     vec_free(r_paths3);
   10805             : 
   10806           0 :     FIB_TEST(lb_count == pool_elts(load_balance_pool), "no leaked LBs");
   10807           0 :     FIB_TEST(pl_count == fib_path_list_pool_size(), "no leaked PLs");
   10808             : 
   10809           0 :     return 0;
   10810             : }
   10811             : 
   10812             : static clib_error_t *
   10813           1 : fib_test (vlib_main_t * vm,
   10814             :           unformat_input_t * input,
   10815             :           vlib_cli_command_t * cmd_arg)
   10816             : {
   10817             :     int res;
   10818             : 
   10819           1 :     res = 0;
   10820             : 
   10821           1 :     fib_test_mk_intf(4);
   10822             : 
   10823           1 :     if (unformat (input, "debug"))
   10824             :     {
   10825           0 :         fib_test_do_debug = 1;
   10826             :     }
   10827             : 
   10828           1 :     if (unformat (input, "ip4"))
   10829             :     {
   10830           0 :         res += fib_test_v4();
   10831             :     }
   10832           1 :     else if (unformat (input, "ip6"))
   10833             :     {
   10834           0 :         res += fib_test_v6();
   10835             :     }
   10836           1 :     else if (unformat (input, "ip"))
   10837             :     {
   10838           0 :         res += fib_test_v4();
   10839           0 :         res += fib_test_v6();
   10840             :     }
   10841           1 :     else if (unformat (input, "label"))
   10842             :     {
   10843           0 :         res += fib_test_label();
   10844             :     }
   10845           1 :     else if (unformat (input, "ae"))
   10846             :     {
   10847           0 :         res += fib_test_ae();
   10848             :     }
   10849           1 :     else if (unformat (input, "pref"))
   10850             :     {
   10851           0 :         res += fib_test_pref();
   10852             :     }
   10853           1 :     else if (unformat (input, "lfib"))
   10854             :     {
   10855           0 :         res += lfib_test();
   10856             :     }
   10857           1 :     else if (unformat (input, "walk"))
   10858             :     {
   10859           0 :         res += fib_test_walk();
   10860             :     }
   10861           1 :     else if (unformat (input, "bfd"))
   10862             :     {
   10863           0 :         res += fib_test_bfd();
   10864             :     }
   10865           1 :     else if (unformat (input, "inherit"))
   10866             :     {
   10867           0 :         res += fib_test_inherit();
   10868             :     }
   10869           1 :     else if (unformat (input, "sticky"))
   10870             :     {
   10871           0 :         res += fib_test_sticky();
   10872             :     }
   10873             :     else
   10874             :     {
   10875           1 :         res += fib_test_v4();
   10876           1 :         res += fib_test_v6();
   10877           1 :         res += fib_test_ae();
   10878           1 :         res += fib_test_bfd();
   10879           1 :         res += fib_test_pref();
   10880           1 :         res += fib_test_label();
   10881           1 :         res += fib_test_inherit();
   10882           1 :         res += lfib_test();
   10883             : 
   10884             :         /*
   10885             :          * fib-walk process must be disabled in order for the walk tests to work
   10886             :          */
   10887           1 :         fib_walk_process_disable();
   10888           1 :         res += fib_test_walk();
   10889           1 :         fib_walk_process_enable();
   10890             :     }
   10891             : 
   10892           1 :     fflush(NULL);
   10893           1 :     if (res)
   10894             :     {
   10895           0 :         return clib_error_return(0, "FIB Unit Test Failed");
   10896             :     }
   10897             :     else
   10898             :     {
   10899           1 :         return (NULL);
   10900             :     }
   10901             : }
   10902             : 
   10903       16239 : VLIB_CLI_COMMAND (test_fib_command, static) = {
   10904             :     .path = "test fib",
   10905             :     .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
   10906             :     .function = fib_test,
   10907             : };
   10908             : 
   10909             : clib_error_t *
   10910         559 : fib_test_init (vlib_main_t *vm)
   10911             : {
   10912         559 :     return 0;
   10913             : }
   10914             : 
   10915        2239 : VLIB_INIT_FUNCTION (fib_test_init);
   10916             : 
   10917             : // clang-format on

Generated by: LCOV version 1.14