MTRIE Optimisations 2
[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/ip6_fib.h>
17 #include <vnet/fib/ip4_fib.h>
18 #include <vnet/fib/mpls_fib.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/dpo/load_balance_map.h>
22 #include <vnet/dpo/mpls_label_dpo.h>
23 #include <vnet/dpo/lookup_dpo.h>
24 #include <vnet/dpo/drop_dpo.h>
25 #include <vnet/dpo/receive_dpo.h>
26 #include <vnet/dpo/ip_null_dpo.h>
27
28 #include <vnet/mpls/mpls.h>
29
30 #include <vnet/fib/fib_path_list.h>
31 #include <vnet/fib/fib_entry_src.h>
32 #include <vnet/fib/fib_walk.h>
33 #include <vnet/fib/fib_node_list.h>
34 #include <vnet/fib/fib_urpf_list.h>
35
36 #define FIB_TEST_I(_cond, _comment, _args...)                   \
37 ({                                                              \
38     int _evald = (_cond);                                       \
39     if (!(_evald)) {                                            \
40         fformat(stderr, "FAIL:%d: " _comment "\n",              \
41                 __LINE__, ##_args);                             \
42     } else {                                                    \
43     }                                                           \
44     _evald;                                                     \
45 })
46 #define FIB_TEST(_cond, _comment, _args...)                     \
47 {                                                               \
48     if (!FIB_TEST_I(_cond, _comment, ##_args)) {                \
49         return 1;                                               \
50         ASSERT(!("FAIL: " _comment));                           \
51     }                                                           \
52 }
53
54 /**
55  * A 'i'm not fussed is this is not efficient' store of test data
56  */
57 typedef struct test_main_t_ {
58     /**
59      * HW if indicies
60      */
61     u32 hw_if_indicies[4];
62     /**
63      * HW interfaces
64      */
65     vnet_hw_interface_t * hw[4];
66
67 } test_main_t;
68 static test_main_t test_main;
69
70 /* fake ethernet device class, distinct from "fake-ethX" */
71 static u8 * format_test_interface_name (u8 * s, va_list * args)
72 {
73   u32 dev_instance = va_arg (*args, u32);
74   return format (s, "test-eth%d", dev_instance);
75 }
76
77 static uword dummy_interface_tx (vlib_main_t * vm,
78                                  vlib_node_runtime_t * node,
79                                  vlib_frame_t * frame)
80 {
81   clib_warning ("you shouldn't be here, leaking buffers...");
82   return frame->n_vectors;
83 }
84
85 static clib_error_t *
86 test_interface_admin_up_down (vnet_main_t * vnm,
87                               u32 hw_if_index,
88                               u32 flags)
89 {
90   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
91     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
92   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
93   return 0;
94 }
95
96 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
97   .name = "Test interface",
98   .format_device_name = format_test_interface_name,
99   .tx_function = dummy_interface_tx,
100   .admin_up_down_function = test_interface_admin_up_down,
101 };
102
103 static u8 *hw_address;
104
105 static int
106 fib_test_mk_intf (u32 ninterfaces)
107 {
108     clib_error_t * error = NULL;
109     test_main_t *tm = &test_main;
110     u8 byte;
111     u32 i;
112
113     ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
114
115     for (i=0; i<6; i++)
116     {
117         byte = 0xd0+i;
118         vec_add1(hw_address, byte);
119     }
120
121     for (i = 0; i < ninterfaces; i++)
122     {
123         hw_address[5] = i;
124
125         error = ethernet_register_interface(vnet_get_main(),
126                                             test_interface_device_class.index,
127                                             i /* instance */,
128                                             hw_address,
129                                             &tm->hw_if_indicies[i], 
130                                             /* flag change */ 0);
131
132         FIB_TEST((NULL == error), "ADD interface %d", i);
133       
134         error = vnet_hw_interface_set_flags(vnet_get_main(),
135                                             tm->hw_if_indicies[i],
136                                             VNET_HW_INTERFACE_FLAG_LINK_UP);
137         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
138                                           tm->hw_if_indicies[i]);
139         vec_validate (ip4_main.fib_index_by_sw_if_index,
140                       tm->hw[i]->sw_if_index);
141         vec_validate (ip6_main.fib_index_by_sw_if_index,
142                       tm->hw[i]->sw_if_index);
143         ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
144         ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
145
146         error = vnet_sw_interface_set_flags(vnet_get_main(),
147                                             tm->hw[i]->sw_if_index,
148                                             VNET_SW_INTERFACE_FLAG_ADMIN_UP);
149         FIB_TEST((NULL == error), "UP interface %d", i);
150     }
151     /*
152      * re-eval after the inevitable realloc
153      */
154     for (i = 0; i < ninterfaces; i++)
155     {
156         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
157                                           tm->hw_if_indicies[i]);
158     }
159
160     return (0);
161 }
162
163 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket)            \
164 {                                                                       \
165     const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding(      \
166         fib_table_lookup_exact_match(fib_index, (_rec_prefix)));        \
167     const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding(      \
168         fib_table_lookup(fib_index, (_via_prefix)));                    \
169     FIB_TEST(!dpo_cmp(_via_dpo,                                         \
170                       load_balance_get_bucket(_rec_dpo->dpoi_index,     \
171                                               _bucket)),                \
172              "%U is recursive via %U",                                  \
173              format_fib_prefix, (_rec_prefix),                          \
174              format_fib_prefix, _via_prefix);                           \
175 }
176
177 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai)               \
178 {                                                                       \
179     const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding(          \
180         fib_table_lookup_exact_match(fib_index, (_prefix)));            \
181     const dpo_id_t *_dpo1 =                                             \
182         load_balance_get_bucket(_dpo->dpoi_index, _bucket);             \
183     FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U",           \
184              format_dpo_type, _dpo1->dpoi_type);                        \
185     FIB_TEST((_ai == _dpo1->dpoi_index),                                \
186              "%U bucket %d resolves via %U",                            \
187              format_fib_prefix, (_prefix),                              \
188              _bucket,                                                   \
189              format_dpo_id, _dpo1, 0);                                  \
190 }
191
192 #define FIB_TEST_RPF(_cond, _comment, _args...)                 \
193 {                                                               \
194     if (!FIB_TEST_I(_cond, _comment, ##_args)) {                \
195         return (0);                                             \
196     }                                                           \
197 }
198
199 static int
200 fib_test_urpf_is_equal (fib_node_index_t fei,
201                        fib_forward_chain_type_t fct,
202                        u32 num, ...)
203 {
204     dpo_id_t dpo = DPO_INVALID;
205     fib_urpf_list_t *urpf;
206     index_t ui;
207     va_list ap;
208     int ii;
209
210     va_start(ap, num);
211
212     fib_entry_contribute_forwarding(fei, fct, &dpo);
213     ui = load_balance_get_urpf(dpo.dpoi_index);
214
215     urpf = fib_urpf_list_get(ui);
216
217     FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
218                  "RPF:%U len %d == %d",
219                  format_fib_urpf_list, ui,
220                  num, vec_len(urpf->furpf_itfs));
221     FIB_TEST_RPF(num == fib_urpf_check_size(ui),
222                  "RPF:%U check-size %d == %d",
223                  format_fib_urpf_list, ui,
224                  num, vec_len(urpf->furpf_itfs));
225
226     for (ii = 0; ii < num; ii++)
227     {
228         adj_index_t ai = va_arg(ap, adj_index_t);
229
230         FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
231                      "RPF:%d item:%d - %d == %d",
232                      ui, ii, ai, urpf->furpf_itfs[ii]);
233         FIB_TEST_RPF(fib_urpf_check(ui, ai),
234                      "RPF:%d %d found",
235                      ui, ai);
236     }
237
238     dpo_reset(&dpo);
239
240     va_end(ap);
241
242     return (1);
243 }
244
245 static u8*
246 fib_test_build_rewrite (u8 *eth_addr)
247 {
248     u8* rewrite = NULL;
249
250     vec_validate(rewrite, 13);
251
252     memcpy(rewrite, eth_addr, 6);
253     memcpy(rewrite+6, eth_addr, 6);
254
255     return (rewrite);
256 }
257
258 typedef enum fib_test_lb_bucket_type_t_ {
259     FT_LB_LABEL_O_ADJ,
260     FT_LB_LABEL_STACK_O_ADJ,
261     FT_LB_LABEL_O_LB,
262     FT_LB_O_LB,
263     FT_LB_SPECIAL,
264     FT_LB_ADJ,
265 } fib_test_lb_bucket_type_t;
266
267 typedef struct fib_test_lb_bucket_t_ {
268     fib_test_lb_bucket_type_t type;
269
270     union
271     {
272         struct
273         {
274             mpls_eos_bit_t eos;
275             mpls_label_t label;
276             u8 ttl;
277             adj_index_t adj;
278         } label_o_adj;
279         struct
280         {
281             mpls_eos_bit_t eos;
282             mpls_label_t label_stack[8];
283             u8 label_stack_size;
284             u8 ttl;
285             adj_index_t adj;
286         } label_stack_o_adj;
287         struct
288         {
289             mpls_eos_bit_t eos;
290             mpls_label_t label;
291             u8 ttl;
292             index_t lb;
293         } label_o_lb;
294         struct
295         {
296             index_t adj;
297         } adj;
298         struct
299         {
300             index_t lb;
301         } lb;
302         struct
303         {
304             index_t adj;
305         } special;
306     };
307 } fib_test_lb_bucket_t;
308
309 #define FIB_TEST_LB(_cond, _comment, _args...)                  \
310 {                                                               \
311     if (!FIB_TEST_I(_cond, _comment, ##_args)) {                \
312         return (0);                                             \
313     }                                                           \
314 }
315
316 static int
317 fib_test_validate_lb_v (const load_balance_t *lb,
318                         u16 n_buckets,
319                         va_list ap)
320 {
321     const dpo_id_t *dpo;
322     int bucket;
323
324     FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
325
326     for (bucket = 0; bucket < n_buckets; bucket++)
327     {
328         const fib_test_lb_bucket_t *exp;
329
330         exp = va_arg(ap, fib_test_lb_bucket_t*);
331         dpo = load_balance_get_bucket_i(lb, bucket);
332
333         switch (exp->type)
334         {
335         case FT_LB_LABEL_STACK_O_ADJ:
336             {
337                 const mpls_label_dpo_t *mld;
338                 mpls_label_t hdr;
339                 u32 ii;
340
341                 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
342                            "bucket %d stacks on %U",
343                            bucket,
344                            format_dpo_type, dpo->dpoi_type);
345             
346                 mld = mpls_label_dpo_get(dpo->dpoi_index);
347
348                 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
349                             "label stack size",
350                             mld->mld_n_labels);
351
352                 for (ii = 0; ii < mld->mld_n_labels; ii++)
353                 {
354                     hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
355                     FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
356                                  exp->label_stack_o_adj.label_stack[ii]),
357                                 "bucket %d stacks on label %d",
358                                 bucket,
359                                 exp->label_stack_o_adj.label_stack[ii]);
360
361                     if (ii == mld->mld_n_labels-1)
362                     {
363                         FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
364                                      exp->label_o_adj.eos),
365                                     "bucket %d stacks on label %d %U!=%U",
366                                     bucket,
367                                     exp->label_stack_o_adj.label_stack[ii],
368                                     format_mpls_eos_bit, exp->label_o_adj.eos,
369                                     format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
370                     }
371                     else
372                     {
373                         FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
374                                     "bucket %d stacks on label %d %U",
375                                     bucket,
376                                     exp->label_stack_o_adj.label_stack[ii],
377                                     format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
378                     }
379                 }
380
381                 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
382                             "bucket %d label stacks on %U",
383                             bucket,
384                             format_dpo_type, mld->mld_dpo.dpoi_type);
385
386                 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
387                             "bucket %d label stacks on adj %d",
388                             bucket,
389                             exp->label_stack_o_adj.adj);
390             }
391             break;
392         case FT_LB_LABEL_O_ADJ:
393             {
394                 const mpls_label_dpo_t *mld;
395                 mpls_label_t hdr;
396                 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
397                            "bucket %d stacks on %U",
398                            bucket,
399                            format_dpo_type, dpo->dpoi_type);
400             
401                 mld = mpls_label_dpo_get(dpo->dpoi_index);
402                 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
403
404                 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
405                              exp->label_o_adj.label),
406                             "bucket %d stacks on label %d",
407                             bucket,
408                             exp->label_o_adj.label);
409
410                 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
411                              exp->label_o_adj.eos),
412                             "bucket %d stacks on label %d %U",
413                             bucket,
414                             exp->label_o_adj.label,
415                             format_mpls_eos_bit, exp->label_o_adj.eos);
416
417                 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
418                             "bucket %d label stacks on %U",
419                             bucket,
420                             format_dpo_type, mld->mld_dpo.dpoi_type);
421
422                 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
423                             "bucket %d label stacks on adj %d",
424                             bucket,
425                             exp->label_o_adj.adj);
426             }
427             break;
428         case FT_LB_LABEL_O_LB:
429             {
430                 const mpls_label_dpo_t *mld;
431                 mpls_label_t hdr;
432
433                 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
434                            "bucket %d stacks on %U",
435                            bucket,
436                            format_dpo_type, dpo->dpoi_type);
437             
438                 mld = mpls_label_dpo_get(dpo->dpoi_index);
439                 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
440
441                 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
442                             mld->mld_n_labels);
443                 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
444                              exp->label_o_lb.label),
445                             "bucket %d stacks on label %d",
446                             bucket,
447                             exp->label_o_lb.label);
448
449                 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
450                              exp->label_o_lb.eos),
451                             "bucket %d stacks on label %d %U",
452                             bucket,
453                             exp->label_o_lb.label,
454                             format_mpls_eos_bit, exp->label_o_lb.eos);
455
456                 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
457                             "bucket %d label stacks on %U",
458                             bucket,
459                             format_dpo_type, mld->mld_dpo.dpoi_type);
460
461                 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
462                             "bucket %d label stacks on LB %d",
463                             bucket,
464                             exp->label_o_lb.lb);
465             }
466             break;
467         case FT_LB_ADJ:
468             FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
469                         (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
470                        "bucket %d stacks on %U",
471                        bucket,
472                        format_dpo_type, dpo->dpoi_type);
473             FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
474                         "bucket %d stacks on adj %d",
475                         bucket,
476                         exp->adj.adj);
477             break;
478         case FT_LB_O_LB:
479             FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
480                        "bucket %d stacks on %U",
481                        bucket,
482                        format_dpo_type, dpo->dpoi_type);
483             FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
484                         "bucket %d stacks on lb %d",
485                         bucket,
486                         exp->lb.lb);
487             break;
488         case FT_LB_SPECIAL:
489             FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
490                        "bucket %d stacks on %U",
491                        bucket,
492                        format_dpo_type, dpo->dpoi_type);
493             FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
494                         "bucket %d stacks on drop %d",
495                         bucket,
496                         exp->special.adj);
497             break;
498         }
499     }
500     return (!0);
501 }
502
503 static int
504 fib_test_validate_entry (fib_node_index_t fei,
505                          fib_forward_chain_type_t fct,
506                          u16 n_buckets,
507                          ...)
508 {
509     dpo_id_t dpo = DPO_INVALID;
510     const load_balance_t *lb;
511     fib_prefix_t pfx;
512     index_t fw_lbi;
513     u32 fib_index;
514     va_list ap;
515     int res;
516
517     va_start(ap, n_buckets);
518
519     fib_entry_get_prefix(fei, &pfx);
520     fib_index = fib_entry_get_fib_index(fei);
521     fib_entry_contribute_forwarding(fei, fct, &dpo);
522
523     FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
524                 "Entry links to %U",
525                 format_dpo_type, dpo.dpoi_type);
526     lb = load_balance_get(dpo.dpoi_index);
527
528     res = fib_test_validate_lb_v(lb, n_buckets, ap);
529
530     /*
531      * ensure that the LB contributed by the entry is the
532      * same as the LB in the forwarding tables
533      */
534     if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
535     {
536         switch (pfx.fp_proto)
537         {
538         case FIB_PROTOCOL_IP4:
539             fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
540             break;
541         case FIB_PROTOCOL_IP6:
542             fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
543             break;
544         case FIB_PROTOCOL_MPLS:
545             {
546                 mpls_unicast_header_t hdr = {
547                     .label_exp_s_ttl = 0,
548                 };
549
550                 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
551                 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
552                 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
553
554                 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
555                 break;
556             }
557         default:
558             fw_lbi = 0;
559         }
560         FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
561                     "Contributed LB = FW LB: %U\n %U",
562                     format_load_balance, fw_lbi, 0,
563                     format_load_balance, dpo.dpoi_index, 0);
564     }
565
566     dpo_reset(&dpo);
567
568     va_end(ap);
569
570     return (res);
571 }
572
573 static int
574 fib_test_v4 (void)
575 {
576     /*
577      * In the default table check for the presence and correct forwarding
578      * of the special entries
579      */
580     fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
581     const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
582     const ip_adjacency_t *adj;
583     const load_balance_t *lb;
584     test_main_t *tm;
585     u32 fib_index;
586     int ii;
587
588     /* via 10.10.10.1 */
589     ip46_address_t nh_10_10_10_1 = {
590         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
591     };
592     /* via 10.10.10.2 */
593     ip46_address_t nh_10_10_10_2 = {
594         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
595     };
596
597     tm = &test_main;
598
599     /* Find or create FIB table 11 */
600     fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
601
602     for (ii = 0; ii < 4; ii++)
603     {
604         ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
605     }
606
607     fib_prefix_t pfx_0_0_0_0_s_0 = {
608         .fp_len = 0,
609         .fp_proto = FIB_PROTOCOL_IP4,
610         .fp_addr = {
611             .ip4 = {
612                 {0}
613             },
614         },
615     };
616
617     fib_prefix_t pfx = {
618         .fp_len = 0,
619         .fp_proto = FIB_PROTOCOL_IP4,
620         .fp_addr = {
621             .ip4 = {
622                 {0}
623             },
624         },
625     };
626
627     dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
628
629     dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
630     FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
631     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
632              "Default route is DROP");
633
634     pfx.fp_len = 32;
635     fei = fib_table_lookup(fib_index, &pfx);
636     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
637     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
638              "all 0s route is DROP");
639
640     pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
641     pfx.fp_len = 32;
642     fei = fib_table_lookup(fib_index, &pfx);
643     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
644     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
645              "all 1s route is DROP");
646
647     pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
648     pfx.fp_len = 8;
649     fei = fib_table_lookup(fib_index, &pfx);
650     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
651     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
652              "all-mcast route is DROP");
653
654     pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
655     pfx.fp_len = 8;
656     fei = fib_table_lookup(fib_index, &pfx);
657     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
658     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
659              "class-e route is DROP");
660
661     /*
662      * at this stage there are 5 entries in the test FIB (plus 5 in the default),
663      * all of which are special sourced and so none of which share path-lists.
664      * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
665      * table, and 4 path-lists in the v6 MFIB table
666      */
667 #define ENBR (5+5+2)
668 #define PNBR (5+5+6)
669     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
670     FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
671              fib_path_list_pool_size());
672     FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
673              fib_entry_pool_size());
674
675     /*
676      * add interface routes.
677      *  validate presence of /24 attached and /32 recieve.
678      *  test for the presence of the receive address in the glean and local adj
679      */
680     fib_prefix_t local_pfx = {
681         .fp_len = 24,
682         .fp_proto = FIB_PROTOCOL_IP4,
683         .fp_addr = {
684             .ip4 = {
685                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
686             },
687         },
688     };
689
690     fib_table_entry_update_one_path(fib_index, &local_pfx,
691                                     FIB_SOURCE_INTERFACE,
692                                     (FIB_ENTRY_FLAG_CONNECTED |
693                                      FIB_ENTRY_FLAG_ATTACHED),
694                                     FIB_PROTOCOL_IP4,
695                                     NULL,
696                                     tm->hw[0]->sw_if_index,
697                                     ~0, // invalid fib index
698                                     1, // weight
699                                     NULL,
700                                     FIB_ROUTE_PATH_FLAG_NONE);
701     fei = fib_table_lookup(fib_index, &local_pfx);
702     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
703     FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
704               fib_entry_get_flags(fei)),
705              "Flags set on attached interface");
706
707     ai = fib_entry_get_adj(fei);
708     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
709     adj = adj_get(ai);
710     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
711              "attached interface adj is glean");
712     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
713                                     &adj->sub_type.glean.receive_addr)),
714               "attached interface adj is receive ok");
715
716     local_pfx.fp_len = 32;
717     fib_table_entry_update_one_path(fib_index, &local_pfx,
718                                     FIB_SOURCE_INTERFACE,
719                                     (FIB_ENTRY_FLAG_CONNECTED |
720                                      FIB_ENTRY_FLAG_LOCAL),
721                                     FIB_PROTOCOL_IP4,
722                                     NULL,
723                                     tm->hw[0]->sw_if_index,
724                                     ~0, // invalid fib index
725                                     1, // weight
726                                     NULL,
727                                     FIB_ROUTE_PATH_FLAG_NONE);
728     fei = fib_table_lookup(fib_index, &local_pfx);
729     FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
730               fib_entry_get_flags(fei)),
731              "Flags set on local interface");
732
733     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
734
735     dpo = fib_entry_contribute_ip_forwarding(fei);
736     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
737              "RPF list for local length 0");
738     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
739     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
740              "local interface adj is local");
741     receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
742
743     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
744                                     &rd->rd_addr)),
745               "local interface adj is receive ok");
746
747     FIB_TEST((2 == fib_table_get_num_entries(fib_index,
748                                              FIB_PROTOCOL_IP4,
749                                              FIB_SOURCE_INTERFACE)),
750              "2 Interface Source'd prefixes");
751
752     /*
753      * +2 interface routes +2 non-shared path-lists
754      */
755     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
756     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
757              fib_path_list_pool_size());
758     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
759              fib_entry_pool_size());
760
761     /*
762      * Modify the default route to be via an adj not yet known.
763      * this sources the defalut route with the API source, which is
764      * a higher preference to the DEFAULT_ROUTE source
765      */
766     pfx.fp_addr.ip4.as_u32 = 0;
767     pfx.fp_len = 0;
768     fib_table_entry_path_add(fib_index, &pfx,
769                              FIB_SOURCE_API,
770                              FIB_ENTRY_FLAG_NONE,
771                              FIB_PROTOCOL_IP4,
772                              &nh_10_10_10_1,
773                              tm->hw[0]->sw_if_index,
774                              ~0, // invalid fib index
775                              1,
776                              NULL,
777                              FIB_ROUTE_PATH_FLAG_NONE);
778     fei = fib_table_lookup(fib_index, &pfx);
779     FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
780              "Flags set on API route");
781
782     FIB_TEST((fei == dfrt), "default route same index");
783     ai = fib_entry_get_adj(fei);
784     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
785     adj = adj_get(ai);
786     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
787              "adj is incomplete");
788     FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
789               "adj nbr next-hop ok");
790     FIB_TEST((1 == fib_table_get_num_entries(fib_index,
791                                              FIB_PROTOCOL_IP4,
792                                              FIB_SOURCE_API)),
793              "1 API Source'd prefixes");
794
795     /*
796      * find the adj in the shared db
797      */
798     locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
799                                     VNET_LINK_IP4,
800                                     &nh_10_10_10_1,
801                                     tm->hw[0]->sw_if_index);
802     FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
803     adj_unlock(locked_ai);
804
805     /*
806      * +1 shared path-list
807      */
808     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
809              fib_path_list_db_size());
810     FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
811              fib_path_list_pool_size());
812     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
813              fib_entry_pool_size());
814
815     /*
816      * remove the API source from the default route. We expected
817      * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
818      */
819     pfx.fp_addr.ip4.as_u32 = 0;
820     pfx.fp_len = 0;
821     fib_table_entry_path_remove(fib_index, &pfx,
822                                 FIB_SOURCE_API,
823                                 FIB_PROTOCOL_IP4,
824                                 &nh_10_10_10_1,
825                                 tm->hw[0]->sw_if_index,
826                                 ~0, // non-recursive path, so no FIB index
827                                 1,
828                                 FIB_ROUTE_PATH_FLAG_NONE);
829
830     fei = fib_table_lookup(fib_index, &pfx);
831
832     FIB_TEST((fei == dfrt), "default route same index");
833     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
834              "Default route is DROP");
835
836     /*
837      * -1 shared-path-list
838      */
839     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
840     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
841              fib_path_list_pool_size());
842     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
843              fib_entry_pool_size());
844
845     /*
846      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
847      */
848     fib_prefix_t pfx_10_10_10_1_s_32 = {
849         .fp_len = 32,
850         .fp_proto = FIB_PROTOCOL_IP4,
851         .fp_addr = {
852             /* 10.10.10.1 */
853             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
854         },
855     };
856     fib_prefix_t pfx_10_10_10_2_s_32 = {
857         .fp_len = 32,
858         .fp_proto = FIB_PROTOCOL_IP4,
859         .fp_addr = {
860             /* 10.10.10.2 */
861             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
862         },
863     };
864     fib_prefix_t pfx_11_11_11_11_s_32 = {
865         .fp_len = 32,
866         .fp_proto = FIB_PROTOCOL_IP4,
867         .fp_addr = {
868             /* 11.11.11.11 */
869             .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
870         },
871     };
872     u8 eth_addr[] = {
873         0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
874     };
875
876     ip46_address_t nh_12_12_12_12 = {
877         .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
878     };
879     adj_index_t ai_12_12_12_12;
880
881     /*
882      * Add a route via an incomplete ADJ. then complete the ADJ
883      * Expect the route LB is updated to use complete adj type.
884      */
885     fei = fib_table_entry_update_one_path(fib_index,
886                                           &pfx_11_11_11_11_s_32,
887                                           FIB_SOURCE_API,
888                                           FIB_ENTRY_FLAG_ATTACHED,
889                                           FIB_PROTOCOL_IP4,
890                                           &pfx_10_10_10_1_s_32.fp_addr,
891                                           tm->hw[0]->sw_if_index,
892                                           ~0, // invalid fib index
893                                           1,
894                                           NULL,
895                                           FIB_ROUTE_PATH_FLAG_NONE);
896
897     dpo = fib_entry_contribute_ip_forwarding(fei);
898     dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
899     FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
900              "11.11.11.11/32 via incomplete adj");
901
902     ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
903                                 VNET_LINK_IP4,
904                                 &pfx_10_10_10_1_s_32.fp_addr,
905                                 tm->hw[0]->sw_if_index);
906     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
907     adj = adj_get(ai_01);
908     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
909              "adj is incomplete");
910     FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
911                                     &adj->sub_type.nbr.next_hop)),
912               "adj nbr next-hop ok");
913
914     adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
915                            fib_test_build_rewrite(eth_addr));
916     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
917              "adj is complete");
918     FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
919                                     &adj->sub_type.nbr.next_hop)),
920               "adj nbr next-hop ok");
921     ai = fib_entry_get_adj(fei);
922     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
923
924     dpo = fib_entry_contribute_ip_forwarding(fei);
925     dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
926     FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
927              "11.11.11.11/32 via complete adj");
928     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
929                                     tm->hw[0]->sw_if_index),
930              "RPF list for adj-fib contains adj");
931
932     ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
933                                          VNET_LINK_IP4,
934                                          &nh_12_12_12_12,
935                                          tm->hw[1]->sw_if_index);
936     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
937     adj = adj_get(ai_12_12_12_12);
938     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
939              "adj is incomplete");
940     FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
941                                     &adj->sub_type.nbr.next_hop)),
942               "adj nbr next-hop ok");
943     adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
944                            fib_test_build_rewrite(eth_addr));
945     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
946              "adj is complete");
947
948     /*
949      * add the adj fib
950      */
951     fei = fib_table_entry_update_one_path(fib_index,
952                                           &pfx_10_10_10_1_s_32,
953                                           FIB_SOURCE_ADJ,
954                                           FIB_ENTRY_FLAG_ATTACHED,
955                                           FIB_PROTOCOL_IP4,
956                                           &pfx_10_10_10_1_s_32.fp_addr,
957                                           tm->hw[0]->sw_if_index,
958                                           ~0, // invalid fib index
959                                           1,
960                                           NULL,
961                                           FIB_ROUTE_PATH_FLAG_NONE);
962     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED  == fib_entry_get_flags(fei)),
963              "Flags set on adj-fib");
964     ai = fib_entry_get_adj(fei);
965     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
966
967     fib_table_entry_path_remove(fib_index,
968                                 &pfx_11_11_11_11_s_32,
969                                 FIB_SOURCE_API,
970                                 FIB_PROTOCOL_IP4,
971                                 &pfx_10_10_10_1_s_32.fp_addr,
972                                 tm->hw[0]->sw_if_index,
973                                 ~0, // invalid fib index
974                                 1,
975                                 FIB_ROUTE_PATH_FLAG_NONE);
976
977     eth_addr[5] = 0xb2;
978
979     ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
980                                 VNET_LINK_IP4,
981                                 &pfx_10_10_10_2_s_32.fp_addr,
982                                 tm->hw[0]->sw_if_index);
983     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
984     adj = adj_get(ai_02);
985     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
986              "adj is incomplete");
987     FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
988                                     &adj->sub_type.nbr.next_hop)),
989               "adj nbr next-hop ok");
990
991     adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
992                            fib_test_build_rewrite(eth_addr));
993     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
994              "adj is complete");
995     FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
996                                     &adj->sub_type.nbr.next_hop)),
997               "adj nbr next-hop ok");
998     FIB_TEST((ai_01 != ai_02), "ADJs are different");
999
1000     fib_table_entry_update_one_path(fib_index,
1001                                     &pfx_10_10_10_2_s_32,
1002                                     FIB_SOURCE_ADJ,
1003                                     FIB_ENTRY_FLAG_ATTACHED,
1004                                     FIB_PROTOCOL_IP4,
1005                                     &pfx_10_10_10_2_s_32.fp_addr,
1006                                     tm->hw[0]->sw_if_index,
1007                                     ~0, // invalid fib index
1008                                     1,
1009                                     NULL,
1010                                     FIB_ROUTE_PATH_FLAG_NONE);
1011
1012     fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1013     ai = fib_entry_get_adj(fei);
1014     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1015
1016     /*
1017      * +2 adj-fibs, and their non-shared path-lists
1018      */
1019     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
1020     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1021              fib_path_list_pool_size());
1022     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1023              fib_entry_pool_size());
1024
1025     /*
1026      * Add 2 routes via the first ADJ. ensure path-list sharing
1027      */
1028     fib_prefix_t pfx_1_1_1_1_s_32 = {
1029         .fp_len = 32,
1030         .fp_proto = FIB_PROTOCOL_IP4,
1031         .fp_addr = {
1032             /* 1.1.1.1/32 */
1033             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1034         },
1035     };
1036
1037     fib_table_entry_path_add(fib_index,
1038                              &pfx_1_1_1_1_s_32,
1039                              FIB_SOURCE_API,
1040                              FIB_ENTRY_FLAG_NONE,
1041                              FIB_PROTOCOL_IP4,
1042                              &nh_10_10_10_1,
1043                              tm->hw[0]->sw_if_index,
1044                              ~0, // invalid fib index
1045                              1,
1046                              NULL,
1047                              FIB_ROUTE_PATH_FLAG_NONE);
1048     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1049     ai = fib_entry_get_adj(fei);
1050     FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1051
1052     /*
1053      * +1 entry and a shared path-list
1054      */
1055     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB is empty");
1056     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1057              fib_path_list_pool_size());
1058     FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1059              fib_entry_pool_size());
1060
1061     /* 1.1.2.0/24 */
1062     fib_prefix_t pfx_1_1_2_0_s_24 = {
1063         .fp_len = 24,
1064         .fp_proto = FIB_PROTOCOL_IP4,
1065         .fp_addr = {
1066             .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1067         }
1068     };
1069
1070     fib_table_entry_path_add(fib_index,
1071                              &pfx_1_1_2_0_s_24,
1072                              FIB_SOURCE_API,
1073                              FIB_ENTRY_FLAG_NONE,
1074                              FIB_PROTOCOL_IP4,
1075                              &nh_10_10_10_1,
1076                              tm->hw[0]->sw_if_index,
1077                              ~0, // invalid fib index
1078                              1,
1079                              NULL,
1080                              FIB_ROUTE_PATH_FLAG_NONE);
1081     fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1082     ai = fib_entry_get_adj(fei);
1083     FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1084
1085     /*
1086      * +1 entry only
1087      */
1088     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB is empty");
1089     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1090              fib_path_list_pool_size());
1091     FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1092              fib_entry_pool_size());
1093
1094     /*
1095      * modify 1.1.2.0/24 to use multipath.
1096      */
1097     fib_table_entry_path_add(fib_index,
1098                              &pfx_1_1_2_0_s_24,
1099                              FIB_SOURCE_API,
1100                              FIB_ENTRY_FLAG_NONE,
1101                              FIB_PROTOCOL_IP4,
1102                              &nh_10_10_10_2,
1103                              tm->hw[0]->sw_if_index,
1104                              ~0, // invalid fib index
1105                              1,
1106                              NULL,
1107                              FIB_ROUTE_PATH_FLAG_NONE);
1108     fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1109     dpo = fib_entry_contribute_ip_forwarding(fei);
1110     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1111                                     1, tm->hw[0]->sw_if_index),
1112              "RPF list for 1.1.2.0/24 contains both adjs");
1113
1114     dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1115     FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1116     FIB_TEST((ai_01 == dpo1->dpoi_index),
1117              "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1118              ai_01, dpo1->dpoi_index);
1119
1120     dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1121     FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1122     FIB_TEST((ai_02 == dpo1->dpoi_index),
1123              "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1124
1125     /*
1126      * +1 shared-pathlist
1127      */
1128     FIB_TEST((2 == fib_path_list_db_size()),   "path list DB is empty");
1129     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1130              fib_path_list_pool_size());
1131     FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1132              fib_entry_pool_size());
1133
1134     /*
1135      * revert the modify
1136      */
1137     fib_table_entry_path_remove(fib_index,
1138                                 &pfx_1_1_2_0_s_24,
1139                                 FIB_SOURCE_API,
1140                                 FIB_PROTOCOL_IP4,
1141                                 &nh_10_10_10_2,
1142                                 tm->hw[0]->sw_if_index,
1143                                 ~0,
1144                                 1,
1145                                 FIB_ROUTE_PATH_FLAG_NONE);
1146     fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1147     dpo = fib_entry_contribute_ip_forwarding(fei);
1148     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1149                                    1, tm->hw[0]->sw_if_index),
1150              "RPF list for 1.1.2.0/24 contains one adj");
1151
1152     ai = fib_entry_get_adj(fei);
1153     FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1154
1155     /*
1156      * +1 shared-pathlist
1157      */
1158     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB is %d",
1159              fib_path_list_db_size());
1160     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1161              fib_path_list_pool_size());
1162     FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1163              fib_entry_pool_size());
1164
1165     /*
1166      * Add 2 recursive routes:
1167      *   100.100.100.100/32 via 1.1.1.1/32  => the via entry is installed.
1168      *   100.100.100.101/32 via 1.1.1.1/32  => the via entry is installed.
1169      */
1170     fib_prefix_t bgp_100_pfx = {
1171         .fp_len = 32,
1172         .fp_proto = FIB_PROTOCOL_IP4,
1173         .fp_addr = {
1174             /* 100.100.100.100/32 */
1175             .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1176         },
1177     };
1178     /* via 1.1.1.1 */
1179     ip46_address_t nh_1_1_1_1 = {
1180         .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1181     };
1182
1183     fei = fib_table_entry_path_add(fib_index,
1184                                    &bgp_100_pfx,
1185                                    FIB_SOURCE_API,
1186                                    FIB_ENTRY_FLAG_NONE,
1187                                    FIB_PROTOCOL_IP4,
1188                                    &nh_1_1_1_1,
1189                                    ~0, // no index provided.
1190                                    fib_index, // nexthop in same fib as route
1191                                    1,
1192                                    NULL,
1193                                    FIB_ROUTE_PATH_FLAG_NONE);
1194
1195     FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1196     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1197                                     tm->hw[0]->sw_if_index),
1198              "RPF list for adj-fib contains adj");
1199
1200     /*
1201      * +1 entry and +1 shared-path-list
1202      */
1203     FIB_TEST((2  == fib_path_list_db_size()),   "path list DB population:%d",
1204              fib_path_list_db_size());
1205     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1206              fib_path_list_pool_size());
1207     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1208              fib_entry_pool_size());
1209
1210     fib_prefix_t bgp_101_pfx = {
1211         .fp_len = 32,
1212         .fp_proto = FIB_PROTOCOL_IP4,
1213         .fp_addr = {
1214             /* 100.100.100.101/32 */
1215             .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1216         },
1217     };
1218
1219     fib_table_entry_path_add(fib_index,
1220                              &bgp_101_pfx,
1221                              FIB_SOURCE_API,
1222                              FIB_ENTRY_FLAG_NONE,
1223                              FIB_PROTOCOL_IP4,
1224                              &nh_1_1_1_1,
1225                              ~0, // no index provided.
1226                              fib_index, // nexthop in same fib as route
1227                              1,
1228                              NULL,
1229                              FIB_ROUTE_PATH_FLAG_NONE);
1230
1231     FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1232     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1233                                     tm->hw[0]->sw_if_index),
1234              "RPF list for adj-fib contains adj");
1235
1236     /*
1237      * +1 entry, but the recursive path-list is shared.
1238      */
1239     FIB_TEST((2  == fib_path_list_db_size()),   "path list DB population:%d",
1240              fib_path_list_db_size());
1241     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1242              fib_path_list_pool_size());
1243     FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1244              fib_entry_pool_size());
1245
1246     /*
1247      * An EXCLUSIVE route; one where the user (me) provides the exclusive
1248      * adjacency through which the route will resovle
1249      */
1250     fib_prefix_t ex_pfx = {
1251         .fp_len = 32,
1252         .fp_proto = FIB_PROTOCOL_IP4,
1253         .fp_addr = {
1254             /* 4.4.4.4/32 */
1255             .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1256         },
1257     };
1258
1259     fib_table_entry_special_add(fib_index,
1260                                 &ex_pfx,
1261                                 FIB_SOURCE_SPECIAL,
1262                                 FIB_ENTRY_FLAG_EXCLUSIVE,
1263                                 locked_ai);
1264     fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1265     FIB_TEST((ai == fib_entry_get_adj(fei)),
1266              "Exclusive route links to user adj");
1267
1268     fib_table_entry_special_remove(fib_index,
1269                                    &ex_pfx,
1270                                    FIB_SOURCE_SPECIAL);
1271     FIB_TEST(FIB_NODE_INDEX_INVALID ==
1272              fib_table_lookup_exact_match(fib_index, &ex_pfx),
1273              "Exclusive reoute removed");
1274
1275     /*
1276      * An EXCLUSIVE route; one where the user (me) provides the exclusive
1277      * adjacency through which the route will resovle
1278      */
1279     dpo_id_t ex_dpo = DPO_INVALID;
1280
1281     lookup_dpo_add_or_lock_w_fib_index(fib_index,
1282                                        DPO_PROTO_IP4,
1283                                        LOOKUP_INPUT_DST_ADDR,
1284                                        LOOKUP_TABLE_FROM_CONFIG,
1285                                        &ex_dpo);
1286
1287     fib_table_entry_special_dpo_add(fib_index,
1288                                     &ex_pfx,
1289                                     FIB_SOURCE_SPECIAL,
1290                                     FIB_ENTRY_FLAG_EXCLUSIVE,
1291                                     &ex_dpo);
1292     fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1293     dpo = fib_entry_contribute_ip_forwarding(fei);
1294     FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1295              "exclusive remote uses lookup DPO");
1296
1297     /*
1298      * update the exclusive to use a different DPO
1299      */
1300     ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1301                              IP_NULL_ACTION_SEND_ICMP_UNREACH,
1302                              &ex_dpo);
1303     fib_table_entry_special_dpo_update(fib_index,
1304                                        &ex_pfx,
1305                                        FIB_SOURCE_SPECIAL,
1306                                        FIB_ENTRY_FLAG_EXCLUSIVE,
1307                                        &ex_dpo);
1308     dpo = fib_entry_contribute_ip_forwarding(fei);
1309     FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1310              "exclusive remote uses now uses NULL DPO");
1311
1312     fib_table_entry_special_remove(fib_index,
1313                                    &ex_pfx,
1314                                    FIB_SOURCE_SPECIAL);
1315     FIB_TEST(FIB_NODE_INDEX_INVALID ==
1316              fib_table_lookup_exact_match(fib_index, &ex_pfx),
1317              "Exclusive reoute removed");
1318     dpo_reset(&ex_dpo);
1319
1320     /*
1321      * Add a recursive route:
1322      *   200.200.200.200/32 via 1.1.1.2/32  => the via entry is NOT installed.
1323      */
1324     fib_prefix_t bgp_200_pfx = {
1325         .fp_len = 32,
1326         .fp_proto = FIB_PROTOCOL_IP4,
1327         .fp_addr = {
1328             /* 200.200.200.200/32 */
1329             .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1330         },
1331     };
1332     /* via 1.1.1.2 */
1333     fib_prefix_t pfx_1_1_1_2_s_32 = {
1334         .fp_len = 32,
1335         .fp_proto = FIB_PROTOCOL_IP4,
1336         .fp_addr = {
1337             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1338         },
1339     };
1340
1341     fib_table_entry_path_add(fib_index,
1342                              &bgp_200_pfx,
1343                              FIB_SOURCE_API,
1344                              FIB_ENTRY_FLAG_NONE,
1345                              FIB_PROTOCOL_IP4,
1346                              &pfx_1_1_1_2_s_32.fp_addr,
1347                              ~0, // no index provided.
1348                              fib_index, // nexthop in same fib as route
1349                              1,
1350                              NULL,
1351                              FIB_ROUTE_PATH_FLAG_NONE);
1352
1353     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1354
1355     /*
1356      * the adj should be recursive via drop, since the route resolves via
1357      * the default route, which is itself a DROP 
1358      */
1359     fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1360     dpo1 = fib_entry_contribute_ip_forwarding(fei);
1361     FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1362     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1363              "RPF list for 1.1.1.2/32 contains 0 adjs");
1364
1365     /*
1366      * +2 entry and +1 shared-path-list
1367      */
1368     FIB_TEST((3  == fib_path_list_db_size()),   "path list DB population:%d",
1369              fib_path_list_db_size());
1370     FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1371              fib_path_list_pool_size());
1372     FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1373              fib_entry_pool_size());
1374
1375     /*
1376      * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1377      * The paths are sort by NH first. in this case the the path with greater
1378      * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1379      */
1380     fib_prefix_t pfx_1_2_3_4_s_32 = {
1381         .fp_len = 32,
1382         .fp_proto = FIB_PROTOCOL_IP4,
1383         .fp_addr = {
1384             .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1385         },
1386     };
1387     fib_table_entry_path_add(fib_index,
1388                              &pfx_1_2_3_4_s_32,
1389                              FIB_SOURCE_API,
1390                              FIB_ENTRY_FLAG_NONE,
1391                              FIB_PROTOCOL_IP4,
1392                              &nh_10_10_10_1,
1393                              tm->hw[0]->sw_if_index,
1394                              ~0,
1395                              1,
1396                              NULL,
1397                              FIB_ROUTE_PATH_FLAG_NONE);
1398     fei = fib_table_entry_path_add(fib_index,
1399                                    &pfx_1_2_3_4_s_32,
1400                                    FIB_SOURCE_API,
1401                                    FIB_ENTRY_FLAG_NONE,
1402                                    FIB_PROTOCOL_IP4,
1403                                    &nh_12_12_12_12,
1404                                    tm->hw[1]->sw_if_index,
1405                                    ~0,
1406                                    3,
1407                                    NULL,
1408                                    FIB_ROUTE_PATH_FLAG_NONE);
1409
1410     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1411     dpo = fib_entry_contribute_ip_forwarding(fei);
1412     lb = load_balance_get(dpo->dpoi_index);
1413     FIB_TEST((lb->lb_n_buckets == 4),
1414              "1.2.3.4/32 LB has %d bucket",
1415              lb->lb_n_buckets);
1416
1417     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1418     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1419     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1420     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1421
1422     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1423                                     tm->hw[0]->sw_if_index,
1424                                     tm->hw[1]->sw_if_index),
1425              "RPF list for 1.2.3.4/32 contains both adjs");
1426
1427
1428     /*
1429      * Unequal Cost load-balance. 4:1 ratio.
1430      *  fits in a 16 bucket LB with ratio 13:3
1431      */
1432     fib_prefix_t pfx_1_2_3_5_s_32 = {
1433         .fp_len = 32,
1434         .fp_proto = FIB_PROTOCOL_IP4,
1435         .fp_addr = {
1436             .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1437         },
1438     };
1439     fib_table_entry_path_add(fib_index,
1440                              &pfx_1_2_3_5_s_32,
1441                              FIB_SOURCE_API,
1442                              FIB_ENTRY_FLAG_NONE,
1443                              FIB_PROTOCOL_IP4,
1444                              &nh_12_12_12_12,
1445                              tm->hw[1]->sw_if_index,
1446                              ~0,
1447                              1,
1448                              NULL,
1449                              FIB_ROUTE_PATH_FLAG_NONE);
1450     fei = fib_table_entry_path_add(fib_index,
1451                                    &pfx_1_2_3_5_s_32,
1452                                    FIB_SOURCE_API,
1453                                    FIB_ENTRY_FLAG_NONE,
1454                                    FIB_PROTOCOL_IP4,
1455                                    &nh_10_10_10_1,
1456                                    tm->hw[0]->sw_if_index,
1457                                    ~0,
1458                                    4,
1459                                    NULL,
1460                                    FIB_ROUTE_PATH_FLAG_NONE);
1461
1462     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1463     dpo = fib_entry_contribute_ip_forwarding(fei);
1464     lb = load_balance_get(dpo->dpoi_index);
1465     FIB_TEST((lb->lb_n_buckets == 16),
1466              "1.2.3.5/32 LB has %d bucket",
1467              lb->lb_n_buckets);
1468
1469     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1470     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1471     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1472     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1473     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1474     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1475     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1476     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1477     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1478     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1479     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1480     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1481     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1482     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1483     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1484     FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1485
1486     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1487                                     tm->hw[0]->sw_if_index,
1488                                     tm->hw[1]->sw_if_index),
1489              "RPF list for 1.2.3.4/32 contains both adjs");
1490
1491     /*
1492      * Test UCMP with a large weight skew - this produces load-balance objects with large
1493      * numbers of buckets to accommodate the skew. By updating said load-balances we are
1494      * laso testing the LB in placce modify code when number of buckets is large.
1495      */
1496     fib_prefix_t pfx_6_6_6_6_s_32 = {
1497         .fp_len = 32,
1498         .fp_proto = FIB_PROTOCOL_IP4,
1499         .fp_addr = {
1500             /* 1.1.1.1/32 */
1501             .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1502         },
1503     };
1504     fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_1 = {
1505         .type = FT_LB_ADJ,
1506         .adj = {
1507             .adj = ai_01,
1508         },
1509     };
1510     fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_2 = {
1511         .type = FT_LB_ADJ,
1512         .adj = {
1513             .adj = ai_02,
1514         },
1515     };
1516     fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1517         .type = FT_LB_ADJ,
1518         .adj = {
1519             .adj = ai_12_12_12_12,
1520         },
1521     };
1522     fib_table_entry_update_one_path(fib_index,
1523                                     &pfx_6_6_6_6_s_32,
1524                                     FIB_SOURCE_API,
1525                                     FIB_ENTRY_FLAG_NONE,
1526                                     FIB_PROTOCOL_IP4,
1527                                     &nh_10_10_10_1,
1528                                     tm->hw[0]->sw_if_index,
1529                                     ~0, // invalid fib index
1530                                     0,  // zero weigth
1531                                     NULL,
1532                                     FIB_ROUTE_PATH_FLAG_NONE);
1533
1534     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1535     FIB_TEST(fib_test_validate_entry(fei,
1536                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1537                                      1,
1538                                      &ip_6_6_6_6_o_10_10_10_1),
1539              "6.6.6.6/32 via 10.10.10.1");
1540
1541     fib_table_entry_path_add(fib_index,
1542                              &pfx_6_6_6_6_s_32,
1543                              FIB_SOURCE_API,
1544                              FIB_ENTRY_FLAG_NONE,
1545                              FIB_PROTOCOL_IP4,
1546                              &nh_10_10_10_2,
1547                              tm->hw[0]->sw_if_index,
1548                              ~0, // invalid fib index
1549                              100,
1550                              NULL,
1551                              FIB_ROUTE_PATH_FLAG_NONE);
1552
1553     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1554     FIB_TEST(fib_test_validate_entry(fei,
1555                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1556                                      64,
1557                                      &ip_6_6_6_6_o_10_10_10_2,
1558                                      &ip_6_6_6_6_o_10_10_10_2,
1559                                      &ip_6_6_6_6_o_10_10_10_2,
1560                                      &ip_6_6_6_6_o_10_10_10_2,
1561                                      &ip_6_6_6_6_o_10_10_10_2,
1562                                      &ip_6_6_6_6_o_10_10_10_2,
1563                                      &ip_6_6_6_6_o_10_10_10_2,
1564                                      &ip_6_6_6_6_o_10_10_10_2,
1565                                      &ip_6_6_6_6_o_10_10_10_2,
1566                                      &ip_6_6_6_6_o_10_10_10_2,
1567                                      &ip_6_6_6_6_o_10_10_10_2,
1568                                      &ip_6_6_6_6_o_10_10_10_2,
1569                                      &ip_6_6_6_6_o_10_10_10_2,
1570                                      &ip_6_6_6_6_o_10_10_10_2,
1571                                      &ip_6_6_6_6_o_10_10_10_2,
1572                                      &ip_6_6_6_6_o_10_10_10_2,
1573                                      &ip_6_6_6_6_o_10_10_10_2,
1574                                      &ip_6_6_6_6_o_10_10_10_2,
1575                                      &ip_6_6_6_6_o_10_10_10_2,
1576                                      &ip_6_6_6_6_o_10_10_10_2,
1577                                      &ip_6_6_6_6_o_10_10_10_2,
1578                                      &ip_6_6_6_6_o_10_10_10_2,
1579                                      &ip_6_6_6_6_o_10_10_10_2,
1580                                      &ip_6_6_6_6_o_10_10_10_2,
1581                                      &ip_6_6_6_6_o_10_10_10_2,
1582                                      &ip_6_6_6_6_o_10_10_10_2,
1583                                      &ip_6_6_6_6_o_10_10_10_2,
1584                                      &ip_6_6_6_6_o_10_10_10_2,
1585                                      &ip_6_6_6_6_o_10_10_10_2,
1586                                      &ip_6_6_6_6_o_10_10_10_2,
1587                                      &ip_6_6_6_6_o_10_10_10_2,
1588                                      &ip_6_6_6_6_o_10_10_10_2,
1589                                      &ip_6_6_6_6_o_10_10_10_2,
1590                                      &ip_6_6_6_6_o_10_10_10_2,
1591                                      &ip_6_6_6_6_o_10_10_10_2,
1592                                      &ip_6_6_6_6_o_10_10_10_2,
1593                                      &ip_6_6_6_6_o_10_10_10_2,
1594                                      &ip_6_6_6_6_o_10_10_10_2,
1595                                      &ip_6_6_6_6_o_10_10_10_2,
1596                                      &ip_6_6_6_6_o_10_10_10_2,
1597                                      &ip_6_6_6_6_o_10_10_10_2,
1598                                      &ip_6_6_6_6_o_10_10_10_2,
1599                                      &ip_6_6_6_6_o_10_10_10_2,
1600                                      &ip_6_6_6_6_o_10_10_10_2,
1601                                      &ip_6_6_6_6_o_10_10_10_2,
1602                                      &ip_6_6_6_6_o_10_10_10_2,
1603                                      &ip_6_6_6_6_o_10_10_10_2,
1604                                      &ip_6_6_6_6_o_10_10_10_2,
1605                                      &ip_6_6_6_6_o_10_10_10_2,
1606                                      &ip_6_6_6_6_o_10_10_10_2,
1607                                      &ip_6_6_6_6_o_10_10_10_2,
1608                                      &ip_6_6_6_6_o_10_10_10_2,
1609                                      &ip_6_6_6_6_o_10_10_10_2,
1610                                      &ip_6_6_6_6_o_10_10_10_2,
1611                                      &ip_6_6_6_6_o_10_10_10_2,
1612                                      &ip_6_6_6_6_o_10_10_10_2,
1613                                      &ip_6_6_6_6_o_10_10_10_2,
1614                                      &ip_6_6_6_6_o_10_10_10_2,
1615                                      &ip_6_6_6_6_o_10_10_10_2,
1616                                      &ip_6_6_6_6_o_10_10_10_2,
1617                                      &ip_6_6_6_6_o_10_10_10_2,
1618                                      &ip_6_6_6_6_o_10_10_10_2,
1619                                      &ip_6_6_6_6_o_10_10_10_2,
1620                                      &ip_6_6_6_6_o_10_10_10_1),
1621              "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1622
1623     fib_table_entry_path_add(fib_index,
1624                              &pfx_6_6_6_6_s_32,
1625                              FIB_SOURCE_API,
1626                              FIB_ENTRY_FLAG_NONE,
1627                              FIB_PROTOCOL_IP4,
1628                              &nh_12_12_12_12,
1629                              tm->hw[1]->sw_if_index,
1630                              ~0, // invalid fib index
1631                              100,
1632                              NULL,
1633                              FIB_ROUTE_PATH_FLAG_NONE);
1634
1635     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1636     FIB_TEST(fib_test_validate_entry(fei,
1637                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1638                                      128,
1639                                      &ip_6_6_6_6_o_10_10_10_1,
1640                                      &ip_6_6_6_6_o_10_10_10_2,
1641                                      &ip_6_6_6_6_o_10_10_10_2,
1642                                      &ip_6_6_6_6_o_10_10_10_2,
1643                                      &ip_6_6_6_6_o_10_10_10_2,
1644                                      &ip_6_6_6_6_o_10_10_10_2,
1645                                      &ip_6_6_6_6_o_10_10_10_2,
1646                                      &ip_6_6_6_6_o_10_10_10_2,
1647                                      &ip_6_6_6_6_o_10_10_10_2,
1648                                      &ip_6_6_6_6_o_10_10_10_2,
1649                                      &ip_6_6_6_6_o_10_10_10_2,
1650                                      &ip_6_6_6_6_o_10_10_10_2,
1651                                      &ip_6_6_6_6_o_10_10_10_2,
1652                                      &ip_6_6_6_6_o_10_10_10_2,
1653                                      &ip_6_6_6_6_o_10_10_10_2,
1654                                      &ip_6_6_6_6_o_10_10_10_2,
1655                                      &ip_6_6_6_6_o_10_10_10_2,
1656                                      &ip_6_6_6_6_o_10_10_10_2,
1657                                      &ip_6_6_6_6_o_10_10_10_2,
1658                                      &ip_6_6_6_6_o_10_10_10_2,
1659                                      &ip_6_6_6_6_o_10_10_10_2,
1660                                      &ip_6_6_6_6_o_10_10_10_2,
1661                                      &ip_6_6_6_6_o_10_10_10_2,
1662                                      &ip_6_6_6_6_o_10_10_10_2,
1663                                      &ip_6_6_6_6_o_10_10_10_2,
1664                                      &ip_6_6_6_6_o_10_10_10_2,
1665                                      &ip_6_6_6_6_o_10_10_10_2,
1666                                      &ip_6_6_6_6_o_10_10_10_2,
1667                                      &ip_6_6_6_6_o_10_10_10_2,
1668                                      &ip_6_6_6_6_o_10_10_10_2,
1669                                      &ip_6_6_6_6_o_10_10_10_2,
1670                                      &ip_6_6_6_6_o_10_10_10_2,
1671                                      &ip_6_6_6_6_o_10_10_10_2,
1672                                      &ip_6_6_6_6_o_10_10_10_2,
1673                                      &ip_6_6_6_6_o_10_10_10_2,
1674                                      &ip_6_6_6_6_o_10_10_10_2,
1675                                      &ip_6_6_6_6_o_10_10_10_2,
1676                                      &ip_6_6_6_6_o_10_10_10_2,
1677                                      &ip_6_6_6_6_o_10_10_10_2,
1678                                      &ip_6_6_6_6_o_10_10_10_2,
1679                                      &ip_6_6_6_6_o_10_10_10_2,
1680                                      &ip_6_6_6_6_o_10_10_10_2,
1681                                      &ip_6_6_6_6_o_10_10_10_2,
1682                                      &ip_6_6_6_6_o_10_10_10_2,
1683                                      &ip_6_6_6_6_o_10_10_10_2,
1684                                      &ip_6_6_6_6_o_10_10_10_2,
1685                                      &ip_6_6_6_6_o_10_10_10_2,
1686                                      &ip_6_6_6_6_o_10_10_10_2,
1687                                      &ip_6_6_6_6_o_10_10_10_2,
1688                                      &ip_6_6_6_6_o_10_10_10_2,
1689                                      &ip_6_6_6_6_o_10_10_10_2,
1690                                      &ip_6_6_6_6_o_10_10_10_2,
1691                                      &ip_6_6_6_6_o_10_10_10_2,
1692                                      &ip_6_6_6_6_o_10_10_10_2,
1693                                      &ip_6_6_6_6_o_10_10_10_2,
1694                                      &ip_6_6_6_6_o_10_10_10_2,
1695                                      &ip_6_6_6_6_o_10_10_10_2,
1696                                      &ip_6_6_6_6_o_10_10_10_2,
1697                                      &ip_6_6_6_6_o_10_10_10_2,
1698                                      &ip_6_6_6_6_o_10_10_10_2,
1699                                      &ip_6_6_6_6_o_10_10_10_2,
1700                                      &ip_6_6_6_6_o_10_10_10_2,
1701                                      &ip_6_6_6_6_o_10_10_10_2,
1702                                      &ip_6_6_6_6_o_10_10_10_2,
1703                                      &ip_6_6_6_6_o_10_10_10_2,
1704                                      &ip_6_6_6_6_o_12_12_12_12,
1705                                      &ip_6_6_6_6_o_12_12_12_12,
1706                                      &ip_6_6_6_6_o_12_12_12_12,
1707                                      &ip_6_6_6_6_o_12_12_12_12,
1708                                      &ip_6_6_6_6_o_12_12_12_12,
1709                                      &ip_6_6_6_6_o_12_12_12_12,
1710                                      &ip_6_6_6_6_o_12_12_12_12,
1711                                      &ip_6_6_6_6_o_12_12_12_12,
1712                                      &ip_6_6_6_6_o_12_12_12_12,
1713                                      &ip_6_6_6_6_o_12_12_12_12,
1714                                      &ip_6_6_6_6_o_12_12_12_12,
1715                                      &ip_6_6_6_6_o_12_12_12_12,
1716                                      &ip_6_6_6_6_o_12_12_12_12,
1717                                      &ip_6_6_6_6_o_12_12_12_12,
1718                                      &ip_6_6_6_6_o_12_12_12_12,
1719                                      &ip_6_6_6_6_o_12_12_12_12,
1720                                      &ip_6_6_6_6_o_12_12_12_12,
1721                                      &ip_6_6_6_6_o_12_12_12_12,
1722                                      &ip_6_6_6_6_o_12_12_12_12,
1723                                      &ip_6_6_6_6_o_12_12_12_12,
1724                                      &ip_6_6_6_6_o_12_12_12_12,
1725                                      &ip_6_6_6_6_o_12_12_12_12,
1726                                      &ip_6_6_6_6_o_12_12_12_12,
1727                                      &ip_6_6_6_6_o_12_12_12_12,
1728                                      &ip_6_6_6_6_o_12_12_12_12,
1729                                      &ip_6_6_6_6_o_12_12_12_12,
1730                                      &ip_6_6_6_6_o_12_12_12_12,
1731                                      &ip_6_6_6_6_o_12_12_12_12,
1732                                      &ip_6_6_6_6_o_12_12_12_12,
1733                                      &ip_6_6_6_6_o_12_12_12_12,
1734                                      &ip_6_6_6_6_o_12_12_12_12,
1735                                      &ip_6_6_6_6_o_12_12_12_12,
1736                                      &ip_6_6_6_6_o_12_12_12_12,
1737                                      &ip_6_6_6_6_o_12_12_12_12,
1738                                      &ip_6_6_6_6_o_12_12_12_12,
1739                                      &ip_6_6_6_6_o_12_12_12_12,
1740                                      &ip_6_6_6_6_o_12_12_12_12,
1741                                      &ip_6_6_6_6_o_12_12_12_12,
1742                                      &ip_6_6_6_6_o_12_12_12_12,
1743                                      &ip_6_6_6_6_o_12_12_12_12,
1744                                      &ip_6_6_6_6_o_12_12_12_12,
1745                                      &ip_6_6_6_6_o_12_12_12_12,
1746                                      &ip_6_6_6_6_o_12_12_12_12,
1747                                      &ip_6_6_6_6_o_12_12_12_12,
1748                                      &ip_6_6_6_6_o_12_12_12_12,
1749                                      &ip_6_6_6_6_o_12_12_12_12,
1750                                      &ip_6_6_6_6_o_12_12_12_12,
1751                                      &ip_6_6_6_6_o_12_12_12_12,
1752                                      &ip_6_6_6_6_o_12_12_12_12,
1753                                      &ip_6_6_6_6_o_12_12_12_12,
1754                                      &ip_6_6_6_6_o_12_12_12_12,
1755                                      &ip_6_6_6_6_o_12_12_12_12,
1756                                      &ip_6_6_6_6_o_12_12_12_12,
1757                                      &ip_6_6_6_6_o_12_12_12_12,
1758                                      &ip_6_6_6_6_o_12_12_12_12,
1759                                      &ip_6_6_6_6_o_12_12_12_12,
1760                                      &ip_6_6_6_6_o_12_12_12_12,
1761                                      &ip_6_6_6_6_o_12_12_12_12,
1762                                      &ip_6_6_6_6_o_12_12_12_12,
1763                                      &ip_6_6_6_6_o_12_12_12_12,
1764                                      &ip_6_6_6_6_o_12_12_12_12,
1765                                      &ip_6_6_6_6_o_12_12_12_12,
1766                                      &ip_6_6_6_6_o_12_12_12_12),
1767              "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1768
1769     fib_table_entry_path_remove(fib_index,
1770                                 &pfx_6_6_6_6_s_32,
1771                                 FIB_SOURCE_API,
1772                                 FIB_PROTOCOL_IP4,
1773                                 &nh_12_12_12_12,
1774                                 tm->hw[1]->sw_if_index,
1775                                 ~0, // invalid fib index
1776                                 100,
1777                                 FIB_ROUTE_PATH_FLAG_NONE);
1778
1779     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1780     FIB_TEST(fib_test_validate_entry(fei,
1781                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1782                                      64,
1783                                      &ip_6_6_6_6_o_10_10_10_2,
1784                                      &ip_6_6_6_6_o_10_10_10_2,
1785                                      &ip_6_6_6_6_o_10_10_10_2,
1786                                      &ip_6_6_6_6_o_10_10_10_2,
1787                                      &ip_6_6_6_6_o_10_10_10_2,
1788                                      &ip_6_6_6_6_o_10_10_10_2,
1789                                      &ip_6_6_6_6_o_10_10_10_2,
1790                                      &ip_6_6_6_6_o_10_10_10_2,
1791                                      &ip_6_6_6_6_o_10_10_10_2,
1792                                      &ip_6_6_6_6_o_10_10_10_2,
1793                                      &ip_6_6_6_6_o_10_10_10_2,
1794                                      &ip_6_6_6_6_o_10_10_10_2,
1795                                      &ip_6_6_6_6_o_10_10_10_2,
1796                                      &ip_6_6_6_6_o_10_10_10_2,
1797                                      &ip_6_6_6_6_o_10_10_10_2,
1798                                      &ip_6_6_6_6_o_10_10_10_2,
1799                                      &ip_6_6_6_6_o_10_10_10_2,
1800                                      &ip_6_6_6_6_o_10_10_10_2,
1801                                      &ip_6_6_6_6_o_10_10_10_2,
1802                                      &ip_6_6_6_6_o_10_10_10_2,
1803                                      &ip_6_6_6_6_o_10_10_10_2,
1804                                      &ip_6_6_6_6_o_10_10_10_2,
1805                                      &ip_6_6_6_6_o_10_10_10_2,
1806                                      &ip_6_6_6_6_o_10_10_10_2,
1807                                      &ip_6_6_6_6_o_10_10_10_2,
1808                                      &ip_6_6_6_6_o_10_10_10_2,
1809                                      &ip_6_6_6_6_o_10_10_10_2,
1810                                      &ip_6_6_6_6_o_10_10_10_2,
1811                                      &ip_6_6_6_6_o_10_10_10_2,
1812                                      &ip_6_6_6_6_o_10_10_10_2,
1813                                      &ip_6_6_6_6_o_10_10_10_2,
1814                                      &ip_6_6_6_6_o_10_10_10_2,
1815                                      &ip_6_6_6_6_o_10_10_10_2,
1816                                      &ip_6_6_6_6_o_10_10_10_2,
1817                                      &ip_6_6_6_6_o_10_10_10_2,
1818                                      &ip_6_6_6_6_o_10_10_10_2,
1819                                      &ip_6_6_6_6_o_10_10_10_2,
1820                                      &ip_6_6_6_6_o_10_10_10_2,
1821                                      &ip_6_6_6_6_o_10_10_10_2,
1822                                      &ip_6_6_6_6_o_10_10_10_2,
1823                                      &ip_6_6_6_6_o_10_10_10_2,
1824                                      &ip_6_6_6_6_o_10_10_10_2,
1825                                      &ip_6_6_6_6_o_10_10_10_2,
1826                                      &ip_6_6_6_6_o_10_10_10_2,
1827                                      &ip_6_6_6_6_o_10_10_10_2,
1828                                      &ip_6_6_6_6_o_10_10_10_2,
1829                                      &ip_6_6_6_6_o_10_10_10_2,
1830                                      &ip_6_6_6_6_o_10_10_10_2,
1831                                      &ip_6_6_6_6_o_10_10_10_2,
1832                                      &ip_6_6_6_6_o_10_10_10_2,
1833                                      &ip_6_6_6_6_o_10_10_10_2,
1834                                      &ip_6_6_6_6_o_10_10_10_2,
1835                                      &ip_6_6_6_6_o_10_10_10_2,
1836                                      &ip_6_6_6_6_o_10_10_10_2,
1837                                      &ip_6_6_6_6_o_10_10_10_2,
1838                                      &ip_6_6_6_6_o_10_10_10_2,
1839                                      &ip_6_6_6_6_o_10_10_10_2,
1840                                      &ip_6_6_6_6_o_10_10_10_2,
1841                                      &ip_6_6_6_6_o_10_10_10_2,
1842                                      &ip_6_6_6_6_o_10_10_10_2,
1843                                      &ip_6_6_6_6_o_10_10_10_2,
1844                                      &ip_6_6_6_6_o_10_10_10_2,
1845                                      &ip_6_6_6_6_o_10_10_10_2,
1846                                      &ip_6_6_6_6_o_10_10_10_1),
1847              "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1848
1849     fib_table_entry_path_remove(fib_index,
1850                                 &pfx_6_6_6_6_s_32,
1851                                 FIB_SOURCE_API,
1852                                 FIB_PROTOCOL_IP4,
1853                                 &nh_10_10_10_2,
1854                                 tm->hw[0]->sw_if_index,
1855                                 ~0, // invalid fib index
1856                                 100,
1857                                 FIB_ROUTE_PATH_FLAG_NONE);
1858
1859     fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1860     FIB_TEST(fib_test_validate_entry(fei,
1861                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1862                                      1,
1863                                      &ip_6_6_6_6_o_10_10_10_1),
1864              "6.6.6.6/32 via 10.10.10.1");
1865
1866     fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
1867
1868     /*
1869      * A recursive via the two unequal cost entries
1870      */
1871     fib_prefix_t bgp_44_s_32 = {
1872         .fp_len = 32,
1873         .fp_proto = FIB_PROTOCOL_IP4,
1874         .fp_addr = {
1875             /* 200.200.200.201/32 */
1876             .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1877         },
1878     };
1879     fei = fib_table_entry_path_add(fib_index,
1880                                    &bgp_44_s_32,
1881                                    FIB_SOURCE_API,
1882                                    FIB_ENTRY_FLAG_NONE,
1883                                    FIB_PROTOCOL_IP4,
1884                                    &pfx_1_2_3_4_s_32.fp_addr,
1885                                    ~0,
1886                                    fib_index,
1887                                    1,
1888                                    NULL,
1889                                    FIB_ROUTE_PATH_FLAG_NONE);
1890     fei = fib_table_entry_path_add(fib_index,
1891                                    &bgp_44_s_32,
1892                                    FIB_SOURCE_API,
1893                                    FIB_ENTRY_FLAG_NONE,
1894                                    FIB_PROTOCOL_IP4,
1895                                    &pfx_1_2_3_5_s_32.fp_addr,
1896                                    ~0,
1897                                    fib_index,
1898                                    1,
1899                                    NULL,
1900                                    FIB_ROUTE_PATH_FLAG_NONE);
1901
1902     FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1903     FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1904     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1905                                     tm->hw[0]->sw_if_index,
1906                                     tm->hw[1]->sw_if_index),
1907              "RPF list for 1.2.3.4/32 contains both adjs");
1908
1909     /*
1910      * test the uRPF check functions
1911      */
1912     dpo_id_t dpo_44 = DPO_INVALID;
1913     index_t urpfi;
1914
1915     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1916     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
1917
1918     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
1919              "uRPF check for 68.68.68.68/32 on %d OK",
1920              tm->hw[0]->sw_if_index);
1921     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
1922              "uRPF check for 68.68.68.68/32 on %d OK",
1923              tm->hw[1]->sw_if_index);
1924     FIB_TEST(!fib_urpf_check(urpfi, 99),
1925              "uRPF check for 68.68.68.68/32 on 99 not-OK",
1926              99);
1927     dpo_reset(&dpo_44);
1928
1929     fib_table_entry_delete(fib_index,
1930                            &bgp_44_s_32,
1931                            FIB_SOURCE_API);
1932     fib_table_entry_delete(fib_index,
1933                            &pfx_1_2_3_5_s_32,
1934                            FIB_SOURCE_API);
1935     fib_table_entry_delete(fib_index,
1936                            &pfx_1_2_3_4_s_32,
1937                            FIB_SOURCE_API);
1938
1939     /*
1940      * Add a recursive route:
1941      *   200.200.200.201/32 via 1.1.1.200/32  => the via entry is NOT installed.
1942      */
1943     fib_prefix_t bgp_201_pfx = {
1944         .fp_len = 32,
1945         .fp_proto = FIB_PROTOCOL_IP4,
1946         .fp_addr = {
1947             /* 200.200.200.201/32 */
1948             .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1949         },
1950     };
1951     /* via 1.1.1.200 */
1952     fib_prefix_t pfx_1_1_1_200_s_32 = {
1953         .fp_len = 32,
1954         .fp_proto = FIB_PROTOCOL_IP4,
1955         .fp_addr = {
1956             .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1957         },
1958     };
1959
1960     fib_table_entry_path_add(fib_index,
1961                              &bgp_201_pfx,
1962                              FIB_SOURCE_API,
1963                              FIB_ENTRY_FLAG_NONE,
1964                              FIB_PROTOCOL_IP4,
1965                              &pfx_1_1_1_200_s_32.fp_addr,
1966                              ~0, // no index provided.
1967                              fib_index, // nexthop in same fib as route
1968                              1,
1969                              NULL,
1970                              FIB_ROUTE_PATH_FLAG_NONE);
1971
1972     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1973
1974     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1975     FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1976              "Flags set on RR via non-attached");
1977     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1978              "RPF list for BGP route empty");
1979
1980     /*
1981      * +2 entry (BGP & RR) and +1 shared-path-list
1982      */
1983     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
1984              fib_path_list_db_size());
1985     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1986              fib_path_list_pool_size());
1987     FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1988              fib_entry_pool_size());
1989
1990     /*
1991      * insert a route that covers the missing 1.1.1.2/32. we epxect
1992      * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
1993      */
1994     fib_prefix_t pfx_1_1_1_0_s_24 = {
1995         .fp_len = 24,
1996         .fp_proto = FIB_PROTOCOL_IP4,
1997         .fp_addr = {
1998             /* 1.1.1.0/24 */
1999             .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2000         },
2001     };
2002
2003     fib_table_entry_path_add(fib_index,
2004                              &pfx_1_1_1_0_s_24,
2005                              FIB_SOURCE_API,
2006                              FIB_ENTRY_FLAG_NONE,
2007                              FIB_PROTOCOL_IP4,
2008                              &nh_10_10_10_1,
2009                              tm->hw[0]->sw_if_index,
2010                              ~0, // invalid fib index
2011                              1,
2012                              NULL,
2013                              FIB_ROUTE_PATH_FLAG_NONE);
2014     fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2015     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2016     ai = fib_entry_get_adj(fei);
2017     FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2018     fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2019     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2020     ai = fib_entry_get_adj(fei);
2021     FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2022     fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2023     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2024     ai = fib_entry_get_adj(fei);
2025     FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2026
2027     /*
2028      * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2029      */
2030     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
2031              fib_path_list_db_size());
2032     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2033              fib_path_list_pool_size());
2034     FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2035              fib_entry_pool_size());
2036
2037     /*
2038      * the recursive adj for 200.200.200.200 should be updated.
2039      */
2040     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2041     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2042     fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2043     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2044                                     tm->hw[0]->sw_if_index),
2045              "RPF list for BGP route has itf index 0");
2046
2047     /*
2048      * insert a more specific route than 1.1.1.0/24 that also covers the
2049      * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2050      * 200.200.200.200 to resolve through it.
2051      */
2052     fib_prefix_t pfx_1_1_1_0_s_28 = {
2053         .fp_len = 28,
2054         .fp_proto = FIB_PROTOCOL_IP4,
2055         .fp_addr = {
2056             /* 1.1.1.0/24 */
2057             .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2058         },
2059     };
2060
2061     fib_table_entry_path_add(fib_index,
2062                              &pfx_1_1_1_0_s_28,
2063                              FIB_SOURCE_API,
2064                              FIB_ENTRY_FLAG_NONE,
2065                              FIB_PROTOCOL_IP4,
2066                              &nh_10_10_10_2,
2067                              tm->hw[0]->sw_if_index,
2068                              ~0, // invalid fib index
2069                              1,
2070                              NULL,
2071                              FIB_ROUTE_PATH_FLAG_NONE);
2072     fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2073     dpo2 = fib_entry_contribute_ip_forwarding(fei);
2074     ai = fib_entry_get_adj(fei);
2075     FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2076
2077     /*
2078      * +1 entry. +1 shared path-list
2079      */
2080     FIB_TEST((5  == fib_path_list_db_size()),   "path list DB population:%d",
2081              fib_path_list_db_size());
2082     FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2083              fib_path_list_pool_size());
2084     FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2085              fib_entry_pool_size());
2086
2087     /*
2088      * the recursive adj for 200.200.200.200 should be updated.
2089      * 200.200.200.201 remains unchanged.
2090      */
2091     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2092     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2093
2094     /*
2095      * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2096      */
2097     fib_table_entry_path_remove(fib_index,
2098                                 &pfx_1_1_1_0_s_28,
2099                                 FIB_SOURCE_API,
2100                                 FIB_PROTOCOL_IP4,
2101                                 &nh_10_10_10_2,
2102                                 tm->hw[0]->sw_if_index,
2103                                 ~0,
2104                                 1,
2105                                 FIB_ROUTE_PATH_FLAG_NONE);
2106     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) == 
2107               FIB_NODE_INDEX_INVALID),
2108              "1.1.1.0/28 removed");
2109     FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) == 
2110               fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2111              "1.1.1.0/28 lookup via /24");
2112     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2113     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2114
2115     /*
2116      * -1 entry. -1 shared path-list
2117      */
2118     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
2119              fib_path_list_db_size());
2120     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2121              fib_path_list_pool_size());
2122     FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2123              fib_entry_pool_size());
2124
2125     /*
2126      * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2127      */
2128     fib_table_entry_path_remove(fib_index,
2129                                 &pfx_1_1_1_0_s_24,
2130                                 FIB_SOURCE_API,
2131                                 FIB_PROTOCOL_IP4,
2132                                 &nh_10_10_10_1,
2133                                 tm->hw[0]->sw_if_index,
2134                                 ~0,
2135                                 1,
2136                                 FIB_ROUTE_PATH_FLAG_NONE);
2137     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) == 
2138               FIB_NODE_INDEX_INVALID),
2139              "1.1.1.0/24 removed");
2140
2141     fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2142     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2143              "1.1.1.2/32 route is DROP");
2144     fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2145     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2146              "1.1.1.200/32 route is DROP");
2147
2148     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2149     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2150
2151     /*
2152      * -1 entry
2153      */
2154     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
2155         fib_path_list_db_size());
2156     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2157         fib_path_list_pool_size());
2158     FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2159              fib_entry_pool_size());
2160
2161     /*
2162      * insert the missing 1.1.1.2/32
2163      */
2164     fei = fib_table_entry_path_add(fib_index,
2165                                    &pfx_1_1_1_2_s_32,
2166                                    FIB_SOURCE_API,
2167                                    FIB_ENTRY_FLAG_NONE,
2168                                    FIB_PROTOCOL_IP4,
2169                                    &nh_10_10_10_1,
2170                                    tm->hw[0]->sw_if_index,
2171                                    ~0, // invalid fib index
2172                                    1,
2173                                    NULL,
2174                                    FIB_ROUTE_PATH_FLAG_NONE);
2175     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2176     ai = fib_entry_get_adj(fei);
2177     FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2178
2179     FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2180     FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2181
2182     /*
2183      * no change. 1.1.1.2/32 was already there RR sourced.
2184      */
2185     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
2186              fib_path_list_db_size());
2187     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2188              fib_path_list_pool_size());
2189     FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2190              fib_entry_pool_size());
2191
2192     /*
2193      * remove 200.200.200.201/32 which does not have a valid via FIB
2194      */
2195     fib_table_entry_path_remove(fib_index,
2196                                 &bgp_201_pfx,
2197                                 FIB_SOURCE_API,
2198                                 FIB_PROTOCOL_IP4,
2199                                 &pfx_1_1_1_200_s_32.fp_addr,
2200                                 ~0, // no index provided.
2201                                 fib_index,
2202                                 1,
2203                                 FIB_ROUTE_PATH_FLAG_NONE);
2204
2205     /*
2206      * -2 entries (BGP and RR). -1 shared path-list;
2207      */
2208     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) == 
2209               FIB_NODE_INDEX_INVALID),
2210              "200.200.200.201/32 removed");
2211     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) == 
2212               FIB_NODE_INDEX_INVALID),
2213              "1.1.1.200/32 removed");
2214
2215     FIB_TEST((3  == fib_path_list_db_size()),   "path list DB population:%d",
2216              fib_path_list_db_size());
2217     FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2218              fib_path_list_pool_size());
2219     FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2220              fib_entry_pool_size());
2221
2222     /*
2223      * remove 200.200.200.200/32 which does have a valid via FIB
2224      */
2225     fib_table_entry_path_remove(fib_index,
2226                                 &bgp_200_pfx,
2227                                 FIB_SOURCE_API,
2228                                 FIB_PROTOCOL_IP4,
2229                                 &pfx_1_1_1_2_s_32.fp_addr,
2230                                 ~0, // no index provided.
2231                                 fib_index,
2232                                 1,
2233                                 FIB_ROUTE_PATH_FLAG_NONE);
2234
2235     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) == 
2236               FIB_NODE_INDEX_INVALID),
2237              "200.200.200.200/32 removed");
2238     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) != 
2239               FIB_NODE_INDEX_INVALID),
2240              "1.1.1.2/32 still present");
2241
2242     /*
2243      * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2244      */
2245     FIB_TEST((2  == fib_path_list_db_size()),   "path list DB population:%d",
2246              fib_path_list_db_size());
2247     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2248              fib_path_list_pool_size());
2249     FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2250              fib_entry_pool_size());
2251
2252     /*
2253      * A recursive prefix that has a 2 path  load-balance.
2254      * It also shares a next-hop with other BGP prefixes and hence
2255      * test the ref counting of RR sourced prefixes and 2 level LB.
2256      */
2257     const fib_prefix_t bgp_102 = {
2258         .fp_len = 32,
2259         .fp_proto = FIB_PROTOCOL_IP4,
2260         .fp_addr = {
2261             /* 100.100.100.101/32 */
2262             .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2263         },
2264     };
2265     fib_table_entry_path_add(fib_index,
2266                              &bgp_102,
2267                              FIB_SOURCE_API,
2268                              FIB_ENTRY_FLAG_NONE,
2269                              FIB_PROTOCOL_IP4,
2270                              &pfx_1_1_1_1_s_32.fp_addr,
2271                              ~0, // no index provided.
2272                              fib_index, // same as route
2273                              1,
2274                              NULL,
2275                              FIB_ROUTE_PATH_FLAG_NONE);
2276     fib_table_entry_path_add(fib_index,
2277                              &bgp_102,
2278                              FIB_SOURCE_API,
2279                              FIB_ENTRY_FLAG_NONE,
2280                              FIB_PROTOCOL_IP4,
2281                              &pfx_1_1_1_2_s_32.fp_addr,
2282                              ~0, // no index provided.
2283                              fib_index, // same as route's FIB
2284                              1,
2285                              NULL,
2286                              FIB_ROUTE_PATH_FLAG_NONE);
2287     fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2288     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2289     dpo = fib_entry_contribute_ip_forwarding(fei);
2290
2291     fei  = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2292     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2293     fei  = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2294     dpo2 = fib_entry_contribute_ip_forwarding(fei);
2295
2296     lb = load_balance_get(dpo->dpoi_index);
2297     FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2298     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2299              "First via 10.10.10.1");
2300     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2301              "Second via 10.10.10.1");
2302
2303     fib_table_entry_path_remove(fib_index,
2304                                 &bgp_102,
2305                                 FIB_SOURCE_API,
2306                                 FIB_PROTOCOL_IP4,
2307                                 &pfx_1_1_1_1_s_32.fp_addr,
2308                                 ~0, // no index provided.
2309                                 fib_index, // same as route's FIB
2310                                 1,
2311                                 FIB_ROUTE_PATH_FLAG_NONE);
2312     fib_table_entry_path_remove(fib_index,
2313                                 &bgp_102,
2314                                 FIB_SOURCE_API,
2315                                 FIB_PROTOCOL_IP4,
2316                                 &pfx_1_1_1_2_s_32.fp_addr,
2317                                 ~0, // no index provided.
2318                                 fib_index, // same as route's FIB
2319                                 1,
2320                                 FIB_ROUTE_PATH_FLAG_NONE);
2321     fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2322     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2323
2324     /*
2325      * remove the remaining recursives
2326      */
2327     fib_table_entry_path_remove(fib_index,
2328                                 &bgp_100_pfx,
2329                                 FIB_SOURCE_API,
2330                                 FIB_PROTOCOL_IP4,
2331                                 &pfx_1_1_1_1_s_32.fp_addr,
2332                                 ~0, // no index provided.
2333                                 fib_index, // same as route's FIB
2334                                 1,
2335                                 FIB_ROUTE_PATH_FLAG_NONE);
2336     fib_table_entry_path_remove(fib_index,
2337                                 &bgp_101_pfx,
2338                                 FIB_SOURCE_API,
2339                                 FIB_PROTOCOL_IP4,
2340                                 &pfx_1_1_1_1_s_32.fp_addr,
2341                                 ~0, // no index provided.
2342                                 fib_index, // same as route's FIB
2343                                 1,
2344                                 FIB_ROUTE_PATH_FLAG_NONE);
2345     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) == 
2346               FIB_NODE_INDEX_INVALID),
2347              "100.100.100.100/32 removed");
2348     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) == 
2349               FIB_NODE_INDEX_INVALID),
2350              "100.100.100.101/32 removed");
2351
2352     /*
2353      * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2354      */
2355     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
2356              fib_path_list_db_size());
2357     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2358              fib_path_list_pool_size());
2359     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2360              fib_entry_pool_size());
2361
2362     /*
2363      * Add a recursive route via a connected cover, using an adj-fib that does exist
2364      */
2365     fib_table_entry_path_add(fib_index,
2366                              &bgp_200_pfx,
2367                              FIB_SOURCE_API,
2368                              FIB_ENTRY_FLAG_NONE,
2369                              FIB_PROTOCOL_IP4,
2370                              &nh_10_10_10_1,
2371                              ~0, // no index provided.
2372                              fib_index, // Same as route's FIB
2373                              1,
2374                              NULL,
2375                              FIB_ROUTE_PATH_FLAG_NONE);
2376
2377     /*
2378      * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2379      */
2380     FIB_TEST((2  == fib_path_list_db_size()),   "path list DB population:%d",
2381              fib_path_list_db_size());
2382     FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2383              fib_path_list_pool_size());
2384     FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2385              fib_entry_pool_size());
2386
2387     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2388     dpo = fib_entry_contribute_ip_forwarding(fei);
2389
2390     fei  = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2391     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2392
2393     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2394              "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2395
2396     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED  == fib_entry_get_flags(fei)),
2397              "Flags set on RR via existing attached");
2398
2399     /*
2400      * Add a recursive route via a connected cover, using and adj-fib that does
2401      * not exist
2402      */
2403     ip46_address_t nh_10_10_10_3 = {
2404         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2405     };
2406     fib_prefix_t pfx_10_10_10_3 = {
2407         .fp_len = 32,
2408         .fp_proto = FIB_PROTOCOL_IP4,
2409         .fp_addr = nh_10_10_10_3,
2410     };
2411
2412     fib_table_entry_path_add(fib_index,
2413                              &bgp_201_pfx,
2414                              FIB_SOURCE_API,
2415                              FIB_ENTRY_FLAG_NONE,
2416                              FIB_PROTOCOL_IP4,
2417                              &nh_10_10_10_3,
2418                              ~0, // no index provided.
2419                              fib_index,
2420                              1,
2421                              NULL,
2422                              FIB_ROUTE_PATH_FLAG_NONE);
2423
2424     /*
2425      * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2426      * one unshared non-recursive via 10.10.10.3
2427      */
2428     FIB_TEST((3  == fib_path_list_db_size()),   "path list DB population:%d",
2429              fib_path_list_db_size());
2430     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2431              fib_path_list_pool_size());
2432     FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2433              fib_entry_pool_size());
2434
2435     ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2436                                 VNET_LINK_IP4,
2437                                 &nh_10_10_10_3,
2438                                 tm->hw[0]->sw_if_index);
2439
2440     fei  = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2441     dpo  = fib_entry_contribute_ip_forwarding(fei);
2442     fei  = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2443     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2444
2445     ai = fib_entry_get_adj(fei);
2446     FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2447     FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2448               fib_entry_get_flags(fei)),
2449              "Flags set on RR via non-existing attached");
2450
2451     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2452              "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2453
2454     adj_unlock(ai_03);
2455
2456     /*
2457      * remove the recursives
2458      */
2459     fib_table_entry_path_remove(fib_index,
2460                                 &bgp_200_pfx,
2461                                 FIB_SOURCE_API,
2462                                 FIB_PROTOCOL_IP4,
2463                                 &nh_10_10_10_1,
2464                                 ~0, // no index provided.
2465                                 fib_index, // same as route's FIB
2466                                 1,
2467                                 FIB_ROUTE_PATH_FLAG_NONE);
2468     fib_table_entry_path_remove(fib_index,
2469                                 &bgp_201_pfx,
2470                                 FIB_SOURCE_API,
2471                                 FIB_PROTOCOL_IP4,
2472                                 &nh_10_10_10_3,
2473                                 ~0, // no index provided.
2474                                 fib_index, // same as route's FIB
2475                                 1,
2476                                 FIB_ROUTE_PATH_FLAG_NONE);
2477
2478     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2479               FIB_NODE_INDEX_INVALID),
2480              "200.200.200.201/32 removed");
2481     FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2482               FIB_NODE_INDEX_INVALID),
2483              "200.200.200.200/32 removed");
2484     FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2485               FIB_NODE_INDEX_INVALID),
2486              "10.10.10.3/32 removed");
2487
2488     /*
2489      * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2490      *  10.10.10.1) and one unshared non-recursive via 10.10.10.3
2491      */
2492     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
2493              fib_path_list_db_size());
2494     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2495              fib_path_list_pool_size());
2496     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2497              fib_entry_pool_size());
2498
2499
2500     /*
2501      * RECURSION LOOPS
2502      *  Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2503      */
2504     fib_prefix_t pfx_5_5_5_5_s_32 = {
2505         .fp_len = 32,
2506         .fp_proto = FIB_PROTOCOL_IP4,
2507         .fp_addr = {
2508             .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2509         },
2510     };
2511     fib_prefix_t pfx_5_5_5_6_s_32 = {
2512         .fp_len = 32,
2513         .fp_proto = FIB_PROTOCOL_IP4,
2514         .fp_addr = {
2515             .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2516         },
2517     };
2518     fib_prefix_t pfx_5_5_5_7_s_32 = {
2519         .fp_len = 32,
2520         .fp_proto = FIB_PROTOCOL_IP4,
2521         .fp_addr = {
2522             .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2523         },
2524     };
2525
2526     fib_table_entry_path_add(fib_index,
2527                              &pfx_5_5_5_5_s_32,
2528                              FIB_SOURCE_API,
2529                              FIB_ENTRY_FLAG_NONE,
2530                              FIB_PROTOCOL_IP4,
2531                              &pfx_5_5_5_6_s_32.fp_addr,
2532                              ~0, // no index provided.
2533                              fib_index,
2534                              1,
2535                              NULL,
2536                              FIB_ROUTE_PATH_FLAG_NONE);
2537     fib_table_entry_path_add(fib_index,
2538                              &pfx_5_5_5_6_s_32,
2539                              FIB_SOURCE_API,
2540                              FIB_ENTRY_FLAG_NONE,
2541                              FIB_PROTOCOL_IP4,
2542                              &pfx_5_5_5_7_s_32.fp_addr,
2543                              ~0, // no index provided.
2544                              fib_index,
2545                              1,
2546                              NULL,
2547                              FIB_ROUTE_PATH_FLAG_NONE);
2548     fib_table_entry_path_add(fib_index,
2549                              &pfx_5_5_5_7_s_32,
2550                              FIB_SOURCE_API,
2551                              FIB_ENTRY_FLAG_NONE,
2552                              FIB_PROTOCOL_IP4,
2553                              &pfx_5_5_5_5_s_32.fp_addr,
2554                              ~0, // no index provided.
2555                              fib_index,
2556                              1,
2557                              NULL,
2558                              FIB_ROUTE_PATH_FLAG_NONE);
2559     /*
2560      * +3 entries, +3 shared path-list
2561      */
2562     FIB_TEST((4  == fib_path_list_db_size()),   "path list DB population:%d",
2563              fib_path_list_db_size());
2564     FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2565              fib_path_list_pool_size());
2566     FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2567              fib_entry_pool_size());
2568
2569     /*
2570      * All the entries have only looped paths, so they are all drop
2571      */
2572     fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2573     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2574              "LB for 5.5.5.7/32 is via adj for DROP");
2575     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2576     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2577              "LB for 5.5.5.5/32 is via adj for DROP");
2578     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2579     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2580              "LB for 5.5.5.6/32 is via adj for DROP");
2581
2582     /*
2583      * provide 5.5.5.6/32 with alternate path.
2584      * this will allow only 5.5.5.6/32 to forward with this path, the others
2585      * are still drop since the loop is still present.
2586      */
2587     fib_table_entry_path_add(fib_index,
2588                              &pfx_5_5_5_6_s_32,
2589                              FIB_SOURCE_API,
2590                              FIB_ENTRY_FLAG_NONE,
2591                              FIB_PROTOCOL_IP4,
2592                              &nh_10_10_10_1,
2593                              tm->hw[0]->sw_if_index,
2594                              ~0,
2595                              1,
2596                              NULL,
2597                              FIB_ROUTE_PATH_FLAG_NONE);
2598
2599
2600     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2601     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2602
2603     lb = load_balance_get(dpo1->dpoi_index);
2604     FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2605
2606     dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2607     FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2608     FIB_TEST((ai_01 == dpo2->dpoi_index),
2609              "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2610
2611     fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2612     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2613              "LB for 5.5.5.7/32 is via adj for DROP");
2614     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2615     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2616              "LB for 5.5.5.5/32 is via adj for DROP");
2617
2618     /*
2619      * remove the alternate path for 5.5.5.6/32
2620      * back to all drop
2621      */
2622     fib_table_entry_path_remove(fib_index,
2623                                 &pfx_5_5_5_6_s_32,
2624                                 FIB_SOURCE_API,
2625                                 FIB_PROTOCOL_IP4,
2626                                 &nh_10_10_10_1,
2627                                 tm->hw[0]->sw_if_index,
2628                                 ~0,
2629                                 1,
2630                                 FIB_ROUTE_PATH_FLAG_NONE);
2631
2632     fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2633     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2634              "LB for 5.5.5.7/32 is via adj for DROP");
2635     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2636     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2637              "LB for 5.5.5.5/32 is via adj for DROP");
2638     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2639     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2640              "LB for 5.5.5.6/32 is via adj for DROP");
2641
2642     /*
2643      * break the loop by giving 5.5.5.5/32 a new set of paths
2644      * expect all to forward via this new path.
2645      */
2646     fib_table_entry_update_one_path(fib_index,
2647                                     &pfx_5_5_5_5_s_32,
2648                                     FIB_SOURCE_API,
2649                                     FIB_ENTRY_FLAG_NONE,
2650                                     FIB_PROTOCOL_IP4,
2651                                     &nh_10_10_10_1,
2652                                     tm->hw[0]->sw_if_index,
2653                                     ~0, // invalid fib index
2654                                     1,
2655                                     NULL,
2656                                     FIB_ROUTE_PATH_FLAG_NONE);
2657
2658     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2659     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2660     lb = load_balance_get(dpo1->dpoi_index);
2661     FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2662
2663     dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2664     FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2665     FIB_TEST((ai_01 == dpo2->dpoi_index),
2666              "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2667
2668     fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2669     dpo2 = fib_entry_contribute_ip_forwarding(fei);
2670
2671     lb = load_balance_get(dpo2->dpoi_index);
2672     FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2673     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2674              "5.5.5.5.7 via 5.5.5.5");
2675
2676     fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2677     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2678
2679     lb = load_balance_get(dpo1->dpoi_index);
2680     FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2681     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2682              "5.5.5.5.6 via 5.5.5.7");
2683
2684     /*
2685      * revert back to the loop. so we can remove the prefixes with
2686      * the loop intact
2687      */
2688     fib_table_entry_update_one_path(fib_index,
2689                                     &pfx_5_5_5_5_s_32,
2690                                     FIB_SOURCE_API,
2691                                     FIB_ENTRY_FLAG_NONE,
2692                                     FIB_PROTOCOL_IP4,
2693                                     &pfx_5_5_5_6_s_32.fp_addr,
2694                                     ~0, // no index provided.
2695                                     fib_index,
2696                                     1,
2697                                     NULL,
2698                                     FIB_ROUTE_PATH_FLAG_NONE);
2699
2700     fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2701     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2702              "LB for 5.5.5.7/32 is via adj for DROP");
2703     fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2704     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2705              "LB for 5.5.5.5/32 is via adj for DROP");
2706     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2707     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2708              "LB for 5.5.5.6/32 is via adj for DROP");
2709
2710     /*
2711      * remove all the 5.5.5.x/32 prefixes
2712      */
2713     fib_table_entry_path_remove(fib_index,
2714                                 &pfx_5_5_5_5_s_32,
2715                                 FIB_SOURCE_API,
2716                                 FIB_PROTOCOL_IP4,
2717                                 &pfx_5_5_5_6_s_32.fp_addr,
2718                                 ~0, // no index provided.
2719                                 fib_index, // same as route's FIB
2720                                 1,
2721                                 FIB_ROUTE_PATH_FLAG_NONE);
2722     fib_table_entry_path_remove(fib_index,
2723                                 &pfx_5_5_5_6_s_32,
2724                                 FIB_SOURCE_API,
2725                                 FIB_PROTOCOL_IP4,
2726                                 &pfx_5_5_5_7_s_32.fp_addr,
2727                                 ~0, // no index provided.
2728                                 fib_index, // same as route's FIB
2729                                 1,
2730                                 FIB_ROUTE_PATH_FLAG_NONE);
2731     fib_table_entry_path_remove(fib_index,
2732                                 &pfx_5_5_5_7_s_32,
2733                                 FIB_SOURCE_API,
2734                                 FIB_PROTOCOL_IP4,
2735                                 &pfx_5_5_5_5_s_32.fp_addr,
2736                                 ~0, // no index provided.
2737                                 fib_index, // same as route's FIB
2738                                 1,
2739                                 FIB_ROUTE_PATH_FLAG_NONE);
2740     fib_table_entry_path_remove(fib_index,
2741                                 &pfx_5_5_5_6_s_32,
2742                                 FIB_SOURCE_API,
2743                                 FIB_PROTOCOL_IP4,
2744                                 &nh_10_10_10_2,
2745                                 ~0, // no index provided.
2746                                 fib_index, // same as route's FIB
2747                                 1,
2748                                 FIB_ROUTE_PATH_FLAG_NONE);
2749
2750     /*
2751      * -3 entries, -3 shared path-list
2752      */
2753     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
2754              fib_path_list_db_size());
2755     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2756              fib_path_list_pool_size());
2757     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2758              fib_entry_pool_size());
2759
2760     /*
2761      * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2762      */
2763     fib_table_entry_path_add(fib_index,
2764                              &pfx_5_5_5_6_s_32,
2765                              FIB_SOURCE_API,
2766                              FIB_ENTRY_FLAG_NONE,
2767                              FIB_PROTOCOL_IP4,
2768                              &pfx_5_5_5_6_s_32.fp_addr,
2769                              ~0, // no index provided.
2770                              fib_index,
2771                              1,
2772                              NULL,
2773                              FIB_ROUTE_PATH_FLAG_NONE);
2774     fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2775     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2776              "1-level 5.5.5.6/32 loop is via adj for DROP");
2777  
2778     fib_table_entry_path_remove(fib_index,
2779                                 &pfx_5_5_5_6_s_32,
2780                                 FIB_SOURCE_API,
2781                                 FIB_PROTOCOL_IP4,
2782                                 &pfx_5_5_5_6_s_32.fp_addr,
2783                                 ~0, // no index provided.
2784                                 fib_index, // same as route's FIB
2785                                 1,
2786                                 FIB_ROUTE_PATH_FLAG_NONE);
2787     FIB_TEST(FIB_NODE_INDEX_INVALID ==
2788              fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2789              "1-level 5.5.5.6/32 loop is removed");
2790
2791     /*
2792      * A recursive route whose next-hop is covered by the prefix.
2793      * This would mean the via-fib, which inherits forwarding from its
2794      * cover, thus picks up forwarding from the prfix, which is via the
2795      * via-fib, and we have a loop.
2796      */
2797     fib_prefix_t pfx_23_23_23_0_s_24 = {
2798         .fp_len = 24,
2799         .fp_proto = FIB_PROTOCOL_IP4,
2800         .fp_addr = {
2801             .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2802         },
2803     };
2804     fib_prefix_t pfx_23_23_23_23_s_32 = {
2805         .fp_len = 32,
2806         .fp_proto = FIB_PROTOCOL_IP4,
2807         .fp_addr = {
2808             .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2809         },
2810     };
2811     fei = fib_table_entry_path_add(fib_index,
2812                                    &pfx_23_23_23_0_s_24,
2813                                    FIB_SOURCE_API,
2814                                    FIB_ENTRY_FLAG_NONE,
2815                                    FIB_PROTOCOL_IP4,
2816                                    &pfx_23_23_23_23_s_32.fp_addr,
2817                                    ~0, // recursive
2818                                    fib_index,
2819                                    1,
2820                                    NULL,
2821                                    FIB_ROUTE_PATH_FLAG_NONE);
2822     dpo = fib_entry_contribute_ip_forwarding(fei);
2823     FIB_TEST(load_balance_is_drop(dpo),
2824              "23.23.23.0/24 via covered is DROP");
2825     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2826
2827     /*
2828      * add-remove test. no change.
2829      */
2830     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
2831              fib_path_list_db_size());
2832     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2833              fib_path_list_pool_size());
2834     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2835              fib_entry_pool_size());
2836
2837     /*
2838      * A recursive route with recursion constraints.
2839      *  200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2840      */
2841     fib_table_entry_path_add(fib_index,
2842                              &bgp_200_pfx,
2843                              FIB_SOURCE_API,
2844                              FIB_ENTRY_FLAG_NONE,
2845                              FIB_PROTOCOL_IP4,
2846                              &nh_1_1_1_1,
2847                              ~0,
2848                              fib_index,
2849                              1,
2850                              NULL,
2851                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2852
2853     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2854     dpo2 = fib_entry_contribute_ip_forwarding(fei);
2855
2856     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2857     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2858
2859     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2860              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2861
2862     /*
2863      * save the load-balance. we expect it to be inplace modified
2864      */
2865     lb = load_balance_get(dpo1->dpoi_index);
2866
2867     /*
2868      * add a covering prefix for the via fib that would otherwise serve
2869      * as the resolving route when the host is removed
2870      */
2871     fib_table_entry_path_add(fib_index,
2872                              &pfx_1_1_1_0_s_28,
2873                              FIB_SOURCE_API,
2874                              FIB_ENTRY_FLAG_NONE,
2875                              FIB_PROTOCOL_IP4,
2876                              &nh_10_10_10_1,
2877                              tm->hw[0]->sw_if_index,
2878                              ~0, // invalid fib index
2879                              1,
2880                              NULL,
2881                              FIB_ROUTE_PATH_FLAG_NONE);
2882     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
2883     ai = fib_entry_get_adj(fei);
2884     FIB_TEST((ai == ai_01),
2885              "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
2886
2887     /*
2888      * remove the host via FIB - expect the BGP prefix to be drop
2889      */
2890     fib_table_entry_path_remove(fib_index,
2891                                 &pfx_1_1_1_1_s_32,
2892                                 FIB_SOURCE_API,
2893                                 FIB_PROTOCOL_IP4,
2894                                 &nh_10_10_10_1,
2895                                 tm->hw[0]->sw_if_index,
2896                                 ~0, // invalid fib index
2897                                 1,
2898                                 FIB_ROUTE_PATH_FLAG_NONE);
2899
2900     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2901              "adj for 200.200.200.200/32 is recursive via adj for DROP");
2902
2903     /*
2904      * add the via-entry host reoute back. expect to resolve again
2905      */
2906     fib_table_entry_path_add(fib_index,
2907                              &pfx_1_1_1_1_s_32,
2908                              FIB_SOURCE_API,
2909                              FIB_ENTRY_FLAG_NONE,
2910                              FIB_PROTOCOL_IP4,
2911                              &nh_10_10_10_1,
2912                              tm->hw[0]->sw_if_index,
2913                              ~0, // invalid fib index
2914                              1,
2915                              NULL,
2916                              FIB_ROUTE_PATH_FLAG_NONE);
2917     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2918              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2919
2920     /*
2921      * add another path for the recursive. it will then have 2.
2922      */
2923     fib_prefix_t pfx_1_1_1_3_s_32 = {
2924         .fp_len = 32,
2925         .fp_proto = FIB_PROTOCOL_IP4,
2926         .fp_addr = {
2927             .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
2928         },
2929     };
2930     fib_table_entry_path_add(fib_index,
2931                              &pfx_1_1_1_3_s_32,
2932                              FIB_SOURCE_API,
2933                              FIB_ENTRY_FLAG_NONE,
2934                              FIB_PROTOCOL_IP4,
2935                              &nh_10_10_10_2,
2936                              tm->hw[0]->sw_if_index,
2937                              ~0, // invalid fib index
2938                              1,
2939                              NULL,
2940                              FIB_ROUTE_PATH_FLAG_NONE);
2941
2942     fib_table_entry_path_add(fib_index,
2943                              &bgp_200_pfx,
2944                              FIB_SOURCE_API,
2945                              FIB_ENTRY_FLAG_NONE,
2946                              FIB_PROTOCOL_IP4,
2947                              &pfx_1_1_1_3_s_32.fp_addr,
2948                              ~0,
2949                              fib_index,
2950                              1,
2951                              NULL,
2952                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2953
2954     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2955     dpo = fib_entry_contribute_ip_forwarding(fei);
2956
2957     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2958     dpo2 = fib_entry_contribute_ip_forwarding(fei);
2959     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2960              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2961     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2962     dpo1 = fib_entry_contribute_ip_forwarding(fei);
2963     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2964              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2965
2966     /*
2967      * expect the lb-map used by the recursive's load-balance is using both buckets
2968      */
2969     load_balance_map_t *lbm;
2970     index_t lbmi;
2971
2972     lb = load_balance_get(dpo->dpoi_index);
2973     lbmi = lb->lb_map;
2974     load_balance_map_lock(lbmi);
2975     lbm = load_balance_map_get(lbmi);
2976
2977     FIB_TEST(lbm->lbm_buckets[0] == 0,
2978              "LB maps's bucket 0 is %d",
2979              lbm->lbm_buckets[0]);
2980     FIB_TEST(lbm->lbm_buckets[1] == 1,
2981              "LB maps's bucket 1 is %d",
2982              lbm->lbm_buckets[1]);
2983
2984     /*
2985      * withdraw one of the /32 via-entrys.
2986      * that ECMP path will be unresolved and forwarding should continue on the
2987      * other available path. this is an iBGP PIC edge failover.
2988      * Test the forwarding changes without re-fetching the adj from the
2989      * recursive entry. this ensures its the same one that is updated; i.e. an
2990      * inplace-modify.
2991      */
2992     fib_table_entry_path_remove(fib_index,
2993                                 &pfx_1_1_1_1_s_32,
2994                                 FIB_SOURCE_API,
2995                                 FIB_PROTOCOL_IP4,
2996                                 &nh_10_10_10_1,
2997                                 tm->hw[0]->sw_if_index,
2998                                 ~0, // invalid fib index
2999                                 1,
3000                                 FIB_ROUTE_PATH_FLAG_NONE);
3001
3002     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3003     FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3004              "post PIC 200.200.200.200/32 was inplace modified");
3005
3006     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3007              "post PIC adj for 200.200.200.200/32 is recursive"
3008              " via adj for 1.1.1.3");
3009
3010     /*
3011      * the LB maps that was locked above should have been modified to remove
3012      * the path that was down, and thus its bucket points to a path that is
3013      * still up.
3014      */
3015     FIB_TEST(lbm->lbm_buckets[0] == 1,
3016              "LB maps's bucket 0 is %d",
3017              lbm->lbm_buckets[0]);
3018     FIB_TEST(lbm->lbm_buckets[1] == 1,
3019              "LB maps's bucket 1 is %d",
3020              lbm->lbm_buckets[1]);
3021
3022     load_balance_map_unlock(lb->lb_map);
3023
3024     /*
3025      * add it back. again 
3026      */
3027     fib_table_entry_path_add(fib_index,
3028                              &pfx_1_1_1_1_s_32,
3029                              FIB_SOURCE_API,
3030                              FIB_ENTRY_FLAG_NONE,
3031                              FIB_PROTOCOL_IP4,
3032                              &nh_10_10_10_1,
3033                              tm->hw[0]->sw_if_index,
3034                              ~0, // invalid fib index
3035                              1,
3036                              NULL,
3037                              FIB_ROUTE_PATH_FLAG_NONE);
3038
3039     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3040              "post PIC recovery adj for 200.200.200.200/32 is recursive "
3041              "via adj for 1.1.1.1");
3042     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3043              "post PIC recovery adj for 200.200.200.200/32 is recursive "
3044              "via adj for 1.1.1.3");
3045
3046     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3047     dpo = fib_entry_contribute_ip_forwarding(fei);
3048     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3049              "post PIC 200.200.200.200/32 was inplace modified");
3050
3051     /*
3052      * add a 3rd path. this makes the LB 16 buckets. 
3053      */
3054     fib_table_entry_path_add(fib_index,
3055                              &bgp_200_pfx,
3056                              FIB_SOURCE_API,
3057                              FIB_ENTRY_FLAG_NONE,
3058                              FIB_PROTOCOL_IP4,
3059                              &pfx_1_1_1_2_s_32.fp_addr,
3060                              ~0,
3061                              fib_index,
3062                              1,
3063                              NULL,
3064                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3065
3066     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3067     dpo = fib_entry_contribute_ip_forwarding(fei);
3068     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3069              "200.200.200.200/32 was inplace modified for 3rd path");
3070     FIB_TEST(16 == lb->lb_n_buckets,
3071              "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3072
3073     lbmi = lb->lb_map;
3074     load_balance_map_lock(lbmi);
3075     lbm = load_balance_map_get(lbmi);
3076
3077     for (ii = 0; ii < 16; ii++)
3078     {
3079         FIB_TEST(lbm->lbm_buckets[ii] == ii,
3080                  "LB Map for 200.200.200.200/32 at %d is %d",
3081                  ii, lbm->lbm_buckets[ii]);
3082     }
3083
3084     /*
3085      * trigger PIC by removing the first via-entry
3086      * the first 6 buckets of the map should map to the next 6
3087      */
3088     fib_table_entry_path_remove(fib_index,
3089                                 &pfx_1_1_1_1_s_32,
3090                                 FIB_SOURCE_API,
3091                                 FIB_PROTOCOL_IP4,
3092                                 &nh_10_10_10_1,
3093                                 tm->hw[0]->sw_if_index,
3094                                 ~0,
3095                                 1,
3096                                 FIB_ROUTE_PATH_FLAG_NONE);
3097
3098     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3099     dpo = fib_entry_contribute_ip_forwarding(fei);
3100     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3101              "200.200.200.200/32 was inplace modified for 3rd path");
3102     FIB_TEST(2 == lb->lb_n_buckets,
3103              "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3104
3105     for (ii = 0; ii < 6; ii++)
3106     {
3107         FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3108                  "LB Map for 200.200.200.200/32 at %d is %d",
3109                  ii, lbm->lbm_buckets[ii]);
3110     }
3111     for (ii = 6; ii < 16; ii++)
3112     {
3113         FIB_TEST(lbm->lbm_buckets[ii] == ii,
3114                  "LB Map for 200.200.200.200/32 at %d is %d",
3115                  ii, lbm->lbm_buckets[ii]);
3116     }
3117
3118
3119     /*
3120      * tidy up
3121      */
3122     fib_table_entry_path_add(fib_index,
3123                              &pfx_1_1_1_1_s_32,
3124                              FIB_SOURCE_API,
3125                              FIB_ENTRY_FLAG_NONE,
3126                              FIB_PROTOCOL_IP4,
3127                              &nh_10_10_10_1,
3128                              tm->hw[0]->sw_if_index,
3129                              ~0,
3130                              1,
3131                              NULL,
3132                              FIB_ROUTE_PATH_FLAG_NONE);
3133
3134     fib_table_entry_path_remove(fib_index,
3135                                 &bgp_200_pfx,
3136                                 FIB_SOURCE_API,
3137                                 FIB_PROTOCOL_IP4,
3138                                 &pfx_1_1_1_2_s_32.fp_addr,
3139                                 ~0,
3140                                 fib_index,
3141                                 1,
3142                                 MPLS_LABEL_INVALID);
3143     fib_table_entry_path_remove(fib_index,
3144                                 &bgp_200_pfx,
3145                                 FIB_SOURCE_API,
3146                                 FIB_PROTOCOL_IP4,
3147                                 &nh_1_1_1_1,
3148                                 ~0,
3149                                 fib_index,
3150                                 1,
3151                                 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3152     fib_table_entry_path_remove(fib_index,
3153                                 &bgp_200_pfx,
3154                                 FIB_SOURCE_API,
3155                                 FIB_PROTOCOL_IP4,
3156                                 &pfx_1_1_1_3_s_32.fp_addr,
3157                                 ~0,
3158                                 fib_index,
3159                                 1,
3160                                 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3161     fib_table_entry_delete(fib_index,
3162                            &pfx_1_1_1_3_s_32,
3163                            FIB_SOURCE_API);
3164     fib_table_entry_delete(fib_index,
3165                            &pfx_1_1_1_0_s_28,
3166                            FIB_SOURCE_API);
3167     FIB_TEST((FIB_NODE_INDEX_INVALID ==
3168               fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3169              "1.1.1.1/28 removed");
3170     FIB_TEST((FIB_NODE_INDEX_INVALID ==
3171               fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3172              "1.1.1.3/32 removed");
3173     FIB_TEST((FIB_NODE_INDEX_INVALID ==
3174               fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3175              "200.200.200.200/32 removed");
3176
3177     /*
3178      * add-remove test. no change.
3179      */
3180     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3181              fib_path_list_db_size());
3182     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3183              fib_path_list_pool_size());
3184     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3185              fib_entry_pool_size());
3186
3187     /*
3188      * A route whose paths are built up iteratively and then removed
3189      * all at once
3190      */
3191     fib_prefix_t pfx_4_4_4_4_s_32 = {
3192         .fp_len = 32,
3193         .fp_proto = FIB_PROTOCOL_IP4,
3194         .fp_addr = {
3195             /* 4.4.4.4/32 */
3196             .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3197         },
3198     };
3199
3200     fib_table_entry_path_add(fib_index,
3201                              &pfx_4_4_4_4_s_32,
3202                              FIB_SOURCE_API,
3203                              FIB_ENTRY_FLAG_NONE,
3204                              FIB_PROTOCOL_IP4,
3205                              &nh_10_10_10_1,
3206                              tm->hw[0]->sw_if_index,
3207                              ~0,
3208                              1,
3209                              NULL,
3210                              FIB_ROUTE_PATH_FLAG_NONE);
3211     fib_table_entry_path_add(fib_index,
3212                              &pfx_4_4_4_4_s_32,
3213                              FIB_SOURCE_API,
3214                              FIB_ENTRY_FLAG_NONE,
3215                              FIB_PROTOCOL_IP4,
3216                              &nh_10_10_10_2,
3217                              tm->hw[0]->sw_if_index,
3218                              ~0,
3219                              1,
3220                              NULL,
3221                              FIB_ROUTE_PATH_FLAG_NONE);
3222     fib_table_entry_path_add(fib_index,
3223                              &pfx_4_4_4_4_s_32,
3224                              FIB_SOURCE_API,
3225                              FIB_ENTRY_FLAG_NONE,
3226                              FIB_PROTOCOL_IP4,
3227                              &nh_10_10_10_3,
3228                              tm->hw[0]->sw_if_index,
3229                              ~0,
3230                              1,
3231                              NULL,
3232                              FIB_ROUTE_PATH_FLAG_NONE);
3233     FIB_TEST(FIB_NODE_INDEX_INVALID !=
3234              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3235              "4.4.4.4/32 present");
3236
3237     fib_table_entry_delete(fib_index,
3238                            &pfx_4_4_4_4_s_32,
3239                            FIB_SOURCE_API);
3240     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3241              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3242              "4.4.4.4/32 removed");
3243
3244     /*
3245      * add-remove test. no change.
3246      */
3247     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3248              fib_path_list_db_size());
3249     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3250              fib_path_list_pool_size());
3251     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3252              fib_entry_pool_size());
3253
3254     /*
3255      * A route with multiple paths at once
3256      */
3257     fib_route_path_t *r_paths = NULL;
3258
3259     for (ii = 0; ii < 4; ii++)
3260     {
3261         fib_route_path_t r_path = {
3262             .frp_proto = FIB_PROTOCOL_IP4,
3263             .frp_addr = {
3264                 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3265             },
3266             .frp_sw_if_index = tm->hw[0]->sw_if_index,
3267             .frp_weight = 1,
3268             .frp_fib_index = ~0,
3269         };
3270         vec_add1(r_paths, r_path);
3271     }
3272
3273     fib_table_entry_update(fib_index,
3274                            &pfx_4_4_4_4_s_32,
3275                            FIB_SOURCE_API,
3276                            FIB_ENTRY_FLAG_NONE,
3277                            r_paths);
3278
3279     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3280     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3281     dpo = fib_entry_contribute_ip_forwarding(fei);
3282
3283     lb = load_balance_get(dpo->dpoi_index);
3284     FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3285
3286     fib_table_entry_delete(fib_index,
3287                            &pfx_4_4_4_4_s_32,
3288                            FIB_SOURCE_API);
3289     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3290              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3291              "4.4.4.4/32 removed");
3292     vec_free(r_paths);
3293
3294     /*
3295      * add-remove test. no change.
3296      */
3297     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3298              fib_path_list_db_size());
3299     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3300              fib_path_list_pool_size());
3301     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3302              fib_entry_pool_size());
3303
3304     /*
3305      * A route deag route
3306      */
3307     fib_table_entry_path_add(fib_index,
3308                              &pfx_4_4_4_4_s_32,
3309                              FIB_SOURCE_API,
3310                              FIB_ENTRY_FLAG_NONE,
3311                              FIB_PROTOCOL_IP4,
3312                              &zero_addr,
3313                              ~0,
3314                              fib_index,
3315                              1,
3316                              NULL,
3317                              FIB_ROUTE_PATH_FLAG_NONE);
3318
3319     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3320     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3321
3322     dpo = fib_entry_contribute_ip_forwarding(fei);
3323     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3324     lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3325
3326     FIB_TEST((fib_index == lkd->lkd_fib_index),
3327              "4.4.4.4/32 is deag in %d %U",
3328              lkd->lkd_fib_index,
3329              format_dpo_id, dpo, 0);
3330
3331     fib_table_entry_delete(fib_index,
3332                            &pfx_4_4_4_4_s_32,
3333                            FIB_SOURCE_API);
3334     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3335              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3336              "4.4.4.4/32 removed");
3337     vec_free(r_paths);
3338
3339     /*
3340      * add-remove test. no change.
3341      */
3342     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3343              fib_path_list_db_size());
3344     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3345              fib_path_list_pool_size());
3346     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3347              fib_entry_pool_size());
3348
3349     /*
3350      * Duplicate paths:
3351      *  add a recursive with duplicate paths. Expect the duplicate to be ignored.
3352      */
3353     fib_prefix_t pfx_34_1_1_1_s_32 = {
3354         .fp_len = 32,
3355         .fp_proto = FIB_PROTOCOL_IP4,
3356         .fp_addr = {
3357             .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3358         },
3359     };
3360     fib_prefix_t pfx_34_34_1_1_s_32 = {
3361         .fp_len = 32,
3362         .fp_proto = FIB_PROTOCOL_IP4,
3363         .fp_addr = {
3364             .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3365         },
3366     };
3367     fei = fib_table_entry_path_add(fib_index,
3368                                    &pfx_34_1_1_1_s_32,
3369                                    FIB_SOURCE_API,
3370                                    FIB_ENTRY_FLAG_NONE,
3371                                    FIB_PROTOCOL_IP4,
3372                                    &pfx_34_34_1_1_s_32.fp_addr,
3373                                    ~0,
3374                                    fib_index,
3375                                    1,
3376                                    NULL,
3377                                    FIB_ROUTE_PATH_FLAG_NONE);
3378     fei = fib_table_entry_path_add(fib_index,
3379                                    &pfx_34_1_1_1_s_32,
3380                                    FIB_SOURCE_API,
3381                                    FIB_ENTRY_FLAG_NONE,
3382                                    FIB_PROTOCOL_IP4,
3383                                    &pfx_34_34_1_1_s_32.fp_addr,
3384                                    ~0,
3385                                    fib_index,
3386                                    1,
3387                                    NULL,
3388                                    FIB_ROUTE_PATH_FLAG_NONE);
3389     FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3390     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3391
3392     /*
3393      * CLEANUP
3394      *   remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3395      *           all of which are via 10.10.10.1, Itf1
3396      */
3397     fib_table_entry_path_remove(fib_index,
3398                                 &pfx_1_1_1_2_s_32,
3399                                 FIB_SOURCE_API,
3400                                 FIB_PROTOCOL_IP4,
3401                                 &nh_10_10_10_1,
3402                                 tm->hw[0]->sw_if_index,
3403                                 ~0,
3404                                 1,
3405                                 FIB_ROUTE_PATH_FLAG_NONE);
3406     fib_table_entry_path_remove(fib_index,
3407                                 &pfx_1_1_1_1_s_32,
3408                                 FIB_SOURCE_API,
3409                                 FIB_PROTOCOL_IP4,
3410                                 &nh_10_10_10_1,
3411                                 tm->hw[0]->sw_if_index,
3412                                 ~0,
3413                                 1,
3414                                 FIB_ROUTE_PATH_FLAG_NONE);
3415     fib_table_entry_path_remove(fib_index,
3416                                 &pfx_1_1_2_0_s_24,
3417                                 FIB_SOURCE_API,
3418                                 FIB_PROTOCOL_IP4,
3419                                 &nh_10_10_10_1,
3420                                 tm->hw[0]->sw_if_index,
3421                                 ~0,
3422                                 1,
3423                                 FIB_ROUTE_PATH_FLAG_NONE);
3424
3425     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3426              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3427              "1.1.1.1/32 removed");
3428     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3429              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3430              "1.1.1.2/32 removed");
3431     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3432              fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3433              "1.1.2.0/24 removed");
3434
3435     /*
3436      * -3 entries and -1 shared path-list
3437      */
3438     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3439              fib_path_list_db_size());
3440     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3441              fib_path_list_pool_size());
3442     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3443              fib_entry_pool_size());
3444
3445     /*
3446      * An attached-host route. Expect to link to the incomplete adj
3447      */
3448     fib_prefix_t pfx_4_1_1_1_s_32 = {
3449         .fp_len = 32,
3450         .fp_proto = FIB_PROTOCOL_IP4,
3451         .fp_addr = {
3452             /* 4.1.1.1/32 */
3453             .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3454         },
3455     };
3456     fib_table_entry_path_add(fib_index,
3457                              &pfx_4_1_1_1_s_32,
3458                              FIB_SOURCE_API,
3459                              FIB_ENTRY_FLAG_NONE,
3460                              FIB_PROTOCOL_IP4,
3461                              &zero_addr,
3462                              tm->hw[0]->sw_if_index,
3463                              fib_index,
3464                              1,
3465                              NULL,
3466                              FIB_ROUTE_PATH_FLAG_NONE);
3467
3468     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3469     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3470     ai = fib_entry_get_adj(fei);
3471
3472     ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3473                               VNET_LINK_IP4,
3474                               &pfx_4_1_1_1_s_32.fp_addr,
3475                               tm->hw[0]->sw_if_index);
3476     FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3477     adj_unlock(ai2);
3478
3479     /*
3480      * +1 entry and +1 shared path-list
3481      */
3482     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3483              fib_path_list_db_size());
3484     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3485              fib_path_list_pool_size());
3486     FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3487              fib_entry_pool_size());
3488
3489     fib_table_entry_delete(fib_index,
3490                            &pfx_4_1_1_1_s_32,
3491                            FIB_SOURCE_API);
3492
3493     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3494              fib_path_list_db_size());
3495     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3496              fib_path_list_pool_size());
3497     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3498              fib_entry_pool_size());
3499
3500     /*
3501      * add a v6 prefix via v4 next-hops
3502      */
3503     fib_prefix_t pfx_2001_s_64 = {
3504         .fp_len = 64,
3505         .fp_proto = FIB_PROTOCOL_IP6,
3506         .fp_addr = {
3507             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3508         },
3509     };
3510     fei = fib_table_entry_path_add(0, //default v6 table
3511                                    &pfx_2001_s_64,
3512                                    FIB_SOURCE_API,
3513                                    FIB_ENTRY_FLAG_NONE,
3514                                    FIB_PROTOCOL_IP4,
3515                                    &nh_10_10_10_1,
3516                                    tm->hw[0]->sw_if_index,
3517                                    fib_index,
3518                                    1,
3519                                    NULL,
3520                                    FIB_ROUTE_PATH_FLAG_NONE);
3521
3522     fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3523     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3524     ai = fib_entry_get_adj(fei);
3525     adj = adj_get(ai);
3526     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3527              "2001::/64 via ARP-adj");
3528     FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3529              "2001::/64 is link type v6");
3530     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3531              "2001::/64 ADJ-adj is NH proto v4");
3532     fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3533
3534     /*
3535      * add a uRPF exempt prefix:
3536      *  test:
3537      *   - it's forwarding is drop
3538      *   - it's uRPF list is not empty
3539      *   - the uRPF list for the default route (it's cover) is empty
3540      */
3541     fei = fib_table_entry_special_add(fib_index,
3542                                       &pfx_4_1_1_1_s_32,
3543                                       FIB_SOURCE_URPF_EXEMPT,
3544                                       FIB_ENTRY_FLAG_DROP,
3545                                       ADJ_INDEX_INVALID);
3546     dpo = fib_entry_contribute_ip_forwarding(fei);
3547     FIB_TEST(load_balance_is_drop(dpo),
3548              "uRPF exempt 4.1.1.1/32 DROP");
3549     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3550              "uRPF list for exempt prefix has itf index 0");
3551     fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3552     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3553              "uRPF list for 0.0.0.0/0 empty");
3554
3555     fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3556
3557     /*
3558      * An adj-fib that fails the refinement criteria - no connected cover
3559      */
3560     fib_prefix_t pfx_12_10_10_2_s_32 = {
3561         .fp_len = 32,
3562         .fp_proto = FIB_PROTOCOL_IP4,
3563         .fp_addr = {
3564             /* 12.10.10.2 */
3565             .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3566         },
3567     };
3568
3569     fib_table_entry_update_one_path(fib_index,
3570                                     &pfx_12_10_10_2_s_32,
3571                                     FIB_SOURCE_ADJ,
3572                                     FIB_ENTRY_FLAG_ATTACHED,
3573                                     FIB_PROTOCOL_IP4,
3574                                     &pfx_12_10_10_2_s_32.fp_addr,
3575                                     tm->hw[0]->sw_if_index,
3576                                     ~0, // invalid fib index
3577                                     1,
3578                                     NULL,
3579                                     FIB_ROUTE_PATH_FLAG_NONE);
3580
3581     fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3582     dpo = fib_entry_contribute_ip_forwarding(fei);
3583     FIB_TEST(!dpo_id_is_valid(dpo),
3584              "no connected cover adj-fib fails refinement");
3585
3586     fib_table_entry_delete(fib_index,
3587                            &pfx_12_10_10_2_s_32,
3588                            FIB_SOURCE_ADJ);
3589
3590     /*
3591      * An adj-fib that fails the refinement criteria - cover is connected
3592      * but on a different interface
3593      */
3594     fib_prefix_t pfx_10_10_10_127_s_32 = {
3595         .fp_len = 32,
3596         .fp_proto = FIB_PROTOCOL_IP4,
3597         .fp_addr = {
3598             /* 10.10.10.127 */
3599             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3600         },
3601     };
3602
3603     fib_table_entry_update_one_path(fib_index,
3604                                     &pfx_10_10_10_127_s_32,
3605                                     FIB_SOURCE_ADJ,
3606                                     FIB_ENTRY_FLAG_ATTACHED,
3607                                     FIB_PROTOCOL_IP4,
3608                                     &pfx_10_10_10_127_s_32.fp_addr,
3609                                     tm->hw[1]->sw_if_index,
3610                                     ~0, // invalid fib index
3611                                     1,
3612                                     NULL,
3613                                     FIB_ROUTE_PATH_FLAG_NONE);
3614
3615     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3616     dpo = fib_entry_contribute_ip_forwarding(fei);
3617     FIB_TEST(!dpo_id_is_valid(dpo),
3618              "wrong interface adj-fib fails refinement");
3619
3620     fib_table_entry_delete(fib_index,
3621                            &pfx_10_10_10_127_s_32,
3622                            FIB_SOURCE_ADJ);
3623
3624     /*
3625      * CLEANUP
3626      *    remove adj-fibs: 
3627      */
3628     fib_table_entry_delete(fib_index,
3629                            &pfx_10_10_10_1_s_32,
3630                            FIB_SOURCE_ADJ);
3631     fib_table_entry_delete(fib_index,
3632                            &pfx_10_10_10_2_s_32,
3633                            FIB_SOURCE_ADJ);
3634     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3635              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
3636              "10.10.10.1/32 adj-fib removed");
3637     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3638              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
3639              "10.10.10.2/32 adj-fib removed");
3640
3641     /*
3642      * -2 entries and -2 non-shared path-list
3643      */
3644     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3645              fib_path_list_db_size());
3646     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
3647              fib_path_list_pool_size());
3648     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
3649              fib_entry_pool_size());
3650
3651     /*
3652      * unlock the adjacencies for which this test provided a rewrite.
3653      * These are the last locks on these adjs. they should thus go away.
3654      */
3655     adj_unlock(ai_02);
3656     adj_unlock(ai_01);
3657     adj_unlock(ai_12_12_12_12);
3658
3659     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3660              adj_nbr_db_size());
3661
3662     /*
3663      * CLEANUP
3664      *   remove the interface prefixes
3665      */
3666     local_pfx.fp_len = 32;
3667     fib_table_entry_special_remove(fib_index, &local_pfx,
3668                                    FIB_SOURCE_INTERFACE);
3669     fei = fib_table_lookup(fib_index, &local_pfx);
3670
3671     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3672              fib_table_lookup_exact_match(fib_index, &local_pfx),
3673              "10.10.10.10/32 adj-fib removed");
3674
3675     local_pfx.fp_len = 24;
3676     fib_table_entry_delete(fib_index, &local_pfx,
3677                            FIB_SOURCE_INTERFACE);
3678
3679     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3680              fib_table_lookup_exact_match(fib_index, &local_pfx),
3681              "10.10.10.10/24 adj-fib removed");
3682
3683     /*
3684      * -2 entries and -2 non-shared path-list
3685      */
3686     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3687              fib_path_list_db_size());
3688     FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
3689              fib_path_list_pool_size());
3690     FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
3691              fib_entry_pool_size());
3692
3693     /*
3694      * Last but not least, remove the VRF
3695      */
3696     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3697                                              FIB_PROTOCOL_IP4,
3698                                              FIB_SOURCE_API)),
3699              "NO API Source'd prefixes");
3700     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3701                                              FIB_PROTOCOL_IP4,
3702                                              FIB_SOURCE_RR)),
3703              "NO RR Source'd prefixes");
3704     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3705                                              FIB_PROTOCOL_IP4,
3706                                              FIB_SOURCE_INTERFACE)),
3707              "NO INterface Source'd prefixes");
3708
3709     fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
3710
3711     FIB_TEST((0  == fib_path_list_db_size()), "path list DB population:%d",
3712              fib_path_list_db_size());
3713     FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
3714              fib_path_list_pool_size());
3715     FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
3716              fib_entry_pool_size());
3717     FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
3718              pool_elts(fib_urpf_list_pool));
3719
3720     return 0;
3721 }
3722
3723 static int
3724 fib_test_v6 (void)
3725 {
3726     /*
3727      * In the default table check for the presence and correct forwarding
3728      * of the special entries
3729      */
3730     fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
3731     const dpo_id_t *dpo, *dpo_drop;
3732     const ip_adjacency_t *adj;
3733     const receive_dpo_t *rd;
3734     test_main_t *tm;
3735     u32 fib_index;
3736     int ii;
3737
3738     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3739              adj_nbr_db_size());
3740
3741     /* via 2001:0:0:1::2 */
3742     ip46_address_t nh_2001_2 = {
3743         .ip6 = {
3744             .as_u64 = {
3745                 [0] = clib_host_to_net_u64(0x2001000000000001),
3746                 [1] = clib_host_to_net_u64(0x0000000000000002),
3747             },
3748         },
3749     };
3750
3751     tm = &test_main;
3752
3753     dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
3754
3755     /* Find or create FIB table 11 */
3756     fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
3757
3758     for (ii = 0; ii < 4; ii++)
3759     {
3760         ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
3761     }
3762
3763     fib_prefix_t pfx_0_0 = {
3764         .fp_len = 0,
3765         .fp_proto = FIB_PROTOCOL_IP6,
3766         .fp_addr = {
3767             .ip6 = {
3768                 {0, 0},
3769             },
3770         },
3771     };
3772
3773     dfrt = fib_table_lookup(fib_index, &pfx_0_0);
3774     FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
3775     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3776              "Default route is DROP");
3777
3778     dpo = fib_entry_contribute_ip_forwarding(dfrt);
3779     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3780                                      &ip6_main,
3781                                      1,
3782                                      &pfx_0_0.fp_addr.ip6)),
3783              "default-route; fwd and non-fwd tables match");
3784
3785     // FIXME - check specials.
3786
3787     /*
3788      * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
3789      * each with 2 entries and a v6 mfib with 4 path-lists.
3790      * All entries are special so no path-list sharing.
3791      */
3792 #define ENPS (5+4)
3793 #define PNPS (5+4+4)
3794     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
3795     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
3796              fib_path_list_pool_size());
3797     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
3798              fib_entry_pool_size());
3799
3800     /*
3801      * add interface routes.
3802      *  validate presence of /64 attached and /128 recieve.
3803      *  test for the presence of the receive address in the glean and local adj
3804      *
3805      * receive on 2001:0:0:1::1/128
3806      */
3807     fib_prefix_t local_pfx = {
3808         .fp_len = 64,
3809         .fp_proto = FIB_PROTOCOL_IP6,
3810         .fp_addr = {
3811             .ip6 = {
3812                 .as_u64 = {
3813                     [0] = clib_host_to_net_u64(0x2001000000000001),
3814                     [1] = clib_host_to_net_u64(0x0000000000000001),
3815                 },
3816             },
3817         }
3818     };
3819
3820     fib_table_entry_update_one_path(fib_index, &local_pfx,
3821                                     FIB_SOURCE_INTERFACE,
3822                                     (FIB_ENTRY_FLAG_CONNECTED |
3823                                      FIB_ENTRY_FLAG_ATTACHED),
3824                                     FIB_PROTOCOL_IP6,
3825                                     NULL,
3826                                     tm->hw[0]->sw_if_index,
3827                                     ~0,
3828                                     1,
3829                                     NULL,
3830                                     FIB_ROUTE_PATH_FLAG_NONE);
3831     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3832
3833     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3834
3835     ai = fib_entry_get_adj(fei);
3836     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
3837     adj = adj_get(ai);
3838     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3839              "attached interface adj is glean");
3840     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3841                                     &adj->sub_type.glean.receive_addr)),
3842               "attached interface adj is receive ok");
3843     dpo = fib_entry_contribute_ip_forwarding(fei);
3844     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3845                                      &ip6_main,
3846                                      1,
3847                                      &local_pfx.fp_addr.ip6)),
3848              "attached-route; fwd and non-fwd tables match");
3849
3850     local_pfx.fp_len = 128;
3851     fib_table_entry_update_one_path(fib_index, &local_pfx,
3852                                     FIB_SOURCE_INTERFACE,
3853                                     (FIB_ENTRY_FLAG_CONNECTED |
3854                                      FIB_ENTRY_FLAG_LOCAL),
3855                                     FIB_PROTOCOL_IP6,
3856                                     NULL,
3857                                     tm->hw[0]->sw_if_index,
3858                                     ~0, // invalid fib index
3859                                     1,
3860                                     NULL,
3861                                     FIB_ROUTE_PATH_FLAG_NONE);
3862     fei = fib_table_lookup(fib_index, &local_pfx);
3863
3864     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3865
3866     dpo = fib_entry_contribute_ip_forwarding(fei);
3867     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3868     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3869              "local interface adj is local");
3870     rd = receive_dpo_get(dpo->dpoi_index);
3871
3872     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3873                                     &rd->rd_addr)),
3874               "local interface adj is receive ok");
3875
3876     dpo = fib_entry_contribute_ip_forwarding(fei);
3877     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3878                                      &ip6_main,
3879                                      1,
3880                                      &local_pfx.fp_addr.ip6)),
3881              "local-route; fwd and non-fwd tables match");
3882
3883     /*
3884      * +2 entries. +2 unshared path-lists
3885      */
3886     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
3887     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3888              fib_path_list_pool_size());
3889     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3890              fib_entry_pool_size());
3891
3892     /*
3893      * Modify the default route to be via an adj not yet known.
3894      * this sources the defalut route with the API source, which is
3895      * a higher preference to the DEFAULT_ROUTE source
3896      */
3897     fib_table_entry_path_add(fib_index, &pfx_0_0,
3898                              FIB_SOURCE_API,
3899                              FIB_ENTRY_FLAG_NONE,
3900                              FIB_PROTOCOL_IP6,
3901                              &nh_2001_2,
3902                              tm->hw[0]->sw_if_index,
3903                              ~0,
3904                              1,
3905                              NULL,
3906                              FIB_ROUTE_PATH_FLAG_NONE);
3907     fei = fib_table_lookup(fib_index, &pfx_0_0);
3908
3909     FIB_TEST((fei == dfrt), "default route same index");
3910     ai = fib_entry_get_adj(fei);
3911     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
3912     adj = adj_get(ai);
3913     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3914              "adj is incomplete");
3915     FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
3916               "adj nbr next-hop ok");
3917
3918     /*
3919      * find the adj in the shared db
3920      */
3921     locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3922                                     VNET_LINK_IP6,
3923                                     &nh_2001_2,
3924                                     tm->hw[0]->sw_if_index);
3925     FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
3926     adj_unlock(locked_ai);
3927
3928     /*
3929      * no more entires. +1 shared path-list
3930      */
3931     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
3932              fib_path_list_db_size());
3933     FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
3934              fib_path_list_pool_size());
3935     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3936              fib_entry_pool_size());
3937
3938     /*
3939      * remove the API source from the default route. We expected
3940      * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
3941      */
3942     fib_table_entry_path_remove(fib_index, &pfx_0_0,
3943                                 FIB_SOURCE_API, 
3944                                 FIB_PROTOCOL_IP6,
3945                                 &nh_2001_2,
3946                                 tm->hw[0]->sw_if_index,
3947                                 ~0,
3948                                 1,
3949                                 FIB_ROUTE_PATH_FLAG_NONE);
3950     fei = fib_table_lookup(fib_index, &pfx_0_0);
3951
3952     FIB_TEST((fei == dfrt), "default route same index");
3953     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3954              "Default route is DROP");
3955
3956     /*
3957      * no more entires. -1 shared path-list
3958      */
3959     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
3960              fib_path_list_db_size());
3961     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3962              fib_path_list_pool_size());
3963     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3964              fib_entry_pool_size());
3965
3966     /*
3967      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3968      */
3969     fib_prefix_t pfx_2001_1_2_s_128 = {
3970         .fp_len   = 128,
3971         .fp_proto = FIB_PROTOCOL_IP6,
3972         .fp_addr  = {
3973             .ip6 = {
3974                 .as_u64 = {
3975                     [0] = clib_host_to_net_u64(0x2001000000000001),
3976                     [1] = clib_host_to_net_u64(0x0000000000000002),
3977                 },
3978             },
3979         }
3980     };
3981     fib_prefix_t pfx_2001_1_3_s_128 = {
3982         .fp_len   = 128,
3983         .fp_proto = FIB_PROTOCOL_IP6,
3984         .fp_addr  = {
3985             .ip6 = {
3986                 .as_u64 = {
3987                     [0] = clib_host_to_net_u64(0x2001000000000001),
3988                     [1] = clib_host_to_net_u64(0x0000000000000003),
3989                 },
3990             },
3991         }
3992     };
3993     u8 eth_addr[] = {
3994         0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
3995     };
3996
3997     ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3998                                 VNET_LINK_IP6,
3999                                 &pfx_2001_1_2_s_128.fp_addr,
4000                                 tm->hw[0]->sw_if_index);
4001     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4002     adj = adj_get(ai_01);
4003     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4004              "adj is incomplete");
4005     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4006                                     &adj->sub_type.nbr.next_hop)),
4007               "adj nbr next-hop ok");
4008
4009     adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4010                            fib_test_build_rewrite(eth_addr));
4011     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4012              "adj is complete");
4013     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4014                                     &adj->sub_type.nbr.next_hop)),
4015               "adj nbr next-hop ok");
4016
4017     fib_table_entry_update_one_path(fib_index,
4018                                     &pfx_2001_1_2_s_128,
4019                                     FIB_SOURCE_ADJ,
4020                                     FIB_ENTRY_FLAG_ATTACHED,
4021                                     FIB_PROTOCOL_IP6,
4022                                     &pfx_2001_1_2_s_128.fp_addr,
4023                                     tm->hw[0]->sw_if_index,
4024                                     ~0,
4025                                     1,
4026                                     NULL,
4027                                     FIB_ROUTE_PATH_FLAG_NONE);
4028
4029     fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4030     ai = fib_entry_get_adj(fei);
4031     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4032
4033     eth_addr[5] = 0xb2;
4034
4035     ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4036                                 VNET_LINK_IP6,
4037                                 &pfx_2001_1_3_s_128.fp_addr,
4038                                 tm->hw[0]->sw_if_index);
4039     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4040     adj = adj_get(ai_02);
4041     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4042              "adj is incomplete");
4043     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4044                                     &adj->sub_type.nbr.next_hop)),
4045               "adj nbr next-hop ok");
4046
4047     adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4048                            fib_test_build_rewrite(eth_addr));
4049     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4050              "adj is complete");
4051     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4052                                     &adj->sub_type.nbr.next_hop)),
4053               "adj nbr next-hop ok");
4054     FIB_TEST((ai_01 != ai_02), "ADJs are different");
4055
4056     fib_table_entry_update_one_path(fib_index,
4057                                     &pfx_2001_1_3_s_128,
4058                                     FIB_SOURCE_ADJ,
4059                                     FIB_ENTRY_FLAG_ATTACHED,
4060                                     FIB_PROTOCOL_IP6,
4061                                     &pfx_2001_1_3_s_128.fp_addr,
4062                                     tm->hw[0]->sw_if_index,
4063                                     ~0,
4064                                     1,
4065                                     NULL,
4066                                     FIB_ROUTE_PATH_FLAG_NONE);
4067
4068     fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4069     ai = fib_entry_get_adj(fei);
4070     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4071
4072     /*
4073      * +2 entries, +2 unshread path-lists.
4074      */
4075     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4076              fib_path_list_db_size());
4077     FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4078              fib_path_list_pool_size());
4079     FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4080              fib_entry_pool_size());
4081
4082     /*
4083      * Add a 2 routes via the first ADJ. ensure path-list sharing
4084      */
4085     fib_prefix_t pfx_2001_a_s_64 = {
4086         .fp_len   = 64,
4087         .fp_proto = FIB_PROTOCOL_IP6,
4088         .fp_addr  = {
4089             .ip6 = {
4090                 .as_u64 = {
4091                     [0] = clib_host_to_net_u64(0x200100000000000a),
4092                     [1] = clib_host_to_net_u64(0x0000000000000000),
4093                 },
4094             },
4095         }
4096     };
4097     fib_prefix_t pfx_2001_b_s_64 = {
4098         .fp_len   = 64,
4099         .fp_proto = FIB_PROTOCOL_IP6,
4100         .fp_addr  = {
4101             .ip6 = {
4102                 .as_u64 = {
4103                     [0] = clib_host_to_net_u64(0x200100000000000b),
4104                     [1] = clib_host_to_net_u64(0x0000000000000000),
4105                 },
4106             },
4107         }
4108     };
4109
4110     fib_table_entry_path_add(fib_index,
4111                              &pfx_2001_a_s_64,
4112                              FIB_SOURCE_API,
4113                              FIB_ENTRY_FLAG_NONE,
4114                              FIB_PROTOCOL_IP6,
4115                              &nh_2001_2,
4116                              tm->hw[0]->sw_if_index,
4117                              ~0,
4118                              1,
4119                              NULL,
4120                              FIB_ROUTE_PATH_FLAG_NONE);
4121     fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4122     ai = fib_entry_get_adj(fei);
4123     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4124     fib_table_entry_path_add(fib_index,
4125                              &pfx_2001_b_s_64,
4126                              FIB_SOURCE_API,
4127                              FIB_ENTRY_FLAG_NONE,
4128                              FIB_PROTOCOL_IP6,
4129                              &nh_2001_2,
4130                              tm->hw[0]->sw_if_index,
4131                              ~0,
4132                              1,
4133                              NULL,
4134                              FIB_ROUTE_PATH_FLAG_NONE);
4135     fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4136     ai = fib_entry_get_adj(fei);
4137     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4138
4139     /*
4140      * +2 entries, +1 shared path-list.
4141      */
4142     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4143              fib_path_list_db_size());
4144     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4145              fib_path_list_pool_size());
4146     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4147              fib_entry_pool_size());
4148
4149     /*
4150      * add a v4 prefix via a v6 next-hop
4151      */
4152     fib_prefix_t pfx_1_1_1_1_s_32 = {
4153         .fp_len = 32,
4154         .fp_proto = FIB_PROTOCOL_IP4,
4155         .fp_addr = {
4156             .ip4.as_u32 = 0x01010101,
4157         },
4158     };
4159     fei = fib_table_entry_path_add(0, // default table
4160                                    &pfx_1_1_1_1_s_32,
4161                                    FIB_SOURCE_API,
4162                                    FIB_ENTRY_FLAG_NONE,
4163                                    FIB_PROTOCOL_IP6,
4164                                    &nh_2001_2,
4165                                    tm->hw[0]->sw_if_index,
4166                                    ~0,
4167                                    1,
4168                                    NULL,
4169                                    FIB_ROUTE_PATH_FLAG_NONE);
4170     FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4171              "1.1.1.1/32 o v6 route present");
4172     ai = fib_entry_get_adj(fei);
4173     adj = adj_get(ai);
4174     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4175              "1.1.1.1/32 via ARP-adj");
4176     FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4177              "1.1.1.1/32 ADJ-adj is link type v4");
4178     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4179              "1.1.1.1/32 ADJ-adj is NH proto v6");
4180     fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4181
4182     /*
4183      * An attached route
4184      */
4185     fib_prefix_t pfx_2001_c_s_64 = {
4186         .fp_len   = 64,
4187         .fp_proto = FIB_PROTOCOL_IP6,
4188         .fp_addr  = {
4189             .ip6 = {
4190                 .as_u64 = {
4191                     [0] = clib_host_to_net_u64(0x200100000000000c),
4192                     [1] = clib_host_to_net_u64(0x0000000000000000),
4193                 },
4194             },
4195         }
4196     };
4197     fib_table_entry_path_add(fib_index,
4198                              &pfx_2001_c_s_64,
4199                              FIB_SOURCE_CLI,
4200                              FIB_ENTRY_FLAG_ATTACHED,
4201                              FIB_PROTOCOL_IP6,
4202                              NULL,
4203                              tm->hw[0]->sw_if_index,
4204                              ~0,
4205                              1,
4206                              NULL,
4207                              FIB_ROUTE_PATH_FLAG_NONE);
4208     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4209     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4210     ai = fib_entry_get_adj(fei);
4211     adj = adj_get(ai);
4212     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4213              "2001:0:0:c/64 attached resolves via glean");
4214
4215     fib_table_entry_path_remove(fib_index,
4216                                 &pfx_2001_c_s_64,
4217                                 FIB_SOURCE_CLI,
4218                                 FIB_PROTOCOL_IP6,
4219                                 NULL,
4220                                 tm->hw[0]->sw_if_index,
4221                                 ~0,
4222                                 1,
4223                                 FIB_ROUTE_PATH_FLAG_NONE);
4224     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4225     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4226
4227     /*
4228      * Shutdown the interface on which we have a connected and through
4229      * which the routes are reachable.
4230      * This will result in the connected, adj-fibs, and routes linking to drop
4231      * The local/for-us prefix continues to receive.
4232      */
4233     clib_error_t * error;
4234
4235     error = vnet_sw_interface_set_flags(vnet_get_main(),
4236                                         tm->hw[0]->sw_if_index,
4237                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4238     FIB_TEST((NULL == error), "Interface shutdown OK");
4239
4240     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4241     dpo = fib_entry_contribute_ip_forwarding(fei);
4242     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4243              "2001::b/64 resolves via drop");
4244
4245     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4246     dpo = fib_entry_contribute_ip_forwarding(fei);
4247     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4248              "2001::a/64 resolves via drop");
4249     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4250     dpo = fib_entry_contribute_ip_forwarding(fei);
4251     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4252              "2001:0:0:1::3/64 resolves via drop");
4253     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4254     dpo = fib_entry_contribute_ip_forwarding(fei);
4255     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4256              "2001:0:0:1::2/64 resolves via drop");
4257     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4258     dpo = fib_entry_contribute_ip_forwarding(fei);
4259     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4260              "2001:0:0:1::1/128 not drop");
4261     local_pfx.fp_len = 64;
4262     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4263     dpo = fib_entry_contribute_ip_forwarding(fei);
4264     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4265              "2001:0:0:1/64 resolves via drop");
4266
4267     /*
4268      * no change
4269      */
4270     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4271              fib_path_list_db_size());
4272     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4273              fib_path_list_pool_size());
4274     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4275              fib_entry_pool_size());
4276
4277     /*
4278      * shutdown one of the other interfaces, then add a connected.
4279      * and swap one of the routes to it.
4280      */
4281     error = vnet_sw_interface_set_flags(vnet_get_main(),
4282                                         tm->hw[1]->sw_if_index,
4283                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4284     FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4285
4286     fib_prefix_t connected_pfx = {
4287         .fp_len = 64,
4288         .fp_proto = FIB_PROTOCOL_IP6,
4289         .fp_addr = {
4290             .ip6 = {
4291                 /* 2001:0:0:2::1/64 */
4292                 .as_u64 = {
4293                     [0] = clib_host_to_net_u64(0x2001000000000002),
4294                     [1] = clib_host_to_net_u64(0x0000000000000001),
4295                 },
4296             },
4297         }
4298     };
4299     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4300                                     FIB_SOURCE_INTERFACE,
4301                                     (FIB_ENTRY_FLAG_CONNECTED |
4302                                      FIB_ENTRY_FLAG_ATTACHED),
4303                                     FIB_PROTOCOL_IP6,
4304                                     NULL,
4305                                     tm->hw[1]->sw_if_index,
4306                                     ~0,
4307                                     1,
4308                                     NULL,
4309                                     FIB_ROUTE_PATH_FLAG_NONE);
4310     fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4311     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4312     dpo = fib_entry_contribute_ip_forwarding(fei);
4313     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4314     FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4315              "2001:0:0:2/64 not resolves via drop");
4316
4317     connected_pfx.fp_len = 128;
4318     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4319                                     FIB_SOURCE_INTERFACE,
4320                                     (FIB_ENTRY_FLAG_CONNECTED |
4321                                      FIB_ENTRY_FLAG_LOCAL),
4322                                     FIB_PROTOCOL_IP6,
4323                                     NULL,
4324                                     tm->hw[0]->sw_if_index,
4325                                     ~0, // invalid fib index
4326                                     1,
4327                                     NULL,
4328                                     FIB_ROUTE_PATH_FLAG_NONE);
4329     fei = fib_table_lookup(fib_index, &connected_pfx);
4330
4331     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4332     dpo = fib_entry_contribute_ip_forwarding(fei);
4333     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4334     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4335              "local interface adj is local");
4336     rd = receive_dpo_get(dpo->dpoi_index);
4337     FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4338                                     &rd->rd_addr)),
4339               "local interface adj is receive ok");
4340
4341     /*
4342      * +2 entries, +2 unshared path-lists
4343      */
4344     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4345              fib_path_list_db_size());
4346     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4347              fib_path_list_pool_size());
4348     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4349              fib_entry_pool_size());
4350
4351
4352     /*
4353      * bring the interface back up. we expected the routes to return
4354      * to normal forwarding.
4355      */
4356     error = vnet_sw_interface_set_flags(vnet_get_main(),
4357                                         tm->hw[0]->sw_if_index,
4358                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4359     FIB_TEST((NULL == error), "Interface bring-up OK");
4360     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4361     ai = fib_entry_get_adj(fei);
4362     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4363     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4364     ai = fib_entry_get_adj(fei);
4365     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4366     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4367     ai = fib_entry_get_adj(fei);
4368     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4369     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4370     ai = fib_entry_get_adj(fei);
4371     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4372     local_pfx.fp_len = 64;
4373     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4374     ai = fib_entry_get_adj(fei);
4375     adj = adj_get(ai);
4376     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4377              "attached interface adj is glean");
4378
4379     /*
4380      * Same test as above, but this time the HW interface goes down
4381      */
4382     error = vnet_hw_interface_set_flags(vnet_get_main(),
4383                                         tm->hw_if_indicies[0],
4384                                         ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4385     FIB_TEST((NULL == error), "Interface shutdown OK");
4386
4387     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4388     dpo = fib_entry_contribute_ip_forwarding(fei);
4389     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4390              "2001::b/64 resolves via drop");
4391     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4392     dpo = fib_entry_contribute_ip_forwarding(fei);
4393     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4394              "2001::a/64 resolves via drop");
4395     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4396     dpo = fib_entry_contribute_ip_forwarding(fei);
4397     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4398              "2001:0:0:1::3/128 resolves via drop");
4399     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4400     dpo = fib_entry_contribute_ip_forwarding(fei);
4401     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4402              "2001:0:0:1::2/128 resolves via drop");
4403     local_pfx.fp_len = 128;
4404     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4405     dpo = fib_entry_contribute_ip_forwarding(fei);
4406     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4407              "2001:0:0:1::1/128 not drop");
4408     local_pfx.fp_len = 64;
4409     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4410     dpo = fib_entry_contribute_ip_forwarding(fei);
4411     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4412              "2001:0:0:1/64 resolves via drop");
4413
4414     error = vnet_hw_interface_set_flags(vnet_get_main(),
4415                                         tm->hw_if_indicies[0],
4416                                         VNET_HW_INTERFACE_FLAG_LINK_UP);
4417     FIB_TEST((NULL == error), "Interface bring-up OK");
4418     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4419     ai = fib_entry_get_adj(fei);
4420     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4421     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4422     ai = fib_entry_get_adj(fei);
4423     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4424     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4425     ai = fib_entry_get_adj(fei);
4426     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4427     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4428     ai = fib_entry_get_adj(fei);
4429     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4430     local_pfx.fp_len = 64;
4431     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4432     ai = fib_entry_get_adj(fei);
4433     adj = adj_get(ai);
4434     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4435              "attached interface adj is glean");
4436
4437     /*
4438      * Delete the interface that the routes reolve through.
4439      * Again no routes are removed. They all point to drop.
4440      *
4441      * This is considered an error case. The control plane should
4442      * not remove interfaces through which routes resolve, but
4443      * such things can happen. ALL affected routes will drop.
4444      */
4445     vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4446
4447     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4448     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4449              "2001::b/64 resolves via drop");
4450     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4451     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4452              "2001::b/64 resolves via drop");
4453     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4454     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4455              "2001:0:0:1::3/64 resolves via drop");
4456     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4457     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4458              "2001:0:0:1::2/64 resolves via drop");
4459     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4460     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4461              "2001:0:0:1::1/128 is drop");
4462     local_pfx.fp_len = 64;
4463     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4464     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4465              "2001:0:0:1/64 resolves via drop");
4466
4467     /*
4468      * no change
4469      */
4470     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4471              fib_path_list_db_size());
4472     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4473              fib_path_list_pool_size());
4474     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4475              fib_entry_pool_size());
4476
4477     /*
4478      * Add the interface back. routes stay unresolved.
4479      */
4480     error = ethernet_register_interface(vnet_get_main(),
4481                                         test_interface_device_class.index,
4482                                         0 /* instance */,
4483                                         hw_address,
4484                                         &tm->hw_if_indicies[0],
4485                                         /* flag change */ 0);
4486
4487     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4488     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4489              "2001::b/64 resolves via drop");
4490     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4491     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4492              "2001::b/64 resolves via drop");
4493     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4494     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4495              "2001:0:0:1::3/64 resolves via drop");
4496     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4497     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4498              "2001:0:0:1::2/64 resolves via drop");
4499     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4500     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4501              "2001:0:0:1::1/128 is drop");
4502     local_pfx.fp_len = 64;
4503     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4504     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4505              "2001:0:0:1/64 resolves via drop");
4506
4507     /*
4508      * CLEANUP ALL the routes
4509      */
4510     fib_table_entry_delete(fib_index,
4511                            &pfx_2001_c_s_64,
4512                            FIB_SOURCE_API);
4513     fib_table_entry_delete(fib_index,
4514                            &pfx_2001_a_s_64,
4515                            FIB_SOURCE_API);
4516     fib_table_entry_delete(fib_index,
4517                            &pfx_2001_b_s_64,
4518                            FIB_SOURCE_API);
4519     fib_table_entry_delete(fib_index,
4520                            &pfx_2001_1_3_s_128,
4521                            FIB_SOURCE_ADJ);
4522     fib_table_entry_delete(fib_index,
4523                            &pfx_2001_1_2_s_128,
4524                            FIB_SOURCE_ADJ);
4525     local_pfx.fp_len = 64;
4526     fib_table_entry_delete(fib_index, &local_pfx,
4527                            FIB_SOURCE_INTERFACE);
4528     local_pfx.fp_len = 128;
4529     fib_table_entry_special_remove(fib_index, &local_pfx,
4530                                    FIB_SOURCE_INTERFACE);
4531     connected_pfx.fp_len = 64;
4532     fib_table_entry_delete(fib_index, &connected_pfx,
4533                            FIB_SOURCE_INTERFACE);
4534     connected_pfx.fp_len = 128;
4535     fib_table_entry_special_remove(fib_index, &connected_pfx,
4536                                    FIB_SOURCE_INTERFACE);
4537
4538     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4539               fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4540              "2001::a/64 removed");
4541     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4542               fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4543              "2001::b/64 removed");
4544     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4545               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4546              "2001:0:0:1::3/128 removed");
4547     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4548               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4549              "2001:0:0:1::3/128 removed");
4550     local_pfx.fp_len = 64;
4551     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4552               fib_table_lookup_exact_match(fib_index, &local_pfx)),
4553              "2001:0:0:1/64 removed");
4554     local_pfx.fp_len = 128;
4555     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4556               fib_table_lookup_exact_match(fib_index, &local_pfx)),
4557              "2001:0:0:1::1/128 removed");
4558     connected_pfx.fp_len = 64;
4559     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4560               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4561              "2001:0:0:2/64 removed");
4562     connected_pfx.fp_len = 128;
4563     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4564               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4565              "2001:0:0:2::1/128 removed");
4566
4567     /*
4568      * -8 entries. -7 path-lists (1 was shared).
4569      */
4570     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4571              fib_path_list_db_size());
4572     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
4573              fib_path_list_pool_size());
4574     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4575              fib_entry_pool_size());
4576
4577     /*
4578      * now remove the VRF
4579      */
4580     fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4581
4582     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4583              fib_path_list_db_size());
4584     FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
4585              fib_path_list_pool_size());
4586     FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
4587              fib_entry_pool_size());
4588
4589     adj_unlock(ai_02);
4590     adj_unlock(ai_01);
4591
4592     /*
4593      * return the interfaces to up state
4594      */
4595     error = vnet_sw_interface_set_flags(vnet_get_main(),
4596                                         tm->hw[0]->sw_if_index,
4597                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4598     error = vnet_sw_interface_set_flags(vnet_get_main(),
4599                                         tm->hw[1]->sw_if_index,
4600                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4601
4602     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4603              adj_nbr_db_size());
4604
4605     return (0);
4606 }
4607
4608 /*
4609  * Test Attached Exports
4610  */
4611 static int
4612 fib_test_ae (void)
4613 {
4614     const dpo_id_t *dpo, *dpo_drop;
4615     const u32 fib_index = 0;
4616     fib_node_index_t fei;
4617     test_main_t *tm;
4618     ip4_main_t *im;
4619
4620     tm = &test_main;
4621     im = &ip4_main;
4622
4623     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4624              adj_nbr_db_size());
4625
4626     /*
4627      * add interface routes. We'll assume this works. It's more rigorously
4628      * tested elsewhere.
4629      */
4630     fib_prefix_t local_pfx = {
4631         .fp_len = 24,
4632         .fp_proto = FIB_PROTOCOL_IP4,
4633         .fp_addr = {
4634             .ip4 = {
4635                 /* 10.10.10.10 */
4636                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4637             },
4638         },
4639     };
4640
4641     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4642     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4643
4644     dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4645
4646     fib_table_entry_update_one_path(fib_index, &local_pfx,
4647                                     FIB_SOURCE_INTERFACE,
4648                                     (FIB_ENTRY_FLAG_CONNECTED |
4649                                      FIB_ENTRY_FLAG_ATTACHED),
4650                                     FIB_PROTOCOL_IP4,
4651                                     NULL,
4652                                     tm->hw[0]->sw_if_index,
4653                                     ~0,
4654                                     1,
4655                                     NULL,
4656                                     FIB_ROUTE_PATH_FLAG_NONE);
4657     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4658     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4659              "attached interface route present");
4660
4661     local_pfx.fp_len = 32;
4662     fib_table_entry_update_one_path(fib_index, &local_pfx,
4663                                     FIB_SOURCE_INTERFACE,
4664                                     (FIB_ENTRY_FLAG_CONNECTED |
4665                                      FIB_ENTRY_FLAG_LOCAL),
4666                                     FIB_PROTOCOL_IP4,
4667                                     NULL,
4668                                     tm->hw[0]->sw_if_index,
4669                                     ~0, // invalid fib index
4670                                     1,
4671                                     NULL,
4672                                     FIB_ROUTE_PATH_FLAG_NONE);
4673     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4674
4675     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4676              "local interface route present");
4677
4678     /*
4679      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4680      */
4681     fib_prefix_t pfx_10_10_10_1_s_32 = {
4682         .fp_len = 32,
4683         .fp_proto = FIB_PROTOCOL_IP4,
4684         .fp_addr = {
4685             /* 10.10.10.1 */
4686             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4687         },
4688     };
4689     fib_node_index_t ai;
4690
4691     fib_table_entry_update_one_path(fib_index,
4692                                     &pfx_10_10_10_1_s_32,
4693                                     FIB_SOURCE_ADJ,
4694                                     FIB_ENTRY_FLAG_ATTACHED,
4695                                     FIB_PROTOCOL_IP4,
4696                                     &pfx_10_10_10_1_s_32.fp_addr,
4697                                     tm->hw[0]->sw_if_index,
4698                                     ~0, // invalid fib index
4699                                     1,
4700                                     NULL,
4701                                     FIB_ROUTE_PATH_FLAG_NONE);
4702
4703     fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4704     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4705     ai = fib_entry_get_adj(fei);
4706
4707     /*
4708      * create another FIB table into which routes will be imported
4709      */
4710     u32 import_fib_index1;
4711
4712     import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4713
4714     /*
4715      * Add an attached route in the import FIB
4716      */
4717     local_pfx.fp_len = 24;
4718     fib_table_entry_update_one_path(import_fib_index1,
4719                                     &local_pfx,
4720                                     FIB_SOURCE_API,
4721                                     FIB_ENTRY_FLAG_NONE,
4722                                     FIB_PROTOCOL_IP4,
4723                                     NULL,
4724                                     tm->hw[0]->sw_if_index,
4725                                     ~0, // invalid fib index
4726                                     1,
4727                                     NULL,
4728                                     FIB_ROUTE_PATH_FLAG_NONE);
4729     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4730     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4731
4732     /*
4733      * check for the presence of the adj-fibs in the import table
4734      */
4735     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4736     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4737     FIB_TEST((ai == fib_entry_get_adj(fei)),
4738              "adj-fib1 Import uses same adj as export");
4739
4740     /*
4741      * check for the presence of the local in the import table
4742      */
4743     local_pfx.fp_len = 32;
4744     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4745     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4746
4747     /*
4748      * Add another adj-fin in the export table. Expect this
4749      * to get magically exported;
4750      */
4751     fib_prefix_t pfx_10_10_10_2_s_32 = {
4752         .fp_len = 32,
4753         .fp_proto = FIB_PROTOCOL_IP4,
4754         .fp_addr = {
4755             /* 10.10.10.2 */
4756             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4757         },
4758     };
4759
4760     fib_table_entry_update_one_path(fib_index,
4761                                     &pfx_10_10_10_2_s_32,
4762                                     FIB_SOURCE_ADJ,
4763                                     FIB_ENTRY_FLAG_ATTACHED,
4764                                     FIB_PROTOCOL_IP4,
4765                                     &pfx_10_10_10_2_s_32.fp_addr,
4766                                     tm->hw[0]->sw_if_index,
4767                                     ~0, // invalid fib index
4768                                     1,
4769                                     NULL,
4770                                     FIB_ROUTE_PATH_FLAG_NONE);
4771     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4772     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4773     ai = fib_entry_get_adj(fei);
4774
4775     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4776     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4777     FIB_TEST((ai == fib_entry_get_adj(fei)),
4778              "Import uses same adj as export");
4779     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
4780              "ADJ-fib2 imported flags %d",
4781              fib_entry_get_flags(fei));
4782
4783     /*
4784      * create a 2nd FIB table into which routes will be imported
4785      */
4786     u32 import_fib_index2;
4787
4788     import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4789
4790     /*
4791      * Add an attached route in the import FIB
4792      */
4793     local_pfx.fp_len = 24;
4794     fib_table_entry_update_one_path(import_fib_index2,
4795                                     &local_pfx,
4796                                     FIB_SOURCE_API,
4797                                     FIB_ENTRY_FLAG_NONE,
4798                                     FIB_PROTOCOL_IP4,
4799                                     NULL,
4800                                     tm->hw[0]->sw_if_index,
4801                                     ~0, // invalid fib index
4802                                     1,
4803                                     NULL,
4804                                     FIB_ROUTE_PATH_FLAG_NONE);
4805     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4806     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4807
4808     /*
4809      * check for the presence of all the adj-fibs and local in the import table
4810      */
4811     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4812     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4813     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4814     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4815     local_pfx.fp_len = 32;
4816     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4817     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4818
4819     /*
4820      * add a 3rd adj-fib. expect it to be exported to both tables.
4821      */
4822     fib_prefix_t pfx_10_10_10_3_s_32 = {
4823         .fp_len = 32,
4824         .fp_proto = FIB_PROTOCOL_IP4,
4825         .fp_addr = {
4826             /* 10.10.10.3 */
4827             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4828         },
4829     };
4830
4831     fib_table_entry_update_one_path(fib_index,
4832                                     &pfx_10_10_10_3_s_32,
4833                                     FIB_SOURCE_ADJ,
4834                                     FIB_ENTRY_FLAG_ATTACHED,
4835                                     FIB_PROTOCOL_IP4,
4836                                     &pfx_10_10_10_3_s_32.fp_addr,
4837                                     tm->hw[0]->sw_if_index,
4838                                     ~0, // invalid fib index
4839                                     1,
4840                                     NULL,
4841                                     FIB_ROUTE_PATH_FLAG_NONE);
4842     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4843     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4844     ai = fib_entry_get_adj(fei);
4845
4846     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4847     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4848     FIB_TEST((ai == fib_entry_get_adj(fei)),
4849              "Import uses same adj as export");
4850     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4851     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4852     FIB_TEST((ai == fib_entry_get_adj(fei)),
4853              "Import uses same adj as export");
4854
4855     /*
4856      * remove the 3rd adj fib. we expect it to be removed from both FIBs
4857      */
4858     fib_table_entry_delete(fib_index,
4859                            &pfx_10_10_10_3_s_32,
4860                            FIB_SOURCE_ADJ);
4861
4862     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4863     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4864
4865     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4866     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
4867
4868     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4869     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4870
4871     /*
4872      * remove the attached route from the 2nd FIB. expect the imported
4873      * entires to be removed
4874      */
4875     local_pfx.fp_len = 24;
4876     fib_table_entry_delete(import_fib_index2,
4877                            &local_pfx,
4878                            FIB_SOURCE_API);
4879     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4880     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4881
4882     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4883     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4884     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4885     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4886     local_pfx.fp_len = 32;
4887     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4888     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4889
4890     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4891     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4892     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4893     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4894     local_pfx.fp_len = 32;
4895     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4896     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4897
4898     /*
4899      * modify the route in FIB1 so it is no longer attached. expect the imported
4900      * entires to be removed
4901      */
4902     local_pfx.fp_len = 24;
4903     fib_table_entry_update_one_path(import_fib_index1,
4904                                     &local_pfx,
4905                                     FIB_SOURCE_API,
4906                                     FIB_ENTRY_FLAG_NONE,
4907                                     FIB_PROTOCOL_IP4,
4908                                     &pfx_10_10_10_2_s_32.fp_addr,
4909                                     tm->hw[0]->sw_if_index,
4910                                     ~0, // invalid fib index
4911                                     1,
4912                                     NULL,
4913                                     FIB_ROUTE_PATH_FLAG_NONE);
4914     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4915     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4916     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4917     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4918     local_pfx.fp_len = 32;
4919     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4920     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4921
4922     /*
4923      * modify it back to attached. expect the adj-fibs back
4924      */
4925     local_pfx.fp_len = 24;
4926     fib_table_entry_update_one_path(import_fib_index1,
4927                                     &local_pfx,
4928                                     FIB_SOURCE_API,
4929                                     FIB_ENTRY_FLAG_NONE,
4930                                     FIB_PROTOCOL_IP4,
4931                                     NULL,
4932                                     tm->hw[0]->sw_if_index,
4933                                     ~0, // invalid fib index
4934                                     1,
4935                                     NULL,
4936                                     FIB_ROUTE_PATH_FLAG_NONE);
4937     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4938     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4939     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4940     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4941     local_pfx.fp_len = 32;
4942     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4943     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4944
4945     /*
4946      * add a covering attached next-hop for the interface address, so we have
4947      * a valid adj to find when we check the forwarding tables
4948      */
4949     fib_prefix_t pfx_10_0_0_0_s_8 = {
4950         .fp_len = 8,
4951         .fp_proto = FIB_PROTOCOL_IP4,
4952         .fp_addr = {
4953             /* 10.0.0.0 */
4954             .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4955         },
4956     };
4957
4958     fei = fib_table_entry_update_one_path(fib_index,
4959                                           &pfx_10_0_0_0_s_8,
4960                                           FIB_SOURCE_API,
4961                                           FIB_ENTRY_FLAG_NONE,
4962                                           FIB_PROTOCOL_IP4,
4963                                           &pfx_10_10_10_3_s_32.fp_addr,
4964                                           tm->hw[0]->sw_if_index,
4965                                           ~0, // invalid fib index
4966                                           1,
4967                                           NULL,
4968                                           FIB_ROUTE_PATH_FLAG_NONE);
4969     dpo = fib_entry_contribute_ip_forwarding(fei);
4970
4971     /*
4972      * remove the route in the export fib. expect the adj-fibs to be removed
4973      */
4974     local_pfx.fp_len = 24;
4975     fib_table_entry_delete(fib_index,
4976                            &local_pfx,
4977                            FIB_SOURCE_INTERFACE);
4978
4979     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4980     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4981     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4982     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4983     local_pfx.fp_len = 32;
4984     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4985     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4986
4987     /*
4988      * the adj-fibs in the export VRF are present in the FIB table,
4989      * but not installed in forwarding, since they have no attached cover.
4990      * Consequently a lookup in the MTRIE gives the adj for the covering
4991      * route 10.0.0.0/8.
4992      */
4993     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4994     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4995
4996     index_t lbi;
4997     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4998     FIB_TEST(lbi == dpo->dpoi_index,
4999              "10.10.10.1 forwards on \n%U not \n%U",
5000              format_load_balance, lbi, 0,
5001              format_dpo_id, dpo, 0);
5002     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5003     FIB_TEST(lbi == dpo->dpoi_index,
5004              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5005     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5006     FIB_TEST(lbi == dpo->dpoi_index,
5007              "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5008
5009     /*
5010      * add the export prefix back, but not as attached.
5011      * No adj-fibs in export nor import tables
5012      */
5013     local_pfx.fp_len = 24;
5014     fei = fib_table_entry_update_one_path(fib_index,
5015                                           &local_pfx,
5016                                           FIB_SOURCE_API,
5017                                           FIB_ENTRY_FLAG_NONE,
5018                                           FIB_PROTOCOL_IP4,
5019                                           &pfx_10_10_10_1_s_32.fp_addr,
5020                                           tm->hw[0]->sw_if_index,
5021                                           ~0, // invalid fib index
5022                                           1,
5023                                           NULL,
5024                                           FIB_ROUTE_PATH_FLAG_NONE);
5025     dpo = fib_entry_contribute_ip_forwarding(fei);
5026
5027     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5028     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5029     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5030     FIB_TEST(lbi == dpo->dpoi_index,
5031              "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5032     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5033     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5034     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5035     FIB_TEST(lbi == dpo->dpoi_index,
5036              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5037
5038     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5039     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5040     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5041     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5042     local_pfx.fp_len = 32;
5043     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5044     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5045
5046     /*
5047      * modify the export prefix so it is attached. expect all covereds to return
5048      */
5049     local_pfx.fp_len = 24;
5050     fib_table_entry_update_one_path(fib_index,
5051                                     &local_pfx,
5052                                     FIB_SOURCE_API,
5053                                     FIB_ENTRY_FLAG_NONE,
5054                                     FIB_PROTOCOL_IP4,
5055                                     NULL,
5056                                     tm->hw[0]->sw_if_index,
5057                                     ~0, // invalid fib index
5058                                     1,
5059                                     NULL,
5060                                     FIB_ROUTE_PATH_FLAG_NONE);
5061
5062     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5063     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5064     dpo = fib_entry_contribute_ip_forwarding(fei);
5065     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5066              "Adj-fib1 is not drop in export");
5067     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5068     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5069     local_pfx.fp_len = 32;
5070     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5071     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5072     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5073     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5074     dpo = fib_entry_contribute_ip_forwarding(fei);
5075     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5076              "Adj-fib1 is not drop in export");
5077     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5078     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5079     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5080     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5081     local_pfx.fp_len = 32;
5082     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5083     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5084
5085     /*
5086      * modify the export prefix so connected. no change.
5087      */
5088     local_pfx.fp_len = 24;
5089     fib_table_entry_update_one_path(fib_index, &local_pfx,
5090                                     FIB_SOURCE_INTERFACE,
5091                                     (FIB_ENTRY_FLAG_CONNECTED |
5092                                      FIB_ENTRY_FLAG_ATTACHED),
5093                                     FIB_PROTOCOL_IP4,
5094                                     NULL,
5095                                     tm->hw[0]->sw_if_index,
5096                                     ~0,
5097                                     1,
5098                                     NULL,
5099                                     FIB_ROUTE_PATH_FLAG_NONE);
5100
5101     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5102     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5103     dpo = fib_entry_contribute_ip_forwarding(fei);
5104     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5105              "Adj-fib1 is not drop in export");
5106     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5107     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5108     local_pfx.fp_len = 32;
5109     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5110     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5111     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5112     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5113     dpo = fib_entry_contribute_ip_forwarding(fei);
5114     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5115              "Adj-fib1 is not drop in export");
5116     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5117     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5118     local_pfx.fp_len = 32;
5119     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5120     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5121
5122     /*
5123      * CLEANUP
5124      */
5125     fib_table_entry_delete(fib_index,
5126                            &pfx_10_0_0_0_s_8,
5127                            FIB_SOURCE_API);
5128     fib_table_entry_delete(fib_index,
5129                            &pfx_10_10_10_1_s_32,
5130                            FIB_SOURCE_ADJ);
5131     fib_table_entry_delete(fib_index,
5132                            &pfx_10_10_10_2_s_32,
5133                            FIB_SOURCE_ADJ);
5134     local_pfx.fp_len = 32;
5135     fib_table_entry_delete(fib_index,
5136                            &local_pfx,
5137                            FIB_SOURCE_INTERFACE);
5138     local_pfx.fp_len = 24;
5139     fib_table_entry_delete(fib_index,
5140                            &local_pfx,
5141                            FIB_SOURCE_API);
5142     fib_table_entry_delete(fib_index,
5143                            &local_pfx,
5144                            FIB_SOURCE_INTERFACE);
5145     local_pfx.fp_len = 24;
5146     fib_table_entry_delete(import_fib_index1,
5147                            &local_pfx,
5148                            FIB_SOURCE_API);
5149
5150     fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5151     fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5152
5153     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5154              adj_nbr_db_size());
5155
5156     return (0);
5157 }
5158
5159
5160 /*
5161  * Test the recursive route route handling for GRE tunnels
5162  */
5163 static int
5164 fib_test_label (void)
5165 {
5166     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;
5167     const u32 fib_index = 0;
5168     test_main_t *tm;
5169     ip4_main_t *im;
5170     int lb_count, ii;
5171
5172     lb_count = pool_elts(load_balance_pool);
5173     tm = &test_main;
5174     im = &ip4_main;
5175
5176     /*
5177      * add interface routes. We'll assume this works. It's more rigorously
5178      * tested elsewhere.
5179      */
5180     fib_prefix_t local0_pfx = {
5181         .fp_len = 24,
5182         .fp_proto = FIB_PROTOCOL_IP4,
5183         .fp_addr = {
5184             .ip4 = {
5185                 /* 10.10.10.10 */
5186                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5187             },
5188         },
5189     };
5190
5191     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5192              adj_nbr_db_size());
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     fib_table_entry_update_one_path(fib_index, &local0_pfx,
5198                                     FIB_SOURCE_INTERFACE,
5199                                     (FIB_ENTRY_FLAG_CONNECTED |
5200                                      FIB_ENTRY_FLAG_ATTACHED),
5201                                     FIB_PROTOCOL_IP4,
5202                                     NULL,
5203                                     tm->hw[0]->sw_if_index,
5204                                     ~0,
5205                                     1,
5206                                     NULL,
5207                                     FIB_ROUTE_PATH_FLAG_NONE);
5208     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5209     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5210              "attached interface route present");
5211
5212     local0_pfx.fp_len = 32;
5213     fib_table_entry_update_one_path(fib_index, &local0_pfx,
5214                                     FIB_SOURCE_INTERFACE,
5215                                     (FIB_ENTRY_FLAG_CONNECTED |
5216                                      FIB_ENTRY_FLAG_LOCAL),
5217                                     FIB_PROTOCOL_IP4,
5218                                     NULL,
5219                                     tm->hw[0]->sw_if_index,
5220                                     ~0, // invalid fib index
5221                                     1,
5222                                     NULL,
5223                                     FIB_ROUTE_PATH_FLAG_NONE);
5224     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5225
5226     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5227              "local interface route present");
5228
5229     fib_prefix_t local1_pfx = {
5230         .fp_len = 24,
5231         .fp_proto = FIB_PROTOCOL_IP4,
5232         .fp_addr = {
5233             .ip4 = {
5234                 /* 10.10.11.10 */
5235                 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5236             },
5237         },
5238     };
5239
5240     vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5241     im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5242
5243     fib_table_entry_update_one_path(fib_index, &local1_pfx,
5244                                     FIB_SOURCE_INTERFACE,
5245                                     (FIB_ENTRY_FLAG_CONNECTED |
5246                                      FIB_ENTRY_FLAG_ATTACHED),
5247                                     FIB_PROTOCOL_IP4,
5248                                     NULL,
5249                                     tm->hw[1]->sw_if_index,
5250                                     ~0,
5251                                     1,
5252                                     NULL,
5253                                     FIB_ROUTE_PATH_FLAG_NONE);
5254     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5255     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5256              "attached interface route present");
5257
5258     local1_pfx.fp_len = 32;
5259     fib_table_entry_update_one_path(fib_index, &local1_pfx,
5260                                     FIB_SOURCE_INTERFACE,
5261                                     (FIB_ENTRY_FLAG_CONNECTED |
5262                                      FIB_ENTRY_FLAG_LOCAL),
5263                                     FIB_PROTOCOL_IP4,
5264                                     NULL,
5265                                     tm->hw[1]->sw_if_index,
5266                                     ~0, // invalid fib index
5267                                     1,
5268                                     NULL,
5269                                     FIB_ROUTE_PATH_FLAG_NONE);
5270     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5271
5272     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5273              "local interface route present");
5274
5275     ip46_address_t nh_10_10_10_1 = {
5276         .ip4 = {
5277             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5278         },
5279     };
5280     ip46_address_t nh_10_10_11_1 = {
5281         .ip4 = {
5282             .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5283         },
5284     };
5285     ip46_address_t nh_10_10_11_2 = {
5286         .ip4 = {
5287             .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5288         },
5289     };
5290
5291     ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5292                                            VNET_LINK_IP4,
5293                                            &nh_10_10_11_1,
5294                                            tm->hw[1]->sw_if_index);
5295     ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5296                                            VNET_LINK_IP4,
5297                                            &nh_10_10_11_2,
5298                                            tm->hw[1]->sw_if_index);
5299     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5300                                              VNET_LINK_MPLS,
5301                                              &nh_10_10_10_1,
5302                                              tm->hw[0]->sw_if_index);
5303     ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5304                                              VNET_LINK_MPLS,
5305                                              &nh_10_10_11_2,
5306                                              tm->hw[1]->sw_if_index);
5307     ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5308                                              VNET_LINK_MPLS,
5309                                              &nh_10_10_11_1,
5310                                              tm->hw[1]->sw_if_index);
5311
5312     /*
5313      * Add an etry with one path with a real out-going label
5314      */
5315     fib_prefix_t pfx_1_1_1_1_s_32 = {
5316         .fp_len = 32,
5317         .fp_proto = FIB_PROTOCOL_IP4,
5318         .fp_addr = {
5319             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5320         },
5321     };
5322     fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5323         .type = FT_LB_LABEL_O_ADJ,
5324         .label_o_adj = {
5325             .adj = ai_mpls_10_10_10_1,
5326             .label = 99,
5327             .eos = MPLS_EOS,
5328         },
5329     };
5330     fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5331         .type = FT_LB_LABEL_O_ADJ,
5332         .label_o_adj = {
5333             .adj = ai_mpls_10_10_10_1,
5334             .label = 99,
5335             .eos = MPLS_NON_EOS,
5336         },
5337     };
5338     mpls_label_t *l99 = NULL;
5339     vec_add1(l99, 99);
5340
5341     fib_table_entry_update_one_path(fib_index,
5342                                     &pfx_1_1_1_1_s_32,
5343                                     FIB_SOURCE_API,
5344                                     FIB_ENTRY_FLAG_NONE,
5345                                     FIB_PROTOCOL_IP4,
5346                                     &nh_10_10_10_1,
5347                                     tm->hw[0]->sw_if_index,
5348                                     ~0, // invalid fib index
5349                                     1,
5350                                     l99,
5351                                     FIB_ROUTE_PATH_FLAG_NONE);
5352
5353     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5354     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5355
5356     FIB_TEST(fib_test_validate_entry(fei, 
5357                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5358                                      1,
5359                                      &l99_eos_o_10_10_10_1),
5360              "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5361
5362     /*
5363      * add a path with an implicit NULL label
5364      */
5365     fib_test_lb_bucket_t a_o_10_10_11_1 = {
5366         .type = FT_LB_ADJ,
5367         .adj = {
5368             .adj = ai_v4_10_10_11_1,
5369         },
5370     };
5371     fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5372         .type = FT_LB_ADJ,
5373         .adj = {
5374             .adj = ai_mpls_10_10_11_1,
5375         },
5376     };
5377     mpls_label_t *l_imp_null = NULL;
5378     vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5379
5380     fei = fib_table_entry_path_add(fib_index,
5381                                    &pfx_1_1_1_1_s_32,
5382                                    FIB_SOURCE_API,
5383                                    FIB_ENTRY_FLAG_NONE,
5384                                    FIB_PROTOCOL_IP4,
5385                                    &nh_10_10_11_1,
5386                                    tm->hw[1]->sw_if_index,
5387                                    ~0, // invalid fib index
5388                                    1,
5389                                    l_imp_null,
5390                                    FIB_ROUTE_PATH_FLAG_NONE);
5391
5392     FIB_TEST(fib_test_validate_entry(fei, 
5393                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5394                                      2,
5395                                      &l99_eos_o_10_10_10_1,
5396                                      &a_o_10_10_11_1),
5397              "1.1.1.1/32 LB 2 buckets via: "
5398              "label 99 over 10.10.10.1, "
5399              "adj over 10.10.11.1");
5400
5401     /*
5402      * assign the route a local label
5403      */
5404     fib_table_entry_local_label_add(fib_index,
5405                                     &pfx_1_1_1_1_s_32,
5406                                     24001);
5407
5408     fib_prefix_t pfx_24001_eos = {
5409         .fp_proto = FIB_PROTOCOL_MPLS,
5410         .fp_label = 24001,
5411         .fp_eos = MPLS_EOS,
5412     };
5413     fib_prefix_t pfx_24001_neos = {
5414         .fp_proto = FIB_PROTOCOL_MPLS,
5415         .fp_label = 24001,
5416         .fp_eos = MPLS_NON_EOS,
5417     };
5418
5419     /*
5420      * The EOS entry should link to both the paths,
5421      *  and use an ip adj for the imp-null
5422      * The NON-EOS entry should link to both the paths,
5423      *  and use an mpls adj for the imp-null
5424      */
5425     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5426                            &pfx_24001_eos);
5427     FIB_TEST(fib_test_validate_entry(fei, 
5428                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5429                                      2,
5430                                      &l99_eos_o_10_10_10_1,
5431                                      &a_o_10_10_11_1),
5432              "24001/eos LB 2 buckets via: "
5433              "label 99 over 10.10.10.1, "
5434              "adj over 10.10.11.1");
5435
5436
5437     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5438                            &pfx_24001_neos);
5439     FIB_TEST(fib_test_validate_entry(fei, 
5440                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5441                                      2,
5442                                      &l99_neos_o_10_10_10_1,
5443                                      &a_mpls_o_10_10_11_1),
5444              "24001/neos LB 1 bucket via: "
5445              "label 99 over 10.10.10.1 ",
5446              "mpls-adj via 10.10.11.1");
5447
5448     /*
5449      * add an unlabelled path, this is excluded from the neos chains,
5450      */
5451     fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5452         .type = FT_LB_ADJ,
5453         .adj = {
5454             .adj = ai_v4_10_10_11_2,
5455         },
5456     };
5457
5458     fei = fib_table_entry_path_add(fib_index,
5459                                    &pfx_1_1_1_1_s_32,
5460                                    FIB_SOURCE_API,
5461                                    FIB_ENTRY_FLAG_NONE,
5462                                    FIB_PROTOCOL_IP4,
5463                                    &nh_10_10_11_2,
5464                                    tm->hw[1]->sw_if_index,
5465                                    ~0, // invalid fib index
5466                                    1,
5467                                    NULL,
5468                                    FIB_ROUTE_PATH_FLAG_NONE);
5469
5470     FIB_TEST(fib_test_validate_entry(fei, 
5471                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5472                                      16, // 3 choices spread over 16 buckets
5473                                      &l99_eos_o_10_10_10_1,
5474                                      &l99_eos_o_10_10_10_1,
5475                                      &l99_eos_o_10_10_10_1,
5476                                      &l99_eos_o_10_10_10_1,
5477                                      &l99_eos_o_10_10_10_1,
5478                                      &l99_eos_o_10_10_10_1,
5479                                      &a_o_10_10_11_1,
5480                                      &a_o_10_10_11_1,
5481                                      &a_o_10_10_11_1,
5482                                      &a_o_10_10_11_1,
5483                                      &a_o_10_10_11_1,
5484                                      &adj_o_10_10_11_2,
5485                                      &adj_o_10_10_11_2,
5486                                      &adj_o_10_10_11_2,
5487                                      &adj_o_10_10_11_2,
5488                                      &adj_o_10_10_11_2),
5489              "1.1.1.1/32 LB 16 buckets via: "
5490              "label 99 over 10.10.10.1, "
5491              "adj over 10.10.11.1",
5492              "adj over 10.10.11.2");
5493
5494     /*
5495      * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5496      */
5497     dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5498     fib_entry_contribute_forwarding(fei,
5499                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5500                                     &non_eos_1_1_1_1);
5501
5502     /*
5503      * n-eos has only the 2 labelled paths
5504      */
5505     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5506                            &pfx_24001_neos);
5507
5508     FIB_TEST(fib_test_validate_entry(fei,
5509                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5510                                      2,
5511                                      &l99_neos_o_10_10_10_1,
5512                                      &a_mpls_o_10_10_11_1),
5513              "24001/neos LB 2 buckets via: "
5514              "label 99 over 10.10.10.1, "
5515              "adj-mpls over 10.10.11.2");
5516
5517     /*
5518      * A labelled recursive
5519      */
5520     fib_prefix_t pfx_2_2_2_2_s_32 = {
5521         .fp_len = 32,
5522         .fp_proto = FIB_PROTOCOL_IP4,
5523         .fp_addr = {
5524             .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5525         },
5526     };
5527     fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5528         .type = FT_LB_LABEL_O_LB,
5529         .label_o_lb = {
5530             .lb = non_eos_1_1_1_1.dpoi_index,
5531             .label = 1600,
5532             .eos = MPLS_EOS,
5533         },
5534     };
5535     mpls_label_t *l1600 = NULL;
5536     vec_add1(l1600, 1600);
5537
5538     fib_table_entry_update_one_path(fib_index,
5539                                     &pfx_2_2_2_2_s_32,
5540                                     FIB_SOURCE_API,
5541                                     FIB_ENTRY_FLAG_NONE,
5542                                     FIB_PROTOCOL_IP4,
5543                                     &pfx_1_1_1_1_s_32.fp_addr,
5544                                     ~0,
5545                                     fib_index,
5546                                     1,
5547                                     l1600,
5548                                     FIB_ROUTE_PATH_FLAG_NONE);
5549
5550     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5551     FIB_TEST(fib_test_validate_entry(fei, 
5552                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5553                                      1,
5554                                      &l1600_eos_o_1_1_1_1),
5555              "2.2.2.2.2/32 LB 1 buckets via: "
5556              "label 1600 over 1.1.1.1");
5557
5558     dpo_id_t dpo_44 = DPO_INVALID;
5559     index_t urpfi;
5560
5561     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5562     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5563
5564     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5565              "uRPF check for 2.2.2.2/32 on %d OK",
5566              tm->hw[0]->sw_if_index);
5567     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5568              "uRPF check for 2.2.2.2/32 on %d OK",
5569              tm->hw[1]->sw_if_index);
5570     FIB_TEST(!fib_urpf_check(urpfi, 99),
5571              "uRPF check for 2.2.2.2/32 on 99 not-OK",
5572              99);
5573
5574     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5575     FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5576              "Shared uRPF on IP and non-EOS chain");
5577
5578     dpo_reset(&dpo_44);
5579
5580     /*
5581      * we are holding a lock on the non-eos LB of the via-entry.
5582      * do a PIC-core failover by shutting the link of the via-entry.
5583      *
5584      * shut down the link with the valid label
5585      */
5586     vnet_sw_interface_set_flags(vnet_get_main(),
5587                                 tm->hw[0]->sw_if_index,
5588                                 0);
5589
5590     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5591     FIB_TEST(fib_test_validate_entry(fei, 
5592                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5593                                      2,
5594                                      &a_o_10_10_11_1,
5595                                      &adj_o_10_10_11_2),
5596              "1.1.1.1/32 LB 2 buckets via: "
5597              "adj over 10.10.11.1, ",
5598              "adj-v4 over 10.10.11.2");
5599
5600     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5601                            &pfx_24001_eos);
5602     FIB_TEST(fib_test_validate_entry(fei, 
5603                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5604                                      2,
5605                                      &a_o_10_10_11_1,
5606                                      &adj_o_10_10_11_2),
5607              "24001/eos LB 2 buckets via: "
5608              "adj over 10.10.11.1, ",
5609              "adj-v4 over 10.10.11.2");
5610
5611     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5612                            &pfx_24001_neos);
5613     FIB_TEST(fib_test_validate_entry(fei,
5614                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5615                                      1,
5616                                      &a_mpls_o_10_10_11_1),
5617              "24001/neos LB 1 buckets via: "
5618              "adj-mpls over 10.10.11.2");
5619
5620     /*
5621      * test that the pre-failover load-balance has been in-place
5622      * modified
5623      */
5624     dpo_id_t current = DPO_INVALID;
5625     fib_entry_contribute_forwarding(fei,
5626                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5627                                     &current);
5628
5629     FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5630                       &current),
5631              "PIC-core LB inplace modified %U %U",
5632              format_dpo_id, &non_eos_1_1_1_1, 0,
5633              format_dpo_id, &current, 0);
5634
5635     dpo_reset(&non_eos_1_1_1_1);
5636     dpo_reset(&current);
5637
5638     /*
5639      * no-shut the link with the valid label
5640      */
5641     vnet_sw_interface_set_flags(vnet_get_main(),
5642                                 tm->hw[0]->sw_if_index,
5643                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5644
5645     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5646     FIB_TEST(fib_test_validate_entry(fei, 
5647                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5648                                      16, // 3 choices spread over 16 buckets
5649                                      &l99_eos_o_10_10_10_1,
5650                                      &l99_eos_o_10_10_10_1,
5651                                      &l99_eos_o_10_10_10_1,
5652                                      &l99_eos_o_10_10_10_1,
5653                                      &l99_eos_o_10_10_10_1,
5654                                      &l99_eos_o_10_10_10_1,
5655                                      &a_o_10_10_11_1,
5656                                      &a_o_10_10_11_1,
5657                                      &a_o_10_10_11_1,
5658                                      &a_o_10_10_11_1,
5659                                      &a_o_10_10_11_1,
5660                                      &adj_o_10_10_11_2,
5661                                      &adj_o_10_10_11_2,
5662                                      &adj_o_10_10_11_2,
5663                                      &adj_o_10_10_11_2,
5664                                      &adj_o_10_10_11_2),
5665              "1.1.1.1/32 LB 16 buckets via: "
5666              "label 99 over 10.10.10.1, "
5667              "adj over 10.10.11.1",
5668              "adj-v4 over 10.10.11.2");
5669
5670
5671     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5672                            &pfx_24001_eos);
5673     FIB_TEST(fib_test_validate_entry(fei, 
5674                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5675                                      16, // 3 choices spread over 16 buckets
5676                                      &l99_eos_o_10_10_10_1,
5677                                      &l99_eos_o_10_10_10_1,
5678                                      &l99_eos_o_10_10_10_1,
5679                                      &l99_eos_o_10_10_10_1,
5680                                      &l99_eos_o_10_10_10_1,
5681                                      &l99_eos_o_10_10_10_1,
5682                                      &a_o_10_10_11_1,
5683                                      &a_o_10_10_11_1,
5684                                      &a_o_10_10_11_1,
5685                                      &a_o_10_10_11_1,
5686                                      &a_o_10_10_11_1,
5687                                      &adj_o_10_10_11_2,
5688                                      &adj_o_10_10_11_2,
5689                                      &adj_o_10_10_11_2,
5690                                      &adj_o_10_10_11_2,
5691                                      &adj_o_10_10_11_2),
5692              "24001/eos LB 16 buckets via: "
5693              "label 99 over 10.10.10.1, "
5694              "adj over 10.10.11.1",
5695              "adj-v4 over 10.10.11.2");
5696
5697     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5698                            &pfx_24001_neos);
5699     FIB_TEST(fib_test_validate_entry(fei, 
5700                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5701                                      2,
5702                                      &l99_neos_o_10_10_10_1,
5703                                      &a_mpls_o_10_10_11_1),
5704              "24001/neos LB 2 buckets via: "
5705              "label 99 over 10.10.10.1, "
5706              "adj-mpls over 10.10.11.2");
5707
5708     /*
5709      * remove the first path with the valid label
5710      */
5711     fib_table_entry_path_remove(fib_index,
5712                                 &pfx_1_1_1_1_s_32,
5713                                 FIB_SOURCE_API,
5714                                 FIB_PROTOCOL_IP4,
5715                                 &nh_10_10_10_1,
5716                                 tm->hw[0]->sw_if_index,
5717                                 ~0, // invalid fib index
5718                                 1,
5719                                 FIB_ROUTE_PATH_FLAG_NONE);
5720
5721     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5722     FIB_TEST(fib_test_validate_entry(fei, 
5723                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5724                                      2,
5725                                      &a_o_10_10_11_1,
5726                                      &adj_o_10_10_11_2),
5727              "1.1.1.1/32 LB 2 buckets via: "
5728              "adj over 10.10.11.1, "
5729              "adj-v4 over 10.10.11.2");
5730
5731     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5732                            &pfx_24001_eos);
5733     FIB_TEST(fib_test_validate_entry(fei, 
5734                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5735                                      2,
5736                                      &a_o_10_10_11_1,
5737                                      &adj_o_10_10_11_2),
5738              "24001/eos LB 2 buckets via: "
5739              "adj over 10.10.11.1, "
5740              "adj-v4 over 10.10.11.2");
5741
5742     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5743                            &pfx_24001_neos);
5744
5745     FIB_TEST(fib_test_validate_entry(fei, 
5746                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5747                                      1,
5748                                      &a_mpls_o_10_10_11_1),
5749              "24001/neos LB 1 buckets via: "
5750              "adj-mpls over 10.10.11.2");
5751
5752     /*
5753      * remove the other path with a valid label
5754      */
5755     fib_test_lb_bucket_t bucket_drop = {
5756         .type = FT_LB_SPECIAL,
5757         .special = {
5758             .adj = DPO_PROTO_IP4,
5759         },
5760     };
5761
5762     fib_table_entry_path_remove(fib_index,
5763                                 &pfx_1_1_1_1_s_32,
5764                                 FIB_SOURCE_API,
5765                                 FIB_PROTOCOL_IP4,
5766                                 &nh_10_10_11_1,
5767                                 tm->hw[1]->sw_if_index,
5768                                 ~0, // invalid fib index
5769                                 1,
5770                                 FIB_ROUTE_PATH_FLAG_NONE);
5771
5772     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5773     FIB_TEST(fib_test_validate_entry(fei, 
5774                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5775                                      1,
5776                                      &adj_o_10_10_11_2),
5777              "1.1.1.1/32 LB 1 buckets via: "
5778              "adj over 10.10.11.2");
5779
5780     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5781                            &pfx_24001_eos);
5782     FIB_TEST(fib_test_validate_entry(fei, 
5783                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5784                                      1,
5785                                      &adj_o_10_10_11_2),
5786              "24001/eos LB 1 buckets via: "
5787              "adj over 10.10.11.2");
5788
5789     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5790                            &pfx_24001_neos);
5791     FIB_TEST(fib_test_validate_entry(fei, 
5792                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5793                                       1,
5794                                       &bucket_drop),
5795              "24001/eos LB 1 buckets via: DROP");
5796
5797     /*
5798      * add back the path with the valid label
5799      */
5800     l99 = NULL;
5801     vec_add1(l99, 99);
5802
5803     fib_table_entry_path_add(fib_index,
5804                              &pfx_1_1_1_1_s_32,
5805                              FIB_SOURCE_API,
5806                              FIB_ENTRY_FLAG_NONE,
5807                              FIB_PROTOCOL_IP4,
5808                              &nh_10_10_10_1,
5809                              tm->hw[0]->sw_if_index,
5810                              ~0, // invalid fib index
5811                              1,
5812                              l99,
5813                              FIB_ROUTE_PATH_FLAG_NONE);
5814
5815     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5816     FIB_TEST(fib_test_validate_entry(fei,
5817                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5818                                      2,
5819                                      &l99_eos_o_10_10_10_1,
5820                                      &adj_o_10_10_11_2),
5821              "1.1.1.1/32 LB 2 buckets via: "
5822              "label 99 over 10.10.10.1, "
5823              "adj over 10.10.11.2");
5824
5825     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5826                            &pfx_24001_eos);
5827     FIB_TEST(fib_test_validate_entry(fei, 
5828                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5829                                      2,
5830                                      &l99_eos_o_10_10_10_1,
5831                                      &adj_o_10_10_11_2),
5832              "24001/eos LB 2 buckets via: "
5833              "label 99 over 10.10.10.1, "
5834              "adj over 10.10.11.2");
5835
5836     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5837                            &pfx_24001_neos);
5838     FIB_TEST(fib_test_validate_entry(fei, 
5839                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5840                                      1,
5841                                      &l99_neos_o_10_10_10_1),
5842              "24001/neos LB 1 buckets via: "
5843              "label 99 over 10.10.10.1");
5844
5845     /*
5846      * change the local label
5847      */
5848     fib_table_entry_local_label_add(fib_index,
5849                                     &pfx_1_1_1_1_s_32,
5850                                     25005);
5851
5852     fib_prefix_t pfx_25005_eos = {
5853         .fp_proto = FIB_PROTOCOL_MPLS,
5854         .fp_label = 25005,
5855         .fp_eos = MPLS_EOS,
5856     };
5857     fib_prefix_t pfx_25005_neos = {
5858         .fp_proto = FIB_PROTOCOL_MPLS,
5859         .fp_label = 25005,
5860         .fp_eos = MPLS_NON_EOS,
5861     };
5862
5863     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5864               fib_table_lookup(fib_index, &pfx_24001_eos)),
5865              "24001/eos removed after label change");
5866     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5867               fib_table_lookup(fib_index, &pfx_24001_neos)),
5868              "24001/eos removed after label change");
5869
5870     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5871                            &pfx_25005_eos);
5872     FIB_TEST(fib_test_validate_entry(fei,
5873                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5874                                      2,
5875                                      &l99_eos_o_10_10_10_1,
5876                                      &adj_o_10_10_11_2),
5877              "25005/eos LB 2 buckets via: "
5878              "label 99 over 10.10.10.1, "
5879              "adj over 10.10.11.2");
5880
5881     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5882                            &pfx_25005_neos);
5883     FIB_TEST(fib_test_validate_entry(fei,
5884                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5885                                      1,
5886                                      &l99_neos_o_10_10_10_1),
5887              "25005/neos LB 1 buckets via: "
5888              "label 99 over 10.10.10.1");
5889
5890     /*
5891      * remove the local label.
5892      * the check that the MPLS entries are gone is done by the fact the
5893      * MPLS table is no longer present.
5894      */
5895     fib_table_entry_local_label_remove(fib_index,
5896                                        &pfx_1_1_1_1_s_32,
5897                                        25005);
5898
5899     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5900     FIB_TEST(fib_test_validate_entry(fei, 
5901                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5902                                      2,
5903                                      &l99_eos_o_10_10_10_1,
5904                                      &adj_o_10_10_11_2),
5905              "24001/eos LB 2 buckets via: "
5906              "label 99 over 10.10.10.1, "
5907              "adj over 10.10.11.2");
5908
5909     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5910               mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5911              "No more MPLS FIB entries => table removed");
5912
5913     /*
5914      * add another via-entry for the recursive
5915      */
5916     fib_prefix_t pfx_1_1_1_2_s_32 = {
5917         .fp_len = 32,
5918         .fp_proto = FIB_PROTOCOL_IP4,
5919         .fp_addr = {
5920             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5921         },
5922     };
5923     fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5924         .type = FT_LB_LABEL_O_ADJ,
5925         .label_o_adj = {
5926             .adj = ai_mpls_10_10_10_1,
5927             .label = 101,
5928             .eos = MPLS_EOS,
5929         },
5930     };
5931     mpls_label_t *l101 = NULL;
5932     vec_add1(l101, 101);
5933
5934     fei = fib_table_entry_update_one_path(fib_index,
5935                                           &pfx_1_1_1_2_s_32,
5936                                           FIB_SOURCE_API,
5937                                           FIB_ENTRY_FLAG_NONE,
5938                                           FIB_PROTOCOL_IP4,
5939                                           &nh_10_10_10_1,
5940                                           tm->hw[0]->sw_if_index,
5941                                           ~0, // invalid fib index
5942                                           1,
5943                                           l101,
5944                                           FIB_ROUTE_PATH_FLAG_NONE);
5945
5946     FIB_TEST(fib_test_validate_entry(fei,
5947                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5948                                      1,
5949                                      &l101_eos_o_10_10_10_1),
5950              "1.1.1.2/32 LB 1 buckets via: "
5951              "label 101 over 10.10.10.1");
5952
5953     dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
5954     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5955                                                      &pfx_1_1_1_1_s_32),
5956                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5957                                     &non_eos_1_1_1_1);
5958     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5959                                                      &pfx_1_1_1_2_s_32),
5960                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5961                                     &non_eos_1_1_1_2);
5962
5963     fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5964         .type = FT_LB_LABEL_O_LB,
5965         .label_o_lb = {
5966             .lb = non_eos_1_1_1_2.dpoi_index,
5967             .label = 1601,
5968             .eos = MPLS_EOS,
5969         },
5970     };
5971     mpls_label_t *l1601 = NULL;
5972     vec_add1(l1601, 1601);
5973
5974     l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5975
5976     fei = fib_table_entry_path_add(fib_index,
5977                                    &pfx_2_2_2_2_s_32,
5978                                    FIB_SOURCE_API,
5979                                    FIB_ENTRY_FLAG_NONE,
5980                                    FIB_PROTOCOL_IP4,
5981                                    &pfx_1_1_1_2_s_32.fp_addr,
5982                                    ~0,
5983                                    fib_index,
5984                                    1,
5985                                    l1601,
5986                                    FIB_ROUTE_PATH_FLAG_NONE);
5987
5988     FIB_TEST(fib_test_validate_entry(fei, 
5989                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5990                                      2,
5991                                      &l1600_eos_o_1_1_1_1,
5992                                      &l1601_eos_o_1_1_1_2),
5993              "2.2.2.2/32 LB 2 buckets via: "
5994              "label 1600 via 1.1,1.1, "
5995              "label 16001 via 1.1.1.2");
5996
5997     /*
5998      * update the via-entry so it no longer has an imp-null path.
5999      * the LB for the recursive can use an imp-null
6000      */
6001     l_imp_null = NULL;
6002     vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6003
6004     fei = fib_table_entry_update_one_path(fib_index,
6005                                           &pfx_1_1_1_2_s_32,
6006                                           FIB_SOURCE_API,
6007                                           FIB_ENTRY_FLAG_NONE,
6008                                           FIB_PROTOCOL_IP4,
6009                                           &nh_10_10_11_1,
6010                                           tm->hw[1]->sw_if_index,
6011                                           ~0, // invalid fib index
6012                                           1,
6013                                           l_imp_null,
6014                                           FIB_ROUTE_PATH_FLAG_NONE);
6015
6016     FIB_TEST(fib_test_validate_entry(fei,
6017                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6018                                      1,
6019                                      &a_o_10_10_11_1),
6020              "1.1.1.2/32 LB 1 buckets via: "
6021              "adj 10.10.11.1");
6022  
6023     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6024     FIB_TEST(fib_test_validate_entry(fei, 
6025                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6026                                      2,
6027                                      &l1600_eos_o_1_1_1_1,
6028                                      &l1601_eos_o_1_1_1_2),
6029              "2.2.2.2/32 LB 2 buckets via: "
6030              "label 1600 via 1.1,1.1, "
6031              "label 16001 via 1.1.1.2");
6032
6033     /*
6034      * update the via-entry so it no longer has labelled paths.
6035      * the LB for the recursive should exclue this via form its LB
6036      */
6037     fei = fib_table_entry_update_one_path(fib_index,
6038                                           &pfx_1_1_1_2_s_32,
6039                                           FIB_SOURCE_API,
6040                                           FIB_ENTRY_FLAG_NONE,
6041                                           FIB_PROTOCOL_IP4,
6042                                           &nh_10_10_11_1,
6043                                           tm->hw[1]->sw_if_index,
6044                                           ~0, // invalid fib index
6045                                           1,
6046                                           NULL,
6047                                           FIB_ROUTE_PATH_FLAG_NONE);
6048
6049     FIB_TEST(fib_test_validate_entry(fei,
6050                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6051                                      1,
6052                                      &a_o_10_10_11_1),
6053              "1.1.1.2/32 LB 1 buckets via: "
6054              "adj 10.10.11.1");
6055  
6056     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6057     FIB_TEST(fib_test_validate_entry(fei, 
6058                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6059                                      1,
6060                                      &l1600_eos_o_1_1_1_1),
6061              "2.2.2.2/32 LB 1 buckets via: "
6062              "label 1600 via 1.1,1.1");
6063
6064     dpo_reset(&non_eos_1_1_1_1);
6065     dpo_reset(&non_eos_1_1_1_2);
6066
6067     /*
6068      * Add a recursive with no out-labels. We expect to use the IP of the via
6069      */
6070     fib_prefix_t pfx_2_2_2_3_s_32 = {
6071         .fp_len = 32,
6072         .fp_proto = FIB_PROTOCOL_IP4,
6073         .fp_addr = {
6074             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6075         },
6076     };
6077     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6078
6079     fib_table_entry_update_one_path(fib_index,
6080                                     &pfx_2_2_2_3_s_32,
6081                                     FIB_SOURCE_API,
6082                                     FIB_ENTRY_FLAG_NONE,
6083                                     FIB_PROTOCOL_IP4,
6084                                     &pfx_1_1_1_1_s_32.fp_addr,
6085                                     ~0,
6086                                     fib_index,
6087                                     1,
6088                                     NULL,
6089                                     FIB_ROUTE_PATH_FLAG_NONE);
6090
6091     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6092                                                      &pfx_1_1_1_1_s_32),
6093                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6094                                     &ip_1_1_1_1);
6095
6096     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6097         .type = FT_LB_O_LB,
6098         .lb = {
6099             .lb = ip_1_1_1_1.dpoi_index,
6100         },
6101     };
6102
6103     fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6104     FIB_TEST(fib_test_validate_entry(fei, 
6105                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6106                                      1,
6107                                      &ip_o_1_1_1_1),
6108              "2.2.2.2.3/32 LB 1 buckets via: "
6109              "ip 1.1.1.1");
6110
6111     /*
6112      * Add a recursive with an imp-null out-label. 
6113      * We expect to use the IP of the via
6114      */
6115     fib_prefix_t pfx_2_2_2_4_s_32 = {
6116         .fp_len = 32,
6117         .fp_proto = FIB_PROTOCOL_IP4,
6118         .fp_addr = {
6119             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6120         },
6121     };
6122
6123     fib_table_entry_update_one_path(fib_index,
6124                                     &pfx_2_2_2_4_s_32,
6125                                     FIB_SOURCE_API,
6126                                     FIB_ENTRY_FLAG_NONE,
6127                                     FIB_PROTOCOL_IP4,
6128                                     &pfx_1_1_1_1_s_32.fp_addr,
6129                                     ~0,
6130                                     fib_index,
6131                                     1,
6132                                     NULL,
6133                                     FIB_ROUTE_PATH_FLAG_NONE);
6134
6135     fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6136     FIB_TEST(fib_test_validate_entry(fei, 
6137                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6138                                      1,
6139                                      &ip_o_1_1_1_1),
6140              "2.2.2.2.4/32 LB 1 buckets via: "
6141              "ip 1.1.1.1");
6142
6143     dpo_reset(&ip_1_1_1_1);
6144
6145     /*
6146      * Create an entry with a deep label stack
6147      */
6148     fib_prefix_t pfx_2_2_5_5_s_32 = {
6149         .fp_len = 32,
6150         .fp_proto = FIB_PROTOCOL_IP4,
6151         .fp_addr = {
6152             .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6153         },
6154     };
6155     fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6156         .type = FT_LB_LABEL_STACK_O_ADJ,
6157         .label_stack_o_adj = {
6158             .adj = ai_mpls_10_10_11_1,
6159             .label_stack_size = 8,
6160             .label_stack = {
6161                 200, 201, 202, 203, 204, 205, 206, 207
6162             },
6163             .eos = MPLS_EOS,
6164         },
6165     };
6166     mpls_label_t *label_stack = NULL;
6167     vec_validate(label_stack, 7);
6168     for (ii = 0; ii < 8; ii++)
6169     {
6170         label_stack[ii] = ii + 200;
6171     }
6172
6173     fei = fib_table_entry_update_one_path(fib_index,
6174                                           &pfx_2_2_5_5_s_32,
6175                                           FIB_SOURCE_API,
6176                                           FIB_ENTRY_FLAG_NONE,
6177                                           FIB_PROTOCOL_IP4,
6178                                           &nh_10_10_11_1,
6179                                           tm->hw[1]->sw_if_index,
6180                                           ~0, // invalid fib index
6181                                           1,
6182                                           label_stack,
6183                                           FIB_ROUTE_PATH_FLAG_NONE);
6184
6185     FIB_TEST(fib_test_validate_entry(fei,
6186                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6187                                      1,
6188                                      &ls_eos_o_10_10_10_1),
6189              "2.2.5.5/32 LB 1 buckets via: "
6190              "adj 10.10.11.1");
6191     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6192
6193     /*
6194      * cleanup
6195      */
6196     fib_table_entry_delete(fib_index,
6197                            &pfx_1_1_1_2_s_32,
6198                            FIB_SOURCE_API);
6199
6200     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6201     FIB_TEST(fib_test_validate_entry(fei, 
6202                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6203                                      1,
6204                                      &l1600_eos_o_1_1_1_1),
6205              "2.2.2.2/32 LB 1 buckets via: "
6206              "label 1600 via 1.1,1.1");
6207
6208     fib_table_entry_delete(fib_index,
6209                            &pfx_1_1_1_1_s_32,
6210                            FIB_SOURCE_API);
6211
6212     FIB_TEST(fib_test_validate_entry(fei, 
6213                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6214                                      1,
6215                                      &bucket_drop),
6216              "2.2.2.2/32 LB 1 buckets via: DROP");
6217
6218     fib_table_entry_delete(fib_index,
6219                            &pfx_2_2_2_2_s_32,
6220                            FIB_SOURCE_API);
6221     fib_table_entry_delete(fib_index,
6222                            &pfx_2_2_2_3_s_32,
6223                            FIB_SOURCE_API);
6224     fib_table_entry_delete(fib_index,
6225                            &pfx_2_2_2_4_s_32,
6226                            FIB_SOURCE_API);
6227
6228     adj_unlock(ai_mpls_10_10_10_1);
6229     adj_unlock(ai_mpls_10_10_11_2);
6230     adj_unlock(ai_v4_10_10_11_1);
6231     adj_unlock(ai_v4_10_10_11_2);
6232     adj_unlock(ai_mpls_10_10_11_1);
6233
6234     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6235              adj_nbr_db_size());
6236
6237     local0_pfx.fp_len = 32;
6238     fib_table_entry_delete(fib_index,
6239                            &local0_pfx,
6240                            FIB_SOURCE_INTERFACE);
6241     local0_pfx.fp_len = 24;
6242     fib_table_entry_delete(fib_index,
6243                            &local0_pfx,
6244                            FIB_SOURCE_INTERFACE);
6245     local1_pfx.fp_len = 32;
6246     fib_table_entry_delete(fib_index,
6247                            &local1_pfx,
6248                            FIB_SOURCE_INTERFACE);
6249     local1_pfx.fp_len = 24;
6250     fib_table_entry_delete(fib_index,
6251                            &local1_pfx,
6252                            FIB_SOURCE_INTERFACE);
6253
6254     /*
6255      * +1 for the drop LB in the MPLS tables.
6256      */
6257     FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6258              "Load-balance resources freed %d of %d",
6259              lb_count+1, pool_elts(load_balance_pool));
6260
6261     return (0);
6262 }
6263
6264 #define N_TEST_CHILDREN 4
6265 #define PARENT_INDEX 0
6266
6267 typedef struct fib_node_test_t_
6268 {
6269     fib_node_t node;
6270     u32 sibling;
6271     u32 index;
6272     fib_node_back_walk_ctx_t *ctxs;
6273     u32 destroyed;
6274 } fib_node_test_t;
6275
6276 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6277
6278 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6279
6280 #define FOR_EACH_TEST_CHILD(_tc)                     \
6281     for (ii = 1, (_tc) = &fib_test_nodes[1];         \
6282          ii < N_TEST_CHILDREN+1;                     \
6283          ii++, (_tc) = &fib_test_nodes[ii])
6284
6285 static fib_node_t *
6286 fib_test_child_get_node (fib_node_index_t index)
6287 {
6288     return (&fib_test_nodes[index].node);
6289 }
6290
6291 static int fib_test_walk_spawns_walks;
6292
6293 static fib_node_back_walk_rc_t
6294 fib_test_child_back_walk_notify (fib_node_t *node,
6295                                  fib_node_back_walk_ctx_t *ctx)
6296 {
6297     fib_node_test_t *tc = (fib_node_test_t*) node;
6298
6299     vec_add1(tc->ctxs, *ctx);
6300
6301     if (1 == fib_test_walk_spawns_walks)
6302         fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6303     if (2 == fib_test_walk_spawns_walks)
6304         fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6305                        FIB_WALK_PRIORITY_HIGH, ctx);
6306
6307     return (FIB_NODE_BACK_WALK_CONTINUE);
6308 }
6309
6310 static void
6311 fib_test_child_last_lock_gone (fib_node_t *node)
6312 {
6313     fib_node_test_t *tc = (fib_node_test_t *)node;
6314
6315     tc->destroyed = 1;
6316 }
6317
6318 /**
6319  * The FIB walk's graph node virtual function table
6320  */
6321 static const fib_node_vft_t fib_test_child_vft = {
6322     .fnv_get = fib_test_child_get_node,
6323     .fnv_last_lock = fib_test_child_last_lock_gone,
6324     .fnv_back_walk = fib_test_child_back_walk_notify,
6325 };
6326
6327 /*
6328  * the function (that should have been static but isn't so I can do this)
6329  * that processes the walk from the async queue,
6330  */
6331 f64 fib_walk_process_queues(vlib_main_t * vm,
6332                             const f64 quota);
6333 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6334
6335 static int
6336 fib_test_walk (void)
6337 {
6338     fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6339     fib_node_test_t *tc;
6340     vlib_main_t *vm;
6341     u32 ii;
6342
6343     vm = vlib_get_main();
6344     fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6345
6346     /*
6347      * init a fake node on which we will add children
6348      */
6349     fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6350                   FIB_NODE_TYPE_TEST);
6351
6352     FOR_EACH_TEST_CHILD(tc)
6353     {
6354         fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6355         fib_node_lock(&tc->node);
6356         tc->ctxs = NULL;
6357         tc->index = ii;
6358         tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6359                                          PARENT_INDEX,
6360                                          FIB_NODE_TYPE_TEST, ii);
6361     }
6362
6363     /*
6364      * enqueue a walk across the parents children.
6365      */
6366     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6367
6368     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6369                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6370     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6371              "Parent has %d children pre-walk",
6372              fib_node_list_get_size(PARENT()->fn_children));
6373
6374     /*
6375      * give the walk a large amount of time so it gets to the end
6376      */
6377     fib_walk_process_queues(vm, 1);
6378
6379     FOR_EACH_TEST_CHILD(tc)
6380     {
6381         FIB_TEST(1 == vec_len(tc->ctxs),
6382                  "%d child visitsed %d times",
6383                  ii, vec_len(tc->ctxs));
6384         vec_free(tc->ctxs);
6385     }
6386     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6387              "Queue is empty post walk");
6388     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6389              "Parent has %d children post walk",
6390              fib_node_list_get_size(PARENT()->fn_children));
6391
6392     /*
6393      * walk again. should be no increase in the number of visits, since
6394      * the walk will have terminated.
6395      */
6396     fib_walk_process_queues(vm, 1);
6397
6398     FOR_EACH_TEST_CHILD(tc)
6399     {
6400         FIB_TEST(0 == vec_len(tc->ctxs),
6401                  "%d child visitsed %d times",
6402                  ii, vec_len(tc->ctxs));
6403     }
6404
6405     /*
6406      * schedule a low and hig priority walk. expect the high to be performed
6407      * before the low.
6408      * schedule the high prio walk first so that it is further from the head
6409      * of the dependency list. that way it won't merge with the low one.
6410      */
6411     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6412     low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6413
6414     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6415                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6416     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6417                    FIB_WALK_PRIORITY_LOW, &low_ctx);
6418
6419     fib_walk_process_queues(vm, 1);
6420
6421     FOR_EACH_TEST_CHILD(tc)
6422     {
6423         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6424                  "%d child visitsed by high prio walk", ii);
6425         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
6426                  "%d child visitsed by low prio walk", ii);
6427         vec_free(tc->ctxs);
6428     }
6429     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6430              "Queue is empty post prio walk");
6431     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6432              "Parent has %d children post prio walk",
6433              fib_node_list_get_size(PARENT()->fn_children));
6434
6435     /*
6436      * schedule 2 walks of the same priority that can be megred.
6437      * expect that each child is thus visited only once.
6438      */
6439     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6440     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6441
6442     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6443                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6444     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6445                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
6446
6447     fib_walk_process_queues(vm, 1);
6448
6449     FOR_EACH_TEST_CHILD(tc)
6450     {
6451         FIB_TEST(1 == vec_len(tc->ctxs),
6452                  "%d child visitsed %d times during merge walk",
6453                  ii, vec_len(tc->ctxs));
6454         vec_free(tc->ctxs);
6455     }
6456     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6457              "Queue is empty post merge walk");
6458     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6459              "Parent has %d children post merge walk",
6460              fib_node_list_get_size(PARENT()->fn_children));
6461
6462     /*
6463      * schedule 2 walks of the same priority that cannot be megred.
6464      * expect that each child is thus visited twice and in the order
6465      * in which the walks were scheduled.
6466      */
6467     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6468     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6469
6470     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6471                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6472     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6473                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
6474
6475     fib_walk_process_queues(vm, 1);
6476
6477     FOR_EACH_TEST_CHILD(tc)
6478     {
6479         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6480                  "%d child visitsed by high prio walk", ii);
6481         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
6482                  "%d child visitsed by low prio walk", ii);
6483         vec_free(tc->ctxs);
6484     }
6485     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6486              "Queue is empty post no-merge walk");
6487     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6488              "Parent has %d children post no-merge walk",
6489              fib_node_list_get_size(PARENT()->fn_children));
6490
6491     /*
6492      * schedule a walk that makes one one child progress.
6493      * we do this by giving the queue draining process zero
6494      * time quanta. it's a do..while loop, so it does something.
6495      */
6496     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6497
6498     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6499                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6500     fib_walk_process_queues(vm, 0);
6501
6502     FOR_EACH_TEST_CHILD(tc)
6503     {
6504         if (ii == N_TEST_CHILDREN)
6505         {
6506             FIB_TEST(1 == vec_len(tc->ctxs),
6507                      "%d child visitsed %d times in zero quanta walk",
6508                      ii, vec_len(tc->ctxs));
6509         }
6510         else
6511         {
6512             FIB_TEST(0 == vec_len(tc->ctxs),
6513                      "%d child visitsed %d times in 0 quanta walk",
6514                      ii, vec_len(tc->ctxs));
6515         }
6516     }
6517     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6518              "Queue is not empty post zero quanta walk");
6519     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6520              "Parent has %d children post zero qunta walk",
6521              fib_node_list_get_size(PARENT()->fn_children));
6522
6523     /*
6524      * another one step
6525      */
6526     fib_walk_process_queues(vm, 0);
6527
6528     FOR_EACH_TEST_CHILD(tc)
6529     {
6530         if (ii >= N_TEST_CHILDREN-1)
6531         {
6532             FIB_TEST(1 == vec_len(tc->ctxs),
6533                      "%d child visitsed %d times in 2nd zero quanta walk",
6534                      ii, vec_len(tc->ctxs));
6535         }
6536         else
6537         {
6538             FIB_TEST(0 == vec_len(tc->ctxs),
6539                      "%d child visitsed %d times in 2nd 0 quanta walk",
6540                      ii, vec_len(tc->ctxs));
6541         }
6542     }
6543     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6544              "Queue is not empty post zero quanta walk");
6545     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6546              "Parent has %d children post zero qunta walk",
6547              fib_node_list_get_size(PARENT()->fn_children));
6548
6549     /*
6550      * schedule another walk that will catch-up and merge.
6551      */
6552     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6553                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6554     fib_walk_process_queues(vm, 1);
6555
6556     FOR_EACH_TEST_CHILD(tc)
6557     {
6558         if (ii >= N_TEST_CHILDREN-1)
6559         {
6560             FIB_TEST(2 == vec_len(tc->ctxs),
6561                      "%d child visitsed %d times in 2nd zero quanta merge walk",
6562                      ii, vec_len(tc->ctxs));
6563             vec_free(tc->ctxs);
6564         }
6565         else
6566         {
6567             FIB_TEST(1 == vec_len(tc->ctxs),
6568                      "%d child visitsed %d times in 2nd 0 quanta merge walk",
6569                      ii, vec_len(tc->ctxs));
6570             vec_free(tc->ctxs);
6571         }
6572     }
6573     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6574              "Queue is not empty post 2nd zero quanta merge walk");
6575     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6576              "Parent has %d children post 2nd zero qunta merge walk",
6577              fib_node_list_get_size(PARENT()->fn_children));
6578
6579     /*
6580      * park a async walk in the middle of the list, then have an sync walk catch
6581      * it. same expectations as async catches async.
6582      */
6583     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6584
6585     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6586                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6587
6588     fib_walk_process_queues(vm, 0);
6589     fib_walk_process_queues(vm, 0);
6590
6591     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6592
6593     FOR_EACH_TEST_CHILD(tc)
6594     {
6595         if (ii >= N_TEST_CHILDREN-1)
6596         {
6597             FIB_TEST(2 == vec_len(tc->ctxs),
6598                      "%d child visitsed %d times in sync catches async walk",
6599                      ii, vec_len(tc->ctxs));
6600             vec_free(tc->ctxs);
6601         }
6602         else
6603         {
6604             FIB_TEST(1 == vec_len(tc->ctxs),
6605                      "%d child visitsed %d times in sync catches async walk",
6606                      ii, vec_len(tc->ctxs));
6607             vec_free(tc->ctxs);
6608         }
6609     }
6610     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6611              "Queue is not empty post 2nd zero quanta merge walk");
6612     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6613              "Parent has %d children post 2nd zero qunta merge walk",
6614              fib_node_list_get_size(PARENT()->fn_children));
6615
6616     /*
6617      * make the parent a child of one of its children, thus inducing a routing loop.
6618      */
6619     fib_test_nodes[PARENT_INDEX].sibling =
6620         fib_node_child_add(FIB_NODE_TYPE_TEST,
6621                            1, // the first child
6622                            FIB_NODE_TYPE_TEST,
6623                            PARENT_INDEX);
6624
6625     /*
6626      * execute a sync walk from the parent. each child visited spawns more sync
6627      * walks. we expect the walk to terminate.
6628      */
6629     fib_test_walk_spawns_walks = 1;
6630
6631     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6632
6633     FOR_EACH_TEST_CHILD(tc)
6634     {
6635         /*
6636          * child 1 - which is last in the list - has the loop.
6637          * the other children a re thus visitsed first. the we meet
6638          * child 1. we go round the loop again, visting the other children.
6639          * then we meet the walk in the dep list and bail. child 1 is not visitsed
6640          * again.
6641          */
6642         if (1 == ii)
6643         {
6644             FIB_TEST(1 == vec_len(tc->ctxs),
6645                      "child %d visitsed %d times during looped sync walk",
6646                      ii, vec_len(tc->ctxs));
6647         }
6648         else
6649         {
6650             FIB_TEST(2 == vec_len(tc->ctxs),
6651                      "child %d visitsed %d times during looped sync walk",
6652                      ii, vec_len(tc->ctxs));
6653         }
6654         vec_free(tc->ctxs);
6655     }
6656     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6657              "Parent has %d children post sync loop walk",
6658              fib_node_list_get_size(PARENT()->fn_children));
6659
6660     /*
6661      * the walk doesn't reach the max depth because the infra knows that sync
6662      * meets sync implies a loop and bails early.
6663      */
6664     FIB_TEST(high_ctx.fnbw_depth == 9,
6665              "Walk context depth %d post sync loop walk",
6666              high_ctx.fnbw_depth);
6667
6668     /*
6669      * execute an async walk of the graph loop, with each child spawns sync walks
6670      */
6671     high_ctx.fnbw_depth = 0;
6672     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6673                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6674
6675     fib_walk_process_queues(vm, 1);
6676
6677     FOR_EACH_TEST_CHILD(tc)
6678     {
6679         /*
6680          * we don't really care how many times the children are visisted, as long as
6681          * it is more than once.
6682          */
6683         FIB_TEST(1 <= vec_len(tc->ctxs),
6684                  "child %d visitsed %d times during looped aync spawns sync walk",
6685                  ii, vec_len(tc->ctxs));
6686         vec_free(tc->ctxs);
6687     }
6688
6689     /*
6690      * execute an async walk of the graph loop, with each child spawns async walks
6691      */
6692     fib_test_walk_spawns_walks = 2;
6693     high_ctx.fnbw_depth = 0;
6694     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6695                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6696
6697     fib_walk_process_queues(vm, 1);
6698
6699     FOR_EACH_TEST_CHILD(tc)
6700     {
6701         /*
6702          * we don't really care how many times the children are visisted, as long as
6703          * it is more than once.
6704          */
6705         FIB_TEST(1 <= vec_len(tc->ctxs),
6706                  "child %d visitsed %d times during looped async spawns async walk",
6707                  ii, vec_len(tc->ctxs));
6708                 vec_free(tc->ctxs);
6709     }
6710
6711
6712     fib_node_child_remove(FIB_NODE_TYPE_TEST,
6713                           1, // the first child
6714                           fib_test_nodes[PARENT_INDEX].sibling);
6715
6716     /*
6717      * cleanup
6718      */
6719     FOR_EACH_TEST_CHILD(tc)
6720     {
6721         fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6722                               tc->sibling);
6723         fib_node_deinit(&tc->node);
6724         fib_node_unlock(&tc->node);
6725     }
6726     fib_node_deinit(PARENT());
6727
6728     /*
6729      * The parent will be destroyed when the last lock on it goes.
6730      * this test ensures all the walk objects are unlocking it.
6731      */
6732     FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6733              "Parent was destroyed");
6734
6735     return (0);
6736 }
6737
6738 static int
6739 lfib_test (void)
6740 {
6741     const mpls_label_t deag_label = 50;
6742     const u32 lfib_index = 0;
6743     const u32 fib_index = 0;
6744     dpo_id_t dpo = DPO_INVALID;
6745     const dpo_id_t *dpo1;
6746     fib_node_index_t lfe;
6747     lookup_dpo_t *lkd;
6748     test_main_t *tm;
6749     int lb_count;
6750     adj_index_t ai_mpls_10_10_10_1;
6751
6752     tm = &test_main;
6753     lb_count = pool_elts(load_balance_pool);
6754
6755     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6756              adj_nbr_db_size());
6757
6758     /*
6759      * MPLS enable an interface so we get the MPLS table created
6760      */
6761     mpls_sw_interface_enable_disable(&mpls_main,
6762                                      tm->hw[0]->sw_if_index,
6763                                      1);
6764
6765     ip46_address_t nh_10_10_10_1 = {
6766         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6767     };
6768     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6769                                              VNET_LINK_MPLS,
6770                                              &nh_10_10_10_1,
6771                                              tm->hw[0]->sw_if_index);
6772
6773     /*
6774      * Test the specials stack properly.
6775      */
6776     fib_prefix_t exp_null_v6_pfx = {
6777         .fp_proto = FIB_PROTOCOL_MPLS,
6778         .fp_eos = MPLS_EOS,
6779         .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6780         .fp_payload_proto = DPO_PROTO_IP6,
6781     };
6782     lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
6783     FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
6784              "%U/%U present",
6785              format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6786              format_mpls_eos_bit, MPLS_EOS);
6787     fib_entry_contribute_forwarding(lfe,
6788                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6789                                     &dpo);
6790     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6791     lkd = lookup_dpo_get(dpo1->dpoi_index);
6792
6793     FIB_TEST((fib_index == lkd->lkd_fib_index),
6794               "%U/%U is deag in %d %U",
6795              format_mpls_unicast_label, deag_label,
6796              format_mpls_eos_bit, MPLS_EOS,
6797              lkd->lkd_fib_index,
6798              format_dpo_id, &dpo, 0);
6799     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6800              "%U/%U is dst deag",
6801              format_mpls_unicast_label, deag_label,
6802              format_mpls_eos_bit, MPLS_EOS);
6803     FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
6804              "%U/%U is lookup in interface's table",
6805              format_mpls_unicast_label, deag_label,
6806              format_mpls_eos_bit, MPLS_EOS);
6807     FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
6808              "%U/%U is %U dst deag",
6809              format_mpls_unicast_label, deag_label,
6810              format_mpls_eos_bit, MPLS_EOS,
6811              format_dpo_proto, lkd->lkd_proto);
6812
6813
6814     /*
6815      * A route deag route for EOS
6816      */
6817     fib_prefix_t pfx = {
6818         .fp_proto = FIB_PROTOCOL_MPLS,
6819         .fp_eos = MPLS_EOS,
6820         .fp_label = deag_label,
6821         .fp_payload_proto = DPO_PROTO_IP4,
6822     };
6823     lfe = fib_table_entry_path_add(lfib_index,
6824                                    &pfx,
6825                                    FIB_SOURCE_CLI,
6826                                    FIB_ENTRY_FLAG_NONE,
6827                                    FIB_PROTOCOL_IP4,
6828                                    &zero_addr,
6829                                    ~0,
6830                                    fib_index,
6831                                    1,
6832                                    NULL,
6833                                    FIB_ROUTE_PATH_FLAG_NONE);
6834
6835     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6836               "%U/%U present",
6837               format_mpls_unicast_label, deag_label,
6838               format_mpls_eos_bit, MPLS_EOS);
6839
6840     fib_entry_contribute_forwarding(lfe,
6841                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6842                                     &dpo);
6843     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6844     lkd = lookup_dpo_get(dpo1->dpoi_index);
6845
6846     FIB_TEST((fib_index == lkd->lkd_fib_index),
6847               "%U/%U is deag in %d %U",
6848              format_mpls_unicast_label, deag_label,
6849              format_mpls_eos_bit, MPLS_EOS,
6850              lkd->lkd_fib_index,
6851              format_dpo_id, &dpo, 0);
6852     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6853              "%U/%U is dst deag",
6854              format_mpls_unicast_label, deag_label,
6855              format_mpls_eos_bit, MPLS_EOS);
6856     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
6857              "%U/%U is %U dst deag",
6858              format_mpls_unicast_label, deag_label,
6859              format_mpls_eos_bit, MPLS_EOS,
6860              format_dpo_proto, lkd->lkd_proto);
6861
6862     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6863
6864     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6865                                                          &pfx)),
6866               "%U/%U not present",
6867               format_mpls_unicast_label, deag_label,
6868               format_mpls_eos_bit, MPLS_EOS);
6869
6870     /*
6871      * A route deag route for non-EOS
6872      */
6873     pfx.fp_eos = MPLS_NON_EOS;
6874     lfe = fib_table_entry_path_add(lfib_index,
6875                                    &pfx,
6876                                    FIB_SOURCE_CLI,
6877                                    FIB_ENTRY_FLAG_NONE,
6878                                    FIB_PROTOCOL_IP4,
6879                                    &zero_addr,
6880                                    ~0,
6881                                    lfib_index,
6882                                    1,
6883                                    NULL,
6884                                    FIB_ROUTE_PATH_FLAG_NONE);
6885
6886     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6887               "%U/%U present",
6888               format_mpls_unicast_label, deag_label,
6889               format_mpls_eos_bit, MPLS_NON_EOS);
6890
6891     fib_entry_contribute_forwarding(lfe,
6892                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6893                                     &dpo);
6894     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6895     lkd = lookup_dpo_get(dpo1->dpoi_index);
6896
6897     FIB_TEST((fib_index == lkd->lkd_fib_index),
6898               "%U/%U is deag in %d %U",
6899              format_mpls_unicast_label, deag_label,
6900              format_mpls_eos_bit, MPLS_NON_EOS,
6901              lkd->lkd_fib_index,
6902              format_dpo_id, &dpo, 0);
6903     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6904              "%U/%U is dst deag",
6905              format_mpls_unicast_label, deag_label,
6906              format_mpls_eos_bit, MPLS_NON_EOS);
6907
6908     FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
6909              "%U/%U is %U dst deag",
6910              format_mpls_unicast_label, deag_label,
6911              format_mpls_eos_bit, MPLS_NON_EOS,
6912              format_dpo_proto, lkd->lkd_proto);
6913
6914     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6915
6916     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6917                                                          &pfx)),
6918               "%U/%U not present",
6919               format_mpls_unicast_label, deag_label,
6920               format_mpls_eos_bit, MPLS_EOS);
6921
6922     dpo_reset(&dpo);
6923
6924     /*
6925      * An MPLS x-connect
6926      */
6927     fib_prefix_t pfx_1200 = {
6928         .fp_len = 21,
6929         .fp_proto = FIB_PROTOCOL_MPLS,
6930         .fp_label = 1200,
6931         .fp_eos = MPLS_NON_EOS,
6932     };
6933     fib_test_lb_bucket_t neos_o_10_10_10_1 = {
6934         .type = FT_LB_LABEL_STACK_O_ADJ,
6935         .label_stack_o_adj = {
6936             .adj = ai_mpls_10_10_10_1,
6937             .label_stack_size = 4,
6938             .label_stack = {
6939                 200, 300, 400, 500,
6940             },
6941             .eos = MPLS_NON_EOS,
6942         },
6943     };
6944     dpo_id_t neos_1200 = DPO_INVALID;
6945     dpo_id_t ip_1200 = DPO_INVALID;
6946     mpls_label_t *l200 = NULL;
6947     vec_add1(l200, 200);
6948     vec_add1(l200, 300);
6949     vec_add1(l200, 400);
6950     vec_add1(l200, 500);
6951
6952     lfe = fib_table_entry_update_one_path(fib_index,
6953                                           &pfx_1200,
6954                                           FIB_SOURCE_API,
6955                                           FIB_ENTRY_FLAG_NONE,
6956                                           FIB_PROTOCOL_IP4,
6957                                           &nh_10_10_10_1,
6958                                           tm->hw[0]->sw_if_index,
6959                                           ~0, // invalid fib index
6960                                           1,
6961                                           l200,
6962                                           FIB_ROUTE_PATH_FLAG_NONE);
6963
6964     FIB_TEST(fib_test_validate_entry(lfe,
6965                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6966                                      1,
6967                                      &neos_o_10_10_10_1),
6968              "1200/0 LB 1 buckets via: "
6969              "adj 10.10.11.1");
6970
6971     /*
6972      * A recursive route via the MPLS x-connect
6973      */
6974     fib_prefix_t pfx_2_2_2_3_s_32 = {
6975         .fp_len = 32,
6976         .fp_proto = FIB_PROTOCOL_IP4,
6977         .fp_addr = {
6978             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6979         },
6980     };
6981     fib_route_path_t *rpaths = NULL, rpath = {
6982         .frp_proto = FIB_PROTOCOL_MPLS,
6983         .frp_local_label = 1200,
6984         .frp_sw_if_index = ~0, // recurive
6985         .frp_fib_index = 0, // Default MPLS fib
6986         .frp_weight = 1,
6987         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6988         .frp_label_stack = NULL,
6989     };
6990     vec_add1(rpaths, rpath);
6991
6992     fib_table_entry_path_add2(fib_index,
6993                               &pfx_2_2_2_3_s_32,
6994                               FIB_SOURCE_API,
6995                               FIB_ENTRY_FLAG_NONE,
6996                               rpaths);
6997
6998     /*
6999      * A labelled recursive route via the MPLS x-connect
7000      */
7001     fib_prefix_t pfx_2_2_2_4_s_32 = {
7002         .fp_len = 32,
7003         .fp_proto = FIB_PROTOCOL_IP4,
7004         .fp_addr = {
7005             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7006         },
7007     };
7008     mpls_label_t *l999 = NULL;
7009     vec_add1(l999, 999);
7010     rpaths[0].frp_label_stack = l999,
7011
7012     fib_table_entry_path_add2(fib_index,
7013                               &pfx_2_2_2_4_s_32,
7014                               FIB_SOURCE_API,
7015                               FIB_ENTRY_FLAG_NONE,
7016                               rpaths);
7017
7018     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7019                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7020                                     &ip_1200);
7021     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7022                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7023                                     &neos_1200);
7024
7025     fib_test_lb_bucket_t ip_o_1200 = {
7026         .type = FT_LB_O_LB,
7027         .lb = {
7028             .lb = ip_1200.dpoi_index,
7029         },
7030     };
7031     fib_test_lb_bucket_t mpls_o_1200 = {
7032         .type = FT_LB_LABEL_O_LB,
7033         .label_o_lb = {
7034             .lb = neos_1200.dpoi_index,
7035             .label = 999,
7036             .eos = MPLS_EOS,
7037         },
7038     };
7039
7040     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7041     FIB_TEST(fib_test_validate_entry(lfe,
7042                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7043                                      1,
7044                                      &ip_o_1200),
7045              "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
7046     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7047     FIB_TEST(fib_test_validate_entry(lfe,
7048                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7049                                      1,
7050                                      &mpls_o_1200),
7051              "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
7052
7053     fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
7054     fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
7055     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7056
7057     dpo_reset(&neos_1200);
7058     dpo_reset(&ip_1200);
7059
7060     /*
7061      * A recursive via a label that does not exist
7062      */
7063     fib_test_lb_bucket_t bucket_drop = {
7064         .type = FT_LB_SPECIAL,
7065         .special = {
7066             .adj = DPO_PROTO_MPLS,
7067         },
7068     };
7069
7070     rpaths[0].frp_label_stack = NULL;
7071     lfe = fib_table_entry_path_add2(fib_index,
7072                                     &pfx_2_2_2_4_s_32,
7073                                     FIB_SOURCE_API,
7074                                     FIB_ENTRY_FLAG_NONE,
7075                                     rpaths);
7076
7077     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7078                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7079                                     &ip_1200);
7080     ip_o_1200.lb.lb = ip_1200.dpoi_index;
7081
7082     FIB_TEST(fib_test_validate_entry(lfe,
7083                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7084                                      1,
7085                                      &ip_o_1200),
7086              "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
7087     lfe = fib_table_lookup(fib_index, &pfx_1200);
7088     FIB_TEST(fib_test_validate_entry(lfe,
7089                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7090                                      1,
7091                                      &bucket_drop),
7092              "2.2.2.4/32 LB 1 buckets via: ip4-DROP");
7093
7094     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7095
7096     dpo_reset(&ip_1200);
7097
7098     /*
7099      * cleanup
7100      */
7101     mpls_sw_interface_enable_disable(&mpls_main,
7102                                      tm->hw[0]->sw_if_index,
7103                                      0);
7104
7105     FIB_TEST(lb_count == pool_elts(load_balance_pool),
7106              "Load-balance resources freed %d of %d",
7107              lb_count, pool_elts(load_balance_pool));
7108
7109     return (0);
7110 }
7111
7112 static clib_error_t *
7113 fib_test (vlib_main_t * vm, 
7114           unformat_input_t * input,
7115           vlib_cli_command_t * cmd_arg)
7116 {
7117     int res;
7118
7119     res = 0;
7120     fib_test_mk_intf(4);
7121
7122     if (unformat (input, "ip"))
7123     {
7124         res += fib_test_v4();
7125         res += fib_test_v6();
7126     }
7127     else if (unformat (input, "label"))
7128     {
7129         res += fib_test_label();
7130     }
7131     else if (unformat (input, "ae"))
7132     {
7133         res += fib_test_ae();
7134     }
7135     else if (unformat (input, "lfib"))
7136     {
7137         res += lfib_test();
7138     }
7139     else if (unformat (input, "walk"))
7140     {
7141         res += fib_test_walk();
7142     }
7143     else
7144     {
7145         /*
7146          * These walk UT aren't run as part of the full suite, since the
7147          * fib-walk process must be disabled in order for the tests to work
7148          *
7149          * fib_test_walk();
7150          */
7151         res += fib_test_v4();
7152         res += fib_test_v6();
7153         res += fib_test_ae();
7154         res += fib_test_label();
7155         res += lfib_test();
7156     }
7157
7158     if (res)
7159     {
7160         return clib_error_return(0, "FIB Unit Test Failed");
7161     }
7162     else
7163     {
7164         return (NULL);
7165     }
7166 }
7167
7168 VLIB_CLI_COMMAND (test_fib_command, static) = {
7169     .path = "test fib",
7170     .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
7171     .function = fib_test,
7172 };
7173
7174 clib_error_t *
7175 fib_test_init (vlib_main_t *vm)
7176 {
7177     return 0;
7178 }
7179
7180 VLIB_INIT_FUNCTION (fib_test_init);