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