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