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