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