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