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