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