move [m]fib and BIER tests to unittest plugin
[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      * CLEANUP
4199      *    remove adj-fibs:
4200      */
4201     fib_table_entry_delete(fib_index,
4202                            &pfx_10_10_10_1_s_32,
4203                            FIB_SOURCE_ADJ);
4204     fib_table_entry_delete(fib_index,
4205                            &pfx_10_10_10_2_s_32,
4206                            FIB_SOURCE_ADJ);
4207     FIB_TEST(FIB_NODE_INDEX_INVALID ==
4208              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4209              "10.10.10.1/32 adj-fib removed");
4210     FIB_TEST(FIB_NODE_INDEX_INVALID ==
4211              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4212              "10.10.10.2/32 adj-fib removed");
4213
4214     /*
4215      * -2 entries and -2 non-shared path-list
4216      */
4217     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
4218              fib_path_list_db_size());
4219     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4220              fib_path_list_pool_size());
4221     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4222              fib_entry_pool_size());
4223
4224     /*
4225      * unlock the adjacencies for which this test provided a rewrite.
4226      * These are the last locks on these adjs. they should thus go away.
4227      */
4228     adj_unlock(ai_02);
4229     adj_unlock(ai_01);
4230     adj_unlock(ai_12_12_12_12);
4231
4232     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4233              adj_nbr_db_size());
4234
4235     /*
4236      * CLEANUP
4237      *   remove the interface prefixes
4238      */
4239     local_pfx.fp_len = 32;
4240     fib_table_entry_special_remove(fib_index, &local_pfx,
4241                                    FIB_SOURCE_INTERFACE);
4242     fei = fib_table_lookup(fib_index, &local_pfx);
4243
4244     FIB_TEST(FIB_NODE_INDEX_INVALID ==
4245              fib_table_lookup_exact_match(fib_index, &local_pfx),
4246              "10.10.10.10/32 adj-fib removed");
4247
4248     local_pfx.fp_len = 24;
4249     fib_table_entry_delete(fib_index, &local_pfx,
4250                            FIB_SOURCE_INTERFACE);
4251
4252     FIB_TEST(FIB_NODE_INDEX_INVALID ==
4253              fib_table_lookup_exact_match(fib_index, &local_pfx),
4254              "10.10.10.10/24 adj-fib removed");
4255
4256     /*
4257      * -2 entries and -2 non-shared path-list
4258      */
4259     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4260              fib_path_list_db_size());
4261     FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4262              fib_path_list_pool_size());
4263     FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4264              fib_entry_pool_size());
4265
4266     /*
4267      * Last but not least, remove the VRF
4268      */
4269     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4270                                              FIB_PROTOCOL_IP4,
4271                                              FIB_SOURCE_API)),
4272              "NO API Source'd prefixes");
4273     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4274                                              FIB_PROTOCOL_IP4,
4275                                              FIB_SOURCE_RR)),
4276              "NO RR Source'd prefixes");
4277     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4278                                              FIB_PROTOCOL_IP4,
4279                                              FIB_SOURCE_INTERFACE)),
4280              "NO INterface Source'd prefixes");
4281
4282     fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4283
4284     FIB_TEST((0  == fib_path_list_db_size()), "path list DB population:%d",
4285              fib_path_list_db_size());
4286     FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4287              fib_path_list_pool_size());
4288     FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4289              fib_entry_pool_size());
4290     FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4291              pool_elts(fib_urpf_list_pool));
4292     FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4293              pool_elts(load_balance_map_pool));
4294     FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4295              pool_elts(load_balance_pool));
4296     FIB_TEST((0 == pool_elts(dvr_dpo_pool)), "L2 DPO pool size is %d",
4297              pool_elts(dvr_dpo_pool));
4298
4299     return (res);
4300 }
4301
4302 static int
4303 fib_test_v6 (void)
4304 {
4305     /*
4306      * In the default table check for the presence and correct forwarding
4307      * of the special entries
4308      */
4309     fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4310     const dpo_id_t *dpo, *dpo_drop;
4311     const ip_adjacency_t *adj;
4312     const receive_dpo_t *rd;
4313     test_main_t *tm;
4314     u32 fib_index;
4315     int ii, res;
4316
4317     res = 0;
4318     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4319              adj_nbr_db_size());
4320
4321     /* via 2001:0:0:1::2 */
4322     ip46_address_t nh_2001_2 = {
4323         .ip6 = {
4324             .as_u64 = {
4325                 [0] = clib_host_to_net_u64(0x2001000000000001),
4326                 [1] = clib_host_to_net_u64(0x0000000000000002),
4327             },
4328         },
4329     };
4330
4331     tm = &test_main;
4332
4333     dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4334
4335     /* Find or create FIB table 11 */
4336     fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4337                                                   FIB_SOURCE_API);
4338
4339     for (ii = 0; ii < 4; ii++)
4340     {
4341         ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4342     }
4343
4344     fib_prefix_t pfx_0_0 = {
4345         .fp_len = 0,
4346         .fp_proto = FIB_PROTOCOL_IP6,
4347         .fp_addr = {
4348             .ip6 = {
4349                 {0, 0},
4350             },
4351         },
4352     };
4353
4354     dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4355     FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4356     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4357              "Default route is DROP");
4358
4359     dpo = fib_entry_contribute_ip_forwarding(dfrt);
4360     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4361                   &ip6_main,
4362                   1,
4363                   &pfx_0_0.fp_addr.ip6)),
4364              "default-route; fwd and non-fwd tables match");
4365
4366     // FIXME - check specials.
4367
4368     /*
4369      * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4370      * each with 2 entries and a v6 mfib with 4 path-lists.
4371      * All entries are special so no path-list sharing.
4372      */
4373 #define ENPS (5+4)
4374     u32 PNPS = (5+4+4);
4375     /*
4376      * if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
4377      */
4378     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
4379     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4380              fib_path_list_pool_size());
4381     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4382              fib_entry_pool_size());
4383
4384     /*
4385      * add interface routes.
4386      *  validate presence of /64 attached and /128 recieve.
4387      *  test for the presence of the receive address in the glean and local adj
4388      *
4389      * receive on 2001:0:0:1::1/128
4390      */
4391     fib_prefix_t local_pfx = {
4392         .fp_len = 64,
4393         .fp_proto = FIB_PROTOCOL_IP6,
4394         .fp_addr = {
4395             .ip6 = {
4396                 .as_u64 = {
4397                     [0] = clib_host_to_net_u64(0x2001000000000001),
4398                     [1] = clib_host_to_net_u64(0x0000000000000001),
4399                 },
4400             },
4401         }
4402     };
4403
4404     fib_table_entry_update_one_path(fib_index, &local_pfx,
4405                                     FIB_SOURCE_INTERFACE,
4406                                     (FIB_ENTRY_FLAG_CONNECTED |
4407                                      FIB_ENTRY_FLAG_ATTACHED),
4408                                     DPO_PROTO_IP6,
4409                                     NULL,
4410                                     tm->hw[0]->sw_if_index,
4411                                     ~0,
4412                                     1,
4413                                     NULL,
4414                                     FIB_ROUTE_PATH_FLAG_NONE);
4415     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4416
4417     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4418
4419     ai = fib_entry_get_adj(fei);
4420     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4421     adj = adj_get(ai);
4422     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4423              "attached interface adj is glean");
4424     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4425                                     &adj->sub_type.glean.receive_addr)),
4426              "attached interface adj is receive ok");
4427     dpo = fib_entry_contribute_ip_forwarding(fei);
4428     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4429                   &ip6_main,
4430                   1,
4431                   &local_pfx.fp_addr.ip6)),
4432              "attached-route; fwd and non-fwd tables match");
4433
4434     local_pfx.fp_len = 128;
4435     fib_table_entry_update_one_path(fib_index, &local_pfx,
4436                                     FIB_SOURCE_INTERFACE,
4437                                     (FIB_ENTRY_FLAG_CONNECTED |
4438                                      FIB_ENTRY_FLAG_LOCAL),
4439                                     DPO_PROTO_IP6,
4440                                     NULL,
4441                                     tm->hw[0]->sw_if_index,
4442                                     ~0, // invalid fib index
4443                                     1,
4444                                     NULL,
4445                                     FIB_ROUTE_PATH_FLAG_NONE);
4446     fei = fib_table_lookup(fib_index, &local_pfx);
4447
4448     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4449
4450     dpo = fib_entry_contribute_ip_forwarding(fei);
4451     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4452     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4453              "local interface adj is local");
4454     rd = receive_dpo_get(dpo->dpoi_index);
4455
4456     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4457                                     &rd->rd_addr)),
4458              "local interface adj is receive ok");
4459
4460     dpo = fib_entry_contribute_ip_forwarding(fei);
4461     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4462                   &ip6_main,
4463                   1,
4464                   &local_pfx.fp_addr.ip6)),
4465              "local-route; fwd and non-fwd tables match");
4466
4467     /*
4468      * +2 entries. +2 unshared path-lists
4469      */
4470     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
4471     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4472              fib_path_list_pool_size());
4473     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4474              fib_entry_pool_size());
4475
4476     /*
4477      * Modify the default route to be via an adj not yet known.
4478      * this sources the defalut route with the API source, which is
4479      * a higher preference to the DEFAULT_ROUTE source
4480      */
4481     fib_table_entry_path_add(fib_index, &pfx_0_0,
4482                              FIB_SOURCE_API,
4483                              FIB_ENTRY_FLAG_NONE,
4484                              DPO_PROTO_IP6,
4485                              &nh_2001_2,
4486                              tm->hw[0]->sw_if_index,
4487                              ~0,
4488                              1,
4489                              NULL,
4490                              FIB_ROUTE_PATH_FLAG_NONE);
4491     fei = fib_table_lookup(fib_index, &pfx_0_0);
4492
4493     FIB_TEST((fei == dfrt), "default route same index");
4494     ai = fib_entry_get_adj(fei);
4495     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4496     adj = adj_get(ai);
4497     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4498              "adj is incomplete");
4499     FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4500              "adj nbr next-hop ok");
4501
4502     /*
4503      * find the adj in the shared db
4504      */
4505     locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4506                                     VNET_LINK_IP6,
4507                                     &nh_2001_2,
4508                                     tm->hw[0]->sw_if_index);
4509     FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4510     adj_unlock(locked_ai);
4511
4512     /*
4513      * no more entires. +1 shared path-list
4514      */
4515     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4516              fib_path_list_db_size());
4517     FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4518              fib_path_list_pool_size());
4519     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4520              fib_entry_pool_size());
4521
4522     /*
4523      * remove the API source from the default route. We expected
4524      * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4525      */
4526     fib_table_entry_path_remove(fib_index, &pfx_0_0,
4527                                 FIB_SOURCE_API,
4528                                 DPO_PROTO_IP6,
4529                                 &nh_2001_2,
4530                                 tm->hw[0]->sw_if_index,
4531                                 ~0,
4532                                 1,
4533                                 FIB_ROUTE_PATH_FLAG_NONE);
4534     fei = fib_table_lookup(fib_index, &pfx_0_0);
4535
4536     FIB_TEST((fei == dfrt), "default route same index");
4537     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4538              "Default route is DROP");
4539
4540     /*
4541      * no more entires. -1 shared path-list
4542      */
4543     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4544              fib_path_list_db_size());
4545     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4546              fib_path_list_pool_size());
4547     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4548              fib_entry_pool_size());
4549
4550     /*
4551      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4552      */
4553     fib_prefix_t pfx_2001_1_2_s_128 = {
4554         .fp_len   = 128,
4555         .fp_proto = FIB_PROTOCOL_IP6,
4556         .fp_addr  = {
4557             .ip6 = {
4558                 .as_u64 = {
4559                     [0] = clib_host_to_net_u64(0x2001000000000001),
4560                     [1] = clib_host_to_net_u64(0x0000000000000002),
4561                 },
4562             },
4563         }
4564     };
4565     fib_prefix_t pfx_2001_1_3_s_128 = {
4566         .fp_len   = 128,
4567         .fp_proto = FIB_PROTOCOL_IP6,
4568         .fp_addr  = {
4569             .ip6 = {
4570                 .as_u64 = {
4571                     [0] = clib_host_to_net_u64(0x2001000000000001),
4572                     [1] = clib_host_to_net_u64(0x0000000000000003),
4573                 },
4574             },
4575         }
4576     };
4577     u8 eth_addr[] = {
4578         0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4579     };
4580
4581     ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4582                                 VNET_LINK_IP6,
4583                                 &pfx_2001_1_2_s_128.fp_addr,
4584                                 tm->hw[0]->sw_if_index);
4585     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4586     adj = adj_get(ai_01);
4587     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4588              "adj is incomplete");
4589     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4590                                     &adj->sub_type.nbr.next_hop)),
4591              "adj nbr next-hop ok");
4592
4593     adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4594                            fib_test_build_rewrite(eth_addr));
4595     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4596              "adj is complete");
4597     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4598                                     &adj->sub_type.nbr.next_hop)),
4599              "adj nbr next-hop ok");
4600
4601     fib_table_entry_path_add(fib_index,
4602                              &pfx_2001_1_2_s_128,
4603                              FIB_SOURCE_ADJ,
4604                              FIB_ENTRY_FLAG_ATTACHED,
4605                              DPO_PROTO_IP6,
4606                              &pfx_2001_1_2_s_128.fp_addr,
4607                              tm->hw[0]->sw_if_index,
4608                              ~0,
4609                              1,
4610                              NULL,
4611                              FIB_ROUTE_PATH_FLAG_NONE);
4612
4613     fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4614     ai = fib_entry_get_adj(fei);
4615     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4616
4617     eth_addr[5] = 0xb2;
4618
4619     ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4620                                 VNET_LINK_IP6,
4621                                 &pfx_2001_1_3_s_128.fp_addr,
4622                                 tm->hw[0]->sw_if_index);
4623     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4624     adj = adj_get(ai_02);
4625     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4626              "adj is incomplete");
4627     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4628                                     &adj->sub_type.nbr.next_hop)),
4629              "adj nbr next-hop ok");
4630
4631     adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4632                            fib_test_build_rewrite(eth_addr));
4633     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4634              "adj is complete");
4635     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4636                                     &adj->sub_type.nbr.next_hop)),
4637              "adj nbr next-hop ok");
4638     FIB_TEST((ai_01 != ai_02), "ADJs are different");
4639
4640     fib_table_entry_path_add(fib_index,
4641                              &pfx_2001_1_3_s_128,
4642                              FIB_SOURCE_ADJ,
4643                              FIB_ENTRY_FLAG_ATTACHED,
4644                              DPO_PROTO_IP6,
4645                              &pfx_2001_1_3_s_128.fp_addr,
4646                              tm->hw[0]->sw_if_index,
4647                              ~0,
4648                              1,
4649                              NULL,
4650                              FIB_ROUTE_PATH_FLAG_NONE);
4651
4652     fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4653     ai = fib_entry_get_adj(fei);
4654     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4655
4656     /*
4657      * +2 entries, +2 unshread path-lists.
4658      */
4659     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4660              fib_path_list_db_size());
4661     FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4662              fib_path_list_pool_size());
4663     FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4664              fib_entry_pool_size());
4665
4666     /*
4667      * Add a 2 routes via the first ADJ. ensure path-list sharing
4668      */
4669     fib_prefix_t pfx_2001_a_s_64 = {
4670         .fp_len   = 64,
4671         .fp_proto = FIB_PROTOCOL_IP6,
4672         .fp_addr  = {
4673             .ip6 = {
4674                 .as_u64 = {
4675                     [0] = clib_host_to_net_u64(0x200100000000000a),
4676                     [1] = clib_host_to_net_u64(0x0000000000000000),
4677                 },
4678             },
4679         }
4680     };
4681     fib_prefix_t pfx_2001_b_s_64 = {
4682         .fp_len   = 64,
4683         .fp_proto = FIB_PROTOCOL_IP6,
4684         .fp_addr  = {
4685             .ip6 = {
4686                 .as_u64 = {
4687                     [0] = clib_host_to_net_u64(0x200100000000000b),
4688                     [1] = clib_host_to_net_u64(0x0000000000000000),
4689                 },
4690             },
4691         }
4692     };
4693
4694     fib_table_entry_path_add(fib_index,
4695                              &pfx_2001_a_s_64,
4696                              FIB_SOURCE_API,
4697                              FIB_ENTRY_FLAG_NONE,
4698                              DPO_PROTO_IP6,
4699                              &nh_2001_2,
4700                              tm->hw[0]->sw_if_index,
4701                              ~0,
4702                              1,
4703                              NULL,
4704                              FIB_ROUTE_PATH_FLAG_NONE);
4705     fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4706     ai = fib_entry_get_adj(fei);
4707     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4708     fib_table_entry_path_add(fib_index,
4709                              &pfx_2001_b_s_64,
4710                              FIB_SOURCE_API,
4711                              FIB_ENTRY_FLAG_NONE,
4712                              DPO_PROTO_IP6,
4713                              &nh_2001_2,
4714                              tm->hw[0]->sw_if_index,
4715                              ~0,
4716                              1,
4717                              NULL,
4718                              FIB_ROUTE_PATH_FLAG_NONE);
4719     fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4720     ai = fib_entry_get_adj(fei);
4721     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4722
4723     /*
4724      * +2 entries, +1 shared path-list.
4725      */
4726     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4727              fib_path_list_db_size());
4728     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4729              fib_path_list_pool_size());
4730     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4731              fib_entry_pool_size());
4732
4733     /*
4734      * add a v4 prefix via a v6 next-hop
4735      */
4736     fib_prefix_t pfx_1_1_1_1_s_32 = {
4737         .fp_len = 32,
4738         .fp_proto = FIB_PROTOCOL_IP4,
4739         .fp_addr = {
4740             .ip4.as_u32 = 0x01010101,
4741         },
4742     };
4743     fei = fib_table_entry_path_add(0, // default table
4744                                    &pfx_1_1_1_1_s_32,
4745                                    FIB_SOURCE_API,
4746                                    FIB_ENTRY_FLAG_NONE,
4747                                    DPO_PROTO_IP6,
4748                                    &nh_2001_2,
4749                                    tm->hw[0]->sw_if_index,
4750                                    ~0,
4751                                    1,
4752                                    NULL,
4753                                    FIB_ROUTE_PATH_FLAG_NONE);
4754     FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4755              "1.1.1.1/32 o v6 route present");
4756     ai = fib_entry_get_adj(fei);
4757     adj = adj_get(ai);
4758     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4759              "1.1.1.1/32 via ARP-adj");
4760     FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4761              "1.1.1.1/32 ADJ-adj is link type v4");
4762     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4763              "1.1.1.1/32 ADJ-adj is NH proto v6");
4764     fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4765
4766     /*
4767      * An attached route
4768      */
4769     fib_prefix_t pfx_2001_c_s_64 = {
4770         .fp_len   = 64,
4771         .fp_proto = FIB_PROTOCOL_IP6,
4772         .fp_addr  = {
4773             .ip6 = {
4774                 .as_u64 = {
4775                     [0] = clib_host_to_net_u64(0x200100000000000c),
4776                     [1] = clib_host_to_net_u64(0x0000000000000000),
4777                 },
4778             },
4779         }
4780     };
4781     fib_table_entry_path_add(fib_index,
4782                              &pfx_2001_c_s_64,
4783                              FIB_SOURCE_CLI,
4784                              FIB_ENTRY_FLAG_ATTACHED,
4785                              DPO_PROTO_IP6,
4786                              NULL,
4787                              tm->hw[0]->sw_if_index,
4788                              ~0,
4789                              1,
4790                              NULL,
4791                              FIB_ROUTE_PATH_FLAG_NONE);
4792     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4793     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4794     ai = fib_entry_get_adj(fei);
4795     adj = adj_get(ai);
4796     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4797              "2001:0:0:c/64 attached resolves via glean");
4798
4799     fib_table_entry_path_remove(fib_index,
4800                                 &pfx_2001_c_s_64,
4801                                 FIB_SOURCE_CLI,
4802                                 DPO_PROTO_IP6,
4803                                 NULL,
4804                                 tm->hw[0]->sw_if_index,
4805                                 ~0,
4806                                 1,
4807                                 FIB_ROUTE_PATH_FLAG_NONE);
4808     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4809     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4810
4811     /*
4812      * Shutdown the interface on which we have a connected and through
4813      * which the routes are reachable.
4814      * This will result in the connected, adj-fibs, and routes linking to drop
4815      * The local/for-us prefix continues to receive.
4816      */
4817     clib_error_t * error;
4818
4819     error = vnet_sw_interface_set_flags(vnet_get_main(),
4820                                         tm->hw[0]->sw_if_index,
4821                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4822     FIB_TEST((NULL == error), "Interface shutdown OK");
4823
4824     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4825     dpo = fib_entry_contribute_ip_forwarding(fei);
4826     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4827              "2001::b/64 resolves via drop");
4828
4829     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4830     dpo = fib_entry_contribute_ip_forwarding(fei);
4831     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4832              "2001::a/64 resolves via drop");
4833     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4834     dpo = fib_entry_contribute_ip_forwarding(fei);
4835     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4836              "2001:0:0:1::3/64 resolves via drop");
4837     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4838     dpo = fib_entry_contribute_ip_forwarding(fei);
4839     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4840              "2001:0:0:1::2/64 resolves via drop");
4841     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4842     dpo = fib_entry_contribute_ip_forwarding(fei);
4843     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4844              "2001:0:0:1::1/128 not drop");
4845     local_pfx.fp_len = 64;
4846     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4847     dpo = fib_entry_contribute_ip_forwarding(fei);
4848     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4849              "2001:0:0:1/64 resolves via drop");
4850
4851     /*
4852      * no change
4853      */
4854     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4855              fib_path_list_db_size());
4856     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4857              fib_path_list_pool_size());
4858     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4859              fib_entry_pool_size());
4860
4861     /*
4862      * shutdown one of the other interfaces, then add a connected.
4863      * and swap one of the routes to it.
4864      */
4865     error = vnet_sw_interface_set_flags(vnet_get_main(),
4866                                         tm->hw[1]->sw_if_index,
4867                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4868     FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4869
4870     fib_prefix_t connected_pfx = {
4871         .fp_len = 64,
4872         .fp_proto = FIB_PROTOCOL_IP6,
4873         .fp_addr = {
4874             .ip6 = {
4875                 /* 2001:0:0:2::1/64 */
4876                 .as_u64 = {
4877                     [0] = clib_host_to_net_u64(0x2001000000000002),
4878                     [1] = clib_host_to_net_u64(0x0000000000000001),
4879                 },
4880             },
4881         }
4882     };
4883     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4884                                     FIB_SOURCE_INTERFACE,
4885                                     (FIB_ENTRY_FLAG_CONNECTED |
4886                                      FIB_ENTRY_FLAG_ATTACHED),
4887                                     DPO_PROTO_IP6,
4888                                     NULL,
4889                                     tm->hw[1]->sw_if_index,
4890                                     ~0,
4891                                     1,
4892                                     NULL,
4893                                     FIB_ROUTE_PATH_FLAG_NONE);
4894     fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4895     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4896     dpo = fib_entry_contribute_ip_forwarding(fei);
4897     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4898     FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4899              "2001:0:0:2/64 not resolves via drop");
4900
4901     connected_pfx.fp_len = 128;
4902     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4903                                     FIB_SOURCE_INTERFACE,
4904                                     (FIB_ENTRY_FLAG_CONNECTED |
4905                                      FIB_ENTRY_FLAG_LOCAL),
4906                                     DPO_PROTO_IP6,
4907                                     NULL,
4908                                     tm->hw[0]->sw_if_index,
4909                                     ~0, // invalid fib index
4910                                     1,
4911                                     NULL,
4912                                     FIB_ROUTE_PATH_FLAG_NONE);
4913     fei = fib_table_lookup(fib_index, &connected_pfx);
4914
4915     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4916     dpo = fib_entry_contribute_ip_forwarding(fei);
4917     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4918     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4919              "local interface adj is local");
4920     rd = receive_dpo_get(dpo->dpoi_index);
4921     FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4922                                     &rd->rd_addr)),
4923              "local interface adj is receive ok");
4924
4925     /*
4926      * +2 entries, +2 unshared path-lists
4927      */
4928     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4929              fib_path_list_db_size());
4930     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4931              fib_path_list_pool_size());
4932     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4933              fib_entry_pool_size());
4934
4935
4936     /*
4937      * bring the interface back up. we expected the routes to return
4938      * to normal forwarding.
4939      */
4940     error = vnet_sw_interface_set_flags(vnet_get_main(),
4941                                         tm->hw[0]->sw_if_index,
4942                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4943     FIB_TEST((NULL == error), "Interface bring-up OK");
4944     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4945     ai = fib_entry_get_adj(fei);
4946     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4947     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4948     ai = fib_entry_get_adj(fei);
4949     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4950     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4951     ai = fib_entry_get_adj(fei);
4952     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4953     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4954     ai = fib_entry_get_adj(fei);
4955     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4956     local_pfx.fp_len = 64;
4957     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4958     ai = fib_entry_get_adj(fei);
4959     adj = adj_get(ai);
4960     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4961              "attached interface adj is glean");
4962
4963     /*
4964      * Same test as above, but this time the HW interface goes down
4965      */
4966     error = vnet_hw_interface_set_flags(vnet_get_main(),
4967                                         tm->hw_if_indicies[0],
4968                                         ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4969     FIB_TEST((NULL == error), "Interface shutdown OK");
4970
4971     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4972     dpo = fib_entry_contribute_ip_forwarding(fei);
4973     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4974              "2001::b/64 resolves via drop");
4975     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4976     dpo = fib_entry_contribute_ip_forwarding(fei);
4977     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4978              "2001::a/64 resolves via drop");
4979     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4980     dpo = fib_entry_contribute_ip_forwarding(fei);
4981     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4982              "2001:0:0:1::3/128 resolves via drop");
4983     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4984     dpo = fib_entry_contribute_ip_forwarding(fei);
4985     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4986              "2001:0:0:1::2/128 resolves via drop");
4987     local_pfx.fp_len = 128;
4988     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4989     dpo = fib_entry_contribute_ip_forwarding(fei);
4990     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4991              "2001:0:0:1::1/128 not drop");
4992     local_pfx.fp_len = 64;
4993     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4994     dpo = fib_entry_contribute_ip_forwarding(fei);
4995     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4996              "2001:0:0:1/64 resolves via drop");
4997
4998     error = vnet_hw_interface_set_flags(vnet_get_main(),
4999                                         tm->hw_if_indicies[0],
5000                                         VNET_HW_INTERFACE_FLAG_LINK_UP);
5001     FIB_TEST((NULL == error), "Interface bring-up OK");
5002     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5003     ai = fib_entry_get_adj(fei);
5004     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
5005     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5006     ai = fib_entry_get_adj(fei);
5007     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
5008     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5009     ai = fib_entry_get_adj(fei);
5010     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
5011     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5012     ai = fib_entry_get_adj(fei);
5013     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
5014     local_pfx.fp_len = 64;
5015     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5016     ai = fib_entry_get_adj(fei);
5017     adj = adj_get(ai);
5018     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
5019              "attached interface adj is glean");
5020
5021     /*
5022      * Delete the interface that the routes reolve through.
5023      * Again no routes are removed. They all point to drop.
5024      *
5025      * This is considered an error case. The control plane should
5026      * not remove interfaces through which routes resolve, but
5027      * such things can happen. ALL affected routes will drop.
5028      */
5029     vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
5030
5031     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5032     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5033              "2001::b/64 resolves via drop");
5034     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5035     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5036              "2001::b/64 resolves via drop");
5037     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5038     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5039              "2001:0:0:1::3/64 resolves via drop");
5040     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5041     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5042              "2001:0:0:1::2/64 resolves via drop");
5043     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5044     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5045              "2001:0:0:1::1/128 is drop");
5046     local_pfx.fp_len = 64;
5047     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5048     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5049              "2001:0:0:1/64 resolves via drop");
5050
5051     /*
5052      * no change
5053      */
5054     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
5055              fib_path_list_db_size());
5056     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5057              fib_path_list_pool_size());
5058     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5059              fib_entry_pool_size());
5060
5061     /*
5062      * Add the interface back. routes stay unresolved.
5063      */
5064     error = ethernet_register_interface(vnet_get_main(),
5065                                         test_interface_device_class.index,
5066                                         0 /* instance */,
5067                                         hw_address,
5068                                         &tm->hw_if_indicies[0],
5069                                         /* flag change */ 0);
5070
5071     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5072     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5073              "2001::b/64 resolves via drop");
5074     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5075     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5076              "2001::b/64 resolves via drop");
5077     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5078     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5079              "2001:0:0:1::3/64 resolves via drop");
5080     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5081     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5082              "2001:0:0:1::2/64 resolves via drop");
5083     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5084     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5085              "2001:0:0:1::1/128 is drop");
5086     local_pfx.fp_len = 64;
5087     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5088     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5089              "2001:0:0:1/64 resolves via drop");
5090
5091     /*
5092      * CLEANUP ALL the routes
5093      */
5094     fib_table_entry_delete(fib_index,
5095                            &pfx_2001_c_s_64,
5096                            FIB_SOURCE_API);
5097     fib_table_entry_delete(fib_index,
5098                            &pfx_2001_a_s_64,
5099                            FIB_SOURCE_API);
5100     fib_table_entry_delete(fib_index,
5101                            &pfx_2001_b_s_64,
5102                            FIB_SOURCE_API);
5103     fib_table_entry_delete(fib_index,
5104                            &pfx_2001_1_3_s_128,
5105                            FIB_SOURCE_ADJ);
5106     fib_table_entry_delete(fib_index,
5107                            &pfx_2001_1_2_s_128,
5108                            FIB_SOURCE_ADJ);
5109     local_pfx.fp_len = 64;
5110     fib_table_entry_delete(fib_index, &local_pfx,
5111                            FIB_SOURCE_INTERFACE);
5112     local_pfx.fp_len = 128;
5113     fib_table_entry_special_remove(fib_index, &local_pfx,
5114                                    FIB_SOURCE_INTERFACE);
5115     connected_pfx.fp_len = 64;
5116     fib_table_entry_delete(fib_index, &connected_pfx,
5117                            FIB_SOURCE_INTERFACE);
5118     connected_pfx.fp_len = 128;
5119     fib_table_entry_special_remove(fib_index, &connected_pfx,
5120                                    FIB_SOURCE_INTERFACE);
5121
5122     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5123               fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5124              "2001::a/64 removed");
5125     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5126               fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5127              "2001::b/64 removed");
5128     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5129               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5130              "2001:0:0:1::3/128 removed");
5131     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5132               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5133              "2001:0:0:1::3/128 removed");
5134     local_pfx.fp_len = 64;
5135     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5136               fib_table_lookup_exact_match(fib_index, &local_pfx)),
5137              "2001:0:0:1/64 removed");
5138     local_pfx.fp_len = 128;
5139     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5140               fib_table_lookup_exact_match(fib_index, &local_pfx)),
5141              "2001:0:0:1::1/128 removed");
5142     connected_pfx.fp_len = 64;
5143     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5144               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5145              "2001:0:0:2/64 removed");
5146     connected_pfx.fp_len = 128;
5147     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5148               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5149              "2001:0:0:2::1/128 removed");
5150
5151     /*
5152      * -8 entries. -7 path-lists (1 was shared).
5153      */
5154     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
5155              fib_path_list_db_size());
5156     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5157              fib_path_list_pool_size());
5158     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5159              fib_entry_pool_size());
5160
5161     /*
5162      * now remove the VRF
5163      */
5164     fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5165
5166     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
5167              fib_path_list_db_size());
5168     FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5169              fib_path_list_pool_size());
5170     FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5171              fib_entry_pool_size());
5172
5173     adj_unlock(ai_02);
5174     adj_unlock(ai_01);
5175
5176     /*
5177      * return the interfaces to up state
5178      */
5179     error = vnet_sw_interface_set_flags(vnet_get_main(),
5180                                         tm->hw[0]->sw_if_index,
5181                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5182     error = vnet_sw_interface_set_flags(vnet_get_main(),
5183                                         tm->hw[1]->sw_if_index,
5184                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5185
5186     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5187              adj_nbr_db_size());
5188
5189     return (res);
5190 }
5191
5192 /*
5193  * Test Attached Exports
5194  */
5195 static int
5196 fib_test_ae (void)
5197 {
5198     const dpo_id_t *dpo, *dpo_drop;
5199     const u32 fib_index = 0;
5200     fib_node_index_t fei;
5201     test_main_t *tm;
5202     ip4_main_t *im;
5203     int res;
5204
5205     res = 0;
5206     tm = &test_main;
5207     im = &ip4_main;
5208
5209     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5210              adj_nbr_db_size());
5211
5212     /*
5213      * add interface routes. We'll assume this works. It's more rigorously
5214      * tested elsewhere.
5215      */
5216     fib_prefix_t local_pfx = {
5217         .fp_len = 24,
5218         .fp_proto = FIB_PROTOCOL_IP4,
5219         .fp_addr = {
5220             .ip4 = {
5221                 /* 10.10.10.10 */
5222                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5223             },
5224         },
5225     };
5226
5227     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5228     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5229
5230     dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5231
5232     fib_table_entry_update_one_path(fib_index, &local_pfx,
5233                                     FIB_SOURCE_INTERFACE,
5234                                     (FIB_ENTRY_FLAG_CONNECTED |
5235                                      FIB_ENTRY_FLAG_ATTACHED),
5236                                     DPO_PROTO_IP4,
5237                                     NULL,
5238                                     tm->hw[0]->sw_if_index,
5239                                     ~0,
5240                                     1,
5241                                     NULL,
5242                                     FIB_ROUTE_PATH_FLAG_NONE);
5243     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5244     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5245              "attached interface route present");
5246
5247     local_pfx.fp_len = 32;
5248     fib_table_entry_update_one_path(fib_index, &local_pfx,
5249                                     FIB_SOURCE_INTERFACE,
5250                                     (FIB_ENTRY_FLAG_CONNECTED |
5251                                      FIB_ENTRY_FLAG_LOCAL),
5252                                     DPO_PROTO_IP4,
5253                                     NULL,
5254                                     tm->hw[0]->sw_if_index,
5255                                     ~0, // invalid fib index
5256                                     1,
5257                                     NULL,
5258                                     FIB_ROUTE_PATH_FLAG_NONE);
5259     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5260
5261     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5262              "local interface route present");
5263
5264     /*
5265      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5266      */
5267     fib_prefix_t pfx_10_10_10_1_s_32 = {
5268         .fp_len = 32,
5269         .fp_proto = FIB_PROTOCOL_IP4,
5270         .fp_addr = {
5271             /* 10.10.10.1 */
5272             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5273         },
5274     };
5275     fib_node_index_t ai;
5276
5277     fib_table_entry_path_add(fib_index,
5278                              &pfx_10_10_10_1_s_32,
5279                              FIB_SOURCE_ADJ,
5280                              FIB_ENTRY_FLAG_ATTACHED,
5281                              DPO_PROTO_IP4,
5282                              &pfx_10_10_10_1_s_32.fp_addr,
5283                              tm->hw[0]->sw_if_index,
5284                              ~0, // invalid fib index
5285                              1,
5286                              NULL,
5287                              FIB_ROUTE_PATH_FLAG_NONE);
5288
5289     fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5290     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5291     ai = fib_entry_get_adj(fei);
5292
5293     /*
5294      * create another FIB table into which routes will be imported
5295      */
5296     u32 import_fib_index1;
5297
5298     import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5299                                                           11,
5300                                                           FIB_SOURCE_CLI);
5301
5302     /*
5303      * Add an attached route in the import FIB
5304      */
5305     local_pfx.fp_len = 24;
5306     fib_table_entry_update_one_path(import_fib_index1,
5307                                     &local_pfx,
5308                                     FIB_SOURCE_API,
5309                                     FIB_ENTRY_FLAG_NONE,
5310                                     DPO_PROTO_IP4,
5311                                     NULL,
5312                                     tm->hw[0]->sw_if_index,
5313                                     ~0, // invalid fib index
5314                                     1,
5315                                     NULL,
5316                                     FIB_ROUTE_PATH_FLAG_NONE);
5317     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5318     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5319
5320     /*
5321      * check for the presence of the adj-fibs in the import table
5322      */
5323     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5324     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5325     FIB_TEST((ai == fib_entry_get_adj(fei)),
5326              "adj-fib1 Import uses same adj as export");
5327
5328     /*
5329      * check for the presence of the local in the import table
5330      */
5331     local_pfx.fp_len = 32;
5332     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5333     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5334
5335     /*
5336      * Add another adj-fin in the export table. Expect this
5337      * to get magically exported;
5338      */
5339     fib_prefix_t pfx_10_10_10_2_s_32 = {
5340         .fp_len = 32,
5341         .fp_proto = FIB_PROTOCOL_IP4,
5342         .fp_addr = {
5343             /* 10.10.10.2 */
5344             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5345         },
5346     };
5347
5348     fib_table_entry_path_add(fib_index,
5349                              &pfx_10_10_10_2_s_32,
5350                              FIB_SOURCE_ADJ,
5351                              FIB_ENTRY_FLAG_ATTACHED,
5352                              DPO_PROTO_IP4,
5353                              &pfx_10_10_10_2_s_32.fp_addr,
5354                              tm->hw[0]->sw_if_index,
5355                              ~0, // invalid fib index
5356                              1,
5357                              NULL,
5358                              FIB_ROUTE_PATH_FLAG_NONE);
5359     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5360     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5361     ai = fib_entry_get_adj(fei);
5362
5363     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5364     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5365     FIB_TEST((ai == fib_entry_get_adj(fei)),
5366              "Import uses same adj as export");
5367     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5368              "ADJ-fib2 imported flags %d",
5369              fib_entry_get_flags(fei));
5370
5371     /*
5372      * create a 2nd FIB table into which routes will be imported
5373      */
5374     u32 import_fib_index2;
5375
5376     import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5377                                                           FIB_SOURCE_CLI);
5378
5379     /*
5380      * Add an attached route in the import FIB
5381      */
5382     local_pfx.fp_len = 24;
5383     fib_table_entry_update_one_path(import_fib_index2,
5384                                     &local_pfx,
5385                                     FIB_SOURCE_API,
5386                                     FIB_ENTRY_FLAG_NONE,
5387                                     DPO_PROTO_IP4,
5388                                     NULL,
5389                                     tm->hw[0]->sw_if_index,
5390                                     ~0, // invalid fib index
5391                                     1,
5392                                     NULL,
5393                                     FIB_ROUTE_PATH_FLAG_NONE);
5394     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5395     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5396
5397     /*
5398      * check for the presence of all the adj-fibs and local in the import table
5399      */
5400     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5401     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5402     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5403     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5404     local_pfx.fp_len = 32;
5405     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5406     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5407
5408     /*
5409      * add a 3rd adj-fib. expect it to be exported to both tables.
5410      */
5411     fib_prefix_t pfx_10_10_10_3_s_32 = {
5412         .fp_len = 32,
5413         .fp_proto = FIB_PROTOCOL_IP4,
5414         .fp_addr = {
5415             /* 10.10.10.3 */
5416             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5417         },
5418     };
5419
5420     fib_table_entry_path_add(fib_index,
5421                              &pfx_10_10_10_3_s_32,
5422                              FIB_SOURCE_ADJ,
5423                              FIB_ENTRY_FLAG_ATTACHED,
5424                              DPO_PROTO_IP4,
5425                              &pfx_10_10_10_3_s_32.fp_addr,
5426                              tm->hw[0]->sw_if_index,
5427                              ~0, // invalid fib index
5428                              1,
5429                              NULL,
5430                              FIB_ROUTE_PATH_FLAG_NONE);
5431     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5432     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5433     ai = fib_entry_get_adj(fei);
5434
5435     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5436     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5437     FIB_TEST((ai == fib_entry_get_adj(fei)),
5438              "Import uses same adj as export");
5439     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5440     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5441     FIB_TEST((ai == fib_entry_get_adj(fei)),
5442              "Import uses same adj as export");
5443
5444     /*
5445      * remove the 3rd adj fib. we expect it to be removed from both FIBs
5446      */
5447     fib_table_entry_delete(fib_index,
5448                            &pfx_10_10_10_3_s_32,
5449                            FIB_SOURCE_ADJ);
5450
5451     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5452     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5453
5454     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5455     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5456
5457     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5458     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5459
5460     /*
5461      * remove the attached route from the 2nd FIB. expect the imported
5462      * entires to be removed
5463      */
5464     local_pfx.fp_len = 24;
5465     fib_table_entry_delete(import_fib_index2,
5466                            &local_pfx,
5467                            FIB_SOURCE_API);
5468     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5469     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5470
5471     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5472     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5473     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5474     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5475     local_pfx.fp_len = 32;
5476     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5477     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5478
5479     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5480     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5481     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5482     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5483     local_pfx.fp_len = 32;
5484     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5485     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5486
5487     /*
5488      * modify the route in FIB1 so it is no longer attached. expect the imported
5489      * entires to be removed
5490      */
5491     local_pfx.fp_len = 24;
5492     fib_table_entry_update_one_path(import_fib_index1,
5493                                     &local_pfx,
5494                                     FIB_SOURCE_API,
5495                                     FIB_ENTRY_FLAG_NONE,
5496                                     DPO_PROTO_IP4,
5497                                     &pfx_10_10_10_2_s_32.fp_addr,
5498                                     tm->hw[0]->sw_if_index,
5499                                     ~0, // invalid fib index
5500                                     1,
5501                                     NULL,
5502                                     FIB_ROUTE_PATH_FLAG_NONE);
5503     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5504     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5505     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5506     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5507     local_pfx.fp_len = 32;
5508     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5509     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5510
5511     /*
5512      * modify it back to attached. expect the adj-fibs back
5513      */
5514     local_pfx.fp_len = 24;
5515     fib_table_entry_update_one_path(import_fib_index1,
5516                                     &local_pfx,
5517                                     FIB_SOURCE_API,
5518                                     FIB_ENTRY_FLAG_NONE,
5519                                     DPO_PROTO_IP4,
5520                                     NULL,
5521                                     tm->hw[0]->sw_if_index,
5522                                     ~0, // invalid fib index
5523                                     1,
5524                                     NULL,
5525                                     FIB_ROUTE_PATH_FLAG_NONE);
5526     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5527     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5528     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5529     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5530     local_pfx.fp_len = 32;
5531     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5532     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5533
5534     /*
5535      * add a covering attached next-hop for the interface address, so we have
5536      * a valid adj to find when we check the forwarding tables
5537      */
5538     fib_prefix_t pfx_10_0_0_0_s_8 = {
5539         .fp_len = 8,
5540         .fp_proto = FIB_PROTOCOL_IP4,
5541         .fp_addr = {
5542             /* 10.0.0.0 */
5543             .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5544         },
5545     };
5546
5547     fei = fib_table_entry_update_one_path(fib_index,
5548                                           &pfx_10_0_0_0_s_8,
5549                                           FIB_SOURCE_API,
5550                                           FIB_ENTRY_FLAG_NONE,
5551                                           DPO_PROTO_IP4,
5552                                           &pfx_10_10_10_3_s_32.fp_addr,
5553                                           tm->hw[0]->sw_if_index,
5554                                           ~0, // invalid fib index
5555                                           1,
5556                                           NULL,
5557                                           FIB_ROUTE_PATH_FLAG_NONE);
5558     dpo = fib_entry_contribute_ip_forwarding(fei);
5559
5560     /*
5561      * remove the route in the export fib. expect the adj-fibs to be removed
5562      */
5563     local_pfx.fp_len = 24;
5564     fib_table_entry_delete(fib_index,
5565                            &local_pfx,
5566                            FIB_SOURCE_INTERFACE);
5567
5568     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5569     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5570     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5571     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5572     local_pfx.fp_len = 32;
5573     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5574     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5575
5576     /*
5577      * the adj-fibs in the export VRF are present in the FIB table,
5578      * but not installed in forwarding, since they have no attached cover.
5579      * Consequently a lookup in the MTRIE gives the adj for the covering
5580      * route 10.0.0.0/8.
5581      */
5582     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5583     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5584
5585     index_t lbi;
5586     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5587     FIB_TEST(lbi == dpo->dpoi_index,
5588              "10.10.10.1 forwards on \n%U not \n%U",
5589              format_load_balance, lbi, 0,
5590              format_dpo_id, dpo, 0);
5591     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5592     FIB_TEST(lbi == dpo->dpoi_index,
5593              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5594     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5595     FIB_TEST(lbi == dpo->dpoi_index,
5596              "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5597
5598     /*
5599      * add the export prefix back, but not as attached.
5600      * No adj-fibs in export nor import tables
5601      */
5602     local_pfx.fp_len = 24;
5603     fei = fib_table_entry_update_one_path(fib_index,
5604                                           &local_pfx,
5605                                           FIB_SOURCE_API,
5606                                           FIB_ENTRY_FLAG_NONE,
5607                                           DPO_PROTO_IP4,
5608                                           &pfx_10_10_10_1_s_32.fp_addr,
5609                                           tm->hw[0]->sw_if_index,
5610                                           ~0, // invalid fib index
5611                                           1,
5612                                           NULL,
5613                                           FIB_ROUTE_PATH_FLAG_NONE);
5614     dpo = fib_entry_contribute_ip_forwarding(fei);
5615
5616     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5617     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5618     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5619     FIB_TEST(lbi == dpo->dpoi_index,
5620              "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5621     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5622     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5623     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5624     FIB_TEST(lbi == dpo->dpoi_index,
5625              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5626
5627     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5628     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5629     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5630     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5631     local_pfx.fp_len = 32;
5632     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5633     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5634
5635     /*
5636      * modify the export prefix so it is attached. expect all covereds to return
5637      */
5638     local_pfx.fp_len = 24;
5639     fib_table_entry_update_one_path(fib_index,
5640                                     &local_pfx,
5641                                     FIB_SOURCE_API,
5642                                     FIB_ENTRY_FLAG_NONE,
5643                                     DPO_PROTO_IP4,
5644                                     NULL,
5645                                     tm->hw[0]->sw_if_index,
5646                                     ~0, // invalid fib index
5647                                     1,
5648                                     NULL,
5649                                     FIB_ROUTE_PATH_FLAG_NONE);
5650
5651     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5652     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5653     dpo = fib_entry_contribute_ip_forwarding(fei);
5654     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5655              "Adj-fib1 is not drop in export");
5656     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5657     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5658     local_pfx.fp_len = 32;
5659     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5660     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5661     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5662     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5663     dpo = fib_entry_contribute_ip_forwarding(fei);
5664     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5665              "Adj-fib1 is not drop in export: %U %U",
5666              format_dpo_id, dpo, 0,
5667              format_dpo_id, load_balance_get_bucket(dpo->dpoi_index, 0), 0);
5668     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5669     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5670     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5671     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5672     local_pfx.fp_len = 32;
5673     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5674     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5675
5676     /*
5677      * modify the export prefix so connected. no change.
5678      */
5679     local_pfx.fp_len = 24;
5680     fib_table_entry_update_one_path(fib_index, &local_pfx,
5681                                     FIB_SOURCE_INTERFACE,
5682                                     (FIB_ENTRY_FLAG_CONNECTED |
5683                                      FIB_ENTRY_FLAG_ATTACHED),
5684                                     DPO_PROTO_IP4,
5685                                     NULL,
5686                                     tm->hw[0]->sw_if_index,
5687                                     ~0,
5688                                     1,
5689                                     NULL,
5690                                     FIB_ROUTE_PATH_FLAG_NONE);
5691
5692     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5693     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5694     dpo = fib_entry_contribute_ip_forwarding(fei);
5695     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5696              "Adj-fib1 is not drop in export");
5697     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5698     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5699     local_pfx.fp_len = 32;
5700     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5701     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
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), "attached in export: ADJ-fib1 imported");
5704     dpo = fib_entry_contribute_ip_forwarding(fei);
5705     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5706              "Adj-fib1 is not drop in export");
5707     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5708     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5709     local_pfx.fp_len = 32;
5710     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5711     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5712
5713     /*
5714      * CLEANUP
5715      */
5716     fib_table_entry_delete(fib_index,
5717                            &pfx_10_0_0_0_s_8,
5718                            FIB_SOURCE_API);
5719     fib_table_entry_delete(fib_index,
5720                            &pfx_10_10_10_1_s_32,
5721                            FIB_SOURCE_ADJ);
5722     fib_table_entry_delete(fib_index,
5723                            &pfx_10_10_10_2_s_32,
5724                            FIB_SOURCE_ADJ);
5725     local_pfx.fp_len = 32;
5726     fib_table_entry_delete(fib_index,
5727                            &local_pfx,
5728                            FIB_SOURCE_INTERFACE);
5729     local_pfx.fp_len = 24;
5730     fib_table_entry_delete(fib_index,
5731                            &local_pfx,
5732                            FIB_SOURCE_API);
5733     fib_table_entry_delete(fib_index,
5734                            &local_pfx,
5735                            FIB_SOURCE_INTERFACE);
5736     local_pfx.fp_len = 24;
5737     fib_table_entry_delete(import_fib_index1,
5738                            &local_pfx,
5739                            FIB_SOURCE_API);
5740
5741     fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5742     fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5743
5744     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5745              adj_nbr_db_size());
5746
5747     return (res);
5748 }
5749
5750 /*
5751  * Test Path Preference
5752  */
5753 static int
5754 fib_test_pref (void)
5755 {
5756     test_main_t *tm = &test_main;
5757     int res;
5758
5759     res = 0;
5760     const fib_prefix_t pfx_1_1_1_1_s_32 = {
5761         .fp_len = 32,
5762         .fp_proto = FIB_PROTOCOL_IP4,
5763         .fp_addr = {
5764             .ip4 = {
5765                 .as_u32 = clib_host_to_net_u32(0x01010101),
5766             },
5767         },
5768     };
5769
5770     /*
5771      * 2 high, 2 medium and 2 low preference non-recursive paths
5772      */
5773     fib_route_path_t nr_path_hi_1 = {
5774         .frp_proto = DPO_PROTO_IP4,
5775         .frp_sw_if_index = tm->hw[0]->sw_if_index,
5776         .frp_fib_index = ~0,
5777         .frp_weight = 1,
5778         .frp_preference = 0,
5779         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5780         .frp_addr = {
5781             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5782         },
5783     };
5784     fib_route_path_t nr_path_hi_2 = {
5785         .frp_proto = DPO_PROTO_IP4,
5786         .frp_sw_if_index = tm->hw[0]->sw_if_index,
5787         .frp_fib_index = ~0,
5788         .frp_weight = 1,
5789         .frp_preference = 0,
5790         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5791         .frp_addr = {
5792             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5793         },
5794     };
5795     fib_route_path_t nr_path_med_1 = {
5796         .frp_proto = DPO_PROTO_IP4,
5797         .frp_sw_if_index = tm->hw[1]->sw_if_index,
5798         .frp_fib_index = ~0,
5799         .frp_weight = 1,
5800         .frp_preference = 1,
5801         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5802         .frp_addr = {
5803             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5804         },
5805     };
5806     fib_route_path_t nr_path_med_2 = {
5807         .frp_proto = DPO_PROTO_IP4,
5808         .frp_sw_if_index = tm->hw[1]->sw_if_index,
5809         .frp_fib_index = ~0,
5810         .frp_weight = 1,
5811         .frp_preference = 1,
5812         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5813         .frp_addr = {
5814             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5815         },
5816     };
5817     fib_route_path_t nr_path_low_1 = {
5818         .frp_proto = DPO_PROTO_IP4,
5819         .frp_sw_if_index = tm->hw[2]->sw_if_index,
5820         .frp_fib_index = ~0,
5821         .frp_weight = 1,
5822         .frp_preference = 2,
5823         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5824         .frp_addr = {
5825             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5826         },
5827     };
5828     fib_route_path_t nr_path_low_2 = {
5829         .frp_proto = DPO_PROTO_IP4,
5830         .frp_sw_if_index = tm->hw[2]->sw_if_index,
5831         .frp_fib_index = ~0,
5832         .frp_weight = 1,
5833         .frp_preference = 2,
5834         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5835         .frp_addr = {
5836             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5837         },
5838     };
5839     fib_route_path_t *nr_paths = NULL;
5840
5841     vec_add1(nr_paths, nr_path_hi_1);
5842     vec_add1(nr_paths, nr_path_hi_2);
5843     vec_add1(nr_paths, nr_path_med_1);
5844     vec_add1(nr_paths, nr_path_med_2);
5845     vec_add1(nr_paths, nr_path_low_1);
5846     vec_add1(nr_paths, nr_path_low_2);
5847
5848     adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5849                                               VNET_LINK_IP4,
5850                                               &nr_path_hi_1.frp_addr,
5851                                               nr_path_hi_1.frp_sw_if_index);
5852     adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5853                                               VNET_LINK_IP4,
5854                                               &nr_path_hi_2.frp_addr,
5855                                               nr_path_hi_2.frp_sw_if_index);
5856     adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5857                                                VNET_LINK_IP4,
5858                                                &nr_path_med_1.frp_addr,
5859                                                nr_path_med_1.frp_sw_if_index);
5860     adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5861                                                VNET_LINK_IP4,
5862                                                &nr_path_med_2.frp_addr,
5863                                                nr_path_med_2.frp_sw_if_index);
5864     adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5865                                                VNET_LINK_IP4,
5866                                                &nr_path_low_1.frp_addr,
5867                                                nr_path_low_1.frp_sw_if_index);
5868     adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5869                                                VNET_LINK_IP4,
5870                                                &nr_path_low_2.frp_addr,
5871                                                nr_path_low_2.frp_sw_if_index);
5872
5873     fib_test_lb_bucket_t ip_hi_1 = {
5874         .type = FT_LB_ADJ,
5875         .adj = {
5876             .adj = ai_hi_1,
5877         },
5878     };
5879     fib_test_lb_bucket_t ip_hi_2 = {
5880         .type = FT_LB_ADJ,
5881         .adj = {
5882             .adj = ai_hi_2,
5883         },
5884     };
5885     fib_test_lb_bucket_t ip_med_1 = {
5886         .type = FT_LB_ADJ,
5887         .adj = {
5888             .adj = ai_med_1,
5889         },
5890     };
5891     fib_test_lb_bucket_t ip_med_2 = {
5892         .type = FT_LB_ADJ,
5893         .adj = {
5894             .adj = ai_med_2,
5895         },
5896     };
5897     fib_test_lb_bucket_t ip_low_1 = {
5898         .type = FT_LB_ADJ,
5899         .adj = {
5900             .adj = ai_low_1,
5901         },
5902     };
5903     fib_test_lb_bucket_t ip_low_2 = {
5904         .type = FT_LB_ADJ,
5905         .adj = {
5906             .adj = ai_low_2,
5907         },
5908     };
5909
5910     fib_node_index_t fei;
5911
5912     fei = fib_table_entry_path_add2(0,
5913                                     &pfx_1_1_1_1_s_32,
5914                                     FIB_SOURCE_API,
5915                                     FIB_ENTRY_FLAG_NONE,
5916                                     nr_paths);
5917
5918     FIB_TEST(!fib_test_validate_entry(fei,
5919                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5920                                       2,
5921                                       &ip_hi_1,
5922                                       &ip_hi_2),
5923              "1.1.1.1/32 via high preference paths");
5924
5925     /*
5926      * bring down the interface on which the high preference path lie
5927      */
5928     vnet_sw_interface_set_flags(vnet_get_main(),
5929                                 tm->hw[0]->sw_if_index,
5930                                 0);
5931
5932     FIB_TEST(!fib_test_validate_entry(fei,
5933                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5934                                       2,
5935                                       &ip_med_1,
5936                                       &ip_med_2),
5937              "1.1.1.1/32 via medium preference paths");
5938
5939     /*
5940      * bring down the interface on which the medium preference path lie
5941      */
5942     vnet_sw_interface_set_flags(vnet_get_main(),
5943                                 tm->hw[1]->sw_if_index,
5944                                 0);
5945
5946     FIB_TEST(!fib_test_validate_entry(fei,
5947                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5948                                       2,
5949                                       &ip_low_1,
5950                                       &ip_low_2),
5951              "1.1.1.1/32 via low preference paths");
5952
5953     /*
5954      * bring up the interface on which the high preference path lie
5955      */
5956     vnet_sw_interface_set_flags(vnet_get_main(),
5957                                 tm->hw[0]->sw_if_index,
5958                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5959
5960     FIB_TEST(!fib_test_validate_entry(fei,
5961                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5962                                       2,
5963                                       &ip_hi_1,
5964                                       &ip_hi_2),
5965              "1.1.1.1/32 via high preference paths");
5966
5967     /*
5968      * bring up the interface on which the medium preference path lie
5969      */
5970     vnet_sw_interface_set_flags(vnet_get_main(),
5971                                 tm->hw[1]->sw_if_index,
5972                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5973
5974     FIB_TEST(!fib_test_validate_entry(fei,
5975                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5976                                       2,
5977                                       &ip_hi_1,
5978                                       &ip_hi_2),
5979              "1.1.1.1/32 via high preference paths");
5980
5981     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5982     fib_entry_contribute_forwarding(fei,
5983                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5984                                     &ip_1_1_1_1);
5985
5986     /*
5987      * 3 recursive paths of different preference
5988      */
5989     const fib_prefix_t pfx_1_1_1_2_s_32 = {
5990         .fp_len = 32,
5991         .fp_proto = FIB_PROTOCOL_IP4,
5992         .fp_addr = {
5993             .ip4 = {
5994                 .as_u32 = clib_host_to_net_u32(0x01010102),
5995             },
5996         },
5997     };
5998     const fib_prefix_t pfx_1_1_1_3_s_32 = {
5999         .fp_len = 32,
6000         .fp_proto = FIB_PROTOCOL_IP4,
6001         .fp_addr = {
6002             .ip4 = {
6003                 .as_u32 = clib_host_to_net_u32(0x01010103),
6004             },
6005         },
6006     };
6007     fei = fib_table_entry_path_add2(0,
6008                                     &pfx_1_1_1_2_s_32,
6009                                     FIB_SOURCE_API,
6010                                     FIB_ENTRY_FLAG_NONE,
6011                                     nr_paths);
6012     dpo_id_t ip_1_1_1_2 = DPO_INVALID;
6013     fib_entry_contribute_forwarding(fei,
6014                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6015                                     &ip_1_1_1_2);
6016     fei = fib_table_entry_path_add2(0,
6017                                     &pfx_1_1_1_3_s_32,
6018                                     FIB_SOURCE_API,
6019                                     FIB_ENTRY_FLAG_NONE,
6020                                     nr_paths);
6021     dpo_id_t ip_1_1_1_3 = DPO_INVALID;
6022     fib_entry_contribute_forwarding(fei,
6023                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6024                                     &ip_1_1_1_3);
6025
6026     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6027         .type = FT_LB_O_LB,
6028         .lb = {
6029             .lb = ip_1_1_1_1.dpoi_index,
6030         },
6031     };
6032     fib_test_lb_bucket_t ip_o_1_1_1_2 = {
6033         .type = FT_LB_O_LB,
6034         .lb = {
6035             .lb = ip_1_1_1_2.dpoi_index,
6036         },
6037     };
6038     fib_test_lb_bucket_t ip_o_1_1_1_3 = {
6039         .type = FT_LB_O_LB,
6040         .lb = {
6041             .lb = ip_1_1_1_3.dpoi_index,
6042         },
6043     };
6044     fib_route_path_t r_path_hi = {
6045         .frp_proto = DPO_PROTO_IP4,
6046         .frp_sw_if_index = ~0,
6047         .frp_fib_index = 0,
6048         .frp_weight = 1,
6049         .frp_preference = 0,
6050         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6051         .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
6052     };
6053     fib_route_path_t r_path_med = {
6054         .frp_proto = DPO_PROTO_IP4,
6055         .frp_sw_if_index = ~0,
6056         .frp_fib_index = 0,
6057         .frp_weight = 1,
6058         .frp_preference = 10,
6059         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6060         .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
6061     };
6062     fib_route_path_t r_path_low = {
6063         .frp_proto = DPO_PROTO_IP4,
6064         .frp_sw_if_index = ~0,
6065         .frp_fib_index = 0,
6066         .frp_weight = 1,
6067         .frp_preference = 255,
6068         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6069         .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
6070     };
6071     fib_route_path_t *r_paths = NULL;
6072
6073     vec_add1(r_paths, r_path_hi);
6074     vec_add1(r_paths, r_path_low);
6075     vec_add1(r_paths, r_path_med);
6076
6077     /*
6078      * add many recursive so we get the LB MAp created
6079      */
6080 #define N_PFXS 64
6081     fib_prefix_t pfx_r[N_PFXS];
6082     unsigned int n_pfxs;
6083     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6084     {
6085         pfx_r[n_pfxs].fp_len = 32;
6086         pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
6087         pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
6088             clib_host_to_net_u32(0x02000000 + n_pfxs);
6089
6090         fei = fib_table_entry_path_add2(0,
6091                                         &pfx_r[n_pfxs],
6092                                         FIB_SOURCE_API,
6093                                         FIB_ENTRY_FLAG_NONE,
6094                                         r_paths);
6095
6096         FIB_TEST(!fib_test_validate_entry(fei,
6097                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6098                                           1,
6099                                           &ip_o_1_1_1_1),
6100                  "recursive via high preference paths");
6101
6102         /*
6103          * withdraw hig pref resolving entry
6104          */
6105         fib_table_entry_delete(0,
6106                                &pfx_1_1_1_1_s_32,
6107                                FIB_SOURCE_API);
6108
6109         /* suspend so the update walk kicks int */
6110         vlib_process_suspend(vlib_get_main(), 1e-5);
6111
6112         FIB_TEST(!fib_test_validate_entry(fei,
6113                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6114                                           1,
6115                                           &ip_o_1_1_1_2),
6116                  "recursive via medium preference paths");
6117
6118         /*
6119          * withdraw medium pref resolving entry
6120          */
6121         fib_table_entry_delete(0,
6122                                &pfx_1_1_1_2_s_32,
6123                                FIB_SOURCE_API);
6124
6125         /* suspend so the update walk kicks int */
6126         vlib_process_suspend(vlib_get_main(), 1e-5);
6127
6128         FIB_TEST(!fib_test_validate_entry(fei,
6129                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6130                                           1,
6131                                           &ip_o_1_1_1_3),
6132                  "recursive via low preference paths");
6133
6134         /*
6135          * add back paths for next iteration
6136          */
6137         fei = fib_table_entry_update(0,
6138                                      &pfx_1_1_1_2_s_32,
6139                                      FIB_SOURCE_API,
6140                                      FIB_ENTRY_FLAG_NONE,
6141                                      nr_paths);
6142         fei = fib_table_entry_update(0,
6143                                      &pfx_1_1_1_1_s_32,
6144                                      FIB_SOURCE_API,
6145                                      FIB_ENTRY_FLAG_NONE,
6146                                      nr_paths);
6147
6148         /* suspend so the update walk kicks int */
6149         vlib_process_suspend(vlib_get_main(), 1e-5);
6150
6151         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6152         FIB_TEST(!fib_test_validate_entry(fei,
6153                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6154                                           1,
6155                                           &ip_o_1_1_1_1),
6156                  "recursive via high preference paths");
6157     }
6158
6159
6160     fib_table_entry_delete(0,
6161                            &pfx_1_1_1_1_s_32,
6162                            FIB_SOURCE_API);
6163
6164     /* suspend so the update walk kicks int */
6165     vlib_process_suspend(vlib_get_main(), 1e-5);
6166
6167     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6168     {
6169         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6170
6171         FIB_TEST(!fib_test_validate_entry(fei,
6172                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6173                                           1,
6174                                           &ip_o_1_1_1_2),
6175                  "recursive via medium preference paths");
6176     }
6177     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6178     {
6179         fib_table_entry_delete(0,
6180                                &pfx_r[n_pfxs],
6181                                FIB_SOURCE_API);
6182     }
6183
6184     /*
6185      * Cleanup
6186      */
6187     fib_table_entry_delete(0,
6188                            &pfx_1_1_1_2_s_32,
6189                            FIB_SOURCE_API);
6190     fib_table_entry_delete(0,
6191                            &pfx_1_1_1_3_s_32,
6192                            FIB_SOURCE_API);
6193
6194     dpo_reset(&ip_1_1_1_1);
6195     dpo_reset(&ip_1_1_1_2);
6196     dpo_reset(&ip_1_1_1_3);
6197     adj_unlock(ai_low_2);
6198     adj_unlock(ai_low_1);
6199     adj_unlock(ai_med_2);
6200     adj_unlock(ai_med_1);
6201     adj_unlock(ai_hi_2);
6202     adj_unlock(ai_hi_1);
6203
6204     return (res);
6205 }
6206
6207 /*
6208  * Test the recursive route route handling for GRE tunnels
6209  */
6210 static int
6211 fib_test_label (void)
6212 {
6213     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;
6214     const u32 fib_index = 0;
6215     int lb_count, ii, res;
6216     test_main_t *tm;
6217     ip4_main_t *im;
6218
6219     res = 0;
6220     lb_count = pool_elts(load_balance_pool);
6221     tm = &test_main;
6222     im = &ip4_main;
6223
6224     /*
6225      * add interface routes. We'll assume this works. It's more rigorously
6226      * tested elsewhere.
6227      */
6228     fib_prefix_t local0_pfx = {
6229         .fp_len = 24,
6230         .fp_proto = FIB_PROTOCOL_IP4,
6231         .fp_addr = {
6232             .ip4 = {
6233                 /* 10.10.10.10 */
6234                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6235             },
6236         },
6237     };
6238
6239     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6240              adj_nbr_db_size());
6241
6242     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6243     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6244
6245     fib_table_entry_update_one_path(fib_index, &local0_pfx,
6246                                     FIB_SOURCE_INTERFACE,
6247                                     (FIB_ENTRY_FLAG_CONNECTED |
6248                                      FIB_ENTRY_FLAG_ATTACHED),
6249                                     DPO_PROTO_IP4,
6250                                     NULL,
6251                                     tm->hw[0]->sw_if_index,
6252                                     ~0,
6253                                     1,
6254                                     NULL,
6255                                     FIB_ROUTE_PATH_FLAG_NONE);
6256     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6257     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6258              "attached interface route present");
6259
6260     local0_pfx.fp_len = 32;
6261     fib_table_entry_update_one_path(fib_index, &local0_pfx,
6262                                     FIB_SOURCE_INTERFACE,
6263                                     (FIB_ENTRY_FLAG_CONNECTED |
6264                                      FIB_ENTRY_FLAG_LOCAL),
6265                                     DPO_PROTO_IP4,
6266                                     NULL,
6267                                     tm->hw[0]->sw_if_index,
6268                                     ~0, // invalid fib index
6269                                     1,
6270                                     NULL,
6271                                     FIB_ROUTE_PATH_FLAG_NONE);
6272     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6273
6274     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6275              "local interface route present");
6276
6277     fib_prefix_t local1_pfx = {
6278         .fp_len = 24,
6279         .fp_proto = FIB_PROTOCOL_IP4,
6280         .fp_addr = {
6281             .ip4 = {
6282                 /* 10.10.11.10 */
6283                 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6284             },
6285         },
6286     };
6287
6288     vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6289     im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6290
6291     fib_table_entry_update_one_path(fib_index, &local1_pfx,
6292                                     FIB_SOURCE_INTERFACE,
6293                                     (FIB_ENTRY_FLAG_CONNECTED |
6294                                      FIB_ENTRY_FLAG_ATTACHED),
6295                                     DPO_PROTO_IP4,
6296                                     NULL,
6297                                     tm->hw[1]->sw_if_index,
6298                                     ~0,
6299                                     1,
6300                                     NULL,
6301                                     FIB_ROUTE_PATH_FLAG_NONE);
6302     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6303     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6304              "attached interface route present");
6305
6306     local1_pfx.fp_len = 32;
6307     fib_table_entry_update_one_path(fib_index, &local1_pfx,
6308                                     FIB_SOURCE_INTERFACE,
6309                                     (FIB_ENTRY_FLAG_CONNECTED |
6310                                      FIB_ENTRY_FLAG_LOCAL),
6311                                     DPO_PROTO_IP4,
6312                                     NULL,
6313                                     tm->hw[1]->sw_if_index,
6314                                     ~0, // invalid fib index
6315                                     1,
6316                                     NULL,
6317                                     FIB_ROUTE_PATH_FLAG_NONE);
6318     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6319
6320     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6321              "local interface route present");
6322
6323     ip46_address_t nh_10_10_10_1 = {
6324         .ip4 = {
6325             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6326         },
6327     };
6328     ip46_address_t nh_10_10_11_1 = {
6329         .ip4 = {
6330             .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6331         },
6332     };
6333     ip46_address_t nh_10_10_11_2 = {
6334         .ip4 = {
6335             .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6336         },
6337     };
6338
6339     ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6340                                            VNET_LINK_IP4,
6341                                            &nh_10_10_11_1,
6342                                            tm->hw[1]->sw_if_index);
6343     ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6344                                            VNET_LINK_IP4,
6345                                            &nh_10_10_11_2,
6346                                            tm->hw[1]->sw_if_index);
6347     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6348                                              VNET_LINK_MPLS,
6349                                              &nh_10_10_10_1,
6350                                              tm->hw[0]->sw_if_index);
6351     ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6352                                              VNET_LINK_MPLS,
6353                                              &nh_10_10_11_2,
6354                                              tm->hw[1]->sw_if_index);
6355     ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6356                                              VNET_LINK_MPLS,
6357                                              &nh_10_10_11_1,
6358                                              tm->hw[1]->sw_if_index);
6359
6360     /*
6361      * Add an etry with one path with a real out-going label
6362      */
6363     fib_prefix_t pfx_1_1_1_1_s_32 = {
6364         .fp_len = 32,
6365         .fp_proto = FIB_PROTOCOL_IP4,
6366         .fp_addr = {
6367             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6368         },
6369     };
6370     fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6371         .type = FT_LB_LABEL_O_ADJ,
6372         .label_o_adj = {
6373             .adj = ai_mpls_10_10_10_1,
6374             .label = 99,
6375             .eos = MPLS_EOS,
6376         },
6377     };
6378     fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6379         .type = FT_LB_LABEL_O_ADJ,
6380         .label_o_adj = {
6381             .adj = ai_mpls_10_10_10_1,
6382             .label = 99,
6383             .eos = MPLS_NON_EOS,
6384         },
6385     };
6386     fib_mpls_label_t *l99 = NULL, fml99 = {
6387         .fml_value = 99,
6388     };
6389     vec_add1(l99, fml99);
6390
6391     fib_table_entry_update_one_path(fib_index,
6392                                     &pfx_1_1_1_1_s_32,
6393                                     FIB_SOURCE_API,
6394                                     FIB_ENTRY_FLAG_NONE,
6395                                     DPO_PROTO_IP4,
6396                                     &nh_10_10_10_1,
6397                                     tm->hw[0]->sw_if_index,
6398                                     ~0, // invalid fib index
6399                                     1,
6400                                     l99,
6401                                     FIB_ROUTE_PATH_FLAG_NONE);
6402
6403     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6404     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6405
6406     FIB_TEST(!fib_test_validate_entry(fei,
6407                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6408                                       1,
6409                                       &l99_eos_o_10_10_10_1),
6410              "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6411
6412     /*
6413      * add a path with an implicit NULL label
6414      */
6415     fib_test_lb_bucket_t a_o_10_10_11_1 = {
6416         .type = FT_LB_ADJ,
6417         .adj = {
6418             .adj = ai_v4_10_10_11_1,
6419         },
6420     };
6421     fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6422         .type = FT_LB_ADJ,
6423         .adj = {
6424             .adj = ai_mpls_10_10_11_1,
6425         },
6426     };
6427     fib_mpls_label_t *l_imp_null = NULL, fml_imp_null = {
6428         .fml_value =  MPLS_IETF_IMPLICIT_NULL_LABEL,
6429     };
6430     vec_add1(l_imp_null, fml_imp_null);
6431
6432     fei = fib_table_entry_path_add(fib_index,
6433                                    &pfx_1_1_1_1_s_32,
6434                                    FIB_SOURCE_API,
6435                                    FIB_ENTRY_FLAG_NONE,
6436                                    DPO_PROTO_IP4,
6437                                    &nh_10_10_11_1,
6438                                    tm->hw[1]->sw_if_index,
6439                                    ~0, // invalid fib index
6440                                    1,
6441                                    l_imp_null,
6442                                    FIB_ROUTE_PATH_FLAG_NONE);
6443
6444     FIB_TEST(!fib_test_validate_entry(fei,
6445                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6446                                       2,
6447                                       &l99_eos_o_10_10_10_1,
6448                                       &a_o_10_10_11_1),
6449              "1.1.1.1/32 LB 2 buckets via: "
6450              "label 99 over 10.10.10.1, "
6451              "adj over 10.10.11.1");
6452
6453     /*
6454      * assign the route a local label
6455      */
6456     fib_table_entry_local_label_add(fib_index,
6457                                     &pfx_1_1_1_1_s_32,
6458                                     24001);
6459
6460     fib_prefix_t pfx_24001_eos = {
6461         .fp_proto = FIB_PROTOCOL_MPLS,
6462         .fp_label = 24001,
6463         .fp_eos = MPLS_EOS,
6464     };
6465     fib_prefix_t pfx_24001_neos = {
6466         .fp_proto = FIB_PROTOCOL_MPLS,
6467         .fp_label = 24001,
6468         .fp_eos = MPLS_NON_EOS,
6469     };
6470     fib_test_lb_bucket_t disp_o_10_10_11_1 = {
6471         .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6472         .adj = {
6473             .adj = ai_v4_10_10_11_1,
6474         },
6475     };
6476
6477     /*
6478      * The EOS entry should link to both the paths,
6479      *  and use an ip adj for the imp-null
6480      * The NON-EOS entry should link to both the paths,
6481      *  and use an mpls adj for the imp-null
6482      */
6483     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6484                            &pfx_24001_eos);
6485     FIB_TEST(!fib_test_validate_entry(fei,
6486                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6487                                       2,
6488                                       &l99_eos_o_10_10_10_1,
6489                                       &disp_o_10_10_11_1),
6490              "24001/eos LB 2 buckets via: "
6491              "label 99 over 10.10.10.1, "
6492              "mpls disp adj over 10.10.11.1");
6493
6494
6495     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6496                            &pfx_24001_neos);
6497     FIB_TEST(!fib_test_validate_entry(fei,
6498                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6499                                       2,
6500                                       &l99_neos_o_10_10_10_1,
6501                                       &a_mpls_o_10_10_11_1),
6502              "24001/neos LB 1 bucket via: "
6503              "label 99 over 10.10.10.1 ",
6504              "mpls-adj via 10.10.11.1");
6505
6506     /*
6507      * add an unlabelled path, this is excluded from the neos chains,
6508      */
6509     fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6510         .type = FT_LB_ADJ,
6511         .adj = {
6512             .adj = ai_v4_10_10_11_2,
6513         },
6514     };
6515     fib_test_lb_bucket_t disp_o_10_10_11_2 = {
6516         .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6517         .adj = {
6518             .adj = ai_v4_10_10_11_2,
6519         },
6520     };
6521
6522
6523     fei = fib_table_entry_path_add(fib_index,
6524                                    &pfx_1_1_1_1_s_32,
6525                                    FIB_SOURCE_API,
6526                                    FIB_ENTRY_FLAG_NONE,
6527                                    DPO_PROTO_IP4,
6528                                    &nh_10_10_11_2,
6529                                    tm->hw[1]->sw_if_index,
6530                                    ~0, // invalid fib index
6531                                    1,
6532                                    NULL,
6533                                    FIB_ROUTE_PATH_FLAG_NONE);
6534
6535     FIB_TEST(!fib_test_validate_entry(fei,
6536                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6537                                       16, // 3 choices spread over 16 buckets
6538                                       &l99_eos_o_10_10_10_1,
6539                                       &l99_eos_o_10_10_10_1,
6540                                       &l99_eos_o_10_10_10_1,
6541                                       &l99_eos_o_10_10_10_1,
6542                                       &l99_eos_o_10_10_10_1,
6543                                       &l99_eos_o_10_10_10_1,
6544                                       &a_o_10_10_11_1,
6545                                       &a_o_10_10_11_1,
6546                                       &a_o_10_10_11_1,
6547                                       &a_o_10_10_11_1,
6548                                       &a_o_10_10_11_1,
6549                                       &adj_o_10_10_11_2,
6550                                       &adj_o_10_10_11_2,
6551                                       &adj_o_10_10_11_2,
6552                                       &adj_o_10_10_11_2,
6553                                       &adj_o_10_10_11_2),
6554              "1.1.1.1/32 LB 16 buckets via: "
6555              "label 99 over 10.10.10.1, "
6556              "adj over 10.10.11.1",
6557              "adj over 10.10.11.2");
6558
6559     /*
6560      * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6561      */
6562     dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6563     fib_entry_contribute_forwarding(fei,
6564                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6565                                     &non_eos_1_1_1_1);
6566
6567     /*
6568      * n-eos has only the 2 labelled paths
6569      */
6570     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6571                            &pfx_24001_neos);
6572
6573     FIB_TEST(!fib_test_validate_entry(fei,
6574                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6575                                       2,
6576                                       &l99_neos_o_10_10_10_1,
6577                                       &a_mpls_o_10_10_11_1),
6578              "24001/neos LB 2 buckets via: "
6579              "label 99 over 10.10.10.1, "
6580              "adj-mpls over 10.10.11.2");
6581
6582     /*
6583      * A labelled recursive
6584      */
6585     fib_prefix_t pfx_2_2_2_2_s_32 = {
6586         .fp_len = 32,
6587         .fp_proto = FIB_PROTOCOL_IP4,
6588         .fp_addr = {
6589             .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6590         },
6591     };
6592     fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6593         .type = FT_LB_LABEL_O_LB,
6594         .label_o_lb = {
6595             .lb = non_eos_1_1_1_1.dpoi_index,
6596             .label = 1600,
6597             .eos = MPLS_EOS,
6598             .mode = FIB_MPLS_LSP_MODE_UNIFORM,
6599         },
6600     };
6601     fib_mpls_label_t *l1600 = NULL, fml1600 = {
6602         .fml_value = 1600,
6603         .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
6604     };
6605     vec_add1(l1600, fml1600);
6606
6607     fei = fib_table_entry_update_one_path(fib_index,
6608                                           &pfx_2_2_2_2_s_32,
6609                                           FIB_SOURCE_API,
6610                                           FIB_ENTRY_FLAG_NONE,
6611                                           DPO_PROTO_IP4,
6612                                           &pfx_1_1_1_1_s_32.fp_addr,
6613                                           ~0,
6614                                           fib_index,
6615                                           1,
6616                                           l1600,
6617                                           FIB_ROUTE_PATH_FLAG_NONE);
6618
6619     FIB_TEST(!fib_test_validate_entry(fei, 
6620                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6621                                       1,
6622                                       &l1600_eos_o_1_1_1_1),
6623              "2.2.2.2.2/32 LB 1 buckets via: "
6624              "label 1600 over 1.1.1.1");
6625
6626     dpo_id_t dpo_44 = DPO_INVALID;
6627     index_t urpfi;
6628
6629     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6630     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6631
6632     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6633              "uRPF check for 2.2.2.2/32 on %d OK",
6634              tm->hw[0]->sw_if_index);
6635     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6636              "uRPF check for 2.2.2.2/32 on %d OK",
6637              tm->hw[1]->sw_if_index);
6638     FIB_TEST(!fib_urpf_check(urpfi, 99),
6639              "uRPF check for 2.2.2.2/32 on 99 not-OK",
6640              99);
6641
6642     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6643     FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6644              "Shared uRPF on IP and non-EOS chain");
6645
6646     dpo_reset(&dpo_44);
6647
6648     /*
6649      * we are holding a lock on the non-eos LB of the via-entry.
6650      * do a PIC-core failover by shutting the link of the via-entry.
6651      *
6652      * shut down the link with the valid label
6653      */
6654     vnet_sw_interface_set_flags(vnet_get_main(),
6655                                 tm->hw[0]->sw_if_index,
6656                                 0);
6657
6658     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6659     FIB_TEST(!fib_test_validate_entry(fei,
6660                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6661                                       2,
6662                                       &a_o_10_10_11_1,
6663                                       &adj_o_10_10_11_2),
6664              "1.1.1.1/32 LB 2 buckets via: "
6665              "adj over 10.10.11.1, ",
6666              "adj-v4 over 10.10.11.2");
6667
6668     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6669                            &pfx_24001_eos);
6670     FIB_TEST(!fib_test_validate_entry(fei,
6671                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6672                                       2,
6673                                       &disp_o_10_10_11_1,
6674                                       &disp_o_10_10_11_2),
6675              "24001/eos LB 2 buckets via: "
6676              "mpls-disp adj over 10.10.11.1, ",
6677              "mpls-disp adj-v4 over 10.10.11.2");
6678
6679     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6680                            &pfx_24001_neos);
6681     FIB_TEST(!fib_test_validate_entry(fei,
6682                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6683                                       1,
6684                                       &a_mpls_o_10_10_11_1),
6685              "24001/neos LB 1 buckets via: "
6686              "adj-mpls over 10.10.11.2");
6687
6688     /*
6689      * test that the pre-failover load-balance has been in-place
6690      * modified
6691      */
6692     dpo_id_t current = DPO_INVALID;
6693     fib_entry_contribute_forwarding(fei,
6694                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6695                                     &current);
6696
6697     FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6698                       &current),
6699              "PIC-core LB inplace modified %U %U",
6700              format_dpo_id, &non_eos_1_1_1_1, 0,
6701              format_dpo_id, &current, 0);
6702
6703     dpo_reset(&non_eos_1_1_1_1);
6704     dpo_reset(&current);
6705
6706     /*
6707      * no-shut the link with the valid label
6708      */
6709     vnet_sw_interface_set_flags(vnet_get_main(),
6710                                 tm->hw[0]->sw_if_index,
6711                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6712
6713     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6714     FIB_TEST(!fib_test_validate_entry(fei,
6715                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6716                                       16, // 3 choices spread over 16 buckets
6717                                       &l99_eos_o_10_10_10_1,
6718                                       &l99_eos_o_10_10_10_1,
6719                                       &l99_eos_o_10_10_10_1,
6720                                       &l99_eos_o_10_10_10_1,
6721                                       &l99_eos_o_10_10_10_1,
6722                                       &l99_eos_o_10_10_10_1,
6723                                       &a_o_10_10_11_1,
6724                                       &a_o_10_10_11_1,
6725                                       &a_o_10_10_11_1,
6726                                       &a_o_10_10_11_1,
6727                                       &a_o_10_10_11_1,
6728                                       &adj_o_10_10_11_2,
6729                                       &adj_o_10_10_11_2,
6730                                       &adj_o_10_10_11_2,
6731                                       &adj_o_10_10_11_2,
6732                                       &adj_o_10_10_11_2),
6733              "1.1.1.1/32 LB 16 buckets via: "
6734              "label 99 over 10.10.10.1, "
6735              "adj over 10.10.11.1",
6736              "adj-v4 over 10.10.11.2");
6737
6738
6739     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6740                            &pfx_24001_eos);
6741     FIB_TEST(!fib_test_validate_entry(fei,
6742                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6743                                       16, // 3 choices spread over 16 buckets
6744                                       &l99_eos_o_10_10_10_1,
6745                                       &l99_eos_o_10_10_10_1,
6746                                       &l99_eos_o_10_10_10_1,
6747                                       &l99_eos_o_10_10_10_1,
6748                                       &l99_eos_o_10_10_10_1,
6749                                       &l99_eos_o_10_10_10_1,
6750                                       &disp_o_10_10_11_1,
6751                                       &disp_o_10_10_11_1,
6752                                       &disp_o_10_10_11_1,
6753                                       &disp_o_10_10_11_1,
6754                                       &disp_o_10_10_11_1,
6755                                       &disp_o_10_10_11_2,
6756                                       &disp_o_10_10_11_2,
6757                                       &disp_o_10_10_11_2,
6758                                       &disp_o_10_10_11_2,
6759                                       &disp_o_10_10_11_2),
6760              "24001/eos LB 16 buckets via: "
6761              "label 99 over 10.10.10.1, "
6762              "MPLS disp adj over 10.10.11.1",
6763              "MPLS disp adj-v4 over 10.10.11.2");
6764
6765     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6766                            &pfx_24001_neos);
6767     FIB_TEST(!fib_test_validate_entry(fei,
6768                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6769                                       2,
6770                                       &l99_neos_o_10_10_10_1,
6771                                       &a_mpls_o_10_10_11_1),
6772              "24001/neos LB 2 buckets via: "
6773              "label 99 over 10.10.10.1, "
6774              "adj-mpls over 10.10.11.2");
6775
6776     /*
6777      * remove the first path with the valid label
6778      */
6779     fib_table_entry_path_remove(fib_index,
6780                                 &pfx_1_1_1_1_s_32,
6781                                 FIB_SOURCE_API,
6782                                 DPO_PROTO_IP4,
6783                                 &nh_10_10_10_1,
6784                                 tm->hw[0]->sw_if_index,
6785                                 ~0, // invalid fib index
6786                                 1,
6787                                 FIB_ROUTE_PATH_FLAG_NONE);
6788
6789     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6790     FIB_TEST(!fib_test_validate_entry(fei,
6791                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6792                                       2,
6793                                       &a_o_10_10_11_1,
6794                                       &adj_o_10_10_11_2),
6795              "1.1.1.1/32 LB 2 buckets via: "
6796              "adj over 10.10.11.1, "
6797              "adj-v4 over 10.10.11.2");
6798
6799     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6800                            &pfx_24001_eos);
6801     FIB_TEST(!fib_test_validate_entry(fei,
6802                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6803                                       2,
6804                                       &disp_o_10_10_11_1,
6805                                       &disp_o_10_10_11_2),
6806              "24001/eos LB 2 buckets via: "
6807              "MPLS disp adj over 10.10.11.1, "
6808              "MPLS disp adj-v4 over 10.10.11.2");
6809
6810     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6811                            &pfx_24001_neos);
6812
6813     FIB_TEST(!fib_test_validate_entry(fei,
6814                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6815                                       1,
6816                                       &a_mpls_o_10_10_11_1),
6817              "24001/neos LB 1 buckets via: "
6818              "adj-mpls over 10.10.11.2");
6819
6820     /*
6821      * remove the other path with a valid label
6822      */
6823     fib_test_lb_bucket_t bucket_drop = {
6824         .type = FT_LB_DROP,
6825     };
6826     fib_test_lb_bucket_t mpls_bucket_drop = {
6827         .type = FT_LB_DROP,
6828         .special = {
6829             .adj = DPO_PROTO_MPLS,
6830         },
6831     };
6832
6833     fib_table_entry_path_remove(fib_index,
6834                                 &pfx_1_1_1_1_s_32,
6835                                 FIB_SOURCE_API,
6836                                 DPO_PROTO_IP4,
6837                                 &nh_10_10_11_1,
6838                                 tm->hw[1]->sw_if_index,
6839                                 ~0, // invalid fib index
6840                                 1,
6841                                 FIB_ROUTE_PATH_FLAG_NONE);
6842
6843     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6844     FIB_TEST(!fib_test_validate_entry(fei,
6845                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6846                                       1,
6847                                       &adj_o_10_10_11_2),
6848              "1.1.1.1/32 LB 1 buckets via: "
6849              "adj over 10.10.11.2");
6850
6851     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6852                            &pfx_24001_eos);
6853     FIB_TEST(!fib_test_validate_entry(fei,
6854                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6855                                       1,
6856                                       &disp_o_10_10_11_2),
6857              "24001/eos LB 1 buckets via: "
6858              "MPLS disp adj over 10.10.11.2");
6859
6860     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6861                            &pfx_24001_neos);
6862     FIB_TEST(!fib_test_validate_entry(fei,
6863                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6864                                       1,
6865                                       &mpls_bucket_drop),
6866              "24001/neos LB 1 buckets via: DROP");
6867
6868     /*
6869      * add back the path with the valid label
6870      */
6871     l99 = NULL;
6872     vec_add1(l99, fml99);
6873
6874     fib_table_entry_path_add(fib_index,
6875                              &pfx_1_1_1_1_s_32,
6876                              FIB_SOURCE_API,
6877                              FIB_ENTRY_FLAG_NONE,
6878                              DPO_PROTO_IP4,
6879                              &nh_10_10_10_1,
6880                              tm->hw[0]->sw_if_index,
6881                              ~0, // invalid fib index
6882                              1,
6883                              l99,
6884                              FIB_ROUTE_PATH_FLAG_NONE);
6885
6886     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6887     FIB_TEST(!fib_test_validate_entry(fei,
6888                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6889                                       2,
6890                                       &l99_eos_o_10_10_10_1,
6891                                       &adj_o_10_10_11_2),
6892              "1.1.1.1/32 LB 2 buckets via: "
6893              "label 99 over 10.10.10.1, "
6894              "adj over 10.10.11.2");
6895
6896     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6897                            &pfx_24001_eos);
6898     FIB_TEST(!fib_test_validate_entry(fei,
6899                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6900                                       2,
6901                                       &l99_eos_o_10_10_10_1,
6902                                       &disp_o_10_10_11_2),
6903              "24001/eos LB 2 buckets via: "
6904              "label 99 over 10.10.10.1, "
6905              "MPLS disp adj over 10.10.11.2");
6906
6907     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6908                            &pfx_24001_neos);
6909     FIB_TEST(!fib_test_validate_entry(fei,
6910                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6911                                       1,
6912                                       &l99_neos_o_10_10_10_1),
6913              "24001/neos LB 1 buckets via: "
6914              "label 99 over 10.10.10.1");
6915
6916     /*
6917      * change the local label
6918      */
6919     fib_table_entry_local_label_add(fib_index,
6920                                     &pfx_1_1_1_1_s_32,
6921                                     25005);
6922
6923     fib_prefix_t pfx_25005_eos = {
6924         .fp_proto = FIB_PROTOCOL_MPLS,
6925         .fp_label = 25005,
6926         .fp_eos = MPLS_EOS,
6927     };
6928     fib_prefix_t pfx_25005_neos = {
6929         .fp_proto = FIB_PROTOCOL_MPLS,
6930         .fp_label = 25005,
6931         .fp_eos = MPLS_NON_EOS,
6932     };
6933
6934     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6935               fib_table_lookup(fib_index, &pfx_24001_eos)),
6936              "24001/eos removed after label change");
6937     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6938               fib_table_lookup(fib_index, &pfx_24001_neos)),
6939              "24001/eos removed after label change");
6940
6941     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6942                            &pfx_25005_eos);
6943     FIB_TEST(!fib_test_validate_entry(fei,
6944                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6945                                       2,
6946                                       &l99_eos_o_10_10_10_1,
6947                                       &disp_o_10_10_11_2),
6948              "25005/eos LB 2 buckets via: "
6949              "label 99 over 10.10.10.1, "
6950              "MPLS disp adj over 10.10.11.2");
6951
6952     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6953                            &pfx_25005_neos);
6954     FIB_TEST(!fib_test_validate_entry(fei,
6955                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6956                                       1,
6957                                       &l99_neos_o_10_10_10_1),
6958              "25005/neos LB 1 buckets via: "
6959              "label 99 over 10.10.10.1");
6960
6961     /*
6962      * remove the local label.
6963      * the check that the MPLS entries are gone is done by the fact the
6964      * MPLS table is no longer present.
6965      */
6966     fib_table_entry_local_label_remove(fib_index,
6967                                        &pfx_1_1_1_1_s_32,
6968                                        25005);
6969
6970     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6971     FIB_TEST(!fib_test_validate_entry(fei,
6972                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6973                                       2,
6974                                       &l99_eos_o_10_10_10_1,
6975                                       &adj_o_10_10_11_2),
6976              "24001/eos LB 2 buckets via: "
6977              "label 99 over 10.10.10.1, "
6978              "adj over 10.10.11.2");
6979
6980     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6981               mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6982              "No more MPLS FIB entries => table removed");
6983
6984     /*
6985      * add another via-entry for the recursive
6986      */
6987     fib_prefix_t pfx_1_1_1_2_s_32 = {
6988         .fp_len = 32,
6989         .fp_proto = FIB_PROTOCOL_IP4,
6990         .fp_addr = {
6991             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6992         },
6993     };
6994     fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6995         .type = FT_LB_LABEL_O_ADJ,
6996         .label_o_adj = {
6997             .adj = ai_mpls_10_10_10_1,
6998             .label = 101,
6999             .eos = MPLS_EOS,
7000         },
7001     };
7002     fib_mpls_label_t *l101 = NULL, fml101 = {
7003         .fml_value = 101,
7004     };
7005     vec_add1(l101, fml101);
7006
7007     fei = fib_table_entry_update_one_path(fib_index,
7008                                           &pfx_1_1_1_2_s_32,
7009                                           FIB_SOURCE_API,
7010                                           FIB_ENTRY_FLAG_NONE,
7011                                           DPO_PROTO_IP4,
7012                                           &nh_10_10_10_1,
7013                                           tm->hw[0]->sw_if_index,
7014                                           ~0, // invalid fib index
7015                                           1,
7016                                           l101,
7017                                           FIB_ROUTE_PATH_FLAG_NONE);
7018
7019     FIB_TEST(!fib_test_validate_entry(fei,
7020                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7021                                       1,
7022                                       &l101_eos_o_10_10_10_1),
7023              "1.1.1.2/32 LB 1 buckets via: "
7024              "label 101 over 10.10.10.1");
7025
7026     dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
7027     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7028                                                      &pfx_1_1_1_1_s_32),
7029                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7030                                     &non_eos_1_1_1_1);
7031     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7032                                                      &pfx_1_1_1_2_s_32),
7033                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7034                                     &non_eos_1_1_1_2);
7035
7036     fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
7037         .type = FT_LB_LABEL_O_LB,
7038         .label_o_lb = {
7039             .lb = non_eos_1_1_1_2.dpoi_index,
7040             .label = 1601,
7041             .eos = MPLS_EOS,
7042         },
7043     };
7044     fib_mpls_label_t *l1601 = NULL, fml1601 = {
7045         .fml_value = 1601,
7046     };
7047     vec_add1(l1601, fml1601);
7048
7049     l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
7050
7051     fei = fib_table_entry_path_add(fib_index,
7052                                    &pfx_2_2_2_2_s_32,
7053                                    FIB_SOURCE_API,
7054                                    FIB_ENTRY_FLAG_NONE,
7055                                    DPO_PROTO_IP4,
7056                                    &pfx_1_1_1_2_s_32.fp_addr,
7057                                    ~0,
7058                                    fib_index,
7059                                    1,
7060                                    l1601,
7061                                    FIB_ROUTE_PATH_FLAG_NONE);
7062
7063     FIB_TEST(!fib_test_validate_entry(fei,
7064                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7065                                       2,
7066                                       &l1600_eos_o_1_1_1_1,
7067                                       &l1601_eos_o_1_1_1_2),
7068              "2.2.2.2/32 LB 2 buckets via: "
7069              "label 1600 via 1.1,1.1, "
7070              "label 16001 via 1.1.1.2");
7071
7072     /*
7073      * update the via-entry so it no longer has an imp-null path.
7074      * the LB for the recursive can use an imp-null
7075      */
7076     l_imp_null = NULL;
7077     vec_add1(l_imp_null, fml_imp_null);
7078
7079     fei = fib_table_entry_update_one_path(fib_index,
7080                                           &pfx_1_1_1_2_s_32,
7081                                           FIB_SOURCE_API,
7082                                           FIB_ENTRY_FLAG_NONE,
7083                                           DPO_PROTO_IP4,
7084                                           &nh_10_10_11_1,
7085                                           tm->hw[1]->sw_if_index,
7086                                           ~0, // invalid fib index
7087                                           1,
7088                                           l_imp_null,
7089                                           FIB_ROUTE_PATH_FLAG_NONE);
7090
7091     FIB_TEST(!fib_test_validate_entry(fei,
7092                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7093                                       1,
7094                                       &a_o_10_10_11_1),
7095              "1.1.1.2/32 LB 1 buckets via: "
7096              "adj 10.10.11.1");
7097
7098     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7099     FIB_TEST(!fib_test_validate_entry(fei,
7100                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7101                                       2,
7102                                       &l1600_eos_o_1_1_1_1,
7103                                       &l1601_eos_o_1_1_1_2),
7104              "2.2.2.2/32 LB 2 buckets via: "
7105              "label 1600 via 1.1,1.1, "
7106              "label 16001 via 1.1.1.2");
7107
7108     /*
7109      * update the via-entry so it no longer has labelled paths.
7110      * the LB for the recursive should exclue this via form its LB
7111      */
7112     fei = fib_table_entry_update_one_path(fib_index,
7113                                           &pfx_1_1_1_2_s_32,
7114                                           FIB_SOURCE_API,
7115                                           FIB_ENTRY_FLAG_NONE,
7116                                           DPO_PROTO_IP4,
7117                                           &nh_10_10_11_1,
7118                                           tm->hw[1]->sw_if_index,
7119                                           ~0, // invalid fib index
7120                                           1,
7121                                           NULL,
7122                                           FIB_ROUTE_PATH_FLAG_NONE);
7123
7124     FIB_TEST(!fib_test_validate_entry(fei,
7125                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7126                                       1,
7127                                       &a_o_10_10_11_1),
7128              "1.1.1.2/32 LB 1 buckets via: "
7129              "adj 10.10.11.1");
7130
7131     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7132     FIB_TEST(!fib_test_validate_entry(fei,
7133                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7134                                       1,
7135                                       &l1600_eos_o_1_1_1_1),
7136              "2.2.2.2/32 LB 1 buckets via: "
7137              "label 1600 via 1.1,1.1");
7138
7139     dpo_reset(&non_eos_1_1_1_1);
7140     dpo_reset(&non_eos_1_1_1_2);
7141
7142     /*
7143      * Add a recursive with no out-labels. We expect to use the IP of the via
7144      */
7145     fib_prefix_t pfx_2_2_2_3_s_32 = {
7146         .fp_len = 32,
7147         .fp_proto = FIB_PROTOCOL_IP4,
7148         .fp_addr = {
7149             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7150         },
7151     };
7152     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7153
7154     fib_table_entry_update_one_path(fib_index,
7155                                     &pfx_2_2_2_3_s_32,
7156                                     FIB_SOURCE_API,
7157                                     FIB_ENTRY_FLAG_NONE,
7158                                     DPO_PROTO_IP4,
7159                                     &pfx_1_1_1_1_s_32.fp_addr,
7160                                     ~0,
7161                                     fib_index,
7162                                     1,
7163                                     NULL,
7164                                     FIB_ROUTE_PATH_FLAG_NONE);
7165
7166     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7167                                                      &pfx_1_1_1_1_s_32),
7168                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7169                                     &ip_1_1_1_1);
7170
7171     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7172         .type = FT_LB_O_LB,
7173         .lb = {
7174             .lb = ip_1_1_1_1.dpoi_index,
7175         },
7176     };
7177
7178     fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7179     FIB_TEST(!fib_test_validate_entry(fei,
7180                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7181                                       1,
7182                                       &ip_o_1_1_1_1),
7183              "2.2.2.2.3/32 LB 1 buckets via: "
7184              "ip 1.1.1.1");
7185
7186     /*
7187      * Add a recursive with an imp-null out-label.
7188      * We expect to use the IP of the via
7189      */
7190     fib_prefix_t pfx_2_2_2_4_s_32 = {
7191         .fp_len = 32,
7192         .fp_proto = FIB_PROTOCOL_IP4,
7193         .fp_addr = {
7194             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7195         },
7196     };
7197
7198     fib_table_entry_update_one_path(fib_index,
7199                                     &pfx_2_2_2_4_s_32,
7200                                     FIB_SOURCE_API,
7201                                     FIB_ENTRY_FLAG_NONE,
7202                                     DPO_PROTO_IP4,
7203                                     &pfx_1_1_1_1_s_32.fp_addr,
7204                                     ~0,
7205                                     fib_index,
7206                                     1,
7207                                     NULL,
7208                                     FIB_ROUTE_PATH_FLAG_NONE);
7209
7210     fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7211     FIB_TEST(!fib_test_validate_entry(fei,
7212                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7213                                       1,
7214                                       &ip_o_1_1_1_1),
7215              "2.2.2.2.4/32 LB 1 buckets via: "
7216              "ip 1.1.1.1");
7217
7218     dpo_reset(&ip_1_1_1_1);
7219
7220     /*
7221      * Create an entry with a deep label stack
7222      */
7223     fib_prefix_t pfx_2_2_5_5_s_32 = {
7224         .fp_len = 32,
7225         .fp_proto = FIB_PROTOCOL_IP4,
7226         .fp_addr = {
7227             .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7228         },
7229     };
7230     fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7231         .type = FT_LB_LABEL_STACK_O_ADJ,
7232         .label_stack_o_adj = {
7233             .adj = ai_mpls_10_10_11_1,
7234             .label_stack_size = 8,
7235             .label_stack = {
7236                 200, 201, 202, 203, 204, 205, 206, 207
7237             },
7238             .eos = MPLS_EOS,
7239         },
7240     };
7241     fib_mpls_label_t *label_stack = NULL;
7242     vec_validate(label_stack, 7);
7243     for (ii = 0; ii < 8; ii++)
7244     {
7245         label_stack[ii].fml_value = ii + 200;
7246     }
7247
7248     fei = fib_table_entry_update_one_path(fib_index,
7249                                           &pfx_2_2_5_5_s_32,
7250                                           FIB_SOURCE_API,
7251                                           FIB_ENTRY_FLAG_NONE,
7252                                           DPO_PROTO_IP4,
7253                                           &nh_10_10_11_1,
7254                                           tm->hw[1]->sw_if_index,
7255                                           ~0, // invalid fib index
7256                                           1,
7257                                           label_stack,
7258                                           FIB_ROUTE_PATH_FLAG_NONE);
7259
7260     FIB_TEST(!fib_test_validate_entry(fei,
7261                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7262                                       1,
7263                                       &ls_eos_o_10_10_10_1),
7264              "2.2.5.5/32 LB 1 buckets via: "
7265              "adj 10.10.11.1");
7266     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7267
7268     /*
7269      * cleanup
7270      */
7271     fib_table_entry_delete(fib_index,
7272                            &pfx_1_1_1_2_s_32,
7273                            FIB_SOURCE_API);
7274
7275     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7276     FIB_TEST(!fib_test_validate_entry(fei,
7277                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7278                                       1,
7279                                       &l1600_eos_o_1_1_1_1),
7280              "2.2.2.2/32 LB 1 buckets via: "
7281              "label 1600 via 1.1,1.1");
7282
7283     fib_table_entry_delete(fib_index,
7284                            &pfx_1_1_1_1_s_32,
7285                            FIB_SOURCE_API);
7286
7287     FIB_TEST(!fib_test_validate_entry(fei,
7288                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7289                                       1,
7290                                       &bucket_drop),
7291              "2.2.2.2/32 LB 1 buckets via: DROP");
7292
7293     fib_table_entry_delete(fib_index,
7294                            &pfx_2_2_2_2_s_32,
7295                            FIB_SOURCE_API);
7296     fib_table_entry_delete(fib_index,
7297                            &pfx_2_2_2_3_s_32,
7298                            FIB_SOURCE_API);
7299     fib_table_entry_delete(fib_index,
7300                            &pfx_2_2_2_4_s_32,
7301                            FIB_SOURCE_API);
7302
7303     adj_unlock(ai_mpls_10_10_10_1);
7304     adj_unlock(ai_mpls_10_10_11_2);
7305     adj_unlock(ai_v4_10_10_11_1);
7306     adj_unlock(ai_v4_10_10_11_2);
7307     adj_unlock(ai_mpls_10_10_11_1);
7308
7309     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7310              adj_nbr_db_size());
7311
7312     local0_pfx.fp_len = 32;
7313     fib_table_entry_delete(fib_index,
7314                            &local0_pfx,
7315                            FIB_SOURCE_INTERFACE);
7316     local0_pfx.fp_len = 24;
7317     fib_table_entry_delete(fib_index,
7318                            &local0_pfx,
7319                            FIB_SOURCE_INTERFACE);
7320     local1_pfx.fp_len = 32;
7321     fib_table_entry_delete(fib_index,
7322                            &local1_pfx,
7323                            FIB_SOURCE_INTERFACE);
7324     local1_pfx.fp_len = 24;
7325     fib_table_entry_delete(fib_index,
7326                            &local1_pfx,
7327                            FIB_SOURCE_INTERFACE);
7328
7329     /*
7330      * +1 for the drop LB in the MPLS tables.
7331      */
7332     FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7333              "Load-balance resources freed %d of %d",
7334              lb_count+1, pool_elts(load_balance_pool));
7335
7336     return (res);
7337 }
7338
7339 #define N_TEST_CHILDREN 4
7340 #define PARENT_INDEX 0
7341
7342 typedef struct fib_node_test_t_
7343 {
7344     fib_node_t node;
7345     u32 sibling;
7346     u32 index;
7347     fib_node_back_walk_ctx_t *ctxs;
7348     u32 destroyed;
7349 } fib_node_test_t;
7350
7351 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7352
7353 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7354
7355 #define FOR_EACH_TEST_CHILD(_tc)                \
7356     for (ii = 1, (_tc) = &fib_test_nodes[1];    \
7357          ii < N_TEST_CHILDREN+1;                \
7358          ii++, (_tc) = &fib_test_nodes[ii])
7359
7360 static fib_node_t *
7361 fib_test_child_get_node (fib_node_index_t index)
7362 {
7363     return (&fib_test_nodes[index].node);
7364 }
7365
7366 static int fib_test_walk_spawns_walks;
7367
7368 static fib_node_back_walk_rc_t
7369 fib_test_child_back_walk_notify (fib_node_t *node,
7370                                  fib_node_back_walk_ctx_t *ctx)
7371 {
7372     fib_node_test_t *tc = (fib_node_test_t*) node;
7373
7374     vec_add1(tc->ctxs, *ctx);
7375
7376     if (1 == fib_test_walk_spawns_walks)
7377         fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7378     if (2 == fib_test_walk_spawns_walks)
7379         fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7380                        FIB_WALK_PRIORITY_HIGH, ctx);
7381
7382     return (FIB_NODE_BACK_WALK_CONTINUE);
7383 }
7384
7385 static void
7386 fib_test_child_last_lock_gone (fib_node_t *node)
7387 {
7388     fib_node_test_t *tc = (fib_node_test_t *)node;
7389
7390     tc->destroyed = 1;
7391 }
7392
7393 /**
7394  * The FIB walk's graph node virtual function table
7395  */
7396 static const fib_node_vft_t fib_test_child_vft = {
7397     .fnv_get = fib_test_child_get_node,
7398     .fnv_last_lock = fib_test_child_last_lock_gone,
7399     .fnv_back_walk = fib_test_child_back_walk_notify,
7400 };
7401
7402 /*
7403  * the function (that should have been static but isn't so I can do this)
7404  * that processes the walk from the async queue,
7405  */
7406 f64 fib_walk_process_queues(vlib_main_t * vm,
7407                             const f64 quota);
7408 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7409
7410 static int
7411 fib_test_walk (void)
7412 {
7413     fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7414     fib_node_test_t *tc;
7415     vlib_main_t *vm;
7416     u32 ii, res;
7417
7418     res = 0;
7419     vm = vlib_get_main();
7420     fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7421
7422     /*
7423      * init a fake node on which we will add children
7424      */
7425     fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7426                   FIB_NODE_TYPE_TEST);
7427
7428     FOR_EACH_TEST_CHILD(tc)
7429     {
7430         fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7431         fib_node_lock(&tc->node);
7432         tc->ctxs = NULL;
7433         tc->index = ii;
7434         tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7435                                          PARENT_INDEX,
7436                                          FIB_NODE_TYPE_TEST, ii);
7437     }
7438
7439     /*
7440      * enqueue a walk across the parents children.
7441      */
7442     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7443
7444     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7445                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7446     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7447              "Parent has %d children pre-walk",
7448              fib_node_list_get_size(PARENT()->fn_children));
7449
7450     /*
7451      * give the walk a large amount of time so it gets to the end
7452      */
7453     fib_walk_process_queues(vm, 1);
7454
7455     FOR_EACH_TEST_CHILD(tc)
7456     {
7457         FIB_TEST(1 == vec_len(tc->ctxs),
7458                  "%d child visitsed %d times",
7459                  ii, vec_len(tc->ctxs));
7460         vec_free(tc->ctxs);
7461     }
7462     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7463              "Queue is empty post walk");
7464     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7465              "Parent has %d children post walk",
7466              fib_node_list_get_size(PARENT()->fn_children));
7467
7468     /*
7469      * walk again. should be no increase in the number of visits, since
7470      * the walk will have terminated.
7471      */
7472     fib_walk_process_queues(vm, 1);
7473
7474     FOR_EACH_TEST_CHILD(tc)
7475     {
7476         FIB_TEST(0 == vec_len(tc->ctxs),
7477                  "%d child visitsed %d times",
7478                  ii, vec_len(tc->ctxs));
7479     }
7480
7481     /*
7482      * schedule a low and hig priority walk. expect the high to be performed
7483      * before the low.
7484      * schedule the high prio walk first so that it is further from the head
7485      * of the dependency list. that way it won't merge with the low one.
7486      */
7487     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7488     low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7489
7490     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7491                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7492     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7493                    FIB_WALK_PRIORITY_LOW, &low_ctx);
7494
7495     fib_walk_process_queues(vm, 1);
7496
7497     FOR_EACH_TEST_CHILD(tc)
7498     {
7499         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7500                  "%d child visitsed by high prio walk", ii);
7501         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
7502                  "%d child visitsed by low prio walk", ii);
7503         vec_free(tc->ctxs);
7504     }
7505     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7506              "Queue is empty post prio walk");
7507     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7508              "Parent has %d children post prio walk",
7509              fib_node_list_get_size(PARENT()->fn_children));
7510
7511     /*
7512      * schedule 2 walks of the same priority that can be megred.
7513      * expect that each child is thus visited only once.
7514      */
7515     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7516     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7517
7518     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7519                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7520     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7521                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
7522
7523     fib_walk_process_queues(vm, 1);
7524
7525     FOR_EACH_TEST_CHILD(tc)
7526     {
7527         FIB_TEST(1 == vec_len(tc->ctxs),
7528                  "%d child visitsed %d times during merge walk",
7529                  ii, vec_len(tc->ctxs));
7530         vec_free(tc->ctxs);
7531     }
7532     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7533              "Queue is empty post merge walk");
7534     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7535              "Parent has %d children post merge walk",
7536              fib_node_list_get_size(PARENT()->fn_children));
7537
7538     /*
7539      * schedule 2 walks of the same priority that cannot be megred.
7540      * expect that each child is thus visited twice and in the order
7541      * in which the walks were scheduled.
7542      */
7543     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7544     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7545
7546     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7547                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7548     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7549                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
7550
7551     fib_walk_process_queues(vm, 1);
7552
7553     FOR_EACH_TEST_CHILD(tc)
7554     {
7555         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7556                  "%d child visitsed by high prio walk", ii);
7557         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
7558                  "%d child visitsed by low prio walk", ii);
7559         vec_free(tc->ctxs);
7560     }
7561     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7562              "Queue is empty post no-merge walk");
7563     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7564              "Parent has %d children post no-merge walk",
7565              fib_node_list_get_size(PARENT()->fn_children));
7566
7567     /*
7568      * schedule a walk that makes one one child progress.
7569      * we do this by giving the queue draining process zero
7570      * time quanta. it's a do..while loop, so it does something.
7571      */
7572     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7573
7574     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7575                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7576     fib_walk_process_queues(vm, 0);
7577
7578     FOR_EACH_TEST_CHILD(tc)
7579     {
7580         if (ii == N_TEST_CHILDREN)
7581         {
7582             FIB_TEST(1 == vec_len(tc->ctxs),
7583                      "%d child visitsed %d times in zero quanta walk",
7584                      ii, vec_len(tc->ctxs));
7585         }
7586         else
7587         {
7588             FIB_TEST(0 == vec_len(tc->ctxs),
7589                      "%d child visitsed %d times in 0 quanta walk",
7590                      ii, vec_len(tc->ctxs));
7591         }
7592     }
7593     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7594              "Queue is not empty post zero quanta walk");
7595     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7596              "Parent has %d children post zero qunta walk",
7597              fib_node_list_get_size(PARENT()->fn_children));
7598
7599     /*
7600      * another one step
7601      */
7602     fib_walk_process_queues(vm, 0);
7603
7604     FOR_EACH_TEST_CHILD(tc)
7605     {
7606         if (ii >= N_TEST_CHILDREN-1)
7607         {
7608             FIB_TEST(1 == vec_len(tc->ctxs),
7609                      "%d child visitsed %d times in 2nd zero quanta walk",
7610                      ii, vec_len(tc->ctxs));
7611         }
7612         else
7613         {
7614             FIB_TEST(0 == vec_len(tc->ctxs),
7615                      "%d child visitsed %d times in 2nd 0 quanta walk",
7616                      ii, vec_len(tc->ctxs));
7617         }
7618     }
7619     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7620              "Queue is not empty post zero quanta walk");
7621     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7622              "Parent has %d children post zero qunta walk",
7623              fib_node_list_get_size(PARENT()->fn_children));
7624
7625     /*
7626      * schedule another walk that will catch-up and merge.
7627      */
7628     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7629                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7630     fib_walk_process_queues(vm, 1);
7631
7632     FOR_EACH_TEST_CHILD(tc)
7633     {
7634         if (ii >= N_TEST_CHILDREN-1)
7635         {
7636             FIB_TEST(2 == vec_len(tc->ctxs),
7637                      "%d child visitsed %d times in 2nd zero quanta merge walk",
7638                      ii, vec_len(tc->ctxs));
7639             vec_free(tc->ctxs);
7640         }
7641         else
7642         {
7643             FIB_TEST(1 == vec_len(tc->ctxs),
7644                      "%d child visitsed %d times in 2nd 0 quanta merge walk",
7645                      ii, vec_len(tc->ctxs));
7646             vec_free(tc->ctxs);
7647         }
7648     }
7649     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7650              "Queue is not empty post 2nd zero quanta merge walk");
7651     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7652              "Parent has %d children post 2nd zero qunta merge walk",
7653              fib_node_list_get_size(PARENT()->fn_children));
7654
7655     /*
7656      * park a async walk in the middle of the list, then have an sync walk catch
7657      * it. same expectations as async catches async.
7658      */
7659     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7660
7661     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7662                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7663
7664     fib_walk_process_queues(vm, 0);
7665     fib_walk_process_queues(vm, 0);
7666
7667     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7668
7669     FOR_EACH_TEST_CHILD(tc)
7670     {
7671         if (ii >= N_TEST_CHILDREN-1)
7672         {
7673             FIB_TEST(2 == vec_len(tc->ctxs),
7674                      "%d child visitsed %d times in sync catches async walk",
7675                      ii, vec_len(tc->ctxs));
7676             vec_free(tc->ctxs);
7677         }
7678         else
7679         {
7680             FIB_TEST(1 == vec_len(tc->ctxs),
7681                      "%d child visitsed %d times in sync catches async walk",
7682                      ii, vec_len(tc->ctxs));
7683             vec_free(tc->ctxs);
7684         }
7685     }
7686     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7687              "Queue is not empty post 2nd zero quanta merge walk");
7688     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7689              "Parent has %d children post 2nd zero qunta merge walk",
7690              fib_node_list_get_size(PARENT()->fn_children));
7691
7692     /*
7693      * make the parent a child of one of its children, thus inducing a routing loop.
7694      */
7695     fib_test_nodes[PARENT_INDEX].sibling =
7696         fib_node_child_add(FIB_NODE_TYPE_TEST,
7697                            1, // the first child
7698                            FIB_NODE_TYPE_TEST,
7699                            PARENT_INDEX);
7700
7701     /*
7702      * execute a sync walk from the parent. each child visited spawns more sync
7703      * walks. we expect the walk to terminate.
7704      */
7705     fib_test_walk_spawns_walks = 1;
7706
7707     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7708
7709     FOR_EACH_TEST_CHILD(tc)
7710     {
7711         /*
7712          * child 1 - which is last in the list - has the loop.
7713          * the other children a re thus visitsed first. the we meet
7714          * child 1. we go round the loop again, visting the other children.
7715          * then we meet the walk in the dep list and bail. child 1 is not visitsed
7716          * again.
7717          */
7718         if (1 == ii)
7719         {
7720             FIB_TEST(1 == vec_len(tc->ctxs),
7721                      "child %d visitsed %d times during looped sync walk",
7722                      ii, vec_len(tc->ctxs));
7723         }
7724         else
7725         {
7726             FIB_TEST(2 == vec_len(tc->ctxs),
7727                      "child %d visitsed %d times during looped sync walk",
7728                      ii, vec_len(tc->ctxs));
7729         }
7730         vec_free(tc->ctxs);
7731     }
7732     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7733              "Parent has %d children post sync loop walk",
7734              fib_node_list_get_size(PARENT()->fn_children));
7735
7736     /*
7737      * the walk doesn't reach the max depth because the infra knows that sync
7738      * meets sync implies a loop and bails early.
7739      */
7740     FIB_TEST(high_ctx.fnbw_depth == 9,
7741              "Walk context depth %d post sync loop walk",
7742              high_ctx.fnbw_depth);
7743
7744     /*
7745      * execute an async walk of the graph loop, with each child spawns sync walks
7746      */
7747     high_ctx.fnbw_depth = 0;
7748     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7749                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7750
7751     fib_walk_process_queues(vm, 1);
7752
7753     FOR_EACH_TEST_CHILD(tc)
7754     {
7755         /*
7756          * we don't really care how many times the children are visisted, as long as
7757          * it is more than once.
7758          */
7759         FIB_TEST(1 <= vec_len(tc->ctxs),
7760                  "child %d visitsed %d times during looped aync spawns sync walk",
7761                  ii, vec_len(tc->ctxs));
7762         vec_free(tc->ctxs);
7763     }
7764
7765     /*
7766      * execute an async walk of the graph loop, with each child spawns async walks
7767      */
7768     fib_test_walk_spawns_walks = 2;
7769     high_ctx.fnbw_depth = 0;
7770     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7771                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7772
7773     fib_walk_process_queues(vm, 1);
7774
7775     FOR_EACH_TEST_CHILD(tc)
7776     {
7777         /*
7778          * we don't really care how many times the children are visisted, as long as
7779          * it is more than once.
7780          */
7781         FIB_TEST(1 <= vec_len(tc->ctxs),
7782                  "child %d visitsed %d times during looped async spawns async walk",
7783                  ii, vec_len(tc->ctxs));
7784         vec_free(tc->ctxs);
7785     }
7786
7787
7788     fib_node_child_remove(FIB_NODE_TYPE_TEST,
7789                           1, // the first child
7790                           fib_test_nodes[PARENT_INDEX].sibling);
7791
7792     /*
7793      * cleanup
7794      */
7795     FOR_EACH_TEST_CHILD(tc)
7796     {
7797         fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7798                               tc->sibling);
7799         fib_node_deinit(&tc->node);
7800         fib_node_unlock(&tc->node);
7801     }
7802     fib_node_deinit(PARENT());
7803
7804     /*
7805      * The parent will be destroyed when the last lock on it goes.
7806      * this test ensures all the walk objects are unlocking it.
7807      */
7808     FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7809              "Parent was destroyed");
7810
7811     return (res);
7812 }
7813
7814 /*
7815  * declaration of the otherwise static callback functions
7816  */
7817 void fib_bfd_notify (bfd_listen_event_e event,
7818                      const bfd_session_t *session);
7819 void adj_bfd_notify (bfd_listen_event_e event,
7820                      const bfd_session_t *session);
7821
7822 /**
7823  * Test BFD session interaction with FIB
7824  */
7825 static int
7826 fib_test_bfd (void)
7827 {
7828     fib_node_index_t fei;
7829     test_main_t *tm;
7830     int n_feis, res;
7831
7832     res = 0;
7833     /* via 10.10.10.1 */
7834     ip46_address_t nh_10_10_10_1 = {
7835         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7836     };
7837     /* via 10.10.10.2 */
7838     ip46_address_t nh_10_10_10_2 = {
7839         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7840     };
7841     /* via 10.10.10.10 */
7842     ip46_address_t nh_10_10_10_10 = {
7843         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7844     };
7845     n_feis = fib_entry_pool_size();
7846
7847     tm = &test_main;
7848
7849     /*
7850      * add interface routes. we'll assume this works. it's tested elsewhere
7851      */
7852     fib_prefix_t pfx_10_10_10_10_s_24 = {
7853         .fp_len = 24,
7854         .fp_proto = FIB_PROTOCOL_IP4,
7855         .fp_addr = nh_10_10_10_10,
7856     };
7857
7858     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7859                                     FIB_SOURCE_INTERFACE,
7860                                     (FIB_ENTRY_FLAG_CONNECTED |
7861                                      FIB_ENTRY_FLAG_ATTACHED),
7862                                     DPO_PROTO_IP4,
7863                                     NULL,
7864                                     tm->hw[0]->sw_if_index,
7865                                     ~0, // invalid fib index
7866                                     1, // weight
7867                                     NULL,
7868                                     FIB_ROUTE_PATH_FLAG_NONE);
7869
7870     fib_prefix_t pfx_10_10_10_10_s_32 = {
7871         .fp_len = 32,
7872         .fp_proto = FIB_PROTOCOL_IP4,
7873         .fp_addr = nh_10_10_10_10,
7874     };
7875     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7876                                     FIB_SOURCE_INTERFACE,
7877                                     (FIB_ENTRY_FLAG_CONNECTED |
7878                                      FIB_ENTRY_FLAG_LOCAL),
7879                                     DPO_PROTO_IP4,
7880                                     NULL,
7881                                     tm->hw[0]->sw_if_index,
7882                                     ~0, // invalid fib index
7883                                     1, // weight
7884                                     NULL,
7885                                     FIB_ROUTE_PATH_FLAG_NONE);
7886
7887     /*
7888      * A BFD session via a neighbour we do not yet know
7889      */
7890     bfd_session_t bfd_10_10_10_1 = {
7891         .udp = {
7892             .key = {
7893                 .fib_index = 0,
7894                 .peer_addr = nh_10_10_10_1,
7895             },
7896         },
7897         .hop_type = BFD_HOP_TYPE_MULTI,
7898         .local_state = BFD_STATE_init,
7899     };
7900
7901     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7902
7903     /*
7904      * A new entry will be created that forwards via the adj
7905      */
7906     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7907                                                     VNET_LINK_IP4,
7908                                                     &nh_10_10_10_1,
7909                                                     tm->hw[0]->sw_if_index);
7910     fib_prefix_t pfx_10_10_10_1_s_32 = {
7911         .fp_addr = nh_10_10_10_1,
7912         .fp_len = 32,
7913         .fp_proto = FIB_PROTOCOL_IP4,
7914     };
7915     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7916         .type = FT_LB_ADJ,
7917         .adj = {
7918             .adj = ai_10_10_10_1,
7919         },
7920     };
7921
7922     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7923     FIB_TEST(!fib_test_validate_entry(fei,
7924                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7925                                       1,
7926                                       &adj_o_10_10_10_1),
7927              "BFD sourced %U via %U",
7928              format_fib_prefix, &pfx_10_10_10_1_s_32,
7929              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7930
7931     /*
7932      * Delete the BFD session. Expect the fib_entry to be removed
7933      */
7934     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7935
7936     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7937     FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7938              "BFD sourced %U removed",
7939              format_fib_prefix, &pfx_10_10_10_1_s_32);
7940
7941     /*
7942      * Add the BFD source back
7943      */
7944     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7945
7946     /*
7947      * source the entry via the ADJ fib
7948      */
7949     fei = fib_table_entry_path_add(0,
7950                                    &pfx_10_10_10_1_s_32,
7951                                    FIB_SOURCE_ADJ,
7952                                    FIB_ENTRY_FLAG_ATTACHED,
7953                                    DPO_PROTO_IP4,
7954                                    &nh_10_10_10_1,
7955                                    tm->hw[0]->sw_if_index,
7956                                    ~0, // invalid fib index
7957                                    1,
7958                                    NULL,
7959                                    FIB_ROUTE_PATH_FLAG_NONE);
7960
7961     /*
7962      * Delete the BFD session. Expect the fib_entry to remain
7963      */
7964     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7965
7966     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7967     FIB_TEST(!fib_test_validate_entry(fei,
7968                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7969                                       1,
7970                                       &adj_o_10_10_10_1),
7971              "BFD sourced %U remains via %U",
7972              format_fib_prefix, &pfx_10_10_10_1_s_32,
7973              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7974
7975     /*
7976      * Add the BFD source back
7977      */
7978     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7979
7980     /*
7981      * Create another ADJ FIB
7982      */
7983     fib_prefix_t pfx_10_10_10_2_s_32 = {
7984         .fp_addr = nh_10_10_10_2,
7985         .fp_len = 32,
7986         .fp_proto = FIB_PROTOCOL_IP4,
7987     };
7988     fib_table_entry_path_add(0,
7989                              &pfx_10_10_10_2_s_32,
7990                              FIB_SOURCE_ADJ,
7991                              FIB_ENTRY_FLAG_ATTACHED,
7992                              DPO_PROTO_IP4,
7993                              &nh_10_10_10_2,
7994                              tm->hw[0]->sw_if_index,
7995                              ~0, // invalid fib index
7996                              1,
7997                              NULL,
7998                              FIB_ROUTE_PATH_FLAG_NONE);
7999     /*
8000      * A BFD session for the new ADJ FIB
8001      */
8002     bfd_session_t bfd_10_10_10_2 = {
8003         .udp = {
8004             .key = {
8005                 .fib_index = 0,
8006                 .peer_addr = nh_10_10_10_2,
8007             },
8008         },
8009         .hop_type = BFD_HOP_TYPE_MULTI,
8010         .local_state = BFD_STATE_init,
8011     };
8012
8013     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
8014
8015     /*
8016      * remove the adj-fib source whilst the session is present
8017      * then add it back
8018      */
8019     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8020     fib_table_entry_path_add(0,
8021                              &pfx_10_10_10_2_s_32,
8022                              FIB_SOURCE_ADJ,
8023                              FIB_ENTRY_FLAG_ATTACHED,
8024                              DPO_PROTO_IP4,
8025                              &nh_10_10_10_2,
8026                              tm->hw[0]->sw_if_index,
8027                              ~0, // invalid fib index
8028                              1,
8029                              NULL,
8030                              FIB_ROUTE_PATH_FLAG_NONE);
8031
8032     /*
8033      * Before adding a recursive via the BFD tracked ADJ-FIBs,
8034      * bring one of the sessions UP, leave the other down
8035      */
8036     bfd_10_10_10_1.local_state = BFD_STATE_up;
8037     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8038     bfd_10_10_10_2.local_state = BFD_STATE_down;
8039     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8040
8041     /*
8042      * A recursive prefix via both of the ADJ FIBs
8043      */
8044     fib_prefix_t pfx_200_0_0_0_s_24 = {
8045         .fp_proto = FIB_PROTOCOL_IP4,
8046         .fp_len = 32,
8047         .fp_addr = {
8048             .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
8049         },
8050     };
8051     const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
8052
8053     dpo_10_10_10_1 =
8054         fib_entry_contribute_ip_forwarding(
8055             fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
8056     dpo_10_10_10_2 =
8057         fib_entry_contribute_ip_forwarding(
8058             fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
8059
8060     fib_test_lb_bucket_t lb_o_10_10_10_1 = {
8061         .type = FT_LB_O_LB,
8062         .lb = {
8063             .lb = dpo_10_10_10_1->dpoi_index,
8064         },
8065     };
8066     fib_test_lb_bucket_t lb_o_10_10_10_2 = {
8067         .type = FT_LB_O_LB,
8068         .lb = {
8069             .lb = dpo_10_10_10_2->dpoi_index,
8070         },
8071     };
8072
8073     /*
8074      * A prefix via the adj-fib that is BFD down => DROP
8075      */
8076     fei = fib_table_entry_path_add(0,
8077                                    &pfx_200_0_0_0_s_24,
8078                                    FIB_SOURCE_API,
8079                                    FIB_ENTRY_FLAG_NONE,
8080                                    DPO_PROTO_IP4,
8081                                    &nh_10_10_10_2,
8082                                    ~0, // recursive
8083                                    0, // default fib index
8084                                    1,
8085                                    NULL,
8086                                    FIB_ROUTE_PATH_FLAG_NONE);
8087     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8088              "%U resolves via drop",
8089              format_fib_prefix, &pfx_200_0_0_0_s_24);
8090
8091     /*
8092      * add a path via the UP BFD adj-fib.
8093      *  we expect that the DOWN BFD ADJ FIB is not used.
8094      */
8095     fei = fib_table_entry_path_add(0,
8096                                    &pfx_200_0_0_0_s_24,
8097                                    FIB_SOURCE_API,
8098                                    FIB_ENTRY_FLAG_NONE,
8099                                    DPO_PROTO_IP4,
8100                                    &nh_10_10_10_1,
8101                                    ~0, // recursive
8102                                    0, // default fib index
8103                                    1,
8104                                    NULL,
8105                                    FIB_ROUTE_PATH_FLAG_NONE);
8106
8107     FIB_TEST(!fib_test_validate_entry(fei,
8108                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8109                                       1,
8110                                       &lb_o_10_10_10_1),
8111              "Recursive %U only UP BFD adj-fibs",
8112              format_fib_prefix, &pfx_200_0_0_0_s_24);
8113
8114     /*
8115      * Send a BFD state change to UP - both sessions are now up
8116      *  the recursive prefix should LB over both
8117      */
8118     bfd_10_10_10_2.local_state = BFD_STATE_up;
8119     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8120
8121
8122     FIB_TEST(!fib_test_validate_entry(fei,
8123                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8124                                       2,
8125                                       &lb_o_10_10_10_1,
8126                                       &lb_o_10_10_10_2),
8127              "Recursive %U via both UP BFD adj-fibs",
8128              format_fib_prefix, &pfx_200_0_0_0_s_24);
8129
8130     /*
8131      * Send a BFD state change to DOWN
8132      *  the recursive prefix should exclude the down
8133      */
8134     bfd_10_10_10_2.local_state = BFD_STATE_down;
8135     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8136
8137
8138     FIB_TEST(!fib_test_validate_entry(fei,
8139                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8140                                       1,
8141                                       &lb_o_10_10_10_1),
8142              "Recursive %U via only UP",
8143              format_fib_prefix, &pfx_200_0_0_0_s_24);
8144
8145     /*
8146      * Delete the BFD session while it is in the DOWN state.
8147      *  FIB should consider the entry's state as back up
8148      */
8149     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8150
8151     FIB_TEST(!fib_test_validate_entry(fei,
8152                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8153                                       2,
8154                                       &lb_o_10_10_10_1,
8155                                       &lb_o_10_10_10_2),
8156              "Recursive %U via both UP BFD adj-fibs post down session delete",
8157              format_fib_prefix, &pfx_200_0_0_0_s_24);
8158
8159     /*
8160      * Delete the BFD other session while it is in the UP state.
8161      */
8162     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8163
8164     FIB_TEST(!fib_test_validate_entry(fei,
8165                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8166                                       2,
8167                                       &lb_o_10_10_10_1,
8168                                       &lb_o_10_10_10_2),
8169              "Recursive %U via both UP BFD adj-fibs post up session delete",
8170              format_fib_prefix, &pfx_200_0_0_0_s_24);
8171
8172     /*
8173      * cleaup
8174      */
8175     fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8176     fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8177     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8178
8179     fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8180     fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8181
8182     adj_unlock(ai_10_10_10_1);
8183     /*
8184      * test no-one left behind
8185      */
8186     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8187     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8188
8189     /*
8190      * Single-hop BFD tests
8191      */
8192     bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8193     bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8194
8195     adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8196
8197     ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8198                                         VNET_LINK_IP4,
8199                                         &nh_10_10_10_1,
8200                                         tm->hw[0]->sw_if_index);
8201     /*
8202      * whilst the BFD session is not signalled, the adj is up
8203      */
8204     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on uninit session");
8205
8206     /*
8207      * bring the BFD session up
8208      */
8209     bfd_10_10_10_1.local_state = BFD_STATE_up;
8210     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8211     FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8212
8213     /*
8214      * bring the BFD session down
8215      */
8216     bfd_10_10_10_1.local_state = BFD_STATE_down;
8217     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8218     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8219
8220     /*
8221      * add an attached next hop FIB entry via the down adj
8222      */
8223     fib_prefix_t pfx_5_5_5_5_s_32 = {
8224         .fp_addr = {
8225             .ip4 = {
8226                 .as_u32 = clib_host_to_net_u32(0x05050505),
8227             },
8228         },
8229         .fp_len = 32,
8230         .fp_proto = FIB_PROTOCOL_IP4,
8231     };
8232
8233     fei = fib_table_entry_path_add(0,
8234                                    &pfx_5_5_5_5_s_32,
8235                                    FIB_SOURCE_CLI,
8236                                    FIB_ENTRY_FLAG_NONE,
8237                                    DPO_PROTO_IP4,
8238                                    &nh_10_10_10_1,
8239                                    tm->hw[0]->sw_if_index,
8240                                    ~0, // invalid fib index
8241                                    1,
8242                                    NULL,
8243                                    FIB_ROUTE_PATH_FLAG_NONE);
8244     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8245              "%U resolves via drop",
8246              format_fib_prefix, &pfx_5_5_5_5_s_32);
8247
8248     /*
8249      * Add a path via an ADJ that is up
8250      */
8251     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8252                                                     VNET_LINK_IP4,
8253                                                     &nh_10_10_10_2,
8254                                                     tm->hw[0]->sw_if_index);
8255
8256     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8257         .type = FT_LB_ADJ,
8258         .adj = {
8259             .adj = ai_10_10_10_2,
8260         },
8261     };
8262     adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8263
8264     fei = fib_table_entry_path_add(0,
8265                                    &pfx_5_5_5_5_s_32,
8266                                    FIB_SOURCE_CLI,
8267                                    FIB_ENTRY_FLAG_NONE,
8268                                    DPO_PROTO_IP4,
8269                                    &nh_10_10_10_2,
8270                                    tm->hw[0]->sw_if_index,
8271                                    ~0, // invalid fib index
8272                                    1,
8273                                    NULL,
8274                                    FIB_ROUTE_PATH_FLAG_NONE);
8275
8276     FIB_TEST(!fib_test_validate_entry(fei,
8277                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8278                                       1,
8279                                       &adj_o_10_10_10_2),
8280              "BFD sourced %U via %U",
8281              format_fib_prefix, &pfx_5_5_5_5_s_32,
8282              format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8283
8284     /*
8285      * Bring up the down session - should now LB
8286      */
8287     bfd_10_10_10_1.local_state = BFD_STATE_up;
8288     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8289     FIB_TEST(!fib_test_validate_entry(fei,
8290                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8291                                       2,
8292                                       &adj_o_10_10_10_1,
8293                                       &adj_o_10_10_10_2),
8294              "BFD sourced %U via noth adjs",
8295              format_fib_prefix, &pfx_5_5_5_5_s_32);
8296
8297     /*
8298      * remove the BFD session state from the adj
8299      */
8300     adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8301
8302     /*
8303      * clean-up
8304      */
8305     fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8306     adj_unlock(ai_10_10_10_1);
8307     adj_unlock(ai_10_10_10_2);
8308
8309     /*
8310      * test no-one left behind
8311      */
8312     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8313     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8314
8315     return (res);
8316 }
8317
8318 static int
8319 lfib_test (void)
8320 {
8321     const mpls_label_t deag_label = 50;
8322     adj_index_t ai_mpls_10_10_10_1;
8323     dpo_id_t dpo = DPO_INVALID;
8324     const u32 lfib_index = 0;
8325     const u32 fib_index = 0;
8326     const dpo_id_t *dpo1;
8327     fib_node_index_t lfe;
8328     lookup_dpo_t *lkd;
8329     int lb_count, res;
8330     test_main_t *tm;
8331
8332     res = 0;
8333     tm = &test_main;
8334     lb_count = pool_elts(load_balance_pool);
8335
8336     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8337              adj_nbr_db_size());
8338
8339     /*
8340      * MPLS enable an interface so we get the MPLS table created
8341      */
8342     mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8343     mpls_sw_interface_enable_disable(&mpls_main,
8344                                      tm->hw[0]->sw_if_index,
8345                                      1, 1);
8346
8347     ip46_address_t nh_10_10_10_1 = {
8348         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8349     };
8350     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8351                                              VNET_LINK_MPLS,
8352                                              &nh_10_10_10_1,
8353                                              tm->hw[0]->sw_if_index);
8354
8355     /*
8356      * Test the specials stack properly.
8357      */
8358     fib_prefix_t exp_null_v6_pfx = {
8359         .fp_proto = FIB_PROTOCOL_MPLS,
8360         .fp_eos = MPLS_EOS,
8361         .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8362         .fp_payload_proto = DPO_PROTO_IP6,
8363     };
8364     lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8365     FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8366              "%U/%U present",
8367              format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8368              format_mpls_eos_bit, MPLS_EOS);
8369     fib_entry_contribute_forwarding(lfe,
8370                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8371                                     &dpo);
8372     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8373     lkd = lookup_dpo_get(dpo1->dpoi_index);
8374
8375     FIB_TEST((fib_index == lkd->lkd_fib_index),
8376              "%U/%U is deag in %d %U",
8377              format_mpls_unicast_label, deag_label,
8378              format_mpls_eos_bit, MPLS_EOS,
8379              lkd->lkd_fib_index,
8380              format_dpo_id, &dpo, 0);
8381     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8382              "%U/%U is dst deag",
8383              format_mpls_unicast_label, deag_label,
8384              format_mpls_eos_bit, MPLS_EOS);
8385     FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8386              "%U/%U is lookup in interface's table",
8387              format_mpls_unicast_label, deag_label,
8388              format_mpls_eos_bit, MPLS_EOS);
8389     FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8390              "%U/%U is %U dst deag",
8391              format_mpls_unicast_label, deag_label,
8392              format_mpls_eos_bit, MPLS_EOS,
8393              format_dpo_proto, lkd->lkd_proto);
8394
8395     /*
8396      * A route deag route for EOS
8397      */
8398     fib_prefix_t pfx = {
8399         .fp_proto = FIB_PROTOCOL_MPLS,
8400         .fp_eos = MPLS_EOS,
8401         .fp_label = deag_label,
8402         .fp_payload_proto = DPO_PROTO_IP4,
8403     };
8404     mpls_disp_dpo_t *mdd;
8405     lfe = fib_table_entry_path_add(lfib_index,
8406                                    &pfx,
8407                                    FIB_SOURCE_CLI,
8408                                    FIB_ENTRY_FLAG_NONE,
8409                                    DPO_PROTO_IP4,
8410                                    &zero_addr,
8411                                    ~0,
8412                                    fib_index,
8413                                    1,
8414                                    NULL,
8415                                    FIB_ROUTE_PATH_FLAG_NONE);
8416
8417     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8418              "%U/%U present",
8419              format_mpls_unicast_label, deag_label,
8420              format_mpls_eos_bit, MPLS_EOS);
8421
8422     fib_entry_contribute_forwarding(lfe,
8423                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8424                                     &dpo);
8425     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8426     mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8427
8428     FIB_TEST((FIB_MPLS_LSP_MODE_PIPE == mdd->mdd_mode),
8429              "%U/%U disp is pipe mode",
8430              format_mpls_unicast_label, deag_label,
8431              format_mpls_eos_bit, MPLS_EOS);
8432
8433     lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8434
8435     FIB_TEST((fib_index == lkd->lkd_fib_index),
8436              "%U/%U is deag in %d %U",
8437              format_mpls_unicast_label, deag_label,
8438              format_mpls_eos_bit, MPLS_EOS,
8439              lkd->lkd_fib_index,
8440              format_dpo_id, &dpo, 0);
8441     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8442              "%U/%U is dst deag",
8443              format_mpls_unicast_label, deag_label,
8444              format_mpls_eos_bit, MPLS_EOS);
8445     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8446              "%U/%U is %U dst deag",
8447              format_mpls_unicast_label, deag_label,
8448              format_mpls_eos_bit, MPLS_EOS,
8449              format_dpo_proto, lkd->lkd_proto);
8450
8451     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8452
8453     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8454                                                          &pfx)),
8455               "%U/%U not present",
8456               format_mpls_unicast_label, deag_label,
8457               format_mpls_eos_bit, MPLS_EOS);
8458     dpo_reset(&dpo);
8459
8460     /*
8461      * A route deag route for EOS with LSP mode uniform
8462      */
8463     fib_mpls_label_t *l_pops = NULL, l_pop = {
8464         .fml_value = MPLS_LABEL_POP,
8465         .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
8466     };
8467     vec_add1(l_pops, l_pop);
8468     lfe = fib_table_entry_path_add(lfib_index,
8469                                    &pfx,
8470                                    FIB_SOURCE_CLI,
8471                                    FIB_ENTRY_FLAG_NONE,
8472                                    DPO_PROTO_IP4,
8473                                    &zero_addr,
8474                                    ~0,
8475                                    fib_index,
8476                                    1,
8477                                    l_pops,
8478                                    FIB_ROUTE_PATH_FLAG_NONE);
8479
8480     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8481               "%U/%U present",
8482               format_mpls_unicast_label, deag_label,
8483               format_mpls_eos_bit, MPLS_EOS);
8484
8485     fib_entry_contribute_forwarding(lfe,
8486                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8487                                     &dpo);
8488     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8489     mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8490
8491     FIB_TEST((FIB_MPLS_LSP_MODE_UNIFORM == mdd->mdd_mode),
8492              "%U/%U disp is uniform mode",
8493              format_mpls_unicast_label, deag_label,
8494              format_mpls_eos_bit, MPLS_EOS);
8495
8496     lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8497
8498     FIB_TEST((fib_index == lkd->lkd_fib_index),
8499               "%U/%U is deag in %d %U",
8500              format_mpls_unicast_label, deag_label,
8501              format_mpls_eos_bit, MPLS_EOS,
8502              lkd->lkd_fib_index,
8503              format_dpo_id, &dpo, 0);
8504     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8505              "%U/%U is dst deag",
8506              format_mpls_unicast_label, deag_label,
8507              format_mpls_eos_bit, MPLS_EOS);
8508     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8509              "%U/%U is %U dst deag",
8510              format_mpls_unicast_label, deag_label,
8511              format_mpls_eos_bit, MPLS_EOS,
8512              format_dpo_proto, lkd->lkd_proto);
8513
8514     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8515
8516     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8517                                                          &pfx)),
8518               "%U/%U not present",
8519               format_mpls_unicast_label, deag_label,
8520               format_mpls_eos_bit, MPLS_EOS);
8521     dpo_reset(&dpo);
8522
8523     /*
8524      * A route deag route for non-EOS
8525      */
8526     pfx.fp_eos = MPLS_NON_EOS;
8527     lfe = fib_table_entry_path_add(lfib_index,
8528                                    &pfx,
8529                                    FIB_SOURCE_CLI,
8530                                    FIB_ENTRY_FLAG_NONE,
8531                                    DPO_PROTO_IP4,
8532                                    &zero_addr,
8533                                    ~0,
8534                                    lfib_index,
8535                                    1,
8536                                    NULL,
8537                                    FIB_ROUTE_PATH_FLAG_NONE);
8538
8539     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8540              "%U/%U present",
8541              format_mpls_unicast_label, deag_label,
8542              format_mpls_eos_bit, MPLS_NON_EOS);
8543
8544     fib_entry_contribute_forwarding(lfe,
8545                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8546                                     &dpo);
8547     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8548     lkd = lookup_dpo_get(dpo1->dpoi_index);
8549
8550     FIB_TEST((fib_index == lkd->lkd_fib_index),
8551              "%U/%U is deag in %d %U",
8552              format_mpls_unicast_label, deag_label,
8553              format_mpls_eos_bit, MPLS_NON_EOS,
8554              lkd->lkd_fib_index,
8555              format_dpo_id, &dpo, 0);
8556     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8557              "%U/%U is dst deag",
8558              format_mpls_unicast_label, deag_label,
8559              format_mpls_eos_bit, MPLS_NON_EOS);
8560
8561     FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8562              "%U/%U is %U dst deag",
8563              format_mpls_unicast_label, deag_label,
8564              format_mpls_eos_bit, MPLS_NON_EOS,
8565              format_dpo_proto, lkd->lkd_proto);
8566
8567     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8568
8569     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8570                                                          &pfx)),
8571              "%U/%U not present",
8572              format_mpls_unicast_label, deag_label,
8573              format_mpls_eos_bit, MPLS_EOS);
8574
8575     dpo_reset(&dpo);
8576
8577     /*
8578      * An MPLS x-connect
8579      */
8580     fib_prefix_t pfx_1200 = {
8581         .fp_len = 21,
8582         .fp_proto = FIB_PROTOCOL_MPLS,
8583         .fp_label = 1200,
8584         .fp_eos = MPLS_NON_EOS,
8585     };
8586     fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8587         .type = FT_LB_LABEL_STACK_O_ADJ,
8588         .label_stack_o_adj = {
8589             .adj = ai_mpls_10_10_10_1,
8590             .label_stack_size = 4,
8591             .label_stack = {
8592                 200, 300, 400, 500,
8593             },
8594             .eos = MPLS_NON_EOS,
8595         },
8596     };
8597     dpo_id_t neos_1200 = DPO_INVALID;
8598     dpo_id_t ip_1200 = DPO_INVALID;
8599     fib_mpls_label_t *l200 = NULL;
8600     u32 ii;
8601     for (ii = 0; ii < 4; ii++)
8602     {
8603         fib_mpls_label_t fml = {
8604             .fml_value = 200 + (ii * 100),
8605         };
8606         vec_add1(l200, fml);
8607     };
8608
8609     lfe = fib_table_entry_update_one_path(fib_index,
8610                                           &pfx_1200,
8611                                           FIB_SOURCE_API,
8612                                           FIB_ENTRY_FLAG_NONE,
8613                                           DPO_PROTO_IP4,
8614                                           &nh_10_10_10_1,
8615                                           tm->hw[0]->sw_if_index,
8616                                           ~0, // invalid fib index
8617                                           1,
8618                                           l200,
8619                                           FIB_ROUTE_PATH_FLAG_NONE);
8620
8621     FIB_TEST(!fib_test_validate_entry(lfe,
8622                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8623                                       1,
8624                                       &neos_o_10_10_10_1),
8625              "1200/0 LB 1 buckets via: "
8626              "adj 10.10.11.1");
8627
8628     /*
8629      * A recursive route via the MPLS x-connect
8630      */
8631     fib_prefix_t pfx_2_2_2_3_s_32 = {
8632         .fp_len = 32,
8633         .fp_proto = FIB_PROTOCOL_IP4,
8634         .fp_addr = {
8635             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8636         },
8637     };
8638     fib_route_path_t *rpaths = NULL, rpath = {
8639         .frp_proto = DPO_PROTO_MPLS,
8640         .frp_local_label = 1200,
8641         .frp_eos = MPLS_NON_EOS,
8642         .frp_sw_if_index = ~0, // recurive
8643         .frp_fib_index = 0, // Default MPLS fib
8644         .frp_weight = 1,
8645         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8646         .frp_label_stack = NULL,
8647     };
8648     vec_add1(rpaths, rpath);
8649
8650     fib_table_entry_path_add2(fib_index,
8651                               &pfx_2_2_2_3_s_32,
8652                               FIB_SOURCE_API,
8653                               FIB_ENTRY_FLAG_NONE,
8654                               rpaths);
8655
8656     /*
8657      * A labelled recursive route via the MPLS x-connect
8658      */
8659     fib_prefix_t pfx_2_2_2_4_s_32 = {
8660         .fp_len = 32,
8661         .fp_proto = FIB_PROTOCOL_IP4,
8662         .fp_addr = {
8663             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8664         },
8665     };
8666     fib_mpls_label_t *l999 = NULL, fml_999 = {
8667         .fml_value = 999,
8668     };
8669     vec_add1(l999, fml_999);
8670     rpaths[0].frp_label_stack = l999,
8671
8672         fib_table_entry_path_add2(fib_index,
8673                                   &pfx_2_2_2_4_s_32,
8674                                   FIB_SOURCE_API,
8675                                   FIB_ENTRY_FLAG_NONE,
8676                                   rpaths);
8677
8678     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8679                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8680                                     &ip_1200);
8681     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8682                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8683                                     &neos_1200);
8684
8685     fib_test_lb_bucket_t ip_o_1200 = {
8686         .type = FT_LB_O_LB,
8687         .lb = {
8688             .lb = ip_1200.dpoi_index,
8689         },
8690     };
8691     fib_test_lb_bucket_t mpls_o_1200 = {
8692         .type = FT_LB_LABEL_O_LB,
8693         .label_o_lb = {
8694             .lb = neos_1200.dpoi_index,
8695             .label = 999,
8696             .eos = MPLS_EOS,
8697         },
8698     };
8699
8700     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8701     FIB_TEST(!fib_test_validate_entry(lfe,
8702                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8703                                       1,
8704                                       &ip_o_1200),
8705              "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8706     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8707     FIB_TEST(!fib_test_validate_entry(lfe,
8708                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8709                                       1,
8710                                       &mpls_o_1200),
8711              "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8712
8713     fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8714     fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8715     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8716
8717     dpo_reset(&neos_1200);
8718     dpo_reset(&ip_1200);
8719
8720     /*
8721      * A recursive via a label that does not exist
8722      */
8723     fib_test_lb_bucket_t bucket_drop = {
8724         .type = FT_LB_DROP,
8725         .special = {
8726             .adj = DPO_PROTO_IP4,
8727         },
8728     };
8729     fib_test_lb_bucket_t mpls_bucket_drop = {
8730         .type = FT_LB_DROP,
8731         .special = {
8732             .adj = DPO_PROTO_MPLS,
8733         },
8734     };
8735
8736     rpaths[0].frp_label_stack = NULL;
8737     lfe = fib_table_entry_path_add2(fib_index,
8738                                     &pfx_2_2_2_4_s_32,
8739                                     FIB_SOURCE_API,
8740                                     FIB_ENTRY_FLAG_NONE,
8741                                     rpaths);
8742
8743     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8744                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8745                                     &ip_1200);
8746     ip_o_1200.lb.lb = ip_1200.dpoi_index;
8747
8748     FIB_TEST(!fib_test_validate_entry(lfe,
8749                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8750                                       1,
8751                                       &bucket_drop),
8752              "2.2.2.2.4/32 LB 1 buckets via: drop");
8753     lfe = fib_table_lookup(fib_index, &pfx_1200);
8754     FIB_TEST(!fib_test_validate_entry(lfe,
8755                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8756                                       1,
8757                                       &bucket_drop),
8758              "1200/neos LB 1 buckets via: ip4-DROP");
8759     FIB_TEST(!fib_test_validate_entry(lfe,
8760                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8761                                       1,
8762                                       &mpls_bucket_drop),
8763              "1200/neos LB 1 buckets via: mpls-DROP");
8764
8765     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8766
8767     dpo_reset(&ip_1200);
8768
8769     /*
8770      * An rx-interface route.
8771      *  like the tail of an mcast LSP
8772      */
8773     dpo_id_t idpo = DPO_INVALID;
8774
8775     interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8776                                  tm->hw[0]->sw_if_index,
8777                                  &idpo);
8778
8779     fib_prefix_t pfx_2500 = {
8780         .fp_len = 21,
8781         .fp_proto = FIB_PROTOCOL_MPLS,
8782         .fp_label = 2500,
8783         .fp_eos = MPLS_EOS,
8784         .fp_payload_proto = DPO_PROTO_IP4,
8785     };
8786     fib_test_lb_bucket_t rx_intf_0 = {
8787         .type = FT_LB_INTF,
8788         .adj = {
8789             .adj = idpo.dpoi_index,
8790         },
8791     };
8792
8793     lfe = fib_table_entry_update_one_path(fib_index,
8794                                           &pfx_2500,
8795                                           FIB_SOURCE_API,
8796                                           FIB_ENTRY_FLAG_NONE,
8797                                           DPO_PROTO_IP4,
8798                                           NULL,
8799                                           tm->hw[0]->sw_if_index,
8800                                           ~0, // invalid fib index
8801                                           0,
8802                                           NULL,
8803                                           FIB_ROUTE_PATH_INTF_RX);
8804     FIB_TEST(!fib_test_validate_entry(lfe,
8805                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8806                                       1,
8807                                       &rx_intf_0),
8808              "2500 rx-interface 0");
8809     fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8810
8811     /*
8812      * An MPLS mulicast entry
8813      */
8814     fib_prefix_t pfx_3500 = {
8815         .fp_len = 21,
8816         .fp_proto = FIB_PROTOCOL_MPLS,
8817         .fp_label = 3500,
8818         .fp_eos = MPLS_EOS,
8819         .fp_payload_proto = DPO_PROTO_IP4,
8820     };
8821     fib_test_rep_bucket_t mc_0 = {
8822         .type = FT_REP_LABEL_O_ADJ,
8823         .label_o_adj = {
8824             .adj = ai_mpls_10_10_10_1,
8825             .label = 3300,
8826             .eos = MPLS_EOS,
8827         },
8828     };
8829     fib_test_rep_bucket_t mc_intf_0 = {
8830         .type = FT_REP_INTF,
8831         .adj = {
8832             .adj = idpo.dpoi_index,
8833         },
8834     };
8835     fib_mpls_label_t *l3300 = NULL, fml_3300 = {
8836         .fml_value = 3300,
8837     };
8838     vec_add1(l3300, fml_3300);
8839
8840     lfe = fib_table_entry_update_one_path(lfib_index,
8841                                           &pfx_3500,
8842                                           FIB_SOURCE_API,
8843                                           FIB_ENTRY_FLAG_MULTICAST,
8844                                           DPO_PROTO_IP4,
8845                                           &nh_10_10_10_1,
8846                                           tm->hw[0]->sw_if_index,
8847                                           ~0, // invalid fib index
8848                                           1,
8849                                           l3300,
8850                                           FIB_ROUTE_PATH_FLAG_NONE);
8851     FIB_TEST(!fib_test_validate_entry(lfe,
8852                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8853                                       1,
8854                                       &mc_0),
8855              "3500 via replicate over 10.10.10.1");
8856
8857     /*
8858      * MPLS Bud-node. Add a replication via an interface-receieve path
8859      */
8860     lfe = fib_table_entry_path_add(lfib_index,
8861                                    &pfx_3500,
8862                                    FIB_SOURCE_API,
8863                                    FIB_ENTRY_FLAG_MULTICAST,
8864                                    DPO_PROTO_IP4,
8865                                    NULL,
8866                                    tm->hw[0]->sw_if_index,
8867                                    ~0, // invalid fib index
8868                                    0,
8869                                    NULL,
8870                                    FIB_ROUTE_PATH_INTF_RX);
8871     FIB_TEST(!fib_test_validate_entry(lfe,
8872                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8873                                       2,
8874                                       &mc_0,
8875                                       &mc_intf_0),
8876              "3500 via replicate over 10.10.10.1 and interface-rx");
8877
8878     /*
8879      * Add a replication via an interface-free for-us path
8880      */
8881     fib_test_rep_bucket_t mc_disp = {
8882         .type = FT_REP_DISP_MFIB_LOOKUP,
8883         .adj = {
8884             .adj = idpo.dpoi_index,
8885         },
8886     };
8887     lfe = fib_table_entry_path_add(lfib_index,
8888                                    &pfx_3500,
8889                                    FIB_SOURCE_API,
8890                                    FIB_ENTRY_FLAG_MULTICAST,
8891                                    DPO_PROTO_IP4,
8892                                    NULL,
8893                                    5, // rpf-id
8894                                    0, // default table
8895                                    0,
8896                                    NULL,
8897                                    FIB_ROUTE_PATH_RPF_ID);
8898     FIB_TEST(!fib_test_validate_entry(lfe,
8899                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8900                                       3,
8901                                       &mc_0,
8902                                       &mc_disp,
8903                                       &mc_intf_0),
8904              "3500 via replicate over 10.10.10.1 and interface-rx");
8905
8906
8907
8908     fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8909     dpo_reset(&idpo);
8910
8911     /*
8912      * cleanup
8913      */
8914     mpls_sw_interface_enable_disable(&mpls_main,
8915                                      tm->hw[0]->sw_if_index,
8916                                      0, 1);
8917     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
8918
8919     FIB_TEST(0 == pool_elts(mpls_disp_dpo_pool),
8920              "mpls_disp_dpo resources freed %d of %d",
8921              0, pool_elts(mpls_disp_dpo_pool));
8922     FIB_TEST(lb_count == pool_elts(load_balance_pool),
8923              "Load-balance resources freed %d of %d",
8924              lb_count, pool_elts(load_balance_pool));
8925     FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
8926              "interface_rx_dpo resources freed %d of %d",
8927              0, pool_elts(interface_rx_dpo_pool));
8928
8929     return (res);
8930 }
8931
8932 static int
8933 fib_test_inherit (void)
8934 {
8935     fib_node_index_t fei;
8936     test_main_t *tm;
8937     int n_feis, res;
8938
8939     res = 0;
8940     n_feis = fib_entry_pool_size();
8941     tm = &test_main;
8942
8943     const ip46_address_t nh_10_10_10_1 = {
8944         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8945     };
8946     const ip46_address_t nh_10_10_10_2 = {
8947         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
8948     };
8949     const ip46_address_t nh_10_10_10_3 = {
8950         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
8951     };
8952     const ip46_address_t nh_10_10_10_16 = {
8953         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a10),
8954     };
8955     const ip46_address_t nh_10_10_10_20 = {
8956         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a14),
8957     };
8958     const ip46_address_t nh_10_10_10_21 = {
8959         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a15),
8960     };
8961     const ip46_address_t nh_10_10_10_22 = {
8962         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a16),
8963     };
8964     const ip46_address_t nh_10_10_10_255 = {
8965         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0aff),
8966     };
8967     const ip46_address_t nh_10_10_10_0 = {
8968         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a00),
8969     };
8970     const ip46_address_t nh_10_10_0_0 = {
8971         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0000),
8972     };
8973     const ip46_address_t nh_11_11_11_11 = {
8974         .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
8975     };
8976     const ip46_address_t nh_11_11_11_0 = {
8977         .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b00),
8978     };
8979
8980     /*
8981      * prefixes at the base of a sub-tree
8982      */
8983     const fib_prefix_t pfx_10_10_10_21_s_32 = {
8984         .fp_len = 32,
8985         .fp_proto = FIB_PROTOCOL_IP4,
8986         .fp_addr = nh_10_10_10_21,
8987     };
8988     const fib_prefix_t pfx_10_10_10_22_s_32 = {
8989         .fp_len = 32,
8990         .fp_proto = FIB_PROTOCOL_IP4,
8991         .fp_addr = nh_10_10_10_22,
8992     };
8993     const fib_prefix_t pfx_10_10_10_255_s_32 = {
8994         .fp_len = 32,
8995         .fp_proto = FIB_PROTOCOL_IP4,
8996         .fp_addr = nh_10_10_10_255,
8997     };
8998     const u32 N_PLS = fib_path_list_pool_size();
8999
9000     fib_table_entry_special_add(0,
9001                                 &pfx_10_10_10_21_s_32,
9002                                 FIB_SOURCE_CLI,
9003                                 FIB_ENTRY_FLAG_DROP);
9004     fib_table_entry_special_add(0,
9005                                 &pfx_10_10_10_22_s_32,
9006                                 FIB_SOURCE_CLI,
9007                                 FIB_ENTRY_FLAG_DROP);
9008     fib_table_entry_special_add(0,
9009                                 &pfx_10_10_10_255_s_32,
9010                                 FIB_SOURCE_CLI,
9011                                 FIB_ENTRY_FLAG_DROP);
9012
9013     /*
9014      * source an entry that pushes its state down the sub-tree
9015      */
9016     const fib_prefix_t pfx_10_10_10_16_s_28 = {
9017         .fp_len = 28,
9018         .fp_proto = FIB_PROTOCOL_IP4,
9019         .fp_addr = nh_10_10_10_16,
9020     };
9021     fib_table_entry_update_one_path(0,
9022                                     &pfx_10_10_10_16_s_28,
9023                                     FIB_SOURCE_API,
9024                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9025                                     DPO_PROTO_IP4,
9026                                     &nh_10_10_10_1,
9027                                     tm->hw[0]->sw_if_index,
9028                                     ~0,
9029                                     1,
9030                                     NULL,
9031                                     FIB_ROUTE_PATH_FLAG_NONE);
9032
9033     /*
9034      * this covering entry and all those below it should have
9035      * the same forwarding information.
9036      */
9037     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9038                                                     VNET_LINK_IP4,
9039                                                     &nh_10_10_10_1,
9040                                                     tm->hw[0]->sw_if_index);
9041     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
9042         .type = FT_LB_ADJ,
9043         .adj = {
9044             .adj = ai_10_10_10_1,
9045         },
9046     };
9047
9048     fei = fib_table_lookup(0, &pfx_10_10_10_16_s_28);
9049     FIB_TEST(!fib_test_validate_entry(fei,
9050                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9051                                       1,
9052                                       &adj_o_10_10_10_1),
9053              "%U via 10.10.10.1",
9054              format_fib_prefix, &pfx_10_10_10_16_s_28);
9055     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9056     FIB_TEST(!fib_test_validate_entry(fei,
9057                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9058                                       1,
9059                                       &adj_o_10_10_10_1),
9060              "%U via 10.10.10.1",
9061              format_fib_prefix, &pfx_10_10_10_21_s_32);
9062     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9063     FIB_TEST(!fib_test_validate_entry(fei,
9064                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9065                                       1,
9066                                       &adj_o_10_10_10_1),
9067              "%U via 10.10.10.1",
9068              format_fib_prefix, &pfx_10_10_10_22_s_32);
9069     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9070     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9071              "%U resolves via drop",
9072              format_fib_prefix, &pfx_10_10_10_255_s_32);
9073
9074     /*
9075      * remove the inherting cover - covereds go back to drop
9076      */
9077     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9078
9079     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9080     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9081              "%U resolves via drop",
9082              format_fib_prefix, &pfx_10_10_10_21_s_32);
9083
9084     /*
9085      * source an entry that pushes its state down the sub-tree
9086      */
9087     const fib_prefix_t pfx_10_10_10_0_s_24 = {
9088         .fp_len = 24,
9089         .fp_proto = FIB_PROTOCOL_IP4,
9090         .fp_addr = nh_10_10_10_0,
9091     };
9092     fib_table_entry_update_one_path(0,
9093                                     &pfx_10_10_10_0_s_24,
9094                                     FIB_SOURCE_API,
9095                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9096                                     DPO_PROTO_IP4,
9097                                     &nh_10_10_10_1,
9098                                     tm->hw[0]->sw_if_index,
9099                                     ~0,
9100                                     1,
9101                                     NULL,
9102                                     FIB_ROUTE_PATH_FLAG_NONE);
9103
9104     /*
9105      * whole sub-tree now covered
9106      */
9107     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9108     FIB_TEST(!fib_test_validate_entry(fei,
9109                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9110                                       1,
9111                                       &adj_o_10_10_10_1),
9112              "%U via 10.10.10.1",
9113              format_fib_prefix, &pfx_10_10_10_0_s_24);
9114     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9115     FIB_TEST(!fib_test_validate_entry(fei,
9116                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9117                                       1,
9118                                       &adj_o_10_10_10_1),
9119              "%U via 10.10.10.1",
9120              format_fib_prefix, &pfx_10_10_10_21_s_32);
9121     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9122     FIB_TEST(!fib_test_validate_entry(fei,
9123                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9124                                       1,
9125                                       &adj_o_10_10_10_1),
9126              "%U via 10.10.10.1",
9127              format_fib_prefix, &pfx_10_10_10_22_s_32);
9128     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9129     FIB_TEST(!fib_test_validate_entry(fei,
9130                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9131                                       1,
9132                                       &adj_o_10_10_10_1),
9133              "%U via 10.10.10.1",
9134              format_fib_prefix, &pfx_10_10_10_255_s_32);
9135
9136     /*
9137      * insert a more specific into the sub-tree - expect inheritance
9138      *  this one is directly covered by the root
9139      */
9140     fib_table_entry_special_add(0,
9141                                 &pfx_10_10_10_16_s_28,
9142                                 FIB_SOURCE_CLI,
9143                                 FIB_ENTRY_FLAG_DROP);
9144     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9145     FIB_TEST(!fib_test_validate_entry(fei,
9146                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9147                                       1,
9148                                       &adj_o_10_10_10_1),
9149              "%U via 10.10.10.1",
9150              format_fib_prefix, &pfx_10_10_10_16_s_28);
9151
9152     /*
9153      * insert a more specific into the sub-tree - expect inheritance
9154      *  this one is indirectly covered by the root
9155      */
9156     const fib_prefix_t pfx_10_10_10_20_s_30 = {
9157         .fp_len = 30,
9158         .fp_proto = FIB_PROTOCOL_IP4,
9159         .fp_addr = nh_10_10_10_20,
9160     };
9161     fib_table_entry_special_add(0,
9162                                 &pfx_10_10_10_20_s_30,
9163                                 FIB_SOURCE_CLI,
9164                                 FIB_ENTRY_FLAG_DROP);
9165     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9166     FIB_TEST(!fib_test_validate_entry(fei,
9167                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9168                                       1,
9169                                       &adj_o_10_10_10_1),
9170              "%U via 10.10.10.1",
9171              format_fib_prefix, &pfx_10_10_10_20_s_30);
9172
9173     /*
9174      * remove the prefix from the middle of the sub-tree
9175      *  the inherited source will be the only one remaining - expect
9176      *  it to be withdrawn and hence the prefix is removed.
9177      */
9178     fib_table_entry_special_remove(0,
9179                                    &pfx_10_10_10_20_s_30,
9180                                    FIB_SOURCE_CLI);
9181     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9182     FIB_TEST((FIB_NODE_INDEX_INVALID == fei),
9183              "%U gone",
9184              format_fib_prefix, &pfx_10_10_10_20_s_30);
9185
9186     /*
9187      * inheriting source is modifed - expect the modification to be present
9188      *  throughout the sub-tree
9189      */
9190     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9191                                                     VNET_LINK_IP4,
9192                                                     &nh_10_10_10_2,
9193                                                     tm->hw[0]->sw_if_index);
9194     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
9195         .type = FT_LB_ADJ,
9196         .adj = {
9197             .adj = ai_10_10_10_2,
9198         },
9199     };
9200
9201     fib_table_entry_update_one_path(0,
9202                                     &pfx_10_10_10_0_s_24,
9203                                     FIB_SOURCE_API,
9204                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9205                                     DPO_PROTO_IP4,
9206                                     &nh_10_10_10_2,
9207                                     tm->hw[0]->sw_if_index,
9208                                     ~0,
9209                                     1,
9210                                     NULL,
9211                                     FIB_ROUTE_PATH_FLAG_NONE);
9212     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9213     FIB_TEST(!fib_test_validate_entry(fei,
9214                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9215                                       1,
9216                                       &adj_o_10_10_10_2),
9217              "%U via 10.10.10.2",
9218              format_fib_prefix, &pfx_10_10_10_21_s_32);
9219     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9220     FIB_TEST(!fib_test_validate_entry(fei,
9221                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9222                                       1,
9223                                       &adj_o_10_10_10_2),
9224              "%U via 10.10.10.2",
9225              format_fib_prefix, &pfx_10_10_10_22_s_32);
9226     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9227     FIB_TEST(!fib_test_validate_entry(fei,
9228                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9229                                       1,
9230                                       &adj_o_10_10_10_2),
9231              "%U via 10.10.10.2",
9232              format_fib_prefix, &pfx_10_10_10_255_s_32);
9233     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9234     FIB_TEST(!fib_test_validate_entry(fei,
9235                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9236                                       1,
9237                                       &adj_o_10_10_10_2),
9238              "%U via 10.10.10.2",
9239              format_fib_prefix, &pfx_10_10_10_0_s_24);
9240
9241     /*
9242      * add the source that replaces inherited state.
9243      * inheriting source is not the best, so it doesn't push state.
9244      */
9245     fib_table_entry_update_one_path(0,
9246                                     &pfx_10_10_10_0_s_24,
9247                                     FIB_SOURCE_PLUGIN_HI,
9248                                     FIB_ENTRY_FLAG_NONE,
9249                                     DPO_PROTO_IP4,
9250                                     &nh_10_10_10_1,
9251                                     tm->hw[0]->sw_if_index,
9252                                     ~0,
9253                                     1,
9254                                     NULL,
9255                                     FIB_ROUTE_PATH_FLAG_NONE);
9256     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9257     FIB_TEST(!fib_test_validate_entry(fei,
9258                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9259                                       1,
9260                                       &adj_o_10_10_10_1),
9261              "%U via 10.10.10.1",
9262              format_fib_prefix, &pfx_10_10_10_0_s_24);
9263
9264     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9265     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9266              "%U resolves via drop",
9267              format_fib_prefix, &pfx_10_10_10_21_s_32);
9268     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9269     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9270              "%U resolves via drop",
9271              format_fib_prefix, &pfx_10_10_10_22_s_32);
9272     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9273     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9274              "%U resolves via drop",
9275              format_fib_prefix, &pfx_10_10_10_255_s_32);
9276     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9277     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9278              "%U resolves via drop",
9279              format_fib_prefix, &pfx_10_10_10_16_s_28);
9280
9281     /*
9282      * withdraw the higher priority source and expect the inherited to return
9283      * throughout the sub-tree
9284      */
9285     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_PLUGIN_HI);
9286
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     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9316     FIB_TEST(!fib_test_validate_entry(fei,
9317                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9318                                       1,
9319                                       &adj_o_10_10_10_2),
9320              "%U via 10.10.10.2",
9321              format_fib_prefix, &pfx_10_10_10_16_s_28);
9322
9323     /*
9324      * source a covered entry in the sub-tree with the same inherting source
9325      *  - expect that it now owns the sub-tree and thus over-rides its cover
9326      */
9327     fib_table_entry_update_one_path(0,
9328                                     &pfx_10_10_10_16_s_28,
9329                                     FIB_SOURCE_API,
9330                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9331                                     DPO_PROTO_IP4,
9332                                     &nh_10_10_10_1,
9333                                     tm->hw[0]->sw_if_index,
9334                                     ~0,
9335                                     1,
9336                                     NULL,
9337                                     FIB_ROUTE_PATH_FLAG_NONE);
9338     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9339     FIB_TEST(!fib_test_validate_entry(fei,
9340                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9341                                       1,
9342                                       &adj_o_10_10_10_1),
9343              "%U via 10.10.10.1",
9344              format_fib_prefix, &pfx_10_10_10_16_s_28);
9345     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9346     FIB_TEST(!fib_test_validate_entry(fei,
9347                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9348                                       1,
9349                                       &adj_o_10_10_10_1),
9350              "%U via 10.10.10.2",
9351              format_fib_prefix, &pfx_10_10_10_22_s_32);
9352     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9353     FIB_TEST(!fib_test_validate_entry(fei,
9354                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9355                                       1,
9356                                       &adj_o_10_10_10_1),
9357              "%U via 10.10.10.2",
9358              format_fib_prefix, &pfx_10_10_10_21_s_32);
9359
9360     /* these two unaffected by the sub-tree change */
9361     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9362     FIB_TEST(!fib_test_validate_entry(fei,
9363                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9364                                       1,
9365                                       &adj_o_10_10_10_2),
9366              "%U via 10.10.10.2",
9367              format_fib_prefix, &pfx_10_10_10_255_s_32);
9368     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9369     FIB_TEST(!fib_test_validate_entry(fei,
9370                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9371                                       1,
9372                                       &adj_o_10_10_10_2),
9373              "%U via 10.10.10.2",
9374              format_fib_prefix, &pfx_10_10_10_0_s_24);
9375
9376     /*
9377      * removes the more specific, expect the /24 to now re-owns the sub-tree
9378      */
9379     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9380
9381     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9382     FIB_TEST(!fib_test_validate_entry(fei,
9383                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9384                                       1,
9385                                       &adj_o_10_10_10_2),
9386              "%U via 10.10.10.2",
9387              format_fib_prefix, &pfx_10_10_10_16_s_28);
9388     FIB_TEST(!fib_test_validate_entry(fei,
9389                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9390                                       1,
9391                                       &adj_o_10_10_10_2),
9392              "%U via 10.10.10.2",
9393              format_fib_prefix, &pfx_10_10_10_21_s_32);
9394     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9395     FIB_TEST(!fib_test_validate_entry(fei,
9396                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9397                                       1,
9398                                       &adj_o_10_10_10_2),
9399              "%U via 10.10.10.2",
9400              format_fib_prefix, &pfx_10_10_10_22_s_32);
9401     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9402     FIB_TEST(!fib_test_validate_entry(fei,
9403                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9404                                       1,
9405                                       &adj_o_10_10_10_2),
9406              "%U via 10.10.10.2",
9407              format_fib_prefix, &pfx_10_10_10_255_s_32);
9408     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9409     FIB_TEST(!fib_test_validate_entry(fei,
9410                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9411                                       1,
9412                                       &adj_o_10_10_10_2),
9413              "%U via 10.10.10.2",
9414              format_fib_prefix, &pfx_10_10_10_0_s_24);
9415     /*
9416      * modify the /24. expect the new forwarding to be pushed down
9417      */
9418     fib_table_entry_update_one_path(0,
9419                                     &pfx_10_10_10_0_s_24,
9420                                     FIB_SOURCE_API,
9421                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9422                                     DPO_PROTO_IP4,
9423                                     &nh_10_10_10_1,
9424                                     tm->hw[0]->sw_if_index,
9425                                     ~0,
9426                                     1,
9427                                     NULL,
9428                                     FIB_ROUTE_PATH_FLAG_NONE);
9429     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9430     FIB_TEST(!fib_test_validate_entry(fei,
9431                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9432                                       1,
9433                                       &adj_o_10_10_10_1),
9434              "%U via 10.10.10.1",
9435              format_fib_prefix, &pfx_10_10_10_16_s_28);
9436     FIB_TEST(!fib_test_validate_entry(fei,
9437                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9438                                       1,
9439                                       &adj_o_10_10_10_1),
9440              "%U via 10.10.10.1",
9441              format_fib_prefix, &pfx_10_10_10_21_s_32);
9442     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9443     FIB_TEST(!fib_test_validate_entry(fei,
9444                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9445                                       1,
9446                                       &adj_o_10_10_10_1),
9447              "%U via 10.10.10.1",
9448              format_fib_prefix, &pfx_10_10_10_22_s_32);
9449     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9450     FIB_TEST(!fib_test_validate_entry(fei,
9451                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9452                                       1,
9453                                       &adj_o_10_10_10_1),
9454              "%U via 10.10.10.1",
9455              format_fib_prefix, &pfx_10_10_10_255_s_32);
9456     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9457     FIB_TEST(!fib_test_validate_entry(fei,
9458                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9459                                       1,
9460                                       &adj_o_10_10_10_1),
9461              "%U via 10.10.10.1",
9462              format_fib_prefix, &pfx_10_10_10_0_s_24);
9463
9464     /*
9465      * add an entry less specific to /24. it should not own the /24's tree
9466      */
9467     const fib_prefix_t pfx_10_10_0_0_s_16 = {
9468         .fp_len = 16,
9469         .fp_proto = FIB_PROTOCOL_IP4,
9470         .fp_addr = nh_10_10_0_0,
9471     };
9472     fib_table_entry_update_one_path(0,
9473                                     &pfx_10_10_0_0_s_16,
9474                                     FIB_SOURCE_API,
9475                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9476                                     DPO_PROTO_IP4,
9477                                     &nh_10_10_10_2,
9478                                     tm->hw[0]->sw_if_index,
9479                                     ~0,
9480                                     1,
9481                                     NULL,
9482                                     FIB_ROUTE_PATH_FLAG_NONE);
9483     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9484     FIB_TEST(!fib_test_validate_entry(fei,
9485                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9486                                       1,
9487                                       &adj_o_10_10_10_1),
9488              "%U via 10.10.10.1",
9489              format_fib_prefix, &pfx_10_10_10_16_s_28);
9490     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9491     FIB_TEST(!fib_test_validate_entry(fei,
9492                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9493                                       1,
9494                                       &adj_o_10_10_10_1),
9495              "%U via 10.10.10.1",
9496              format_fib_prefix, &pfx_10_10_10_22_s_32);
9497     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9498     FIB_TEST(!fib_test_validate_entry(fei,
9499                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9500                                       1,
9501                                       &adj_o_10_10_10_1),
9502              "%U via 10.10.10.1",
9503              format_fib_prefix, &pfx_10_10_10_255_s_32);
9504     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
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_0_s_24);
9511     fei = fib_table_lookup_exact_match(0, &pfx_10_10_0_0_s_16);
9512     FIB_TEST(!fib_test_validate_entry(fei,
9513                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9514                                       1,
9515                                       &adj_o_10_10_10_2),
9516              "%U via 10.10.10.2",
9517              format_fib_prefix, &pfx_10_10_0_0_s_16);
9518
9519     /*
9520      * Add/remove an interposer source to a new /32
9521      */
9522     const fib_prefix_t pfx_11_11_11_11_s_32 = {
9523         .fp_len = 32,
9524         .fp_proto = FIB_PROTOCOL_IP4,
9525         .fp_addr = nh_11_11_11_11,
9526     };
9527
9528     fib_table_entry_update_one_path(0,
9529                                     &pfx_11_11_11_11_s_32,
9530                                     FIB_SOURCE_API,
9531                                     FIB_ENTRY_FLAG_NONE,
9532                                     DPO_PROTO_IP4,
9533                                     &nh_10_10_10_3,
9534                                     tm->hw[0]->sw_if_index,
9535                                     ~0,
9536                                     1,
9537                                     NULL,
9538                                     FIB_ROUTE_PATH_FLAG_NONE);
9539
9540     dpo_id_t interposer = DPO_INVALID;
9541     fib_mpls_label_t *l99 = NULL, fml_99 = {
9542         .fml_value = 99,
9543     };
9544     vec_add1(l99, fml_99);
9545
9546     mpls_label_dpo_create(l99,
9547                           MPLS_EOS,
9548                           DPO_PROTO_IP4,
9549                           MPLS_LABEL_DPO_FLAG_NONE,
9550                           punt_dpo_get(DPO_PROTO_MPLS),
9551                           &interposer);
9552
9553     adj_index_t ai_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9554                                                     VNET_LINK_IP4,
9555                                                     &nh_10_10_10_3,
9556                                                     tm->hw[0]->sw_if_index);
9557     fib_test_lb_bucket_t adj_o_10_10_10_3 = {
9558         .type = FT_LB_ADJ,
9559         .adj = {
9560             .adj = ai_10_10_10_3,
9561         },
9562     };
9563     fib_test_lb_bucket_t l99_o_10_10_10_3 = {
9564         .type = FT_LB_LABEL_O_ADJ,
9565         .label_o_adj = {
9566             .adj = ai_10_10_10_3,
9567             .label = 99,
9568             .eos = MPLS_EOS,
9569         },
9570     };
9571
9572     fei = fib_table_entry_special_dpo_add(0,
9573                                           &pfx_11_11_11_11_s_32,
9574                                           FIB_SOURCE_SPECIAL,
9575                                           FIB_ENTRY_FLAG_INTERPOSE,
9576                                           &interposer);
9577     FIB_TEST(!fib_test_validate_entry(fei,
9578                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9579                                       1,
9580                                       &l99_o_10_10_10_3),
9581              "%U via interposer adj",
9582              format_fib_prefix,&pfx_11_11_11_11_s_32);
9583
9584     fib_table_entry_special_remove(0,
9585                                    &pfx_11_11_11_11_s_32,
9586                                    FIB_SOURCE_SPECIAL);
9587     FIB_TEST(!fib_test_validate_entry(fei,
9588                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9589                                       1,
9590                                       &adj_o_10_10_10_3),
9591              "%U via 10.10.10.1",
9592              format_fib_prefix, &pfx_11_11_11_11_s_32);
9593
9594     /*
9595      * remove and re-add the second best API source while the interpose
9596      * is present
9597      */
9598     fei = fib_table_entry_special_dpo_add(0,
9599                                           &pfx_11_11_11_11_s_32,
9600                                           FIB_SOURCE_SPECIAL,
9601                                           FIB_ENTRY_FLAG_INTERPOSE,
9602                                           &interposer);
9603     FIB_TEST(!fib_test_validate_entry(fei,
9604                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9605                                       1,
9606                                       &l99_o_10_10_10_3),
9607              "%U via interposer adj",
9608              format_fib_prefix,&pfx_11_11_11_11_s_32);
9609
9610     FIB_TEST(2 == pool_elts(mpls_label_dpo_pool),
9611              "MPLS label pool: %d",
9612              pool_elts(mpls_label_dpo_pool));
9613
9614     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9615
9616     /*
9617      * the interpose does not get stacked when there are not valid paths
9618      */
9619     fib_test_lb_bucket_t bucket_drop = {
9620         .type = FT_LB_DROP,
9621         .special = {
9622             .adj = DPO_PROTO_IP4,
9623         },
9624     };
9625     FIB_TEST(!fib_test_validate_entry(fei,
9626                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9627                                       1,
9628                                       &bucket_drop),
9629              "%U via drop",
9630              format_fib_prefix,&pfx_11_11_11_11_s_32);
9631
9632     fib_table_entry_update_one_path(0,
9633                                     &pfx_11_11_11_11_s_32,
9634                                     FIB_SOURCE_API,
9635                                     FIB_ENTRY_FLAG_NONE,
9636                                     DPO_PROTO_IP4,
9637                                     &nh_10_10_10_3,
9638                                     tm->hw[0]->sw_if_index,
9639                                     ~0,
9640                                     1,
9641                                     NULL,
9642                                     FIB_ROUTE_PATH_FLAG_NONE);
9643     FIB_TEST(!fib_test_validate_entry(fei,
9644                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9645                                       1,
9646                                       &l99_o_10_10_10_3),
9647              "%U via interposer adj",
9648              format_fib_prefix,&pfx_11_11_11_11_s_32);
9649     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9650
9651     /*
9652      * add a cover for the interposed entry, so that we test it selects
9653      * the covers forwarding.
9654      */
9655     const fib_prefix_t pfx_11_11_11_0_s_24 = {
9656         .fp_len = 24,
9657         .fp_proto = FIB_PROTOCOL_IP4,
9658         .fp_addr = nh_11_11_11_0,
9659     };
9660     fib_table_entry_update_one_path(0,
9661                                     &pfx_11_11_11_0_s_24,
9662                                     FIB_SOURCE_API,
9663                                     FIB_ENTRY_FLAG_NONE,
9664                                     DPO_PROTO_IP4,
9665                                     &nh_10_10_10_3,
9666                                     tm->hw[0]->sw_if_index,
9667                                     ~0,
9668                                     1,
9669                                     NULL,
9670                                     FIB_ROUTE_PATH_FLAG_NONE);
9671     FIB_TEST(!fib_test_validate_entry(fei,
9672                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9673                                       1,
9674                                       &l99_o_10_10_10_3),
9675              "%U via interposer adj",
9676              format_fib_prefix,&pfx_11_11_11_11_s_32);
9677
9678     /*
9679      * multiple interpose sources on the same entry. Only the high
9680      * priority source gets to add the interpose.
9681      */
9682     dpo_id_t interposer2 = DPO_INVALID;
9683     fib_mpls_label_t *l100 = NULL, fml_100 = {
9684         .fml_value = 100,
9685     };
9686     vec_add1(l100, fml_100);
9687
9688     mpls_label_dpo_create(l100,
9689                           MPLS_EOS,
9690                           DPO_PROTO_IP4,
9691                           MPLS_LABEL_DPO_FLAG_NONE,
9692                           punt_dpo_get(DPO_PROTO_MPLS),
9693                           &interposer2);
9694
9695     fei = fib_table_entry_special_dpo_add(0,
9696                                           &pfx_11_11_11_11_s_32,
9697                                           FIB_SOURCE_CLASSIFY,
9698                                           FIB_ENTRY_FLAG_INTERPOSE,
9699                                           &interposer2);
9700     FIB_TEST(!fib_test_validate_entry(fei,
9701                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9702                                       1,
9703                                       &l99_o_10_10_10_3),
9704              "%U via interposer label 99",
9705              format_fib_prefix,&pfx_11_11_11_11_s_32);
9706
9707     fib_test_lb_bucket_t l100_o_10_10_10_3 = {
9708         .type = FT_LB_LABEL_O_ADJ,
9709         .label_o_adj = {
9710             .adj = ai_10_10_10_3,
9711             .label = 100,
9712             .eos = MPLS_EOS,
9713         },
9714     };
9715
9716     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_SPECIAL);
9717
9718     FIB_TEST(!fib_test_validate_entry(fei,
9719                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9720                                       1,
9721                                       &l100_o_10_10_10_3),
9722              "%U via interposer label 99",
9723              format_fib_prefix,&pfx_11_11_11_11_s_32);
9724
9725     fib_table_entry_delete(0, &pfx_11_11_11_0_s_24, FIB_SOURCE_API);
9726     FIB_TEST(!fib_test_validate_entry(fei,
9727                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9728                                       1,
9729                                       &bucket_drop),
9730              "%U via drop",
9731              format_fib_prefix,&pfx_11_11_11_11_s_32);
9732     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_CLASSIFY);
9733
9734     /*
9735      * update a source to/from interpose.
9736      */
9737     /* fib_table_entry_update_one_path(0, */
9738     /*                                 &pfx_11_11_11_0_s_24, */
9739     /*                              FIB_SOURCE_API, */
9740     /*                              FIB_ENTRY_FLAG_NONE, */
9741     /*                              DPO_PROTO_IP4, */
9742     /*                                 &nh_10_10_10_3, */
9743     /*                              tm->hw[0]->sw_if_index, */
9744     /*                              ~0, */
9745     /*                              1, */
9746     /*                              NULL, */
9747     /*                              FIB_ROUTE_PATH_FLAG_NONE); */
9748     /* fei = fib_table_entry_special_dpo_add(0, */
9749     /*                                       &pfx_11_11_11_11_s_32, */
9750     /*                                       FIB_SOURCE_API, */
9751     /*                                       FIB_ENTRY_FLAG_INTERPOSE, */
9752     /*                                       &interposer); */
9753     /* FIB_TEST(!fib_test_validate_entry(fei, */
9754     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
9755     /*                                   1, */
9756     /*                                   &l99_o_10_10_10_3), */
9757     /*          "%U via interposer label 99", */
9758     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
9759
9760     /* FIB_TEST(3 == pool_elts(mpls_label_dpo_pool), */
9761     /*          "MPLS label pool: %d", */
9762     /*          pool_elts(mpls_label_dpo_pool)); */
9763     /* FIB_TEST((2 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
9764     /*          "Interposer %d locks", */
9765     /*          mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
9766
9767     /* fib_table_entry_update_one_path(0, */
9768     /*                                 &pfx_11_11_11_11_s_32, */
9769     /*                              FIB_SOURCE_API, */
9770     /*                              FIB_ENTRY_FLAG_NONE, */
9771     /*                              DPO_PROTO_IP4, */
9772     /*                                 &nh_10_10_10_2, */
9773     /*                              tm->hw[0]->sw_if_index, */
9774     /*                              ~0, */
9775     /*                              1, */
9776     /*                              NULL, */
9777     /*                              FIB_ROUTE_PATH_FLAG_NONE); */
9778     /* FIB_TEST(!fib_test_validate_entry(fei, */
9779     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
9780     /*                                   1, */
9781     /*                                   &adj_o_10_10_10_2), */
9782     /*          "%U via 10.10.10.2", */
9783     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
9784
9785     /* FIB_TEST((1 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
9786     /*          "Interposer %d locks", */
9787     /*          mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
9788     /* FIB_TEST(2 == pool_elts(mpls_label_dpo_pool), */
9789     /*          "MPLS label pool: %d", */
9790     /*          pool_elts(mpls_label_dpo_pool)); */
9791
9792     /* fei = fib_table_entry_special_dpo_add(0, */
9793     /*                                       &pfx_11_11_11_11_s_32, */
9794     /*                                       FIB_SOURCE_API, */
9795     /*                                       FIB_ENTRY_FLAG_INTERPOSE, */
9796     /*                                       &interposer); */
9797     /* FIB_TEST(!fib_test_validate_entry(fei, */
9798     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
9799     /*                                   1, */
9800     /*                                   &l99_o_10_10_10_3), */
9801     /*          "%U via interposer label 99", */
9802     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
9803
9804     /* fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API); */
9805
9806     /*
9807      * Add/remove an interposer source from the top of the subtrie. The
9808      * interposer source is not inherited.
9809      */
9810     fib_table_entry_update_one_path(0,
9811                                     &pfx_10_10_10_0_s_24,
9812                                     FIB_SOURCE_API,
9813                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9814                                     DPO_PROTO_IP4,
9815                                     &nh_10_10_10_3,
9816                                     tm->hw[0]->sw_if_index,
9817                                     ~0,
9818                                     1,
9819                                     NULL,
9820                                     FIB_ROUTE_PATH_FLAG_NONE);
9821     fei = fib_table_entry_special_dpo_add(0,
9822                                           &pfx_10_10_10_0_s_24,
9823                                           FIB_SOURCE_SPECIAL,
9824                                           FIB_ENTRY_FLAG_INTERPOSE,
9825                                           &interposer);
9826     FIB_TEST(!fib_test_validate_entry(fei,
9827                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9828                                       1,
9829                                       &l99_o_10_10_10_3),
9830              "%U via interposer label",
9831              format_fib_prefix,&pfx_10_10_10_0_s_24);
9832     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9833     FIB_TEST(!fib_test_validate_entry(fei,
9834                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9835                                       1,
9836                                       &bucket_drop),
9837              "%U via drop",
9838              format_fib_prefix, &pfx_10_10_10_21_s_32);
9839
9840     fib_table_entry_special_remove(0,
9841                                    &pfx_10_10_10_0_s_24,
9842                                    FIB_SOURCE_SPECIAL);
9843     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9844     FIB_TEST(!fib_test_validate_entry(fei,
9845                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9846                                       1,
9847                                       &adj_o_10_10_10_3),
9848              "%U via 10.10.10.1",
9849              format_fib_prefix, &pfx_10_10_10_0_s_24);
9850     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9851     FIB_TEST(!fib_test_validate_entry(fei,
9852                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9853                                       1,
9854                                       &adj_o_10_10_10_3),
9855              "%U via via 10.10.10.1",
9856              format_fib_prefix, &pfx_10_10_10_21_s_32);
9857
9858     /*
9859      * Add/remove an interposer source from the top of the subtrie. The
9860      * interposer source is inherited.
9861      */
9862     fei = fib_table_entry_special_dpo_add(0,
9863                                           &pfx_10_10_10_0_s_24,
9864                                           FIB_SOURCE_SPECIAL,
9865                                           (FIB_ENTRY_FLAG_COVERED_INHERIT |
9866                                            FIB_ENTRY_FLAG_INTERPOSE),
9867                                           &interposer);
9868     FIB_TEST(!fib_test_validate_entry(fei,
9869                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9870                                       1,
9871                                       &l99_o_10_10_10_3),
9872              "%U via interposer label",
9873              format_fib_prefix,&pfx_10_10_10_0_s_24);
9874
9875     /* interposer gets forwarding from the drop cli source */
9876     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9877     FIB_TEST(!fib_test_validate_entry(fei,
9878                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9879                                       1,
9880                                       &bucket_drop),
9881              "%U via drop",
9882              format_fib_prefix,&pfx_10_10_10_21_s_32);
9883
9884     fib_table_entry_update_one_path(0,
9885                                     &pfx_10_10_10_21_s_32,
9886                                     FIB_SOURCE_API,
9887                                     FIB_ENTRY_FLAG_NONE,
9888                                     DPO_PROTO_IP4,
9889                                     &nh_10_10_10_3,
9890                                     tm->hw[0]->sw_if_index,
9891                                     ~0,
9892                                     1,
9893                                     NULL,
9894                                     FIB_ROUTE_PATH_FLAG_NONE);
9895     fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_CLI);
9896     /* interposer gets forwarding from the API source */
9897     FIB_TEST(!fib_test_validate_entry(fei,
9898                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9899                                       1,
9900                                       &l99_o_10_10_10_3),
9901              "%U via interposer label",
9902              format_fib_prefix,&pfx_10_10_10_21_s_32);
9903
9904     /*
9905      * cleanup
9906      */
9907     fib_table_entry_delete(0, &pfx_10_10_10_22_s_32, FIB_SOURCE_CLI);
9908     fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_API);
9909     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_CLI);
9910     fib_table_entry_delete(0, &pfx_10_10_10_255_s_32, FIB_SOURCE_CLI);
9911     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_API);
9912     fib_table_entry_delete(0, &pfx_10_10_0_0_s_16, FIB_SOURCE_API);
9913     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_SPECIAL);
9914     adj_unlock(ai_10_10_10_1);
9915     adj_unlock(ai_10_10_10_2);
9916     adj_unlock(ai_10_10_10_3);
9917     dpo_reset(&interposer);
9918     dpo_reset(&interposer2);
9919     FIB_TEST(0 == pool_elts(mpls_label_dpo_pool),
9920              "MPLS label pool empty: %d",
9921              pool_elts(mpls_label_dpo_pool));
9922     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
9923     FIB_TEST(N_PLS == fib_path_list_pool_size(),
9924              "number of path-lists: %d = %d",
9925              N_PLS, fib_path_list_pool_size());
9926
9927     /*
9928      * test the v6 tree walk.
9929      * a /64 that covers everything. a /96 that covers one /128
9930      * a second /128 covered only by the /64.
9931      */
9932     const fib_prefix_t pfx_2001_s_64 = {
9933         .fp_len = 64,
9934         .fp_proto = FIB_PROTOCOL_IP6,
9935         .fp_addr = {
9936             .ip6 = {
9937                 .as_u64 = {
9938                     [0] = clib_host_to_net_u64(0x2001000000000000),
9939                     [1] = clib_host_to_net_u64(0x0000000000000000),
9940                 },
9941             },
9942         },
9943     };
9944     const fib_prefix_t pfx_2001_1_s_96 = {
9945         .fp_len = 96,
9946         .fp_proto = FIB_PROTOCOL_IP6,
9947         .fp_addr = {
9948             .ip6 = {
9949                 .as_u64 = {
9950                     [0] = clib_host_to_net_u64(0x2001000000000000),
9951                     [1] = clib_host_to_net_u64(0x1000000000000000),
9952                 },
9953             },
9954         },
9955     };
9956     const fib_prefix_t pfx_2001_1_1_s_128 = {
9957         .fp_len = 128,
9958         .fp_proto = FIB_PROTOCOL_IP6,
9959         .fp_addr = {
9960             .ip6 = {
9961                 .as_u64 = {
9962                     [0] = clib_host_to_net_u64(0x2001000000000000),
9963                     [1] = clib_host_to_net_u64(0x1000000000000001),
9964                 },
9965             },
9966         },
9967     };
9968     const fib_prefix_t pfx_2001_0_1_s_128 = {
9969         .fp_len = 128,
9970         .fp_proto = FIB_PROTOCOL_IP6,
9971         .fp_addr = {
9972             .ip6 = {
9973                 .as_u64 = {
9974                     [0] = clib_host_to_net_u64(0x2001000000000000),
9975                     [1] = clib_host_to_net_u64(0x0000000000000001),
9976                 },
9977             },
9978         },
9979     };
9980     const ip46_address_t nh_3000_1 = {
9981         .ip6 = {
9982             .as_u64 = {
9983                 [0] = clib_host_to_net_u64(0x3000000000000000),
9984                 [1] = clib_host_to_net_u64(0x0000000000000001),
9985             },
9986         },
9987     };
9988     const ip46_address_t nh_3000_2 = {
9989         .ip6 = {
9990             .as_u64 = {
9991                 [0] = clib_host_to_net_u64(0x3000000000000000),
9992                 [1] = clib_host_to_net_u64(0x0000000000000002),
9993             },
9994         },
9995     };
9996     adj_index_t ai_3000_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
9997                                                 VNET_LINK_IP6,
9998                                                 &nh_3000_1,
9999                                                 tm->hw[0]->sw_if_index);
10000     adj_index_t ai_3000_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
10001                                                 VNET_LINK_IP6,
10002                                                 &nh_3000_2,
10003                                                 tm->hw[0]->sw_if_index);
10004     fib_test_lb_bucket_t adj_o_3000_1 = {
10005         .type = FT_LB_ADJ,
10006         .adj = {
10007             .adj = ai_3000_1,
10008         },
10009     };
10010     fib_test_lb_bucket_t adj_o_3000_2 = {
10011         .type = FT_LB_ADJ,
10012         .adj = {
10013             .adj = ai_3000_2,
10014         },
10015     };
10016
10017     fib_table_entry_special_add(0,
10018                                 &pfx_2001_0_1_s_128,
10019                                 FIB_SOURCE_CLI,
10020                                 FIB_ENTRY_FLAG_DROP);
10021     fib_table_entry_special_add(0,
10022                                 &pfx_2001_1_1_s_128,
10023                                 FIB_SOURCE_CLI,
10024                                 FIB_ENTRY_FLAG_DROP);
10025
10026     /*
10027      * /96 has inherited forwarding pushed down to its covered /128
10028      */
10029     fib_table_entry_update_one_path(0,
10030                                     &pfx_2001_1_s_96,
10031                                     FIB_SOURCE_API,
10032                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
10033                                     DPO_PROTO_IP6,
10034                                     &nh_3000_1,
10035                                     tm->hw[0]->sw_if_index,
10036                                     ~0,
10037                                     1,
10038                                     NULL,
10039                                     FIB_ROUTE_PATH_FLAG_NONE);
10040     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
10041     FIB_TEST(!fib_test_validate_entry(fei,
10042                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10043                                       1,
10044                                       &adj_o_3000_1),
10045              "%U via 3000::1",
10046              format_fib_prefix, &pfx_2001_1_s_96);
10047     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
10048     FIB_TEST(!fib_test_validate_entry(fei,
10049                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10050                                       1,
10051                                       &adj_o_3000_1),
10052              "%U via 3000::1",
10053              format_fib_prefix, &pfx_2001_1_1_s_128);
10054     fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
10055     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
10056              "%U resolves via drop",
10057              format_fib_prefix, &pfx_2001_0_1_s_128);
10058
10059     /*
10060      * /64 has inherited forwarding pushed down to all, but the /96
10061      * and its sub-tree remain unaffected.
10062      */
10063     fib_table_entry_update_one_path(0,
10064                                     &pfx_2001_s_64,
10065                                     FIB_SOURCE_API,
10066                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
10067                                     DPO_PROTO_IP6,
10068                                     &nh_3000_2,
10069                                     tm->hw[0]->sw_if_index,
10070                                     ~0,
10071                                     1,
10072                                     NULL,
10073                                     FIB_ROUTE_PATH_FLAG_NONE);
10074
10075     fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
10076     FIB_TEST(!fib_test_validate_entry(fei,
10077                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10078                                       1,
10079                                       &adj_o_3000_2),
10080              "%U via 3000::2",
10081              format_fib_prefix, &pfx_2001_s_64);
10082     fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
10083     FIB_TEST(!fib_test_validate_entry(fei,
10084                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10085                                       1,
10086                                       &adj_o_3000_2),
10087              "%U via 3000::1",
10088              format_fib_prefix, &pfx_2001_0_1_s_128);
10089
10090     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
10091     FIB_TEST(!fib_test_validate_entry(fei,
10092                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10093                                       1,
10094                                       &adj_o_3000_1),
10095              "%U via 3000::1",
10096              format_fib_prefix, &pfx_2001_1_s_96);
10097     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
10098     FIB_TEST(!fib_test_validate_entry(fei,
10099                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10100                                       1,
10101                                       &adj_o_3000_1),
10102              "%U via 3000::1",
10103              format_fib_prefix, &pfx_2001_1_1_s_128);
10104
10105     /*
10106      * Cleanup
10107      */
10108     fib_table_entry_delete(0, &pfx_2001_0_1_s_128, FIB_SOURCE_CLI);
10109     fib_table_entry_delete(0, &pfx_2001_1_1_s_128, FIB_SOURCE_CLI);
10110     fib_table_entry_delete(0, &pfx_2001_s_64,      FIB_SOURCE_API);
10111     fib_table_entry_delete(0, &pfx_2001_1_s_96,    FIB_SOURCE_API);
10112     adj_unlock(ai_3000_1);
10113     adj_unlock(ai_3000_2);
10114
10115     /*
10116      * test no-one left behind
10117      */
10118     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
10119     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
10120
10121     return (res);
10122 }
10123
10124 static int
10125 fib_test_sticky (void)
10126 {
10127     fib_route_path_t *r_paths = NULL;
10128     test_main_t *tm = &test_main;
10129     u32 ii, lb_count, pl_count;
10130     dpo_id_t dpo = DPO_INVALID;
10131     fib_node_index_t pl_index;
10132     int res = 0;
10133 #define N_PATHS 16
10134
10135     fib_test_lb_bucket_t buckets[N_PATHS];
10136     bfd_session_t bfds[N_PATHS] = {{0}};
10137
10138     lb_count = pool_elts(load_balance_pool);
10139     pl_count = fib_path_list_pool_size();
10140
10141     for (ii = 0; ii < N_PATHS; ii++)
10142     {
10143         ip46_address_t nh = {
10144             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
10145         };
10146         adj_index_t ai;
10147
10148         ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
10149                                  VNET_LINK_IP4,
10150                                  &nh, tm->hw[0]->sw_if_index);
10151
10152         buckets[ii].type = FT_LB_ADJ;
10153         buckets[ii].adj.adj = ai;
10154
10155         bfds[ii].udp.key.peer_addr = nh;
10156         bfds[ii].udp.key.sw_if_index = tm->hw[0]->sw_if_index;
10157         bfds[ii].hop_type = BFD_HOP_TYPE_SINGLE;
10158         bfds[ii].local_state = BFD_STATE_init;
10159         adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfds[ii]);
10160         bfds[ii].local_state = BFD_STATE_up;
10161         adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[ii]);
10162     }
10163
10164     for (ii = 0; ii < N_PATHS; ii++)
10165     {
10166         fib_route_path_t r_path = {
10167             .frp_proto = DPO_PROTO_IP4,
10168             .frp_addr = {
10169                 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
10170             },
10171             .frp_sw_if_index = tm->hw[0]->sw_if_index,
10172             .frp_weight = 1,
10173             .frp_fib_index = ~0,
10174         };
10175         vec_add1(r_paths, r_path);
10176     };
10177
10178     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths);
10179     fib_path_list_lock(pl_index);
10180
10181     fib_path_list_contribute_forwarding(pl_index,
10182                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10183                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10184                                         &dpo);
10185
10186     FIB_TEST(!fib_test_validate_lb(&dpo,
10187                                    16,
10188                                    &buckets[0],
10189                                    &buckets[1],
10190                                    &buckets[2],
10191                                    &buckets[3],
10192                                    &buckets[4],
10193                                    &buckets[5],
10194                                    &buckets[6],
10195                                    &buckets[7],
10196                                    &buckets[8],
10197                                    &buckets[9],
10198                                    &buckets[10],
10199                                    &buckets[11],
10200                                    &buckets[12],
10201                                    &buckets[13],
10202                                    &buckets[14],
10203                                    &buckets[15]),
10204              "Setup OK");
10205
10206     /* take down paths */
10207     bfds[0].local_state = BFD_STATE_down;
10208     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
10209
10210     fib_path_list_contribute_forwarding(pl_index,
10211                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10212                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10213                                         &dpo);
10214
10215     FIB_TEST(!fib_test_validate_lb(&dpo,
10216                                    16,
10217                                    &buckets[1],
10218                                    &buckets[1],
10219                                    &buckets[2],
10220                                    &buckets[3],
10221                                    &buckets[4],
10222                                    &buckets[5],
10223                                    &buckets[6],
10224                                    &buckets[7],
10225                                    &buckets[8],
10226                                    &buckets[9],
10227                                    &buckets[10],
10228                                    &buckets[11],
10229                                    &buckets[12],
10230                                    &buckets[13],
10231                                    &buckets[14],
10232                                    &buckets[15]),
10233              "Failed at shut-down path 0");
10234
10235     bfds[7].local_state = BFD_STATE_down;
10236     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
10237
10238     fib_path_list_contribute_forwarding(pl_index,
10239                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10240                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10241                                         &dpo);
10242
10243     FIB_TEST(!fib_test_validate_lb(&dpo,
10244                                    16,
10245                                    &buckets[1],
10246                                    &buckets[1],
10247                                    &buckets[2],
10248                                    &buckets[3],
10249                                    &buckets[4],
10250                                    &buckets[5],
10251                                    &buckets[6],
10252                                    &buckets[2],
10253                                    &buckets[8],
10254                                    &buckets[9],
10255                                    &buckets[10],
10256                                    &buckets[11],
10257                                    &buckets[12],
10258                                    &buckets[13],
10259                                    &buckets[14],
10260                                    &buckets[15]),
10261              "Failed at shut-down path 7");
10262
10263     /* paths back up */
10264     bfds[0].local_state = BFD_STATE_up;
10265     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
10266     bfds[7].local_state = BFD_STATE_up;
10267     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
10268
10269     fib_path_list_contribute_forwarding(pl_index,
10270                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10271                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10272                                         &dpo);
10273
10274     FIB_TEST(!fib_test_validate_lb(&dpo,
10275                                    16,
10276                                    &buckets[0],
10277                                    &buckets[1],
10278                                    &buckets[2],
10279                                    &buckets[3],
10280                                    &buckets[4],
10281                                    &buckets[5],
10282                                    &buckets[6],
10283                                    &buckets[7],
10284                                    &buckets[8],
10285                                    &buckets[9],
10286                                    &buckets[10],
10287                                    &buckets[11],
10288                                    &buckets[12],
10289                                    &buckets[13],
10290                                    &buckets[14],
10291                                    &buckets[15]),
10292              "recovery OK");
10293
10294     fib_path_list_unlock(pl_index);
10295
10296     /*
10297      * non-power of 2 number of buckets
10298      */
10299     fib_route_path_t *r_paths2 = NULL;
10300
10301     r_paths2 = vec_dup(r_paths);
10302     _vec_len(r_paths2) = 3;
10303
10304     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths2);
10305     fib_path_list_lock(pl_index);
10306
10307     fib_path_list_contribute_forwarding(pl_index,
10308                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10309                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10310                                         &dpo);
10311
10312     FIB_TEST(!fib_test_validate_lb(&dpo,
10313                                    16,
10314                                    &buckets[0],
10315                                    &buckets[0],
10316                                    &buckets[0],
10317                                    &buckets[0],
10318                                    &buckets[0],
10319                                    &buckets[0],
10320                                    &buckets[1],
10321                                    &buckets[1],
10322                                    &buckets[1],
10323                                    &buckets[1],
10324                                    &buckets[1],
10325                                    &buckets[2],
10326                                    &buckets[2],
10327                                    &buckets[2],
10328                                    &buckets[2],
10329                                    &buckets[2]),
10330              "non-power of 2");
10331
10332     bfds[1].local_state = BFD_STATE_down;
10333     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10334
10335     fib_path_list_contribute_forwarding(pl_index,
10336                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10337                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10338                                         &dpo);
10339
10340     /*
10341      * path 1's buckets alternate between path 0 and 2
10342      */
10343     FIB_TEST(!fib_test_validate_lb(&dpo,
10344                                    16,
10345                                    &buckets[0],
10346                                    &buckets[0],
10347                                    &buckets[0],
10348                                    &buckets[0],
10349                                    &buckets[0],
10350                                    &buckets[0],
10351                                    &buckets[0],
10352                                    &buckets[2],
10353                                    &buckets[0],
10354                                    &buckets[2],
10355                                    &buckets[0],
10356                                    &buckets[2],
10357                                    &buckets[2],
10358                                    &buckets[2],
10359                                    &buckets[2],
10360                                    &buckets[2]),
10361              "non-power of 2");
10362     bfds[1].local_state = BFD_STATE_up;
10363     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10364
10365     fib_path_list_unlock(pl_index);
10366
10367     /*
10368      * unequal cost
10369      */
10370     fib_route_path_t *r_paths3 = NULL;
10371
10372     r_paths3 = vec_dup(r_paths);
10373     _vec_len(r_paths3) = 3;
10374
10375     r_paths3[0].frp_weight = 3;
10376
10377     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths3);
10378     fib_path_list_lock(pl_index);
10379
10380     fib_path_list_contribute_forwarding(pl_index,
10381                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10382                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10383                                         &dpo);
10384
10385     FIB_TEST(!fib_test_validate_lb(&dpo,
10386                                    16,
10387                                    &buckets[1],
10388                                    &buckets[1],
10389                                    &buckets[1],
10390                                    &buckets[2],
10391                                    &buckets[2],
10392                                    &buckets[2],
10393                                    &buckets[0],
10394                                    &buckets[0],
10395                                    &buckets[0],
10396                                    &buckets[0],
10397                                    &buckets[0],
10398                                    &buckets[0],
10399                                    &buckets[0],
10400                                    &buckets[0],
10401                                    &buckets[0],
10402                                    &buckets[0]),
10403              "UCMP");
10404
10405     bfds[1].local_state = BFD_STATE_down;
10406     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10407
10408     fib_path_list_contribute_forwarding(pl_index,
10409                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10410                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10411                                         &dpo);
10412     /* No attempt to Un-equal distribute the down path's buckets */
10413     FIB_TEST(!fib_test_validate_lb(&dpo,
10414                                    16,
10415                                    &buckets[2],
10416                                    &buckets[0],
10417                                    &buckets[2],
10418                                    &buckets[2],
10419                                    &buckets[2],
10420                                    &buckets[2],
10421                                    &buckets[0],
10422                                    &buckets[0],
10423                                    &buckets[0],
10424                                    &buckets[0],
10425                                    &buckets[0],
10426                                    &buckets[0],
10427                                    &buckets[0],
10428                                    &buckets[0],
10429                                    &buckets[0],
10430                                    &buckets[0]),
10431              "UCMP");
10432     bfds[1].local_state = BFD_STATE_up;
10433     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10434
10435     dpo_reset(&dpo);
10436     fib_path_list_unlock(pl_index);
10437
10438     vec_free(r_paths);
10439     vec_free(r_paths2);
10440     vec_free(r_paths3);
10441
10442     FIB_TEST(lb_count == pool_elts(load_balance_pool), "no leaked LBs");
10443     FIB_TEST(pl_count == fib_path_list_pool_size(), "no leaked PLs");
10444
10445     return 0;
10446 }
10447
10448 static clib_error_t *
10449 fib_test (vlib_main_t * vm,
10450           unformat_input_t * input,
10451           vlib_cli_command_t * cmd_arg)
10452 {
10453     int res;
10454
10455     res = 0;
10456
10457     fib_test_mk_intf(4);
10458
10459     if (unformat (input, "debug"))
10460     {
10461         fib_test_do_debug = 1;
10462     }
10463
10464     if (unformat (input, "ip4"))
10465     {
10466         res += fib_test_v4();
10467     }
10468     else if (unformat (input, "ip6"))
10469     {
10470         res += fib_test_v6();
10471     }
10472     else if (unformat (input, "ip"))
10473     {
10474         res += fib_test_v4();
10475         res += fib_test_v6();
10476     }
10477     else if (unformat (input, "label"))
10478     {
10479         res += fib_test_label();
10480     }
10481     else if (unformat (input, "ae"))
10482     {
10483         res += fib_test_ae();
10484     }
10485     else if (unformat (input, "pref"))
10486     {
10487         res += fib_test_pref();
10488     }
10489     else if (unformat (input, "lfib"))
10490     {
10491         res += lfib_test();
10492     }
10493     else if (unformat (input, "walk"))
10494     {
10495         res += fib_test_walk();
10496     }
10497     else if (unformat (input, "bfd"))
10498     {
10499         res += fib_test_bfd();
10500     }
10501     else if (unformat (input, "inherit"))
10502     {
10503         res += fib_test_inherit();
10504     }
10505     else if (unformat (input, "sticky"))
10506     {
10507         res += fib_test_sticky();
10508     }
10509     else
10510     {
10511         res += fib_test_v4();
10512         res += fib_test_v6();
10513         res += fib_test_ae();
10514         res += fib_test_bfd();
10515         res += fib_test_pref();
10516         res += fib_test_label();
10517         res += fib_test_inherit();
10518         res += lfib_test();
10519
10520         /*
10521          * fib-walk process must be disabled in order for the walk tests to work
10522          */
10523         fib_walk_process_disable();
10524         res += fib_test_walk();
10525         fib_walk_process_enable();
10526     }
10527
10528     fflush(NULL);
10529     if (res)
10530     {
10531         return clib_error_return(0, "FIB Unit Test Failed");
10532     }
10533     else
10534     {
10535         return (NULL);
10536     }
10537 }
10538
10539 VLIB_CLI_COMMAND (test_fib_command, static) = {
10540     .path = "test fib",
10541     .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
10542     .function = fib_test,
10543 };
10544
10545 clib_error_t *
10546 fib_test_init (vlib_main_t *vm)
10547 {
10548     return 0;
10549 }
10550
10551 VLIB_INIT_FUNCTION (fib_test_init);