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