VPP-1568:when entry src cover change, recursive-loop fib still can not work.
[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(&ip6_main, 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                   &ip6_main,
4437                   1,
4438                   &pfx_0_0.fp_addr.ip6)),
4439              "default-route; fwd and non-fwd tables match");
4440
4441     // FIXME - check specials.
4442
4443     /*
4444      * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4445      * each with 2 entries and a v6 mfib with 4 path-lists.
4446      * All entries are special so no path-list sharing.
4447      */
4448 #define ENPS (5+4)
4449     u32 PNPS = (5+4+4);
4450     /*
4451      * if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
4452      */
4453     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
4454     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4455              fib_path_list_pool_size());
4456     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4457              fib_entry_pool_size());
4458
4459     /*
4460      * add interface routes.
4461      *  validate presence of /64 attached and /128 recieve.
4462      *  test for the presence of the receive address in the glean and local adj
4463      *
4464      * receive on 2001:0:0:1::1/128
4465      */
4466     fib_prefix_t local_pfx = {
4467         .fp_len = 64,
4468         .fp_proto = FIB_PROTOCOL_IP6,
4469         .fp_addr = {
4470             .ip6 = {
4471                 .as_u64 = {
4472                     [0] = clib_host_to_net_u64(0x2001000000000001),
4473                     [1] = clib_host_to_net_u64(0x0000000000000001),
4474                 },
4475             },
4476         }
4477     };
4478
4479     fib_table_entry_update_one_path(fib_index, &local_pfx,
4480                                     FIB_SOURCE_INTERFACE,
4481                                     (FIB_ENTRY_FLAG_CONNECTED |
4482                                      FIB_ENTRY_FLAG_ATTACHED),
4483                                     DPO_PROTO_IP6,
4484                                     NULL,
4485                                     tm->hw[0]->sw_if_index,
4486                                     ~0,
4487                                     1,
4488                                     NULL,
4489                                     FIB_ROUTE_PATH_FLAG_NONE);
4490     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4491
4492     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4493
4494     ai = fib_entry_get_adj(fei);
4495     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4496     adj = adj_get(ai);
4497     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4498              "attached interface adj is glean");
4499     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4500                                     &adj->sub_type.glean.receive_addr)),
4501              "attached interface adj is receive ok");
4502     dpo = fib_entry_contribute_ip_forwarding(fei);
4503     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4504                   &ip6_main,
4505                   1,
4506                   &local_pfx.fp_addr.ip6)),
4507              "attached-route; fwd and non-fwd tables match");
4508
4509     local_pfx.fp_len = 128;
4510     fib_table_entry_update_one_path(fib_index, &local_pfx,
4511                                     FIB_SOURCE_INTERFACE,
4512                                     (FIB_ENTRY_FLAG_CONNECTED |
4513                                      FIB_ENTRY_FLAG_LOCAL),
4514                                     DPO_PROTO_IP6,
4515                                     NULL,
4516                                     tm->hw[0]->sw_if_index,
4517                                     ~0, // invalid fib index
4518                                     1,
4519                                     NULL,
4520                                     FIB_ROUTE_PATH_FLAG_NONE);
4521     fei = fib_table_lookup(fib_index, &local_pfx);
4522
4523     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4524
4525     dpo = fib_entry_contribute_ip_forwarding(fei);
4526     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4527     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4528              "local interface adj is local");
4529     rd = receive_dpo_get(dpo->dpoi_index);
4530
4531     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4532                                     &rd->rd_addr)),
4533              "local interface adj is receive ok");
4534
4535     dpo = fib_entry_contribute_ip_forwarding(fei);
4536     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4537                   &ip6_main,
4538                   1,
4539                   &local_pfx.fp_addr.ip6)),
4540              "local-route; fwd and non-fwd tables match");
4541
4542     /*
4543      * +2 entries. +2 unshared path-lists
4544      */
4545     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
4546     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4547              fib_path_list_pool_size());
4548     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4549              fib_entry_pool_size());
4550
4551     /*
4552      * Modify the default route to be via an adj not yet known.
4553      * this sources the defalut route with the API source, which is
4554      * a higher preference to the DEFAULT_ROUTE source
4555      */
4556     fib_table_entry_path_add(fib_index, &pfx_0_0,
4557                              FIB_SOURCE_API,
4558                              FIB_ENTRY_FLAG_NONE,
4559                              DPO_PROTO_IP6,
4560                              &nh_2001_2,
4561                              tm->hw[0]->sw_if_index,
4562                              ~0,
4563                              1,
4564                              NULL,
4565                              FIB_ROUTE_PATH_FLAG_NONE);
4566     fei = fib_table_lookup(fib_index, &pfx_0_0);
4567
4568     FIB_TEST((fei == dfrt), "default route same index");
4569     ai = fib_entry_get_adj(fei);
4570     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4571     adj = adj_get(ai);
4572     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4573              "adj is incomplete");
4574     FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4575              "adj nbr next-hop ok");
4576
4577     /*
4578      * find the adj in the shared db
4579      */
4580     locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4581                                     VNET_LINK_IP6,
4582                                     &nh_2001_2,
4583                                     tm->hw[0]->sw_if_index);
4584     FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4585     adj_unlock(locked_ai);
4586
4587     /*
4588      * no more entires. +1 shared path-list
4589      */
4590     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4591              fib_path_list_db_size());
4592     FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4593              fib_path_list_pool_size());
4594     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4595              fib_entry_pool_size());
4596
4597     /*
4598      * remove the API source from the default route. We expected
4599      * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4600      */
4601     fib_table_entry_path_remove(fib_index, &pfx_0_0,
4602                                 FIB_SOURCE_API,
4603                                 DPO_PROTO_IP6,
4604                                 &nh_2001_2,
4605                                 tm->hw[0]->sw_if_index,
4606                                 ~0,
4607                                 1,
4608                                 FIB_ROUTE_PATH_FLAG_NONE);
4609     fei = fib_table_lookup(fib_index, &pfx_0_0);
4610
4611     FIB_TEST((fei == dfrt), "default route same index");
4612     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4613              "Default route is DROP");
4614
4615     /*
4616      * no more entires. -1 shared path-list
4617      */
4618     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4619              fib_path_list_db_size());
4620     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4621              fib_path_list_pool_size());
4622     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4623              fib_entry_pool_size());
4624
4625     /*
4626      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4627      */
4628     fib_prefix_t pfx_2001_1_2_s_128 = {
4629         .fp_len   = 128,
4630         .fp_proto = FIB_PROTOCOL_IP6,
4631         .fp_addr  = {
4632             .ip6 = {
4633                 .as_u64 = {
4634                     [0] = clib_host_to_net_u64(0x2001000000000001),
4635                     [1] = clib_host_to_net_u64(0x0000000000000002),
4636                 },
4637             },
4638         }
4639     };
4640     fib_prefix_t pfx_2001_1_3_s_128 = {
4641         .fp_len   = 128,
4642         .fp_proto = FIB_PROTOCOL_IP6,
4643         .fp_addr  = {
4644             .ip6 = {
4645                 .as_u64 = {
4646                     [0] = clib_host_to_net_u64(0x2001000000000001),
4647                     [1] = clib_host_to_net_u64(0x0000000000000003),
4648                 },
4649             },
4650         }
4651     };
4652     u8 eth_addr[] = {
4653         0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4654     };
4655
4656     ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4657                                 VNET_LINK_IP6,
4658                                 &pfx_2001_1_2_s_128.fp_addr,
4659                                 tm->hw[0]->sw_if_index);
4660     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4661     adj = adj_get(ai_01);
4662     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4663              "adj is incomplete");
4664     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4665                                     &adj->sub_type.nbr.next_hop)),
4666              "adj nbr next-hop ok");
4667
4668     adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4669                            fib_test_build_rewrite(eth_addr));
4670     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4671              "adj is complete");
4672     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4673                                     &adj->sub_type.nbr.next_hop)),
4674              "adj nbr next-hop ok");
4675
4676     fib_table_entry_path_add(fib_index,
4677                              &pfx_2001_1_2_s_128,
4678                              FIB_SOURCE_ADJ,
4679                              FIB_ENTRY_FLAG_ATTACHED,
4680                              DPO_PROTO_IP6,
4681                              &pfx_2001_1_2_s_128.fp_addr,
4682                              tm->hw[0]->sw_if_index,
4683                              ~0,
4684                              1,
4685                              NULL,
4686                              FIB_ROUTE_PATH_FLAG_NONE);
4687
4688     fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4689     ai = fib_entry_get_adj(fei);
4690     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4691
4692     eth_addr[5] = 0xb2;
4693
4694     ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4695                                 VNET_LINK_IP6,
4696                                 &pfx_2001_1_3_s_128.fp_addr,
4697                                 tm->hw[0]->sw_if_index);
4698     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4699     adj = adj_get(ai_02);
4700     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4701              "adj is incomplete");
4702     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4703                                     &adj->sub_type.nbr.next_hop)),
4704              "adj nbr next-hop ok");
4705
4706     adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4707                            fib_test_build_rewrite(eth_addr));
4708     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4709              "adj is complete");
4710     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4711                                     &adj->sub_type.nbr.next_hop)),
4712              "adj nbr next-hop ok");
4713     FIB_TEST((ai_01 != ai_02), "ADJs are different");
4714
4715     fib_table_entry_path_add(fib_index,
4716                              &pfx_2001_1_3_s_128,
4717                              FIB_SOURCE_ADJ,
4718                              FIB_ENTRY_FLAG_ATTACHED,
4719                              DPO_PROTO_IP6,
4720                              &pfx_2001_1_3_s_128.fp_addr,
4721                              tm->hw[0]->sw_if_index,
4722                              ~0,
4723                              1,
4724                              NULL,
4725                              FIB_ROUTE_PATH_FLAG_NONE);
4726
4727     fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4728     ai = fib_entry_get_adj(fei);
4729     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4730
4731     /*
4732      * +2 entries, +2 unshread path-lists.
4733      */
4734     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4735              fib_path_list_db_size());
4736     FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4737              fib_path_list_pool_size());
4738     FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4739              fib_entry_pool_size());
4740
4741     /*
4742      * Add a 2 routes via the first ADJ. ensure path-list sharing
4743      */
4744     fib_prefix_t pfx_2001_a_s_64 = {
4745         .fp_len   = 64,
4746         .fp_proto = FIB_PROTOCOL_IP6,
4747         .fp_addr  = {
4748             .ip6 = {
4749                 .as_u64 = {
4750                     [0] = clib_host_to_net_u64(0x200100000000000a),
4751                     [1] = clib_host_to_net_u64(0x0000000000000000),
4752                 },
4753             },
4754         }
4755     };
4756     fib_prefix_t pfx_2001_b_s_64 = {
4757         .fp_len   = 64,
4758         .fp_proto = FIB_PROTOCOL_IP6,
4759         .fp_addr  = {
4760             .ip6 = {
4761                 .as_u64 = {
4762                     [0] = clib_host_to_net_u64(0x200100000000000b),
4763                     [1] = clib_host_to_net_u64(0x0000000000000000),
4764                 },
4765             },
4766         }
4767     };
4768
4769     fib_table_entry_path_add(fib_index,
4770                              &pfx_2001_a_s_64,
4771                              FIB_SOURCE_API,
4772                              FIB_ENTRY_FLAG_NONE,
4773                              DPO_PROTO_IP6,
4774                              &nh_2001_2,
4775                              tm->hw[0]->sw_if_index,
4776                              ~0,
4777                              1,
4778                              NULL,
4779                              FIB_ROUTE_PATH_FLAG_NONE);
4780     fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4781     ai = fib_entry_get_adj(fei);
4782     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4783     fib_table_entry_path_add(fib_index,
4784                              &pfx_2001_b_s_64,
4785                              FIB_SOURCE_API,
4786                              FIB_ENTRY_FLAG_NONE,
4787                              DPO_PROTO_IP6,
4788                              &nh_2001_2,
4789                              tm->hw[0]->sw_if_index,
4790                              ~0,
4791                              1,
4792                              NULL,
4793                              FIB_ROUTE_PATH_FLAG_NONE);
4794     fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4795     ai = fib_entry_get_adj(fei);
4796     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4797
4798     /*
4799      * +2 entries, +1 shared path-list.
4800      */
4801     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4802              fib_path_list_db_size());
4803     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4804              fib_path_list_pool_size());
4805     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4806              fib_entry_pool_size());
4807
4808     /*
4809      * add a v4 prefix via a v6 next-hop
4810      */
4811     fib_prefix_t pfx_1_1_1_1_s_32 = {
4812         .fp_len = 32,
4813         .fp_proto = FIB_PROTOCOL_IP4,
4814         .fp_addr = {
4815             .ip4.as_u32 = 0x01010101,
4816         },
4817     };
4818     fei = fib_table_entry_path_add(0, // default table
4819                                    &pfx_1_1_1_1_s_32,
4820                                    FIB_SOURCE_API,
4821                                    FIB_ENTRY_FLAG_NONE,
4822                                    DPO_PROTO_IP6,
4823                                    &nh_2001_2,
4824                                    tm->hw[0]->sw_if_index,
4825                                    ~0,
4826                                    1,
4827                                    NULL,
4828                                    FIB_ROUTE_PATH_FLAG_NONE);
4829     FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4830              "1.1.1.1/32 o v6 route present");
4831     ai = fib_entry_get_adj(fei);
4832     adj = adj_get(ai);
4833     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4834              "1.1.1.1/32 via ARP-adj");
4835     FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4836              "1.1.1.1/32 ADJ-adj is link type v4");
4837     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4838              "1.1.1.1/32 ADJ-adj is NH proto v6");
4839     fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4840
4841     /*
4842      * An attached route
4843      */
4844     fib_prefix_t pfx_2001_c_s_64 = {
4845         .fp_len   = 64,
4846         .fp_proto = FIB_PROTOCOL_IP6,
4847         .fp_addr  = {
4848             .ip6 = {
4849                 .as_u64 = {
4850                     [0] = clib_host_to_net_u64(0x200100000000000c),
4851                     [1] = clib_host_to_net_u64(0x0000000000000000),
4852                 },
4853             },
4854         }
4855     };
4856     fib_table_entry_path_add(fib_index,
4857                              &pfx_2001_c_s_64,
4858                              FIB_SOURCE_CLI,
4859                              FIB_ENTRY_FLAG_ATTACHED,
4860                              DPO_PROTO_IP6,
4861                              NULL,
4862                              tm->hw[0]->sw_if_index,
4863                              ~0,
4864                              1,
4865                              NULL,
4866                              FIB_ROUTE_PATH_FLAG_NONE);
4867     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4868     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4869     ai = fib_entry_get_adj(fei);
4870     adj = adj_get(ai);
4871     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4872              "2001:0:0:c/64 attached resolves via glean");
4873
4874     fib_table_entry_path_remove(fib_index,
4875                                 &pfx_2001_c_s_64,
4876                                 FIB_SOURCE_CLI,
4877                                 DPO_PROTO_IP6,
4878                                 NULL,
4879                                 tm->hw[0]->sw_if_index,
4880                                 ~0,
4881                                 1,
4882                                 FIB_ROUTE_PATH_FLAG_NONE);
4883     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4884     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4885
4886     /*
4887      * Shutdown the interface on which we have a connected and through
4888      * which the routes are reachable.
4889      * This will result in the connected, adj-fibs, and routes linking to drop
4890      * The local/for-us prefix continues to receive.
4891      */
4892     clib_error_t * error;
4893
4894     error = vnet_sw_interface_set_flags(vnet_get_main(),
4895                                         tm->hw[0]->sw_if_index,
4896                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4897     FIB_TEST((NULL == error), "Interface shutdown OK");
4898
4899     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4900     dpo = fib_entry_contribute_ip_forwarding(fei);
4901     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4902              "2001::b/64 resolves via drop");
4903
4904     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4905     dpo = fib_entry_contribute_ip_forwarding(fei);
4906     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4907              "2001::a/64 resolves via drop");
4908     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4909     dpo = fib_entry_contribute_ip_forwarding(fei);
4910     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4911              "2001:0:0:1::3/64 resolves via drop");
4912     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4913     dpo = fib_entry_contribute_ip_forwarding(fei);
4914     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4915              "2001:0:0:1::2/64 resolves via drop");
4916     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4917     dpo = fib_entry_contribute_ip_forwarding(fei);
4918     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4919              "2001:0:0:1::1/128 not drop");
4920     local_pfx.fp_len = 64;
4921     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4922     dpo = fib_entry_contribute_ip_forwarding(fei);
4923     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4924              "2001:0:0:1/64 resolves via drop");
4925
4926     /*
4927      * no change
4928      */
4929     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4930              fib_path_list_db_size());
4931     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4932              fib_path_list_pool_size());
4933     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4934              fib_entry_pool_size());
4935
4936     /*
4937      * shutdown one of the other interfaces, then add a connected.
4938      * and swap one of the routes to it.
4939      */
4940     error = vnet_sw_interface_set_flags(vnet_get_main(),
4941                                         tm->hw[1]->sw_if_index,
4942                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4943     FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4944
4945     fib_prefix_t connected_pfx = {
4946         .fp_len = 64,
4947         .fp_proto = FIB_PROTOCOL_IP6,
4948         .fp_addr = {
4949             .ip6 = {
4950                 /* 2001:0:0:2::1/64 */
4951                 .as_u64 = {
4952                     [0] = clib_host_to_net_u64(0x2001000000000002),
4953                     [1] = clib_host_to_net_u64(0x0000000000000001),
4954                 },
4955             },
4956         }
4957     };
4958     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4959                                     FIB_SOURCE_INTERFACE,
4960                                     (FIB_ENTRY_FLAG_CONNECTED |
4961                                      FIB_ENTRY_FLAG_ATTACHED),
4962                                     DPO_PROTO_IP6,
4963                                     NULL,
4964                                     tm->hw[1]->sw_if_index,
4965                                     ~0,
4966                                     1,
4967                                     NULL,
4968                                     FIB_ROUTE_PATH_FLAG_NONE);
4969     fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4970     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4971     dpo = fib_entry_contribute_ip_forwarding(fei);
4972     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4973     FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4974              "2001:0:0:2/64 not resolves via drop");
4975
4976     connected_pfx.fp_len = 128;
4977     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4978                                     FIB_SOURCE_INTERFACE,
4979                                     (FIB_ENTRY_FLAG_CONNECTED |
4980                                      FIB_ENTRY_FLAG_LOCAL),
4981                                     DPO_PROTO_IP6,
4982                                     NULL,
4983                                     tm->hw[0]->sw_if_index,
4984                                     ~0, // invalid fib index
4985                                     1,
4986                                     NULL,
4987                                     FIB_ROUTE_PATH_FLAG_NONE);
4988     fei = fib_table_lookup(fib_index, &connected_pfx);
4989
4990     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4991     dpo = fib_entry_contribute_ip_forwarding(fei);
4992     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4993     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4994              "local interface adj is local");
4995     rd = receive_dpo_get(dpo->dpoi_index);
4996     FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4997                                     &rd->rd_addr)),
4998              "local interface adj is receive ok");
4999
5000     /*
5001      * +2 entries, +2 unshared path-lists
5002      */
5003     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
5004              fib_path_list_db_size());
5005     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5006              fib_path_list_pool_size());
5007     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5008              fib_entry_pool_size());
5009
5010
5011     /*
5012      * bring the interface back up. we expected the routes to return
5013      * to normal forwarding.
5014      */
5015     error = vnet_sw_interface_set_flags(vnet_get_main(),
5016                                         tm->hw[0]->sw_if_index,
5017                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5018     FIB_TEST((NULL == error), "Interface bring-up OK");
5019     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5020     ai = fib_entry_get_adj(fei);
5021     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
5022     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5023     ai = fib_entry_get_adj(fei);
5024     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
5025     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5026     ai = fib_entry_get_adj(fei);
5027     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
5028     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5029     ai = fib_entry_get_adj(fei);
5030     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
5031     local_pfx.fp_len = 64;
5032     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5033     ai = fib_entry_get_adj(fei);
5034     adj = adj_get(ai);
5035     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
5036              "attached interface adj is glean");
5037
5038     /*
5039      * Same test as above, but this time the HW interface goes down
5040      */
5041     error = vnet_hw_interface_set_flags(vnet_get_main(),
5042                                         tm->hw_if_indicies[0],
5043                                         ~VNET_HW_INTERFACE_FLAG_LINK_UP);
5044     FIB_TEST((NULL == error), "Interface shutdown OK");
5045
5046     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5047     dpo = fib_entry_contribute_ip_forwarding(fei);
5048     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5049              "2001::b/64 resolves via drop");
5050     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5051     dpo = fib_entry_contribute_ip_forwarding(fei);
5052     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5053              "2001::a/64 resolves via drop");
5054     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5055     dpo = fib_entry_contribute_ip_forwarding(fei);
5056     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5057              "2001:0:0:1::3/128 resolves via drop");
5058     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5059     dpo = fib_entry_contribute_ip_forwarding(fei);
5060     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5061              "2001:0:0:1::2/128 resolves via drop");
5062     local_pfx.fp_len = 128;
5063     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5064     dpo = fib_entry_contribute_ip_forwarding(fei);
5065     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5066              "2001:0:0:1::1/128 not drop");
5067     local_pfx.fp_len = 64;
5068     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5069     dpo = fib_entry_contribute_ip_forwarding(fei);
5070     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5071              "2001:0:0:1/64 resolves via drop");
5072
5073     error = vnet_hw_interface_set_flags(vnet_get_main(),
5074                                         tm->hw_if_indicies[0],
5075                                         VNET_HW_INTERFACE_FLAG_LINK_UP);
5076     FIB_TEST((NULL == error), "Interface bring-up OK");
5077     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5078     ai = fib_entry_get_adj(fei);
5079     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
5080     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5081     ai = fib_entry_get_adj(fei);
5082     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
5083     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5084     ai = fib_entry_get_adj(fei);
5085     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
5086     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5087     ai = fib_entry_get_adj(fei);
5088     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
5089     local_pfx.fp_len = 64;
5090     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5091     ai = fib_entry_get_adj(fei);
5092     adj = adj_get(ai);
5093     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
5094              "attached interface adj is glean");
5095
5096     /*
5097      * Delete the interface that the routes reolve through.
5098      * Again no routes are removed. They all point to drop.
5099      *
5100      * This is considered an error case. The control plane should
5101      * not remove interfaces through which routes resolve, but
5102      * such things can happen. ALL affected routes will drop.
5103      */
5104     vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
5105
5106     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_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_a_s_64);
5110     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5111              "2001::b/64 resolves via drop");
5112     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5113     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5114              "2001:0:0:1::3/64 resolves via drop");
5115     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5116     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5117              "2001:0:0:1::2/64 resolves via drop");
5118     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5119     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5120              "2001:0:0:1::1/128 is drop");
5121     local_pfx.fp_len = 64;
5122     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5123     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5124              "2001:0:0:1/64 resolves via drop");
5125
5126     /*
5127      * no change
5128      */
5129     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
5130              fib_path_list_db_size());
5131     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5132              fib_path_list_pool_size());
5133     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5134              fib_entry_pool_size());
5135
5136     /*
5137      * Add the interface back. routes stay unresolved.
5138      */
5139     error = ethernet_register_interface(vnet_get_main(),
5140                                         test_interface_device_class.index,
5141                                         0 /* instance */,
5142                                         hw_address,
5143                                         &tm->hw_if_indicies[0],
5144                                         /* flag change */ 0);
5145
5146     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_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_a_s_64);
5150     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5151              "2001::b/64 resolves via drop");
5152     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5153     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5154              "2001:0:0:1::3/64 resolves via drop");
5155     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5156     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5157              "2001:0:0:1::2/64 resolves via drop");
5158     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5159     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5160              "2001:0:0:1::1/128 is drop");
5161     local_pfx.fp_len = 64;
5162     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5163     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5164              "2001:0:0:1/64 resolves via drop");
5165
5166     /*
5167      * CLEANUP ALL the routes
5168      */
5169     fib_table_entry_delete(fib_index,
5170                            &pfx_2001_c_s_64,
5171                            FIB_SOURCE_API);
5172     fib_table_entry_delete(fib_index,
5173                            &pfx_2001_a_s_64,
5174                            FIB_SOURCE_API);
5175     fib_table_entry_delete(fib_index,
5176                            &pfx_2001_b_s_64,
5177                            FIB_SOURCE_API);
5178     fib_table_entry_delete(fib_index,
5179                            &pfx_2001_1_3_s_128,
5180                            FIB_SOURCE_ADJ);
5181     fib_table_entry_delete(fib_index,
5182                            &pfx_2001_1_2_s_128,
5183                            FIB_SOURCE_ADJ);
5184     local_pfx.fp_len = 64;
5185     fib_table_entry_delete(fib_index, &local_pfx,
5186                            FIB_SOURCE_INTERFACE);
5187     local_pfx.fp_len = 128;
5188     fib_table_entry_special_remove(fib_index, &local_pfx,
5189                                    FIB_SOURCE_INTERFACE);
5190     connected_pfx.fp_len = 64;
5191     fib_table_entry_delete(fib_index, &connected_pfx,
5192                            FIB_SOURCE_INTERFACE);
5193     connected_pfx.fp_len = 128;
5194     fib_table_entry_special_remove(fib_index, &connected_pfx,
5195                                    FIB_SOURCE_INTERFACE);
5196
5197     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5198               fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5199              "2001::a/64 removed");
5200     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5201               fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5202              "2001::b/64 removed");
5203     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5204               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5205              "2001:0:0:1::3/128 removed");
5206     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5207               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5208              "2001:0:0:1::3/128 removed");
5209     local_pfx.fp_len = 64;
5210     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5211               fib_table_lookup_exact_match(fib_index, &local_pfx)),
5212              "2001:0:0:1/64 removed");
5213     local_pfx.fp_len = 128;
5214     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5215               fib_table_lookup_exact_match(fib_index, &local_pfx)),
5216              "2001:0:0:1::1/128 removed");
5217     connected_pfx.fp_len = 64;
5218     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5219               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5220              "2001:0:0:2/64 removed");
5221     connected_pfx.fp_len = 128;
5222     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5223               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5224              "2001:0:0:2::1/128 removed");
5225
5226     /*
5227      * -8 entries. -7 path-lists (1 was shared).
5228      */
5229     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
5230              fib_path_list_db_size());
5231     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5232              fib_path_list_pool_size());
5233     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5234              fib_entry_pool_size());
5235
5236     /*
5237      * now remove the VRF
5238      */
5239     fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5240
5241     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
5242              fib_path_list_db_size());
5243     FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5244              fib_path_list_pool_size());
5245     FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5246              fib_entry_pool_size());
5247
5248     adj_unlock(ai_02);
5249     adj_unlock(ai_01);
5250
5251     /*
5252      * return the interfaces to up state
5253      */
5254     error = vnet_sw_interface_set_flags(vnet_get_main(),
5255                                         tm->hw[0]->sw_if_index,
5256                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5257     error = vnet_sw_interface_set_flags(vnet_get_main(),
5258                                         tm->hw[1]->sw_if_index,
5259                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5260
5261     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5262              adj_nbr_db_size());
5263
5264     return (res);
5265 }
5266
5267 /*
5268  * Test Attached Exports
5269  */
5270 static int
5271 fib_test_ae (void)
5272 {
5273     const dpo_id_t *dpo, *dpo_drop;
5274     const u32 fib_index = 0;
5275     fib_node_index_t fei;
5276     test_main_t *tm;
5277     ip4_main_t *im;
5278     int res;
5279
5280     res = 0;
5281     tm = &test_main;
5282     im = &ip4_main;
5283
5284     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5285              adj_nbr_db_size());
5286
5287     /*
5288      * add interface routes. We'll assume this works. It's more rigorously
5289      * tested elsewhere.
5290      */
5291     fib_prefix_t local_pfx = {
5292         .fp_len = 24,
5293         .fp_proto = FIB_PROTOCOL_IP4,
5294         .fp_addr = {
5295             .ip4 = {
5296                 /* 10.10.10.10 */
5297                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5298             },
5299         },
5300     };
5301
5302     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5303     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5304
5305     dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5306
5307     fib_table_entry_update_one_path(fib_index, &local_pfx,
5308                                     FIB_SOURCE_INTERFACE,
5309                                     (FIB_ENTRY_FLAG_CONNECTED |
5310                                      FIB_ENTRY_FLAG_ATTACHED),
5311                                     DPO_PROTO_IP4,
5312                                     NULL,
5313                                     tm->hw[0]->sw_if_index,
5314                                     ~0,
5315                                     1,
5316                                     NULL,
5317                                     FIB_ROUTE_PATH_FLAG_NONE);
5318     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5319     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5320              "attached interface route present");
5321
5322     local_pfx.fp_len = 32;
5323     fib_table_entry_update_one_path(fib_index, &local_pfx,
5324                                     FIB_SOURCE_INTERFACE,
5325                                     (FIB_ENTRY_FLAG_CONNECTED |
5326                                      FIB_ENTRY_FLAG_LOCAL),
5327                                     DPO_PROTO_IP4,
5328                                     NULL,
5329                                     tm->hw[0]->sw_if_index,
5330                                     ~0, // invalid fib index
5331                                     1,
5332                                     NULL,
5333                                     FIB_ROUTE_PATH_FLAG_NONE);
5334     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5335
5336     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5337              "local interface route present");
5338
5339     /*
5340      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5341      */
5342     fib_prefix_t pfx_10_10_10_1_s_32 = {
5343         .fp_len = 32,
5344         .fp_proto = FIB_PROTOCOL_IP4,
5345         .fp_addr = {
5346             /* 10.10.10.1 */
5347             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5348         },
5349     };
5350     fib_node_index_t ai;
5351
5352     fib_table_entry_path_add(fib_index,
5353                              &pfx_10_10_10_1_s_32,
5354                              FIB_SOURCE_ADJ,
5355                              FIB_ENTRY_FLAG_ATTACHED,
5356                              DPO_PROTO_IP4,
5357                              &pfx_10_10_10_1_s_32.fp_addr,
5358                              tm->hw[0]->sw_if_index,
5359                              ~0, // invalid fib index
5360                              1,
5361                              NULL,
5362                              FIB_ROUTE_PATH_FLAG_NONE);
5363
5364     fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5365     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5366     ai = fib_entry_get_adj(fei);
5367
5368     /*
5369      * create another FIB table into which routes will be imported
5370      */
5371     u32 import_fib_index1;
5372
5373     import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5374                                                           11,
5375                                                           FIB_SOURCE_CLI);
5376
5377     /*
5378      * Add an attached route in the import FIB
5379      */
5380     local_pfx.fp_len = 24;
5381     fib_table_entry_update_one_path(import_fib_index1,
5382                                     &local_pfx,
5383                                     FIB_SOURCE_API,
5384                                     FIB_ENTRY_FLAG_NONE,
5385                                     DPO_PROTO_IP4,
5386                                     NULL,
5387                                     tm->hw[0]->sw_if_index,
5388                                     ~0, // invalid fib index
5389                                     1,
5390                                     NULL,
5391                                     FIB_ROUTE_PATH_FLAG_NONE);
5392     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5393     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5394
5395     /*
5396      * check for the presence of the adj-fibs in the import table
5397      */
5398     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5399     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5400     FIB_TEST((ai == fib_entry_get_adj(fei)),
5401              "adj-fib1 Import uses same adj as export");
5402
5403     /*
5404      * check for the presence of the local in the import table
5405      */
5406     local_pfx.fp_len = 32;
5407     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5408     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5409
5410     /*
5411      * Add another adj-fin in the export table. Expect this
5412      * to get magically exported;
5413      */
5414     fib_prefix_t pfx_10_10_10_2_s_32 = {
5415         .fp_len = 32,
5416         .fp_proto = FIB_PROTOCOL_IP4,
5417         .fp_addr = {
5418             /* 10.10.10.2 */
5419             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5420         },
5421     };
5422
5423     fib_table_entry_path_add(fib_index,
5424                              &pfx_10_10_10_2_s_32,
5425                              FIB_SOURCE_ADJ,
5426                              FIB_ENTRY_FLAG_ATTACHED,
5427                              DPO_PROTO_IP4,
5428                              &pfx_10_10_10_2_s_32.fp_addr,
5429                              tm->hw[0]->sw_if_index,
5430                              ~0, // invalid fib index
5431                              1,
5432                              NULL,
5433                              FIB_ROUTE_PATH_FLAG_NONE);
5434     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5435     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5436     ai = fib_entry_get_adj(fei);
5437
5438     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5439     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5440     FIB_TEST((ai == fib_entry_get_adj(fei)),
5441              "Import uses same adj as export");
5442     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5443              "ADJ-fib2 imported flags %d",
5444              fib_entry_get_flags(fei));
5445
5446     /*
5447      * create a 2nd FIB table into which routes will be imported
5448      */
5449     u32 import_fib_index2;
5450
5451     import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5452                                                           FIB_SOURCE_CLI);
5453
5454     /*
5455      * Add an attached route in the import FIB
5456      */
5457     local_pfx.fp_len = 24;
5458     fib_table_entry_update_one_path(import_fib_index2,
5459                                     &local_pfx,
5460                                     FIB_SOURCE_API,
5461                                     FIB_ENTRY_FLAG_NONE,
5462                                     DPO_PROTO_IP4,
5463                                     NULL,
5464                                     tm->hw[0]->sw_if_index,
5465                                     ~0, // invalid fib index
5466                                     1,
5467                                     NULL,
5468                                     FIB_ROUTE_PATH_FLAG_NONE);
5469     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5470     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5471
5472     /*
5473      * check for the presence of all the adj-fibs and local in the import table
5474      */
5475     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5476     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5477     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5478     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5479     local_pfx.fp_len = 32;
5480     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5481     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5482
5483     /*
5484      * add a 3rd adj-fib. expect it to be exported to both tables.
5485      */
5486     fib_prefix_t pfx_10_10_10_3_s_32 = {
5487         .fp_len = 32,
5488         .fp_proto = FIB_PROTOCOL_IP4,
5489         .fp_addr = {
5490             /* 10.10.10.3 */
5491             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5492         },
5493     };
5494
5495     fib_table_entry_path_add(fib_index,
5496                              &pfx_10_10_10_3_s_32,
5497                              FIB_SOURCE_ADJ,
5498                              FIB_ENTRY_FLAG_ATTACHED,
5499                              DPO_PROTO_IP4,
5500                              &pfx_10_10_10_3_s_32.fp_addr,
5501                              tm->hw[0]->sw_if_index,
5502                              ~0, // invalid fib index
5503                              1,
5504                              NULL,
5505                              FIB_ROUTE_PATH_FLAG_NONE);
5506     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5507     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5508     ai = fib_entry_get_adj(fei);
5509
5510     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5511     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5512     FIB_TEST((ai == fib_entry_get_adj(fei)),
5513              "Import uses same adj as export");
5514     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5515     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5516     FIB_TEST((ai == fib_entry_get_adj(fei)),
5517              "Import uses same adj as export");
5518
5519     /*
5520      * remove the 3rd adj fib. we expect it to be removed from both FIBs
5521      */
5522     fib_table_entry_delete(fib_index,
5523                            &pfx_10_10_10_3_s_32,
5524                            FIB_SOURCE_ADJ);
5525
5526     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5527     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5528
5529     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5530     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5531
5532     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5533     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5534
5535     /*
5536      * remove the attached route from the 2nd FIB. expect the imported
5537      * entires to be removed
5538      */
5539     local_pfx.fp_len = 24;
5540     fib_table_entry_delete(import_fib_index2,
5541                            &local_pfx,
5542                            FIB_SOURCE_API);
5543     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5544     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5545
5546     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5547     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5548     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5549     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5550     local_pfx.fp_len = 32;
5551     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5552     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5553
5554     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5555     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5556     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5557     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5558     local_pfx.fp_len = 32;
5559     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5560     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5561
5562     /*
5563      * modify the route in FIB1 so it is no longer attached. expect the imported
5564      * entires to be removed
5565      */
5566     local_pfx.fp_len = 24;
5567     fib_table_entry_update_one_path(import_fib_index1,
5568                                     &local_pfx,
5569                                     FIB_SOURCE_API,
5570                                     FIB_ENTRY_FLAG_NONE,
5571                                     DPO_PROTO_IP4,
5572                                     &pfx_10_10_10_2_s_32.fp_addr,
5573                                     tm->hw[0]->sw_if_index,
5574                                     ~0, // invalid fib index
5575                                     1,
5576                                     NULL,
5577                                     FIB_ROUTE_PATH_FLAG_NONE);
5578     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5579     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5580     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5581     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5582     local_pfx.fp_len = 32;
5583     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5584     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5585
5586     /*
5587      * modify it back to attached. expect the adj-fibs back
5588      */
5589     local_pfx.fp_len = 24;
5590     fib_table_entry_update_one_path(import_fib_index1,
5591                                     &local_pfx,
5592                                     FIB_SOURCE_API,
5593                                     FIB_ENTRY_FLAG_NONE,
5594                                     DPO_PROTO_IP4,
5595                                     NULL,
5596                                     tm->hw[0]->sw_if_index,
5597                                     ~0, // invalid fib index
5598                                     1,
5599                                     NULL,
5600                                     FIB_ROUTE_PATH_FLAG_NONE);
5601     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5602     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5603     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5604     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5605     local_pfx.fp_len = 32;
5606     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5607     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5608
5609     /*
5610      * add a covering attached next-hop for the interface address, so we have
5611      * a valid adj to find when we check the forwarding tables
5612      */
5613     fib_prefix_t pfx_10_0_0_0_s_8 = {
5614         .fp_len = 8,
5615         .fp_proto = FIB_PROTOCOL_IP4,
5616         .fp_addr = {
5617             /* 10.0.0.0 */
5618             .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5619         },
5620     };
5621
5622     fei = fib_table_entry_update_one_path(fib_index,
5623                                           &pfx_10_0_0_0_s_8,
5624                                           FIB_SOURCE_API,
5625                                           FIB_ENTRY_FLAG_NONE,
5626                                           DPO_PROTO_IP4,
5627                                           &pfx_10_10_10_3_s_32.fp_addr,
5628                                           tm->hw[0]->sw_if_index,
5629                                           ~0, // invalid fib index
5630                                           1,
5631                                           NULL,
5632                                           FIB_ROUTE_PATH_FLAG_NONE);
5633     dpo = fib_entry_contribute_ip_forwarding(fei);
5634
5635     /*
5636      * remove the route in the export fib. expect the adj-fibs to be removed
5637      */
5638     local_pfx.fp_len = 24;
5639     fib_table_entry_delete(fib_index,
5640                            &local_pfx,
5641                            FIB_SOURCE_INTERFACE);
5642
5643     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5644     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5645     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5646     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5647     local_pfx.fp_len = 32;
5648     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5649     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5650
5651     /*
5652      * the adj-fibs in the export VRF are present in the FIB table,
5653      * but not installed in forwarding, since they have no attached cover.
5654      * Consequently a lookup in the MTRIE gives the adj for the covering
5655      * route 10.0.0.0/8.
5656      */
5657     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5658     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5659
5660     index_t lbi;
5661     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5662     FIB_TEST(lbi == dpo->dpoi_index,
5663              "10.10.10.1 forwards on \n%U not \n%U",
5664              format_load_balance, lbi, 0,
5665              format_dpo_id, dpo, 0);
5666     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5667     FIB_TEST(lbi == dpo->dpoi_index,
5668              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5669     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5670     FIB_TEST(lbi == dpo->dpoi_index,
5671              "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5672
5673     /*
5674      * add the export prefix back, but not as attached.
5675      * No adj-fibs in export nor import tables
5676      */
5677     local_pfx.fp_len = 24;
5678     fei = fib_table_entry_update_one_path(fib_index,
5679                                           &local_pfx,
5680                                           FIB_SOURCE_API,
5681                                           FIB_ENTRY_FLAG_NONE,
5682                                           DPO_PROTO_IP4,
5683                                           &pfx_10_10_10_1_s_32.fp_addr,
5684                                           tm->hw[0]->sw_if_index,
5685                                           ~0, // invalid fib index
5686                                           1,
5687                                           NULL,
5688                                           FIB_ROUTE_PATH_FLAG_NONE);
5689     dpo = fib_entry_contribute_ip_forwarding(fei);
5690
5691     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5692     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5693     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5694     FIB_TEST(lbi == dpo->dpoi_index,
5695              "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5696     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5697     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5698     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5699     FIB_TEST(lbi == dpo->dpoi_index,
5700              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5701
5702     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5703     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5704     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5705     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5706     local_pfx.fp_len = 32;
5707     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5708     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5709
5710     /*
5711      * modify the export prefix so it is attached. expect all covereds to return
5712      */
5713     local_pfx.fp_len = 24;
5714     fib_table_entry_update_one_path(fib_index,
5715                                     &local_pfx,
5716                                     FIB_SOURCE_API,
5717                                     FIB_ENTRY_FLAG_NONE,
5718                                     DPO_PROTO_IP4,
5719                                     NULL,
5720                                     tm->hw[0]->sw_if_index,
5721                                     ~0, // invalid fib index
5722                                     1,
5723                                     NULL,
5724                                     FIB_ROUTE_PATH_FLAG_NONE);
5725
5726     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5727     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5728     dpo = fib_entry_contribute_ip_forwarding(fei);
5729     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5730              "Adj-fib1 is not drop in export");
5731     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5732     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5733     local_pfx.fp_len = 32;
5734     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5735     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5736     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5737     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5738     dpo = fib_entry_contribute_ip_forwarding(fei);
5739     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5740              "Adj-fib1 is not drop in export: %U %U",
5741              format_dpo_id, dpo, 0,
5742              format_dpo_id, load_balance_get_bucket(dpo->dpoi_index, 0), 0);
5743     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5744     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5745     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5746     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5747     local_pfx.fp_len = 32;
5748     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5749     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5750
5751     /*
5752      * modify the export prefix so connected. no change.
5753      */
5754     local_pfx.fp_len = 24;
5755     fib_table_entry_update_one_path(fib_index, &local_pfx,
5756                                     FIB_SOURCE_INTERFACE,
5757                                     (FIB_ENTRY_FLAG_CONNECTED |
5758                                      FIB_ENTRY_FLAG_ATTACHED),
5759                                     DPO_PROTO_IP4,
5760                                     NULL,
5761                                     tm->hw[0]->sw_if_index,
5762                                     ~0,
5763                                     1,
5764                                     NULL,
5765                                     FIB_ROUTE_PATH_FLAG_NONE);
5766
5767     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5768     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5769     dpo = fib_entry_contribute_ip_forwarding(fei);
5770     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5771              "Adj-fib1 is not drop in export");
5772     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5773     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5774     local_pfx.fp_len = 32;
5775     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5776     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5777     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5778     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5779     dpo = fib_entry_contribute_ip_forwarding(fei);
5780     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5781              "Adj-fib1 is not drop in export");
5782     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5783     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5784     local_pfx.fp_len = 32;
5785     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5786     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5787
5788     /*
5789      * CLEANUP
5790      */
5791     fib_table_entry_delete(fib_index,
5792                            &pfx_10_0_0_0_s_8,
5793                            FIB_SOURCE_API);
5794     fib_table_entry_delete(fib_index,
5795                            &pfx_10_10_10_1_s_32,
5796                            FIB_SOURCE_ADJ);
5797     fib_table_entry_delete(fib_index,
5798                            &pfx_10_10_10_2_s_32,
5799                            FIB_SOURCE_ADJ);
5800     local_pfx.fp_len = 32;
5801     fib_table_entry_delete(fib_index,
5802                            &local_pfx,
5803                            FIB_SOURCE_INTERFACE);
5804     local_pfx.fp_len = 24;
5805     fib_table_entry_delete(fib_index,
5806                            &local_pfx,
5807                            FIB_SOURCE_API);
5808     fib_table_entry_delete(fib_index,
5809                            &local_pfx,
5810                            FIB_SOURCE_INTERFACE);
5811     local_pfx.fp_len = 24;
5812     fib_table_entry_delete(import_fib_index1,
5813                            &local_pfx,
5814                            FIB_SOURCE_API);
5815
5816     fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5817     fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5818
5819     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5820              adj_nbr_db_size());
5821
5822     return (res);
5823 }
5824
5825 /*
5826  * Test Path Preference
5827  */
5828 static int
5829 fib_test_pref (void)
5830 {
5831     test_main_t *tm = &test_main;
5832     int res;
5833
5834     res = 0;
5835     const fib_prefix_t pfx_1_1_1_1_s_32 = {
5836         .fp_len = 32,
5837         .fp_proto = FIB_PROTOCOL_IP4,
5838         .fp_addr = {
5839             .ip4 = {
5840                 .as_u32 = clib_host_to_net_u32(0x01010101),
5841             },
5842         },
5843     };
5844
5845     /*
5846      * 2 high, 2 medium and 2 low preference non-recursive paths
5847      */
5848     fib_route_path_t nr_path_hi_1 = {
5849         .frp_proto = DPO_PROTO_IP4,
5850         .frp_sw_if_index = tm->hw[0]->sw_if_index,
5851         .frp_fib_index = ~0,
5852         .frp_weight = 1,
5853         .frp_preference = 0,
5854         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5855         .frp_addr = {
5856             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5857         },
5858     };
5859     fib_route_path_t nr_path_hi_2 = {
5860         .frp_proto = DPO_PROTO_IP4,
5861         .frp_sw_if_index = tm->hw[0]->sw_if_index,
5862         .frp_fib_index = ~0,
5863         .frp_weight = 1,
5864         .frp_preference = 0,
5865         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5866         .frp_addr = {
5867             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5868         },
5869     };
5870     fib_route_path_t nr_path_med_1 = {
5871         .frp_proto = DPO_PROTO_IP4,
5872         .frp_sw_if_index = tm->hw[1]->sw_if_index,
5873         .frp_fib_index = ~0,
5874         .frp_weight = 1,
5875         .frp_preference = 1,
5876         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5877         .frp_addr = {
5878             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5879         },
5880     };
5881     fib_route_path_t nr_path_med_2 = {
5882         .frp_proto = DPO_PROTO_IP4,
5883         .frp_sw_if_index = tm->hw[1]->sw_if_index,
5884         .frp_fib_index = ~0,
5885         .frp_weight = 1,
5886         .frp_preference = 1,
5887         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5888         .frp_addr = {
5889             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5890         },
5891     };
5892     fib_route_path_t nr_path_low_1 = {
5893         .frp_proto = DPO_PROTO_IP4,
5894         .frp_sw_if_index = tm->hw[2]->sw_if_index,
5895         .frp_fib_index = ~0,
5896         .frp_weight = 1,
5897         .frp_preference = 2,
5898         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5899         .frp_addr = {
5900             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5901         },
5902     };
5903     fib_route_path_t nr_path_low_2 = {
5904         .frp_proto = DPO_PROTO_IP4,
5905         .frp_sw_if_index = tm->hw[2]->sw_if_index,
5906         .frp_fib_index = ~0,
5907         .frp_weight = 1,
5908         .frp_preference = 2,
5909         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5910         .frp_addr = {
5911             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5912         },
5913     };
5914     fib_route_path_t *nr_paths = NULL;
5915
5916     vec_add1(nr_paths, nr_path_hi_1);
5917     vec_add1(nr_paths, nr_path_hi_2);
5918     vec_add1(nr_paths, nr_path_med_1);
5919     vec_add1(nr_paths, nr_path_med_2);
5920     vec_add1(nr_paths, nr_path_low_1);
5921     vec_add1(nr_paths, nr_path_low_2);
5922
5923     adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5924                                               VNET_LINK_IP4,
5925                                               &nr_path_hi_1.frp_addr,
5926                                               nr_path_hi_1.frp_sw_if_index);
5927     adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5928                                               VNET_LINK_IP4,
5929                                               &nr_path_hi_2.frp_addr,
5930                                               nr_path_hi_2.frp_sw_if_index);
5931     adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5932                                                VNET_LINK_IP4,
5933                                                &nr_path_med_1.frp_addr,
5934                                                nr_path_med_1.frp_sw_if_index);
5935     adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5936                                                VNET_LINK_IP4,
5937                                                &nr_path_med_2.frp_addr,
5938                                                nr_path_med_2.frp_sw_if_index);
5939     adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5940                                                VNET_LINK_IP4,
5941                                                &nr_path_low_1.frp_addr,
5942                                                nr_path_low_1.frp_sw_if_index);
5943     adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5944                                                VNET_LINK_IP4,
5945                                                &nr_path_low_2.frp_addr,
5946                                                nr_path_low_2.frp_sw_if_index);
5947
5948     fib_test_lb_bucket_t ip_hi_1 = {
5949         .type = FT_LB_ADJ,
5950         .adj = {
5951             .adj = ai_hi_1,
5952         },
5953     };
5954     fib_test_lb_bucket_t ip_hi_2 = {
5955         .type = FT_LB_ADJ,
5956         .adj = {
5957             .adj = ai_hi_2,
5958         },
5959     };
5960     fib_test_lb_bucket_t ip_med_1 = {
5961         .type = FT_LB_ADJ,
5962         .adj = {
5963             .adj = ai_med_1,
5964         },
5965     };
5966     fib_test_lb_bucket_t ip_med_2 = {
5967         .type = FT_LB_ADJ,
5968         .adj = {
5969             .adj = ai_med_2,
5970         },
5971     };
5972     fib_test_lb_bucket_t ip_low_1 = {
5973         .type = FT_LB_ADJ,
5974         .adj = {
5975             .adj = ai_low_1,
5976         },
5977     };
5978     fib_test_lb_bucket_t ip_low_2 = {
5979         .type = FT_LB_ADJ,
5980         .adj = {
5981             .adj = ai_low_2,
5982         },
5983     };
5984
5985     fib_node_index_t fei;
5986
5987     fei = fib_table_entry_path_add2(0,
5988                                     &pfx_1_1_1_1_s_32,
5989                                     FIB_SOURCE_API,
5990                                     FIB_ENTRY_FLAG_NONE,
5991                                     nr_paths);
5992
5993     FIB_TEST(!fib_test_validate_entry(fei,
5994                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5995                                       2,
5996                                       &ip_hi_1,
5997                                       &ip_hi_2),
5998              "1.1.1.1/32 via high preference paths");
5999
6000     /*
6001      * bring down the interface on which the high preference path lie
6002      */
6003     vnet_sw_interface_set_flags(vnet_get_main(),
6004                                 tm->hw[0]->sw_if_index,
6005                                 0);
6006
6007     FIB_TEST(!fib_test_validate_entry(fei,
6008                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6009                                       2,
6010                                       &ip_med_1,
6011                                       &ip_med_2),
6012              "1.1.1.1/32 via medium preference paths");
6013
6014     /*
6015      * bring down the interface on which the medium preference path lie
6016      */
6017     vnet_sw_interface_set_flags(vnet_get_main(),
6018                                 tm->hw[1]->sw_if_index,
6019                                 0);
6020
6021     FIB_TEST(!fib_test_validate_entry(fei,
6022                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6023                                       2,
6024                                       &ip_low_1,
6025                                       &ip_low_2),
6026              "1.1.1.1/32 via low preference paths");
6027
6028     /*
6029      * bring up the interface on which the high preference path lie
6030      */
6031     vnet_sw_interface_set_flags(vnet_get_main(),
6032                                 tm->hw[0]->sw_if_index,
6033                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6034
6035     FIB_TEST(!fib_test_validate_entry(fei,
6036                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6037                                       2,
6038                                       &ip_hi_1,
6039                                       &ip_hi_2),
6040              "1.1.1.1/32 via high preference paths");
6041
6042     /*
6043      * bring up the interface on which the medium preference path lie
6044      */
6045     vnet_sw_interface_set_flags(vnet_get_main(),
6046                                 tm->hw[1]->sw_if_index,
6047                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6048
6049     FIB_TEST(!fib_test_validate_entry(fei,
6050                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6051                                       2,
6052                                       &ip_hi_1,
6053                                       &ip_hi_2),
6054              "1.1.1.1/32 via high preference paths");
6055
6056     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6057     fib_entry_contribute_forwarding(fei,
6058                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6059                                     &ip_1_1_1_1);
6060
6061     /*
6062      * 3 recursive paths of different preference
6063      */
6064     const fib_prefix_t pfx_1_1_1_2_s_32 = {
6065         .fp_len = 32,
6066         .fp_proto = FIB_PROTOCOL_IP4,
6067         .fp_addr = {
6068             .ip4 = {
6069                 .as_u32 = clib_host_to_net_u32(0x01010102),
6070             },
6071         },
6072     };
6073     const fib_prefix_t pfx_1_1_1_3_s_32 = {
6074         .fp_len = 32,
6075         .fp_proto = FIB_PROTOCOL_IP4,
6076         .fp_addr = {
6077             .ip4 = {
6078                 .as_u32 = clib_host_to_net_u32(0x01010103),
6079             },
6080         },
6081     };
6082     fei = fib_table_entry_path_add2(0,
6083                                     &pfx_1_1_1_2_s_32,
6084                                     FIB_SOURCE_API,
6085                                     FIB_ENTRY_FLAG_NONE,
6086                                     nr_paths);
6087     dpo_id_t ip_1_1_1_2 = DPO_INVALID;
6088     fib_entry_contribute_forwarding(fei,
6089                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6090                                     &ip_1_1_1_2);
6091     fei = fib_table_entry_path_add2(0,
6092                                     &pfx_1_1_1_3_s_32,
6093                                     FIB_SOURCE_API,
6094                                     FIB_ENTRY_FLAG_NONE,
6095                                     nr_paths);
6096     dpo_id_t ip_1_1_1_3 = DPO_INVALID;
6097     fib_entry_contribute_forwarding(fei,
6098                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6099                                     &ip_1_1_1_3);
6100
6101     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6102         .type = FT_LB_O_LB,
6103         .lb = {
6104             .lb = ip_1_1_1_1.dpoi_index,
6105         },
6106     };
6107     fib_test_lb_bucket_t ip_o_1_1_1_2 = {
6108         .type = FT_LB_O_LB,
6109         .lb = {
6110             .lb = ip_1_1_1_2.dpoi_index,
6111         },
6112     };
6113     fib_test_lb_bucket_t ip_o_1_1_1_3 = {
6114         .type = FT_LB_O_LB,
6115         .lb = {
6116             .lb = ip_1_1_1_3.dpoi_index,
6117         },
6118     };
6119     fib_route_path_t r_path_hi = {
6120         .frp_proto = DPO_PROTO_IP4,
6121         .frp_sw_if_index = ~0,
6122         .frp_fib_index = 0,
6123         .frp_weight = 1,
6124         .frp_preference = 0,
6125         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6126         .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
6127     };
6128     fib_route_path_t r_path_med = {
6129         .frp_proto = DPO_PROTO_IP4,
6130         .frp_sw_if_index = ~0,
6131         .frp_fib_index = 0,
6132         .frp_weight = 1,
6133         .frp_preference = 10,
6134         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6135         .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
6136     };
6137     fib_route_path_t r_path_low = {
6138         .frp_proto = DPO_PROTO_IP4,
6139         .frp_sw_if_index = ~0,
6140         .frp_fib_index = 0,
6141         .frp_weight = 1,
6142         .frp_preference = 255,
6143         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6144         .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
6145     };
6146     fib_route_path_t *r_paths = NULL;
6147
6148     vec_add1(r_paths, r_path_hi);
6149     vec_add1(r_paths, r_path_low);
6150     vec_add1(r_paths, r_path_med);
6151
6152     /*
6153      * add many recursive so we get the LB MAp created
6154      */
6155 #define N_PFXS 64
6156     fib_prefix_t pfx_r[N_PFXS];
6157     unsigned int n_pfxs;
6158     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6159     {
6160         pfx_r[n_pfxs].fp_len = 32;
6161         pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
6162         pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
6163             clib_host_to_net_u32(0x02000000 + n_pfxs);
6164
6165         fei = fib_table_entry_path_add2(0,
6166                                         &pfx_r[n_pfxs],
6167                                         FIB_SOURCE_API,
6168                                         FIB_ENTRY_FLAG_NONE,
6169                                         r_paths);
6170
6171         FIB_TEST(!fib_test_validate_entry(fei,
6172                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6173                                           1,
6174                                           &ip_o_1_1_1_1),
6175                  "recursive via high preference paths");
6176
6177         /*
6178          * withdraw hig pref resolving entry
6179          */
6180         fib_table_entry_delete(0,
6181                                &pfx_1_1_1_1_s_32,
6182                                FIB_SOURCE_API);
6183
6184         /* suspend so the update walk kicks int */
6185         vlib_process_suspend(vlib_get_main(), 1e-5);
6186
6187         FIB_TEST(!fib_test_validate_entry(fei,
6188                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6189                                           1,
6190                                           &ip_o_1_1_1_2),
6191                  "recursive via medium preference paths");
6192
6193         /*
6194          * withdraw medium pref resolving entry
6195          */
6196         fib_table_entry_delete(0,
6197                                &pfx_1_1_1_2_s_32,
6198                                FIB_SOURCE_API);
6199
6200         /* suspend so the update walk kicks int */
6201         vlib_process_suspend(vlib_get_main(), 1e-5);
6202
6203         FIB_TEST(!fib_test_validate_entry(fei,
6204                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6205                                           1,
6206                                           &ip_o_1_1_1_3),
6207                  "recursive via low preference paths");
6208
6209         /*
6210          * add back paths for next iteration
6211          */
6212         fei = fib_table_entry_update(0,
6213                                      &pfx_1_1_1_2_s_32,
6214                                      FIB_SOURCE_API,
6215                                      FIB_ENTRY_FLAG_NONE,
6216                                      nr_paths);
6217         fei = fib_table_entry_update(0,
6218                                      &pfx_1_1_1_1_s_32,
6219                                      FIB_SOURCE_API,
6220                                      FIB_ENTRY_FLAG_NONE,
6221                                      nr_paths);
6222
6223         /* suspend so the update walk kicks int */
6224         vlib_process_suspend(vlib_get_main(), 1e-5);
6225
6226         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6227         FIB_TEST(!fib_test_validate_entry(fei,
6228                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6229                                           1,
6230                                           &ip_o_1_1_1_1),
6231                  "recursive via high preference paths");
6232     }
6233
6234
6235     fib_table_entry_delete(0,
6236                            &pfx_1_1_1_1_s_32,
6237                            FIB_SOURCE_API);
6238
6239     /* suspend so the update walk kicks int */
6240     vlib_process_suspend(vlib_get_main(), 1e-5);
6241
6242     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6243     {
6244         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6245
6246         FIB_TEST(!fib_test_validate_entry(fei,
6247                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6248                                           1,
6249                                           &ip_o_1_1_1_2),
6250                  "recursive via medium preference paths");
6251     }
6252     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6253     {
6254         fib_table_entry_delete(0,
6255                                &pfx_r[n_pfxs],
6256                                FIB_SOURCE_API);
6257     }
6258
6259     /*
6260      * Cleanup
6261      */
6262     fib_table_entry_delete(0,
6263                            &pfx_1_1_1_2_s_32,
6264                            FIB_SOURCE_API);
6265     fib_table_entry_delete(0,
6266                            &pfx_1_1_1_3_s_32,
6267                            FIB_SOURCE_API);
6268
6269     dpo_reset(&ip_1_1_1_1);
6270     dpo_reset(&ip_1_1_1_2);
6271     dpo_reset(&ip_1_1_1_3);
6272     adj_unlock(ai_low_2);
6273     adj_unlock(ai_low_1);
6274     adj_unlock(ai_med_2);
6275     adj_unlock(ai_med_1);
6276     adj_unlock(ai_hi_2);
6277     adj_unlock(ai_hi_1);
6278
6279     return (res);
6280 }
6281
6282 /*
6283  * Test the recursive route route handling for GRE tunnels
6284  */
6285 static int
6286 fib_test_label (void)
6287 {
6288     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;
6289     const u32 fib_index = 0;
6290     int lb_count, ii, res;
6291     test_main_t *tm;
6292     ip4_main_t *im;
6293
6294     res = 0;
6295     lb_count = pool_elts(load_balance_pool);
6296     tm = &test_main;
6297     im = &ip4_main;
6298
6299     /*
6300      * add interface routes. We'll assume this works. It's more rigorously
6301      * tested elsewhere.
6302      */
6303     fib_prefix_t local0_pfx = {
6304         .fp_len = 24,
6305         .fp_proto = FIB_PROTOCOL_IP4,
6306         .fp_addr = {
6307             .ip4 = {
6308                 /* 10.10.10.10 */
6309                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6310             },
6311         },
6312     };
6313
6314     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6315              adj_nbr_db_size());
6316
6317     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6318     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6319
6320     fib_table_entry_update_one_path(fib_index, &local0_pfx,
6321                                     FIB_SOURCE_INTERFACE,
6322                                     (FIB_ENTRY_FLAG_CONNECTED |
6323                                      FIB_ENTRY_FLAG_ATTACHED),
6324                                     DPO_PROTO_IP4,
6325                                     NULL,
6326                                     tm->hw[0]->sw_if_index,
6327                                     ~0,
6328                                     1,
6329                                     NULL,
6330                                     FIB_ROUTE_PATH_FLAG_NONE);
6331     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6332     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6333              "attached interface route present");
6334
6335     local0_pfx.fp_len = 32;
6336     fib_table_entry_update_one_path(fib_index, &local0_pfx,
6337                                     FIB_SOURCE_INTERFACE,
6338                                     (FIB_ENTRY_FLAG_CONNECTED |
6339                                      FIB_ENTRY_FLAG_LOCAL),
6340                                     DPO_PROTO_IP4,
6341                                     NULL,
6342                                     tm->hw[0]->sw_if_index,
6343                                     ~0, // invalid fib index
6344                                     1,
6345                                     NULL,
6346                                     FIB_ROUTE_PATH_FLAG_NONE);
6347     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6348
6349     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6350              "local interface route present");
6351
6352     fib_prefix_t local1_pfx = {
6353         .fp_len = 24,
6354         .fp_proto = FIB_PROTOCOL_IP4,
6355         .fp_addr = {
6356             .ip4 = {
6357                 /* 10.10.11.10 */
6358                 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6359             },
6360         },
6361     };
6362
6363     vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6364     im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6365
6366     fib_table_entry_update_one_path(fib_index, &local1_pfx,
6367                                     FIB_SOURCE_INTERFACE,
6368                                     (FIB_ENTRY_FLAG_CONNECTED |
6369                                      FIB_ENTRY_FLAG_ATTACHED),
6370                                     DPO_PROTO_IP4,
6371                                     NULL,
6372                                     tm->hw[1]->sw_if_index,
6373                                     ~0,
6374                                     1,
6375                                     NULL,
6376                                     FIB_ROUTE_PATH_FLAG_NONE);
6377     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6378     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6379              "attached interface route present");
6380
6381     local1_pfx.fp_len = 32;
6382     fib_table_entry_update_one_path(fib_index, &local1_pfx,
6383                                     FIB_SOURCE_INTERFACE,
6384                                     (FIB_ENTRY_FLAG_CONNECTED |
6385                                      FIB_ENTRY_FLAG_LOCAL),
6386                                     DPO_PROTO_IP4,
6387                                     NULL,
6388                                     tm->hw[1]->sw_if_index,
6389                                     ~0, // invalid fib index
6390                                     1,
6391                                     NULL,
6392                                     FIB_ROUTE_PATH_FLAG_NONE);
6393     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6394
6395     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6396              "local interface route present");
6397
6398     ip46_address_t nh_10_10_10_1 = {
6399         .ip4 = {
6400             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6401         },
6402     };
6403     ip46_address_t nh_10_10_11_1 = {
6404         .ip4 = {
6405             .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6406         },
6407     };
6408     ip46_address_t nh_10_10_11_2 = {
6409         .ip4 = {
6410             .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6411         },
6412     };
6413
6414     ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6415                                            VNET_LINK_IP4,
6416                                            &nh_10_10_11_1,
6417                                            tm->hw[1]->sw_if_index);
6418     ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6419                                            VNET_LINK_IP4,
6420                                            &nh_10_10_11_2,
6421                                            tm->hw[1]->sw_if_index);
6422     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6423                                              VNET_LINK_MPLS,
6424                                              &nh_10_10_10_1,
6425                                              tm->hw[0]->sw_if_index);
6426     ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6427                                              VNET_LINK_MPLS,
6428                                              &nh_10_10_11_2,
6429                                              tm->hw[1]->sw_if_index);
6430     ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6431                                              VNET_LINK_MPLS,
6432                                              &nh_10_10_11_1,
6433                                              tm->hw[1]->sw_if_index);
6434
6435     /*
6436      * Add an etry with one path with a real out-going label
6437      */
6438     fib_prefix_t pfx_1_1_1_1_s_32 = {
6439         .fp_len = 32,
6440         .fp_proto = FIB_PROTOCOL_IP4,
6441         .fp_addr = {
6442             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6443         },
6444     };
6445     fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6446         .type = FT_LB_LABEL_O_ADJ,
6447         .label_o_adj = {
6448             .adj = ai_mpls_10_10_10_1,
6449             .label = 99,
6450             .eos = MPLS_EOS,
6451         },
6452     };
6453     fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6454         .type = FT_LB_LABEL_O_ADJ,
6455         .label_o_adj = {
6456             .adj = ai_mpls_10_10_10_1,
6457             .label = 99,
6458             .eos = MPLS_NON_EOS,
6459         },
6460     };
6461     fib_mpls_label_t *l99 = NULL, fml99 = {
6462         .fml_value = 99,
6463     };
6464     vec_add1(l99, fml99);
6465
6466     fib_table_entry_update_one_path(fib_index,
6467                                     &pfx_1_1_1_1_s_32,
6468                                     FIB_SOURCE_API,
6469                                     FIB_ENTRY_FLAG_NONE,
6470                                     DPO_PROTO_IP4,
6471                                     &nh_10_10_10_1,
6472                                     tm->hw[0]->sw_if_index,
6473                                     ~0, // invalid fib index
6474                                     1,
6475                                     l99,
6476                                     FIB_ROUTE_PATH_FLAG_NONE);
6477
6478     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6479     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6480
6481     FIB_TEST(!fib_test_validate_entry(fei,
6482                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6483                                       1,
6484                                       &l99_eos_o_10_10_10_1),
6485              "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6486
6487     /*
6488      * add a path with an implicit NULL label
6489      */
6490     fib_test_lb_bucket_t a_o_10_10_11_1 = {
6491         .type = FT_LB_ADJ,
6492         .adj = {
6493             .adj = ai_v4_10_10_11_1,
6494         },
6495     };
6496     fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6497         .type = FT_LB_ADJ,
6498         .adj = {
6499             .adj = ai_mpls_10_10_11_1,
6500         },
6501     };
6502     fib_mpls_label_t *l_imp_null = NULL, fml_imp_null = {
6503         .fml_value =  MPLS_IETF_IMPLICIT_NULL_LABEL,
6504     };
6505     vec_add1(l_imp_null, fml_imp_null);
6506
6507     fei = fib_table_entry_path_add(fib_index,
6508                                    &pfx_1_1_1_1_s_32,
6509                                    FIB_SOURCE_API,
6510                                    FIB_ENTRY_FLAG_NONE,
6511                                    DPO_PROTO_IP4,
6512                                    &nh_10_10_11_1,
6513                                    tm->hw[1]->sw_if_index,
6514                                    ~0, // invalid fib index
6515                                    1,
6516                                    l_imp_null,
6517                                    FIB_ROUTE_PATH_FLAG_NONE);
6518
6519     FIB_TEST(!fib_test_validate_entry(fei,
6520                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6521                                       2,
6522                                       &l99_eos_o_10_10_10_1,
6523                                       &a_o_10_10_11_1),
6524              "1.1.1.1/32 LB 2 buckets via: "
6525              "label 99 over 10.10.10.1, "
6526              "adj over 10.10.11.1");
6527
6528     /*
6529      * assign the route a local label
6530      */
6531     fib_table_entry_local_label_add(fib_index,
6532                                     &pfx_1_1_1_1_s_32,
6533                                     24001);
6534
6535     fib_prefix_t pfx_24001_eos = {
6536         .fp_proto = FIB_PROTOCOL_MPLS,
6537         .fp_label = 24001,
6538         .fp_eos = MPLS_EOS,
6539     };
6540     fib_prefix_t pfx_24001_neos = {
6541         .fp_proto = FIB_PROTOCOL_MPLS,
6542         .fp_label = 24001,
6543         .fp_eos = MPLS_NON_EOS,
6544     };
6545     fib_test_lb_bucket_t disp_o_10_10_11_1 = {
6546         .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6547         .adj = {
6548             .adj = ai_v4_10_10_11_1,
6549         },
6550     };
6551
6552     /*
6553      * The EOS entry should link to both the paths,
6554      *  and use an ip adj for the imp-null
6555      * The NON-EOS entry should link to both the paths,
6556      *  and use an mpls adj for the imp-null
6557      */
6558     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6559                            &pfx_24001_eos);
6560     FIB_TEST(!fib_test_validate_entry(fei,
6561                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6562                                       2,
6563                                       &l99_eos_o_10_10_10_1,
6564                                       &disp_o_10_10_11_1),
6565              "24001/eos LB 2 buckets via: "
6566              "label 99 over 10.10.10.1, "
6567              "mpls disp adj over 10.10.11.1");
6568
6569
6570     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6571                            &pfx_24001_neos);
6572     FIB_TEST(!fib_test_validate_entry(fei,
6573                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6574                                       2,
6575                                       &l99_neos_o_10_10_10_1,
6576                                       &a_mpls_o_10_10_11_1),
6577              "24001/neos LB 1 bucket via: "
6578              "label 99 over 10.10.10.1 ",
6579              "mpls-adj via 10.10.11.1");
6580
6581     /*
6582      * add an unlabelled path, this is excluded from the neos chains,
6583      */
6584     fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6585         .type = FT_LB_ADJ,
6586         .adj = {
6587             .adj = ai_v4_10_10_11_2,
6588         },
6589     };
6590     fib_test_lb_bucket_t disp_o_10_10_11_2 = {
6591         .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6592         .adj = {
6593             .adj = ai_v4_10_10_11_2,
6594         },
6595     };
6596
6597
6598     fei = fib_table_entry_path_add(fib_index,
6599                                    &pfx_1_1_1_1_s_32,
6600                                    FIB_SOURCE_API,
6601                                    FIB_ENTRY_FLAG_NONE,
6602                                    DPO_PROTO_IP4,
6603                                    &nh_10_10_11_2,
6604                                    tm->hw[1]->sw_if_index,
6605                                    ~0, // invalid fib index
6606                                    1,
6607                                    NULL,
6608                                    FIB_ROUTE_PATH_FLAG_NONE);
6609
6610     FIB_TEST(!fib_test_validate_entry(fei,
6611                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6612                                       16, // 3 choices spread over 16 buckets
6613                                       &l99_eos_o_10_10_10_1,
6614                                       &l99_eos_o_10_10_10_1,
6615                                       &l99_eos_o_10_10_10_1,
6616                                       &l99_eos_o_10_10_10_1,
6617                                       &l99_eos_o_10_10_10_1,
6618                                       &l99_eos_o_10_10_10_1,
6619                                       &a_o_10_10_11_1,
6620                                       &a_o_10_10_11_1,
6621                                       &a_o_10_10_11_1,
6622                                       &a_o_10_10_11_1,
6623                                       &a_o_10_10_11_1,
6624                                       &adj_o_10_10_11_2,
6625                                       &adj_o_10_10_11_2,
6626                                       &adj_o_10_10_11_2,
6627                                       &adj_o_10_10_11_2,
6628                                       &adj_o_10_10_11_2),
6629              "1.1.1.1/32 LB 16 buckets via: "
6630              "label 99 over 10.10.10.1, "
6631              "adj over 10.10.11.1",
6632              "adj over 10.10.11.2");
6633
6634     /*
6635      * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6636      */
6637     dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6638     fib_entry_contribute_forwarding(fei,
6639                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6640                                     &non_eos_1_1_1_1);
6641
6642     /*
6643      * n-eos has only the 2 labelled paths
6644      */
6645     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6646                            &pfx_24001_neos);
6647
6648     FIB_TEST(!fib_test_validate_entry(fei,
6649                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6650                                       2,
6651                                       &l99_neos_o_10_10_10_1,
6652                                       &a_mpls_o_10_10_11_1),
6653              "24001/neos LB 2 buckets via: "
6654              "label 99 over 10.10.10.1, "
6655              "adj-mpls over 10.10.11.2");
6656
6657     /*
6658      * A labelled recursive
6659      */
6660     fib_prefix_t pfx_2_2_2_2_s_32 = {
6661         .fp_len = 32,
6662         .fp_proto = FIB_PROTOCOL_IP4,
6663         .fp_addr = {
6664             .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6665         },
6666     };
6667     fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6668         .type = FT_LB_LABEL_O_LB,
6669         .label_o_lb = {
6670             .lb = non_eos_1_1_1_1.dpoi_index,
6671             .label = 1600,
6672             .eos = MPLS_EOS,
6673             .mode = FIB_MPLS_LSP_MODE_UNIFORM,
6674         },
6675     };
6676     fib_mpls_label_t *l1600 = NULL, fml1600 = {
6677         .fml_value = 1600,
6678         .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
6679     };
6680     vec_add1(l1600, fml1600);
6681
6682     fei = fib_table_entry_update_one_path(fib_index,
6683                                           &pfx_2_2_2_2_s_32,
6684                                           FIB_SOURCE_API,
6685                                           FIB_ENTRY_FLAG_NONE,
6686                                           DPO_PROTO_IP4,
6687                                           &pfx_1_1_1_1_s_32.fp_addr,
6688                                           ~0,
6689                                           fib_index,
6690                                           1,
6691                                           l1600,
6692                                           FIB_ROUTE_PATH_FLAG_NONE);
6693
6694     FIB_TEST(!fib_test_validate_entry(fei, 
6695                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6696                                       1,
6697                                       &l1600_eos_o_1_1_1_1),
6698              "2.2.2.2.2/32 LB 1 buckets via: "
6699              "label 1600 over 1.1.1.1");
6700
6701     dpo_id_t dpo_44 = DPO_INVALID;
6702     index_t urpfi;
6703
6704     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6705     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6706
6707     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6708              "uRPF check for 2.2.2.2/32 on %d OK",
6709              tm->hw[0]->sw_if_index);
6710     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6711              "uRPF check for 2.2.2.2/32 on %d OK",
6712              tm->hw[1]->sw_if_index);
6713     FIB_TEST(!fib_urpf_check(urpfi, 99),
6714              "uRPF check for 2.2.2.2/32 on 99 not-OK",
6715              99);
6716
6717     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6718     FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6719              "Shared uRPF on IP and non-EOS chain");
6720
6721     dpo_reset(&dpo_44);
6722
6723     /*
6724      * we are holding a lock on the non-eos LB of the via-entry.
6725      * do a PIC-core failover by shutting the link of the via-entry.
6726      *
6727      * shut down the link with the valid label
6728      */
6729     vnet_sw_interface_set_flags(vnet_get_main(),
6730                                 tm->hw[0]->sw_if_index,
6731                                 0);
6732
6733     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6734     FIB_TEST(!fib_test_validate_entry(fei,
6735                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6736                                       2,
6737                                       &a_o_10_10_11_1,
6738                                       &adj_o_10_10_11_2),
6739              "1.1.1.1/32 LB 2 buckets via: "
6740              "adj over 10.10.11.1, ",
6741              "adj-v4 over 10.10.11.2");
6742
6743     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6744                            &pfx_24001_eos);
6745     FIB_TEST(!fib_test_validate_entry(fei,
6746                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6747                                       2,
6748                                       &disp_o_10_10_11_1,
6749                                       &disp_o_10_10_11_2),
6750              "24001/eos LB 2 buckets via: "
6751              "mpls-disp adj over 10.10.11.1, ",
6752              "mpls-disp adj-v4 over 10.10.11.2");
6753
6754     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6755                            &pfx_24001_neos);
6756     FIB_TEST(!fib_test_validate_entry(fei,
6757                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6758                                       1,
6759                                       &a_mpls_o_10_10_11_1),
6760              "24001/neos LB 1 buckets via: "
6761              "adj-mpls over 10.10.11.2");
6762
6763     /*
6764      * test that the pre-failover load-balance has been in-place
6765      * modified
6766      */
6767     dpo_id_t current = DPO_INVALID;
6768     fib_entry_contribute_forwarding(fei,
6769                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6770                                     &current);
6771
6772     FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6773                       &current),
6774              "PIC-core LB inplace modified %U %U",
6775              format_dpo_id, &non_eos_1_1_1_1, 0,
6776              format_dpo_id, &current, 0);
6777
6778     dpo_reset(&non_eos_1_1_1_1);
6779     dpo_reset(&current);
6780
6781     /*
6782      * no-shut the link with the valid label
6783      */
6784     vnet_sw_interface_set_flags(vnet_get_main(),
6785                                 tm->hw[0]->sw_if_index,
6786                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6787
6788     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6789     FIB_TEST(!fib_test_validate_entry(fei,
6790                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6791                                       16, // 3 choices spread over 16 buckets
6792                                       &l99_eos_o_10_10_10_1,
6793                                       &l99_eos_o_10_10_10_1,
6794                                       &l99_eos_o_10_10_10_1,
6795                                       &l99_eos_o_10_10_10_1,
6796                                       &l99_eos_o_10_10_10_1,
6797                                       &l99_eos_o_10_10_10_1,
6798                                       &a_o_10_10_11_1,
6799                                       &a_o_10_10_11_1,
6800                                       &a_o_10_10_11_1,
6801                                       &a_o_10_10_11_1,
6802                                       &a_o_10_10_11_1,
6803                                       &adj_o_10_10_11_2,
6804                                       &adj_o_10_10_11_2,
6805                                       &adj_o_10_10_11_2,
6806                                       &adj_o_10_10_11_2,
6807                                       &adj_o_10_10_11_2),
6808              "1.1.1.1/32 LB 16 buckets via: "
6809              "label 99 over 10.10.10.1, "
6810              "adj over 10.10.11.1",
6811              "adj-v4 over 10.10.11.2");
6812
6813
6814     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6815                            &pfx_24001_eos);
6816     FIB_TEST(!fib_test_validate_entry(fei,
6817                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6818                                       16, // 3 choices spread over 16 buckets
6819                                       &l99_eos_o_10_10_10_1,
6820                                       &l99_eos_o_10_10_10_1,
6821                                       &l99_eos_o_10_10_10_1,
6822                                       &l99_eos_o_10_10_10_1,
6823                                       &l99_eos_o_10_10_10_1,
6824                                       &l99_eos_o_10_10_10_1,
6825                                       &disp_o_10_10_11_1,
6826                                       &disp_o_10_10_11_1,
6827                                       &disp_o_10_10_11_1,
6828                                       &disp_o_10_10_11_1,
6829                                       &disp_o_10_10_11_1,
6830                                       &disp_o_10_10_11_2,
6831                                       &disp_o_10_10_11_2,
6832                                       &disp_o_10_10_11_2,
6833                                       &disp_o_10_10_11_2,
6834                                       &disp_o_10_10_11_2),
6835              "24001/eos LB 16 buckets via: "
6836              "label 99 over 10.10.10.1, "
6837              "MPLS disp adj over 10.10.11.1",
6838              "MPLS disp adj-v4 over 10.10.11.2");
6839
6840     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6841                            &pfx_24001_neos);
6842     FIB_TEST(!fib_test_validate_entry(fei,
6843                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6844                                       2,
6845                                       &l99_neos_o_10_10_10_1,
6846                                       &a_mpls_o_10_10_11_1),
6847              "24001/neos LB 2 buckets via: "
6848              "label 99 over 10.10.10.1, "
6849              "adj-mpls over 10.10.11.2");
6850
6851     /*
6852      * remove the first path with the valid label
6853      */
6854     fib_table_entry_path_remove(fib_index,
6855                                 &pfx_1_1_1_1_s_32,
6856                                 FIB_SOURCE_API,
6857                                 DPO_PROTO_IP4,
6858                                 &nh_10_10_10_1,
6859                                 tm->hw[0]->sw_if_index,
6860                                 ~0, // invalid fib index
6861                                 1,
6862                                 FIB_ROUTE_PATH_FLAG_NONE);
6863
6864     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6865     FIB_TEST(!fib_test_validate_entry(fei,
6866                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6867                                       2,
6868                                       &a_o_10_10_11_1,
6869                                       &adj_o_10_10_11_2),
6870              "1.1.1.1/32 LB 2 buckets via: "
6871              "adj over 10.10.11.1, "
6872              "adj-v4 over 10.10.11.2");
6873
6874     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6875                            &pfx_24001_eos);
6876     FIB_TEST(!fib_test_validate_entry(fei,
6877                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6878                                       2,
6879                                       &disp_o_10_10_11_1,
6880                                       &disp_o_10_10_11_2),
6881              "24001/eos LB 2 buckets via: "
6882              "MPLS disp adj over 10.10.11.1, "
6883              "MPLS disp adj-v4 over 10.10.11.2");
6884
6885     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6886                            &pfx_24001_neos);
6887
6888     FIB_TEST(!fib_test_validate_entry(fei,
6889                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6890                                       1,
6891                                       &a_mpls_o_10_10_11_1),
6892              "24001/neos LB 1 buckets via: "
6893              "adj-mpls over 10.10.11.2");
6894
6895     /*
6896      * remove the other path with a valid label
6897      */
6898     fib_test_lb_bucket_t bucket_drop = {
6899         .type = FT_LB_DROP,
6900     };
6901     fib_test_lb_bucket_t mpls_bucket_drop = {
6902         .type = FT_LB_DROP,
6903         .special = {
6904             .adj = DPO_PROTO_MPLS,
6905         },
6906     };
6907
6908     fib_table_entry_path_remove(fib_index,
6909                                 &pfx_1_1_1_1_s_32,
6910                                 FIB_SOURCE_API,
6911                                 DPO_PROTO_IP4,
6912                                 &nh_10_10_11_1,
6913                                 tm->hw[1]->sw_if_index,
6914                                 ~0, // invalid fib index
6915                                 1,
6916                                 FIB_ROUTE_PATH_FLAG_NONE);
6917
6918     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6919     FIB_TEST(!fib_test_validate_entry(fei,
6920                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6921                                       1,
6922                                       &adj_o_10_10_11_2),
6923              "1.1.1.1/32 LB 1 buckets via: "
6924              "adj over 10.10.11.2");
6925
6926     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6927                            &pfx_24001_eos);
6928     FIB_TEST(!fib_test_validate_entry(fei,
6929                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6930                                       1,
6931                                       &disp_o_10_10_11_2),
6932              "24001/eos LB 1 buckets via: "
6933              "MPLS disp adj over 10.10.11.2");
6934
6935     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6936                            &pfx_24001_neos);
6937     FIB_TEST(!fib_test_validate_entry(fei,
6938                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6939                                       1,
6940                                       &mpls_bucket_drop),
6941              "24001/neos LB 1 buckets via: DROP");
6942
6943     /*
6944      * add back the path with the valid label
6945      */
6946     l99 = NULL;
6947     vec_add1(l99, fml99);
6948
6949     fib_table_entry_path_add(fib_index,
6950                              &pfx_1_1_1_1_s_32,
6951                              FIB_SOURCE_API,
6952                              FIB_ENTRY_FLAG_NONE,
6953                              DPO_PROTO_IP4,
6954                              &nh_10_10_10_1,
6955                              tm->hw[0]->sw_if_index,
6956                              ~0, // invalid fib index
6957                              1,
6958                              l99,
6959                              FIB_ROUTE_PATH_FLAG_NONE);
6960
6961     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6962     FIB_TEST(!fib_test_validate_entry(fei,
6963                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6964                                       2,
6965                                       &l99_eos_o_10_10_10_1,
6966                                       &adj_o_10_10_11_2),
6967              "1.1.1.1/32 LB 2 buckets via: "
6968              "label 99 over 10.10.10.1, "
6969              "adj over 10.10.11.2");
6970
6971     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6972                            &pfx_24001_eos);
6973     FIB_TEST(!fib_test_validate_entry(fei,
6974                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6975                                       2,
6976                                       &l99_eos_o_10_10_10_1,
6977                                       &disp_o_10_10_11_2),
6978              "24001/eos LB 2 buckets via: "
6979              "label 99 over 10.10.10.1, "
6980              "MPLS disp adj over 10.10.11.2");
6981
6982     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6983                            &pfx_24001_neos);
6984     FIB_TEST(!fib_test_validate_entry(fei,
6985                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6986                                       1,
6987                                       &l99_neos_o_10_10_10_1),
6988              "24001/neos LB 1 buckets via: "
6989              "label 99 over 10.10.10.1");
6990
6991     /*
6992      * change the local label
6993      */
6994     fib_table_entry_local_label_add(fib_index,
6995                                     &pfx_1_1_1_1_s_32,
6996                                     25005);
6997
6998     fib_prefix_t pfx_25005_eos = {
6999         .fp_proto = FIB_PROTOCOL_MPLS,
7000         .fp_label = 25005,
7001         .fp_eos = MPLS_EOS,
7002     };
7003     fib_prefix_t pfx_25005_neos = {
7004         .fp_proto = FIB_PROTOCOL_MPLS,
7005         .fp_label = 25005,
7006         .fp_eos = MPLS_NON_EOS,
7007     };
7008
7009     FIB_TEST((FIB_NODE_INDEX_INVALID ==
7010               fib_table_lookup(fib_index, &pfx_24001_eos)),
7011              "24001/eos removed after label change");
7012     FIB_TEST((FIB_NODE_INDEX_INVALID ==
7013               fib_table_lookup(fib_index, &pfx_24001_neos)),
7014              "24001/eos removed after label change");
7015
7016     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7017                            &pfx_25005_eos);
7018     FIB_TEST(!fib_test_validate_entry(fei,
7019                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7020                                       2,
7021                                       &l99_eos_o_10_10_10_1,
7022                                       &disp_o_10_10_11_2),
7023              "25005/eos LB 2 buckets via: "
7024              "label 99 over 10.10.10.1, "
7025              "MPLS disp adj over 10.10.11.2");
7026
7027     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7028                            &pfx_25005_neos);
7029     FIB_TEST(!fib_test_validate_entry(fei,
7030                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7031                                       1,
7032                                       &l99_neos_o_10_10_10_1),
7033              "25005/neos LB 1 buckets via: "
7034              "label 99 over 10.10.10.1");
7035
7036     /*
7037      * remove the local label.
7038      * the check that the MPLS entries are gone is done by the fact the
7039      * MPLS table is no longer present.
7040      */
7041     fib_table_entry_local_label_remove(fib_index,
7042                                        &pfx_1_1_1_1_s_32,
7043                                        25005);
7044
7045     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
7046     FIB_TEST(!fib_test_validate_entry(fei,
7047                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7048                                       2,
7049                                       &l99_eos_o_10_10_10_1,
7050                                       &adj_o_10_10_11_2),
7051              "24001/eos LB 2 buckets via: "
7052              "label 99 over 10.10.10.1, "
7053              "adj over 10.10.11.2");
7054
7055     FIB_TEST((FIB_NODE_INDEX_INVALID ==
7056               mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
7057              "No more MPLS FIB entries => table removed");
7058
7059     /*
7060      * add another via-entry for the recursive
7061      */
7062     fib_prefix_t pfx_1_1_1_2_s_32 = {
7063         .fp_len = 32,
7064         .fp_proto = FIB_PROTOCOL_IP4,
7065         .fp_addr = {
7066             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
7067         },
7068     };
7069     fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
7070         .type = FT_LB_LABEL_O_ADJ,
7071         .label_o_adj = {
7072             .adj = ai_mpls_10_10_10_1,
7073             .label = 101,
7074             .eos = MPLS_EOS,
7075         },
7076     };
7077     fib_mpls_label_t *l101 = NULL, fml101 = {
7078         .fml_value = 101,
7079     };
7080     vec_add1(l101, fml101);
7081
7082     fei = fib_table_entry_update_one_path(fib_index,
7083                                           &pfx_1_1_1_2_s_32,
7084                                           FIB_SOURCE_API,
7085                                           FIB_ENTRY_FLAG_NONE,
7086                                           DPO_PROTO_IP4,
7087                                           &nh_10_10_10_1,
7088                                           tm->hw[0]->sw_if_index,
7089                                           ~0, // invalid fib index
7090                                           1,
7091                                           l101,
7092                                           FIB_ROUTE_PATH_FLAG_NONE);
7093
7094     FIB_TEST(!fib_test_validate_entry(fei,
7095                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7096                                       1,
7097                                       &l101_eos_o_10_10_10_1),
7098              "1.1.1.2/32 LB 1 buckets via: "
7099              "label 101 over 10.10.10.1");
7100
7101     dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
7102     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7103                                                      &pfx_1_1_1_1_s_32),
7104                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7105                                     &non_eos_1_1_1_1);
7106     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7107                                                      &pfx_1_1_1_2_s_32),
7108                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7109                                     &non_eos_1_1_1_2);
7110
7111     fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
7112         .type = FT_LB_LABEL_O_LB,
7113         .label_o_lb = {
7114             .lb = non_eos_1_1_1_2.dpoi_index,
7115             .label = 1601,
7116             .eos = MPLS_EOS,
7117         },
7118     };
7119     fib_mpls_label_t *l1601 = NULL, fml1601 = {
7120         .fml_value = 1601,
7121     };
7122     vec_add1(l1601, fml1601);
7123
7124     l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
7125
7126     fei = fib_table_entry_path_add(fib_index,
7127                                    &pfx_2_2_2_2_s_32,
7128                                    FIB_SOURCE_API,
7129                                    FIB_ENTRY_FLAG_NONE,
7130                                    DPO_PROTO_IP4,
7131                                    &pfx_1_1_1_2_s_32.fp_addr,
7132                                    ~0,
7133                                    fib_index,
7134                                    1,
7135                                    l1601,
7136                                    FIB_ROUTE_PATH_FLAG_NONE);
7137
7138     FIB_TEST(!fib_test_validate_entry(fei,
7139                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7140                                       2,
7141                                       &l1600_eos_o_1_1_1_1,
7142                                       &l1601_eos_o_1_1_1_2),
7143              "2.2.2.2/32 LB 2 buckets via: "
7144              "label 1600 via 1.1,1.1, "
7145              "label 16001 via 1.1.1.2");
7146
7147     /*
7148      * update the via-entry so it no longer has an imp-null path.
7149      * the LB for the recursive can use an imp-null
7150      */
7151     l_imp_null = NULL;
7152     vec_add1(l_imp_null, fml_imp_null);
7153
7154     fei = fib_table_entry_update_one_path(fib_index,
7155                                           &pfx_1_1_1_2_s_32,
7156                                           FIB_SOURCE_API,
7157                                           FIB_ENTRY_FLAG_NONE,
7158                                           DPO_PROTO_IP4,
7159                                           &nh_10_10_11_1,
7160                                           tm->hw[1]->sw_if_index,
7161                                           ~0, // invalid fib index
7162                                           1,
7163                                           l_imp_null,
7164                                           FIB_ROUTE_PATH_FLAG_NONE);
7165
7166     FIB_TEST(!fib_test_validate_entry(fei,
7167                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7168                                       1,
7169                                       &a_o_10_10_11_1),
7170              "1.1.1.2/32 LB 1 buckets via: "
7171              "adj 10.10.11.1");
7172
7173     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7174     FIB_TEST(!fib_test_validate_entry(fei,
7175                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7176                                       2,
7177                                       &l1600_eos_o_1_1_1_1,
7178                                       &l1601_eos_o_1_1_1_2),
7179              "2.2.2.2/32 LB 2 buckets via: "
7180              "label 1600 via 1.1,1.1, "
7181              "label 16001 via 1.1.1.2");
7182
7183     /*
7184      * update the via-entry so it no longer has labelled paths.
7185      * the LB for the recursive should exclue this via form its LB
7186      */
7187     fei = fib_table_entry_update_one_path(fib_index,
7188                                           &pfx_1_1_1_2_s_32,
7189                                           FIB_SOURCE_API,
7190                                           FIB_ENTRY_FLAG_NONE,
7191                                           DPO_PROTO_IP4,
7192                                           &nh_10_10_11_1,
7193                                           tm->hw[1]->sw_if_index,
7194                                           ~0, // invalid fib index
7195                                           1,
7196                                           NULL,
7197                                           FIB_ROUTE_PATH_FLAG_NONE);
7198
7199     FIB_TEST(!fib_test_validate_entry(fei,
7200                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7201                                       1,
7202                                       &a_o_10_10_11_1),
7203              "1.1.1.2/32 LB 1 buckets via: "
7204              "adj 10.10.11.1");
7205
7206     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7207     FIB_TEST(!fib_test_validate_entry(fei,
7208                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7209                                       1,
7210                                       &l1600_eos_o_1_1_1_1),
7211              "2.2.2.2/32 LB 1 buckets via: "
7212              "label 1600 via 1.1,1.1");
7213
7214     dpo_reset(&non_eos_1_1_1_1);
7215     dpo_reset(&non_eos_1_1_1_2);
7216
7217     /*
7218      * Add a recursive with no out-labels. We expect to use the IP of the via
7219      */
7220     fib_prefix_t pfx_2_2_2_3_s_32 = {
7221         .fp_len = 32,
7222         .fp_proto = FIB_PROTOCOL_IP4,
7223         .fp_addr = {
7224             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7225         },
7226     };
7227     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7228
7229     fib_table_entry_update_one_path(fib_index,
7230                                     &pfx_2_2_2_3_s_32,
7231                                     FIB_SOURCE_API,
7232                                     FIB_ENTRY_FLAG_NONE,
7233                                     DPO_PROTO_IP4,
7234                                     &pfx_1_1_1_1_s_32.fp_addr,
7235                                     ~0,
7236                                     fib_index,
7237                                     1,
7238                                     NULL,
7239                                     FIB_ROUTE_PATH_FLAG_NONE);
7240
7241     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7242                                                      &pfx_1_1_1_1_s_32),
7243                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7244                                     &ip_1_1_1_1);
7245
7246     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7247         .type = FT_LB_O_LB,
7248         .lb = {
7249             .lb = ip_1_1_1_1.dpoi_index,
7250         },
7251     };
7252
7253     fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7254     FIB_TEST(!fib_test_validate_entry(fei,
7255                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7256                                       1,
7257                                       &ip_o_1_1_1_1),
7258              "2.2.2.2.3/32 LB 1 buckets via: "
7259              "ip 1.1.1.1");
7260
7261     /*
7262      * Add a recursive with an imp-null out-label.
7263      * We expect to use the IP of the via
7264      */
7265     fib_prefix_t pfx_2_2_2_4_s_32 = {
7266         .fp_len = 32,
7267         .fp_proto = FIB_PROTOCOL_IP4,
7268         .fp_addr = {
7269             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7270         },
7271     };
7272
7273     fib_table_entry_update_one_path(fib_index,
7274                                     &pfx_2_2_2_4_s_32,
7275                                     FIB_SOURCE_API,
7276                                     FIB_ENTRY_FLAG_NONE,
7277                                     DPO_PROTO_IP4,
7278                                     &pfx_1_1_1_1_s_32.fp_addr,
7279                                     ~0,
7280                                     fib_index,
7281                                     1,
7282                                     NULL,
7283                                     FIB_ROUTE_PATH_FLAG_NONE);
7284
7285     fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7286     FIB_TEST(!fib_test_validate_entry(fei,
7287                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7288                                       1,
7289                                       &ip_o_1_1_1_1),
7290              "2.2.2.2.4/32 LB 1 buckets via: "
7291              "ip 1.1.1.1");
7292
7293     dpo_reset(&ip_1_1_1_1);
7294
7295     /*
7296      * Create an entry with a deep label stack
7297      */
7298     fib_prefix_t pfx_2_2_5_5_s_32 = {
7299         .fp_len = 32,
7300         .fp_proto = FIB_PROTOCOL_IP4,
7301         .fp_addr = {
7302             .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7303         },
7304     };
7305     fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7306         .type = FT_LB_LABEL_STACK_O_ADJ,
7307         .label_stack_o_adj = {
7308             .adj = ai_mpls_10_10_11_1,
7309             .label_stack_size = 8,
7310             .label_stack = {
7311                 200, 201, 202, 203, 204, 205, 206, 207
7312             },
7313             .eos = MPLS_EOS,
7314         },
7315     };
7316     fib_mpls_label_t *label_stack = NULL;
7317     vec_validate(label_stack, 7);
7318     for (ii = 0; ii < 8; ii++)
7319     {
7320         label_stack[ii].fml_value = ii + 200;
7321     }
7322
7323     fei = fib_table_entry_update_one_path(fib_index,
7324                                           &pfx_2_2_5_5_s_32,
7325                                           FIB_SOURCE_API,
7326                                           FIB_ENTRY_FLAG_NONE,
7327                                           DPO_PROTO_IP4,
7328                                           &nh_10_10_11_1,
7329                                           tm->hw[1]->sw_if_index,
7330                                           ~0, // invalid fib index
7331                                           1,
7332                                           label_stack,
7333                                           FIB_ROUTE_PATH_FLAG_NONE);
7334
7335     FIB_TEST(!fib_test_validate_entry(fei,
7336                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7337                                       1,
7338                                       &ls_eos_o_10_10_10_1),
7339              "2.2.5.5/32 LB 1 buckets via: "
7340              "adj 10.10.11.1");
7341     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7342
7343     /*
7344      * cleanup
7345      */
7346     fib_table_entry_delete(fib_index,
7347                            &pfx_1_1_1_2_s_32,
7348                            FIB_SOURCE_API);
7349
7350     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7351     FIB_TEST(!fib_test_validate_entry(fei,
7352                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7353                                       1,
7354                                       &l1600_eos_o_1_1_1_1),
7355              "2.2.2.2/32 LB 1 buckets via: "
7356              "label 1600 via 1.1,1.1");
7357
7358     fib_table_entry_delete(fib_index,
7359                            &pfx_1_1_1_1_s_32,
7360                            FIB_SOURCE_API);
7361
7362     FIB_TEST(!fib_test_validate_entry(fei,
7363                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7364                                       1,
7365                                       &bucket_drop),
7366              "2.2.2.2/32 LB 1 buckets via: DROP");
7367
7368     fib_table_entry_delete(fib_index,
7369                            &pfx_2_2_2_2_s_32,
7370                            FIB_SOURCE_API);
7371     fib_table_entry_delete(fib_index,
7372                            &pfx_2_2_2_3_s_32,
7373                            FIB_SOURCE_API);
7374     fib_table_entry_delete(fib_index,
7375                            &pfx_2_2_2_4_s_32,
7376                            FIB_SOURCE_API);
7377
7378     adj_unlock(ai_mpls_10_10_10_1);
7379     adj_unlock(ai_mpls_10_10_11_2);
7380     adj_unlock(ai_v4_10_10_11_1);
7381     adj_unlock(ai_v4_10_10_11_2);
7382     adj_unlock(ai_mpls_10_10_11_1);
7383
7384     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7385              adj_nbr_db_size());
7386
7387     local0_pfx.fp_len = 32;
7388     fib_table_entry_delete(fib_index,
7389                            &local0_pfx,
7390                            FIB_SOURCE_INTERFACE);
7391     local0_pfx.fp_len = 24;
7392     fib_table_entry_delete(fib_index,
7393                            &local0_pfx,
7394                            FIB_SOURCE_INTERFACE);
7395     local1_pfx.fp_len = 32;
7396     fib_table_entry_delete(fib_index,
7397                            &local1_pfx,
7398                            FIB_SOURCE_INTERFACE);
7399     local1_pfx.fp_len = 24;
7400     fib_table_entry_delete(fib_index,
7401                            &local1_pfx,
7402                            FIB_SOURCE_INTERFACE);
7403
7404     /*
7405      * +1 for the drop LB in the MPLS tables.
7406      */
7407     FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7408              "Load-balance resources freed %d of %d",
7409              lb_count+1, pool_elts(load_balance_pool));
7410
7411     return (res);
7412 }
7413
7414 #define N_TEST_CHILDREN 4
7415 #define PARENT_INDEX 0
7416
7417 typedef struct fib_node_test_t_
7418 {
7419     fib_node_t node;
7420     u32 sibling;
7421     u32 index;
7422     fib_node_back_walk_ctx_t *ctxs;
7423     u32 destroyed;
7424 } fib_node_test_t;
7425
7426 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7427
7428 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7429
7430 #define FOR_EACH_TEST_CHILD(_tc)                \
7431     for (ii = 1, (_tc) = &fib_test_nodes[1];    \
7432          ii < N_TEST_CHILDREN+1;                \
7433          ii++, (_tc) = &fib_test_nodes[ii])
7434
7435 static fib_node_t *
7436 fib_test_child_get_node (fib_node_index_t index)
7437 {
7438     return (&fib_test_nodes[index].node);
7439 }
7440
7441 static int fib_test_walk_spawns_walks;
7442
7443 static fib_node_back_walk_rc_t
7444 fib_test_child_back_walk_notify (fib_node_t *node,
7445                                  fib_node_back_walk_ctx_t *ctx)
7446 {
7447     fib_node_test_t *tc = (fib_node_test_t*) node;
7448
7449     vec_add1(tc->ctxs, *ctx);
7450
7451     if (1 == fib_test_walk_spawns_walks)
7452         fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7453     if (2 == fib_test_walk_spawns_walks)
7454         fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7455                        FIB_WALK_PRIORITY_HIGH, ctx);
7456
7457     return (FIB_NODE_BACK_WALK_CONTINUE);
7458 }
7459
7460 static void
7461 fib_test_child_last_lock_gone (fib_node_t *node)
7462 {
7463     fib_node_test_t *tc = (fib_node_test_t *)node;
7464
7465     tc->destroyed = 1;
7466 }
7467
7468 /**
7469  * The FIB walk's graph node virtual function table
7470  */
7471 static const fib_node_vft_t fib_test_child_vft = {
7472     .fnv_get = fib_test_child_get_node,
7473     .fnv_last_lock = fib_test_child_last_lock_gone,
7474     .fnv_back_walk = fib_test_child_back_walk_notify,
7475 };
7476
7477 /*
7478  * the function (that should have been static but isn't so I can do this)
7479  * that processes the walk from the async queue,
7480  */
7481 f64 fib_walk_process_queues(vlib_main_t * vm,
7482                             const f64 quota);
7483 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7484
7485 static int
7486 fib_test_walk (void)
7487 {
7488     fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7489     fib_node_test_t *tc;
7490     vlib_main_t *vm;
7491     u32 ii, res;
7492
7493     res = 0;
7494     vm = vlib_get_main();
7495     fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7496
7497     /*
7498      * init a fake node on which we will add children
7499      */
7500     fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7501                   FIB_NODE_TYPE_TEST);
7502
7503     FOR_EACH_TEST_CHILD(tc)
7504     {
7505         fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7506         fib_node_lock(&tc->node);
7507         tc->ctxs = NULL;
7508         tc->index = ii;
7509         tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7510                                          PARENT_INDEX,
7511                                          FIB_NODE_TYPE_TEST, ii);
7512     }
7513
7514     /*
7515      * enqueue a walk across the parents children.
7516      */
7517     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7518
7519     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7520                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7521     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7522              "Parent has %d children pre-walk",
7523              fib_node_list_get_size(PARENT()->fn_children));
7524
7525     /*
7526      * give the walk a large amount of time so it gets to the end
7527      */
7528     fib_walk_process_queues(vm, 1);
7529
7530     FOR_EACH_TEST_CHILD(tc)
7531     {
7532         FIB_TEST(1 == vec_len(tc->ctxs),
7533                  "%d child visitsed %d times",
7534                  ii, vec_len(tc->ctxs));
7535         vec_free(tc->ctxs);
7536     }
7537     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7538              "Queue is empty post walk");
7539     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7540              "Parent has %d children post walk",
7541              fib_node_list_get_size(PARENT()->fn_children));
7542
7543     /*
7544      * walk again. should be no increase in the number of visits, since
7545      * the walk will have terminated.
7546      */
7547     fib_walk_process_queues(vm, 1);
7548
7549     FOR_EACH_TEST_CHILD(tc)
7550     {
7551         FIB_TEST(0 == vec_len(tc->ctxs),
7552                  "%d child visitsed %d times",
7553                  ii, vec_len(tc->ctxs));
7554     }
7555
7556     /*
7557      * schedule a low and hig priority walk. expect the high to be performed
7558      * before the low.
7559      * schedule the high prio walk first so that it is further from the head
7560      * of the dependency list. that way it won't merge with the low one.
7561      */
7562     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7563     low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7564
7565     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7566                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7567     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7568                    FIB_WALK_PRIORITY_LOW, &low_ctx);
7569
7570     fib_walk_process_queues(vm, 1);
7571
7572     FOR_EACH_TEST_CHILD(tc)
7573     {
7574         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7575                  "%d child visitsed by high prio walk", ii);
7576         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
7577                  "%d child visitsed by low prio walk", ii);
7578         vec_free(tc->ctxs);
7579     }
7580     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7581              "Queue is empty post prio walk");
7582     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7583              "Parent has %d children post prio walk",
7584              fib_node_list_get_size(PARENT()->fn_children));
7585
7586     /*
7587      * schedule 2 walks of the same priority that can be megred.
7588      * expect that each child is thus visited only once.
7589      */
7590     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7591     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7592
7593     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7594                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7595     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7596                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
7597
7598     fib_walk_process_queues(vm, 1);
7599
7600     FOR_EACH_TEST_CHILD(tc)
7601     {
7602         FIB_TEST(1 == vec_len(tc->ctxs),
7603                  "%d child visitsed %d times during merge walk",
7604                  ii, vec_len(tc->ctxs));
7605         vec_free(tc->ctxs);
7606     }
7607     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7608              "Queue is empty post merge walk");
7609     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7610              "Parent has %d children post merge walk",
7611              fib_node_list_get_size(PARENT()->fn_children));
7612
7613     /*
7614      * schedule 2 walks of the same priority that cannot be megred.
7615      * expect that each child is thus visited twice and in the order
7616      * in which the walks were scheduled.
7617      */
7618     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7619     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7620
7621     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7622                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7623     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7624                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
7625
7626     fib_walk_process_queues(vm, 1);
7627
7628     FOR_EACH_TEST_CHILD(tc)
7629     {
7630         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7631                  "%d child visitsed by high prio walk", ii);
7632         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
7633                  "%d child visitsed by low prio walk", ii);
7634         vec_free(tc->ctxs);
7635     }
7636     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7637              "Queue is empty post no-merge walk");
7638     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7639              "Parent has %d children post no-merge walk",
7640              fib_node_list_get_size(PARENT()->fn_children));
7641
7642     /*
7643      * schedule a walk that makes one one child progress.
7644      * we do this by giving the queue draining process zero
7645      * time quanta. it's a do..while loop, so it does something.
7646      */
7647     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7648
7649     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7650                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7651     fib_walk_process_queues(vm, 0);
7652
7653     FOR_EACH_TEST_CHILD(tc)
7654     {
7655         if (ii == N_TEST_CHILDREN)
7656         {
7657             FIB_TEST(1 == vec_len(tc->ctxs),
7658                      "%d child visitsed %d times in zero quanta walk",
7659                      ii, vec_len(tc->ctxs));
7660         }
7661         else
7662         {
7663             FIB_TEST(0 == vec_len(tc->ctxs),
7664                      "%d child visitsed %d times in 0 quanta walk",
7665                      ii, vec_len(tc->ctxs));
7666         }
7667     }
7668     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7669              "Queue is not empty post zero quanta walk");
7670     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7671              "Parent has %d children post zero qunta walk",
7672              fib_node_list_get_size(PARENT()->fn_children));
7673
7674     /*
7675      * another one step
7676      */
7677     fib_walk_process_queues(vm, 0);
7678
7679     FOR_EACH_TEST_CHILD(tc)
7680     {
7681         if (ii >= N_TEST_CHILDREN-1)
7682         {
7683             FIB_TEST(1 == vec_len(tc->ctxs),
7684                      "%d child visitsed %d times in 2nd zero quanta walk",
7685                      ii, vec_len(tc->ctxs));
7686         }
7687         else
7688         {
7689             FIB_TEST(0 == vec_len(tc->ctxs),
7690                      "%d child visitsed %d times in 2nd 0 quanta walk",
7691                      ii, vec_len(tc->ctxs));
7692         }
7693     }
7694     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7695              "Queue is not empty post zero quanta walk");
7696     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7697              "Parent has %d children post zero qunta walk",
7698              fib_node_list_get_size(PARENT()->fn_children));
7699
7700     /*
7701      * schedule another walk that will catch-up and merge.
7702      */
7703     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7704                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7705     fib_walk_process_queues(vm, 1);
7706
7707     FOR_EACH_TEST_CHILD(tc)
7708     {
7709         if (ii >= N_TEST_CHILDREN-1)
7710         {
7711             FIB_TEST(2 == vec_len(tc->ctxs),
7712                      "%d child visitsed %d times in 2nd zero quanta merge walk",
7713                      ii, vec_len(tc->ctxs));
7714             vec_free(tc->ctxs);
7715         }
7716         else
7717         {
7718             FIB_TEST(1 == vec_len(tc->ctxs),
7719                      "%d child visitsed %d times in 2nd 0 quanta merge walk",
7720                      ii, vec_len(tc->ctxs));
7721             vec_free(tc->ctxs);
7722         }
7723     }
7724     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7725              "Queue is not empty post 2nd zero quanta merge walk");
7726     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7727              "Parent has %d children post 2nd zero qunta merge walk",
7728              fib_node_list_get_size(PARENT()->fn_children));
7729
7730     /*
7731      * park a async walk in the middle of the list, then have an sync walk catch
7732      * it. same expectations as async catches async.
7733      */
7734     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7735
7736     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7737                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7738
7739     fib_walk_process_queues(vm, 0);
7740     fib_walk_process_queues(vm, 0);
7741
7742     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7743
7744     FOR_EACH_TEST_CHILD(tc)
7745     {
7746         if (ii >= N_TEST_CHILDREN-1)
7747         {
7748             FIB_TEST(2 == vec_len(tc->ctxs),
7749                      "%d child visitsed %d times in sync catches async walk",
7750                      ii, vec_len(tc->ctxs));
7751             vec_free(tc->ctxs);
7752         }
7753         else
7754         {
7755             FIB_TEST(1 == vec_len(tc->ctxs),
7756                      "%d child visitsed %d times in sync catches async walk",
7757                      ii, vec_len(tc->ctxs));
7758             vec_free(tc->ctxs);
7759         }
7760     }
7761     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7762              "Queue is not empty post 2nd zero quanta merge walk");
7763     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7764              "Parent has %d children post 2nd zero qunta merge walk",
7765              fib_node_list_get_size(PARENT()->fn_children));
7766
7767     /*
7768      * make the parent a child of one of its children, thus inducing a routing loop.
7769      */
7770     fib_test_nodes[PARENT_INDEX].sibling =
7771         fib_node_child_add(FIB_NODE_TYPE_TEST,
7772                            1, // the first child
7773                            FIB_NODE_TYPE_TEST,
7774                            PARENT_INDEX);
7775
7776     /*
7777      * execute a sync walk from the parent. each child visited spawns more sync
7778      * walks. we expect the walk to terminate.
7779      */
7780     fib_test_walk_spawns_walks = 1;
7781
7782     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7783
7784     FOR_EACH_TEST_CHILD(tc)
7785     {
7786         /*
7787          * child 1 - which is last in the list - has the loop.
7788          * the other children a re thus visitsed first. the we meet
7789          * child 1. we go round the loop again, visting the other children.
7790          * then we meet the walk in the dep list and bail. child 1 is not visitsed
7791          * again.
7792          */
7793         if (1 == ii)
7794         {
7795             FIB_TEST(1 == vec_len(tc->ctxs),
7796                      "child %d visitsed %d times during looped sync walk",
7797                      ii, vec_len(tc->ctxs));
7798         }
7799         else
7800         {
7801             FIB_TEST(2 == vec_len(tc->ctxs),
7802                      "child %d visitsed %d times during looped sync walk",
7803                      ii, vec_len(tc->ctxs));
7804         }
7805         vec_free(tc->ctxs);
7806     }
7807     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7808              "Parent has %d children post sync loop walk",
7809              fib_node_list_get_size(PARENT()->fn_children));
7810
7811     /*
7812      * the walk doesn't reach the max depth because the infra knows that sync
7813      * meets sync implies a loop and bails early.
7814      */
7815     FIB_TEST(high_ctx.fnbw_depth == 9,
7816              "Walk context depth %d post sync loop walk",
7817              high_ctx.fnbw_depth);
7818
7819     /*
7820      * execute an async walk of the graph loop, with each child spawns sync walks
7821      */
7822     high_ctx.fnbw_depth = 0;
7823     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7824                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7825
7826     fib_walk_process_queues(vm, 1);
7827
7828     FOR_EACH_TEST_CHILD(tc)
7829     {
7830         /*
7831          * we don't really care how many times the children are visisted, as long as
7832          * it is more than once.
7833          */
7834         FIB_TEST(1 <= vec_len(tc->ctxs),
7835                  "child %d visitsed %d times during looped aync spawns sync walk",
7836                  ii, vec_len(tc->ctxs));
7837         vec_free(tc->ctxs);
7838     }
7839
7840     /*
7841      * execute an async walk of the graph loop, with each child spawns async walks
7842      */
7843     fib_test_walk_spawns_walks = 2;
7844     high_ctx.fnbw_depth = 0;
7845     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7846                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7847
7848     fib_walk_process_queues(vm, 1);
7849
7850     FOR_EACH_TEST_CHILD(tc)
7851     {
7852         /*
7853          * we don't really care how many times the children are visisted, as long as
7854          * it is more than once.
7855          */
7856         FIB_TEST(1 <= vec_len(tc->ctxs),
7857                  "child %d visitsed %d times during looped async spawns async walk",
7858                  ii, vec_len(tc->ctxs));
7859         vec_free(tc->ctxs);
7860     }
7861
7862
7863     fib_node_child_remove(FIB_NODE_TYPE_TEST,
7864                           1, // the first child
7865                           fib_test_nodes[PARENT_INDEX].sibling);
7866
7867     /*
7868      * cleanup
7869      */
7870     FOR_EACH_TEST_CHILD(tc)
7871     {
7872         fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7873                               tc->sibling);
7874         fib_node_deinit(&tc->node);
7875         fib_node_unlock(&tc->node);
7876     }
7877     fib_node_deinit(PARENT());
7878
7879     /*
7880      * The parent will be destroyed when the last lock on it goes.
7881      * this test ensures all the walk objects are unlocking it.
7882      */
7883     FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7884              "Parent was destroyed");
7885
7886     return (res);
7887 }
7888
7889 /*
7890  * declaration of the otherwise static callback functions
7891  */
7892 void fib_bfd_notify (bfd_listen_event_e event,
7893                      const bfd_session_t *session);
7894 void adj_bfd_notify (bfd_listen_event_e event,
7895                      const bfd_session_t *session);
7896
7897 /**
7898  * Test BFD session interaction with FIB
7899  */
7900 static int
7901 fib_test_bfd (void)
7902 {
7903     fib_node_index_t fei;
7904     test_main_t *tm;
7905     int n_feis, res;
7906
7907     res = 0;
7908     /* via 10.10.10.1 */
7909     ip46_address_t nh_10_10_10_1 = {
7910         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7911     };
7912     /* via 10.10.10.2 */
7913     ip46_address_t nh_10_10_10_2 = {
7914         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7915     };
7916     /* via 10.10.10.10 */
7917     ip46_address_t nh_10_10_10_10 = {
7918         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7919     };
7920     n_feis = fib_entry_pool_size();
7921
7922     tm = &test_main;
7923
7924     /*
7925      * add interface routes. we'll assume this works. it's tested elsewhere
7926      */
7927     fib_prefix_t pfx_10_10_10_10_s_24 = {
7928         .fp_len = 24,
7929         .fp_proto = FIB_PROTOCOL_IP4,
7930         .fp_addr = nh_10_10_10_10,
7931     };
7932
7933     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7934                                     FIB_SOURCE_INTERFACE,
7935                                     (FIB_ENTRY_FLAG_CONNECTED |
7936                                      FIB_ENTRY_FLAG_ATTACHED),
7937                                     DPO_PROTO_IP4,
7938                                     NULL,
7939                                     tm->hw[0]->sw_if_index,
7940                                     ~0, // invalid fib index
7941                                     1, // weight
7942                                     NULL,
7943                                     FIB_ROUTE_PATH_FLAG_NONE);
7944
7945     fib_prefix_t pfx_10_10_10_10_s_32 = {
7946         .fp_len = 32,
7947         .fp_proto = FIB_PROTOCOL_IP4,
7948         .fp_addr = nh_10_10_10_10,
7949     };
7950     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7951                                     FIB_SOURCE_INTERFACE,
7952                                     (FIB_ENTRY_FLAG_CONNECTED |
7953                                      FIB_ENTRY_FLAG_LOCAL),
7954                                     DPO_PROTO_IP4,
7955                                     NULL,
7956                                     tm->hw[0]->sw_if_index,
7957                                     ~0, // invalid fib index
7958                                     1, // weight
7959                                     NULL,
7960                                     FIB_ROUTE_PATH_FLAG_NONE);
7961
7962     /*
7963      * A BFD session via a neighbour we do not yet know
7964      */
7965     bfd_session_t bfd_10_10_10_1 = {
7966         .udp = {
7967             .key = {
7968                 .fib_index = 0,
7969                 .peer_addr = nh_10_10_10_1,
7970             },
7971         },
7972         .hop_type = BFD_HOP_TYPE_MULTI,
7973         .local_state = BFD_STATE_init,
7974     };
7975
7976     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7977
7978     /*
7979      * A new entry will be created that forwards via the adj
7980      */
7981     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7982                                                     VNET_LINK_IP4,
7983                                                     &nh_10_10_10_1,
7984                                                     tm->hw[0]->sw_if_index);
7985     fib_prefix_t pfx_10_10_10_1_s_32 = {
7986         .fp_addr = nh_10_10_10_1,
7987         .fp_len = 32,
7988         .fp_proto = FIB_PROTOCOL_IP4,
7989     };
7990     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7991         .type = FT_LB_ADJ,
7992         .adj = {
7993             .adj = ai_10_10_10_1,
7994         },
7995     };
7996
7997     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7998     FIB_TEST(!fib_test_validate_entry(fei,
7999                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8000                                       1,
8001                                       &adj_o_10_10_10_1),
8002              "BFD sourced %U via %U",
8003              format_fib_prefix, &pfx_10_10_10_1_s_32,
8004              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
8005
8006     /*
8007      * Delete the BFD session. Expect the fib_entry to be removed
8008      */
8009     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8010
8011     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8012     FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
8013              "BFD sourced %U removed",
8014              format_fib_prefix, &pfx_10_10_10_1_s_32);
8015
8016     /*
8017      * Add the BFD source back
8018      */
8019     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8020
8021     /*
8022      * source the entry via the ADJ fib
8023      */
8024     fei = fib_table_entry_path_add(0,
8025                                    &pfx_10_10_10_1_s_32,
8026                                    FIB_SOURCE_ADJ,
8027                                    FIB_ENTRY_FLAG_ATTACHED,
8028                                    DPO_PROTO_IP4,
8029                                    &nh_10_10_10_1,
8030                                    tm->hw[0]->sw_if_index,
8031                                    ~0, // invalid fib index
8032                                    1,
8033                                    NULL,
8034                                    FIB_ROUTE_PATH_FLAG_NONE);
8035
8036     /*
8037      * Delete the BFD session. Expect the fib_entry to remain
8038      */
8039     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8040
8041     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8042     FIB_TEST(!fib_test_validate_entry(fei,
8043                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8044                                       1,
8045                                       &adj_o_10_10_10_1),
8046              "BFD sourced %U remains via %U",
8047              format_fib_prefix, &pfx_10_10_10_1_s_32,
8048              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
8049
8050     /*
8051      * Add the BFD source back
8052      */
8053     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8054
8055     /*
8056      * Create another ADJ FIB
8057      */
8058     fib_prefix_t pfx_10_10_10_2_s_32 = {
8059         .fp_addr = nh_10_10_10_2,
8060         .fp_len = 32,
8061         .fp_proto = FIB_PROTOCOL_IP4,
8062     };
8063     fib_table_entry_path_add(0,
8064                              &pfx_10_10_10_2_s_32,
8065                              FIB_SOURCE_ADJ,
8066                              FIB_ENTRY_FLAG_ATTACHED,
8067                              DPO_PROTO_IP4,
8068                              &nh_10_10_10_2,
8069                              tm->hw[0]->sw_if_index,
8070                              ~0, // invalid fib index
8071                              1,
8072                              NULL,
8073                              FIB_ROUTE_PATH_FLAG_NONE);
8074     /*
8075      * A BFD session for the new ADJ FIB
8076      */
8077     bfd_session_t bfd_10_10_10_2 = {
8078         .udp = {
8079             .key = {
8080                 .fib_index = 0,
8081                 .peer_addr = nh_10_10_10_2,
8082             },
8083         },
8084         .hop_type = BFD_HOP_TYPE_MULTI,
8085         .local_state = BFD_STATE_init,
8086     };
8087
8088     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
8089
8090     /*
8091      * remove the adj-fib source whilst the session is present
8092      * then add it back
8093      */
8094     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8095     fib_table_entry_path_add(0,
8096                              &pfx_10_10_10_2_s_32,
8097                              FIB_SOURCE_ADJ,
8098                              FIB_ENTRY_FLAG_ATTACHED,
8099                              DPO_PROTO_IP4,
8100                              &nh_10_10_10_2,
8101                              tm->hw[0]->sw_if_index,
8102                              ~0, // invalid fib index
8103                              1,
8104                              NULL,
8105                              FIB_ROUTE_PATH_FLAG_NONE);
8106
8107     /*
8108      * Before adding a recursive via the BFD tracked ADJ-FIBs,
8109      * bring one of the sessions UP, leave the other down
8110      */
8111     bfd_10_10_10_1.local_state = BFD_STATE_up;
8112     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8113     bfd_10_10_10_2.local_state = BFD_STATE_down;
8114     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8115
8116     /*
8117      * A recursive prefix via both of the ADJ FIBs
8118      */
8119     fib_prefix_t pfx_200_0_0_0_s_24 = {
8120         .fp_proto = FIB_PROTOCOL_IP4,
8121         .fp_len = 32,
8122         .fp_addr = {
8123             .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
8124         },
8125     };
8126     const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
8127
8128     dpo_10_10_10_1 =
8129         fib_entry_contribute_ip_forwarding(
8130             fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
8131     dpo_10_10_10_2 =
8132         fib_entry_contribute_ip_forwarding(
8133             fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
8134
8135     fib_test_lb_bucket_t lb_o_10_10_10_1 = {
8136         .type = FT_LB_O_LB,
8137         .lb = {
8138             .lb = dpo_10_10_10_1->dpoi_index,
8139         },
8140     };
8141     fib_test_lb_bucket_t lb_o_10_10_10_2 = {
8142         .type = FT_LB_O_LB,
8143         .lb = {
8144             .lb = dpo_10_10_10_2->dpoi_index,
8145         },
8146     };
8147
8148     /*
8149      * A prefix via the adj-fib that is BFD down => DROP
8150      */
8151     fei = fib_table_entry_path_add(0,
8152                                    &pfx_200_0_0_0_s_24,
8153                                    FIB_SOURCE_API,
8154                                    FIB_ENTRY_FLAG_NONE,
8155                                    DPO_PROTO_IP4,
8156                                    &nh_10_10_10_2,
8157                                    ~0, // recursive
8158                                    0, // default fib index
8159                                    1,
8160                                    NULL,
8161                                    FIB_ROUTE_PATH_FLAG_NONE);
8162     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8163              "%U resolves via drop",
8164              format_fib_prefix, &pfx_200_0_0_0_s_24);
8165
8166     /*
8167      * add a path via the UP BFD adj-fib.
8168      *  we expect that the DOWN BFD ADJ FIB is not used.
8169      */
8170     fei = fib_table_entry_path_add(0,
8171                                    &pfx_200_0_0_0_s_24,
8172                                    FIB_SOURCE_API,
8173                                    FIB_ENTRY_FLAG_NONE,
8174                                    DPO_PROTO_IP4,
8175                                    &nh_10_10_10_1,
8176                                    ~0, // recursive
8177                                    0, // default fib index
8178                                    1,
8179                                    NULL,
8180                                    FIB_ROUTE_PATH_FLAG_NONE);
8181
8182     FIB_TEST(!fib_test_validate_entry(fei,
8183                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8184                                       1,
8185                                       &lb_o_10_10_10_1),
8186              "Recursive %U only UP BFD adj-fibs",
8187              format_fib_prefix, &pfx_200_0_0_0_s_24);
8188
8189     /*
8190      * Send a BFD state change to UP - both sessions are now up
8191      *  the recursive prefix should LB over both
8192      */
8193     bfd_10_10_10_2.local_state = BFD_STATE_up;
8194     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8195
8196
8197     FIB_TEST(!fib_test_validate_entry(fei,
8198                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8199                                       2,
8200                                       &lb_o_10_10_10_1,
8201                                       &lb_o_10_10_10_2),
8202              "Recursive %U via both UP BFD adj-fibs",
8203              format_fib_prefix, &pfx_200_0_0_0_s_24);
8204
8205     /*
8206      * Send a BFD state change to DOWN
8207      *  the recursive prefix should exclude the down
8208      */
8209     bfd_10_10_10_2.local_state = BFD_STATE_down;
8210     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8211
8212
8213     FIB_TEST(!fib_test_validate_entry(fei,
8214                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8215                                       1,
8216                                       &lb_o_10_10_10_1),
8217              "Recursive %U via only UP",
8218              format_fib_prefix, &pfx_200_0_0_0_s_24);
8219
8220     /*
8221      * Delete the BFD session while it is in the DOWN state.
8222      *  FIB should consider the entry's state as back up
8223      */
8224     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8225
8226     FIB_TEST(!fib_test_validate_entry(fei,
8227                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8228                                       2,
8229                                       &lb_o_10_10_10_1,
8230                                       &lb_o_10_10_10_2),
8231              "Recursive %U via both UP BFD adj-fibs post down session delete",
8232              format_fib_prefix, &pfx_200_0_0_0_s_24);
8233
8234     /*
8235      * Delete the BFD other session while it is in the UP state.
8236      */
8237     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8238
8239     FIB_TEST(!fib_test_validate_entry(fei,
8240                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8241                                       2,
8242                                       &lb_o_10_10_10_1,
8243                                       &lb_o_10_10_10_2),
8244              "Recursive %U via both UP BFD adj-fibs post up session delete",
8245              format_fib_prefix, &pfx_200_0_0_0_s_24);
8246
8247     /*
8248      * cleaup
8249      */
8250     fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8251     fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8252     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8253
8254     fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8255     fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8256
8257     adj_unlock(ai_10_10_10_1);
8258     /*
8259      * test no-one left behind
8260      */
8261     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8262     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8263
8264     /*
8265      * Single-hop BFD tests
8266      */
8267     bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8268     bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8269
8270     adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8271
8272     ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8273                                         VNET_LINK_IP4,
8274                                         &nh_10_10_10_1,
8275                                         tm->hw[0]->sw_if_index);
8276     /*
8277      * whilst the BFD session is not signalled, the adj is up
8278      */
8279     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on uninit session");
8280
8281     /*
8282      * bring the BFD session up
8283      */
8284     bfd_10_10_10_1.local_state = BFD_STATE_up;
8285     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8286     FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8287
8288     /*
8289      * bring the BFD session down
8290      */
8291     bfd_10_10_10_1.local_state = BFD_STATE_down;
8292     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8293     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8294
8295     /*
8296      * add an attached next hop FIB entry via the down adj
8297      */
8298     fib_prefix_t pfx_5_5_5_5_s_32 = {
8299         .fp_addr = {
8300             .ip4 = {
8301                 .as_u32 = clib_host_to_net_u32(0x05050505),
8302             },
8303         },
8304         .fp_len = 32,
8305         .fp_proto = FIB_PROTOCOL_IP4,
8306     };
8307
8308     fei = fib_table_entry_path_add(0,
8309                                    &pfx_5_5_5_5_s_32,
8310                                    FIB_SOURCE_CLI,
8311                                    FIB_ENTRY_FLAG_NONE,
8312                                    DPO_PROTO_IP4,
8313                                    &nh_10_10_10_1,
8314                                    tm->hw[0]->sw_if_index,
8315                                    ~0, // invalid fib index
8316                                    1,
8317                                    NULL,
8318                                    FIB_ROUTE_PATH_FLAG_NONE);
8319     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8320              "%U resolves via drop",
8321              format_fib_prefix, &pfx_5_5_5_5_s_32);
8322
8323     /*
8324      * Add a path via an ADJ that is up
8325      */
8326     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8327                                                     VNET_LINK_IP4,
8328                                                     &nh_10_10_10_2,
8329                                                     tm->hw[0]->sw_if_index);
8330
8331     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8332         .type = FT_LB_ADJ,
8333         .adj = {
8334             .adj = ai_10_10_10_2,
8335         },
8336     };
8337     adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8338
8339     fei = fib_table_entry_path_add(0,
8340                                    &pfx_5_5_5_5_s_32,
8341                                    FIB_SOURCE_CLI,
8342                                    FIB_ENTRY_FLAG_NONE,
8343                                    DPO_PROTO_IP4,
8344                                    &nh_10_10_10_2,
8345                                    tm->hw[0]->sw_if_index,
8346                                    ~0, // invalid fib index
8347                                    1,
8348                                    NULL,
8349                                    FIB_ROUTE_PATH_FLAG_NONE);
8350
8351     FIB_TEST(!fib_test_validate_entry(fei,
8352                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8353                                       1,
8354                                       &adj_o_10_10_10_2),
8355              "BFD sourced %U via %U",
8356              format_fib_prefix, &pfx_5_5_5_5_s_32,
8357              format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8358
8359     /*
8360      * Bring up the down session - should now LB
8361      */
8362     bfd_10_10_10_1.local_state = BFD_STATE_up;
8363     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8364     FIB_TEST(!fib_test_validate_entry(fei,
8365                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8366                                       2,
8367                                       &adj_o_10_10_10_1,
8368                                       &adj_o_10_10_10_2),
8369              "BFD sourced %U via noth adjs",
8370              format_fib_prefix, &pfx_5_5_5_5_s_32);
8371
8372     /*
8373      * remove the BFD session state from the adj
8374      */
8375     adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8376
8377     /*
8378      * clean-up
8379      */
8380     fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8381     adj_unlock(ai_10_10_10_1);
8382     adj_unlock(ai_10_10_10_2);
8383
8384     /*
8385      * test no-one left behind
8386      */
8387     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8388     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8389
8390     return (res);
8391 }
8392
8393 static int
8394 lfib_test (void)
8395 {
8396     const mpls_label_t deag_label = 50;
8397     adj_index_t ai_mpls_10_10_10_1;
8398     dpo_id_t dpo = DPO_INVALID;
8399     const u32 lfib_index = 0;
8400     const u32 fib_index = 0;
8401     const dpo_id_t *dpo1;
8402     fib_node_index_t lfe;
8403     lookup_dpo_t *lkd;
8404     int lb_count, res;
8405     test_main_t *tm;
8406
8407     res = 0;
8408     tm = &test_main;
8409     lb_count = pool_elts(load_balance_pool);
8410
8411     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8412              adj_nbr_db_size());
8413
8414     /*
8415      * MPLS enable an interface so we get the MPLS table created
8416      */
8417     mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8418     mpls_sw_interface_enable_disable(&mpls_main,
8419                                      tm->hw[0]->sw_if_index,
8420                                      1, 1);
8421
8422     ip46_address_t nh_10_10_10_1 = {
8423         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8424     };
8425     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8426                                              VNET_LINK_MPLS,
8427                                              &nh_10_10_10_1,
8428                                              tm->hw[0]->sw_if_index);
8429
8430     /*
8431      * Test the specials stack properly.
8432      */
8433     fib_prefix_t exp_null_v6_pfx = {
8434         .fp_proto = FIB_PROTOCOL_MPLS,
8435         .fp_eos = MPLS_EOS,
8436         .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8437         .fp_payload_proto = DPO_PROTO_IP6,
8438     };
8439     lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8440     FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8441              "%U/%U present",
8442              format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8443              format_mpls_eos_bit, MPLS_EOS);
8444     fib_entry_contribute_forwarding(lfe,
8445                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8446                                     &dpo);
8447     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8448     lkd = lookup_dpo_get(dpo1->dpoi_index);
8449
8450     FIB_TEST((fib_index == lkd->lkd_fib_index),
8451              "%U/%U is deag in %d %U",
8452              format_mpls_unicast_label, deag_label,
8453              format_mpls_eos_bit, MPLS_EOS,
8454              lkd->lkd_fib_index,
8455              format_dpo_id, &dpo, 0);
8456     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8457              "%U/%U is dst deag",
8458              format_mpls_unicast_label, deag_label,
8459              format_mpls_eos_bit, MPLS_EOS);
8460     FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8461              "%U/%U is lookup in interface's table",
8462              format_mpls_unicast_label, deag_label,
8463              format_mpls_eos_bit, MPLS_EOS);
8464     FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8465              "%U/%U is %U dst deag",
8466              format_mpls_unicast_label, deag_label,
8467              format_mpls_eos_bit, MPLS_EOS,
8468              format_dpo_proto, lkd->lkd_proto);
8469
8470     /*
8471      * A route deag route for EOS
8472      */
8473     fib_prefix_t pfx = {
8474         .fp_proto = FIB_PROTOCOL_MPLS,
8475         .fp_eos = MPLS_EOS,
8476         .fp_label = deag_label,
8477         .fp_payload_proto = DPO_PROTO_IP4,
8478     };
8479     mpls_disp_dpo_t *mdd;
8480     lfe = fib_table_entry_path_add(lfib_index,
8481                                    &pfx,
8482                                    FIB_SOURCE_CLI,
8483                                    FIB_ENTRY_FLAG_NONE,
8484                                    DPO_PROTO_IP4,
8485                                    &zero_addr,
8486                                    ~0,
8487                                    fib_index,
8488                                    1,
8489                                    NULL,
8490                                    FIB_ROUTE_PATH_FLAG_NONE);
8491
8492     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8493              "%U/%U present",
8494              format_mpls_unicast_label, deag_label,
8495              format_mpls_eos_bit, MPLS_EOS);
8496
8497     fib_entry_contribute_forwarding(lfe,
8498                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8499                                     &dpo);
8500     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8501     mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8502
8503     FIB_TEST((FIB_MPLS_LSP_MODE_PIPE == mdd->mdd_mode),
8504              "%U/%U disp is pipe mode",
8505              format_mpls_unicast_label, deag_label,
8506              format_mpls_eos_bit, MPLS_EOS);
8507
8508     lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8509
8510     FIB_TEST((fib_index == lkd->lkd_fib_index),
8511              "%U/%U is deag in %d %U",
8512              format_mpls_unicast_label, deag_label,
8513              format_mpls_eos_bit, MPLS_EOS,
8514              lkd->lkd_fib_index,
8515              format_dpo_id, &dpo, 0);
8516     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8517              "%U/%U is dst deag",
8518              format_mpls_unicast_label, deag_label,
8519              format_mpls_eos_bit, MPLS_EOS);
8520     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8521              "%U/%U is %U dst deag",
8522              format_mpls_unicast_label, deag_label,
8523              format_mpls_eos_bit, MPLS_EOS,
8524              format_dpo_proto, lkd->lkd_proto);
8525
8526     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8527
8528     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8529                                                          &pfx)),
8530               "%U/%U not present",
8531               format_mpls_unicast_label, deag_label,
8532               format_mpls_eos_bit, MPLS_EOS);
8533     dpo_reset(&dpo);
8534
8535     /*
8536      * A route deag route for EOS with LSP mode uniform
8537      */
8538     fib_mpls_label_t *l_pops = NULL, l_pop = {
8539         .fml_value = MPLS_LABEL_POP,
8540         .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
8541     };
8542     vec_add1(l_pops, l_pop);
8543     lfe = fib_table_entry_path_add(lfib_index,
8544                                    &pfx,
8545                                    FIB_SOURCE_CLI,
8546                                    FIB_ENTRY_FLAG_NONE,
8547                                    DPO_PROTO_IP4,
8548                                    &zero_addr,
8549                                    ~0,
8550                                    fib_index,
8551                                    1,
8552                                    l_pops,
8553                                    FIB_ROUTE_PATH_FLAG_NONE);
8554
8555     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8556               "%U/%U present",
8557               format_mpls_unicast_label, deag_label,
8558               format_mpls_eos_bit, MPLS_EOS);
8559
8560     fib_entry_contribute_forwarding(lfe,
8561                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8562                                     &dpo);
8563     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8564     mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8565
8566     FIB_TEST((FIB_MPLS_LSP_MODE_UNIFORM == mdd->mdd_mode),
8567              "%U/%U disp is uniform mode",
8568              format_mpls_unicast_label, deag_label,
8569              format_mpls_eos_bit, MPLS_EOS);
8570
8571     lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8572
8573     FIB_TEST((fib_index == lkd->lkd_fib_index),
8574               "%U/%U is deag in %d %U",
8575              format_mpls_unicast_label, deag_label,
8576              format_mpls_eos_bit, MPLS_EOS,
8577              lkd->lkd_fib_index,
8578              format_dpo_id, &dpo, 0);
8579     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8580              "%U/%U is dst deag",
8581              format_mpls_unicast_label, deag_label,
8582              format_mpls_eos_bit, MPLS_EOS);
8583     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8584              "%U/%U is %U dst deag",
8585              format_mpls_unicast_label, deag_label,
8586              format_mpls_eos_bit, MPLS_EOS,
8587              format_dpo_proto, lkd->lkd_proto);
8588
8589     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8590
8591     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8592                                                          &pfx)),
8593               "%U/%U not present",
8594               format_mpls_unicast_label, deag_label,
8595               format_mpls_eos_bit, MPLS_EOS);
8596     dpo_reset(&dpo);
8597
8598     /*
8599      * A route deag route for non-EOS
8600      */
8601     pfx.fp_eos = MPLS_NON_EOS;
8602     lfe = fib_table_entry_path_add(lfib_index,
8603                                    &pfx,
8604                                    FIB_SOURCE_CLI,
8605                                    FIB_ENTRY_FLAG_NONE,
8606                                    DPO_PROTO_IP4,
8607                                    &zero_addr,
8608                                    ~0,
8609                                    lfib_index,
8610                                    1,
8611                                    NULL,
8612                                    FIB_ROUTE_PATH_FLAG_NONE);
8613
8614     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8615              "%U/%U present",
8616              format_mpls_unicast_label, deag_label,
8617              format_mpls_eos_bit, MPLS_NON_EOS);
8618
8619     fib_entry_contribute_forwarding(lfe,
8620                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8621                                     &dpo);
8622     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8623     lkd = lookup_dpo_get(dpo1->dpoi_index);
8624
8625     FIB_TEST((fib_index == lkd->lkd_fib_index),
8626              "%U/%U is deag in %d %U",
8627              format_mpls_unicast_label, deag_label,
8628              format_mpls_eos_bit, MPLS_NON_EOS,
8629              lkd->lkd_fib_index,
8630              format_dpo_id, &dpo, 0);
8631     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8632              "%U/%U is dst deag",
8633              format_mpls_unicast_label, deag_label,
8634              format_mpls_eos_bit, MPLS_NON_EOS);
8635
8636     FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8637              "%U/%U is %U dst deag",
8638              format_mpls_unicast_label, deag_label,
8639              format_mpls_eos_bit, MPLS_NON_EOS,
8640              format_dpo_proto, lkd->lkd_proto);
8641
8642     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8643
8644     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8645                                                          &pfx)),
8646              "%U/%U not present",
8647              format_mpls_unicast_label, deag_label,
8648              format_mpls_eos_bit, MPLS_EOS);
8649
8650     dpo_reset(&dpo);
8651
8652     /*
8653      * An MPLS x-connect
8654      */
8655     fib_prefix_t pfx_1200 = {
8656         .fp_len = 21,
8657         .fp_proto = FIB_PROTOCOL_MPLS,
8658         .fp_label = 1200,
8659         .fp_eos = MPLS_NON_EOS,
8660     };
8661     fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8662         .type = FT_LB_LABEL_STACK_O_ADJ,
8663         .label_stack_o_adj = {
8664             .adj = ai_mpls_10_10_10_1,
8665             .label_stack_size = 4,
8666             .label_stack = {
8667                 200, 300, 400, 500,
8668             },
8669             .eos = MPLS_NON_EOS,
8670         },
8671     };
8672     dpo_id_t neos_1200 = DPO_INVALID;
8673     dpo_id_t ip_1200 = DPO_INVALID;
8674     fib_mpls_label_t *l200 = NULL;
8675     u32 ii;
8676     for (ii = 0; ii < 4; ii++)
8677     {
8678         fib_mpls_label_t fml = {
8679             .fml_value = 200 + (ii * 100),
8680         };
8681         vec_add1(l200, fml);
8682     };
8683
8684     lfe = fib_table_entry_update_one_path(fib_index,
8685                                           &pfx_1200,
8686                                           FIB_SOURCE_API,
8687                                           FIB_ENTRY_FLAG_NONE,
8688                                           DPO_PROTO_IP4,
8689                                           &nh_10_10_10_1,
8690                                           tm->hw[0]->sw_if_index,
8691                                           ~0, // invalid fib index
8692                                           1,
8693                                           l200,
8694                                           FIB_ROUTE_PATH_FLAG_NONE);
8695
8696     FIB_TEST(!fib_test_validate_entry(lfe,
8697                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8698                                       1,
8699                                       &neos_o_10_10_10_1),
8700              "1200/0 LB 1 buckets via: "
8701              "adj 10.10.11.1");
8702
8703     /*
8704      * A recursive route via the MPLS x-connect
8705      */
8706     fib_prefix_t pfx_2_2_2_3_s_32 = {
8707         .fp_len = 32,
8708         .fp_proto = FIB_PROTOCOL_IP4,
8709         .fp_addr = {
8710             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8711         },
8712     };
8713     fib_route_path_t *rpaths = NULL, rpath = {
8714         .frp_proto = DPO_PROTO_MPLS,
8715         .frp_local_label = 1200,
8716         .frp_eos = MPLS_NON_EOS,
8717         .frp_sw_if_index = ~0, // recurive
8718         .frp_fib_index = 0, // Default MPLS fib
8719         .frp_weight = 1,
8720         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8721         .frp_label_stack = NULL,
8722     };
8723     vec_add1(rpaths, rpath);
8724
8725     fib_table_entry_path_add2(fib_index,
8726                               &pfx_2_2_2_3_s_32,
8727                               FIB_SOURCE_API,
8728                               FIB_ENTRY_FLAG_NONE,
8729                               rpaths);
8730
8731     /*
8732      * A labelled recursive route via the MPLS x-connect
8733      */
8734     fib_prefix_t pfx_2_2_2_4_s_32 = {
8735         .fp_len = 32,
8736         .fp_proto = FIB_PROTOCOL_IP4,
8737         .fp_addr = {
8738             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8739         },
8740     };
8741     fib_mpls_label_t *l999 = NULL, fml_999 = {
8742         .fml_value = 999,
8743     };
8744     vec_add1(l999, fml_999);
8745     rpaths[0].frp_label_stack = l999,
8746
8747         fib_table_entry_path_add2(fib_index,
8748                                   &pfx_2_2_2_4_s_32,
8749                                   FIB_SOURCE_API,
8750                                   FIB_ENTRY_FLAG_NONE,
8751                                   rpaths);
8752
8753     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8754                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8755                                     &ip_1200);
8756     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8757                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8758                                     &neos_1200);
8759
8760     fib_test_lb_bucket_t ip_o_1200 = {
8761         .type = FT_LB_O_LB,
8762         .lb = {
8763             .lb = ip_1200.dpoi_index,
8764         },
8765     };
8766     fib_test_lb_bucket_t mpls_o_1200 = {
8767         .type = FT_LB_LABEL_O_LB,
8768         .label_o_lb = {
8769             .lb = neos_1200.dpoi_index,
8770             .label = 999,
8771             .eos = MPLS_EOS,
8772         },
8773     };
8774
8775     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8776     FIB_TEST(!fib_test_validate_entry(lfe,
8777                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8778                                       1,
8779                                       &ip_o_1200),
8780              "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8781     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8782     FIB_TEST(!fib_test_validate_entry(lfe,
8783                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8784                                       1,
8785                                       &mpls_o_1200),
8786              "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8787
8788     fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8789     fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8790     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8791
8792     dpo_reset(&neos_1200);
8793     dpo_reset(&ip_1200);
8794
8795     /*
8796      * A recursive via a label that does not exist
8797      */
8798     fib_test_lb_bucket_t bucket_drop = {
8799         .type = FT_LB_DROP,
8800         .special = {
8801             .adj = DPO_PROTO_IP4,
8802         },
8803     };
8804     fib_test_lb_bucket_t mpls_bucket_drop = {
8805         .type = FT_LB_DROP,
8806         .special = {
8807             .adj = DPO_PROTO_MPLS,
8808         },
8809     };
8810
8811     rpaths[0].frp_label_stack = NULL;
8812     lfe = fib_table_entry_path_add2(fib_index,
8813                                     &pfx_2_2_2_4_s_32,
8814                                     FIB_SOURCE_API,
8815                                     FIB_ENTRY_FLAG_NONE,
8816                                     rpaths);
8817
8818     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8819                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8820                                     &ip_1200);
8821     ip_o_1200.lb.lb = ip_1200.dpoi_index;
8822
8823     FIB_TEST(!fib_test_validate_entry(lfe,
8824                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8825                                       1,
8826                                       &bucket_drop),
8827              "2.2.2.2.4/32 LB 1 buckets via: drop");
8828     lfe = fib_table_lookup(fib_index, &pfx_1200);
8829     FIB_TEST(!fib_test_validate_entry(lfe,
8830                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8831                                       1,
8832                                       &bucket_drop),
8833              "1200/neos LB 1 buckets via: ip4-DROP");
8834     FIB_TEST(!fib_test_validate_entry(lfe,
8835                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8836                                       1,
8837                                       &mpls_bucket_drop),
8838              "1200/neos LB 1 buckets via: mpls-DROP");
8839
8840     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8841
8842     dpo_reset(&ip_1200);
8843
8844     /*
8845      * An rx-interface route.
8846      *  like the tail of an mcast LSP
8847      */
8848     dpo_id_t idpo = DPO_INVALID;
8849
8850     interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8851                                  tm->hw[0]->sw_if_index,
8852                                  &idpo);
8853
8854     fib_prefix_t pfx_2500 = {
8855         .fp_len = 21,
8856         .fp_proto = FIB_PROTOCOL_MPLS,
8857         .fp_label = 2500,
8858         .fp_eos = MPLS_EOS,
8859         .fp_payload_proto = DPO_PROTO_IP4,
8860     };
8861     fib_test_lb_bucket_t rx_intf_0 = {
8862         .type = FT_LB_INTF,
8863         .adj = {
8864             .adj = idpo.dpoi_index,
8865         },
8866     };
8867
8868     lfe = fib_table_entry_update_one_path(fib_index,
8869                                           &pfx_2500,
8870                                           FIB_SOURCE_API,
8871                                           FIB_ENTRY_FLAG_NONE,
8872                                           DPO_PROTO_IP4,
8873                                           NULL,
8874                                           tm->hw[0]->sw_if_index,
8875                                           ~0, // invalid fib index
8876                                           0,
8877                                           NULL,
8878                                           FIB_ROUTE_PATH_INTF_RX);
8879     FIB_TEST(!fib_test_validate_entry(lfe,
8880                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8881                                       1,
8882                                       &rx_intf_0),
8883              "2500 rx-interface 0");
8884     fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8885
8886     /*
8887      * An MPLS mulicast entry
8888      */
8889     fib_prefix_t pfx_3500 = {
8890         .fp_len = 21,
8891         .fp_proto = FIB_PROTOCOL_MPLS,
8892         .fp_label = 3500,
8893         .fp_eos = MPLS_EOS,
8894         .fp_payload_proto = DPO_PROTO_IP4,
8895     };
8896     fib_test_rep_bucket_t mc_0 = {
8897         .type = FT_REP_LABEL_O_ADJ,
8898         .label_o_adj = {
8899             .adj = ai_mpls_10_10_10_1,
8900             .label = 3300,
8901             .eos = MPLS_EOS,
8902         },
8903     };
8904     fib_test_rep_bucket_t mc_intf_0 = {
8905         .type = FT_REP_INTF,
8906         .adj = {
8907             .adj = idpo.dpoi_index,
8908         },
8909     };
8910     fib_mpls_label_t *l3300 = NULL, fml_3300 = {
8911         .fml_value = 3300,
8912     };
8913     vec_add1(l3300, fml_3300);
8914
8915     lfe = fib_table_entry_update_one_path(lfib_index,
8916                                           &pfx_3500,
8917                                           FIB_SOURCE_API,
8918                                           FIB_ENTRY_FLAG_MULTICAST,
8919                                           DPO_PROTO_IP4,
8920                                           &nh_10_10_10_1,
8921                                           tm->hw[0]->sw_if_index,
8922                                           ~0, // invalid fib index
8923                                           1,
8924                                           l3300,
8925                                           FIB_ROUTE_PATH_FLAG_NONE);
8926     FIB_TEST(!fib_test_validate_entry(lfe,
8927                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8928                                       1,
8929                                       &mc_0),
8930              "3500 via replicate over 10.10.10.1");
8931
8932     /*
8933      * MPLS Bud-node. Add a replication via an interface-receieve path
8934      */
8935     lfe = fib_table_entry_path_add(lfib_index,
8936                                    &pfx_3500,
8937                                    FIB_SOURCE_API,
8938                                    FIB_ENTRY_FLAG_MULTICAST,
8939                                    DPO_PROTO_IP4,
8940                                    NULL,
8941                                    tm->hw[0]->sw_if_index,
8942                                    ~0, // invalid fib index
8943                                    0,
8944                                    NULL,
8945                                    FIB_ROUTE_PATH_INTF_RX);
8946     FIB_TEST(!fib_test_validate_entry(lfe,
8947                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8948                                       2,
8949                                       &mc_0,
8950                                       &mc_intf_0),
8951              "3500 via replicate over 10.10.10.1 and interface-rx");
8952
8953     /*
8954      * Add a replication via an interface-free for-us path
8955      */
8956     fib_test_rep_bucket_t mc_disp = {
8957         .type = FT_REP_DISP_MFIB_LOOKUP,
8958         .adj = {
8959             .adj = idpo.dpoi_index,
8960         },
8961     };
8962     lfe = fib_table_entry_path_add(lfib_index,
8963                                    &pfx_3500,
8964                                    FIB_SOURCE_API,
8965                                    FIB_ENTRY_FLAG_MULTICAST,
8966                                    DPO_PROTO_IP4,
8967                                    NULL,
8968                                    5, // rpf-id
8969                                    0, // default table
8970                                    0,
8971                                    NULL,
8972                                    FIB_ROUTE_PATH_RPF_ID);
8973     FIB_TEST(!fib_test_validate_entry(lfe,
8974                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8975                                       3,
8976                                       &mc_0,
8977                                       &mc_disp,
8978                                       &mc_intf_0),
8979              "3500 via replicate over 10.10.10.1 and interface-rx");
8980
8981
8982
8983     fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8984     dpo_reset(&idpo);
8985
8986     /*
8987      * cleanup
8988      */
8989     mpls_sw_interface_enable_disable(&mpls_main,
8990                                      tm->hw[0]->sw_if_index,
8991                                      0, 1);
8992     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
8993
8994     FIB_TEST(0 == pool_elts(mpls_disp_dpo_pool),
8995              "mpls_disp_dpo resources freed %d of %d",
8996              0, pool_elts(mpls_disp_dpo_pool));
8997     FIB_TEST(lb_count == pool_elts(load_balance_pool),
8998              "Load-balance resources freed %d of %d",
8999              lb_count, pool_elts(load_balance_pool));
9000     FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
9001              "interface_rx_dpo resources freed %d of %d",
9002              0, pool_elts(interface_rx_dpo_pool));
9003
9004     return (res);
9005 }
9006
9007 static int
9008 fib_test_inherit (void)
9009 {
9010     fib_node_index_t fei;
9011     test_main_t *tm;
9012     int n_feis, res;
9013
9014     res = 0;
9015     n_feis = fib_entry_pool_size();
9016     tm = &test_main;
9017
9018     const ip46_address_t nh_10_10_10_1 = {
9019         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
9020     };
9021     const ip46_address_t nh_10_10_10_2 = {
9022         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
9023     };
9024     const ip46_address_t nh_10_10_10_3 = {
9025         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
9026     };
9027     const ip46_address_t nh_10_10_10_16 = {
9028         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a10),
9029     };
9030     const ip46_address_t nh_10_10_10_20 = {
9031         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a14),
9032     };
9033     const ip46_address_t nh_10_10_10_21 = {
9034         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a15),
9035     };
9036     const ip46_address_t nh_10_10_10_22 = {
9037         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a16),
9038     };
9039     const ip46_address_t nh_10_10_10_255 = {
9040         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0aff),
9041     };
9042     const ip46_address_t nh_10_10_10_0 = {
9043         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a00),
9044     };
9045     const ip46_address_t nh_10_10_0_0 = {
9046         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0000),
9047     };
9048     const ip46_address_t nh_11_11_11_11 = {
9049         .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
9050     };
9051     const ip46_address_t nh_11_11_11_0 = {
9052         .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b00),
9053     };
9054
9055     /*
9056      * prefixes at the base of a sub-tree
9057      */
9058     const fib_prefix_t pfx_10_10_10_21_s_32 = {
9059         .fp_len = 32,
9060         .fp_proto = FIB_PROTOCOL_IP4,
9061         .fp_addr = nh_10_10_10_21,
9062     };
9063     const fib_prefix_t pfx_10_10_10_22_s_32 = {
9064         .fp_len = 32,
9065         .fp_proto = FIB_PROTOCOL_IP4,
9066         .fp_addr = nh_10_10_10_22,
9067     };
9068     const fib_prefix_t pfx_10_10_10_255_s_32 = {
9069         .fp_len = 32,
9070         .fp_proto = FIB_PROTOCOL_IP4,
9071         .fp_addr = nh_10_10_10_255,
9072     };
9073     const u32 N_PLS = fib_path_list_pool_size();
9074
9075     fib_table_entry_special_add(0,
9076                                 &pfx_10_10_10_21_s_32,
9077                                 FIB_SOURCE_CLI,
9078                                 FIB_ENTRY_FLAG_DROP);
9079     fib_table_entry_special_add(0,
9080                                 &pfx_10_10_10_22_s_32,
9081                                 FIB_SOURCE_CLI,
9082                                 FIB_ENTRY_FLAG_DROP);
9083     fib_table_entry_special_add(0,
9084                                 &pfx_10_10_10_255_s_32,
9085                                 FIB_SOURCE_CLI,
9086                                 FIB_ENTRY_FLAG_DROP);
9087
9088     /*
9089      * source an entry that pushes its state down the sub-tree
9090      */
9091     const fib_prefix_t pfx_10_10_10_16_s_28 = {
9092         .fp_len = 28,
9093         .fp_proto = FIB_PROTOCOL_IP4,
9094         .fp_addr = nh_10_10_10_16,
9095     };
9096     fib_table_entry_update_one_path(0,
9097                                     &pfx_10_10_10_16_s_28,
9098                                     FIB_SOURCE_API,
9099                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9100                                     DPO_PROTO_IP4,
9101                                     &nh_10_10_10_1,
9102                                     tm->hw[0]->sw_if_index,
9103                                     ~0,
9104                                     1,
9105                                     NULL,
9106                                     FIB_ROUTE_PATH_FLAG_NONE);
9107
9108     /*
9109      * this covering entry and all those below it should have
9110      * the same forwarding information.
9111      */
9112     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9113                                                     VNET_LINK_IP4,
9114                                                     &nh_10_10_10_1,
9115                                                     tm->hw[0]->sw_if_index);
9116     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
9117         .type = FT_LB_ADJ,
9118         .adj = {
9119             .adj = ai_10_10_10_1,
9120         },
9121     };
9122
9123     fei = fib_table_lookup(0, &pfx_10_10_10_16_s_28);
9124     FIB_TEST(!fib_test_validate_entry(fei,
9125                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9126                                       1,
9127                                       &adj_o_10_10_10_1),
9128              "%U via 10.10.10.1",
9129              format_fib_prefix, &pfx_10_10_10_16_s_28);
9130     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9131     FIB_TEST(!fib_test_validate_entry(fei,
9132                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9133                                       1,
9134                                       &adj_o_10_10_10_1),
9135              "%U via 10.10.10.1",
9136              format_fib_prefix, &pfx_10_10_10_21_s_32);
9137     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9138     FIB_TEST(!fib_test_validate_entry(fei,
9139                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9140                                       1,
9141                                       &adj_o_10_10_10_1),
9142              "%U via 10.10.10.1",
9143              format_fib_prefix, &pfx_10_10_10_22_s_32);
9144     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9145     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9146              "%U resolves via drop",
9147              format_fib_prefix, &pfx_10_10_10_255_s_32);
9148
9149     /*
9150      * remove the inherting cover - covereds go back to drop
9151      */
9152     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9153
9154     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9155     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9156              "%U resolves via drop",
9157              format_fib_prefix, &pfx_10_10_10_21_s_32);
9158
9159     /*
9160      * source an entry that pushes its state down the sub-tree
9161      */
9162     const fib_prefix_t pfx_10_10_10_0_s_24 = {
9163         .fp_len = 24,
9164         .fp_proto = FIB_PROTOCOL_IP4,
9165         .fp_addr = nh_10_10_10_0,
9166     };
9167     fib_table_entry_update_one_path(0,
9168                                     &pfx_10_10_10_0_s_24,
9169                                     FIB_SOURCE_API,
9170                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9171                                     DPO_PROTO_IP4,
9172                                     &nh_10_10_10_1,
9173                                     tm->hw[0]->sw_if_index,
9174                                     ~0,
9175                                     1,
9176                                     NULL,
9177                                     FIB_ROUTE_PATH_FLAG_NONE);
9178
9179     /*
9180      * whole sub-tree now covered
9181      */
9182     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9183     FIB_TEST(!fib_test_validate_entry(fei,
9184                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9185                                       1,
9186                                       &adj_o_10_10_10_1),
9187              "%U via 10.10.10.1",
9188              format_fib_prefix, &pfx_10_10_10_0_s_24);
9189     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9190     FIB_TEST(!fib_test_validate_entry(fei,
9191                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9192                                       1,
9193                                       &adj_o_10_10_10_1),
9194              "%U via 10.10.10.1",
9195              format_fib_prefix, &pfx_10_10_10_21_s_32);
9196     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9197     FIB_TEST(!fib_test_validate_entry(fei,
9198                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9199                                       1,
9200                                       &adj_o_10_10_10_1),
9201              "%U via 10.10.10.1",
9202              format_fib_prefix, &pfx_10_10_10_22_s_32);
9203     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9204     FIB_TEST(!fib_test_validate_entry(fei,
9205                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9206                                       1,
9207                                       &adj_o_10_10_10_1),
9208              "%U via 10.10.10.1",
9209              format_fib_prefix, &pfx_10_10_10_255_s_32);
9210
9211     /*
9212      * insert a more specific into the sub-tree - expect inheritance
9213      *  this one is directly covered by the root
9214      */
9215     fib_table_entry_special_add(0,
9216                                 &pfx_10_10_10_16_s_28,
9217                                 FIB_SOURCE_CLI,
9218                                 FIB_ENTRY_FLAG_DROP);
9219     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9220     FIB_TEST(!fib_test_validate_entry(fei,
9221                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9222                                       1,
9223                                       &adj_o_10_10_10_1),
9224              "%U via 10.10.10.1",
9225              format_fib_prefix, &pfx_10_10_10_16_s_28);
9226
9227     /*
9228      * insert a more specific into the sub-tree - expect inheritance
9229      *  this one is indirectly covered by the root
9230      */
9231     const fib_prefix_t pfx_10_10_10_20_s_30 = {
9232         .fp_len = 30,
9233         .fp_proto = FIB_PROTOCOL_IP4,
9234         .fp_addr = nh_10_10_10_20,
9235     };
9236     fib_table_entry_special_add(0,
9237                                 &pfx_10_10_10_20_s_30,
9238                                 FIB_SOURCE_CLI,
9239                                 FIB_ENTRY_FLAG_DROP);
9240     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9241     FIB_TEST(!fib_test_validate_entry(fei,
9242                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9243                                       1,
9244                                       &adj_o_10_10_10_1),
9245              "%U via 10.10.10.1",
9246              format_fib_prefix, &pfx_10_10_10_20_s_30);
9247
9248     /*
9249      * remove the prefix from the middle of the sub-tree
9250      *  the inherited source will be the only one remaining - expect
9251      *  it to be withdrawn and hence the prefix is removed.
9252      */
9253     fib_table_entry_special_remove(0,
9254                                    &pfx_10_10_10_20_s_30,
9255                                    FIB_SOURCE_CLI);
9256     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9257     FIB_TEST((FIB_NODE_INDEX_INVALID == fei),
9258              "%U gone",
9259              format_fib_prefix, &pfx_10_10_10_20_s_30);
9260
9261     /*
9262      * inheriting source is modifed - expect the modification to be present
9263      *  throughout the sub-tree
9264      */
9265     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9266                                                     VNET_LINK_IP4,
9267                                                     &nh_10_10_10_2,
9268                                                     tm->hw[0]->sw_if_index);
9269     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
9270         .type = FT_LB_ADJ,
9271         .adj = {
9272             .adj = ai_10_10_10_2,
9273         },
9274     };
9275
9276     fib_table_entry_update_one_path(0,
9277                                     &pfx_10_10_10_0_s_24,
9278                                     FIB_SOURCE_API,
9279                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9280                                     DPO_PROTO_IP4,
9281                                     &nh_10_10_10_2,
9282                                     tm->hw[0]->sw_if_index,
9283                                     ~0,
9284                                     1,
9285                                     NULL,
9286                                     FIB_ROUTE_PATH_FLAG_NONE);
9287     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9288     FIB_TEST(!fib_test_validate_entry(fei,
9289                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9290                                       1,
9291                                       &adj_o_10_10_10_2),
9292              "%U via 10.10.10.2",
9293              format_fib_prefix, &pfx_10_10_10_21_s_32);
9294     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9295     FIB_TEST(!fib_test_validate_entry(fei,
9296                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9297                                       1,
9298                                       &adj_o_10_10_10_2),
9299              "%U via 10.10.10.2",
9300              format_fib_prefix, &pfx_10_10_10_22_s_32);
9301     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9302     FIB_TEST(!fib_test_validate_entry(fei,
9303                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9304                                       1,
9305                                       &adj_o_10_10_10_2),
9306              "%U via 10.10.10.2",
9307              format_fib_prefix, &pfx_10_10_10_255_s_32);
9308     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9309     FIB_TEST(!fib_test_validate_entry(fei,
9310                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9311                                       1,
9312                                       &adj_o_10_10_10_2),
9313              "%U via 10.10.10.2",
9314              format_fib_prefix, &pfx_10_10_10_0_s_24);
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                                     FIB_SOURCE_PLUGIN_HI,
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, FIB_SOURCE_PLUGIN_HI);
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);