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