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