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