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