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