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