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