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