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