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