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