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