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