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