ip: Path MTU
[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;
5873     ip4_main_t *im;
5874     int res, i;
5875
5876     tm = &test_main;
5877     im = &ip4_main;
5878     res = 0;
5879
5880     const fib_prefix_t pfx_1_1_1_1_s_32 = {
5881         .fp_len = 32,
5882         .fp_proto = FIB_PROTOCOL_IP4,
5883         .fp_addr = {
5884             .ip4 = {
5885                 .as_u32 = clib_host_to_net_u32(0x01010101),
5886             },
5887         },
5888     };
5889
5890     vec_validate(im->fib_index_by_sw_if_index, tm->hw[2]->sw_if_index);
5891
5892     for (i = 0; i <= 2; i++)
5893         im->fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
5894
5895     /*
5896      * 2 high, 2 medium and 2 low preference non-recursive paths
5897      */
5898     fib_route_path_t nr_path_hi_1 = {
5899         .frp_proto = DPO_PROTO_IP4,
5900         .frp_sw_if_index = tm->hw[0]->sw_if_index,
5901         .frp_fib_index = ~0,
5902         .frp_weight = 1,
5903         .frp_preference = 0,
5904         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5905         .frp_addr = {
5906             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5907         },
5908     };
5909     fib_route_path_t nr_path_hi_2 = {
5910         .frp_proto = DPO_PROTO_IP4,
5911         .frp_sw_if_index = tm->hw[0]->sw_if_index,
5912         .frp_fib_index = ~0,
5913         .frp_weight = 1,
5914         .frp_preference = 0,
5915         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5916         .frp_addr = {
5917             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5918         },
5919     };
5920     fib_route_path_t nr_path_med_1 = {
5921         .frp_proto = DPO_PROTO_IP4,
5922         .frp_sw_if_index = tm->hw[1]->sw_if_index,
5923         .frp_fib_index = ~0,
5924         .frp_weight = 1,
5925         .frp_preference = 1,
5926         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5927         .frp_addr = {
5928             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5929         },
5930     };
5931     fib_route_path_t nr_path_med_2 = {
5932         .frp_proto = DPO_PROTO_IP4,
5933         .frp_sw_if_index = tm->hw[1]->sw_if_index,
5934         .frp_fib_index = ~0,
5935         .frp_weight = 1,
5936         .frp_preference = 1,
5937         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5938         .frp_addr = {
5939             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5940         },
5941     };
5942     fib_route_path_t nr_path_low_1 = {
5943         .frp_proto = DPO_PROTO_IP4,
5944         .frp_sw_if_index = tm->hw[2]->sw_if_index,
5945         .frp_fib_index = ~0,
5946         .frp_weight = 1,
5947         .frp_preference = 2,
5948         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5949         .frp_addr = {
5950             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5951         },
5952     };
5953     fib_route_path_t nr_path_low_2 = {
5954         .frp_proto = DPO_PROTO_IP4,
5955         .frp_sw_if_index = tm->hw[2]->sw_if_index,
5956         .frp_fib_index = ~0,
5957         .frp_weight = 1,
5958         .frp_preference = 2,
5959         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5960         .frp_addr = {
5961             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5962         },
5963     };
5964     fib_route_path_t *nr_paths = NULL;
5965
5966     vec_add1(nr_paths, nr_path_hi_1);
5967     vec_add1(nr_paths, nr_path_hi_2);
5968     vec_add1(nr_paths, nr_path_med_1);
5969     vec_add1(nr_paths, nr_path_med_2);
5970     vec_add1(nr_paths, nr_path_low_1);
5971     vec_add1(nr_paths, nr_path_low_2);
5972
5973     adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5974                                               VNET_LINK_IP4,
5975                                               &nr_path_hi_1.frp_addr,
5976                                               nr_path_hi_1.frp_sw_if_index);
5977     adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5978                                               VNET_LINK_IP4,
5979                                               &nr_path_hi_2.frp_addr,
5980                                               nr_path_hi_2.frp_sw_if_index);
5981     adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5982                                                VNET_LINK_IP4,
5983                                                &nr_path_med_1.frp_addr,
5984                                                nr_path_med_1.frp_sw_if_index);
5985     adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5986                                                VNET_LINK_IP4,
5987                                                &nr_path_med_2.frp_addr,
5988                                                nr_path_med_2.frp_sw_if_index);
5989     adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5990                                                VNET_LINK_IP4,
5991                                                &nr_path_low_1.frp_addr,
5992                                                nr_path_low_1.frp_sw_if_index);
5993     adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5994                                                VNET_LINK_IP4,
5995                                                &nr_path_low_2.frp_addr,
5996                                                nr_path_low_2.frp_sw_if_index);
5997
5998     fib_test_lb_bucket_t ip_hi_1 = {
5999         .type = FT_LB_ADJ,
6000         .adj = {
6001             .adj = ai_hi_1,
6002         },
6003     };
6004     fib_test_lb_bucket_t ip_hi_2 = {
6005         .type = FT_LB_ADJ,
6006         .adj = {
6007             .adj = ai_hi_2,
6008         },
6009     };
6010     fib_test_lb_bucket_t ip_med_1 = {
6011         .type = FT_LB_ADJ,
6012         .adj = {
6013             .adj = ai_med_1,
6014         },
6015     };
6016     fib_test_lb_bucket_t ip_med_2 = {
6017         .type = FT_LB_ADJ,
6018         .adj = {
6019             .adj = ai_med_2,
6020         },
6021     };
6022     fib_test_lb_bucket_t ip_low_1 = {
6023         .type = FT_LB_ADJ,
6024         .adj = {
6025             .adj = ai_low_1,
6026         },
6027     };
6028     fib_test_lb_bucket_t ip_low_2 = {
6029         .type = FT_LB_ADJ,
6030         .adj = {
6031             .adj = ai_low_2,
6032         },
6033     };
6034
6035     fib_node_index_t fei;
6036
6037     fei = fib_table_entry_path_add2(0,
6038                                     &pfx_1_1_1_1_s_32,
6039                                     FIB_SOURCE_API,
6040                                     FIB_ENTRY_FLAG_NONE,
6041                                     nr_paths);
6042
6043     FIB_TEST(!fib_test_validate_entry(fei,
6044                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6045                                       2,
6046                                       &ip_hi_1,
6047                                       &ip_hi_2),
6048              "1.1.1.1/32 via high preference paths");
6049
6050     /*
6051      * bring down the interface on which the high preference path lie
6052      */
6053     vnet_sw_interface_set_flags(vnet_get_main(),
6054                                 tm->hw[0]->sw_if_index,
6055                                 0);
6056
6057     FIB_TEST(!fib_test_validate_entry(fei,
6058                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6059                                       2,
6060                                       &ip_med_1,
6061                                       &ip_med_2),
6062              "1.1.1.1/32 via medium preference paths");
6063
6064     /*
6065      * bring down the interface on which the medium preference path lie
6066      */
6067     vnet_sw_interface_set_flags(vnet_get_main(),
6068                                 tm->hw[1]->sw_if_index,
6069                                 0);
6070
6071     FIB_TEST(!fib_test_validate_entry(fei,
6072                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6073                                       2,
6074                                       &ip_low_1,
6075                                       &ip_low_2),
6076              "1.1.1.1/32 via low preference paths");
6077
6078     /*
6079      * bring up the interface on which the high preference path lie
6080      */
6081     vnet_sw_interface_set_flags(vnet_get_main(),
6082                                 tm->hw[0]->sw_if_index,
6083                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6084
6085     FIB_TEST(!fib_test_validate_entry(fei,
6086                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6087                                       2,
6088                                       &ip_hi_1,
6089                                       &ip_hi_2),
6090              "1.1.1.1/32 via high preference paths");
6091
6092     /*
6093      * bring up the interface on which the medium preference path lie
6094      */
6095     vnet_sw_interface_set_flags(vnet_get_main(),
6096                                 tm->hw[1]->sw_if_index,
6097                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6098
6099     FIB_TEST(!fib_test_validate_entry(fei,
6100                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6101                                       2,
6102                                       &ip_hi_1,
6103                                       &ip_hi_2),
6104              "1.1.1.1/32 via high preference paths");
6105
6106     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6107     fib_entry_contribute_forwarding(fei,
6108                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6109                                     &ip_1_1_1_1);
6110
6111     /*
6112      * 3 recursive paths of different preference
6113      */
6114     const fib_prefix_t pfx_1_1_1_2_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(0x01010102),
6120             },
6121         },
6122     };
6123     const fib_prefix_t pfx_1_1_1_3_s_32 = {
6124         .fp_len = 32,
6125         .fp_proto = FIB_PROTOCOL_IP4,
6126         .fp_addr = {
6127             .ip4 = {
6128                 .as_u32 = clib_host_to_net_u32(0x01010103),
6129             },
6130         },
6131     };
6132     fei = fib_table_entry_path_add2(0,
6133                                     &pfx_1_1_1_2_s_32,
6134                                     FIB_SOURCE_API,
6135                                     FIB_ENTRY_FLAG_NONE,
6136                                     nr_paths);
6137     dpo_id_t ip_1_1_1_2 = DPO_INVALID;
6138     fib_entry_contribute_forwarding(fei,
6139                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6140                                     &ip_1_1_1_2);
6141     fei = fib_table_entry_path_add2(0,
6142                                     &pfx_1_1_1_3_s_32,
6143                                     FIB_SOURCE_API,
6144                                     FIB_ENTRY_FLAG_NONE,
6145                                     nr_paths);
6146     dpo_id_t ip_1_1_1_3 = DPO_INVALID;
6147     fib_entry_contribute_forwarding(fei,
6148                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6149                                     &ip_1_1_1_3);
6150
6151     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6152         .type = FT_LB_O_LB,
6153         .lb = {
6154             .lb = ip_1_1_1_1.dpoi_index,
6155         },
6156     };
6157     fib_test_lb_bucket_t ip_o_1_1_1_2 = {
6158         .type = FT_LB_O_LB,
6159         .lb = {
6160             .lb = ip_1_1_1_2.dpoi_index,
6161         },
6162     };
6163     fib_test_lb_bucket_t ip_o_1_1_1_3 = {
6164         .type = FT_LB_O_LB,
6165         .lb = {
6166             .lb = ip_1_1_1_3.dpoi_index,
6167         },
6168     };
6169     fib_route_path_t r_path_hi = {
6170         .frp_proto = DPO_PROTO_IP4,
6171         .frp_sw_if_index = ~0,
6172         .frp_fib_index = 0,
6173         .frp_weight = 1,
6174         .frp_preference = 0,
6175         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6176         .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
6177     };
6178     fib_route_path_t r_path_med = {
6179         .frp_proto = DPO_PROTO_IP4,
6180         .frp_sw_if_index = ~0,
6181         .frp_fib_index = 0,
6182         .frp_weight = 1,
6183         .frp_preference = 10,
6184         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6185         .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
6186     };
6187     fib_route_path_t r_path_low = {
6188         .frp_proto = DPO_PROTO_IP4,
6189         .frp_sw_if_index = ~0,
6190         .frp_fib_index = 0,
6191         .frp_weight = 1,
6192         .frp_preference = 255,
6193         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6194         .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
6195     };
6196     fib_route_path_t *r_paths = NULL;
6197
6198     vec_add1(r_paths, r_path_hi);
6199     vec_add1(r_paths, r_path_low);
6200     vec_add1(r_paths, r_path_med);
6201
6202     /*
6203      * add many recursive so we get the LB MAp created
6204      */
6205 #define N_PFXS 64
6206     fib_prefix_t pfx_r[N_PFXS];
6207     unsigned int n_pfxs;
6208     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6209     {
6210         pfx_r[n_pfxs].fp_len = 32;
6211         pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
6212         pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
6213             clib_host_to_net_u32(0x02000000 + n_pfxs);
6214
6215         fei = fib_table_entry_path_add2(0,
6216                                         &pfx_r[n_pfxs],
6217                                         FIB_SOURCE_API,
6218                                         FIB_ENTRY_FLAG_NONE,
6219                                         r_paths);
6220
6221         FIB_TEST(!fib_test_validate_entry(fei,
6222                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6223                                           1,
6224                                           &ip_o_1_1_1_1),
6225                  "recursive via high preference paths");
6226
6227         /*
6228          * withdraw hig pref resolving entry
6229          */
6230         fib_table_entry_delete(0,
6231                                &pfx_1_1_1_1_s_32,
6232                                FIB_SOURCE_API);
6233
6234         /* suspend so the update walk kicks int */
6235         vlib_process_suspend(vlib_get_main(), 1e-5);
6236
6237         FIB_TEST(!fib_test_validate_entry(fei,
6238                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6239                                           1,
6240                                           &ip_o_1_1_1_2),
6241                  "recursive via medium preference paths");
6242
6243         /*
6244          * withdraw medium pref resolving entry
6245          */
6246         fib_table_entry_delete(0,
6247                                &pfx_1_1_1_2_s_32,
6248                                FIB_SOURCE_API);
6249
6250         /* suspend so the update walk kicks int */
6251         vlib_process_suspend(vlib_get_main(), 1e-5);
6252
6253         FIB_TEST(!fib_test_validate_entry(fei,
6254                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6255                                           1,
6256                                           &ip_o_1_1_1_3),
6257                  "recursive via low preference paths");
6258
6259         /*
6260          * add back paths for next iteration
6261          */
6262         fei = fib_table_entry_update(0,
6263                                      &pfx_1_1_1_2_s_32,
6264                                      FIB_SOURCE_API,
6265                                      FIB_ENTRY_FLAG_NONE,
6266                                      nr_paths);
6267         fei = fib_table_entry_update(0,
6268                                      &pfx_1_1_1_1_s_32,
6269                                      FIB_SOURCE_API,
6270                                      FIB_ENTRY_FLAG_NONE,
6271                                      nr_paths);
6272
6273         /* suspend so the update walk kicks int */
6274         vlib_process_suspend(vlib_get_main(), 1e-5);
6275
6276         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6277         FIB_TEST(!fib_test_validate_entry(fei,
6278                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6279                                           1,
6280                                           &ip_o_1_1_1_1),
6281                  "recursive via high preference paths");
6282     }
6283
6284
6285     fib_table_entry_delete(0,
6286                            &pfx_1_1_1_1_s_32,
6287                            FIB_SOURCE_API);
6288
6289     /* suspend so the update walk kicks int */
6290     vlib_process_suspend(vlib_get_main(), 1e-5);
6291
6292     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6293     {
6294         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6295
6296         FIB_TEST(!fib_test_validate_entry(fei,
6297                                           FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6298                                           1,
6299                                           &ip_o_1_1_1_2),
6300                  "recursive via medium preference paths");
6301     }
6302     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6303     {
6304         fib_table_entry_delete(0,
6305                                &pfx_r[n_pfxs],
6306                                FIB_SOURCE_API);
6307     }
6308
6309     /*
6310      * Cleanup
6311      */
6312     fib_table_entry_delete(0,
6313                            &pfx_1_1_1_2_s_32,
6314                            FIB_SOURCE_API);
6315     fib_table_entry_delete(0,
6316                            &pfx_1_1_1_3_s_32,
6317                            FIB_SOURCE_API);
6318
6319     dpo_reset(&ip_1_1_1_1);
6320     dpo_reset(&ip_1_1_1_2);
6321     dpo_reset(&ip_1_1_1_3);
6322     adj_unlock(ai_low_2);
6323     adj_unlock(ai_low_1);
6324     adj_unlock(ai_med_2);
6325     adj_unlock(ai_med_1);
6326     adj_unlock(ai_hi_2);
6327     adj_unlock(ai_hi_1);
6328
6329     return (res);
6330 }
6331
6332 /*
6333  * Test the recursive route route handling for GRE tunnels
6334  */
6335 static int
6336 fib_test_label (void)
6337 {
6338     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;
6339     const u32 fib_index = 0;
6340     int lb_count, ii, res;
6341     test_main_t *tm;
6342     ip4_main_t *im;
6343
6344     res = 0;
6345     lb_count = pool_elts(load_balance_pool);
6346     tm = &test_main;
6347     im = &ip4_main;
6348
6349     /*
6350      * add interface routes. We'll assume this works. It's more rigorously
6351      * tested elsewhere.
6352      */
6353     fib_prefix_t local0_pfx = {
6354         .fp_len = 24,
6355         .fp_proto = FIB_PROTOCOL_IP4,
6356         .fp_addr = {
6357             .ip4 = {
6358                 /* 10.10.10.10 */
6359                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6360             },
6361         },
6362     };
6363
6364     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6365              adj_nbr_db_size());
6366
6367     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6368     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6369
6370     fib_table_entry_update_one_path(fib_index, &local0_pfx,
6371                                     FIB_SOURCE_INTERFACE,
6372                                     (FIB_ENTRY_FLAG_CONNECTED |
6373                                      FIB_ENTRY_FLAG_ATTACHED),
6374                                     DPO_PROTO_IP4,
6375                                     NULL,
6376                                     tm->hw[0]->sw_if_index,
6377                                     ~0,
6378                                     1,
6379                                     NULL,
6380                                     FIB_ROUTE_PATH_FLAG_NONE);
6381     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6382     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6383              "attached interface route present");
6384
6385     local0_pfx.fp_len = 32;
6386     fib_table_entry_update_one_path(fib_index, &local0_pfx,
6387                                     FIB_SOURCE_INTERFACE,
6388                                     (FIB_ENTRY_FLAG_CONNECTED |
6389                                      FIB_ENTRY_FLAG_LOCAL),
6390                                     DPO_PROTO_IP4,
6391                                     NULL,
6392                                     tm->hw[0]->sw_if_index,
6393                                     ~0, // invalid fib index
6394                                     1,
6395                                     NULL,
6396                                     FIB_ROUTE_PATH_FLAG_NONE);
6397     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6398
6399     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6400              "local interface route present");
6401
6402     fib_prefix_t local1_pfx = {
6403         .fp_len = 24,
6404         .fp_proto = FIB_PROTOCOL_IP4,
6405         .fp_addr = {
6406             .ip4 = {
6407                 /* 10.10.11.10 */
6408                 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6409             },
6410         },
6411     };
6412
6413     vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6414     im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6415
6416     fib_table_entry_update_one_path(fib_index, &local1_pfx,
6417                                     FIB_SOURCE_INTERFACE,
6418                                     (FIB_ENTRY_FLAG_CONNECTED |
6419                                      FIB_ENTRY_FLAG_ATTACHED),
6420                                     DPO_PROTO_IP4,
6421                                     NULL,
6422                                     tm->hw[1]->sw_if_index,
6423                                     ~0,
6424                                     1,
6425                                     NULL,
6426                                     FIB_ROUTE_PATH_FLAG_NONE);
6427     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6428     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6429              "attached interface route present");
6430
6431     local1_pfx.fp_len = 32;
6432     fib_table_entry_update_one_path(fib_index, &local1_pfx,
6433                                     FIB_SOURCE_INTERFACE,
6434                                     (FIB_ENTRY_FLAG_CONNECTED |
6435                                      FIB_ENTRY_FLAG_LOCAL),
6436                                     DPO_PROTO_IP4,
6437                                     NULL,
6438                                     tm->hw[1]->sw_if_index,
6439                                     ~0, // invalid fib index
6440                                     1,
6441                                     NULL,
6442                                     FIB_ROUTE_PATH_FLAG_NONE);
6443     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6444
6445     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6446              "local interface route present");
6447
6448     ip46_address_t nh_10_10_10_1 = {
6449         .ip4 = {
6450             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6451         },
6452     };
6453     ip46_address_t nh_10_10_11_1 = {
6454         .ip4 = {
6455             .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6456         },
6457     };
6458     ip46_address_t nh_10_10_11_2 = {
6459         .ip4 = {
6460             .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6461         },
6462     };
6463
6464     ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6465                                            VNET_LINK_IP4,
6466                                            &nh_10_10_11_1,
6467                                            tm->hw[1]->sw_if_index);
6468     ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6469                                            VNET_LINK_IP4,
6470                                            &nh_10_10_11_2,
6471                                            tm->hw[1]->sw_if_index);
6472     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6473                                              VNET_LINK_MPLS,
6474                                              &nh_10_10_10_1,
6475                                              tm->hw[0]->sw_if_index);
6476     ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6477                                              VNET_LINK_MPLS,
6478                                              &nh_10_10_11_2,
6479                                              tm->hw[1]->sw_if_index);
6480     ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6481                                              VNET_LINK_MPLS,
6482                                              &nh_10_10_11_1,
6483                                              tm->hw[1]->sw_if_index);
6484
6485     /*
6486      * Add an etry with one path with a real out-going label
6487      */
6488     fib_prefix_t pfx_1_1_1_1_s_32 = {
6489         .fp_len = 32,
6490         .fp_proto = FIB_PROTOCOL_IP4,
6491         .fp_addr = {
6492             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6493         },
6494     };
6495     fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6496         .type = FT_LB_LABEL_O_ADJ,
6497         .label_o_adj = {
6498             .adj = ai_mpls_10_10_10_1,
6499             .label = 99,
6500             .eos = MPLS_EOS,
6501         },
6502     };
6503     fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6504         .type = FT_LB_LABEL_O_ADJ,
6505         .label_o_adj = {
6506             .adj = ai_mpls_10_10_10_1,
6507             .label = 99,
6508             .eos = MPLS_NON_EOS,
6509         },
6510     };
6511     fib_mpls_label_t *l99 = NULL, fml99 = {
6512         .fml_value = 99,
6513     };
6514     vec_add1(l99, fml99);
6515
6516     fib_table_entry_update_one_path(fib_index,
6517                                     &pfx_1_1_1_1_s_32,
6518                                     FIB_SOURCE_API,
6519                                     FIB_ENTRY_FLAG_NONE,
6520                                     DPO_PROTO_IP4,
6521                                     &nh_10_10_10_1,
6522                                     tm->hw[0]->sw_if_index,
6523                                     ~0, // invalid fib index
6524                                     1,
6525                                     l99,
6526                                     FIB_ROUTE_PATH_FLAG_NONE);
6527
6528     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6529     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6530
6531     FIB_TEST(!fib_test_validate_entry(fei,
6532                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6533                                       1,
6534                                       &l99_eos_o_10_10_10_1),
6535              "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6536
6537     /*
6538      * add a path with an implicit NULL label
6539      */
6540     fib_test_lb_bucket_t a_o_10_10_11_1 = {
6541         .type = FT_LB_ADJ,
6542         .adj = {
6543             .adj = ai_v4_10_10_11_1,
6544         },
6545     };
6546     fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6547         .type = FT_LB_ADJ,
6548         .adj = {
6549             .adj = ai_mpls_10_10_11_1,
6550         },
6551     };
6552     fib_mpls_label_t *l_imp_null = NULL, fml_imp_null = {
6553         .fml_value =  MPLS_IETF_IMPLICIT_NULL_LABEL,
6554     };
6555     vec_add1(l_imp_null, fml_imp_null);
6556
6557     fei = fib_table_entry_path_add(fib_index,
6558                                    &pfx_1_1_1_1_s_32,
6559                                    FIB_SOURCE_API,
6560                                    FIB_ENTRY_FLAG_NONE,
6561                                    DPO_PROTO_IP4,
6562                                    &nh_10_10_11_1,
6563                                    tm->hw[1]->sw_if_index,
6564                                    ~0, // invalid fib index
6565                                    1,
6566                                    l_imp_null,
6567                                    FIB_ROUTE_PATH_FLAG_NONE);
6568
6569     FIB_TEST(!fib_test_validate_entry(fei,
6570                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6571                                       2,
6572                                       &l99_eos_o_10_10_10_1,
6573                                       &a_o_10_10_11_1),
6574              "1.1.1.1/32 LB 2 buckets via: "
6575              "label 99 over 10.10.10.1, "
6576              "adj over 10.10.11.1");
6577
6578     /*
6579      * assign the route a local label
6580      */
6581     fib_table_entry_local_label_add(fib_index,
6582                                     &pfx_1_1_1_1_s_32,
6583                                     24001);
6584
6585     fib_prefix_t pfx_24001_eos = {
6586         .fp_proto = FIB_PROTOCOL_MPLS,
6587         .fp_label = 24001,
6588         .fp_eos = MPLS_EOS,
6589     };
6590     fib_prefix_t pfx_24001_neos = {
6591         .fp_proto = FIB_PROTOCOL_MPLS,
6592         .fp_label = 24001,
6593         .fp_eos = MPLS_NON_EOS,
6594     };
6595     fib_test_lb_bucket_t disp_o_10_10_11_1 = {
6596         .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6597         .adj = {
6598             .adj = ai_v4_10_10_11_1,
6599         },
6600     };
6601
6602     /*
6603      * The EOS entry should link to both the paths,
6604      *  and use an ip adj for the imp-null
6605      * The NON-EOS entry should link to both the paths,
6606      *  and use an mpls adj for the imp-null
6607      */
6608     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6609                            &pfx_24001_eos);
6610     FIB_TEST(!fib_test_validate_entry(fei,
6611                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6612                                       2,
6613                                       &l99_eos_o_10_10_10_1,
6614                                       &disp_o_10_10_11_1),
6615              "24001/eos LB 2 buckets via: "
6616              "label 99 over 10.10.10.1, "
6617              "mpls disp adj over 10.10.11.1");
6618
6619
6620     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6621                            &pfx_24001_neos);
6622     FIB_TEST(!fib_test_validate_entry(fei,
6623                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6624                                       2,
6625                                       &l99_neos_o_10_10_10_1,
6626                                       &a_mpls_o_10_10_11_1),
6627              "24001/neos LB 1 bucket via: "
6628              "label 99 over 10.10.10.1 ",
6629              "mpls-adj via 10.10.11.1");
6630
6631     /*
6632      * add an unlabelled path, this is excluded from the neos chains,
6633      */
6634     fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6635         .type = FT_LB_ADJ,
6636         .adj = {
6637             .adj = ai_v4_10_10_11_2,
6638         },
6639     };
6640     fib_test_lb_bucket_t disp_o_10_10_11_2 = {
6641         .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6642         .adj = {
6643             .adj = ai_v4_10_10_11_2,
6644         },
6645     };
6646
6647
6648     fei = fib_table_entry_path_add(fib_index,
6649                                    &pfx_1_1_1_1_s_32,
6650                                    FIB_SOURCE_API,
6651                                    FIB_ENTRY_FLAG_NONE,
6652                                    DPO_PROTO_IP4,
6653                                    &nh_10_10_11_2,
6654                                    tm->hw[1]->sw_if_index,
6655                                    ~0, // invalid fib index
6656                                    1,
6657                                    NULL,
6658                                    FIB_ROUTE_PATH_FLAG_NONE);
6659
6660     FIB_TEST(!fib_test_validate_entry(fei,
6661                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6662                                       16, // 3 choices spread over 16 buckets
6663                                       &l99_eos_o_10_10_10_1,
6664                                       &l99_eos_o_10_10_10_1,
6665                                       &l99_eos_o_10_10_10_1,
6666                                       &l99_eos_o_10_10_10_1,
6667                                       &l99_eos_o_10_10_10_1,
6668                                       &l99_eos_o_10_10_10_1,
6669                                       &a_o_10_10_11_1,
6670                                       &a_o_10_10_11_1,
6671                                       &a_o_10_10_11_1,
6672                                       &a_o_10_10_11_1,
6673                                       &a_o_10_10_11_1,
6674                                       &adj_o_10_10_11_2,
6675                                       &adj_o_10_10_11_2,
6676                                       &adj_o_10_10_11_2,
6677                                       &adj_o_10_10_11_2,
6678                                       &adj_o_10_10_11_2),
6679              "1.1.1.1/32 LB 16 buckets via: "
6680              "label 99 over 10.10.10.1, "
6681              "adj over 10.10.11.1",
6682              "adj over 10.10.11.2");
6683
6684     /*
6685      * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6686      */
6687     dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6688     fib_entry_contribute_forwarding(fei,
6689                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6690                                     &non_eos_1_1_1_1);
6691
6692     /*
6693      * n-eos has only the 2 labelled paths
6694      */
6695     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6696                            &pfx_24001_neos);
6697
6698     FIB_TEST(!fib_test_validate_entry(fei,
6699                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6700                                       2,
6701                                       &l99_neos_o_10_10_10_1,
6702                                       &a_mpls_o_10_10_11_1),
6703              "24001/neos LB 2 buckets via: "
6704              "label 99 over 10.10.10.1, "
6705              "adj-mpls over 10.10.11.2");
6706
6707     /*
6708      * A labelled recursive
6709      */
6710     fib_prefix_t pfx_2_2_2_2_s_32 = {
6711         .fp_len = 32,
6712         .fp_proto = FIB_PROTOCOL_IP4,
6713         .fp_addr = {
6714             .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6715         },
6716     };
6717     fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6718         .type = FT_LB_LABEL_O_LB,
6719         .label_o_lb = {
6720             .lb = non_eos_1_1_1_1.dpoi_index,
6721             .label = 1600,
6722             .eos = MPLS_EOS,
6723             .mode = FIB_MPLS_LSP_MODE_UNIFORM,
6724         },
6725     };
6726     fib_mpls_label_t *l1600 = NULL, fml1600 = {
6727         .fml_value = 1600,
6728         .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
6729     };
6730     vec_add1(l1600, fml1600);
6731
6732     fei = fib_table_entry_update_one_path(fib_index,
6733                                           &pfx_2_2_2_2_s_32,
6734                                           FIB_SOURCE_API,
6735                                           FIB_ENTRY_FLAG_NONE,
6736                                           DPO_PROTO_IP4,
6737                                           &pfx_1_1_1_1_s_32.fp_addr,
6738                                           ~0,
6739                                           fib_index,
6740                                           1,
6741                                           l1600,
6742                                           FIB_ROUTE_PATH_FLAG_NONE);
6743
6744     FIB_TEST(!fib_test_validate_entry(fei,
6745                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6746                                       1,
6747                                       &l1600_eos_o_1_1_1_1),
6748              "2.2.2.2.2/32 LB 1 buckets via: "
6749              "label 1600 over 1.1.1.1");
6750
6751     dpo_id_t dpo_44 = DPO_INVALID;
6752     index_t urpfi;
6753
6754     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6755     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6756
6757     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6758              "uRPF check for 2.2.2.2/32 on %d OK",
6759              tm->hw[0]->sw_if_index);
6760     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6761              "uRPF check for 2.2.2.2/32 on %d OK",
6762              tm->hw[1]->sw_if_index);
6763     FIB_TEST(!fib_urpf_check(urpfi, 99),
6764              "uRPF check for 2.2.2.2/32 on 99 not-OK",
6765              99);
6766
6767     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6768     FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6769              "Shared uRPF on IP and non-EOS chain");
6770
6771     dpo_reset(&dpo_44);
6772
6773     /*
6774      * we are holding a lock on the non-eos LB of the via-entry.
6775      * do a PIC-core failover by shutting the link of the via-entry.
6776      *
6777      * shut down the link with the valid label
6778      */
6779     vnet_sw_interface_set_flags(vnet_get_main(),
6780                                 tm->hw[0]->sw_if_index,
6781                                 0);
6782
6783     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6784     FIB_TEST(!fib_test_validate_entry(fei,
6785                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6786                                       2,
6787                                       &a_o_10_10_11_1,
6788                                       &adj_o_10_10_11_2),
6789              "1.1.1.1/32 LB 2 buckets via: "
6790              "adj over 10.10.11.1, ",
6791              "adj-v4 over 10.10.11.2");
6792
6793     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6794                            &pfx_24001_eos);
6795     FIB_TEST(!fib_test_validate_entry(fei,
6796                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6797                                       2,
6798                                       &disp_o_10_10_11_1,
6799                                       &disp_o_10_10_11_2),
6800              "24001/eos LB 2 buckets via: "
6801              "mpls-disp adj over 10.10.11.1, ",
6802              "mpls-disp adj-v4 over 10.10.11.2");
6803
6804     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6805                            &pfx_24001_neos);
6806     FIB_TEST(!fib_test_validate_entry(fei,
6807                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6808                                       1,
6809                                       &a_mpls_o_10_10_11_1),
6810              "24001/neos LB 1 buckets via: "
6811              "adj-mpls over 10.10.11.2");
6812
6813     /*
6814      * test that the pre-failover load-balance has been in-place
6815      * modified
6816      */
6817     dpo_id_t current = DPO_INVALID;
6818     fib_entry_contribute_forwarding(fei,
6819                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6820                                     &current);
6821
6822     FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6823                       &current),
6824              "PIC-core LB inplace modified %U %U",
6825              format_dpo_id, &non_eos_1_1_1_1, 0,
6826              format_dpo_id, &current, 0);
6827
6828     dpo_reset(&non_eos_1_1_1_1);
6829     dpo_reset(&current);
6830
6831     /*
6832      * no-shut the link with the valid label
6833      */
6834     vnet_sw_interface_set_flags(vnet_get_main(),
6835                                 tm->hw[0]->sw_if_index,
6836                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6837
6838     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6839     FIB_TEST(!fib_test_validate_entry(fei,
6840                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6841                                       16, // 3 choices spread over 16 buckets
6842                                       &l99_eos_o_10_10_10_1,
6843                                       &l99_eos_o_10_10_10_1,
6844                                       &l99_eos_o_10_10_10_1,
6845                                       &l99_eos_o_10_10_10_1,
6846                                       &l99_eos_o_10_10_10_1,
6847                                       &l99_eos_o_10_10_10_1,
6848                                       &a_o_10_10_11_1,
6849                                       &a_o_10_10_11_1,
6850                                       &a_o_10_10_11_1,
6851                                       &a_o_10_10_11_1,
6852                                       &a_o_10_10_11_1,
6853                                       &adj_o_10_10_11_2,
6854                                       &adj_o_10_10_11_2,
6855                                       &adj_o_10_10_11_2,
6856                                       &adj_o_10_10_11_2,
6857                                       &adj_o_10_10_11_2),
6858              "1.1.1.1/32 LB 16 buckets via: "
6859              "label 99 over 10.10.10.1, "
6860              "adj over 10.10.11.1",
6861              "adj-v4 over 10.10.11.2");
6862
6863
6864     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6865                            &pfx_24001_eos);
6866     FIB_TEST(!fib_test_validate_entry(fei,
6867                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6868                                       16, // 3 choices spread over 16 buckets
6869                                       &l99_eos_o_10_10_10_1,
6870                                       &l99_eos_o_10_10_10_1,
6871                                       &l99_eos_o_10_10_10_1,
6872                                       &l99_eos_o_10_10_10_1,
6873                                       &l99_eos_o_10_10_10_1,
6874                                       &l99_eos_o_10_10_10_1,
6875                                       &disp_o_10_10_11_1,
6876                                       &disp_o_10_10_11_1,
6877                                       &disp_o_10_10_11_1,
6878                                       &disp_o_10_10_11_1,
6879                                       &disp_o_10_10_11_1,
6880                                       &disp_o_10_10_11_2,
6881                                       &disp_o_10_10_11_2,
6882                                       &disp_o_10_10_11_2,
6883                                       &disp_o_10_10_11_2,
6884                                       &disp_o_10_10_11_2),
6885              "24001/eos LB 16 buckets via: "
6886              "label 99 over 10.10.10.1, "
6887              "MPLS disp adj over 10.10.11.1",
6888              "MPLS disp adj-v4 over 10.10.11.2");
6889
6890     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6891                            &pfx_24001_neos);
6892     FIB_TEST(!fib_test_validate_entry(fei,
6893                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6894                                       2,
6895                                       &l99_neos_o_10_10_10_1,
6896                                       &a_mpls_o_10_10_11_1),
6897              "24001/neos LB 2 buckets via: "
6898              "label 99 over 10.10.10.1, "
6899              "adj-mpls over 10.10.11.2");
6900
6901     /*
6902      * remove the first path with the valid label
6903      */
6904     fib_table_entry_path_remove(fib_index,
6905                                 &pfx_1_1_1_1_s_32,
6906                                 FIB_SOURCE_API,
6907                                 DPO_PROTO_IP4,
6908                                 &nh_10_10_10_1,
6909                                 tm->hw[0]->sw_if_index,
6910                                 ~0, // invalid fib index
6911                                 1,
6912                                 FIB_ROUTE_PATH_FLAG_NONE);
6913
6914     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6915     FIB_TEST(!fib_test_validate_entry(fei,
6916                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6917                                       2,
6918                                       &a_o_10_10_11_1,
6919                                       &adj_o_10_10_11_2),
6920              "1.1.1.1/32 LB 2 buckets via: "
6921              "adj over 10.10.11.1, "
6922              "adj-v4 over 10.10.11.2");
6923
6924     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6925                            &pfx_24001_eos);
6926     FIB_TEST(!fib_test_validate_entry(fei,
6927                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6928                                       2,
6929                                       &disp_o_10_10_11_1,
6930                                       &disp_o_10_10_11_2),
6931              "24001/eos LB 2 buckets via: "
6932              "MPLS disp adj over 10.10.11.1, "
6933              "MPLS disp adj-v4 over 10.10.11.2");
6934
6935     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6936                            &pfx_24001_neos);
6937
6938     FIB_TEST(!fib_test_validate_entry(fei,
6939                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6940                                       1,
6941                                       &a_mpls_o_10_10_11_1),
6942              "24001/neos LB 1 buckets via: "
6943              "adj-mpls over 10.10.11.2");
6944
6945     /*
6946      * remove the other path with a valid label
6947      */
6948     fib_test_lb_bucket_t bucket_drop = {
6949         .type = FT_LB_DROP,
6950     };
6951     fib_test_lb_bucket_t mpls_bucket_drop = {
6952         .type = FT_LB_DROP,
6953         .special = {
6954             .adj = DPO_PROTO_MPLS,
6955         },
6956     };
6957
6958     fib_table_entry_path_remove(fib_index,
6959                                 &pfx_1_1_1_1_s_32,
6960                                 FIB_SOURCE_API,
6961                                 DPO_PROTO_IP4,
6962                                 &nh_10_10_11_1,
6963                                 tm->hw[1]->sw_if_index,
6964                                 ~0, // invalid fib index
6965                                 1,
6966                                 FIB_ROUTE_PATH_FLAG_NONE);
6967
6968     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6969     FIB_TEST(!fib_test_validate_entry(fei,
6970                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6971                                       1,
6972                                       &adj_o_10_10_11_2),
6973              "1.1.1.1/32 LB 1 buckets via: "
6974              "adj over 10.10.11.2");
6975
6976     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6977                            &pfx_24001_eos);
6978     FIB_TEST(!fib_test_validate_entry(fei,
6979                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6980                                       1,
6981                                       &disp_o_10_10_11_2),
6982              "24001/eos LB 1 buckets via: "
6983              "MPLS disp adj over 10.10.11.2");
6984
6985     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6986                            &pfx_24001_neos);
6987     FIB_TEST(!fib_test_validate_entry(fei,
6988                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6989                                       1,
6990                                       &mpls_bucket_drop),
6991              "24001/neos LB 1 buckets via: DROP");
6992
6993     /*
6994      * add back the path with the valid label
6995      */
6996     l99 = NULL;
6997     vec_add1(l99, fml99);
6998
6999     fib_table_entry_path_add(fib_index,
7000                              &pfx_1_1_1_1_s_32,
7001                              FIB_SOURCE_API,
7002                              FIB_ENTRY_FLAG_NONE,
7003                              DPO_PROTO_IP4,
7004                              &nh_10_10_10_1,
7005                              tm->hw[0]->sw_if_index,
7006                              ~0, // invalid fib index
7007                              1,
7008                              l99,
7009                              FIB_ROUTE_PATH_FLAG_NONE);
7010
7011     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
7012     FIB_TEST(!fib_test_validate_entry(fei,
7013                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7014                                       2,
7015                                       &l99_eos_o_10_10_10_1,
7016                                       &adj_o_10_10_11_2),
7017              "1.1.1.1/32 LB 2 buckets via: "
7018              "label 99 over 10.10.10.1, "
7019              "adj over 10.10.11.2");
7020
7021     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7022                            &pfx_24001_eos);
7023     FIB_TEST(!fib_test_validate_entry(fei,
7024                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7025                                       2,
7026                                       &l99_eos_o_10_10_10_1,
7027                                       &disp_o_10_10_11_2),
7028              "24001/eos LB 2 buckets via: "
7029              "label 99 over 10.10.10.1, "
7030              "MPLS disp adj over 10.10.11.2");
7031
7032     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7033                            &pfx_24001_neos);
7034     FIB_TEST(!fib_test_validate_entry(fei,
7035                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7036                                       1,
7037                                       &l99_neos_o_10_10_10_1),
7038              "24001/neos LB 1 buckets via: "
7039              "label 99 over 10.10.10.1");
7040
7041     /*
7042      * change the local label
7043      */
7044     fib_table_entry_local_label_add(fib_index,
7045                                     &pfx_1_1_1_1_s_32,
7046                                     25005);
7047
7048     fib_prefix_t pfx_25005_eos = {
7049         .fp_proto = FIB_PROTOCOL_MPLS,
7050         .fp_label = 25005,
7051         .fp_eos = MPLS_EOS,
7052     };
7053     fib_prefix_t pfx_25005_neos = {
7054         .fp_proto = FIB_PROTOCOL_MPLS,
7055         .fp_label = 25005,
7056         .fp_eos = MPLS_NON_EOS,
7057     };
7058
7059     FIB_TEST((FIB_NODE_INDEX_INVALID ==
7060               fib_table_lookup(fib_index, &pfx_24001_eos)),
7061              "24001/eos removed after label change");
7062     FIB_TEST((FIB_NODE_INDEX_INVALID ==
7063               fib_table_lookup(fib_index, &pfx_24001_neos)),
7064              "24001/eos removed after label change");
7065
7066     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7067                            &pfx_25005_eos);
7068     FIB_TEST(!fib_test_validate_entry(fei,
7069                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7070                                       2,
7071                                       &l99_eos_o_10_10_10_1,
7072                                       &disp_o_10_10_11_2),
7073              "25005/eos LB 2 buckets via: "
7074              "label 99 over 10.10.10.1, "
7075              "MPLS disp adj over 10.10.11.2");
7076
7077     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7078                            &pfx_25005_neos);
7079     FIB_TEST(!fib_test_validate_entry(fei,
7080                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7081                                       1,
7082                                       &l99_neos_o_10_10_10_1),
7083              "25005/neos LB 1 buckets via: "
7084              "label 99 over 10.10.10.1");
7085
7086     /*
7087      * remove the local label.
7088      * the check that the MPLS entries are gone is done by the fact the
7089      * MPLS table is no longer present.
7090      */
7091     fib_table_entry_local_label_remove(fib_index,
7092                                        &pfx_1_1_1_1_s_32,
7093                                        25005);
7094
7095     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
7096     FIB_TEST(!fib_test_validate_entry(fei,
7097                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7098                                       2,
7099                                       &l99_eos_o_10_10_10_1,
7100                                       &adj_o_10_10_11_2),
7101              "24001/eos LB 2 buckets via: "
7102              "label 99 over 10.10.10.1, "
7103              "adj over 10.10.11.2");
7104
7105     FIB_TEST((FIB_NODE_INDEX_INVALID ==
7106               mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
7107              "No more MPLS FIB entries => table removed");
7108
7109     /*
7110      * add another via-entry for the recursive
7111      */
7112     fib_prefix_t pfx_1_1_1_2_s_32 = {
7113         .fp_len = 32,
7114         .fp_proto = FIB_PROTOCOL_IP4,
7115         .fp_addr = {
7116             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
7117         },
7118     };
7119     fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
7120         .type = FT_LB_LABEL_O_ADJ,
7121         .label_o_adj = {
7122             .adj = ai_mpls_10_10_10_1,
7123             .label = 101,
7124             .eos = MPLS_EOS,
7125         },
7126     };
7127     fib_mpls_label_t *l101 = NULL, fml101 = {
7128         .fml_value = 101,
7129     };
7130     vec_add1(l101, fml101);
7131
7132     fei = fib_table_entry_update_one_path(fib_index,
7133                                           &pfx_1_1_1_2_s_32,
7134                                           FIB_SOURCE_API,
7135                                           FIB_ENTRY_FLAG_NONE,
7136                                           DPO_PROTO_IP4,
7137                                           &nh_10_10_10_1,
7138                                           tm->hw[0]->sw_if_index,
7139                                           ~0, // invalid fib index
7140                                           1,
7141                                           l101,
7142                                           FIB_ROUTE_PATH_FLAG_NONE);
7143
7144     FIB_TEST(!fib_test_validate_entry(fei,
7145                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7146                                       1,
7147                                       &l101_eos_o_10_10_10_1),
7148              "1.1.1.2/32 LB 1 buckets via: "
7149              "label 101 over 10.10.10.1");
7150
7151     dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
7152     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7153                                                      &pfx_1_1_1_1_s_32),
7154                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7155                                     &non_eos_1_1_1_1);
7156     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7157                                                      &pfx_1_1_1_2_s_32),
7158                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7159                                     &non_eos_1_1_1_2);
7160
7161     fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
7162         .type = FT_LB_LABEL_O_LB,
7163         .label_o_lb = {
7164             .lb = non_eos_1_1_1_2.dpoi_index,
7165             .label = 1601,
7166             .eos = MPLS_EOS,
7167         },
7168     };
7169     fib_mpls_label_t *l1601 = NULL, fml1601 = {
7170         .fml_value = 1601,
7171     };
7172     vec_add1(l1601, fml1601);
7173
7174     l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
7175
7176     fei = fib_table_entry_path_add(fib_index,
7177                                    &pfx_2_2_2_2_s_32,
7178                                    FIB_SOURCE_API,
7179                                    FIB_ENTRY_FLAG_NONE,
7180                                    DPO_PROTO_IP4,
7181                                    &pfx_1_1_1_2_s_32.fp_addr,
7182                                    ~0,
7183                                    fib_index,
7184                                    1,
7185                                    l1601,
7186                                    FIB_ROUTE_PATH_FLAG_NONE);
7187
7188     FIB_TEST(!fib_test_validate_entry(fei,
7189                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7190                                       2,
7191                                       &l1600_eos_o_1_1_1_1,
7192                                       &l1601_eos_o_1_1_1_2),
7193              "2.2.2.2/32 LB 2 buckets via: "
7194              "label 1600 via 1.1,1.1, "
7195              "label 16001 via 1.1.1.2");
7196
7197     /*
7198      * update the via-entry so it no longer has an imp-null path.
7199      * the LB for the recursive can use an imp-null
7200      */
7201     l_imp_null = NULL;
7202     vec_add1(l_imp_null, fml_imp_null);
7203
7204     fei = fib_table_entry_update_one_path(fib_index,
7205                                           &pfx_1_1_1_2_s_32,
7206                                           FIB_SOURCE_API,
7207                                           FIB_ENTRY_FLAG_NONE,
7208                                           DPO_PROTO_IP4,
7209                                           &nh_10_10_11_1,
7210                                           tm->hw[1]->sw_if_index,
7211                                           ~0, // invalid fib index
7212                                           1,
7213                                           l_imp_null,
7214                                           FIB_ROUTE_PATH_FLAG_NONE);
7215
7216     FIB_TEST(!fib_test_validate_entry(fei,
7217                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7218                                       1,
7219                                       &a_o_10_10_11_1),
7220              "1.1.1.2/32 LB 1 buckets via: "
7221              "adj 10.10.11.1");
7222
7223     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7224     FIB_TEST(!fib_test_validate_entry(fei,
7225                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7226                                       2,
7227                                       &l1600_eos_o_1_1_1_1,
7228                                       &l1601_eos_o_1_1_1_2),
7229              "2.2.2.2/32 LB 2 buckets via: "
7230              "label 1600 via 1.1,1.1, "
7231              "label 16001 via 1.1.1.2");
7232
7233     /*
7234      * update the via-entry so it no longer has labelled paths.
7235      * the LB for the recursive should exclue this via form its LB
7236      */
7237     fei = fib_table_entry_update_one_path(fib_index,
7238                                           &pfx_1_1_1_2_s_32,
7239                                           FIB_SOURCE_API,
7240                                           FIB_ENTRY_FLAG_NONE,
7241                                           DPO_PROTO_IP4,
7242                                           &nh_10_10_11_1,
7243                                           tm->hw[1]->sw_if_index,
7244                                           ~0, // invalid fib index
7245                                           1,
7246                                           NULL,
7247                                           FIB_ROUTE_PATH_FLAG_NONE);
7248
7249     FIB_TEST(!fib_test_validate_entry(fei,
7250                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7251                                       1,
7252                                       &a_o_10_10_11_1),
7253              "1.1.1.2/32 LB 1 buckets via: "
7254              "adj 10.10.11.1");
7255
7256     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7257     FIB_TEST(!fib_test_validate_entry(fei,
7258                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7259                                       1,
7260                                       &l1600_eos_o_1_1_1_1),
7261              "2.2.2.2/32 LB 1 buckets via: "
7262              "label 1600 via 1.1,1.1");
7263
7264     dpo_reset(&non_eos_1_1_1_1);
7265     dpo_reset(&non_eos_1_1_1_2);
7266
7267     /*
7268      * Add a recursive with no out-labels. We expect to use the IP of the via
7269      */
7270     fib_prefix_t pfx_2_2_2_3_s_32 = {
7271         .fp_len = 32,
7272         .fp_proto = FIB_PROTOCOL_IP4,
7273         .fp_addr = {
7274             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7275         },
7276     };
7277     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7278
7279     fib_table_entry_update_one_path(fib_index,
7280                                     &pfx_2_2_2_3_s_32,
7281                                     FIB_SOURCE_API,
7282                                     FIB_ENTRY_FLAG_NONE,
7283                                     DPO_PROTO_IP4,
7284                                     &pfx_1_1_1_1_s_32.fp_addr,
7285                                     ~0,
7286                                     fib_index,
7287                                     1,
7288                                     NULL,
7289                                     FIB_ROUTE_PATH_FLAG_NONE);
7290
7291     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7292                                                      &pfx_1_1_1_1_s_32),
7293                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7294                                     &ip_1_1_1_1);
7295
7296     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7297         .type = FT_LB_O_LB,
7298         .lb = {
7299             .lb = ip_1_1_1_1.dpoi_index,
7300         },
7301     };
7302
7303     fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7304     FIB_TEST(!fib_test_validate_entry(fei,
7305                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7306                                       1,
7307                                       &ip_o_1_1_1_1),
7308              "2.2.2.2.3/32 LB 1 buckets via: "
7309              "ip 1.1.1.1");
7310
7311     /*
7312      * Add a recursive with an imp-null out-label.
7313      * We expect to use the IP of the via
7314      */
7315     fib_prefix_t pfx_2_2_2_4_s_32 = {
7316         .fp_len = 32,
7317         .fp_proto = FIB_PROTOCOL_IP4,
7318         .fp_addr = {
7319             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7320         },
7321     };
7322
7323     fib_table_entry_update_one_path(fib_index,
7324                                     &pfx_2_2_2_4_s_32,
7325                                     FIB_SOURCE_API,
7326                                     FIB_ENTRY_FLAG_NONE,
7327                                     DPO_PROTO_IP4,
7328                                     &pfx_1_1_1_1_s_32.fp_addr,
7329                                     ~0,
7330                                     fib_index,
7331                                     1,
7332                                     NULL,
7333                                     FIB_ROUTE_PATH_FLAG_NONE);
7334
7335     fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7336     FIB_TEST(!fib_test_validate_entry(fei,
7337                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7338                                       1,
7339                                       &ip_o_1_1_1_1),
7340              "2.2.2.2.4/32 LB 1 buckets via: "
7341              "ip 1.1.1.1");
7342
7343     dpo_reset(&ip_1_1_1_1);
7344
7345     /*
7346      * Create an entry with a deep label stack
7347      */
7348     fib_prefix_t pfx_2_2_5_5_s_32 = {
7349         .fp_len = 32,
7350         .fp_proto = FIB_PROTOCOL_IP4,
7351         .fp_addr = {
7352             .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7353         },
7354     };
7355     fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7356         .type = FT_LB_LABEL_STACK_O_ADJ,
7357         .label_stack_o_adj = {
7358             .adj = ai_mpls_10_10_11_1,
7359             .label_stack_size = 8,
7360             .label_stack = {
7361                 200, 201, 202, 203, 204, 205, 206, 207
7362             },
7363             .eos = MPLS_EOS,
7364         },
7365     };
7366     fib_mpls_label_t *label_stack = NULL;
7367     vec_validate(label_stack, 7);
7368     for (ii = 0; ii < 8; ii++)
7369     {
7370         label_stack[ii].fml_value = ii + 200;
7371     }
7372
7373     fei = fib_table_entry_update_one_path(fib_index,
7374                                           &pfx_2_2_5_5_s_32,
7375                                           FIB_SOURCE_API,
7376                                           FIB_ENTRY_FLAG_NONE,
7377                                           DPO_PROTO_IP4,
7378                                           &nh_10_10_11_1,
7379                                           tm->hw[1]->sw_if_index,
7380                                           ~0, // invalid fib index
7381                                           1,
7382                                           label_stack,
7383                                           FIB_ROUTE_PATH_FLAG_NONE);
7384
7385     FIB_TEST(!fib_test_validate_entry(fei,
7386                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7387                                       1,
7388                                       &ls_eos_o_10_10_10_1),
7389              "2.2.5.5/32 LB 1 buckets via: "
7390              "adj 10.10.11.1");
7391     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7392
7393     /*
7394      * cleanup
7395      */
7396     fib_table_entry_delete(fib_index,
7397                            &pfx_1_1_1_2_s_32,
7398                            FIB_SOURCE_API);
7399
7400     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7401     FIB_TEST(!fib_test_validate_entry(fei,
7402                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7403                                       1,
7404                                       &l1600_eos_o_1_1_1_1),
7405              "2.2.2.2/32 LB 1 buckets via: "
7406              "label 1600 via 1.1,1.1");
7407
7408     fib_table_entry_delete(fib_index,
7409                            &pfx_1_1_1_1_s_32,
7410                            FIB_SOURCE_API);
7411
7412     FIB_TEST(!fib_test_validate_entry(fei,
7413                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7414                                       1,
7415                                       &bucket_drop),
7416              "2.2.2.2/32 LB 1 buckets via: DROP");
7417
7418     fib_table_entry_delete(fib_index,
7419                            &pfx_2_2_2_2_s_32,
7420                            FIB_SOURCE_API);
7421     fib_table_entry_delete(fib_index,
7422                            &pfx_2_2_2_3_s_32,
7423                            FIB_SOURCE_API);
7424     fib_table_entry_delete(fib_index,
7425                            &pfx_2_2_2_4_s_32,
7426                            FIB_SOURCE_API);
7427
7428     adj_unlock(ai_mpls_10_10_10_1);
7429     adj_unlock(ai_mpls_10_10_11_2);
7430     adj_unlock(ai_v4_10_10_11_1);
7431     adj_unlock(ai_v4_10_10_11_2);
7432     adj_unlock(ai_mpls_10_10_11_1);
7433
7434     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7435              adj_nbr_db_size());
7436
7437     local0_pfx.fp_len = 32;
7438     fib_table_entry_delete(fib_index,
7439                            &local0_pfx,
7440                            FIB_SOURCE_INTERFACE);
7441     local0_pfx.fp_len = 24;
7442     fib_table_entry_delete(fib_index,
7443                            &local0_pfx,
7444                            FIB_SOURCE_INTERFACE);
7445     local1_pfx.fp_len = 32;
7446     fib_table_entry_delete(fib_index,
7447                            &local1_pfx,
7448                            FIB_SOURCE_INTERFACE);
7449     local1_pfx.fp_len = 24;
7450     fib_table_entry_delete(fib_index,
7451                            &local1_pfx,
7452                            FIB_SOURCE_INTERFACE);
7453
7454     /*
7455      * +1 for the drop LB in the MPLS tables.
7456      */
7457     FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7458              "Load-balance resources freed %d of %d",
7459              lb_count+1, pool_elts(load_balance_pool));
7460
7461     return (res);
7462 }
7463
7464 #define N_TEST_CHILDREN 4
7465 #define PARENT_INDEX 0
7466
7467 typedef struct fib_node_test_t_
7468 {
7469     fib_node_t node;
7470     u32 sibling;
7471     u32 index;
7472     fib_node_back_walk_ctx_t *ctxs;
7473     u32 destroyed;
7474 } fib_node_test_t;
7475
7476 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7477
7478 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7479
7480 #define FOR_EACH_TEST_CHILD(_tc)                \
7481     for (ii = 1, (_tc) = &fib_test_nodes[1];    \
7482          ii < N_TEST_CHILDREN+1;                \
7483          ii++, (_tc) = &fib_test_nodes[ii])
7484
7485 static fib_node_t *
7486 fib_test_child_get_node (fib_node_index_t index)
7487 {
7488     return (&fib_test_nodes[index].node);
7489 }
7490
7491 static int fib_test_walk_spawns_walks;
7492
7493 static fib_node_back_walk_rc_t
7494 fib_test_child_back_walk_notify (fib_node_t *node,
7495                                  fib_node_back_walk_ctx_t *ctx)
7496 {
7497     fib_node_test_t *tc = (fib_node_test_t*) node;
7498
7499     vec_add1(tc->ctxs, *ctx);
7500
7501     if (1 == fib_test_walk_spawns_walks)
7502         fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7503     if (2 == fib_test_walk_spawns_walks)
7504         fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7505                        FIB_WALK_PRIORITY_HIGH, ctx);
7506
7507     return (FIB_NODE_BACK_WALK_CONTINUE);
7508 }
7509
7510 static void
7511 fib_test_child_last_lock_gone (fib_node_t *node)
7512 {
7513     fib_node_test_t *tc = (fib_node_test_t *)node;
7514
7515     tc->destroyed = 1;
7516 }
7517
7518 /**
7519  * The FIB walk's graph node virtual function table
7520  */
7521 static const fib_node_vft_t fib_test_child_vft = {
7522     .fnv_get = fib_test_child_get_node,
7523     .fnv_last_lock = fib_test_child_last_lock_gone,
7524     .fnv_back_walk = fib_test_child_back_walk_notify,
7525 };
7526
7527 /*
7528  * the function (that should have been static but isn't so I can do this)
7529  * that processes the walk from the async queue,
7530  */
7531 f64 fib_walk_process_queues(vlib_main_t * vm,
7532                             const f64 quota);
7533 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7534
7535 static int
7536 fib_test_walk (void)
7537 {
7538     fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7539     fib_node_test_t *tc;
7540     vlib_main_t *vm;
7541     u32 ii, res;
7542
7543     res = 0;
7544     vm = vlib_get_main();
7545     fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7546
7547     /*
7548      * init a fake node on which we will add children
7549      */
7550     fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7551                   FIB_NODE_TYPE_TEST);
7552
7553     FOR_EACH_TEST_CHILD(tc)
7554     {
7555         fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7556         fib_node_lock(&tc->node);
7557         tc->ctxs = NULL;
7558         tc->index = ii;
7559         tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7560                                          PARENT_INDEX,
7561                                          FIB_NODE_TYPE_TEST, ii);
7562     }
7563
7564     /*
7565      * enqueue a walk across the parents children.
7566      */
7567     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7568
7569     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7570                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7571     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7572              "Parent has %d children pre-walk",
7573              fib_node_list_get_size(PARENT()->fn_children));
7574
7575     /*
7576      * give the walk a large amount of time so it gets to the end
7577      */
7578     fib_walk_process_queues(vm, 1);
7579
7580     FOR_EACH_TEST_CHILD(tc)
7581     {
7582         FIB_TEST(1 == vec_len(tc->ctxs),
7583                  "%d child visitsed %d times",
7584                  ii, vec_len(tc->ctxs));
7585         vec_free(tc->ctxs);
7586     }
7587     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7588              "Queue is empty post walk");
7589     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7590              "Parent has %d children post walk",
7591              fib_node_list_get_size(PARENT()->fn_children));
7592
7593     /*
7594      * walk again. should be no increase in the number of visits, since
7595      * the walk will have terminated.
7596      */
7597     fib_walk_process_queues(vm, 1);
7598
7599     FOR_EACH_TEST_CHILD(tc)
7600     {
7601         FIB_TEST(0 == vec_len(tc->ctxs),
7602                  "%d child visitsed %d times",
7603                  ii, vec_len(tc->ctxs));
7604     }
7605
7606     /*
7607      * schedule a low and hig priority walk. expect the high to be performed
7608      * before the low.
7609      * schedule the high prio walk first so that it is further from the head
7610      * of the dependency list. that way it won't merge with the low one.
7611      */
7612     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7613     low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7614
7615     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7616                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7617     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7618                    FIB_WALK_PRIORITY_LOW, &low_ctx);
7619
7620     fib_walk_process_queues(vm, 1);
7621
7622     FOR_EACH_TEST_CHILD(tc)
7623     {
7624         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7625                  "%d child visitsed by high prio walk", ii);
7626         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
7627                  "%d child visitsed by low prio walk", ii);
7628         vec_free(tc->ctxs);
7629     }
7630     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7631              "Queue is empty post prio walk");
7632     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7633              "Parent has %d children post prio walk",
7634              fib_node_list_get_size(PARENT()->fn_children));
7635
7636     /*
7637      * schedule 2 walks of the same priority that can be megred.
7638      * expect that each child is thus visited only once.
7639      */
7640     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7641     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7642
7643     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7644                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7645     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7646                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
7647
7648     fib_walk_process_queues(vm, 1);
7649
7650     FOR_EACH_TEST_CHILD(tc)
7651     {
7652         FIB_TEST(1 == vec_len(tc->ctxs),
7653                  "%d child visitsed %d times during merge walk",
7654                  ii, vec_len(tc->ctxs));
7655         vec_free(tc->ctxs);
7656     }
7657     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7658              "Queue is empty post merge walk");
7659     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7660              "Parent has %d children post merge walk",
7661              fib_node_list_get_size(PARENT()->fn_children));
7662
7663     /*
7664      * schedule 2 walks of the same priority that cannot be megred.
7665      * expect that each child is thus visited twice and in the order
7666      * in which the walks were scheduled.
7667      */
7668     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7669     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7670
7671     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7672                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7673     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7674                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
7675
7676     fib_walk_process_queues(vm, 1);
7677
7678     FOR_EACH_TEST_CHILD(tc)
7679     {
7680         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7681                  "%d child visitsed by high prio walk", ii);
7682         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
7683                  "%d child visitsed by low prio walk", ii);
7684         vec_free(tc->ctxs);
7685     }
7686     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7687              "Queue is empty post no-merge walk");
7688     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7689              "Parent has %d children post no-merge walk",
7690              fib_node_list_get_size(PARENT()->fn_children));
7691
7692     /*
7693      * schedule a walk that makes one one child progress.
7694      * we do this by giving the queue draining process zero
7695      * time quanta. it's a do..while loop, so it does something.
7696      */
7697     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7698
7699     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7700                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7701     fib_walk_process_queues(vm, 0);
7702
7703     FOR_EACH_TEST_CHILD(tc)
7704     {
7705         if (ii == N_TEST_CHILDREN)
7706         {
7707             FIB_TEST(1 == vec_len(tc->ctxs),
7708                      "%d child visitsed %d times in zero quanta walk",
7709                      ii, vec_len(tc->ctxs));
7710         }
7711         else
7712         {
7713             FIB_TEST(0 == vec_len(tc->ctxs),
7714                      "%d child visitsed %d times in 0 quanta walk",
7715                      ii, vec_len(tc->ctxs));
7716         }
7717     }
7718     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7719              "Queue is not empty post zero quanta walk");
7720     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7721              "Parent has %d children post zero qunta walk",
7722              fib_node_list_get_size(PARENT()->fn_children));
7723
7724     /*
7725      * another one step
7726      */
7727     fib_walk_process_queues(vm, 0);
7728
7729     FOR_EACH_TEST_CHILD(tc)
7730     {
7731         if (ii >= N_TEST_CHILDREN-1)
7732         {
7733             FIB_TEST(1 == vec_len(tc->ctxs),
7734                      "%d child visitsed %d times in 2nd zero quanta walk",
7735                      ii, vec_len(tc->ctxs));
7736         }
7737         else
7738         {
7739             FIB_TEST(0 == vec_len(tc->ctxs),
7740                      "%d child visitsed %d times in 2nd 0 quanta walk",
7741                      ii, vec_len(tc->ctxs));
7742         }
7743     }
7744     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7745              "Queue is not empty post zero quanta walk");
7746     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7747              "Parent has %d children post zero qunta walk",
7748              fib_node_list_get_size(PARENT()->fn_children));
7749
7750     /*
7751      * schedule another walk that will catch-up and merge.
7752      */
7753     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7754                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7755     fib_walk_process_queues(vm, 1);
7756
7757     FOR_EACH_TEST_CHILD(tc)
7758     {
7759         if (ii >= N_TEST_CHILDREN-1)
7760         {
7761             FIB_TEST(2 == vec_len(tc->ctxs),
7762                      "%d child visitsed %d times in 2nd zero quanta merge walk",
7763                      ii, vec_len(tc->ctxs));
7764             vec_free(tc->ctxs);
7765         }
7766         else
7767         {
7768             FIB_TEST(1 == vec_len(tc->ctxs),
7769                      "%d child visitsed %d times in 2nd 0 quanta merge walk",
7770                      ii, vec_len(tc->ctxs));
7771             vec_free(tc->ctxs);
7772         }
7773     }
7774     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7775              "Queue is not empty post 2nd zero quanta merge walk");
7776     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7777              "Parent has %d children post 2nd zero qunta merge walk",
7778              fib_node_list_get_size(PARENT()->fn_children));
7779
7780     /*
7781      * park a async walk in the middle of the list, then have an sync walk catch
7782      * it. same expectations as async catches async.
7783      */
7784     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7785
7786     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7787                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7788
7789     fib_walk_process_queues(vm, 0);
7790     fib_walk_process_queues(vm, 0);
7791
7792     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7793
7794     FOR_EACH_TEST_CHILD(tc)
7795     {
7796         if (ii >= N_TEST_CHILDREN-1)
7797         {
7798             FIB_TEST(2 == vec_len(tc->ctxs),
7799                      "%d child visitsed %d times in sync catches async walk",
7800                      ii, vec_len(tc->ctxs));
7801             vec_free(tc->ctxs);
7802         }
7803         else
7804         {
7805             FIB_TEST(1 == vec_len(tc->ctxs),
7806                      "%d child visitsed %d times in sync catches async walk",
7807                      ii, vec_len(tc->ctxs));
7808             vec_free(tc->ctxs);
7809         }
7810     }
7811     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7812              "Queue is not empty post 2nd zero quanta merge walk");
7813     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7814              "Parent has %d children post 2nd zero qunta merge walk",
7815              fib_node_list_get_size(PARENT()->fn_children));
7816
7817     /*
7818      * make the parent a child of one of its children, thus inducing a routing loop.
7819      */
7820     fib_test_nodes[PARENT_INDEX].sibling =
7821         fib_node_child_add(FIB_NODE_TYPE_TEST,
7822                            1, // the first child
7823                            FIB_NODE_TYPE_TEST,
7824                            PARENT_INDEX);
7825
7826     /*
7827      * execute a sync walk from the parent. each child visited spawns more sync
7828      * walks. we expect the walk to terminate.
7829      */
7830     fib_test_walk_spawns_walks = 1;
7831
7832     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7833
7834     FOR_EACH_TEST_CHILD(tc)
7835     {
7836         /*
7837          * child 1 - which is last in the list - has the loop.
7838          * the other children a re thus visitsed first. the we meet
7839          * child 1. we go round the loop again, visting the other children.
7840          * then we meet the walk in the dep list and bail. child 1 is not visitsed
7841          * again.
7842          */
7843         if (1 == ii)
7844         {
7845             FIB_TEST(1 == vec_len(tc->ctxs),
7846                      "child %d visitsed %d times during looped sync walk",
7847                      ii, vec_len(tc->ctxs));
7848         }
7849         else
7850         {
7851             FIB_TEST(2 == vec_len(tc->ctxs),
7852                      "child %d visitsed %d times during looped sync walk",
7853                      ii, vec_len(tc->ctxs));
7854         }
7855         vec_free(tc->ctxs);
7856     }
7857     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7858              "Parent has %d children post sync loop walk",
7859              fib_node_list_get_size(PARENT()->fn_children));
7860
7861     /*
7862      * the walk doesn't reach the max depth because the infra knows that sync
7863      * meets sync implies a loop and bails early.
7864      */
7865     FIB_TEST(high_ctx.fnbw_depth == 9,
7866              "Walk context depth %d post sync loop walk",
7867              high_ctx.fnbw_depth);
7868
7869     /*
7870      * execute an async walk of the graph loop, with each child spawns sync walks
7871      */
7872     high_ctx.fnbw_depth = 0;
7873     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7874                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7875
7876     fib_walk_process_queues(vm, 1);
7877
7878     FOR_EACH_TEST_CHILD(tc)
7879     {
7880         /*
7881          * we don't really care how many times the children are visited, as long as
7882          * it is more than once.
7883          */
7884         FIB_TEST(1 <= vec_len(tc->ctxs),
7885                  "child %d visitsed %d times during looped aync spawns sync walk",
7886                  ii, vec_len(tc->ctxs));
7887         vec_free(tc->ctxs);
7888     }
7889
7890     /*
7891      * execute an async walk of the graph loop, with each child spawns async walks
7892      */
7893     fib_test_walk_spawns_walks = 2;
7894     high_ctx.fnbw_depth = 0;
7895     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7896                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7897
7898     fib_walk_process_queues(vm, 1);
7899
7900     FOR_EACH_TEST_CHILD(tc)
7901     {
7902         /*
7903          * we don't really care how many times the children are visited, as long as
7904          * it is more than once.
7905          */
7906         FIB_TEST(1 <= vec_len(tc->ctxs),
7907                  "child %d visitsed %d times during looped async spawns async walk",
7908                  ii, vec_len(tc->ctxs));
7909         vec_free(tc->ctxs);
7910     }
7911
7912
7913     fib_node_child_remove(FIB_NODE_TYPE_TEST,
7914                           1, // the first child
7915                           fib_test_nodes[PARENT_INDEX].sibling);
7916
7917     /*
7918      * cleanup
7919      */
7920     FOR_EACH_TEST_CHILD(tc)
7921     {
7922         fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7923                               tc->sibling);
7924         fib_node_deinit(&tc->node);
7925         fib_node_unlock(&tc->node);
7926     }
7927     fib_node_deinit(PARENT());
7928
7929     /*
7930      * The parent will be destroyed when the last lock on it goes.
7931      * this test ensures all the walk objects are unlocking it.
7932      */
7933     FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7934              "Parent was destroyed");
7935
7936     return (res);
7937 }
7938
7939 /*
7940  * declaration of the otherwise static callback functions
7941  */
7942 void fib_bfd_notify (bfd_listen_event_e event,
7943                      const bfd_session_t *session);
7944 void adj_bfd_notify (bfd_listen_event_e event,
7945                      const bfd_session_t *session);
7946
7947 /**
7948  * Test BFD session interaction with FIB
7949  */
7950 static int
7951 fib_test_bfd (void)
7952 {
7953     fib_node_index_t fei;
7954     test_main_t *tm;
7955     int n_feis, res;
7956
7957     res = 0;
7958     /* via 10.10.10.1 */
7959     ip46_address_t nh_10_10_10_1 = {
7960         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7961     };
7962     /* via 10.10.10.2 */
7963     ip46_address_t nh_10_10_10_2 = {
7964         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7965     };
7966     /* via 10.10.10.10 */
7967     ip46_address_t nh_10_10_10_10 = {
7968         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7969     };
7970     n_feis = fib_entry_pool_size();
7971
7972     tm = &test_main;
7973
7974     /*
7975      * add interface routes. we'll assume this works. it's tested elsewhere
7976      */
7977     fib_prefix_t pfx_10_10_10_10_s_24 = {
7978         .fp_len = 24,
7979         .fp_proto = FIB_PROTOCOL_IP4,
7980         .fp_addr = nh_10_10_10_10,
7981     };
7982
7983     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7984                                     FIB_SOURCE_INTERFACE,
7985                                     (FIB_ENTRY_FLAG_CONNECTED |
7986                                      FIB_ENTRY_FLAG_ATTACHED),
7987                                     DPO_PROTO_IP4,
7988                                     NULL,
7989                                     tm->hw[0]->sw_if_index,
7990                                     ~0, // invalid fib index
7991                                     1, // weight
7992                                     NULL,
7993                                     FIB_ROUTE_PATH_FLAG_NONE);
7994
7995     fib_prefix_t pfx_10_10_10_10_s_32 = {
7996         .fp_len = 32,
7997         .fp_proto = FIB_PROTOCOL_IP4,
7998         .fp_addr = nh_10_10_10_10,
7999     };
8000     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
8001                                     FIB_SOURCE_INTERFACE,
8002                                     (FIB_ENTRY_FLAG_CONNECTED |
8003                                      FIB_ENTRY_FLAG_LOCAL),
8004                                     DPO_PROTO_IP4,
8005                                     NULL,
8006                                     tm->hw[0]->sw_if_index,
8007                                     ~0, // invalid fib index
8008                                     1, // weight
8009                                     NULL,
8010                                     FIB_ROUTE_PATH_FLAG_NONE);
8011
8012     /*
8013      * A BFD session via a neighbour we do not yet know
8014      */
8015     bfd_session_t bfd_10_10_10_1 = {
8016         .udp = {
8017             .key = {
8018                 .fib_index = 0,
8019                 .peer_addr = nh_10_10_10_1,
8020             },
8021         },
8022         .hop_type = BFD_HOP_TYPE_MULTI,
8023         .local_state = BFD_STATE_init,
8024     };
8025
8026     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8027
8028     /*
8029      * A new entry will be created that forwards via the adj
8030      */
8031     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8032                                                     VNET_LINK_IP4,
8033                                                     &nh_10_10_10_1,
8034                                                     tm->hw[0]->sw_if_index);
8035     fib_prefix_t pfx_10_10_10_1_s_32 = {
8036         .fp_addr = nh_10_10_10_1,
8037         .fp_len = 32,
8038         .fp_proto = FIB_PROTOCOL_IP4,
8039     };
8040     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
8041         .type = FT_LB_ADJ,
8042         .adj = {
8043             .adj = ai_10_10_10_1,
8044         },
8045     };
8046
8047     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8048     FIB_TEST(!fib_test_validate_entry(fei,
8049                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8050                                       1,
8051                                       &adj_o_10_10_10_1),
8052              "BFD sourced %U via %U",
8053              format_fib_prefix, &pfx_10_10_10_1_s_32,
8054              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
8055
8056     /*
8057      * Delete the BFD session. Expect the fib_entry to be removed
8058      */
8059     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8060
8061     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8062     FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
8063              "BFD sourced %U removed",
8064              format_fib_prefix, &pfx_10_10_10_1_s_32);
8065
8066     /*
8067      * Add the BFD source back
8068      */
8069     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8070
8071     /*
8072      * source the entry via the ADJ fib
8073      */
8074     fei = fib_table_entry_path_add(0,
8075                                    &pfx_10_10_10_1_s_32,
8076                                    FIB_SOURCE_ADJ,
8077                                    FIB_ENTRY_FLAG_ATTACHED,
8078                                    DPO_PROTO_IP4,
8079                                    &nh_10_10_10_1,
8080                                    tm->hw[0]->sw_if_index,
8081                                    ~0, // invalid fib index
8082                                    1,
8083                                    NULL,
8084                                    FIB_ROUTE_PATH_FLAG_NONE);
8085
8086     /*
8087      * Delete the BFD session. Expect the fib_entry to remain
8088      */
8089     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8090
8091     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8092     FIB_TEST(!fib_test_validate_entry(fei,
8093                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8094                                       1,
8095                                       &adj_o_10_10_10_1),
8096              "BFD sourced %U remains via %U",
8097              format_fib_prefix, &pfx_10_10_10_1_s_32,
8098              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
8099
8100     /*
8101      * Add the BFD source back
8102      */
8103     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8104
8105     /*
8106      * Create another ADJ FIB
8107      */
8108     fib_prefix_t pfx_10_10_10_2_s_32 = {
8109         .fp_addr = nh_10_10_10_2,
8110         .fp_len = 32,
8111         .fp_proto = FIB_PROTOCOL_IP4,
8112     };
8113     fib_table_entry_path_add(0,
8114                              &pfx_10_10_10_2_s_32,
8115                              FIB_SOURCE_ADJ,
8116                              FIB_ENTRY_FLAG_ATTACHED,
8117                              DPO_PROTO_IP4,
8118                              &nh_10_10_10_2,
8119                              tm->hw[0]->sw_if_index,
8120                              ~0, // invalid fib index
8121                              1,
8122                              NULL,
8123                              FIB_ROUTE_PATH_FLAG_NONE);
8124     /*
8125      * A BFD session for the new ADJ FIB
8126      */
8127     bfd_session_t bfd_10_10_10_2 = {
8128         .udp = {
8129             .key = {
8130                 .fib_index = 0,
8131                 .peer_addr = nh_10_10_10_2,
8132             },
8133         },
8134         .hop_type = BFD_HOP_TYPE_MULTI,
8135         .local_state = BFD_STATE_init,
8136     };
8137
8138     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
8139
8140     /*
8141      * remove the adj-fib source whilst the session is present
8142      * then add it back
8143      */
8144     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8145     fib_table_entry_path_add(0,
8146                              &pfx_10_10_10_2_s_32,
8147                              FIB_SOURCE_ADJ,
8148                              FIB_ENTRY_FLAG_ATTACHED,
8149                              DPO_PROTO_IP4,
8150                              &nh_10_10_10_2,
8151                              tm->hw[0]->sw_if_index,
8152                              ~0, // invalid fib index
8153                              1,
8154                              NULL,
8155                              FIB_ROUTE_PATH_FLAG_NONE);
8156
8157     /*
8158      * Before adding a recursive via the BFD tracked ADJ-FIBs,
8159      * bring one of the sessions UP, leave the other down
8160      */
8161     bfd_10_10_10_1.local_state = BFD_STATE_up;
8162     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8163     bfd_10_10_10_2.local_state = BFD_STATE_down;
8164     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8165
8166     /*
8167      * A recursive prefix via both of the ADJ FIBs
8168      */
8169     fib_prefix_t pfx_200_0_0_0_s_24 = {
8170         .fp_proto = FIB_PROTOCOL_IP4,
8171         .fp_len = 32,
8172         .fp_addr = {
8173             .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
8174         },
8175     };
8176     const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
8177
8178     dpo_10_10_10_1 =
8179         fib_entry_contribute_ip_forwarding(
8180             fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
8181     dpo_10_10_10_2 =
8182         fib_entry_contribute_ip_forwarding(
8183             fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
8184
8185     fib_test_lb_bucket_t lb_o_10_10_10_1 = {
8186         .type = FT_LB_O_LB,
8187         .lb = {
8188             .lb = dpo_10_10_10_1->dpoi_index,
8189         },
8190     };
8191     fib_test_lb_bucket_t lb_o_10_10_10_2 = {
8192         .type = FT_LB_O_LB,
8193         .lb = {
8194             .lb = dpo_10_10_10_2->dpoi_index,
8195         },
8196     };
8197
8198     /*
8199      * A prefix via the adj-fib that is BFD down => DROP
8200      */
8201     fei = fib_table_entry_path_add(0,
8202                                    &pfx_200_0_0_0_s_24,
8203                                    FIB_SOURCE_API,
8204                                    FIB_ENTRY_FLAG_NONE,
8205                                    DPO_PROTO_IP4,
8206                                    &nh_10_10_10_2,
8207                                    ~0, // recursive
8208                                    0, // default fib index
8209                                    1,
8210                                    NULL,
8211                                    FIB_ROUTE_PATH_FLAG_NONE);
8212     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8213              "%U resolves via drop",
8214              format_fib_prefix, &pfx_200_0_0_0_s_24);
8215
8216     /*
8217      * add a path via the UP BFD adj-fib.
8218      *  we expect that the DOWN BFD ADJ FIB is not used.
8219      */
8220     fei = fib_table_entry_path_add(0,
8221                                    &pfx_200_0_0_0_s_24,
8222                                    FIB_SOURCE_API,
8223                                    FIB_ENTRY_FLAG_NONE,
8224                                    DPO_PROTO_IP4,
8225                                    &nh_10_10_10_1,
8226                                    ~0, // recursive
8227                                    0, // default fib index
8228                                    1,
8229                                    NULL,
8230                                    FIB_ROUTE_PATH_FLAG_NONE);
8231
8232     FIB_TEST(!fib_test_validate_entry(fei,
8233                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8234                                       1,
8235                                       &lb_o_10_10_10_1),
8236              "Recursive %U only UP BFD adj-fibs",
8237              format_fib_prefix, &pfx_200_0_0_0_s_24);
8238
8239     /*
8240      * Send a BFD state change to UP - both sessions are now up
8241      *  the recursive prefix should LB over both
8242      */
8243     bfd_10_10_10_2.local_state = BFD_STATE_up;
8244     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8245
8246
8247     FIB_TEST(!fib_test_validate_entry(fei,
8248                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8249                                       2,
8250                                       &lb_o_10_10_10_1,
8251                                       &lb_o_10_10_10_2),
8252              "Recursive %U via both UP BFD adj-fibs",
8253              format_fib_prefix, &pfx_200_0_0_0_s_24);
8254
8255     /*
8256      * Send a BFD state change to DOWN
8257      *  the recursive prefix should exclude the down
8258      */
8259     bfd_10_10_10_2.local_state = BFD_STATE_down;
8260     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8261
8262
8263     FIB_TEST(!fib_test_validate_entry(fei,
8264                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8265                                       1,
8266                                       &lb_o_10_10_10_1),
8267              "Recursive %U via only UP",
8268              format_fib_prefix, &pfx_200_0_0_0_s_24);
8269
8270     /*
8271      * Delete the BFD session while it is in the DOWN state.
8272      *  FIB should consider the entry's state as back up
8273      */
8274     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8275
8276     FIB_TEST(!fib_test_validate_entry(fei,
8277                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8278                                       2,
8279                                       &lb_o_10_10_10_1,
8280                                       &lb_o_10_10_10_2),
8281              "Recursive %U via both UP BFD adj-fibs post down session delete",
8282              format_fib_prefix, &pfx_200_0_0_0_s_24);
8283
8284     /*
8285      * Delete the BFD other session while it is in the UP state.
8286      */
8287     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8288
8289     FIB_TEST(!fib_test_validate_entry(fei,
8290                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8291                                       2,
8292                                       &lb_o_10_10_10_1,
8293                                       &lb_o_10_10_10_2),
8294              "Recursive %U via both UP BFD adj-fibs post up session delete",
8295              format_fib_prefix, &pfx_200_0_0_0_s_24);
8296
8297     /*
8298      * cleaup
8299      */
8300     fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8301     fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8302     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8303
8304     fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8305     fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8306
8307     adj_unlock(ai_10_10_10_1);
8308     /*
8309      * test no-one left behind
8310      */
8311     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8312     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8313
8314     /*
8315      * Single-hop BFD tests
8316      */
8317     bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8318     bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8319
8320     adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8321
8322     ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8323                                         VNET_LINK_IP4,
8324                                         &nh_10_10_10_1,
8325                                         tm->hw[0]->sw_if_index);
8326     /*
8327      * whilst the BFD session is not signalled, the adj is up
8328      */
8329     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on uninit session");
8330
8331     /*
8332      * bring the BFD session up
8333      */
8334     bfd_10_10_10_1.local_state = BFD_STATE_up;
8335     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8336     FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8337
8338     /*
8339      * bring the BFD session down
8340      */
8341     bfd_10_10_10_1.local_state = BFD_STATE_down;
8342     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8343     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8344
8345     /*
8346      * add an attached next hop FIB entry via the down adj
8347      */
8348     fib_prefix_t pfx_5_5_5_5_s_32 = {
8349         .fp_addr = {
8350             .ip4 = {
8351                 .as_u32 = clib_host_to_net_u32(0x05050505),
8352             },
8353         },
8354         .fp_len = 32,
8355         .fp_proto = FIB_PROTOCOL_IP4,
8356     };
8357
8358     fei = fib_table_entry_path_add(0,
8359                                    &pfx_5_5_5_5_s_32,
8360                                    FIB_SOURCE_CLI,
8361                                    FIB_ENTRY_FLAG_NONE,
8362                                    DPO_PROTO_IP4,
8363                                    &nh_10_10_10_1,
8364                                    tm->hw[0]->sw_if_index,
8365                                    ~0, // invalid fib index
8366                                    1,
8367                                    NULL,
8368                                    FIB_ROUTE_PATH_FLAG_NONE);
8369     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8370              "%U resolves via drop",
8371              format_fib_prefix, &pfx_5_5_5_5_s_32);
8372
8373     /*
8374      * Add a path via an ADJ that is up
8375      */
8376     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8377                                                     VNET_LINK_IP4,
8378                                                     &nh_10_10_10_2,
8379                                                     tm->hw[0]->sw_if_index);
8380
8381     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8382         .type = FT_LB_ADJ,
8383         .adj = {
8384             .adj = ai_10_10_10_2,
8385         },
8386     };
8387     adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8388
8389     fei = fib_table_entry_path_add(0,
8390                                    &pfx_5_5_5_5_s_32,
8391                                    FIB_SOURCE_CLI,
8392                                    FIB_ENTRY_FLAG_NONE,
8393                                    DPO_PROTO_IP4,
8394                                    &nh_10_10_10_2,
8395                                    tm->hw[0]->sw_if_index,
8396                                    ~0, // invalid fib index
8397                                    1,
8398                                    NULL,
8399                                    FIB_ROUTE_PATH_FLAG_NONE);
8400
8401     FIB_TEST(!fib_test_validate_entry(fei,
8402                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8403                                       1,
8404                                       &adj_o_10_10_10_2),
8405              "BFD sourced %U via %U",
8406              format_fib_prefix, &pfx_5_5_5_5_s_32,
8407              format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8408
8409     /*
8410      * Bring up the down session - should now LB
8411      */
8412     bfd_10_10_10_1.local_state = BFD_STATE_up;
8413     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8414     FIB_TEST(!fib_test_validate_entry(fei,
8415                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8416                                       2,
8417                                       &adj_o_10_10_10_1,
8418                                       &adj_o_10_10_10_2),
8419              "BFD sourced %U via noth adjs",
8420              format_fib_prefix, &pfx_5_5_5_5_s_32);
8421
8422     /*
8423      * remove the BFD session state from the adj
8424      */
8425     adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8426
8427     /*
8428      * clean-up
8429      */
8430     fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8431     adj_unlock(ai_10_10_10_1);
8432     adj_unlock(ai_10_10_10_2);
8433
8434     /*
8435      * test no-one left behind
8436      */
8437     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8438     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8439
8440     return (res);
8441 }
8442
8443 static int
8444 lfib_test (void)
8445 {
8446     const mpls_label_t deag_label = 50;
8447     adj_index_t ai_mpls_10_10_10_1;
8448     dpo_id_t dpo = DPO_INVALID;
8449     const u32 lfib_index = 0;
8450     const u32 fib_index = 0;
8451     const dpo_id_t *dpo1;
8452     fib_node_index_t lfe;
8453     lookup_dpo_t *lkd;
8454     int lb_count, res;
8455     test_main_t *tm;
8456
8457     res = 0;
8458     tm = &test_main;
8459     lb_count = pool_elts(load_balance_pool);
8460
8461     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8462              adj_nbr_db_size());
8463
8464     /*
8465      * MPLS enable an interface so we get the MPLS table created
8466      */
8467     mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8468     mpls_sw_interface_enable_disable(&mpls_main,
8469                                      tm->hw[0]->sw_if_index,
8470                                      1, 1);
8471
8472     ip46_address_t nh_10_10_10_1 = {
8473         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8474     };
8475     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8476                                              VNET_LINK_MPLS,
8477                                              &nh_10_10_10_1,
8478                                              tm->hw[0]->sw_if_index);
8479
8480     /*
8481      * Test the specials stack properly.
8482      */
8483     fib_prefix_t exp_null_v6_pfx = {
8484         .fp_proto = FIB_PROTOCOL_MPLS,
8485         .fp_eos = MPLS_EOS,
8486         .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8487         .fp_payload_proto = DPO_PROTO_IP6,
8488     };
8489     lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8490     FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8491              "%U/%U present",
8492              format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8493              format_mpls_eos_bit, MPLS_EOS);
8494     fib_entry_contribute_forwarding(lfe,
8495                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8496                                     &dpo);
8497     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8498     lkd = lookup_dpo_get(dpo1->dpoi_index);
8499
8500     FIB_TEST((fib_index == lkd->lkd_fib_index),
8501              "%U/%U is deag in %d %U",
8502              format_mpls_unicast_label, deag_label,
8503              format_mpls_eos_bit, MPLS_EOS,
8504              lkd->lkd_fib_index,
8505              format_dpo_id, &dpo, 0);
8506     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8507              "%U/%U is dst deag",
8508              format_mpls_unicast_label, deag_label,
8509              format_mpls_eos_bit, MPLS_EOS);
8510     FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8511              "%U/%U is lookup in interface's table",
8512              format_mpls_unicast_label, deag_label,
8513              format_mpls_eos_bit, MPLS_EOS);
8514     FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8515              "%U/%U is %U dst deag",
8516              format_mpls_unicast_label, deag_label,
8517              format_mpls_eos_bit, MPLS_EOS,
8518              format_dpo_proto, lkd->lkd_proto);
8519
8520     /*
8521      * A route deag route for EOS
8522      */
8523     fib_prefix_t pfx = {
8524         .fp_proto = FIB_PROTOCOL_MPLS,
8525         .fp_eos = MPLS_EOS,
8526         .fp_label = deag_label,
8527         .fp_payload_proto = DPO_PROTO_IP4,
8528     };
8529     mpls_disp_dpo_t *mdd;
8530     lfe = fib_table_entry_path_add(lfib_index,
8531                                    &pfx,
8532                                    FIB_SOURCE_CLI,
8533                                    FIB_ENTRY_FLAG_NONE,
8534                                    DPO_PROTO_IP4,
8535                                    &zero_addr,
8536                                    ~0,
8537                                    fib_index,
8538                                    1,
8539                                    NULL,
8540                                    FIB_ROUTE_PATH_FLAG_NONE);
8541
8542     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8543              "%U/%U present",
8544              format_mpls_unicast_label, deag_label,
8545              format_mpls_eos_bit, MPLS_EOS);
8546
8547     fib_entry_contribute_forwarding(lfe,
8548                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8549                                     &dpo);
8550     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8551     mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8552
8553     FIB_TEST((FIB_MPLS_LSP_MODE_PIPE == mdd->mdd_mode),
8554              "%U/%U disp is pipe mode",
8555              format_mpls_unicast_label, deag_label,
8556              format_mpls_eos_bit, MPLS_EOS);
8557
8558     lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8559
8560     FIB_TEST((fib_index == lkd->lkd_fib_index),
8561              "%U/%U is deag in %d %U",
8562              format_mpls_unicast_label, deag_label,
8563              format_mpls_eos_bit, MPLS_EOS,
8564              lkd->lkd_fib_index,
8565              format_dpo_id, &dpo, 0);
8566     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8567              "%U/%U is dst deag",
8568              format_mpls_unicast_label, deag_label,
8569              format_mpls_eos_bit, MPLS_EOS);
8570     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8571              "%U/%U is %U dst deag",
8572              format_mpls_unicast_label, deag_label,
8573              format_mpls_eos_bit, MPLS_EOS,
8574              format_dpo_proto, lkd->lkd_proto);
8575
8576     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8577
8578     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8579                                                          &pfx)),
8580               "%U/%U not present",
8581               format_mpls_unicast_label, deag_label,
8582               format_mpls_eos_bit, MPLS_EOS);
8583     dpo_reset(&dpo);
8584
8585     /*
8586      * A route deag route for EOS with LSP mode uniform
8587      */
8588     fib_mpls_label_t *l_pops = NULL, l_pop = {
8589         .fml_value = MPLS_LABEL_POP,
8590         .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
8591     };
8592     vec_add1(l_pops, l_pop);
8593     lfe = fib_table_entry_path_add(lfib_index,
8594                                    &pfx,
8595                                    FIB_SOURCE_CLI,
8596                                    FIB_ENTRY_FLAG_NONE,
8597                                    DPO_PROTO_IP4,
8598                                    &zero_addr,
8599                                    ~0,
8600                                    fib_index,
8601                                    1,
8602                                    l_pops,
8603                                    FIB_ROUTE_PATH_FLAG_NONE);
8604
8605     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8606               "%U/%U present",
8607               format_mpls_unicast_label, deag_label,
8608               format_mpls_eos_bit, MPLS_EOS);
8609
8610     fib_entry_contribute_forwarding(lfe,
8611                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8612                                     &dpo);
8613     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8614     mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8615
8616     FIB_TEST((FIB_MPLS_LSP_MODE_UNIFORM == mdd->mdd_mode),
8617              "%U/%U disp is uniform mode",
8618              format_mpls_unicast_label, deag_label,
8619              format_mpls_eos_bit, MPLS_EOS);
8620
8621     lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8622
8623     FIB_TEST((fib_index == lkd->lkd_fib_index),
8624               "%U/%U is deag in %d %U",
8625              format_mpls_unicast_label, deag_label,
8626              format_mpls_eos_bit, MPLS_EOS,
8627              lkd->lkd_fib_index,
8628              format_dpo_id, &dpo, 0);
8629     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8630              "%U/%U is dst deag",
8631              format_mpls_unicast_label, deag_label,
8632              format_mpls_eos_bit, MPLS_EOS);
8633     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8634              "%U/%U is %U dst deag",
8635              format_mpls_unicast_label, deag_label,
8636              format_mpls_eos_bit, MPLS_EOS,
8637              format_dpo_proto, lkd->lkd_proto);
8638
8639     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8640
8641     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8642                                                          &pfx)),
8643               "%U/%U not present",
8644               format_mpls_unicast_label, deag_label,
8645               format_mpls_eos_bit, MPLS_EOS);
8646     dpo_reset(&dpo);
8647
8648     /*
8649      * A route deag route for non-EOS
8650      */
8651     pfx.fp_eos = MPLS_NON_EOS;
8652     lfe = fib_table_entry_path_add(lfib_index,
8653                                    &pfx,
8654                                    FIB_SOURCE_CLI,
8655                                    FIB_ENTRY_FLAG_NONE,
8656                                    DPO_PROTO_IP4,
8657                                    &zero_addr,
8658                                    ~0,
8659                                    lfib_index,
8660                                    1,
8661                                    NULL,
8662                                    FIB_ROUTE_PATH_FLAG_NONE);
8663
8664     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8665              "%U/%U present",
8666              format_mpls_unicast_label, deag_label,
8667              format_mpls_eos_bit, MPLS_NON_EOS);
8668
8669     fib_entry_contribute_forwarding(lfe,
8670                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8671                                     &dpo);
8672     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8673     lkd = lookup_dpo_get(dpo1->dpoi_index);
8674
8675     FIB_TEST((fib_index == lkd->lkd_fib_index),
8676              "%U/%U is deag in %d %U",
8677              format_mpls_unicast_label, deag_label,
8678              format_mpls_eos_bit, MPLS_NON_EOS,
8679              lkd->lkd_fib_index,
8680              format_dpo_id, &dpo, 0);
8681     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8682              "%U/%U is dst deag",
8683              format_mpls_unicast_label, deag_label,
8684              format_mpls_eos_bit, MPLS_NON_EOS);
8685
8686     FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8687              "%U/%U is %U dst deag",
8688              format_mpls_unicast_label, deag_label,
8689              format_mpls_eos_bit, MPLS_NON_EOS,
8690              format_dpo_proto, lkd->lkd_proto);
8691
8692     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8693
8694     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8695                                                          &pfx)),
8696              "%U/%U not present",
8697              format_mpls_unicast_label, deag_label,
8698              format_mpls_eos_bit, MPLS_EOS);
8699
8700     dpo_reset(&dpo);
8701
8702     /*
8703      * An MPLS x-connect
8704      */
8705     fib_prefix_t pfx_1200 = {
8706         .fp_len = 21,
8707         .fp_proto = FIB_PROTOCOL_MPLS,
8708         .fp_label = 1200,
8709         .fp_eos = MPLS_NON_EOS,
8710     };
8711     fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8712         .type = FT_LB_LABEL_STACK_O_ADJ,
8713         .label_stack_o_adj = {
8714             .adj = ai_mpls_10_10_10_1,
8715             .label_stack_size = 4,
8716             .label_stack = {
8717                 200, 300, 400, 500,
8718             },
8719             .eos = MPLS_NON_EOS,
8720         },
8721     };
8722     dpo_id_t neos_1200 = DPO_INVALID;
8723     dpo_id_t ip_1200 = DPO_INVALID;
8724     fib_mpls_label_t *l200 = NULL;
8725     u32 ii;
8726     for (ii = 0; ii < 4; ii++)
8727     {
8728         fib_mpls_label_t fml = {
8729             .fml_value = 200 + (ii * 100),
8730         };
8731         vec_add1(l200, fml);
8732     };
8733
8734     lfe = fib_table_entry_update_one_path(fib_index,
8735                                           &pfx_1200,
8736                                           FIB_SOURCE_API,
8737                                           FIB_ENTRY_FLAG_NONE,
8738                                           DPO_PROTO_IP4,
8739                                           &nh_10_10_10_1,
8740                                           tm->hw[0]->sw_if_index,
8741                                           ~0, // invalid fib index
8742                                           1,
8743                                           l200,
8744                                           FIB_ROUTE_PATH_FLAG_NONE);
8745
8746     FIB_TEST(!fib_test_validate_entry(lfe,
8747                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8748                                       1,
8749                                       &neos_o_10_10_10_1),
8750              "1200/0 LB 1 buckets via: "
8751              "adj 10.10.11.1");
8752
8753     /*
8754      * A recursive route via the MPLS x-connect
8755      */
8756     fib_prefix_t pfx_2_2_2_3_s_32 = {
8757         .fp_len = 32,
8758         .fp_proto = FIB_PROTOCOL_IP4,
8759         .fp_addr = {
8760             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8761         },
8762     };
8763     fib_route_path_t *rpaths = NULL, rpath = {
8764         .frp_proto = DPO_PROTO_MPLS,
8765         .frp_local_label = 1200,
8766         .frp_eos = MPLS_NON_EOS,
8767         .frp_sw_if_index = ~0, // recurive
8768         .frp_fib_index = 0, // Default MPLS fib
8769         .frp_weight = 1,
8770         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8771         .frp_label_stack = NULL,
8772     };
8773     vec_add1(rpaths, rpath);
8774
8775     fib_table_entry_path_add2(fib_index,
8776                               &pfx_2_2_2_3_s_32,
8777                               FIB_SOURCE_API,
8778                               FIB_ENTRY_FLAG_NONE,
8779                               rpaths);
8780
8781     /*
8782      * A labelled recursive route via the MPLS x-connect
8783      */
8784     fib_prefix_t pfx_2_2_2_4_s_32 = {
8785         .fp_len = 32,
8786         .fp_proto = FIB_PROTOCOL_IP4,
8787         .fp_addr = {
8788             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8789         },
8790     };
8791     fib_mpls_label_t *l999 = NULL, fml_999 = {
8792         .fml_value = 999,
8793     };
8794     vec_add1(l999, fml_999);
8795     rpaths[0].frp_label_stack = l999,
8796
8797         fib_table_entry_path_add2(fib_index,
8798                                   &pfx_2_2_2_4_s_32,
8799                                   FIB_SOURCE_API,
8800                                   FIB_ENTRY_FLAG_NONE,
8801                                   rpaths);
8802
8803     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8804                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8805                                     &ip_1200);
8806     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8807                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8808                                     &neos_1200);
8809
8810     fib_test_lb_bucket_t ip_o_1200 = {
8811         .type = FT_LB_O_LB,
8812         .lb = {
8813             .lb = ip_1200.dpoi_index,
8814         },
8815     };
8816     fib_test_lb_bucket_t mpls_o_1200 = {
8817         .type = FT_LB_LABEL_O_LB,
8818         .label_o_lb = {
8819             .lb = neos_1200.dpoi_index,
8820             .label = 999,
8821             .eos = MPLS_EOS,
8822         },
8823     };
8824
8825     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8826     FIB_TEST(!fib_test_validate_entry(lfe,
8827                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8828                                       1,
8829                                       &ip_o_1200),
8830              "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8831     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8832     FIB_TEST(!fib_test_validate_entry(lfe,
8833                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8834                                       1,
8835                                       &mpls_o_1200),
8836              "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8837
8838     fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8839     fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8840     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8841
8842     dpo_reset(&neos_1200);
8843     dpo_reset(&ip_1200);
8844
8845     /*
8846      * A recursive via a label that does not exist
8847      */
8848     fib_test_lb_bucket_t bucket_drop = {
8849         .type = FT_LB_DROP,
8850         .special = {
8851             .adj = DPO_PROTO_IP4,
8852         },
8853     };
8854     fib_test_lb_bucket_t mpls_bucket_drop = {
8855         .type = FT_LB_DROP,
8856         .special = {
8857             .adj = DPO_PROTO_MPLS,
8858         },
8859     };
8860
8861     rpaths[0].frp_label_stack = NULL;
8862     lfe = fib_table_entry_path_add2(fib_index,
8863                                     &pfx_2_2_2_4_s_32,
8864                                     FIB_SOURCE_API,
8865                                     FIB_ENTRY_FLAG_NONE,
8866                                     rpaths);
8867
8868     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8869                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8870                                     &ip_1200);
8871     ip_o_1200.lb.lb = ip_1200.dpoi_index;
8872
8873     FIB_TEST(!fib_test_validate_entry(lfe,
8874                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8875                                       1,
8876                                       &bucket_drop),
8877              "2.2.2.2.4/32 LB 1 buckets via: drop");
8878     lfe = fib_table_lookup(fib_index, &pfx_1200);
8879     FIB_TEST(!fib_test_validate_entry(lfe,
8880                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8881                                       1,
8882                                       &bucket_drop),
8883              "1200/neos LB 1 buckets via: ip4-DROP");
8884     FIB_TEST(!fib_test_validate_entry(lfe,
8885                                       FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8886                                       1,
8887                                       &mpls_bucket_drop),
8888              "1200/neos LB 1 buckets via: mpls-DROP");
8889
8890     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8891
8892     dpo_reset(&ip_1200);
8893
8894     /*
8895      * An rx-interface route.
8896      *  like the tail of an mcast LSP
8897      */
8898     dpo_id_t idpo = DPO_INVALID;
8899
8900     interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8901                                  tm->hw[0]->sw_if_index,
8902                                  &idpo);
8903
8904     fib_prefix_t pfx_2500 = {
8905         .fp_len = 21,
8906         .fp_proto = FIB_PROTOCOL_MPLS,
8907         .fp_label = 2500,
8908         .fp_eos = MPLS_EOS,
8909         .fp_payload_proto = DPO_PROTO_IP4,
8910     };
8911     fib_test_lb_bucket_t rx_intf_0 = {
8912         .type = FT_LB_INTF,
8913         .adj = {
8914             .adj = idpo.dpoi_index,
8915         },
8916     };
8917
8918     lfe = fib_table_entry_update_one_path(fib_index,
8919                                           &pfx_2500,
8920                                           FIB_SOURCE_API,
8921                                           FIB_ENTRY_FLAG_NONE,
8922                                           DPO_PROTO_IP4,
8923                                           NULL,
8924                                           tm->hw[0]->sw_if_index,
8925                                           ~0, // invalid fib index
8926                                           0,
8927                                           NULL,
8928                                           FIB_ROUTE_PATH_INTF_RX);
8929     FIB_TEST(!fib_test_validate_entry(lfe,
8930                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8931                                       1,
8932                                       &rx_intf_0),
8933              "2500 rx-interface 0");
8934     fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8935
8936     /*
8937      * An MPLS mulicast entry
8938      */
8939     fib_prefix_t pfx_3500 = {
8940         .fp_len = 21,
8941         .fp_proto = FIB_PROTOCOL_MPLS,
8942         .fp_label = 3500,
8943         .fp_eos = MPLS_EOS,
8944         .fp_payload_proto = DPO_PROTO_IP4,
8945     };
8946     fib_test_rep_bucket_t mc_0 = {
8947         .type = FT_REP_LABEL_O_ADJ,
8948         .label_o_adj = {
8949             .adj = ai_mpls_10_10_10_1,
8950             .label = 3300,
8951             .eos = MPLS_EOS,
8952         },
8953     };
8954     fib_test_rep_bucket_t mc_intf_0 = {
8955         .type = FT_REP_INTF,
8956         .adj = {
8957             .adj = idpo.dpoi_index,
8958         },
8959     };
8960     fib_mpls_label_t *l3300 = NULL, fml_3300 = {
8961         .fml_value = 3300,
8962     };
8963     vec_add1(l3300, fml_3300);
8964
8965     lfe = fib_table_entry_update_one_path(lfib_index,
8966                                           &pfx_3500,
8967                                           FIB_SOURCE_API,
8968                                           FIB_ENTRY_FLAG_MULTICAST,
8969                                           DPO_PROTO_IP4,
8970                                           &nh_10_10_10_1,
8971                                           tm->hw[0]->sw_if_index,
8972                                           ~0, // invalid fib index
8973                                           1,
8974                                           l3300,
8975                                           FIB_ROUTE_PATH_FLAG_NONE);
8976     FIB_TEST(!fib_test_validate_entry(lfe,
8977                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8978                                       1,
8979                                       &mc_0),
8980              "3500 via replicate over 10.10.10.1");
8981
8982     /*
8983      * MPLS Bud-node. Add a replication via an interface-receieve path
8984      */
8985     lfe = fib_table_entry_path_add(lfib_index,
8986                                    &pfx_3500,
8987                                    FIB_SOURCE_API,
8988                                    FIB_ENTRY_FLAG_MULTICAST,
8989                                    DPO_PROTO_IP4,
8990                                    NULL,
8991                                    tm->hw[0]->sw_if_index,
8992                                    ~0, // invalid fib index
8993                                    0,
8994                                    NULL,
8995                                    FIB_ROUTE_PATH_INTF_RX);
8996     FIB_TEST(!fib_test_validate_entry(lfe,
8997                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8998                                       2,
8999                                       &mc_0,
9000                                       &mc_intf_0),
9001              "3500 via replicate over 10.10.10.1 and interface-rx");
9002
9003     /*
9004      * Add a replication via an interface-free for-us path
9005      */
9006     fib_test_rep_bucket_t mc_disp = {
9007         .type = FT_REP_DISP_MFIB_LOOKUP,
9008         .adj = {
9009             .adj = idpo.dpoi_index,
9010         },
9011     };
9012     lfe = fib_table_entry_path_add(lfib_index,
9013                                    &pfx_3500,
9014                                    FIB_SOURCE_API,
9015                                    FIB_ENTRY_FLAG_MULTICAST,
9016                                    DPO_PROTO_IP4,
9017                                    NULL,
9018                                    5, // rpf-id
9019                                    0, // default table
9020                                    0,
9021                                    NULL,
9022                                    FIB_ROUTE_PATH_RPF_ID);
9023     FIB_TEST(!fib_test_validate_entry(lfe,
9024                                       FIB_FORW_CHAIN_TYPE_MPLS_EOS,
9025                                       3,
9026                                       &mc_0,
9027                                       &mc_disp,
9028                                       &mc_intf_0),
9029              "3500 via replicate over 10.10.10.1 and interface-rx");
9030
9031
9032
9033     fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
9034     dpo_reset(&idpo);
9035
9036     /*
9037      * cleanup
9038      */
9039     mpls_sw_interface_enable_disable(&mpls_main,
9040                                      tm->hw[0]->sw_if_index,
9041                                      0, 1);
9042     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
9043
9044     FIB_TEST(0 == pool_elts(mpls_disp_dpo_pool),
9045              "mpls_disp_dpo resources freed %d of %d",
9046              0, pool_elts(mpls_disp_dpo_pool));
9047     FIB_TEST(lb_count == pool_elts(load_balance_pool),
9048              "Load-balance resources freed %d of %d",
9049              lb_count, pool_elts(load_balance_pool));
9050     FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
9051              "interface_rx_dpo resources freed %d of %d",
9052              0, pool_elts(interface_rx_dpo_pool));
9053
9054     return (res);
9055 }
9056
9057 static int
9058 fib_test_inherit (void)
9059 {
9060     fib_node_index_t fei;
9061     int n_feis, res, i;
9062     test_main_t *tm;
9063     ip4_main_t *im4;
9064     ip6_main_t *im6;
9065
9066     tm = &test_main;
9067     im4 = &ip4_main;
9068     im6 = &ip6_main;
9069     res = 0;
9070
9071     vec_validate(im4->fib_index_by_sw_if_index, tm->hw[2]->sw_if_index);
9072     vec_validate(im6->fib_index_by_sw_if_index, tm->hw[2]->sw_if_index);
9073
9074     for (i = 0; i <= 2; i++)
9075     {
9076         im4->fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
9077         im6->fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
9078     }
9079     n_feis = fib_entry_pool_size();
9080
9081     const ip46_address_t nh_10_10_10_1 = {
9082         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
9083     };
9084     const ip46_address_t nh_10_10_10_2 = {
9085         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
9086     };
9087     const ip46_address_t nh_10_10_10_3 = {
9088         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
9089     };
9090     const ip46_address_t nh_10_10_10_16 = {
9091         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a10),
9092     };
9093     const ip46_address_t nh_10_10_10_20 = {
9094         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a14),
9095     };
9096     const ip46_address_t nh_10_10_10_21 = {
9097         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a15),
9098     };
9099     const ip46_address_t nh_10_10_10_22 = {
9100         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a16),
9101     };
9102     const ip46_address_t nh_10_10_10_255 = {
9103         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0aff),
9104     };
9105     const ip46_address_t nh_10_10_10_0 = {
9106         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a00),
9107     };
9108     const ip46_address_t nh_10_10_0_0 = {
9109         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0000),
9110     };
9111     const ip46_address_t nh_11_11_11_11 = {
9112         .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
9113     };
9114     const ip46_address_t nh_11_11_11_0 = {
9115         .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b00),
9116     };
9117
9118     /*
9119      * prefixes at the base of a sub-tree
9120      */
9121     const fib_prefix_t pfx_10_10_10_21_s_32 = {
9122         .fp_len = 32,
9123         .fp_proto = FIB_PROTOCOL_IP4,
9124         .fp_addr = nh_10_10_10_21,
9125     };
9126     const fib_prefix_t pfx_10_10_10_22_s_32 = {
9127         .fp_len = 32,
9128         .fp_proto = FIB_PROTOCOL_IP4,
9129         .fp_addr = nh_10_10_10_22,
9130     };
9131     const fib_prefix_t pfx_10_10_10_255_s_32 = {
9132         .fp_len = 32,
9133         .fp_proto = FIB_PROTOCOL_IP4,
9134         .fp_addr = nh_10_10_10_255,
9135     };
9136     const u32 N_PLS = fib_path_list_pool_size();
9137
9138     fib_table_entry_special_add(0,
9139                                 &pfx_10_10_10_21_s_32,
9140                                 FIB_SOURCE_CLI,
9141                                 FIB_ENTRY_FLAG_DROP);
9142     fib_table_entry_special_add(0,
9143                                 &pfx_10_10_10_22_s_32,
9144                                 FIB_SOURCE_CLI,
9145                                 FIB_ENTRY_FLAG_DROP);
9146     fib_table_entry_special_add(0,
9147                                 &pfx_10_10_10_255_s_32,
9148                                 FIB_SOURCE_CLI,
9149                                 FIB_ENTRY_FLAG_DROP);
9150
9151     /*
9152      * source an entry that pushes its state down the sub-tree
9153      */
9154     const fib_prefix_t pfx_10_10_10_16_s_28 = {
9155         .fp_len = 28,
9156         .fp_proto = FIB_PROTOCOL_IP4,
9157         .fp_addr = nh_10_10_10_16,
9158     };
9159     fib_table_entry_update_one_path(0,
9160                                     &pfx_10_10_10_16_s_28,
9161                                     FIB_SOURCE_API,
9162                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9163                                     DPO_PROTO_IP4,
9164                                     &nh_10_10_10_1,
9165                                     tm->hw[0]->sw_if_index,
9166                                     ~0,
9167                                     1,
9168                                     NULL,
9169                                     FIB_ROUTE_PATH_FLAG_NONE);
9170
9171     /*
9172      * this covering entry and all those below it should have
9173      * the same forwarding information.
9174      */
9175     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9176                                                     VNET_LINK_IP4,
9177                                                     &nh_10_10_10_1,
9178                                                     tm->hw[0]->sw_if_index);
9179     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
9180         .type = FT_LB_ADJ,
9181         .adj = {
9182             .adj = ai_10_10_10_1,
9183         },
9184     };
9185
9186     fei = fib_table_lookup(0, &pfx_10_10_10_16_s_28);
9187     FIB_TEST(!fib_test_validate_entry(fei,
9188                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9189                                       1,
9190                                       &adj_o_10_10_10_1),
9191              "%U via 10.10.10.1",
9192              format_fib_prefix, &pfx_10_10_10_16_s_28);
9193     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9194     FIB_TEST(!fib_test_validate_entry(fei,
9195                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9196                                       1,
9197                                       &adj_o_10_10_10_1),
9198              "%U via 10.10.10.1",
9199              format_fib_prefix, &pfx_10_10_10_21_s_32);
9200     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9201     FIB_TEST(!fib_test_validate_entry(fei,
9202                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9203                                       1,
9204                                       &adj_o_10_10_10_1),
9205              "%U via 10.10.10.1",
9206              format_fib_prefix, &pfx_10_10_10_22_s_32);
9207     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9208     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9209              "%U resolves via drop",
9210              format_fib_prefix, &pfx_10_10_10_255_s_32);
9211
9212     /*
9213      * remove the inherting cover - covereds go back to drop
9214      */
9215     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9216
9217     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9218     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9219              "%U resolves via drop",
9220              format_fib_prefix, &pfx_10_10_10_21_s_32);
9221
9222     /*
9223      * source an entry that pushes its state down the sub-tree
9224      */
9225     const fib_prefix_t pfx_10_10_10_0_s_24 = {
9226         .fp_len = 24,
9227         .fp_proto = FIB_PROTOCOL_IP4,
9228         .fp_addr = nh_10_10_10_0,
9229     };
9230     fib_table_entry_update_one_path(0,
9231                                     &pfx_10_10_10_0_s_24,
9232                                     FIB_SOURCE_API,
9233                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9234                                     DPO_PROTO_IP4,
9235                                     &nh_10_10_10_1,
9236                                     tm->hw[0]->sw_if_index,
9237                                     ~0,
9238                                     1,
9239                                     NULL,
9240                                     FIB_ROUTE_PATH_FLAG_NONE);
9241
9242     /*
9243      * whole sub-tree now covered
9244      */
9245     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9246     FIB_TEST(!fib_test_validate_entry(fei,
9247                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9248                                       1,
9249                                       &adj_o_10_10_10_1),
9250              "%U via 10.10.10.1",
9251              format_fib_prefix, &pfx_10_10_10_0_s_24);
9252     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9253     FIB_TEST(!fib_test_validate_entry(fei,
9254                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9255                                       1,
9256                                       &adj_o_10_10_10_1),
9257              "%U via 10.10.10.1",
9258              format_fib_prefix, &pfx_10_10_10_21_s_32);
9259     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9260     FIB_TEST(!fib_test_validate_entry(fei,
9261                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9262                                       1,
9263                                       &adj_o_10_10_10_1),
9264              "%U via 10.10.10.1",
9265              format_fib_prefix, &pfx_10_10_10_22_s_32);
9266     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9267     FIB_TEST(!fib_test_validate_entry(fei,
9268                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9269                                       1,
9270                                       &adj_o_10_10_10_1),
9271              "%U via 10.10.10.1",
9272              format_fib_prefix, &pfx_10_10_10_255_s_32);
9273
9274     /*
9275      * insert a more specific into the sub-tree - expect inheritance
9276      *  this one is directly covered by the root
9277      */
9278     fib_table_entry_special_add(0,
9279                                 &pfx_10_10_10_16_s_28,
9280                                 FIB_SOURCE_CLI,
9281                                 FIB_ENTRY_FLAG_DROP);
9282     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9283     FIB_TEST(!fib_test_validate_entry(fei,
9284                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9285                                       1,
9286                                       &adj_o_10_10_10_1),
9287              "%U via 10.10.10.1",
9288              format_fib_prefix, &pfx_10_10_10_16_s_28);
9289
9290     /*
9291      * insert a more specific into the sub-tree - expect inheritance
9292      *  this one is indirectly covered by the root
9293      */
9294     const fib_prefix_t pfx_10_10_10_20_s_30 = {
9295         .fp_len = 30,
9296         .fp_proto = FIB_PROTOCOL_IP4,
9297         .fp_addr = nh_10_10_10_20,
9298     };
9299     fib_table_entry_special_add(0,
9300                                 &pfx_10_10_10_20_s_30,
9301                                 FIB_SOURCE_CLI,
9302                                 FIB_ENTRY_FLAG_DROP);
9303     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9304     FIB_TEST(!fib_test_validate_entry(fei,
9305                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9306                                       1,
9307                                       &adj_o_10_10_10_1),
9308              "%U via 10.10.10.1",
9309              format_fib_prefix, &pfx_10_10_10_20_s_30);
9310
9311     /*
9312      * remove the prefix from the middle of the sub-tree
9313      *  the inherited source will be the only one remaining - expect
9314      *  it to be withdrawn and hence the prefix is removed.
9315      */
9316     fib_table_entry_special_remove(0,
9317                                    &pfx_10_10_10_20_s_30,
9318                                    FIB_SOURCE_CLI);
9319     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9320     FIB_TEST((FIB_NODE_INDEX_INVALID == fei),
9321              "%U gone",
9322              format_fib_prefix, &pfx_10_10_10_20_s_30);
9323
9324     /*
9325      * inheriting source is modifed - expect the modification to be present
9326      *  throughout the sub-tree
9327      */
9328     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9329                                                     VNET_LINK_IP4,
9330                                                     &nh_10_10_10_2,
9331                                                     tm->hw[0]->sw_if_index);
9332     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
9333         .type = FT_LB_ADJ,
9334         .adj = {
9335             .adj = ai_10_10_10_2,
9336         },
9337     };
9338
9339     fib_table_entry_update_one_path(0,
9340                                     &pfx_10_10_10_0_s_24,
9341                                     FIB_SOURCE_API,
9342                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9343                                     DPO_PROTO_IP4,
9344                                     &nh_10_10_10_2,
9345                                     tm->hw[0]->sw_if_index,
9346                                     ~0,
9347                                     1,
9348                                     NULL,
9349                                     FIB_ROUTE_PATH_FLAG_NONE);
9350     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9351     FIB_TEST(!fib_test_validate_entry(fei,
9352                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9353                                       1,
9354                                       &adj_o_10_10_10_2),
9355              "%U via 10.10.10.2",
9356              format_fib_prefix, &pfx_10_10_10_21_s_32);
9357     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9358     FIB_TEST(!fib_test_validate_entry(fei,
9359                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9360                                       1,
9361                                       &adj_o_10_10_10_2),
9362              "%U via 10.10.10.2",
9363              format_fib_prefix, &pfx_10_10_10_22_s_32);
9364     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9365     FIB_TEST(!fib_test_validate_entry(fei,
9366                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9367                                       1,
9368                                       &adj_o_10_10_10_2),
9369              "%U via 10.10.10.2",
9370              format_fib_prefix, &pfx_10_10_10_255_s_32);
9371     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9372     FIB_TEST(!fib_test_validate_entry(fei,
9373                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9374                                       1,
9375                                       &adj_o_10_10_10_2),
9376              "%U via 10.10.10.2",
9377              format_fib_prefix, &pfx_10_10_10_0_s_24);
9378
9379     fib_source_t hi_src = fib_source_allocate("test", 0x50,
9380                                               FIB_SOURCE_BH_SIMPLE);
9381
9382     /*
9383      * add the source that replaces inherited state.
9384      * inheriting source is not the best, so it doesn't push state.
9385      */
9386     fib_table_entry_update_one_path(0,
9387                                     &pfx_10_10_10_0_s_24,
9388                                     hi_src,
9389                                     FIB_ENTRY_FLAG_NONE,
9390                                     DPO_PROTO_IP4,
9391                                     &nh_10_10_10_1,
9392                                     tm->hw[0]->sw_if_index,
9393                                     ~0,
9394                                     1,
9395                                     NULL,
9396                                     FIB_ROUTE_PATH_FLAG_NONE);
9397     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9398     FIB_TEST(!fib_test_validate_entry(fei,
9399                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9400                                       1,
9401                                       &adj_o_10_10_10_1),
9402              "%U via 10.10.10.1",
9403              format_fib_prefix, &pfx_10_10_10_0_s_24);
9404
9405     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9406     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9407              "%U resolves via drop",
9408              format_fib_prefix, &pfx_10_10_10_21_s_32);
9409     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9410     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9411              "%U resolves via drop",
9412              format_fib_prefix, &pfx_10_10_10_22_s_32);
9413     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9414     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9415              "%U resolves via drop",
9416              format_fib_prefix, &pfx_10_10_10_255_s_32);
9417     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9418     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9419              "%U resolves via drop",
9420              format_fib_prefix, &pfx_10_10_10_16_s_28);
9421
9422     /*
9423      * withdraw the higher priority source and expect the inherited to return
9424      * throughout the sub-tree
9425      */
9426     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, hi_src);
9427
9428     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9429     FIB_TEST(!fib_test_validate_entry(fei,
9430                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9431                                       1,
9432                                       &adj_o_10_10_10_2),
9433              "%U via 10.10.10.2",
9434              format_fib_prefix, &pfx_10_10_10_21_s_32);
9435     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9436     FIB_TEST(!fib_test_validate_entry(fei,
9437                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9438                                       1,
9439                                       &adj_o_10_10_10_2),
9440              "%U via 10.10.10.2",
9441              format_fib_prefix, &pfx_10_10_10_22_s_32);
9442     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9443     FIB_TEST(!fib_test_validate_entry(fei,
9444                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9445                                       1,
9446                                       &adj_o_10_10_10_2),
9447              "%U via 10.10.10.2",
9448              format_fib_prefix, &pfx_10_10_10_255_s_32);
9449     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9450     FIB_TEST(!fib_test_validate_entry(fei,
9451                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9452                                       1,
9453                                       &adj_o_10_10_10_2),
9454              "%U via 10.10.10.2",
9455              format_fib_prefix, &pfx_10_10_10_0_s_24);
9456     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9457     FIB_TEST(!fib_test_validate_entry(fei,
9458                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9459                                       1,
9460                                       &adj_o_10_10_10_2),
9461              "%U via 10.10.10.2",
9462              format_fib_prefix, &pfx_10_10_10_16_s_28);
9463
9464     /*
9465      * source a covered entry in the sub-tree with the same inherting source
9466      *  - expect that it now owns the sub-tree and thus over-rides its cover
9467      */
9468     fib_table_entry_update_one_path(0,
9469                                     &pfx_10_10_10_16_s_28,
9470                                     FIB_SOURCE_API,
9471                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9472                                     DPO_PROTO_IP4,
9473                                     &nh_10_10_10_1,
9474                                     tm->hw[0]->sw_if_index,
9475                                     ~0,
9476                                     1,
9477                                     NULL,
9478                                     FIB_ROUTE_PATH_FLAG_NONE);
9479     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9480     FIB_TEST(!fib_test_validate_entry(fei,
9481                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9482                                       1,
9483                                       &adj_o_10_10_10_1),
9484              "%U via 10.10.10.1",
9485              format_fib_prefix, &pfx_10_10_10_16_s_28);
9486     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9487     FIB_TEST(!fib_test_validate_entry(fei,
9488                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9489                                       1,
9490                                       &adj_o_10_10_10_1),
9491              "%U via 10.10.10.2",
9492              format_fib_prefix, &pfx_10_10_10_22_s_32);
9493     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9494     FIB_TEST(!fib_test_validate_entry(fei,
9495                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9496                                       1,
9497                                       &adj_o_10_10_10_1),
9498              "%U via 10.10.10.2",
9499              format_fib_prefix, &pfx_10_10_10_21_s_32);
9500
9501     /* these two unaffected by the sub-tree change */
9502     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9503     FIB_TEST(!fib_test_validate_entry(fei,
9504                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9505                                       1,
9506                                       &adj_o_10_10_10_2),
9507              "%U via 10.10.10.2",
9508              format_fib_prefix, &pfx_10_10_10_255_s_32);
9509     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9510     FIB_TEST(!fib_test_validate_entry(fei,
9511                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9512                                       1,
9513                                       &adj_o_10_10_10_2),
9514              "%U via 10.10.10.2",
9515              format_fib_prefix, &pfx_10_10_10_0_s_24);
9516
9517     /*
9518      * removes the more specific, expect the /24 to now re-owns the sub-tree
9519      */
9520     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9521
9522     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9523     FIB_TEST(!fib_test_validate_entry(fei,
9524                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9525                                       1,
9526                                       &adj_o_10_10_10_2),
9527              "%U via 10.10.10.2",
9528              format_fib_prefix, &pfx_10_10_10_16_s_28);
9529     FIB_TEST(!fib_test_validate_entry(fei,
9530                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9531                                       1,
9532                                       &adj_o_10_10_10_2),
9533              "%U via 10.10.10.2",
9534              format_fib_prefix, &pfx_10_10_10_21_s_32);
9535     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9536     FIB_TEST(!fib_test_validate_entry(fei,
9537                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9538                                       1,
9539                                       &adj_o_10_10_10_2),
9540              "%U via 10.10.10.2",
9541              format_fib_prefix, &pfx_10_10_10_22_s_32);
9542     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9543     FIB_TEST(!fib_test_validate_entry(fei,
9544                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9545                                       1,
9546                                       &adj_o_10_10_10_2),
9547              "%U via 10.10.10.2",
9548              format_fib_prefix, &pfx_10_10_10_255_s_32);
9549     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9550     FIB_TEST(!fib_test_validate_entry(fei,
9551                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9552                                       1,
9553                                       &adj_o_10_10_10_2),
9554              "%U via 10.10.10.2",
9555              format_fib_prefix, &pfx_10_10_10_0_s_24);
9556     /*
9557      * modify the /24. expect the new forwarding to be pushed down
9558      */
9559     fib_table_entry_update_one_path(0,
9560                                     &pfx_10_10_10_0_s_24,
9561                                     FIB_SOURCE_API,
9562                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9563                                     DPO_PROTO_IP4,
9564                                     &nh_10_10_10_1,
9565                                     tm->hw[0]->sw_if_index,
9566                                     ~0,
9567                                     1,
9568                                     NULL,
9569                                     FIB_ROUTE_PATH_FLAG_NONE);
9570     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9571     FIB_TEST(!fib_test_validate_entry(fei,
9572                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9573                                       1,
9574                                       &adj_o_10_10_10_1),
9575              "%U via 10.10.10.1",
9576              format_fib_prefix, &pfx_10_10_10_16_s_28);
9577     FIB_TEST(!fib_test_validate_entry(fei,
9578                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9579                                       1,
9580                                       &adj_o_10_10_10_1),
9581              "%U via 10.10.10.1",
9582              format_fib_prefix, &pfx_10_10_10_21_s_32);
9583     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9584     FIB_TEST(!fib_test_validate_entry(fei,
9585                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9586                                       1,
9587                                       &adj_o_10_10_10_1),
9588              "%U via 10.10.10.1",
9589              format_fib_prefix, &pfx_10_10_10_22_s_32);
9590     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9591     FIB_TEST(!fib_test_validate_entry(fei,
9592                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9593                                       1,
9594                                       &adj_o_10_10_10_1),
9595              "%U via 10.10.10.1",
9596              format_fib_prefix, &pfx_10_10_10_255_s_32);
9597     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9598     FIB_TEST(!fib_test_validate_entry(fei,
9599                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9600                                       1,
9601                                       &adj_o_10_10_10_1),
9602              "%U via 10.10.10.1",
9603              format_fib_prefix, &pfx_10_10_10_0_s_24);
9604
9605     /*
9606      * add an entry less specific to /24. it should not own the /24's tree
9607      */
9608     const fib_prefix_t pfx_10_10_0_0_s_16 = {
9609         .fp_len = 16,
9610         .fp_proto = FIB_PROTOCOL_IP4,
9611         .fp_addr = nh_10_10_0_0,
9612     };
9613     fib_table_entry_update_one_path(0,
9614                                     &pfx_10_10_0_0_s_16,
9615                                     FIB_SOURCE_API,
9616                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
9617                                     DPO_PROTO_IP4,
9618                                     &nh_10_10_10_2,
9619                                     tm->hw[0]->sw_if_index,
9620                                     ~0,
9621                                     1,
9622                                     NULL,
9623                                     FIB_ROUTE_PATH_FLAG_NONE);
9624     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9625     FIB_TEST(!fib_test_validate_entry(fei,
9626                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9627                                       1,
9628                                       &adj_o_10_10_10_1),
9629              "%U via 10.10.10.1",
9630              format_fib_prefix, &pfx_10_10_10_16_s_28);
9631     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9632     FIB_TEST(!fib_test_validate_entry(fei,
9633                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9634                                       1,
9635                                       &adj_o_10_10_10_1),
9636              "%U via 10.10.10.1",
9637              format_fib_prefix, &pfx_10_10_10_22_s_32);
9638     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9639     FIB_TEST(!fib_test_validate_entry(fei,
9640                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9641                                       1,
9642                                       &adj_o_10_10_10_1),
9643              "%U via 10.10.10.1",
9644              format_fib_prefix, &pfx_10_10_10_255_s_32);
9645     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9646     FIB_TEST(!fib_test_validate_entry(fei,
9647                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9648                                       1,
9649                                       &adj_o_10_10_10_1),
9650              "%U via 10.10.10.1",
9651              format_fib_prefix, &pfx_10_10_10_0_s_24);
9652     fei = fib_table_lookup_exact_match(0, &pfx_10_10_0_0_s_16);
9653     FIB_TEST(!fib_test_validate_entry(fei,
9654                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9655                                       1,
9656                                       &adj_o_10_10_10_2),
9657              "%U via 10.10.10.2",
9658              format_fib_prefix, &pfx_10_10_0_0_s_16);
9659
9660     /*
9661      * Add/remove an interposer source to a new /32
9662      */
9663     const fib_prefix_t pfx_11_11_11_11_s_32 = {
9664         .fp_len = 32,
9665         .fp_proto = FIB_PROTOCOL_IP4,
9666         .fp_addr = nh_11_11_11_11,
9667     };
9668
9669     fib_table_entry_update_one_path(0,
9670                                     &pfx_11_11_11_11_s_32,
9671                                     FIB_SOURCE_API,
9672                                     FIB_ENTRY_FLAG_NONE,
9673                                     DPO_PROTO_IP4,
9674                                     &nh_10_10_10_3,
9675                                     tm->hw[0]->sw_if_index,
9676                                     ~0,
9677                                     1,
9678                                     NULL,
9679                                     FIB_ROUTE_PATH_FLAG_NONE);
9680
9681     dpo_id_t interposer = DPO_INVALID;
9682     fib_mpls_label_t *l99 = NULL, fml_99 = {
9683         .fml_value = 99,
9684     };
9685     vec_add1(l99, fml_99);
9686
9687     mpls_label_dpo_create(l99,
9688                           MPLS_EOS,
9689                           DPO_PROTO_IP4,
9690                           MPLS_LABEL_DPO_FLAG_NONE,
9691                           punt_dpo_get(DPO_PROTO_MPLS),
9692                           &interposer);
9693
9694     adj_index_t ai_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9695                                                     VNET_LINK_IP4,
9696                                                     &nh_10_10_10_3,
9697                                                     tm->hw[0]->sw_if_index);
9698     fib_test_lb_bucket_t adj_o_10_10_10_3 = {
9699         .type = FT_LB_ADJ,
9700         .adj = {
9701             .adj = ai_10_10_10_3,
9702         },
9703     };
9704     fib_test_lb_bucket_t l99_o_10_10_10_3 = {
9705         .type = FT_LB_LABEL_O_ADJ,
9706         .label_o_adj = {
9707             .adj = ai_10_10_10_3,
9708             .label = 99,
9709             .eos = MPLS_EOS,
9710         },
9711     };
9712
9713     fei = fib_table_entry_special_dpo_add(0,
9714                                           &pfx_11_11_11_11_s_32,
9715                                           FIB_SOURCE_SPECIAL,
9716                                           FIB_ENTRY_FLAG_INTERPOSE,
9717                                           &interposer);
9718     FIB_TEST(!fib_test_validate_entry(fei,
9719                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9720                                       1,
9721                                       &l99_o_10_10_10_3),
9722              "%U via interposer adj",
9723              format_fib_prefix,&pfx_11_11_11_11_s_32);
9724
9725     fib_table_entry_special_remove(0,
9726                                    &pfx_11_11_11_11_s_32,
9727                                    FIB_SOURCE_SPECIAL);
9728     FIB_TEST(!fib_test_validate_entry(fei,
9729                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9730                                       1,
9731                                       &adj_o_10_10_10_3),
9732              "%U via 10.10.10.1",
9733              format_fib_prefix, &pfx_11_11_11_11_s_32);
9734     dpo_reset(&interposer);
9735     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9736
9737     /*
9738      * add an interposer to a source with path-extensions
9739      */
9740     fib_mpls_label_t *l3300 = NULL, fml_3300 = {
9741         .fml_value = 3300,
9742     };
9743     vec_add1(l3300, fml_3300);
9744     fib_table_entry_update_one_path(0,
9745                                     &pfx_11_11_11_11_s_32,
9746                                     FIB_SOURCE_API,
9747                                     FIB_ENTRY_FLAG_NONE,
9748                                     DPO_PROTO_IP4,
9749                                     &nh_10_10_10_3,
9750                                     tm->hw[0]->sw_if_index,
9751                                     ~0,
9752                                     1,
9753                                     l3300,
9754                                     FIB_ROUTE_PATH_FLAG_NONE);
9755
9756     mpls_label_dpo_create(l99,
9757                           MPLS_EOS,
9758                           DPO_PROTO_IP4,
9759                           MPLS_LABEL_DPO_FLAG_NONE,
9760                           punt_dpo_get(DPO_PROTO_MPLS),
9761                           &interposer);
9762
9763     adj_index_t ai_mpls_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9764                                                          VNET_LINK_MPLS,
9765                                                          &nh_10_10_10_3,
9766                                                          tm->hw[0]->sw_if_index);
9767     fib_test_lb_bucket_t l3300_o_10_10_10_3 = {
9768         .type = FT_LB_LABEL_O_ADJ,
9769         .label_o_adj = {
9770             .adj = ai_mpls_10_10_10_3,
9771             .label = 3300,
9772             .eos = MPLS_EOS,
9773         },
9774     };
9775     fib_test_lb_bucket_t lchain_o_10_10_10_3 = {
9776         .type = FT_LB_LABEL_CHAIN_O_ADJ,
9777         .label_chain_o_adj = {
9778             .adj = ai_mpls_10_10_10_3,
9779             .label_chain_size = 2,
9780             .label_chain = {
9781                 99, 3300
9782             },
9783             .eos = MPLS_EOS,
9784         },
9785     };
9786
9787     fei = fib_table_entry_special_dpo_add(0,
9788                                           &pfx_11_11_11_11_s_32,
9789                                           FIB_SOURCE_SPECIAL,
9790                                           FIB_ENTRY_FLAG_INTERPOSE,
9791                                           &interposer);
9792
9793     FIB_TEST(!fib_test_validate_entry(fei,
9794                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9795                                       1,
9796                                       &lchain_o_10_10_10_3),
9797              "%U via interposer & mpls on adj",
9798              format_fib_prefix, &pfx_11_11_11_11_s_32);
9799
9800     fib_table_entry_special_remove(0,
9801                                    &pfx_11_11_11_11_s_32,
9802                                    FIB_SOURCE_SPECIAL);
9803     FIB_TEST(!fib_test_validate_entry(fei,
9804                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9805                                       1,
9806                                       &l3300_o_10_10_10_3),
9807              "%U via 10.10.10.1",
9808              format_fib_prefix, &pfx_11_11_11_11_s_32);
9809     adj_unlock(ai_mpls_10_10_10_3);
9810
9811     /*
9812      * remove and re-add the second best API source while the interpose
9813      * is present
9814      */
9815     fei = fib_table_entry_special_dpo_add(0,
9816                                           &pfx_11_11_11_11_s_32,
9817                                           FIB_SOURCE_SPECIAL,
9818                                           FIB_ENTRY_FLAG_INTERPOSE,
9819                                           &interposer);
9820     FIB_TEST(!fib_test_validate_entry(fei,
9821                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9822                                       1,
9823                                       &lchain_o_10_10_10_3),
9824              "%U via interposer adj",
9825              format_fib_prefix,&pfx_11_11_11_11_s_32);
9826
9827     FIB_TEST(3 == pool_elts(mpls_label_dpo_pool),
9828              "MPLS label pool: %d",
9829              pool_elts(mpls_label_dpo_pool));
9830
9831     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9832
9833     /*
9834      * the interpose does not get stacked when there are not valid paths
9835      */
9836     fib_test_lb_bucket_t bucket_drop = {
9837         .type = FT_LB_DROP,
9838         .special = {
9839             .adj = DPO_PROTO_IP4,
9840         },
9841     };
9842     FIB_TEST(!fib_test_validate_entry(fei,
9843                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9844                                       1,
9845                                       &bucket_drop),
9846              "%U via drop",
9847              format_fib_prefix,&pfx_11_11_11_11_s_32);
9848
9849     fib_table_entry_update_one_path(0,
9850                                     &pfx_11_11_11_11_s_32,
9851                                     FIB_SOURCE_API,
9852                                     FIB_ENTRY_FLAG_NONE,
9853                                     DPO_PROTO_IP4,
9854                                     &nh_10_10_10_3,
9855                                     tm->hw[0]->sw_if_index,
9856                                     ~0,
9857                                     1,
9858                                     NULL,
9859                                     FIB_ROUTE_PATH_FLAG_NONE);
9860     FIB_TEST(!fib_test_validate_entry(fei,
9861                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9862                                       1,
9863                                       &l99_o_10_10_10_3),
9864              "%U via interposer adj",
9865              format_fib_prefix,&pfx_11_11_11_11_s_32);
9866     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9867
9868     /*
9869      * add a cover for the interposed entry, so that we test it selects
9870      * the covers forwarding.
9871      */
9872     const fib_prefix_t pfx_11_11_11_0_s_24 = {
9873         .fp_len = 24,
9874         .fp_proto = FIB_PROTOCOL_IP4,
9875         .fp_addr = nh_11_11_11_0,
9876     };
9877     fib_table_entry_update_one_path(0,
9878                                     &pfx_11_11_11_0_s_24,
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     FIB_TEST(!fib_test_validate_entry(fei,
9889                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9890                                       1,
9891                                       &l99_o_10_10_10_3),
9892              "%U via interposer adj",
9893              format_fib_prefix,&pfx_11_11_11_11_s_32);
9894
9895     /*
9896      * multiple interpose sources on the same entry. Only the high
9897      * priority source gets to add the interpose.
9898      */
9899     fib_table_entry_update_one_path(0,
9900                                     &pfx_11_11_11_11_s_32,
9901                                     FIB_SOURCE_API,
9902                                     FIB_ENTRY_FLAG_NONE,
9903                                     DPO_PROTO_IP4,
9904                                     &nh_10_10_10_3,
9905                                     tm->hw[0]->sw_if_index,
9906                                     ~0,
9907                                     1,
9908                                     NULL,
9909                                     FIB_ROUTE_PATH_FLAG_NONE);
9910
9911     dpo_id_t interposer2 = DPO_INVALID;
9912     fib_mpls_label_t *l100 = NULL, fml_100 = {
9913         .fml_value = 100,
9914     };
9915     vec_add1(l100, fml_100);
9916
9917     mpls_label_dpo_create(l100,
9918                           MPLS_EOS,
9919                           DPO_PROTO_IP4,
9920                           MPLS_LABEL_DPO_FLAG_NONE,
9921                           punt_dpo_get(DPO_PROTO_MPLS),
9922                           &interposer2);
9923
9924     fei = fib_table_entry_special_dpo_add(0,
9925                                           &pfx_11_11_11_11_s_32,
9926                                           FIB_SOURCE_CLASSIFY,
9927                                           FIB_ENTRY_FLAG_INTERPOSE,
9928                                           &interposer2);
9929
9930     fib_test_lb_bucket_t lc100_o_10_10_10_3 = {
9931         .type = FT_LB_LABEL_CHAIN_O_ADJ,
9932         .label_chain_o_adj = {
9933             .adj = ai_10_10_10_3,
9934             .label_chain_size = 2,
9935             .label_chain = {
9936                 99, 100
9937             },
9938             .eos = MPLS_EOS,
9939         },
9940     };
9941
9942     FIB_TEST(!fib_test_validate_entry(fei,
9943                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9944                                       1,
9945                                       &lc100_o_10_10_10_3),
9946              "%U via interposer label 99",
9947              format_fib_prefix,&pfx_11_11_11_11_s_32);
9948
9949     fib_test_lb_bucket_t l100_o_10_10_10_3 = {
9950         .type = FT_LB_LABEL_O_ADJ,
9951         .label_o_adj = {
9952             .adj = ai_10_10_10_3,
9953             .label = 100,
9954             .eos = MPLS_EOS,
9955         },
9956     };
9957
9958     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_SPECIAL);
9959
9960     FIB_TEST(!fib_test_validate_entry(fei,
9961                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9962                                       1,
9963                                       &l100_o_10_10_10_3),
9964              "%U via interposer label 99",
9965              format_fib_prefix,&pfx_11_11_11_11_s_32);
9966
9967     fib_table_entry_delete(0, &pfx_11_11_11_0_s_24, FIB_SOURCE_API);
9968     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9969     FIB_TEST(!fib_test_validate_entry(fei,
9970                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9971                                       1,
9972                                       &bucket_drop),
9973              "%U via drop",
9974              format_fib_prefix,&pfx_11_11_11_11_s_32);
9975     fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_CLASSIFY);
9976
9977     /*
9978      * update a source to/from interpose.
9979      */
9980     /* fib_table_entry_update_one_path(0, */
9981     /*                                 &pfx_11_11_11_0_s_24, */
9982     /*                              FIB_SOURCE_API, */
9983     /*                              FIB_ENTRY_FLAG_NONE, */
9984     /*                              DPO_PROTO_IP4, */
9985     /*                                 &nh_10_10_10_3, */
9986     /*                              tm->hw[0]->sw_if_index, */
9987     /*                              ~0, */
9988     /*                              1, */
9989     /*                              NULL, */
9990     /*                              FIB_ROUTE_PATH_FLAG_NONE); */
9991     /* fei = fib_table_entry_special_dpo_add(0, */
9992     /*                                       &pfx_11_11_11_11_s_32, */
9993     /*                                       FIB_SOURCE_API, */
9994     /*                                       FIB_ENTRY_FLAG_INTERPOSE, */
9995     /*                                       &interposer); */
9996     /* FIB_TEST(!fib_test_validate_entry(fei, */
9997     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
9998     /*                                   1, */
9999     /*                                   &l99_o_10_10_10_3), */
10000     /*          "%U via interposer label 99", */
10001     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
10002
10003     /* FIB_TEST(3 == pool_elts(mpls_label_dpo_pool), */
10004     /*          "MPLS label pool: %d", */
10005     /*          pool_elts(mpls_label_dpo_pool)); */
10006     /* FIB_TEST((2 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
10007     /*          "Interposer %d locks", */
10008     /*          mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
10009
10010     /* fib_table_entry_update_one_path(0, */
10011     /*                                 &pfx_11_11_11_11_s_32, */
10012     /*                              FIB_SOURCE_API, */
10013     /*                              FIB_ENTRY_FLAG_NONE, */
10014     /*                              DPO_PROTO_IP4, */
10015     /*                                 &nh_10_10_10_2, */
10016     /*                              tm->hw[0]->sw_if_index, */
10017     /*                              ~0, */
10018     /*                              1, */
10019     /*                              NULL, */
10020     /*                              FIB_ROUTE_PATH_FLAG_NONE); */
10021     /* FIB_TEST(!fib_test_validate_entry(fei, */
10022     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
10023     /*                                   1, */
10024     /*                                   &adj_o_10_10_10_2), */
10025     /*          "%U via 10.10.10.2", */
10026     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
10027
10028     /* FIB_TEST((1 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
10029     /*          "Interposer %d locks", */
10030     /*          mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
10031     /* FIB_TEST(2 == pool_elts(mpls_label_dpo_pool), */
10032     /*          "MPLS label pool: %d", */
10033     /*          pool_elts(mpls_label_dpo_pool)); */
10034
10035     /* fei = fib_table_entry_special_dpo_add(0, */
10036     /*                                       &pfx_11_11_11_11_s_32, */
10037     /*                                       FIB_SOURCE_API, */
10038     /*                                       FIB_ENTRY_FLAG_INTERPOSE, */
10039     /*                                       &interposer); */
10040     /* FIB_TEST(!fib_test_validate_entry(fei, */
10041     /*                                   FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
10042     /*                                   1, */
10043     /*                                   &l99_o_10_10_10_3), */
10044     /*          "%U via interposer label 99", */
10045     /*          format_fib_prefix,&pfx_11_11_11_11_s_32); */
10046
10047     /* fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API); */
10048
10049     /*
10050      * Add/remove an interposer source from the top of the subtrie. The
10051      * interposer source is not inherited.
10052      */
10053     fib_table_entry_update_one_path(0,
10054                                     &pfx_10_10_10_0_s_24,
10055                                     FIB_SOURCE_API,
10056                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
10057                                     DPO_PROTO_IP4,
10058                                     &nh_10_10_10_3,
10059                                     tm->hw[0]->sw_if_index,
10060                                     ~0,
10061                                     1,
10062                                     NULL,
10063                                     FIB_ROUTE_PATH_FLAG_NONE);
10064     fei = fib_table_entry_special_dpo_add(0,
10065                                           &pfx_10_10_10_0_s_24,
10066                                           FIB_SOURCE_SPECIAL,
10067                                           FIB_ENTRY_FLAG_INTERPOSE,
10068                                           &interposer);
10069     FIB_TEST(!fib_test_validate_entry(fei,
10070                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10071                                       1,
10072                                       &l99_o_10_10_10_3),
10073              "%U via interposer label",
10074              format_fib_prefix,&pfx_10_10_10_0_s_24);
10075     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10076     FIB_TEST(!fib_test_validate_entry(fei,
10077                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10078                                       1,
10079                                       &bucket_drop),
10080              "%U via drop",
10081              format_fib_prefix, &pfx_10_10_10_21_s_32);
10082
10083     fib_table_entry_special_remove(0,
10084                                    &pfx_10_10_10_0_s_24,
10085                                    FIB_SOURCE_SPECIAL);
10086     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
10087     FIB_TEST(!fib_test_validate_entry(fei,
10088                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10089                                       1,
10090                                       &adj_o_10_10_10_3),
10091              "%U via 10.10.10.1",
10092              format_fib_prefix, &pfx_10_10_10_0_s_24);
10093     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10094     FIB_TEST(!fib_test_validate_entry(fei,
10095                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10096                                       1,
10097                                       &adj_o_10_10_10_3),
10098              "%U via via 10.10.10.1",
10099              format_fib_prefix, &pfx_10_10_10_21_s_32);
10100
10101     /*
10102      * Add/remove an interposer source from the top of the subtrie. The
10103      * interposer source is inherited.
10104      */
10105     fei = fib_table_entry_special_dpo_add(0,
10106                                           &pfx_10_10_10_0_s_24,
10107                                           FIB_SOURCE_SPECIAL,
10108                                           (FIB_ENTRY_FLAG_COVERED_INHERIT |
10109                                            FIB_ENTRY_FLAG_INTERPOSE),
10110                                           &interposer);
10111     FIB_TEST(!fib_test_validate_entry(fei,
10112                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10113                                       1,
10114                                       &l99_o_10_10_10_3),
10115              "%U via interposer label",
10116              format_fib_prefix,&pfx_10_10_10_0_s_24);
10117
10118     /* interposer gets forwarding from the drop cli source */
10119     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10120     FIB_TEST(!fib_test_validate_entry(fei,
10121                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10122                                       1,
10123                                       &bucket_drop),
10124              "%U via drop",
10125              format_fib_prefix,&pfx_10_10_10_21_s_32);
10126
10127     fib_table_entry_update_one_path(0,
10128                                     &pfx_10_10_10_21_s_32,
10129                                     FIB_SOURCE_API,
10130                                     FIB_ENTRY_FLAG_NONE,
10131                                     DPO_PROTO_IP4,
10132                                     &nh_10_10_10_3,
10133                                     tm->hw[0]->sw_if_index,
10134                                     ~0,
10135                                     1,
10136                                     NULL,
10137                                     FIB_ROUTE_PATH_FLAG_NONE);
10138     fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_CLI);
10139     /* interposer gets forwarding from the API source */
10140     FIB_TEST(!fib_test_validate_entry(fei,
10141                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10142                                       1,
10143                                       &l99_o_10_10_10_3),
10144              "%U via interposer label",
10145              format_fib_prefix,&pfx_10_10_10_21_s_32);
10146
10147     /*
10148      * cleanup
10149      */
10150     fib_table_entry_delete(0, &pfx_10_10_10_22_s_32, FIB_SOURCE_CLI);
10151     fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_API);
10152     fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_CLI);
10153     fib_table_entry_delete(0, &pfx_10_10_10_255_s_32, FIB_SOURCE_CLI);
10154     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_API);
10155     fib_table_entry_delete(0, &pfx_10_10_0_0_s_16, FIB_SOURCE_API);
10156     fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_SPECIAL);
10157     adj_unlock(ai_10_10_10_1);
10158     adj_unlock(ai_10_10_10_2);
10159     adj_unlock(ai_10_10_10_3);
10160     dpo_reset(&interposer);
10161     dpo_reset(&interposer2);
10162     FIB_TEST(0 == pool_elts(mpls_label_dpo_pool),
10163              "MPLS label pool empty: %d",
10164              pool_elts(mpls_label_dpo_pool));
10165     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
10166     FIB_TEST(N_PLS == fib_path_list_pool_size(),
10167              "number of path-lists: %d = %d",
10168              N_PLS, fib_path_list_pool_size());
10169
10170     /*
10171      * test the v6 tree walk.
10172      * a /64 that covers everything. a /96 that covers one /128
10173      * a second /128 covered only by the /64.
10174      */
10175     const fib_prefix_t pfx_2001_s_64 = {
10176         .fp_len = 64,
10177         .fp_proto = FIB_PROTOCOL_IP6,
10178         .fp_addr = {
10179             .ip6 = {
10180                 .as_u64 = {
10181                     [0] = clib_host_to_net_u64(0x2001000000000000),
10182                     [1] = clib_host_to_net_u64(0x0000000000000000),
10183                 },
10184             },
10185         },
10186     };
10187     const fib_prefix_t pfx_2001_1_s_96 = {
10188         .fp_len = 96,
10189         .fp_proto = FIB_PROTOCOL_IP6,
10190         .fp_addr = {
10191             .ip6 = {
10192                 .as_u64 = {
10193                     [0] = clib_host_to_net_u64(0x2001000000000000),
10194                     [1] = clib_host_to_net_u64(0x1000000000000000),
10195                 },
10196             },
10197         },
10198     };
10199     const fib_prefix_t pfx_2001_1_1_s_128 = {
10200         .fp_len = 128,
10201         .fp_proto = FIB_PROTOCOL_IP6,
10202         .fp_addr = {
10203             .ip6 = {
10204                 .as_u64 = {
10205                     [0] = clib_host_to_net_u64(0x2001000000000000),
10206                     [1] = clib_host_to_net_u64(0x1000000000000001),
10207                 },
10208             },
10209         },
10210     };
10211     const fib_prefix_t pfx_2001_0_1_s_128 = {
10212         .fp_len = 128,
10213         .fp_proto = FIB_PROTOCOL_IP6,
10214         .fp_addr = {
10215             .ip6 = {
10216                 .as_u64 = {
10217                     [0] = clib_host_to_net_u64(0x2001000000000000),
10218                     [1] = clib_host_to_net_u64(0x0000000000000001),
10219                 },
10220             },
10221         },
10222     };
10223     const ip46_address_t nh_3000_1 = {
10224         .ip6 = {
10225             .as_u64 = {
10226                 [0] = clib_host_to_net_u64(0x3000000000000000),
10227                 [1] = clib_host_to_net_u64(0x0000000000000001),
10228             },
10229         },
10230     };
10231     const ip46_address_t nh_3000_2 = {
10232         .ip6 = {
10233             .as_u64 = {
10234                 [0] = clib_host_to_net_u64(0x3000000000000000),
10235                 [1] = clib_host_to_net_u64(0x0000000000000002),
10236             },
10237         },
10238     };
10239     adj_index_t ai_3000_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
10240                                                 VNET_LINK_IP6,
10241                                                 &nh_3000_1,
10242                                                 tm->hw[0]->sw_if_index);
10243     adj_index_t ai_3000_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
10244                                                 VNET_LINK_IP6,
10245                                                 &nh_3000_2,
10246                                                 tm->hw[0]->sw_if_index);
10247     fib_test_lb_bucket_t adj_o_3000_1 = {
10248         .type = FT_LB_ADJ,
10249         .adj = {
10250             .adj = ai_3000_1,
10251         },
10252     };
10253     fib_test_lb_bucket_t adj_o_3000_2 = {
10254         .type = FT_LB_ADJ,
10255         .adj = {
10256             .adj = ai_3000_2,
10257         },
10258     };
10259
10260     fib_table_entry_special_add(0,
10261                                 &pfx_2001_0_1_s_128,
10262                                 FIB_SOURCE_CLI,
10263                                 FIB_ENTRY_FLAG_DROP);
10264     fib_table_entry_special_add(0,
10265                                 &pfx_2001_1_1_s_128,
10266                                 FIB_SOURCE_CLI,
10267                                 FIB_ENTRY_FLAG_DROP);
10268
10269     /*
10270      * /96 has inherited forwarding pushed down to its covered /128
10271      */
10272     fib_table_entry_update_one_path(0,
10273                                     &pfx_2001_1_s_96,
10274                                     FIB_SOURCE_API,
10275                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
10276                                     DPO_PROTO_IP6,
10277                                     &nh_3000_1,
10278                                     tm->hw[0]->sw_if_index,
10279                                     ~0,
10280                                     1,
10281                                     NULL,
10282                                     FIB_ROUTE_PATH_FLAG_NONE);
10283     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
10284     FIB_TEST(!fib_test_validate_entry(fei,
10285                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10286                                       1,
10287                                       &adj_o_3000_1),
10288              "%U via 3000::1",
10289              format_fib_prefix, &pfx_2001_1_s_96);
10290     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
10291     FIB_TEST(!fib_test_validate_entry(fei,
10292                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10293                                       1,
10294                                       &adj_o_3000_1),
10295              "%U via 3000::1",
10296              format_fib_prefix, &pfx_2001_1_1_s_128);
10297     fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
10298     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
10299              "%U resolves via drop",
10300              format_fib_prefix, &pfx_2001_0_1_s_128);
10301
10302     /*
10303      * /64 has inherited forwarding pushed down to all, but the /96
10304      * and its sub-tree remain unaffected.
10305      */
10306     fib_table_entry_update_one_path(0,
10307                                     &pfx_2001_s_64,
10308                                     FIB_SOURCE_API,
10309                                     FIB_ENTRY_FLAG_COVERED_INHERIT,
10310                                     DPO_PROTO_IP6,
10311                                     &nh_3000_2,
10312                                     tm->hw[0]->sw_if_index,
10313                                     ~0,
10314                                     1,
10315                                     NULL,
10316                                     FIB_ROUTE_PATH_FLAG_NONE);
10317
10318     fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
10319     FIB_TEST(!fib_test_validate_entry(fei,
10320                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10321                                       1,
10322                                       &adj_o_3000_2),
10323              "%U via 3000::2",
10324              format_fib_prefix, &pfx_2001_s_64);
10325     fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
10326     FIB_TEST(!fib_test_validate_entry(fei,
10327                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10328                                       1,
10329                                       &adj_o_3000_2),
10330              "%U via 3000::1",
10331              format_fib_prefix, &pfx_2001_0_1_s_128);
10332
10333     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
10334     FIB_TEST(!fib_test_validate_entry(fei,
10335                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10336                                       1,
10337                                       &adj_o_3000_1),
10338              "%U via 3000::1",
10339              format_fib_prefix, &pfx_2001_1_s_96);
10340     fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
10341     FIB_TEST(!fib_test_validate_entry(fei,
10342                                       FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10343                                       1,
10344                                       &adj_o_3000_1),
10345              "%U via 3000::1",
10346              format_fib_prefix, &pfx_2001_1_1_s_128);
10347
10348     /*
10349      * Cleanup
10350      */
10351     fib_table_entry_delete(0, &pfx_2001_0_1_s_128, FIB_SOURCE_CLI);
10352     fib_table_entry_delete(0, &pfx_2001_1_1_s_128, FIB_SOURCE_CLI);
10353     fib_table_entry_delete(0, &pfx_2001_s_64,      FIB_SOURCE_API);
10354     fib_table_entry_delete(0, &pfx_2001_1_s_96,    FIB_SOURCE_API);
10355     adj_unlock(ai_3000_1);
10356     adj_unlock(ai_3000_2);
10357
10358     /*
10359      * test no-one left behind
10360      */
10361     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
10362     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
10363
10364     return (res);
10365 }
10366
10367 static int
10368 fib_test_sticky (void)
10369 {
10370     fib_route_path_t *r_paths = NULL;
10371     test_main_t *tm = &test_main;
10372     u32 ii, lb_count, pl_count;
10373     dpo_id_t dpo = DPO_INVALID;
10374     fib_node_index_t pl_index;
10375     int res = 0;
10376 #define N_PATHS 16
10377
10378     fib_test_lb_bucket_t buckets[N_PATHS];
10379     bfd_session_t bfds[N_PATHS] = {{0}};
10380
10381     lb_count = pool_elts(load_balance_pool);
10382     pl_count = fib_path_list_pool_size();
10383
10384     for (ii = 0; ii < N_PATHS; ii++)
10385     {
10386         ip46_address_t nh = {
10387             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
10388         };
10389         adj_index_t ai;
10390
10391         ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
10392                                  VNET_LINK_IP4,
10393                                  &nh, tm->hw[0]->sw_if_index);
10394
10395         buckets[ii].type = FT_LB_ADJ;
10396         buckets[ii].adj.adj = ai;
10397
10398         bfds[ii].udp.key.peer_addr = nh;
10399         bfds[ii].udp.key.sw_if_index = tm->hw[0]->sw_if_index;
10400         bfds[ii].hop_type = BFD_HOP_TYPE_SINGLE;
10401         bfds[ii].local_state = BFD_STATE_init;
10402         adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfds[ii]);
10403         bfds[ii].local_state = BFD_STATE_up;
10404         adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[ii]);
10405     }
10406
10407     for (ii = 0; ii < N_PATHS; ii++)
10408     {
10409         fib_route_path_t r_path = {
10410             .frp_proto = DPO_PROTO_IP4,
10411             .frp_addr = {
10412                 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
10413             },
10414             .frp_sw_if_index = tm->hw[0]->sw_if_index,
10415             .frp_weight = 1,
10416             .frp_fib_index = ~0,
10417         };
10418         vec_add1(r_paths, r_path);
10419     };
10420
10421     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths);
10422     fib_path_list_lock(pl_index);
10423
10424     fib_path_list_contribute_forwarding(pl_index,
10425                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10426                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10427                                         &dpo);
10428
10429     FIB_TEST(!fib_test_validate_lb(&dpo,
10430                                    16,
10431                                    &buckets[0],
10432                                    &buckets[1],
10433                                    &buckets[2],
10434                                    &buckets[3],
10435                                    &buckets[4],
10436                                    &buckets[5],
10437                                    &buckets[6],
10438                                    &buckets[7],
10439                                    &buckets[8],
10440                                    &buckets[9],
10441                                    &buckets[10],
10442                                    &buckets[11],
10443                                    &buckets[12],
10444                                    &buckets[13],
10445                                    &buckets[14],
10446                                    &buckets[15]),
10447              "Setup OK");
10448
10449     /* take down paths */
10450     bfds[0].local_state = BFD_STATE_down;
10451     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
10452
10453     fib_path_list_contribute_forwarding(pl_index,
10454                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10455                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10456                                         &dpo);
10457
10458     FIB_TEST(!fib_test_validate_lb(&dpo,
10459                                    16,
10460                                    &buckets[1],
10461                                    &buckets[1],
10462                                    &buckets[2],
10463                                    &buckets[3],
10464                                    &buckets[4],
10465                                    &buckets[5],
10466                                    &buckets[6],
10467                                    &buckets[7],
10468                                    &buckets[8],
10469                                    &buckets[9],
10470                                    &buckets[10],
10471                                    &buckets[11],
10472                                    &buckets[12],
10473                                    &buckets[13],
10474                                    &buckets[14],
10475                                    &buckets[15]),
10476              "Failed at shut-down path 0");
10477
10478     bfds[7].local_state = BFD_STATE_down;
10479     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
10480
10481     fib_path_list_contribute_forwarding(pl_index,
10482                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10483                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10484                                         &dpo);
10485
10486     FIB_TEST(!fib_test_validate_lb(&dpo,
10487                                    16,
10488                                    &buckets[1],
10489                                    &buckets[1],
10490                                    &buckets[2],
10491                                    &buckets[3],
10492                                    &buckets[4],
10493                                    &buckets[5],
10494                                    &buckets[6],
10495                                    &buckets[2],
10496                                    &buckets[8],
10497                                    &buckets[9],
10498                                    &buckets[10],
10499                                    &buckets[11],
10500                                    &buckets[12],
10501                                    &buckets[13],
10502                                    &buckets[14],
10503                                    &buckets[15]),
10504              "Failed at shut-down path 7");
10505
10506     /* paths back up */
10507     bfds[0].local_state = BFD_STATE_up;
10508     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
10509     bfds[7].local_state = BFD_STATE_up;
10510     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
10511
10512     fib_path_list_contribute_forwarding(pl_index,
10513                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10514                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10515                                         &dpo);
10516
10517     FIB_TEST(!fib_test_validate_lb(&dpo,
10518                                    16,
10519                                    &buckets[0],
10520                                    &buckets[1],
10521                                    &buckets[2],
10522                                    &buckets[3],
10523                                    &buckets[4],
10524                                    &buckets[5],
10525                                    &buckets[6],
10526                                    &buckets[7],
10527                                    &buckets[8],
10528                                    &buckets[9],
10529                                    &buckets[10],
10530                                    &buckets[11],
10531                                    &buckets[12],
10532                                    &buckets[13],
10533                                    &buckets[14],
10534                                    &buckets[15]),
10535              "recovery OK");
10536
10537     fib_path_list_unlock(pl_index);
10538
10539     /*
10540      * non-power of 2 number of buckets
10541      */
10542     fib_route_path_t *r_paths2 = NULL;
10543
10544     r_paths2 = vec_dup(r_paths);
10545     _vec_len(r_paths2) = 3;
10546
10547     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths2);
10548     fib_path_list_lock(pl_index);
10549
10550     fib_path_list_contribute_forwarding(pl_index,
10551                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10552                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10553                                         &dpo);
10554
10555     FIB_TEST(!fib_test_validate_lb(&dpo,
10556                                    16,
10557                                    &buckets[0],
10558                                    &buckets[0],
10559                                    &buckets[0],
10560                                    &buckets[0],
10561                                    &buckets[0],
10562                                    &buckets[0],
10563                                    &buckets[1],
10564                                    &buckets[1],
10565                                    &buckets[1],
10566                                    &buckets[1],
10567                                    &buckets[1],
10568                                    &buckets[2],
10569                                    &buckets[2],
10570                                    &buckets[2],
10571                                    &buckets[2],
10572                                    &buckets[2]),
10573              "non-power of 2");
10574
10575     bfds[1].local_state = BFD_STATE_down;
10576     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10577
10578     fib_path_list_contribute_forwarding(pl_index,
10579                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10580                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10581                                         &dpo);
10582
10583     /*
10584      * path 1's buckets alternate between path 0 and 2
10585      */
10586     FIB_TEST(!fib_test_validate_lb(&dpo,
10587                                    16,
10588                                    &buckets[0],
10589                                    &buckets[0],
10590                                    &buckets[0],
10591                                    &buckets[0],
10592                                    &buckets[0],
10593                                    &buckets[0],
10594                                    &buckets[0],
10595                                    &buckets[2],
10596                                    &buckets[0],
10597                                    &buckets[2],
10598                                    &buckets[0],
10599                                    &buckets[2],
10600                                    &buckets[2],
10601                                    &buckets[2],
10602                                    &buckets[2],
10603                                    &buckets[2]),
10604              "non-power of 2");
10605     bfds[1].local_state = BFD_STATE_up;
10606     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10607
10608     fib_path_list_unlock(pl_index);
10609
10610     /*
10611      * unequal cost
10612      */
10613     fib_route_path_t *r_paths3 = NULL;
10614
10615     r_paths3 = vec_dup(r_paths);
10616     _vec_len(r_paths3) = 3;
10617
10618     r_paths3[0].frp_weight = 3;
10619
10620     pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths3);
10621     fib_path_list_lock(pl_index);
10622
10623     fib_path_list_contribute_forwarding(pl_index,
10624                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10625                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10626                                         &dpo);
10627
10628     FIB_TEST(!fib_test_validate_lb(&dpo,
10629                                    16,
10630                                    &buckets[1],
10631                                    &buckets[1],
10632                                    &buckets[1],
10633                                    &buckets[2],
10634                                    &buckets[2],
10635                                    &buckets[2],
10636                                    &buckets[0],
10637                                    &buckets[0],
10638                                    &buckets[0],
10639                                    &buckets[0],
10640                                    &buckets[0],
10641                                    &buckets[0],
10642                                    &buckets[0],
10643                                    &buckets[0],
10644                                    &buckets[0],
10645                                    &buckets[0]),
10646              "UCMP");
10647
10648     bfds[1].local_state = BFD_STATE_down;
10649     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10650
10651     fib_path_list_contribute_forwarding(pl_index,
10652                                         FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10653                                         FIB_PATH_LIST_FWD_FLAG_STICKY,
10654                                         &dpo);
10655     /* No attempt to Un-equal distribute the down path's buckets */
10656     FIB_TEST(!fib_test_validate_lb(&dpo,
10657                                    16,
10658                                    &buckets[2],
10659                                    &buckets[0],
10660                                    &buckets[2],
10661                                    &buckets[2],
10662                                    &buckets[2],
10663                                    &buckets[2],
10664                                    &buckets[0],
10665                                    &buckets[0],
10666                                    &buckets[0],
10667                                    &buckets[0],
10668                                    &buckets[0],
10669                                    &buckets[0],
10670                                    &buckets[0],
10671                                    &buckets[0],
10672                                    &buckets[0],
10673                                    &buckets[0]),
10674              "UCMP");
10675     bfds[1].local_state = BFD_STATE_up;
10676     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10677
10678     dpo_reset(&dpo);
10679     fib_path_list_unlock(pl_index);
10680
10681     vec_free(r_paths);
10682     vec_free(r_paths2);
10683     vec_free(r_paths3);
10684
10685     FIB_TEST(lb_count == pool_elts(load_balance_pool), "no leaked LBs");
10686     FIB_TEST(pl_count == fib_path_list_pool_size(), "no leaked PLs");
10687
10688     return 0;
10689 }
10690
10691 static clib_error_t *
10692 fib_test (vlib_main_t * vm,
10693           unformat_input_t * input,
10694           vlib_cli_command_t * cmd_arg)
10695 {
10696     int res;
10697
10698     res = 0;
10699
10700     fib_test_mk_intf(4);
10701
10702     if (unformat (input, "debug"))
10703     {
10704         fib_test_do_debug = 1;
10705     }
10706
10707     if (unformat (input, "ip4"))
10708     {
10709         res += fib_test_v4();
10710     }
10711     else if (unformat (input, "ip6"))
10712     {
10713         res += fib_test_v6();
10714     }
10715     else if (unformat (input, "ip"))
10716     {
10717         res += fib_test_v4();
10718         res += fib_test_v6();
10719     }
10720     else if (unformat (input, "label"))
10721     {
10722         res += fib_test_label();
10723     }
10724     else if (unformat (input, "ae"))
10725     {
10726         res += fib_test_ae();
10727     }
10728     else if (unformat (input, "pref"))
10729     {
10730         res += fib_test_pref();
10731     }
10732     else if (unformat (input, "lfib"))
10733     {
10734         res += lfib_test();
10735     }
10736     else if (unformat (input, "walk"))
10737     {
10738         res += fib_test_walk();
10739     }
10740     else if (unformat (input, "bfd"))
10741     {
10742         res += fib_test_bfd();
10743     }
10744     else if (unformat (input, "inherit"))
10745     {
10746         res += fib_test_inherit();
10747     }
10748     else if (unformat (input, "sticky"))
10749     {
10750         res += fib_test_sticky();
10751     }
10752     else
10753     {
10754         res += fib_test_v4();
10755         res += fib_test_v6();
10756         res += fib_test_ae();
10757         res += fib_test_bfd();
10758         res += fib_test_pref();
10759         res += fib_test_label();
10760         res += fib_test_inherit();
10761         res += lfib_test();
10762
10763         /*
10764          * fib-walk process must be disabled in order for the walk tests to work
10765          */
10766         fib_walk_process_disable();
10767         res += fib_test_walk();
10768         fib_walk_process_enable();
10769     }
10770
10771     fflush(NULL);
10772     if (res)
10773     {
10774         return clib_error_return(0, "FIB Unit Test Failed");
10775     }
10776     else
10777     {
10778         return (NULL);
10779     }
10780 }
10781
10782 VLIB_CLI_COMMAND (test_fib_command, static) = {
10783     .path = "test fib",
10784     .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
10785     .function = fib_test,
10786 };
10787
10788 clib_error_t *
10789 fib_test_init (vlib_main_t *vm)
10790 {
10791     return 0;
10792 }
10793
10794 VLIB_INIT_FUNCTION (fib_test_init);
10795
10796 // clang-format on