486e561679847f2c8e062da7c7ac066f8f1b4589
[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      * Make the default route recursive via a unknown next-hop. Thus the
2981      * next hop's cover would be the default route
2982      */
2983     fei = fib_table_entry_path_add(fib_index,
2984                                    &pfx_0_0_0_0_s_0,
2985                                    FIB_SOURCE_API,
2986                                    FIB_ENTRY_FLAG_NONE,
2987                                    FIB_PROTOCOL_IP4,
2988                                    &pfx_23_23_23_23_s_32.fp_addr,
2989                                    ~0, // recursive
2990                                    fib_index,
2991                                    1,
2992                                    NULL,
2993                                    FIB_ROUTE_PATH_FLAG_NONE);
2994     dpo = fib_entry_contribute_ip_forwarding(fei);
2995     FIB_TEST(load_balance_is_drop(dpo),
2996              "0.0.0.0.0/0 via is DROP");
2997     FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
2998              "no resolving interface for looped 0.0.0.0/0");
2999
3000     fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3001     dpo = fib_entry_contribute_ip_forwarding(fei);
3002     FIB_TEST(load_balance_is_drop(dpo),
3003              "23.23.23.23/32 via is DROP");
3004     FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3005              "no resolving interface for looped 23.23.23.23/32");
3006
3007     fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3008
3009     /*
3010      * A recursive route with recursion constraints.
3011      *  200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3012      */
3013     fib_table_entry_path_add(fib_index,
3014                              &bgp_200_pfx,
3015                              FIB_SOURCE_API,
3016                              FIB_ENTRY_FLAG_NONE,
3017                              FIB_PROTOCOL_IP4,
3018                              &nh_1_1_1_1,
3019                              ~0,
3020                              fib_index,
3021                              1,
3022                              NULL,
3023                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3024
3025     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3026     dpo2 = fib_entry_contribute_ip_forwarding(fei);
3027
3028     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3029     dpo1 = fib_entry_contribute_ip_forwarding(fei);
3030
3031     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3032              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3033
3034     /*
3035      * save the load-balance. we expect it to be inplace modified
3036      */
3037     lb = load_balance_get(dpo1->dpoi_index);
3038
3039     /*
3040      * add a covering prefix for the via fib that would otherwise serve
3041      * as the resolving route when the host is removed
3042      */
3043     fib_table_entry_path_add(fib_index,
3044                              &pfx_1_1_1_0_s_28,
3045                              FIB_SOURCE_API,
3046                              FIB_ENTRY_FLAG_NONE,
3047                              FIB_PROTOCOL_IP4,
3048                              &nh_10_10_10_1,
3049                              tm->hw[0]->sw_if_index,
3050                              ~0, // invalid fib index
3051                              1,
3052                              NULL,
3053                              FIB_ROUTE_PATH_FLAG_NONE);
3054     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3055     ai = fib_entry_get_adj(fei);
3056     FIB_TEST((ai == ai_01),
3057              "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3058
3059     /*
3060      * remove the host via FIB - expect the BGP prefix to be drop
3061      */
3062     fib_table_entry_path_remove(fib_index,
3063                                 &pfx_1_1_1_1_s_32,
3064                                 FIB_SOURCE_API,
3065                                 FIB_PROTOCOL_IP4,
3066                                 &nh_10_10_10_1,
3067                                 tm->hw[0]->sw_if_index,
3068                                 ~0, // invalid fib index
3069                                 1,
3070                                 FIB_ROUTE_PATH_FLAG_NONE);
3071
3072     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3073              "adj for 200.200.200.200/32 is recursive via adj for DROP");
3074
3075     /*
3076      * add the via-entry host reoute back. expect to resolve again
3077      */
3078     fib_table_entry_path_add(fib_index,
3079                              &pfx_1_1_1_1_s_32,
3080                              FIB_SOURCE_API,
3081                              FIB_ENTRY_FLAG_NONE,
3082                              FIB_PROTOCOL_IP4,
3083                              &nh_10_10_10_1,
3084                              tm->hw[0]->sw_if_index,
3085                              ~0, // invalid fib index
3086                              1,
3087                              NULL,
3088                              FIB_ROUTE_PATH_FLAG_NONE);
3089     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3090              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3091
3092     /*
3093      * add another path for the recursive. it will then have 2.
3094      */
3095     fib_prefix_t pfx_1_1_1_3_s_32 = {
3096         .fp_len = 32,
3097         .fp_proto = FIB_PROTOCOL_IP4,
3098         .fp_addr = {
3099             .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3100         },
3101     };
3102     fib_table_entry_path_add(fib_index,
3103                              &pfx_1_1_1_3_s_32,
3104                              FIB_SOURCE_API,
3105                              FIB_ENTRY_FLAG_NONE,
3106                              FIB_PROTOCOL_IP4,
3107                              &nh_10_10_10_2,
3108                              tm->hw[0]->sw_if_index,
3109                              ~0, // invalid fib index
3110                              1,
3111                              NULL,
3112                              FIB_ROUTE_PATH_FLAG_NONE);
3113
3114     fib_table_entry_path_add(fib_index,
3115                              &bgp_200_pfx,
3116                              FIB_SOURCE_API,
3117                              FIB_ENTRY_FLAG_NONE,
3118                              FIB_PROTOCOL_IP4,
3119                              &pfx_1_1_1_3_s_32.fp_addr,
3120                              ~0,
3121                              fib_index,
3122                              1,
3123                              NULL,
3124                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3125
3126     /*
3127      * add a bunch load more entries using this path combo so that we get
3128      * an LB-map created.
3129      */
3130 #define N_P 128
3131     fib_prefix_t bgp_78s[N_P];
3132     for (ii = 0; ii < N_P; ii++)
3133     {
3134         bgp_78s[ii].fp_len = 32;
3135         bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3136         bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3137
3138         
3139         fib_table_entry_path_add(fib_index,
3140                                  &bgp_78s[ii],
3141                                  FIB_SOURCE_API,
3142                                  FIB_ENTRY_FLAG_NONE,
3143                                  FIB_PROTOCOL_IP4,
3144                                  &pfx_1_1_1_3_s_32.fp_addr,
3145                                  ~0,
3146                                  fib_index,
3147                                  1,
3148                                  NULL,
3149                                  FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3150         fib_table_entry_path_add(fib_index,
3151                                  &bgp_78s[ii],
3152                                  FIB_SOURCE_API,
3153                                  FIB_ENTRY_FLAG_NONE,
3154                                  FIB_PROTOCOL_IP4,
3155                                  &nh_1_1_1_1,
3156                                  ~0,
3157                                  fib_index,
3158                                  1,
3159                                  NULL,
3160                                  FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3161     }
3162
3163     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3164     dpo = fib_entry_contribute_ip_forwarding(fei);
3165
3166     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3167     dpo2 = fib_entry_contribute_ip_forwarding(fei);
3168     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3169              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3170     fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3171     dpo1 = fib_entry_contribute_ip_forwarding(fei);
3172     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3173              "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3174
3175     /*
3176      * expect the lb-map used by the recursive's load-balance is using both buckets
3177      */
3178     load_balance_map_t *lbm;
3179     index_t lbmi;
3180
3181     lb = load_balance_get(dpo->dpoi_index);
3182     lbmi = lb->lb_map;
3183     load_balance_map_lock(lbmi);
3184     lbm = load_balance_map_get(lbmi);
3185
3186     FIB_TEST(lbm->lbm_buckets[0] == 0,
3187              "LB maps's bucket 0 is %d",
3188              lbm->lbm_buckets[0]);
3189     FIB_TEST(lbm->lbm_buckets[1] == 1,
3190              "LB maps's bucket 1 is %d",
3191              lbm->lbm_buckets[1]);
3192
3193     /*
3194      * withdraw one of the /32 via-entrys.
3195      * that ECMP path will be unresolved and forwarding should continue on the
3196      * other available path. this is an iBGP PIC edge failover.
3197      * Test the forwarding changes without re-fetching the adj from the
3198      * recursive entry. this ensures its the same one that is updated; i.e. an
3199      * inplace-modify.
3200      */
3201     fib_table_entry_path_remove(fib_index,
3202                                 &pfx_1_1_1_1_s_32,
3203                                 FIB_SOURCE_API,
3204                                 FIB_PROTOCOL_IP4,
3205                                 &nh_10_10_10_1,
3206                                 tm->hw[0]->sw_if_index,
3207                                 ~0, // invalid fib index
3208                                 1,
3209                                 FIB_ROUTE_PATH_FLAG_NONE);
3210
3211     /* suspend so the update walk kicks int */
3212     vlib_process_suspend(vlib_get_main(), 1e-5);
3213
3214     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3215     FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3216              "post PIC 200.200.200.200/32 was inplace modified");
3217
3218     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3219              "post PIC adj for 200.200.200.200/32 is recursive"
3220              " via adj for 1.1.1.3");
3221
3222     /*
3223      * the LB maps that was locked above should have been modified to remove
3224      * the path that was down, and thus its bucket points to a path that is
3225      * still up.
3226      */
3227     FIB_TEST(lbm->lbm_buckets[0] == 1,
3228              "LB maps's bucket 0 is %d",
3229              lbm->lbm_buckets[0]);
3230     FIB_TEST(lbm->lbm_buckets[1] == 1,
3231              "LB maps's bucket 1 is %d",
3232              lbm->lbm_buckets[1]);
3233
3234     load_balance_map_unlock(lbmi);
3235
3236     /*
3237      * add it back. again 
3238      */
3239     fib_table_entry_path_add(fib_index,
3240                              &pfx_1_1_1_1_s_32,
3241                              FIB_SOURCE_API,
3242                              FIB_ENTRY_FLAG_NONE,
3243                              FIB_PROTOCOL_IP4,
3244                              &nh_10_10_10_1,
3245                              tm->hw[0]->sw_if_index,
3246                              ~0, // invalid fib index
3247                              1,
3248                              NULL,
3249                              FIB_ROUTE_PATH_FLAG_NONE);
3250
3251     /* suspend so the update walk kicks in */
3252     vlib_process_suspend(vlib_get_main(), 1e-5);
3253
3254     FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3255              "post PIC recovery adj for 200.200.200.200/32 is recursive "
3256              "via adj for 1.1.1.1");
3257     FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3258              "post PIC recovery adj for 200.200.200.200/32 is recursive "
3259              "via adj for 1.1.1.3");
3260
3261     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3262     dpo = fib_entry_contribute_ip_forwarding(fei);
3263     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3264              "post PIC 200.200.200.200/32 was inplace modified");
3265
3266     /*
3267      * add a 3rd path. this makes the LB 16 buckets. 
3268      */
3269     fib_table_entry_path_add(fib_index,
3270                              &bgp_200_pfx,
3271                              FIB_SOURCE_API,
3272                              FIB_ENTRY_FLAG_NONE,
3273                              FIB_PROTOCOL_IP4,
3274                              &pfx_1_1_1_2_s_32.fp_addr,
3275                              ~0,
3276                              fib_index,
3277                              1,
3278                              NULL,
3279                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3280     for (ii = 0; ii < N_P; ii++)
3281     {
3282         fib_table_entry_path_add(fib_index,
3283                                  &bgp_78s[ii],
3284                              FIB_SOURCE_API,
3285                              FIB_ENTRY_FLAG_NONE,
3286                              FIB_PROTOCOL_IP4,
3287                              &pfx_1_1_1_2_s_32.fp_addr,
3288                              ~0,
3289                              fib_index,
3290                              1,
3291                              NULL,
3292                              FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3293     }
3294
3295     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3296     dpo = fib_entry_contribute_ip_forwarding(fei);
3297     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3298              "200.200.200.200/32 was inplace modified for 3rd path");
3299     FIB_TEST(16 == lb->lb_n_buckets,
3300              "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3301
3302     lbmi = lb->lb_map;
3303     load_balance_map_lock(lbmi);
3304     lbm = load_balance_map_get(lbmi);
3305
3306     for (ii = 0; ii < 16; ii++)
3307     {
3308         FIB_TEST(lbm->lbm_buckets[ii] == ii,
3309                  "LB Map for 200.200.200.200/32 at %d is %d",
3310                  ii, lbm->lbm_buckets[ii]);
3311     }
3312
3313     /*
3314      * trigger PIC by removing the first via-entry
3315      * the first 6 buckets of the map should map to the next 6
3316      */
3317     fib_table_entry_path_remove(fib_index,
3318                                 &pfx_1_1_1_1_s_32,
3319                                 FIB_SOURCE_API,
3320                                 FIB_PROTOCOL_IP4,
3321                                 &nh_10_10_10_1,
3322                                 tm->hw[0]->sw_if_index,
3323                                 ~0,
3324                                 1,
3325                                 FIB_ROUTE_PATH_FLAG_NONE);
3326     /* suspend so the update walk kicks int */
3327     vlib_process_suspend(vlib_get_main(), 1e-5);
3328
3329     fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3330     dpo = fib_entry_contribute_ip_forwarding(fei);
3331     FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3332              "200.200.200.200/32 was inplace modified for 3rd path");
3333     FIB_TEST(2 == lb->lb_n_buckets,
3334              "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3335
3336     for (ii = 0; ii < 6; ii++)
3337     {
3338         FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3339                  "LB Map for 200.200.200.200/32 at %d is %d",
3340                  ii, lbm->lbm_buckets[ii]);
3341     }
3342     for (ii = 6; ii < 16; ii++)
3343     {
3344         FIB_TEST(lbm->lbm_buckets[ii] == ii,
3345                  "LB Map for 200.200.200.200/32 at %d is %d",
3346                  ii, lbm->lbm_buckets[ii]);
3347     }
3348     load_balance_map_unlock(lbmi);
3349
3350     /*
3351      * tidy up
3352      */
3353     fib_table_entry_path_add(fib_index,
3354                              &pfx_1_1_1_1_s_32,
3355                              FIB_SOURCE_API,
3356                              FIB_ENTRY_FLAG_NONE,
3357                              FIB_PROTOCOL_IP4,
3358                              &nh_10_10_10_1,
3359                              tm->hw[0]->sw_if_index,
3360                              ~0,
3361                              1,
3362                              NULL,
3363                              FIB_ROUTE_PATH_FLAG_NONE);
3364
3365     for (ii = 0; ii < N_P; ii++)
3366     {
3367         fib_table_entry_delete(fib_index,
3368                                &bgp_78s[ii],
3369                                FIB_SOURCE_API);
3370         FIB_TEST((FIB_NODE_INDEX_INVALID ==
3371                   fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3372                  "%U removed",
3373                  format_fib_prefix, &bgp_78s[ii]);
3374     }
3375     fib_table_entry_path_remove(fib_index,
3376                                 &bgp_200_pfx,
3377                                 FIB_SOURCE_API,
3378                                 FIB_PROTOCOL_IP4,
3379                                 &pfx_1_1_1_2_s_32.fp_addr,
3380                                 ~0,
3381                                 fib_index,
3382                                 1,
3383                                 MPLS_LABEL_INVALID);
3384     fib_table_entry_path_remove(fib_index,
3385                                 &bgp_200_pfx,
3386                                 FIB_SOURCE_API,
3387                                 FIB_PROTOCOL_IP4,
3388                                 &nh_1_1_1_1,
3389                                 ~0,
3390                                 fib_index,
3391                                 1,
3392                                 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3393     fib_table_entry_path_remove(fib_index,
3394                                 &bgp_200_pfx,
3395                                 FIB_SOURCE_API,
3396                                 FIB_PROTOCOL_IP4,
3397                                 &pfx_1_1_1_3_s_32.fp_addr,
3398                                 ~0,
3399                                 fib_index,
3400                                 1,
3401                                 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3402     fib_table_entry_delete(fib_index,
3403                            &pfx_1_1_1_3_s_32,
3404                            FIB_SOURCE_API);
3405     fib_table_entry_delete(fib_index,
3406                            &pfx_1_1_1_0_s_28,
3407                            FIB_SOURCE_API);
3408     /* suspend so the update walk kicks int */
3409     vlib_process_suspend(vlib_get_main(), 1e-5);
3410     FIB_TEST((FIB_NODE_INDEX_INVALID ==
3411               fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3412              "1.1.1.1/28 removed");
3413     FIB_TEST((FIB_NODE_INDEX_INVALID ==
3414               fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3415              "1.1.1.3/32 removed");
3416     FIB_TEST((FIB_NODE_INDEX_INVALID ==
3417               fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3418              "200.200.200.200/32 removed");
3419
3420     /*
3421      * add-remove test. no change.
3422      */
3423     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3424              fib_path_list_db_size());
3425     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3426              fib_path_list_pool_size());
3427     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3428              fib_entry_pool_size());
3429
3430     /*
3431      * A route whose paths are built up iteratively and then removed
3432      * all at once
3433      */
3434     fib_prefix_t pfx_4_4_4_4_s_32 = {
3435         .fp_len = 32,
3436         .fp_proto = FIB_PROTOCOL_IP4,
3437         .fp_addr = {
3438             /* 4.4.4.4/32 */
3439             .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3440         },
3441     };
3442
3443     fib_table_entry_path_add(fib_index,
3444                              &pfx_4_4_4_4_s_32,
3445                              FIB_SOURCE_API,
3446                              FIB_ENTRY_FLAG_NONE,
3447                              FIB_PROTOCOL_IP4,
3448                              &nh_10_10_10_1,
3449                              tm->hw[0]->sw_if_index,
3450                              ~0,
3451                              1,
3452                              NULL,
3453                              FIB_ROUTE_PATH_FLAG_NONE);
3454     fib_table_entry_path_add(fib_index,
3455                              &pfx_4_4_4_4_s_32,
3456                              FIB_SOURCE_API,
3457                              FIB_ENTRY_FLAG_NONE,
3458                              FIB_PROTOCOL_IP4,
3459                              &nh_10_10_10_2,
3460                              tm->hw[0]->sw_if_index,
3461                              ~0,
3462                              1,
3463                              NULL,
3464                              FIB_ROUTE_PATH_FLAG_NONE);
3465     fib_table_entry_path_add(fib_index,
3466                              &pfx_4_4_4_4_s_32,
3467                              FIB_SOURCE_API,
3468                              FIB_ENTRY_FLAG_NONE,
3469                              FIB_PROTOCOL_IP4,
3470                              &nh_10_10_10_3,
3471                              tm->hw[0]->sw_if_index,
3472                              ~0,
3473                              1,
3474                              NULL,
3475                              FIB_ROUTE_PATH_FLAG_NONE);
3476     FIB_TEST(FIB_NODE_INDEX_INVALID !=
3477              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3478              "4.4.4.4/32 present");
3479
3480     fib_table_entry_delete(fib_index,
3481                            &pfx_4_4_4_4_s_32,
3482                            FIB_SOURCE_API);
3483     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3484              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3485              "4.4.4.4/32 removed");
3486
3487     /*
3488      * add-remove test. no change.
3489      */
3490     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3491              fib_path_list_db_size());
3492     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3493              fib_path_list_pool_size());
3494     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3495              fib_entry_pool_size());
3496
3497     /*
3498      * A route with multiple paths at once
3499      */
3500     fib_route_path_t *r_paths = NULL;
3501
3502     for (ii = 0; ii < 4; ii++)
3503     {
3504         fib_route_path_t r_path = {
3505             .frp_proto = FIB_PROTOCOL_IP4,
3506             .frp_addr = {
3507                 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3508             },
3509             .frp_sw_if_index = tm->hw[0]->sw_if_index,
3510             .frp_weight = 1,
3511             .frp_fib_index = ~0,
3512         };
3513         vec_add1(r_paths, r_path);
3514     }
3515
3516     fib_table_entry_update(fib_index,
3517                            &pfx_4_4_4_4_s_32,
3518                            FIB_SOURCE_API,
3519                            FIB_ENTRY_FLAG_NONE,
3520                            r_paths);
3521
3522     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3523     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3524     dpo = fib_entry_contribute_ip_forwarding(fei);
3525
3526     lb = load_balance_get(dpo->dpoi_index);
3527     FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3528
3529     fib_table_entry_delete(fib_index,
3530                            &pfx_4_4_4_4_s_32,
3531                            FIB_SOURCE_API);
3532     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3533              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3534              "4.4.4.4/32 removed");
3535     vec_free(r_paths);
3536
3537     /*
3538      * add-remove test. no change.
3539      */
3540     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3541              fib_path_list_db_size());
3542     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3543              fib_path_list_pool_size());
3544     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3545              fib_entry_pool_size());
3546
3547     /*
3548      * A route deag route
3549      */
3550     fib_table_entry_path_add(fib_index,
3551                              &pfx_4_4_4_4_s_32,
3552                              FIB_SOURCE_API,
3553                              FIB_ENTRY_FLAG_NONE,
3554                              FIB_PROTOCOL_IP4,
3555                              &zero_addr,
3556                              ~0,
3557                              fib_index,
3558                              1,
3559                              NULL,
3560                              FIB_ROUTE_PATH_FLAG_NONE);
3561
3562     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3563     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3564
3565     dpo = fib_entry_contribute_ip_forwarding(fei);
3566     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3567     lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3568
3569     FIB_TEST((fib_index == lkd->lkd_fib_index),
3570              "4.4.4.4/32 is deag in %d %U",
3571              lkd->lkd_fib_index,
3572              format_dpo_id, dpo, 0);
3573
3574     fib_table_entry_delete(fib_index,
3575                            &pfx_4_4_4_4_s_32,
3576                            FIB_SOURCE_API);
3577     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3578              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3579              "4.4.4.4/32 removed");
3580     vec_free(r_paths);
3581
3582     /*
3583      * add-remove test. no change.
3584      */
3585     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3586              fib_path_list_db_size());
3587     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3588              fib_path_list_pool_size());
3589     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3590              fib_entry_pool_size());
3591
3592     /*
3593      * Duplicate paths:
3594      *  add a recursive with duplicate paths. Expect the duplicate to be ignored.
3595      */
3596     fib_prefix_t pfx_34_1_1_1_s_32 = {
3597         .fp_len = 32,
3598         .fp_proto = FIB_PROTOCOL_IP4,
3599         .fp_addr = {
3600             .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3601         },
3602     };
3603     fib_prefix_t pfx_34_34_1_1_s_32 = {
3604         .fp_len = 32,
3605         .fp_proto = FIB_PROTOCOL_IP4,
3606         .fp_addr = {
3607             .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3608         },
3609     };
3610     fei = fib_table_entry_path_add(fib_index,
3611                                    &pfx_34_1_1_1_s_32,
3612                                    FIB_SOURCE_API,
3613                                    FIB_ENTRY_FLAG_NONE,
3614                                    FIB_PROTOCOL_IP4,
3615                                    &pfx_34_34_1_1_s_32.fp_addr,
3616                                    ~0,
3617                                    fib_index,
3618                                    1,
3619                                    NULL,
3620                                    FIB_ROUTE_PATH_FLAG_NONE);
3621     fei = fib_table_entry_path_add(fib_index,
3622                                    &pfx_34_1_1_1_s_32,
3623                                    FIB_SOURCE_API,
3624                                    FIB_ENTRY_FLAG_NONE,
3625                                    FIB_PROTOCOL_IP4,
3626                                    &pfx_34_34_1_1_s_32.fp_addr,
3627                                    ~0,
3628                                    fib_index,
3629                                    1,
3630                                    NULL,
3631                                    FIB_ROUTE_PATH_FLAG_NONE);
3632     FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3633     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3634
3635     /*
3636      * CLEANUP
3637      *   remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3638      *           all of which are via 10.10.10.1, Itf1
3639      */
3640     fib_table_entry_path_remove(fib_index,
3641                                 &pfx_1_1_1_2_s_32,
3642                                 FIB_SOURCE_API,
3643                                 FIB_PROTOCOL_IP4,
3644                                 &nh_10_10_10_1,
3645                                 tm->hw[0]->sw_if_index,
3646                                 ~0,
3647                                 1,
3648                                 FIB_ROUTE_PATH_FLAG_NONE);
3649     fib_table_entry_path_remove(fib_index,
3650                                 &pfx_1_1_1_1_s_32,
3651                                 FIB_SOURCE_API,
3652                                 FIB_PROTOCOL_IP4,
3653                                 &nh_10_10_10_1,
3654                                 tm->hw[0]->sw_if_index,
3655                                 ~0,
3656                                 1,
3657                                 FIB_ROUTE_PATH_FLAG_NONE);
3658     fib_table_entry_path_remove(fib_index,
3659                                 &pfx_1_1_2_0_s_24,
3660                                 FIB_SOURCE_API,
3661                                 FIB_PROTOCOL_IP4,
3662                                 &nh_10_10_10_1,
3663                                 tm->hw[0]->sw_if_index,
3664                                 ~0,
3665                                 1,
3666                                 FIB_ROUTE_PATH_FLAG_NONE);
3667
3668     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3669              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3670              "1.1.1.1/32 removed");
3671     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3672              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3673              "1.1.1.2/32 removed");
3674     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3675              fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3676              "1.1.2.0/24 removed");
3677
3678     /*
3679      * -3 entries and -1 shared path-list
3680      */
3681     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3682              fib_path_list_db_size());
3683     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3684              fib_path_list_pool_size());
3685     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3686              fib_entry_pool_size());
3687
3688     /*
3689      * An attached-host route. Expect to link to the incomplete adj
3690      */
3691     fib_prefix_t pfx_4_1_1_1_s_32 = {
3692         .fp_len = 32,
3693         .fp_proto = FIB_PROTOCOL_IP4,
3694         .fp_addr = {
3695             /* 4.1.1.1/32 */
3696             .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3697         },
3698     };
3699     fib_table_entry_path_add(fib_index,
3700                              &pfx_4_1_1_1_s_32,
3701                              FIB_SOURCE_API,
3702                              FIB_ENTRY_FLAG_NONE,
3703                              FIB_PROTOCOL_IP4,
3704                              &zero_addr,
3705                              tm->hw[0]->sw_if_index,
3706                              fib_index,
3707                              1,
3708                              NULL,
3709                              FIB_ROUTE_PATH_FLAG_NONE);
3710
3711     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3712     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3713     ai = fib_entry_get_adj(fei);
3714
3715     ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3716                               VNET_LINK_IP4,
3717                               &pfx_4_1_1_1_s_32.fp_addr,
3718                               tm->hw[0]->sw_if_index);
3719     FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3720     adj_unlock(ai2);
3721
3722     /*
3723      * +1 entry and +1 shared path-list
3724      */
3725     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3726              fib_path_list_db_size());
3727     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3728              fib_path_list_pool_size());
3729     FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3730              fib_entry_pool_size());
3731
3732     fib_table_entry_delete(fib_index,
3733                            &pfx_4_1_1_1_s_32,
3734                            FIB_SOURCE_API);
3735
3736     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3737              fib_path_list_db_size());
3738     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3739              fib_path_list_pool_size());
3740     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3741              fib_entry_pool_size());
3742
3743     /*
3744      * add a v6 prefix via v4 next-hops
3745      */
3746     fib_prefix_t pfx_2001_s_64 = {
3747         .fp_len = 64,
3748         .fp_proto = FIB_PROTOCOL_IP6,
3749         .fp_addr = {
3750             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3751         },
3752     };
3753     fei = fib_table_entry_path_add(0, //default v6 table
3754                                    &pfx_2001_s_64,
3755                                    FIB_SOURCE_API,
3756                                    FIB_ENTRY_FLAG_NONE,
3757                                    FIB_PROTOCOL_IP4,
3758                                    &nh_10_10_10_1,
3759                                    tm->hw[0]->sw_if_index,
3760                                    fib_index,
3761                                    1,
3762                                    NULL,
3763                                    FIB_ROUTE_PATH_FLAG_NONE);
3764
3765     fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3766     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3767     ai = fib_entry_get_adj(fei);
3768     adj = adj_get(ai);
3769     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3770              "2001::/64 via ARP-adj");
3771     FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3772              "2001::/64 is link type v6");
3773     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3774              "2001::/64 ADJ-adj is NH proto v4");
3775     fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3776
3777     /*
3778      * add a uRPF exempt prefix:
3779      *  test:
3780      *   - it's forwarding is drop
3781      *   - it's uRPF list is not empty
3782      *   - the uRPF list for the default route (it's cover) is empty
3783      */
3784     fei = fib_table_entry_special_add(fib_index,
3785                                       &pfx_4_1_1_1_s_32,
3786                                       FIB_SOURCE_URPF_EXEMPT,
3787                                       FIB_ENTRY_FLAG_DROP);
3788     dpo = fib_entry_contribute_ip_forwarding(fei);
3789     FIB_TEST(load_balance_is_drop(dpo),
3790              "uRPF exempt 4.1.1.1/32 DROP");
3791     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3792              "uRPF list for exempt prefix has itf index 0");
3793     fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3794     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3795              "uRPF list for 0.0.0.0/0 empty");
3796
3797     fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3798
3799     /*
3800      * An adj-fib that fails the refinement criteria - no connected cover
3801      */
3802     fib_prefix_t pfx_12_10_10_2_s_32 = {
3803         .fp_len = 32,
3804         .fp_proto = FIB_PROTOCOL_IP4,
3805         .fp_addr = {
3806             /* 12.10.10.2 */
3807             .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3808         },
3809     };
3810
3811     fib_table_entry_update_one_path(fib_index,
3812                                     &pfx_12_10_10_2_s_32,
3813                                     FIB_SOURCE_ADJ,
3814                                     FIB_ENTRY_FLAG_ATTACHED,
3815                                     FIB_PROTOCOL_IP4,
3816                                     &pfx_12_10_10_2_s_32.fp_addr,
3817                                     tm->hw[0]->sw_if_index,
3818                                     ~0, // invalid fib index
3819                                     1,
3820                                     NULL,
3821                                     FIB_ROUTE_PATH_FLAG_NONE);
3822
3823     fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3824     dpo = fib_entry_contribute_ip_forwarding(fei);
3825     FIB_TEST(!dpo_id_is_valid(dpo),
3826              "no connected cover adj-fib fails refinement");
3827
3828     fib_table_entry_delete(fib_index,
3829                            &pfx_12_10_10_2_s_32,
3830                            FIB_SOURCE_ADJ);
3831
3832     /*
3833      * An adj-fib that fails the refinement criteria - cover is connected
3834      * but on a different interface
3835      */
3836     fib_prefix_t pfx_10_10_10_127_s_32 = {
3837         .fp_len = 32,
3838         .fp_proto = FIB_PROTOCOL_IP4,
3839         .fp_addr = {
3840             /* 10.10.10.127 */
3841             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3842         },
3843     };
3844
3845     fib_table_entry_update_one_path(fib_index,
3846                                     &pfx_10_10_10_127_s_32,
3847                                     FIB_SOURCE_ADJ,
3848                                     FIB_ENTRY_FLAG_ATTACHED,
3849                                     FIB_PROTOCOL_IP4,
3850                                     &pfx_10_10_10_127_s_32.fp_addr,
3851                                     tm->hw[1]->sw_if_index,
3852                                     ~0, // invalid fib index
3853                                     1,
3854                                     NULL,
3855                                     FIB_ROUTE_PATH_FLAG_NONE);
3856
3857     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3858     dpo = fib_entry_contribute_ip_forwarding(fei);
3859     FIB_TEST(!dpo_id_is_valid(dpo),
3860              "wrong interface adj-fib fails refinement");
3861
3862     fib_table_entry_delete(fib_index,
3863                            &pfx_10_10_10_127_s_32,
3864                            FIB_SOURCE_ADJ);
3865     /*
3866      * change the table's flow-hash config - expect the update to propagete to
3867      * the entries' load-balance objects
3868      */
3869     flow_hash_config_t old_hash_config, new_hash_config;
3870
3871     old_hash_config = fib_table_get_flow_hash_config(fib_index,
3872                                                      FIB_PROTOCOL_IP4);
3873     new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
3874                        IP_FLOW_HASH_DST_ADDR);
3875
3876     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
3877     dpo = fib_entry_contribute_ip_forwarding(fei);
3878     lb = load_balance_get(dpo->dpoi_index);
3879     FIB_TEST((lb->lb_hash_config == old_hash_config),
3880              "Table and LB hash config match: %U",
3881              format_ip_flow_hash_config, lb->lb_hash_config);
3882
3883     fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
3884
3885     FIB_TEST((lb->lb_hash_config == new_hash_config),
3886              "Table and LB newhash config match: %U",
3887              format_ip_flow_hash_config, lb->lb_hash_config);
3888
3889     /*
3890      * CLEANUP
3891      *    remove adj-fibs: 
3892      */
3893     fib_table_entry_delete(fib_index,
3894                            &pfx_10_10_10_1_s_32,
3895                            FIB_SOURCE_ADJ);
3896     fib_table_entry_delete(fib_index,
3897                            &pfx_10_10_10_2_s_32,
3898                            FIB_SOURCE_ADJ);
3899     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3900              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
3901              "10.10.10.1/32 adj-fib removed");
3902     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3903              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
3904              "10.10.10.2/32 adj-fib removed");
3905
3906     /*
3907      * -2 entries and -2 non-shared path-list
3908      */
3909     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3910              fib_path_list_db_size());
3911     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
3912              fib_path_list_pool_size());
3913     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
3914              fib_entry_pool_size());
3915
3916     /*
3917      * unlock the adjacencies for which this test provided a rewrite.
3918      * These are the last locks on these adjs. they should thus go away.
3919      */
3920     adj_unlock(ai_02);
3921     adj_unlock(ai_01);
3922     adj_unlock(ai_12_12_12_12);
3923
3924     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3925              adj_nbr_db_size());
3926
3927     /*
3928      * CLEANUP
3929      *   remove the interface prefixes
3930      */
3931     local_pfx.fp_len = 32;
3932     fib_table_entry_special_remove(fib_index, &local_pfx,
3933                                    FIB_SOURCE_INTERFACE);
3934     fei = fib_table_lookup(fib_index, &local_pfx);
3935
3936     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3937              fib_table_lookup_exact_match(fib_index, &local_pfx),
3938              "10.10.10.10/32 adj-fib removed");
3939
3940     local_pfx.fp_len = 24;
3941     fib_table_entry_delete(fib_index, &local_pfx,
3942                            FIB_SOURCE_INTERFACE);
3943
3944     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3945              fib_table_lookup_exact_match(fib_index, &local_pfx),
3946              "10.10.10.10/24 adj-fib removed");
3947
3948     /*
3949      * -2 entries and -2 non-shared path-list
3950      */
3951     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
3952              fib_path_list_db_size());
3953     FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
3954              fib_path_list_pool_size());
3955     FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
3956              fib_entry_pool_size());
3957
3958     /*
3959      * Last but not least, remove the VRF
3960      */
3961     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3962                                              FIB_PROTOCOL_IP4,
3963                                              FIB_SOURCE_API)),
3964              "NO API Source'd prefixes");
3965     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3966                                              FIB_PROTOCOL_IP4,
3967                                              FIB_SOURCE_RR)),
3968              "NO RR Source'd prefixes");
3969     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3970                                              FIB_PROTOCOL_IP4,
3971                                              FIB_SOURCE_INTERFACE)),
3972              "NO INterface Source'd prefixes");
3973
3974     fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
3975
3976     FIB_TEST((0  == fib_path_list_db_size()), "path list DB population:%d",
3977              fib_path_list_db_size());
3978     FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
3979              fib_path_list_pool_size());
3980     FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
3981              fib_entry_pool_size());
3982     FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
3983              pool_elts(fib_urpf_list_pool));
3984     FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
3985              pool_elts(load_balance_map_pool));
3986     FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
3987              pool_elts(load_balance_pool));
3988
3989     return 0;
3990 }
3991
3992 static int
3993 fib_test_v6 (void)
3994 {
3995     /*
3996      * In the default table check for the presence and correct forwarding
3997      * of the special entries
3998      */
3999     fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4000     const dpo_id_t *dpo, *dpo_drop;
4001     const ip_adjacency_t *adj;
4002     const receive_dpo_t *rd;
4003     test_main_t *tm;
4004     u32 fib_index;
4005     int ii;
4006
4007     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4008              adj_nbr_db_size());
4009
4010     /* via 2001:0:0:1::2 */
4011     ip46_address_t nh_2001_2 = {
4012         .ip6 = {
4013             .as_u64 = {
4014                 [0] = clib_host_to_net_u64(0x2001000000000001),
4015                 [1] = clib_host_to_net_u64(0x0000000000000002),
4016             },
4017         },
4018     };
4019
4020     tm = &test_main;
4021
4022     dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4023
4024     /* Find or create FIB table 11 */
4025     fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
4026
4027     for (ii = 0; ii < 4; ii++)
4028     {
4029         ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4030     }
4031
4032     fib_prefix_t pfx_0_0 = {
4033         .fp_len = 0,
4034         .fp_proto = FIB_PROTOCOL_IP6,
4035         .fp_addr = {
4036             .ip6 = {
4037                 {0, 0},
4038             },
4039         },
4040     };
4041
4042     dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4043     FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4044     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4045              "Default route is DROP");
4046
4047     dpo = fib_entry_contribute_ip_forwarding(dfrt);
4048     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4049                                      &ip6_main,
4050                                      1,
4051                                      &pfx_0_0.fp_addr.ip6)),
4052              "default-route; fwd and non-fwd tables match");
4053
4054     // FIXME - check specials.
4055
4056     /*
4057      * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4058      * each with 2 entries and a v6 mfib with 4 path-lists.
4059      * All entries are special so no path-list sharing.
4060      */
4061 #define ENPS (5+4)
4062 #define PNPS (5+4+4)
4063     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
4064     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4065              fib_path_list_pool_size());
4066     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4067              fib_entry_pool_size());
4068
4069     /*
4070      * add interface routes.
4071      *  validate presence of /64 attached and /128 recieve.
4072      *  test for the presence of the receive address in the glean and local adj
4073      *
4074      * receive on 2001:0:0:1::1/128
4075      */
4076     fib_prefix_t local_pfx = {
4077         .fp_len = 64,
4078         .fp_proto = FIB_PROTOCOL_IP6,
4079         .fp_addr = {
4080             .ip6 = {
4081                 .as_u64 = {
4082                     [0] = clib_host_to_net_u64(0x2001000000000001),
4083                     [1] = clib_host_to_net_u64(0x0000000000000001),
4084                 },
4085             },
4086         }
4087     };
4088
4089     fib_table_entry_update_one_path(fib_index, &local_pfx,
4090                                     FIB_SOURCE_INTERFACE,
4091                                     (FIB_ENTRY_FLAG_CONNECTED |
4092                                      FIB_ENTRY_FLAG_ATTACHED),
4093                                     FIB_PROTOCOL_IP6,
4094                                     NULL,
4095                                     tm->hw[0]->sw_if_index,
4096                                     ~0,
4097                                     1,
4098                                     NULL,
4099                                     FIB_ROUTE_PATH_FLAG_NONE);
4100     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4101
4102     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4103
4104     ai = fib_entry_get_adj(fei);
4105     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4106     adj = adj_get(ai);
4107     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4108              "attached interface adj is glean");
4109     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4110                                     &adj->sub_type.glean.receive_addr)),
4111               "attached interface adj is receive ok");
4112     dpo = fib_entry_contribute_ip_forwarding(fei);
4113     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4114                                      &ip6_main,
4115                                      1,
4116                                      &local_pfx.fp_addr.ip6)),
4117              "attached-route; fwd and non-fwd tables match");
4118
4119     local_pfx.fp_len = 128;
4120     fib_table_entry_update_one_path(fib_index, &local_pfx,
4121                                     FIB_SOURCE_INTERFACE,
4122                                     (FIB_ENTRY_FLAG_CONNECTED |
4123                                      FIB_ENTRY_FLAG_LOCAL),
4124                                     FIB_PROTOCOL_IP6,
4125                                     NULL,
4126                                     tm->hw[0]->sw_if_index,
4127                                     ~0, // invalid fib index
4128                                     1,
4129                                     NULL,
4130                                     FIB_ROUTE_PATH_FLAG_NONE);
4131     fei = fib_table_lookup(fib_index, &local_pfx);
4132
4133     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4134
4135     dpo = fib_entry_contribute_ip_forwarding(fei);
4136     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4137     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4138              "local interface adj is local");
4139     rd = receive_dpo_get(dpo->dpoi_index);
4140
4141     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4142                                     &rd->rd_addr)),
4143               "local interface adj is receive ok");
4144
4145     dpo = fib_entry_contribute_ip_forwarding(fei);
4146     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4147                                      &ip6_main,
4148                                      1,
4149                                      &local_pfx.fp_addr.ip6)),
4150              "local-route; fwd and non-fwd tables match");
4151
4152     /*
4153      * +2 entries. +2 unshared path-lists
4154      */
4155     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
4156     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4157              fib_path_list_pool_size());
4158     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4159              fib_entry_pool_size());
4160
4161     /*
4162      * Modify the default route to be via an adj not yet known.
4163      * this sources the defalut route with the API source, which is
4164      * a higher preference to the DEFAULT_ROUTE source
4165      */
4166     fib_table_entry_path_add(fib_index, &pfx_0_0,
4167                              FIB_SOURCE_API,
4168                              FIB_ENTRY_FLAG_NONE,
4169                              FIB_PROTOCOL_IP6,
4170                              &nh_2001_2,
4171                              tm->hw[0]->sw_if_index,
4172                              ~0,
4173                              1,
4174                              NULL,
4175                              FIB_ROUTE_PATH_FLAG_NONE);
4176     fei = fib_table_lookup(fib_index, &pfx_0_0);
4177
4178     FIB_TEST((fei == dfrt), "default route same index");
4179     ai = fib_entry_get_adj(fei);
4180     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4181     adj = adj_get(ai);
4182     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4183              "adj is incomplete");
4184     FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4185               "adj nbr next-hop ok");
4186
4187     /*
4188      * find the adj in the shared db
4189      */
4190     locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4191                                     VNET_LINK_IP6,
4192                                     &nh_2001_2,
4193                                     tm->hw[0]->sw_if_index);
4194     FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4195     adj_unlock(locked_ai);
4196
4197     /*
4198      * no more entires. +1 shared path-list
4199      */
4200     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4201              fib_path_list_db_size());
4202     FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4203              fib_path_list_pool_size());
4204     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4205              fib_entry_pool_size());
4206
4207     /*
4208      * remove the API source from the default route. We expected
4209      * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4210      */
4211     fib_table_entry_path_remove(fib_index, &pfx_0_0,
4212                                 FIB_SOURCE_API, 
4213                                 FIB_PROTOCOL_IP6,
4214                                 &nh_2001_2,
4215                                 tm->hw[0]->sw_if_index,
4216                                 ~0,
4217                                 1,
4218                                 FIB_ROUTE_PATH_FLAG_NONE);
4219     fei = fib_table_lookup(fib_index, &pfx_0_0);
4220
4221     FIB_TEST((fei == dfrt), "default route same index");
4222     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4223              "Default route is DROP");
4224
4225     /*
4226      * no more entires. -1 shared path-list
4227      */
4228     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4229              fib_path_list_db_size());
4230     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4231              fib_path_list_pool_size());
4232     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4233              fib_entry_pool_size());
4234
4235     /*
4236      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4237      */
4238     fib_prefix_t pfx_2001_1_2_s_128 = {
4239         .fp_len   = 128,
4240         .fp_proto = FIB_PROTOCOL_IP6,
4241         .fp_addr  = {
4242             .ip6 = {
4243                 .as_u64 = {
4244                     [0] = clib_host_to_net_u64(0x2001000000000001),
4245                     [1] = clib_host_to_net_u64(0x0000000000000002),
4246                 },
4247             },
4248         }
4249     };
4250     fib_prefix_t pfx_2001_1_3_s_128 = {
4251         .fp_len   = 128,
4252         .fp_proto = FIB_PROTOCOL_IP6,
4253         .fp_addr  = {
4254             .ip6 = {
4255                 .as_u64 = {
4256                     [0] = clib_host_to_net_u64(0x2001000000000001),
4257                     [1] = clib_host_to_net_u64(0x0000000000000003),
4258                 },
4259             },
4260         }
4261     };
4262     u8 eth_addr[] = {
4263         0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4264     };
4265
4266     ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4267                                 VNET_LINK_IP6,
4268                                 &pfx_2001_1_2_s_128.fp_addr,
4269                                 tm->hw[0]->sw_if_index);
4270     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4271     adj = adj_get(ai_01);
4272     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4273              "adj is incomplete");
4274     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4275                                     &adj->sub_type.nbr.next_hop)),
4276               "adj nbr next-hop ok");
4277
4278     adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4279                            fib_test_build_rewrite(eth_addr));
4280     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4281              "adj is complete");
4282     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4283                                     &adj->sub_type.nbr.next_hop)),
4284               "adj nbr next-hop ok");
4285
4286     fib_table_entry_update_one_path(fib_index,
4287                                     &pfx_2001_1_2_s_128,
4288                                     FIB_SOURCE_ADJ,
4289                                     FIB_ENTRY_FLAG_ATTACHED,
4290                                     FIB_PROTOCOL_IP6,
4291                                     &pfx_2001_1_2_s_128.fp_addr,
4292                                     tm->hw[0]->sw_if_index,
4293                                     ~0,
4294                                     1,
4295                                     NULL,
4296                                     FIB_ROUTE_PATH_FLAG_NONE);
4297
4298     fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4299     ai = fib_entry_get_adj(fei);
4300     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4301
4302     eth_addr[5] = 0xb2;
4303
4304     ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4305                                 VNET_LINK_IP6,
4306                                 &pfx_2001_1_3_s_128.fp_addr,
4307                                 tm->hw[0]->sw_if_index);
4308     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4309     adj = adj_get(ai_02);
4310     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4311              "adj is incomplete");
4312     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4313                                     &adj->sub_type.nbr.next_hop)),
4314               "adj nbr next-hop ok");
4315
4316     adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4317                            fib_test_build_rewrite(eth_addr));
4318     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4319              "adj is complete");
4320     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4321                                     &adj->sub_type.nbr.next_hop)),
4322               "adj nbr next-hop ok");
4323     FIB_TEST((ai_01 != ai_02), "ADJs are different");
4324
4325     fib_table_entry_update_one_path(fib_index,
4326                                     &pfx_2001_1_3_s_128,
4327                                     FIB_SOURCE_ADJ,
4328                                     FIB_ENTRY_FLAG_ATTACHED,
4329                                     FIB_PROTOCOL_IP6,
4330                                     &pfx_2001_1_3_s_128.fp_addr,
4331                                     tm->hw[0]->sw_if_index,
4332                                     ~0,
4333                                     1,
4334                                     NULL,
4335                                     FIB_ROUTE_PATH_FLAG_NONE);
4336
4337     fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4338     ai = fib_entry_get_adj(fei);
4339     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4340
4341     /*
4342      * +2 entries, +2 unshread path-lists.
4343      */
4344     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4345              fib_path_list_db_size());
4346     FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4347              fib_path_list_pool_size());
4348     FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4349              fib_entry_pool_size());
4350
4351     /*
4352      * Add a 2 routes via the first ADJ. ensure path-list sharing
4353      */
4354     fib_prefix_t pfx_2001_a_s_64 = {
4355         .fp_len   = 64,
4356         .fp_proto = FIB_PROTOCOL_IP6,
4357         .fp_addr  = {
4358             .ip6 = {
4359                 .as_u64 = {
4360                     [0] = clib_host_to_net_u64(0x200100000000000a),
4361                     [1] = clib_host_to_net_u64(0x0000000000000000),
4362                 },
4363             },
4364         }
4365     };
4366     fib_prefix_t pfx_2001_b_s_64 = {
4367         .fp_len   = 64,
4368         .fp_proto = FIB_PROTOCOL_IP6,
4369         .fp_addr  = {
4370             .ip6 = {
4371                 .as_u64 = {
4372                     [0] = clib_host_to_net_u64(0x200100000000000b),
4373                     [1] = clib_host_to_net_u64(0x0000000000000000),
4374                 },
4375             },
4376         }
4377     };
4378
4379     fib_table_entry_path_add(fib_index,
4380                              &pfx_2001_a_s_64,
4381                              FIB_SOURCE_API,
4382                              FIB_ENTRY_FLAG_NONE,
4383                              FIB_PROTOCOL_IP6,
4384                              &nh_2001_2,
4385                              tm->hw[0]->sw_if_index,
4386                              ~0,
4387                              1,
4388                              NULL,
4389                              FIB_ROUTE_PATH_FLAG_NONE);
4390     fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4391     ai = fib_entry_get_adj(fei);
4392     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4393     fib_table_entry_path_add(fib_index,
4394                              &pfx_2001_b_s_64,
4395                              FIB_SOURCE_API,
4396                              FIB_ENTRY_FLAG_NONE,
4397                              FIB_PROTOCOL_IP6,
4398                              &nh_2001_2,
4399                              tm->hw[0]->sw_if_index,
4400                              ~0,
4401                              1,
4402                              NULL,
4403                              FIB_ROUTE_PATH_FLAG_NONE);
4404     fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4405     ai = fib_entry_get_adj(fei);
4406     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4407
4408     /*
4409      * +2 entries, +1 shared path-list.
4410      */
4411     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4412              fib_path_list_db_size());
4413     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4414              fib_path_list_pool_size());
4415     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4416              fib_entry_pool_size());
4417
4418     /*
4419      * add a v4 prefix via a v6 next-hop
4420      */
4421     fib_prefix_t pfx_1_1_1_1_s_32 = {
4422         .fp_len = 32,
4423         .fp_proto = FIB_PROTOCOL_IP4,
4424         .fp_addr = {
4425             .ip4.as_u32 = 0x01010101,
4426         },
4427     };
4428     fei = fib_table_entry_path_add(0, // default table
4429                                    &pfx_1_1_1_1_s_32,
4430                                    FIB_SOURCE_API,
4431                                    FIB_ENTRY_FLAG_NONE,
4432                                    FIB_PROTOCOL_IP6,
4433                                    &nh_2001_2,
4434                                    tm->hw[0]->sw_if_index,
4435                                    ~0,
4436                                    1,
4437                                    NULL,
4438                                    FIB_ROUTE_PATH_FLAG_NONE);
4439     FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4440              "1.1.1.1/32 o v6 route present");
4441     ai = fib_entry_get_adj(fei);
4442     adj = adj_get(ai);
4443     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4444              "1.1.1.1/32 via ARP-adj");
4445     FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4446              "1.1.1.1/32 ADJ-adj is link type v4");
4447     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4448              "1.1.1.1/32 ADJ-adj is NH proto v6");
4449     fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4450
4451     /*
4452      * An attached route
4453      */
4454     fib_prefix_t pfx_2001_c_s_64 = {
4455         .fp_len   = 64,
4456         .fp_proto = FIB_PROTOCOL_IP6,
4457         .fp_addr  = {
4458             .ip6 = {
4459                 .as_u64 = {
4460                     [0] = clib_host_to_net_u64(0x200100000000000c),
4461                     [1] = clib_host_to_net_u64(0x0000000000000000),
4462                 },
4463             },
4464         }
4465     };
4466     fib_table_entry_path_add(fib_index,
4467                              &pfx_2001_c_s_64,
4468                              FIB_SOURCE_CLI,
4469                              FIB_ENTRY_FLAG_ATTACHED,
4470                              FIB_PROTOCOL_IP6,
4471                              NULL,
4472                              tm->hw[0]->sw_if_index,
4473                              ~0,
4474                              1,
4475                              NULL,
4476                              FIB_ROUTE_PATH_FLAG_NONE);
4477     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4478     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4479     ai = fib_entry_get_adj(fei);
4480     adj = adj_get(ai);
4481     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4482              "2001:0:0:c/64 attached resolves via glean");
4483
4484     fib_table_entry_path_remove(fib_index,
4485                                 &pfx_2001_c_s_64,
4486                                 FIB_SOURCE_CLI,
4487                                 FIB_PROTOCOL_IP6,
4488                                 NULL,
4489                                 tm->hw[0]->sw_if_index,
4490                                 ~0,
4491                                 1,
4492                                 FIB_ROUTE_PATH_FLAG_NONE);
4493     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4494     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4495
4496     /*
4497      * Shutdown the interface on which we have a connected and through
4498      * which the routes are reachable.
4499      * This will result in the connected, adj-fibs, and routes linking to drop
4500      * The local/for-us prefix continues to receive.
4501      */
4502     clib_error_t * error;
4503
4504     error = vnet_sw_interface_set_flags(vnet_get_main(),
4505                                         tm->hw[0]->sw_if_index,
4506                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4507     FIB_TEST((NULL == error), "Interface shutdown OK");
4508
4509     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4510     dpo = fib_entry_contribute_ip_forwarding(fei);
4511     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4512              "2001::b/64 resolves via drop");
4513
4514     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4515     dpo = fib_entry_contribute_ip_forwarding(fei);
4516     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4517              "2001::a/64 resolves via drop");
4518     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4519     dpo = fib_entry_contribute_ip_forwarding(fei);
4520     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4521              "2001:0:0:1::3/64 resolves via drop");
4522     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4523     dpo = fib_entry_contribute_ip_forwarding(fei);
4524     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4525              "2001:0:0:1::2/64 resolves via drop");
4526     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4527     dpo = fib_entry_contribute_ip_forwarding(fei);
4528     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4529              "2001:0:0:1::1/128 not drop");
4530     local_pfx.fp_len = 64;
4531     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4532     dpo = fib_entry_contribute_ip_forwarding(fei);
4533     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4534              "2001:0:0:1/64 resolves via drop");
4535
4536     /*
4537      * no change
4538      */
4539     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4540              fib_path_list_db_size());
4541     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4542              fib_path_list_pool_size());
4543     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4544              fib_entry_pool_size());
4545
4546     /*
4547      * shutdown one of the other interfaces, then add a connected.
4548      * and swap one of the routes to it.
4549      */
4550     error = vnet_sw_interface_set_flags(vnet_get_main(),
4551                                         tm->hw[1]->sw_if_index,
4552                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4553     FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4554
4555     fib_prefix_t connected_pfx = {
4556         .fp_len = 64,
4557         .fp_proto = FIB_PROTOCOL_IP6,
4558         .fp_addr = {
4559             .ip6 = {
4560                 /* 2001:0:0:2::1/64 */
4561                 .as_u64 = {
4562                     [0] = clib_host_to_net_u64(0x2001000000000002),
4563                     [1] = clib_host_to_net_u64(0x0000000000000001),
4564                 },
4565             },
4566         }
4567     };
4568     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4569                                     FIB_SOURCE_INTERFACE,
4570                                     (FIB_ENTRY_FLAG_CONNECTED |
4571                                      FIB_ENTRY_FLAG_ATTACHED),
4572                                     FIB_PROTOCOL_IP6,
4573                                     NULL,
4574                                     tm->hw[1]->sw_if_index,
4575                                     ~0,
4576                                     1,
4577                                     NULL,
4578                                     FIB_ROUTE_PATH_FLAG_NONE);
4579     fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4580     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4581     dpo = fib_entry_contribute_ip_forwarding(fei);
4582     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4583     FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4584              "2001:0:0:2/64 not resolves via drop");
4585
4586     connected_pfx.fp_len = 128;
4587     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4588                                     FIB_SOURCE_INTERFACE,
4589                                     (FIB_ENTRY_FLAG_CONNECTED |
4590                                      FIB_ENTRY_FLAG_LOCAL),
4591                                     FIB_PROTOCOL_IP6,
4592                                     NULL,
4593                                     tm->hw[0]->sw_if_index,
4594                                     ~0, // invalid fib index
4595                                     1,
4596                                     NULL,
4597                                     FIB_ROUTE_PATH_FLAG_NONE);
4598     fei = fib_table_lookup(fib_index, &connected_pfx);
4599
4600     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4601     dpo = fib_entry_contribute_ip_forwarding(fei);
4602     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4603     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4604              "local interface adj is local");
4605     rd = receive_dpo_get(dpo->dpoi_index);
4606     FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4607                                     &rd->rd_addr)),
4608               "local interface adj is receive ok");
4609
4610     /*
4611      * +2 entries, +2 unshared path-lists
4612      */
4613     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4614              fib_path_list_db_size());
4615     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4616              fib_path_list_pool_size());
4617     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4618              fib_entry_pool_size());
4619
4620
4621     /*
4622      * bring the interface back up. we expected the routes to return
4623      * to normal forwarding.
4624      */
4625     error = vnet_sw_interface_set_flags(vnet_get_main(),
4626                                         tm->hw[0]->sw_if_index,
4627                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4628     FIB_TEST((NULL == error), "Interface bring-up OK");
4629     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4630     ai = fib_entry_get_adj(fei);
4631     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4632     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4633     ai = fib_entry_get_adj(fei);
4634     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4635     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4636     ai = fib_entry_get_adj(fei);
4637     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4638     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4639     ai = fib_entry_get_adj(fei);
4640     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4641     local_pfx.fp_len = 64;
4642     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4643     ai = fib_entry_get_adj(fei);
4644     adj = adj_get(ai);
4645     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4646              "attached interface adj is glean");
4647
4648     /*
4649      * Same test as above, but this time the HW interface goes down
4650      */
4651     error = vnet_hw_interface_set_flags(vnet_get_main(),
4652                                         tm->hw_if_indicies[0],
4653                                         ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4654     FIB_TEST((NULL == error), "Interface shutdown OK");
4655
4656     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4657     dpo = fib_entry_contribute_ip_forwarding(fei);
4658     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4659              "2001::b/64 resolves via drop");
4660     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4661     dpo = fib_entry_contribute_ip_forwarding(fei);
4662     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4663              "2001::a/64 resolves via drop");
4664     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4665     dpo = fib_entry_contribute_ip_forwarding(fei);
4666     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4667              "2001:0:0:1::3/128 resolves via drop");
4668     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4669     dpo = fib_entry_contribute_ip_forwarding(fei);
4670     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4671              "2001:0:0:1::2/128 resolves via drop");
4672     local_pfx.fp_len = 128;
4673     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4674     dpo = fib_entry_contribute_ip_forwarding(fei);
4675     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4676              "2001:0:0:1::1/128 not drop");
4677     local_pfx.fp_len = 64;
4678     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4679     dpo = fib_entry_contribute_ip_forwarding(fei);
4680     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4681              "2001:0:0:1/64 resolves via drop");
4682
4683     error = vnet_hw_interface_set_flags(vnet_get_main(),
4684                                         tm->hw_if_indicies[0],
4685                                         VNET_HW_INTERFACE_FLAG_LINK_UP);
4686     FIB_TEST((NULL == error), "Interface bring-up OK");
4687     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4688     ai = fib_entry_get_adj(fei);
4689     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4690     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4691     ai = fib_entry_get_adj(fei);
4692     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4693     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4694     ai = fib_entry_get_adj(fei);
4695     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4696     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4697     ai = fib_entry_get_adj(fei);
4698     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4699     local_pfx.fp_len = 64;
4700     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4701     ai = fib_entry_get_adj(fei);
4702     adj = adj_get(ai);
4703     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4704              "attached interface adj is glean");
4705
4706     /*
4707      * Delete the interface that the routes reolve through.
4708      * Again no routes are removed. They all point to drop.
4709      *
4710      * This is considered an error case. The control plane should
4711      * not remove interfaces through which routes resolve, but
4712      * such things can happen. ALL affected routes will drop.
4713      */
4714     vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4715
4716     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4717     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4718              "2001::b/64 resolves via drop");
4719     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4720     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4721              "2001::b/64 resolves via drop");
4722     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4723     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4724              "2001:0:0:1::3/64 resolves via drop");
4725     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4726     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4727              "2001:0:0:1::2/64 resolves via drop");
4728     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4729     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4730              "2001:0:0:1::1/128 is drop");
4731     local_pfx.fp_len = 64;
4732     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4733     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4734              "2001:0:0:1/64 resolves via drop");
4735
4736     /*
4737      * no change
4738      */
4739     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4740              fib_path_list_db_size());
4741     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4742              fib_path_list_pool_size());
4743     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4744              fib_entry_pool_size());
4745
4746     /*
4747      * Add the interface back. routes stay unresolved.
4748      */
4749     error = ethernet_register_interface(vnet_get_main(),
4750                                         test_interface_device_class.index,
4751                                         0 /* instance */,
4752                                         hw_address,
4753                                         &tm->hw_if_indicies[0],
4754                                         /* flag change */ 0);
4755
4756     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4757     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4758              "2001::b/64 resolves via drop");
4759     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4760     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4761              "2001::b/64 resolves via drop");
4762     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4763     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4764              "2001:0:0:1::3/64 resolves via drop");
4765     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4766     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4767              "2001:0:0:1::2/64 resolves via drop");
4768     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4769     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4770              "2001:0:0:1::1/128 is drop");
4771     local_pfx.fp_len = 64;
4772     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4773     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4774              "2001:0:0:1/64 resolves via drop");
4775
4776     /*
4777      * CLEANUP ALL the routes
4778      */
4779     fib_table_entry_delete(fib_index,
4780                            &pfx_2001_c_s_64,
4781                            FIB_SOURCE_API);
4782     fib_table_entry_delete(fib_index,
4783                            &pfx_2001_a_s_64,
4784                            FIB_SOURCE_API);
4785     fib_table_entry_delete(fib_index,
4786                            &pfx_2001_b_s_64,
4787                            FIB_SOURCE_API);
4788     fib_table_entry_delete(fib_index,
4789                            &pfx_2001_1_3_s_128,
4790                            FIB_SOURCE_ADJ);
4791     fib_table_entry_delete(fib_index,
4792                            &pfx_2001_1_2_s_128,
4793                            FIB_SOURCE_ADJ);
4794     local_pfx.fp_len = 64;
4795     fib_table_entry_delete(fib_index, &local_pfx,
4796                            FIB_SOURCE_INTERFACE);
4797     local_pfx.fp_len = 128;
4798     fib_table_entry_special_remove(fib_index, &local_pfx,
4799                                    FIB_SOURCE_INTERFACE);
4800     connected_pfx.fp_len = 64;
4801     fib_table_entry_delete(fib_index, &connected_pfx,
4802                            FIB_SOURCE_INTERFACE);
4803     connected_pfx.fp_len = 128;
4804     fib_table_entry_special_remove(fib_index, &connected_pfx,
4805                                    FIB_SOURCE_INTERFACE);
4806
4807     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4808               fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4809              "2001::a/64 removed");
4810     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4811               fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4812              "2001::b/64 removed");
4813     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4814               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4815              "2001:0:0:1::3/128 removed");
4816     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4817               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4818              "2001:0:0:1::3/128 removed");
4819     local_pfx.fp_len = 64;
4820     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4821               fib_table_lookup_exact_match(fib_index, &local_pfx)),
4822              "2001:0:0:1/64 removed");
4823     local_pfx.fp_len = 128;
4824     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4825               fib_table_lookup_exact_match(fib_index, &local_pfx)),
4826              "2001:0:0:1::1/128 removed");
4827     connected_pfx.fp_len = 64;
4828     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4829               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4830              "2001:0:0:2/64 removed");
4831     connected_pfx.fp_len = 128;
4832     FIB_TEST((FIB_NODE_INDEX_INVALID ==
4833               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4834              "2001:0:0:2::1/128 removed");
4835
4836     /*
4837      * -8 entries. -7 path-lists (1 was shared).
4838      */
4839     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4840              fib_path_list_db_size());
4841     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
4842              fib_path_list_pool_size());
4843     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4844              fib_entry_pool_size());
4845
4846     /*
4847      * now remove the VRF
4848      */
4849     fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4850
4851     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4852              fib_path_list_db_size());
4853     FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
4854              fib_path_list_pool_size());
4855     FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
4856              fib_entry_pool_size());
4857
4858     adj_unlock(ai_02);
4859     adj_unlock(ai_01);
4860
4861     /*
4862      * return the interfaces to up state
4863      */
4864     error = vnet_sw_interface_set_flags(vnet_get_main(),
4865                                         tm->hw[0]->sw_if_index,
4866                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4867     error = vnet_sw_interface_set_flags(vnet_get_main(),
4868                                         tm->hw[1]->sw_if_index,
4869                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4870
4871     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4872              adj_nbr_db_size());
4873
4874     return (0);
4875 }
4876
4877 /*
4878  * Test Attached Exports
4879  */
4880 static int
4881 fib_test_ae (void)
4882 {
4883     const dpo_id_t *dpo, *dpo_drop;
4884     const u32 fib_index = 0;
4885     fib_node_index_t fei;
4886     test_main_t *tm;
4887     ip4_main_t *im;
4888
4889     tm = &test_main;
4890     im = &ip4_main;
4891
4892     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4893              adj_nbr_db_size());
4894
4895     /*
4896      * add interface routes. We'll assume this works. It's more rigorously
4897      * tested elsewhere.
4898      */
4899     fib_prefix_t local_pfx = {
4900         .fp_len = 24,
4901         .fp_proto = FIB_PROTOCOL_IP4,
4902         .fp_addr = {
4903             .ip4 = {
4904                 /* 10.10.10.10 */
4905                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4906             },
4907         },
4908     };
4909
4910     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4911     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4912
4913     dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4914
4915     fib_table_entry_update_one_path(fib_index, &local_pfx,
4916                                     FIB_SOURCE_INTERFACE,
4917                                     (FIB_ENTRY_FLAG_CONNECTED |
4918                                      FIB_ENTRY_FLAG_ATTACHED),
4919                                     FIB_PROTOCOL_IP4,
4920                                     NULL,
4921                                     tm->hw[0]->sw_if_index,
4922                                     ~0,
4923                                     1,
4924                                     NULL,
4925                                     FIB_ROUTE_PATH_FLAG_NONE);
4926     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4927     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4928              "attached interface route present");
4929
4930     local_pfx.fp_len = 32;
4931     fib_table_entry_update_one_path(fib_index, &local_pfx,
4932                                     FIB_SOURCE_INTERFACE,
4933                                     (FIB_ENTRY_FLAG_CONNECTED |
4934                                      FIB_ENTRY_FLAG_LOCAL),
4935                                     FIB_PROTOCOL_IP4,
4936                                     NULL,
4937                                     tm->hw[0]->sw_if_index,
4938                                     ~0, // invalid fib index
4939                                     1,
4940                                     NULL,
4941                                     FIB_ROUTE_PATH_FLAG_NONE);
4942     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4943
4944     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4945              "local interface route present");
4946
4947     /*
4948      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4949      */
4950     fib_prefix_t pfx_10_10_10_1_s_32 = {
4951         .fp_len = 32,
4952         .fp_proto = FIB_PROTOCOL_IP4,
4953         .fp_addr = {
4954             /* 10.10.10.1 */
4955             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4956         },
4957     };
4958     fib_node_index_t ai;
4959
4960     fib_table_entry_update_one_path(fib_index,
4961                                     &pfx_10_10_10_1_s_32,
4962                                     FIB_SOURCE_ADJ,
4963                                     FIB_ENTRY_FLAG_ATTACHED,
4964                                     FIB_PROTOCOL_IP4,
4965                                     &pfx_10_10_10_1_s_32.fp_addr,
4966                                     tm->hw[0]->sw_if_index,
4967                                     ~0, // invalid fib index
4968                                     1,
4969                                     NULL,
4970                                     FIB_ROUTE_PATH_FLAG_NONE);
4971
4972     fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4973     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4974     ai = fib_entry_get_adj(fei);
4975
4976     /*
4977      * create another FIB table into which routes will be imported
4978      */
4979     u32 import_fib_index1;
4980
4981     import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4982
4983     /*
4984      * Add an attached route in the import FIB
4985      */
4986     local_pfx.fp_len = 24;
4987     fib_table_entry_update_one_path(import_fib_index1,
4988                                     &local_pfx,
4989                                     FIB_SOURCE_API,
4990                                     FIB_ENTRY_FLAG_NONE,
4991                                     FIB_PROTOCOL_IP4,
4992                                     NULL,
4993                                     tm->hw[0]->sw_if_index,
4994                                     ~0, // invalid fib index
4995                                     1,
4996                                     NULL,
4997                                     FIB_ROUTE_PATH_FLAG_NONE);
4998     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4999     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5000
5001     /*
5002      * check for the presence of the adj-fibs in the import table
5003      */
5004     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5005     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5006     FIB_TEST((ai == fib_entry_get_adj(fei)),
5007              "adj-fib1 Import uses same adj as export");
5008
5009     /*
5010      * check for the presence of the local in the import table
5011      */
5012     local_pfx.fp_len = 32;
5013     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5014     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5015
5016     /*
5017      * Add another adj-fin in the export table. Expect this
5018      * to get magically exported;
5019      */
5020     fib_prefix_t pfx_10_10_10_2_s_32 = {
5021         .fp_len = 32,
5022         .fp_proto = FIB_PROTOCOL_IP4,
5023         .fp_addr = {
5024             /* 10.10.10.2 */
5025             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5026         },
5027     };
5028
5029     fib_table_entry_update_one_path(fib_index,
5030                                     &pfx_10_10_10_2_s_32,
5031                                     FIB_SOURCE_ADJ,
5032                                     FIB_ENTRY_FLAG_ATTACHED,
5033                                     FIB_PROTOCOL_IP4,
5034                                     &pfx_10_10_10_2_s_32.fp_addr,
5035                                     tm->hw[0]->sw_if_index,
5036                                     ~0, // invalid fib index
5037                                     1,
5038                                     NULL,
5039                                     FIB_ROUTE_PATH_FLAG_NONE);
5040     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5041     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5042     ai = fib_entry_get_adj(fei);
5043
5044     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5045     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5046     FIB_TEST((ai == fib_entry_get_adj(fei)),
5047              "Import uses same adj as export");
5048     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5049              "ADJ-fib2 imported flags %d",
5050              fib_entry_get_flags(fei));
5051
5052     /*
5053      * create a 2nd FIB table into which routes will be imported
5054      */
5055     u32 import_fib_index2;
5056
5057     import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
5058
5059     /*
5060      * Add an attached route in the import FIB
5061      */
5062     local_pfx.fp_len = 24;
5063     fib_table_entry_update_one_path(import_fib_index2,
5064                                     &local_pfx,
5065                                     FIB_SOURCE_API,
5066                                     FIB_ENTRY_FLAG_NONE,
5067                                     FIB_PROTOCOL_IP4,
5068                                     NULL,
5069                                     tm->hw[0]->sw_if_index,
5070                                     ~0, // invalid fib index
5071                                     1,
5072                                     NULL,
5073                                     FIB_ROUTE_PATH_FLAG_NONE);
5074     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5075     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5076
5077     /*
5078      * check for the presence of all the adj-fibs and local in the import table
5079      */
5080     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5081     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5082     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5083     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5084     local_pfx.fp_len = 32;
5085     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5086     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5087
5088     /*
5089      * add a 3rd adj-fib. expect it to be exported to both tables.
5090      */
5091     fib_prefix_t pfx_10_10_10_3_s_32 = {
5092         .fp_len = 32,
5093         .fp_proto = FIB_PROTOCOL_IP4,
5094         .fp_addr = {
5095             /* 10.10.10.3 */
5096             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5097         },
5098     };
5099
5100     fib_table_entry_update_one_path(fib_index,
5101                                     &pfx_10_10_10_3_s_32,
5102                                     FIB_SOURCE_ADJ,
5103                                     FIB_ENTRY_FLAG_ATTACHED,
5104                                     FIB_PROTOCOL_IP4,
5105                                     &pfx_10_10_10_3_s_32.fp_addr,
5106                                     tm->hw[0]->sw_if_index,
5107                                     ~0, // invalid fib index
5108                                     1,
5109                                     NULL,
5110                                     FIB_ROUTE_PATH_FLAG_NONE);
5111     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5112     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5113     ai = fib_entry_get_adj(fei);
5114
5115     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5116     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5117     FIB_TEST((ai == fib_entry_get_adj(fei)),
5118              "Import uses same adj as export");
5119     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5120     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5121     FIB_TEST((ai == fib_entry_get_adj(fei)),
5122              "Import uses same adj as export");
5123
5124     /*
5125      * remove the 3rd adj fib. we expect it to be removed from both FIBs
5126      */
5127     fib_table_entry_delete(fib_index,
5128                            &pfx_10_10_10_3_s_32,
5129                            FIB_SOURCE_ADJ);
5130
5131     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5132     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5133
5134     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5135     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5136
5137     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5138     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5139
5140     /*
5141      * remove the attached route from the 2nd FIB. expect the imported
5142      * entires to be removed
5143      */
5144     local_pfx.fp_len = 24;
5145     fib_table_entry_delete(import_fib_index2,
5146                            &local_pfx,
5147                            FIB_SOURCE_API);
5148     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5149     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5150
5151     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5152     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5153     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5154     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5155     local_pfx.fp_len = 32;
5156     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5157     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5158
5159     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5160     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5161     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5162     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5163     local_pfx.fp_len = 32;
5164     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5165     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5166
5167     /*
5168      * modify the route in FIB1 so it is no longer attached. expect the imported
5169      * entires to be removed
5170      */
5171     local_pfx.fp_len = 24;
5172     fib_table_entry_update_one_path(import_fib_index1,
5173                                     &local_pfx,
5174                                     FIB_SOURCE_API,
5175                                     FIB_ENTRY_FLAG_NONE,
5176                                     FIB_PROTOCOL_IP4,
5177                                     &pfx_10_10_10_2_s_32.fp_addr,
5178                                     tm->hw[0]->sw_if_index,
5179                                     ~0, // invalid fib index
5180                                     1,
5181                                     NULL,
5182                                     FIB_ROUTE_PATH_FLAG_NONE);
5183     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5184     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5185     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5186     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5187     local_pfx.fp_len = 32;
5188     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5189     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5190
5191     /*
5192      * modify it back to attached. expect the adj-fibs back
5193      */
5194     local_pfx.fp_len = 24;
5195     fib_table_entry_update_one_path(import_fib_index1,
5196                                     &local_pfx,
5197                                     FIB_SOURCE_API,
5198                                     FIB_ENTRY_FLAG_NONE,
5199                                     FIB_PROTOCOL_IP4,
5200                                     NULL,
5201                                     tm->hw[0]->sw_if_index,
5202                                     ~0, // invalid fib index
5203                                     1,
5204                                     NULL,
5205                                     FIB_ROUTE_PATH_FLAG_NONE);
5206     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5207     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5208     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5209     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5210     local_pfx.fp_len = 32;
5211     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5212     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5213
5214     /*
5215      * add a covering attached next-hop for the interface address, so we have
5216      * a valid adj to find when we check the forwarding tables
5217      */
5218     fib_prefix_t pfx_10_0_0_0_s_8 = {
5219         .fp_len = 8,
5220         .fp_proto = FIB_PROTOCOL_IP4,
5221         .fp_addr = {
5222             /* 10.0.0.0 */
5223             .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5224         },
5225     };
5226
5227     fei = fib_table_entry_update_one_path(fib_index,
5228                                           &pfx_10_0_0_0_s_8,
5229                                           FIB_SOURCE_API,
5230                                           FIB_ENTRY_FLAG_NONE,
5231                                           FIB_PROTOCOL_IP4,
5232                                           &pfx_10_10_10_3_s_32.fp_addr,
5233                                           tm->hw[0]->sw_if_index,
5234                                           ~0, // invalid fib index
5235                                           1,
5236                                           NULL,
5237                                           FIB_ROUTE_PATH_FLAG_NONE);
5238     dpo = fib_entry_contribute_ip_forwarding(fei);
5239
5240     /*
5241      * remove the route in the export fib. expect the adj-fibs to be removed
5242      */
5243     local_pfx.fp_len = 24;
5244     fib_table_entry_delete(fib_index,
5245                            &local_pfx,
5246                            FIB_SOURCE_INTERFACE);
5247
5248     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5249     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5250     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5251     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5252     local_pfx.fp_len = 32;
5253     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5254     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5255
5256     /*
5257      * the adj-fibs in the export VRF are present in the FIB table,
5258      * but not installed in forwarding, since they have no attached cover.
5259      * Consequently a lookup in the MTRIE gives the adj for the covering
5260      * route 10.0.0.0/8.
5261      */
5262     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5263     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5264
5265     index_t lbi;
5266     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5267     FIB_TEST(lbi == dpo->dpoi_index,
5268              "10.10.10.1 forwards on \n%U not \n%U",
5269              format_load_balance, lbi, 0,
5270              format_dpo_id, dpo, 0);
5271     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5272     FIB_TEST(lbi == dpo->dpoi_index,
5273              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5274     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5275     FIB_TEST(lbi == dpo->dpoi_index,
5276              "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5277
5278     /*
5279      * add the export prefix back, but not as attached.
5280      * No adj-fibs in export nor import tables
5281      */
5282     local_pfx.fp_len = 24;
5283     fei = fib_table_entry_update_one_path(fib_index,
5284                                           &local_pfx,
5285                                           FIB_SOURCE_API,
5286                                           FIB_ENTRY_FLAG_NONE,
5287                                           FIB_PROTOCOL_IP4,
5288                                           &pfx_10_10_10_1_s_32.fp_addr,
5289                                           tm->hw[0]->sw_if_index,
5290                                           ~0, // invalid fib index
5291                                           1,
5292                                           NULL,
5293                                           FIB_ROUTE_PATH_FLAG_NONE);
5294     dpo = fib_entry_contribute_ip_forwarding(fei);
5295
5296     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5297     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5298     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5299     FIB_TEST(lbi == dpo->dpoi_index,
5300              "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
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 in export");
5303     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5304     FIB_TEST(lbi == dpo->dpoi_index,
5305              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5306
5307     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5308     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5309     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5310     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5311     local_pfx.fp_len = 32;
5312     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5313     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5314
5315     /*
5316      * modify the export prefix so it is attached. expect all covereds to return
5317      */
5318     local_pfx.fp_len = 24;
5319     fib_table_entry_update_one_path(fib_index,
5320                                     &local_pfx,
5321                                     FIB_SOURCE_API,
5322                                     FIB_ENTRY_FLAG_NONE,
5323                                     FIB_PROTOCOL_IP4,
5324                                     NULL,
5325                                     tm->hw[0]->sw_if_index,
5326                                     ~0, // invalid fib index
5327                                     1,
5328                                     NULL,
5329                                     FIB_ROUTE_PATH_FLAG_NONE);
5330
5331     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5332     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5333     dpo = fib_entry_contribute_ip_forwarding(fei);
5334     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5335              "Adj-fib1 is not drop in export");
5336     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5337     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5338     local_pfx.fp_len = 32;
5339     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5340     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5341     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5342     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5343     dpo = fib_entry_contribute_ip_forwarding(fei);
5344     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5345              "Adj-fib1 is not drop in export");
5346     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5347     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5348     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5349     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5350     local_pfx.fp_len = 32;
5351     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5352     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5353
5354     /*
5355      * modify the export prefix so connected. no change.
5356      */
5357     local_pfx.fp_len = 24;
5358     fib_table_entry_update_one_path(fib_index, &local_pfx,
5359                                     FIB_SOURCE_INTERFACE,
5360                                     (FIB_ENTRY_FLAG_CONNECTED |
5361                                      FIB_ENTRY_FLAG_ATTACHED),
5362                                     FIB_PROTOCOL_IP4,
5363                                     NULL,
5364                                     tm->hw[0]->sw_if_index,
5365                                     ~0,
5366                                     1,
5367                                     NULL,
5368                                     FIB_ROUTE_PATH_FLAG_NONE);
5369
5370     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5371     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5372     dpo = fib_entry_contribute_ip_forwarding(fei);
5373     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5374              "Adj-fib1 is not drop in export");
5375     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5376     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5377     local_pfx.fp_len = 32;
5378     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5379     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5380     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5381     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5382     dpo = fib_entry_contribute_ip_forwarding(fei);
5383     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5384              "Adj-fib1 is not drop in export");
5385     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5386     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5387     local_pfx.fp_len = 32;
5388     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5389     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5390
5391     /*
5392      * CLEANUP
5393      */
5394     fib_table_entry_delete(fib_index,
5395                            &pfx_10_0_0_0_s_8,
5396                            FIB_SOURCE_API);
5397     fib_table_entry_delete(fib_index,
5398                            &pfx_10_10_10_1_s_32,
5399                            FIB_SOURCE_ADJ);
5400     fib_table_entry_delete(fib_index,
5401                            &pfx_10_10_10_2_s_32,
5402                            FIB_SOURCE_ADJ);
5403     local_pfx.fp_len = 32;
5404     fib_table_entry_delete(fib_index,
5405                            &local_pfx,
5406                            FIB_SOURCE_INTERFACE);
5407     local_pfx.fp_len = 24;
5408     fib_table_entry_delete(fib_index,
5409                            &local_pfx,
5410                            FIB_SOURCE_API);
5411     fib_table_entry_delete(fib_index,
5412                            &local_pfx,
5413                            FIB_SOURCE_INTERFACE);
5414     local_pfx.fp_len = 24;
5415     fib_table_entry_delete(import_fib_index1,
5416                            &local_pfx,
5417                            FIB_SOURCE_API);
5418
5419     fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5420     fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5421
5422     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5423              adj_nbr_db_size());
5424
5425     return (0);
5426 }
5427
5428
5429 /*
5430  * Test the recursive route route handling for GRE tunnels
5431  */
5432 static int
5433 fib_test_label (void)
5434 {
5435     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;
5436     const u32 fib_index = 0;
5437     test_main_t *tm;
5438     ip4_main_t *im;
5439     int lb_count, ii;
5440
5441     lb_count = pool_elts(load_balance_pool);
5442     tm = &test_main;
5443     im = &ip4_main;
5444
5445     /*
5446      * add interface routes. We'll assume this works. It's more rigorously
5447      * tested elsewhere.
5448      */
5449     fib_prefix_t local0_pfx = {
5450         .fp_len = 24,
5451         .fp_proto = FIB_PROTOCOL_IP4,
5452         .fp_addr = {
5453             .ip4 = {
5454                 /* 10.10.10.10 */
5455                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5456             },
5457         },
5458     };
5459
5460     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5461              adj_nbr_db_size());
5462
5463     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5464     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5465
5466     fib_table_entry_update_one_path(fib_index, &local0_pfx,
5467                                     FIB_SOURCE_INTERFACE,
5468                                     (FIB_ENTRY_FLAG_CONNECTED |
5469                                      FIB_ENTRY_FLAG_ATTACHED),
5470                                     FIB_PROTOCOL_IP4,
5471                                     NULL,
5472                                     tm->hw[0]->sw_if_index,
5473                                     ~0,
5474                                     1,
5475                                     NULL,
5476                                     FIB_ROUTE_PATH_FLAG_NONE);
5477     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5478     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5479              "attached interface route present");
5480
5481     local0_pfx.fp_len = 32;
5482     fib_table_entry_update_one_path(fib_index, &local0_pfx,
5483                                     FIB_SOURCE_INTERFACE,
5484                                     (FIB_ENTRY_FLAG_CONNECTED |
5485                                      FIB_ENTRY_FLAG_LOCAL),
5486                                     FIB_PROTOCOL_IP4,
5487                                     NULL,
5488                                     tm->hw[0]->sw_if_index,
5489                                     ~0, // invalid fib index
5490                                     1,
5491                                     NULL,
5492                                     FIB_ROUTE_PATH_FLAG_NONE);
5493     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5494
5495     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5496              "local interface route present");
5497
5498     fib_prefix_t local1_pfx = {
5499         .fp_len = 24,
5500         .fp_proto = FIB_PROTOCOL_IP4,
5501         .fp_addr = {
5502             .ip4 = {
5503                 /* 10.10.11.10 */
5504                 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5505             },
5506         },
5507     };
5508
5509     vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5510     im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5511
5512     fib_table_entry_update_one_path(fib_index, &local1_pfx,
5513                                     FIB_SOURCE_INTERFACE,
5514                                     (FIB_ENTRY_FLAG_CONNECTED |
5515                                      FIB_ENTRY_FLAG_ATTACHED),
5516                                     FIB_PROTOCOL_IP4,
5517                                     NULL,
5518                                     tm->hw[1]->sw_if_index,
5519                                     ~0,
5520                                     1,
5521                                     NULL,
5522                                     FIB_ROUTE_PATH_FLAG_NONE);
5523     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5524     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5525              "attached interface route present");
5526
5527     local1_pfx.fp_len = 32;
5528     fib_table_entry_update_one_path(fib_index, &local1_pfx,
5529                                     FIB_SOURCE_INTERFACE,
5530                                     (FIB_ENTRY_FLAG_CONNECTED |
5531                                      FIB_ENTRY_FLAG_LOCAL),
5532                                     FIB_PROTOCOL_IP4,
5533                                     NULL,
5534                                     tm->hw[1]->sw_if_index,
5535                                     ~0, // invalid fib index
5536                                     1,
5537                                     NULL,
5538                                     FIB_ROUTE_PATH_FLAG_NONE);
5539     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5540
5541     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5542              "local interface route present");
5543
5544     ip46_address_t nh_10_10_10_1 = {
5545         .ip4 = {
5546             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5547         },
5548     };
5549     ip46_address_t nh_10_10_11_1 = {
5550         .ip4 = {
5551             .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5552         },
5553     };
5554     ip46_address_t nh_10_10_11_2 = {
5555         .ip4 = {
5556             .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5557         },
5558     };
5559
5560     ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5561                                            VNET_LINK_IP4,
5562                                            &nh_10_10_11_1,
5563                                            tm->hw[1]->sw_if_index);
5564     ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5565                                            VNET_LINK_IP4,
5566                                            &nh_10_10_11_2,
5567                                            tm->hw[1]->sw_if_index);
5568     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5569                                              VNET_LINK_MPLS,
5570                                              &nh_10_10_10_1,
5571                                              tm->hw[0]->sw_if_index);
5572     ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5573                                              VNET_LINK_MPLS,
5574                                              &nh_10_10_11_2,
5575                                              tm->hw[1]->sw_if_index);
5576     ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5577                                              VNET_LINK_MPLS,
5578                                              &nh_10_10_11_1,
5579                                              tm->hw[1]->sw_if_index);
5580
5581     /*
5582      * Add an etry with one path with a real out-going label
5583      */
5584     fib_prefix_t pfx_1_1_1_1_s_32 = {
5585         .fp_len = 32,
5586         .fp_proto = FIB_PROTOCOL_IP4,
5587         .fp_addr = {
5588             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5589         },
5590     };
5591     fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5592         .type = FT_LB_LABEL_O_ADJ,
5593         .label_o_adj = {
5594             .adj = ai_mpls_10_10_10_1,
5595             .label = 99,
5596             .eos = MPLS_EOS,
5597         },
5598     };
5599     fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5600         .type = FT_LB_LABEL_O_ADJ,
5601         .label_o_adj = {
5602             .adj = ai_mpls_10_10_10_1,
5603             .label = 99,
5604             .eos = MPLS_NON_EOS,
5605         },
5606     };
5607     mpls_label_t *l99 = NULL;
5608     vec_add1(l99, 99);
5609
5610     fib_table_entry_update_one_path(fib_index,
5611                                     &pfx_1_1_1_1_s_32,
5612                                     FIB_SOURCE_API,
5613                                     FIB_ENTRY_FLAG_NONE,
5614                                     FIB_PROTOCOL_IP4,
5615                                     &nh_10_10_10_1,
5616                                     tm->hw[0]->sw_if_index,
5617                                     ~0, // invalid fib index
5618                                     1,
5619                                     l99,
5620                                     FIB_ROUTE_PATH_FLAG_NONE);
5621
5622     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5623     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5624
5625     FIB_TEST(fib_test_validate_entry(fei, 
5626                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5627                                      1,
5628                                      &l99_eos_o_10_10_10_1),
5629              "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5630
5631     /*
5632      * add a path with an implicit NULL label
5633      */
5634     fib_test_lb_bucket_t a_o_10_10_11_1 = {
5635         .type = FT_LB_ADJ,
5636         .adj = {
5637             .adj = ai_v4_10_10_11_1,
5638         },
5639     };
5640     fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5641         .type = FT_LB_ADJ,
5642         .adj = {
5643             .adj = ai_mpls_10_10_11_1,
5644         },
5645     };
5646     mpls_label_t *l_imp_null = NULL;
5647     vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5648
5649     fei = fib_table_entry_path_add(fib_index,
5650                                    &pfx_1_1_1_1_s_32,
5651                                    FIB_SOURCE_API,
5652                                    FIB_ENTRY_FLAG_NONE,
5653                                    FIB_PROTOCOL_IP4,
5654                                    &nh_10_10_11_1,
5655                                    tm->hw[1]->sw_if_index,
5656                                    ~0, // invalid fib index
5657                                    1,
5658                                    l_imp_null,
5659                                    FIB_ROUTE_PATH_FLAG_NONE);
5660
5661     FIB_TEST(fib_test_validate_entry(fei, 
5662                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5663                                      2,
5664                                      &l99_eos_o_10_10_10_1,
5665                                      &a_o_10_10_11_1),
5666              "1.1.1.1/32 LB 2 buckets via: "
5667              "label 99 over 10.10.10.1, "
5668              "adj over 10.10.11.1");
5669
5670     /*
5671      * assign the route a local label
5672      */
5673     fib_table_entry_local_label_add(fib_index,
5674                                     &pfx_1_1_1_1_s_32,
5675                                     24001);
5676
5677     fib_prefix_t pfx_24001_eos = {
5678         .fp_proto = FIB_PROTOCOL_MPLS,
5679         .fp_label = 24001,
5680         .fp_eos = MPLS_EOS,
5681     };
5682     fib_prefix_t pfx_24001_neos = {
5683         .fp_proto = FIB_PROTOCOL_MPLS,
5684         .fp_label = 24001,
5685         .fp_eos = MPLS_NON_EOS,
5686     };
5687
5688     /*
5689      * The EOS entry should link to both the paths,
5690      *  and use an ip adj for the imp-null
5691      * The NON-EOS entry should link to both the paths,
5692      *  and use an mpls adj for the imp-null
5693      */
5694     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5695                            &pfx_24001_eos);
5696     FIB_TEST(fib_test_validate_entry(fei, 
5697                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5698                                      2,
5699                                      &l99_eos_o_10_10_10_1,
5700                                      &a_o_10_10_11_1),
5701              "24001/eos LB 2 buckets via: "
5702              "label 99 over 10.10.10.1, "
5703              "adj over 10.10.11.1");
5704
5705
5706     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5707                            &pfx_24001_neos);
5708     FIB_TEST(fib_test_validate_entry(fei, 
5709                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5710                                      2,
5711                                      &l99_neos_o_10_10_10_1,
5712                                      &a_mpls_o_10_10_11_1),
5713              "24001/neos LB 1 bucket via: "
5714              "label 99 over 10.10.10.1 ",
5715              "mpls-adj via 10.10.11.1");
5716
5717     /*
5718      * add an unlabelled path, this is excluded from the neos chains,
5719      */
5720     fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5721         .type = FT_LB_ADJ,
5722         .adj = {
5723             .adj = ai_v4_10_10_11_2,
5724         },
5725     };
5726
5727     fei = fib_table_entry_path_add(fib_index,
5728                                    &pfx_1_1_1_1_s_32,
5729                                    FIB_SOURCE_API,
5730                                    FIB_ENTRY_FLAG_NONE,
5731                                    FIB_PROTOCOL_IP4,
5732                                    &nh_10_10_11_2,
5733                                    tm->hw[1]->sw_if_index,
5734                                    ~0, // invalid fib index
5735                                    1,
5736                                    NULL,
5737                                    FIB_ROUTE_PATH_FLAG_NONE);
5738
5739     FIB_TEST(fib_test_validate_entry(fei, 
5740                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5741                                      16, // 3 choices spread over 16 buckets
5742                                      &l99_eos_o_10_10_10_1,
5743                                      &l99_eos_o_10_10_10_1,
5744                                      &l99_eos_o_10_10_10_1,
5745                                      &l99_eos_o_10_10_10_1,
5746                                      &l99_eos_o_10_10_10_1,
5747                                      &l99_eos_o_10_10_10_1,
5748                                      &a_o_10_10_11_1,
5749                                      &a_o_10_10_11_1,
5750                                      &a_o_10_10_11_1,
5751                                      &a_o_10_10_11_1,
5752                                      &a_o_10_10_11_1,
5753                                      &adj_o_10_10_11_2,
5754                                      &adj_o_10_10_11_2,
5755                                      &adj_o_10_10_11_2,
5756                                      &adj_o_10_10_11_2,
5757                                      &adj_o_10_10_11_2),
5758              "1.1.1.1/32 LB 16 buckets via: "
5759              "label 99 over 10.10.10.1, "
5760              "adj over 10.10.11.1",
5761              "adj over 10.10.11.2");
5762
5763     /*
5764      * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5765      */
5766     dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5767     fib_entry_contribute_forwarding(fei,
5768                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5769                                     &non_eos_1_1_1_1);
5770
5771     /*
5772      * n-eos has only the 2 labelled paths
5773      */
5774     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5775                            &pfx_24001_neos);
5776
5777     FIB_TEST(fib_test_validate_entry(fei,
5778                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5779                                      2,
5780                                      &l99_neos_o_10_10_10_1,
5781                                      &a_mpls_o_10_10_11_1),
5782              "24001/neos LB 2 buckets via: "
5783              "label 99 over 10.10.10.1, "
5784              "adj-mpls over 10.10.11.2");
5785
5786     /*
5787      * A labelled recursive
5788      */
5789     fib_prefix_t pfx_2_2_2_2_s_32 = {
5790         .fp_len = 32,
5791         .fp_proto = FIB_PROTOCOL_IP4,
5792         .fp_addr = {
5793             .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5794         },
5795     };
5796     fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5797         .type = FT_LB_LABEL_O_LB,
5798         .label_o_lb = {
5799             .lb = non_eos_1_1_1_1.dpoi_index,
5800             .label = 1600,
5801             .eos = MPLS_EOS,
5802         },
5803     };
5804     mpls_label_t *l1600 = NULL;
5805     vec_add1(l1600, 1600);
5806
5807     fib_table_entry_update_one_path(fib_index,
5808                                     &pfx_2_2_2_2_s_32,
5809                                     FIB_SOURCE_API,
5810                                     FIB_ENTRY_FLAG_NONE,
5811                                     FIB_PROTOCOL_IP4,
5812                                     &pfx_1_1_1_1_s_32.fp_addr,
5813                                     ~0,
5814                                     fib_index,
5815                                     1,
5816                                     l1600,
5817                                     FIB_ROUTE_PATH_FLAG_NONE);
5818
5819     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5820     FIB_TEST(fib_test_validate_entry(fei, 
5821                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5822                                      1,
5823                                      &l1600_eos_o_1_1_1_1),
5824              "2.2.2.2.2/32 LB 1 buckets via: "
5825              "label 1600 over 1.1.1.1");
5826
5827     dpo_id_t dpo_44 = DPO_INVALID;
5828     index_t urpfi;
5829
5830     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5831     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5832
5833     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5834              "uRPF check for 2.2.2.2/32 on %d OK",
5835              tm->hw[0]->sw_if_index);
5836     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5837              "uRPF check for 2.2.2.2/32 on %d OK",
5838              tm->hw[1]->sw_if_index);
5839     FIB_TEST(!fib_urpf_check(urpfi, 99),
5840              "uRPF check for 2.2.2.2/32 on 99 not-OK",
5841              99);
5842
5843     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5844     FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5845              "Shared uRPF on IP and non-EOS chain");
5846
5847     dpo_reset(&dpo_44);
5848
5849     /*
5850      * we are holding a lock on the non-eos LB of the via-entry.
5851      * do a PIC-core failover by shutting the link of the via-entry.
5852      *
5853      * shut down the link with the valid label
5854      */
5855     vnet_sw_interface_set_flags(vnet_get_main(),
5856                                 tm->hw[0]->sw_if_index,
5857                                 0);
5858
5859     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5860     FIB_TEST(fib_test_validate_entry(fei, 
5861                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5862                                      2,
5863                                      &a_o_10_10_11_1,
5864                                      &adj_o_10_10_11_2),
5865              "1.1.1.1/32 LB 2 buckets via: "
5866              "adj over 10.10.11.1, ",
5867              "adj-v4 over 10.10.11.2");
5868
5869     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5870                            &pfx_24001_eos);
5871     FIB_TEST(fib_test_validate_entry(fei, 
5872                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5873                                      2,
5874                                      &a_o_10_10_11_1,
5875                                      &adj_o_10_10_11_2),
5876              "24001/eos LB 2 buckets via: "
5877              "adj over 10.10.11.1, ",
5878              "adj-v4 over 10.10.11.2");
5879
5880     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5881                            &pfx_24001_neos);
5882     FIB_TEST(fib_test_validate_entry(fei,
5883                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5884                                      1,
5885                                      &a_mpls_o_10_10_11_1),
5886              "24001/neos LB 1 buckets via: "
5887              "adj-mpls over 10.10.11.2");
5888
5889     /*
5890      * test that the pre-failover load-balance has been in-place
5891      * modified
5892      */
5893     dpo_id_t current = DPO_INVALID;
5894     fib_entry_contribute_forwarding(fei,
5895                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5896                                     &current);
5897
5898     FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5899                       &current),
5900              "PIC-core LB inplace modified %U %U",
5901              format_dpo_id, &non_eos_1_1_1_1, 0,
5902              format_dpo_id, &current, 0);
5903
5904     dpo_reset(&non_eos_1_1_1_1);
5905     dpo_reset(&current);
5906
5907     /*
5908      * no-shut the link with the valid label
5909      */
5910     vnet_sw_interface_set_flags(vnet_get_main(),
5911                                 tm->hw[0]->sw_if_index,
5912                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5913
5914     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5915     FIB_TEST(fib_test_validate_entry(fei, 
5916                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5917                                      16, // 3 choices spread over 16 buckets
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                                      &l99_eos_o_10_10_10_1,
5922                                      &l99_eos_o_10_10_10_1,
5923                                      &l99_eos_o_10_10_10_1,
5924                                      &a_o_10_10_11_1,
5925                                      &a_o_10_10_11_1,
5926                                      &a_o_10_10_11_1,
5927                                      &a_o_10_10_11_1,
5928                                      &a_o_10_10_11_1,
5929                                      &adj_o_10_10_11_2,
5930                                      &adj_o_10_10_11_2,
5931                                      &adj_o_10_10_11_2,
5932                                      &adj_o_10_10_11_2,
5933                                      &adj_o_10_10_11_2),
5934              "1.1.1.1/32 LB 16 buckets via: "
5935              "label 99 over 10.10.10.1, "
5936              "adj over 10.10.11.1",
5937              "adj-v4 over 10.10.11.2");
5938
5939
5940     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5941                            &pfx_24001_eos);
5942     FIB_TEST(fib_test_validate_entry(fei, 
5943                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5944                                      16, // 3 choices spread over 16 buckets
5945                                      &l99_eos_o_10_10_10_1,
5946                                      &l99_eos_o_10_10_10_1,
5947                                      &l99_eos_o_10_10_10_1,
5948                                      &l99_eos_o_10_10_10_1,
5949                                      &l99_eos_o_10_10_10_1,
5950                                      &l99_eos_o_10_10_10_1,
5951                                      &a_o_10_10_11_1,
5952                                      &a_o_10_10_11_1,
5953                                      &a_o_10_10_11_1,
5954                                      &a_o_10_10_11_1,
5955                                      &a_o_10_10_11_1,
5956                                      &adj_o_10_10_11_2,
5957                                      &adj_o_10_10_11_2,
5958                                      &adj_o_10_10_11_2,
5959                                      &adj_o_10_10_11_2,
5960                                      &adj_o_10_10_11_2),
5961              "24001/eos LB 16 buckets via: "
5962              "label 99 over 10.10.10.1, "
5963              "adj over 10.10.11.1",
5964              "adj-v4 over 10.10.11.2");
5965
5966     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5967                            &pfx_24001_neos);
5968     FIB_TEST(fib_test_validate_entry(fei, 
5969                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5970                                      2,
5971                                      &l99_neos_o_10_10_10_1,
5972                                      &a_mpls_o_10_10_11_1),
5973              "24001/neos LB 2 buckets via: "
5974              "label 99 over 10.10.10.1, "
5975              "adj-mpls over 10.10.11.2");
5976
5977     /*
5978      * remove the first path with the valid label
5979      */
5980     fib_table_entry_path_remove(fib_index,
5981                                 &pfx_1_1_1_1_s_32,
5982                                 FIB_SOURCE_API,
5983                                 FIB_PROTOCOL_IP4,
5984                                 &nh_10_10_10_1,
5985                                 tm->hw[0]->sw_if_index,
5986                                 ~0, // invalid fib index
5987                                 1,
5988                                 FIB_ROUTE_PATH_FLAG_NONE);
5989
5990     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5991     FIB_TEST(fib_test_validate_entry(fei, 
5992                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5993                                      2,
5994                                      &a_o_10_10_11_1,
5995                                      &adj_o_10_10_11_2),
5996              "1.1.1.1/32 LB 2 buckets via: "
5997              "adj over 10.10.11.1, "
5998              "adj-v4 over 10.10.11.2");
5999
6000     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6001                            &pfx_24001_eos);
6002     FIB_TEST(fib_test_validate_entry(fei, 
6003                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6004                                      2,
6005                                      &a_o_10_10_11_1,
6006                                      &adj_o_10_10_11_2),
6007              "24001/eos LB 2 buckets via: "
6008              "adj over 10.10.11.1, "
6009              "adj-v4 over 10.10.11.2");
6010
6011     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6012                            &pfx_24001_neos);
6013
6014     FIB_TEST(fib_test_validate_entry(fei, 
6015                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6016                                      1,
6017                                      &a_mpls_o_10_10_11_1),
6018              "24001/neos LB 1 buckets via: "
6019              "adj-mpls over 10.10.11.2");
6020
6021     /*
6022      * remove the other path with a valid label
6023      */
6024     fib_test_lb_bucket_t bucket_drop = {
6025         .type = FT_LB_SPECIAL,
6026         .special = {
6027             .adj = DPO_PROTO_IP4,
6028         },
6029     };
6030     fib_test_lb_bucket_t mpls_bucket_drop = {
6031         .type = FT_LB_SPECIAL,
6032         .special = {
6033             .adj = DPO_PROTO_MPLS,
6034         },
6035     };
6036
6037     fib_table_entry_path_remove(fib_index,
6038                                 &pfx_1_1_1_1_s_32,
6039                                 FIB_SOURCE_API,
6040                                 FIB_PROTOCOL_IP4,
6041                                 &nh_10_10_11_1,
6042                                 tm->hw[1]->sw_if_index,
6043                                 ~0, // invalid fib index
6044                                 1,
6045                                 FIB_ROUTE_PATH_FLAG_NONE);
6046
6047     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6048     FIB_TEST(fib_test_validate_entry(fei, 
6049                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6050                                      1,
6051                                      &adj_o_10_10_11_2),
6052              "1.1.1.1/32 LB 1 buckets via: "
6053              "adj over 10.10.11.2");
6054
6055     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6056                            &pfx_24001_eos);
6057     FIB_TEST(fib_test_validate_entry(fei, 
6058                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6059                                      1,
6060                                      &adj_o_10_10_11_2),
6061              "24001/eos LB 1 buckets via: "
6062              "adj over 10.10.11.2");
6063
6064     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6065                            &pfx_24001_neos);
6066     FIB_TEST(fib_test_validate_entry(fei, 
6067                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6068                                      1,
6069                                      &mpls_bucket_drop),
6070              "24001/neos LB 1 buckets via: DROP");
6071
6072     /*
6073      * add back the path with the valid label
6074      */
6075     l99 = NULL;
6076     vec_add1(l99, 99);
6077
6078     fib_table_entry_path_add(fib_index,
6079                              &pfx_1_1_1_1_s_32,
6080                              FIB_SOURCE_API,
6081                              FIB_ENTRY_FLAG_NONE,
6082                              FIB_PROTOCOL_IP4,
6083                              &nh_10_10_10_1,
6084                              tm->hw[0]->sw_if_index,
6085                              ~0, // invalid fib index
6086                              1,
6087                              l99,
6088                              FIB_ROUTE_PATH_FLAG_NONE);
6089
6090     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6091     FIB_TEST(fib_test_validate_entry(fei,
6092                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6093                                      2,
6094                                      &l99_eos_o_10_10_10_1,
6095                                      &adj_o_10_10_11_2),
6096              "1.1.1.1/32 LB 2 buckets via: "
6097              "label 99 over 10.10.10.1, "
6098              "adj over 10.10.11.2");
6099
6100     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6101                            &pfx_24001_eos);
6102     FIB_TEST(fib_test_validate_entry(fei, 
6103                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6104                                      2,
6105                                      &l99_eos_o_10_10_10_1,
6106                                      &adj_o_10_10_11_2),
6107              "24001/eos LB 2 buckets via: "
6108              "label 99 over 10.10.10.1, "
6109              "adj over 10.10.11.2");
6110
6111     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6112                            &pfx_24001_neos);
6113     FIB_TEST(fib_test_validate_entry(fei, 
6114                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6115                                      1,
6116                                      &l99_neos_o_10_10_10_1),
6117              "24001/neos LB 1 buckets via: "
6118              "label 99 over 10.10.10.1");
6119
6120     /*
6121      * change the local label
6122      */
6123     fib_table_entry_local_label_add(fib_index,
6124                                     &pfx_1_1_1_1_s_32,
6125                                     25005);
6126
6127     fib_prefix_t pfx_25005_eos = {
6128         .fp_proto = FIB_PROTOCOL_MPLS,
6129         .fp_label = 25005,
6130         .fp_eos = MPLS_EOS,
6131     };
6132     fib_prefix_t pfx_25005_neos = {
6133         .fp_proto = FIB_PROTOCOL_MPLS,
6134         .fp_label = 25005,
6135         .fp_eos = MPLS_NON_EOS,
6136     };
6137
6138     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6139               fib_table_lookup(fib_index, &pfx_24001_eos)),
6140              "24001/eos removed after label change");
6141     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6142               fib_table_lookup(fib_index, &pfx_24001_neos)),
6143              "24001/eos removed after label change");
6144
6145     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6146                            &pfx_25005_eos);
6147     FIB_TEST(fib_test_validate_entry(fei,
6148                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6149                                      2,
6150                                      &l99_eos_o_10_10_10_1,
6151                                      &adj_o_10_10_11_2),
6152              "25005/eos LB 2 buckets via: "
6153              "label 99 over 10.10.10.1, "
6154              "adj over 10.10.11.2");
6155
6156     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6157                            &pfx_25005_neos);
6158     FIB_TEST(fib_test_validate_entry(fei,
6159                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6160                                      1,
6161                                      &l99_neos_o_10_10_10_1),
6162              "25005/neos LB 1 buckets via: "
6163              "label 99 over 10.10.10.1");
6164
6165     /*
6166      * remove the local label.
6167      * the check that the MPLS entries are gone is done by the fact the
6168      * MPLS table is no longer present.
6169      */
6170     fib_table_entry_local_label_remove(fib_index,
6171                                        &pfx_1_1_1_1_s_32,
6172                                        25005);
6173
6174     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6175     FIB_TEST(fib_test_validate_entry(fei, 
6176                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6177                                      2,
6178                                      &l99_eos_o_10_10_10_1,
6179                                      &adj_o_10_10_11_2),
6180              "24001/eos LB 2 buckets via: "
6181              "label 99 over 10.10.10.1, "
6182              "adj over 10.10.11.2");
6183
6184     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6185               mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6186              "No more MPLS FIB entries => table removed");
6187
6188     /*
6189      * add another via-entry for the recursive
6190      */
6191     fib_prefix_t pfx_1_1_1_2_s_32 = {
6192         .fp_len = 32,
6193         .fp_proto = FIB_PROTOCOL_IP4,
6194         .fp_addr = {
6195             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6196         },
6197     };
6198     fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6199         .type = FT_LB_LABEL_O_ADJ,
6200         .label_o_adj = {
6201             .adj = ai_mpls_10_10_10_1,
6202             .label = 101,
6203             .eos = MPLS_EOS,
6204         },
6205     };
6206     mpls_label_t *l101 = NULL;
6207     vec_add1(l101, 101);
6208
6209     fei = fib_table_entry_update_one_path(fib_index,
6210                                           &pfx_1_1_1_2_s_32,
6211                                           FIB_SOURCE_API,
6212                                           FIB_ENTRY_FLAG_NONE,
6213                                           FIB_PROTOCOL_IP4,
6214                                           &nh_10_10_10_1,
6215                                           tm->hw[0]->sw_if_index,
6216                                           ~0, // invalid fib index
6217                                           1,
6218                                           l101,
6219                                           FIB_ROUTE_PATH_FLAG_NONE);
6220
6221     FIB_TEST(fib_test_validate_entry(fei,
6222                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6223                                      1,
6224                                      &l101_eos_o_10_10_10_1),
6225              "1.1.1.2/32 LB 1 buckets via: "
6226              "label 101 over 10.10.10.1");
6227
6228     dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6229     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6230                                                      &pfx_1_1_1_1_s_32),
6231                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6232                                     &non_eos_1_1_1_1);
6233     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6234                                                      &pfx_1_1_1_2_s_32),
6235                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6236                                     &non_eos_1_1_1_2);
6237
6238     fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6239         .type = FT_LB_LABEL_O_LB,
6240         .label_o_lb = {
6241             .lb = non_eos_1_1_1_2.dpoi_index,
6242             .label = 1601,
6243             .eos = MPLS_EOS,
6244         },
6245     };
6246     mpls_label_t *l1601 = NULL;
6247     vec_add1(l1601, 1601);
6248
6249     l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6250
6251     fei = fib_table_entry_path_add(fib_index,
6252                                    &pfx_2_2_2_2_s_32,
6253                                    FIB_SOURCE_API,
6254                                    FIB_ENTRY_FLAG_NONE,
6255                                    FIB_PROTOCOL_IP4,
6256                                    &pfx_1_1_1_2_s_32.fp_addr,
6257                                    ~0,
6258                                    fib_index,
6259                                    1,
6260                                    l1601,
6261                                    FIB_ROUTE_PATH_FLAG_NONE);
6262
6263     FIB_TEST(fib_test_validate_entry(fei, 
6264                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6265                                      2,
6266                                      &l1600_eos_o_1_1_1_1,
6267                                      &l1601_eos_o_1_1_1_2),
6268              "2.2.2.2/32 LB 2 buckets via: "
6269              "label 1600 via 1.1,1.1, "
6270              "label 16001 via 1.1.1.2");
6271
6272     /*
6273      * update the via-entry so it no longer has an imp-null path.
6274      * the LB for the recursive can use an imp-null
6275      */
6276     l_imp_null = NULL;
6277     vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6278
6279     fei = fib_table_entry_update_one_path(fib_index,
6280                                           &pfx_1_1_1_2_s_32,
6281                                           FIB_SOURCE_API,
6282                                           FIB_ENTRY_FLAG_NONE,
6283                                           FIB_PROTOCOL_IP4,
6284                                           &nh_10_10_11_1,
6285                                           tm->hw[1]->sw_if_index,
6286                                           ~0, // invalid fib index
6287                                           1,
6288                                           l_imp_null,
6289                                           FIB_ROUTE_PATH_FLAG_NONE);
6290
6291     FIB_TEST(fib_test_validate_entry(fei,
6292                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6293                                      1,
6294                                      &a_o_10_10_11_1),
6295              "1.1.1.2/32 LB 1 buckets via: "
6296              "adj 10.10.11.1");
6297  
6298     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6299     FIB_TEST(fib_test_validate_entry(fei, 
6300                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6301                                      2,
6302                                      &l1600_eos_o_1_1_1_1,
6303                                      &l1601_eos_o_1_1_1_2),
6304              "2.2.2.2/32 LB 2 buckets via: "
6305              "label 1600 via 1.1,1.1, "
6306              "label 16001 via 1.1.1.2");
6307
6308     /*
6309      * update the via-entry so it no longer has labelled paths.
6310      * the LB for the recursive should exclue this via form its LB
6311      */
6312     fei = fib_table_entry_update_one_path(fib_index,
6313                                           &pfx_1_1_1_2_s_32,
6314                                           FIB_SOURCE_API,
6315                                           FIB_ENTRY_FLAG_NONE,
6316                                           FIB_PROTOCOL_IP4,
6317                                           &nh_10_10_11_1,
6318                                           tm->hw[1]->sw_if_index,
6319                                           ~0, // invalid fib index
6320                                           1,
6321                                           NULL,
6322                                           FIB_ROUTE_PATH_FLAG_NONE);
6323
6324     FIB_TEST(fib_test_validate_entry(fei,
6325                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6326                                      1,
6327                                      &a_o_10_10_11_1),
6328              "1.1.1.2/32 LB 1 buckets via: "
6329              "adj 10.10.11.1");
6330  
6331     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6332     FIB_TEST(fib_test_validate_entry(fei, 
6333                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6334                                      1,
6335                                      &l1600_eos_o_1_1_1_1),
6336              "2.2.2.2/32 LB 1 buckets via: "
6337              "label 1600 via 1.1,1.1");
6338
6339     dpo_reset(&non_eos_1_1_1_1);
6340     dpo_reset(&non_eos_1_1_1_2);
6341
6342     /*
6343      * Add a recursive with no out-labels. We expect to use the IP of the via
6344      */
6345     fib_prefix_t pfx_2_2_2_3_s_32 = {
6346         .fp_len = 32,
6347         .fp_proto = FIB_PROTOCOL_IP4,
6348         .fp_addr = {
6349             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6350         },
6351     };
6352     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6353
6354     fib_table_entry_update_one_path(fib_index,
6355                                     &pfx_2_2_2_3_s_32,
6356                                     FIB_SOURCE_API,
6357                                     FIB_ENTRY_FLAG_NONE,
6358                                     FIB_PROTOCOL_IP4,
6359                                     &pfx_1_1_1_1_s_32.fp_addr,
6360                                     ~0,
6361                                     fib_index,
6362                                     1,
6363                                     NULL,
6364                                     FIB_ROUTE_PATH_FLAG_NONE);
6365
6366     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6367                                                      &pfx_1_1_1_1_s_32),
6368                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6369                                     &ip_1_1_1_1);
6370
6371     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6372         .type = FT_LB_O_LB,
6373         .lb = {
6374             .lb = ip_1_1_1_1.dpoi_index,
6375         },
6376     };
6377
6378     fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6379     FIB_TEST(fib_test_validate_entry(fei, 
6380                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6381                                      1,
6382                                      &ip_o_1_1_1_1),
6383              "2.2.2.2.3/32 LB 1 buckets via: "
6384              "ip 1.1.1.1");
6385
6386     /*
6387      * Add a recursive with an imp-null out-label. 
6388      * We expect to use the IP of the via
6389      */
6390     fib_prefix_t pfx_2_2_2_4_s_32 = {
6391         .fp_len = 32,
6392         .fp_proto = FIB_PROTOCOL_IP4,
6393         .fp_addr = {
6394             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6395         },
6396     };
6397
6398     fib_table_entry_update_one_path(fib_index,
6399                                     &pfx_2_2_2_4_s_32,
6400                                     FIB_SOURCE_API,
6401                                     FIB_ENTRY_FLAG_NONE,
6402                                     FIB_PROTOCOL_IP4,
6403                                     &pfx_1_1_1_1_s_32.fp_addr,
6404                                     ~0,
6405                                     fib_index,
6406                                     1,
6407                                     NULL,
6408                                     FIB_ROUTE_PATH_FLAG_NONE);
6409
6410     fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6411     FIB_TEST(fib_test_validate_entry(fei, 
6412                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6413                                      1,
6414                                      &ip_o_1_1_1_1),
6415              "2.2.2.2.4/32 LB 1 buckets via: "
6416              "ip 1.1.1.1");
6417
6418     dpo_reset(&ip_1_1_1_1);
6419
6420     /*
6421      * Create an entry with a deep label stack
6422      */
6423     fib_prefix_t pfx_2_2_5_5_s_32 = {
6424         .fp_len = 32,
6425         .fp_proto = FIB_PROTOCOL_IP4,
6426         .fp_addr = {
6427             .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6428         },
6429     };
6430     fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6431         .type = FT_LB_LABEL_STACK_O_ADJ,
6432         .label_stack_o_adj = {
6433             .adj = ai_mpls_10_10_11_1,
6434             .label_stack_size = 8,
6435             .label_stack = {
6436                 200, 201, 202, 203, 204, 205, 206, 207
6437             },
6438             .eos = MPLS_EOS,
6439         },
6440     };
6441     mpls_label_t *label_stack = NULL;
6442     vec_validate(label_stack, 7);
6443     for (ii = 0; ii < 8; ii++)
6444     {
6445         label_stack[ii] = ii + 200;
6446     }
6447
6448     fei = fib_table_entry_update_one_path(fib_index,
6449                                           &pfx_2_2_5_5_s_32,
6450                                           FIB_SOURCE_API,
6451                                           FIB_ENTRY_FLAG_NONE,
6452                                           FIB_PROTOCOL_IP4,
6453                                           &nh_10_10_11_1,
6454                                           tm->hw[1]->sw_if_index,
6455                                           ~0, // invalid fib index
6456                                           1,
6457                                           label_stack,
6458                                           FIB_ROUTE_PATH_FLAG_NONE);
6459
6460     FIB_TEST(fib_test_validate_entry(fei,
6461                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6462                                      1,
6463                                      &ls_eos_o_10_10_10_1),
6464              "2.2.5.5/32 LB 1 buckets via: "
6465              "adj 10.10.11.1");
6466     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6467
6468     /*
6469      * cleanup
6470      */
6471     fib_table_entry_delete(fib_index,
6472                            &pfx_1_1_1_2_s_32,
6473                            FIB_SOURCE_API);
6474
6475     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6476     FIB_TEST(fib_test_validate_entry(fei, 
6477                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6478                                      1,
6479                                      &l1600_eos_o_1_1_1_1),
6480              "2.2.2.2/32 LB 1 buckets via: "
6481              "label 1600 via 1.1,1.1");
6482
6483     fib_table_entry_delete(fib_index,
6484                            &pfx_1_1_1_1_s_32,
6485                            FIB_SOURCE_API);
6486
6487     FIB_TEST(fib_test_validate_entry(fei, 
6488                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6489                                      1,
6490                                      &bucket_drop),
6491              "2.2.2.2/32 LB 1 buckets via: DROP");
6492
6493     fib_table_entry_delete(fib_index,
6494                            &pfx_2_2_2_2_s_32,
6495                            FIB_SOURCE_API);
6496     fib_table_entry_delete(fib_index,
6497                            &pfx_2_2_2_3_s_32,
6498                            FIB_SOURCE_API);
6499     fib_table_entry_delete(fib_index,
6500                            &pfx_2_2_2_4_s_32,
6501                            FIB_SOURCE_API);
6502
6503     adj_unlock(ai_mpls_10_10_10_1);
6504     adj_unlock(ai_mpls_10_10_11_2);
6505     adj_unlock(ai_v4_10_10_11_1);
6506     adj_unlock(ai_v4_10_10_11_2);
6507     adj_unlock(ai_mpls_10_10_11_1);
6508
6509     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6510              adj_nbr_db_size());
6511
6512     local0_pfx.fp_len = 32;
6513     fib_table_entry_delete(fib_index,
6514                            &local0_pfx,
6515                            FIB_SOURCE_INTERFACE);
6516     local0_pfx.fp_len = 24;
6517     fib_table_entry_delete(fib_index,
6518                            &local0_pfx,
6519                            FIB_SOURCE_INTERFACE);
6520     local1_pfx.fp_len = 32;
6521     fib_table_entry_delete(fib_index,
6522                            &local1_pfx,
6523                            FIB_SOURCE_INTERFACE);
6524     local1_pfx.fp_len = 24;
6525     fib_table_entry_delete(fib_index,
6526                            &local1_pfx,
6527                            FIB_SOURCE_INTERFACE);
6528
6529     /*
6530      * +1 for the drop LB in the MPLS tables.
6531      */
6532     FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6533              "Load-balance resources freed %d of %d",
6534              lb_count+1, pool_elts(load_balance_pool));
6535
6536     return (0);
6537 }
6538
6539 #define N_TEST_CHILDREN 4
6540 #define PARENT_INDEX 0
6541
6542 typedef struct fib_node_test_t_
6543 {
6544     fib_node_t node;
6545     u32 sibling;
6546     u32 index;
6547     fib_node_back_walk_ctx_t *ctxs;
6548     u32 destroyed;
6549 } fib_node_test_t;
6550
6551 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6552
6553 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6554
6555 #define FOR_EACH_TEST_CHILD(_tc)                     \
6556     for (ii = 1, (_tc) = &fib_test_nodes[1];         \
6557          ii < N_TEST_CHILDREN+1;                     \
6558          ii++, (_tc) = &fib_test_nodes[ii])
6559
6560 static fib_node_t *
6561 fib_test_child_get_node (fib_node_index_t index)
6562 {
6563     return (&fib_test_nodes[index].node);
6564 }
6565
6566 static int fib_test_walk_spawns_walks;
6567
6568 static fib_node_back_walk_rc_t
6569 fib_test_child_back_walk_notify (fib_node_t *node,
6570                                  fib_node_back_walk_ctx_t *ctx)
6571 {
6572     fib_node_test_t *tc = (fib_node_test_t*) node;
6573
6574     vec_add1(tc->ctxs, *ctx);
6575
6576     if (1 == fib_test_walk_spawns_walks)
6577         fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6578     if (2 == fib_test_walk_spawns_walks)
6579         fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6580                        FIB_WALK_PRIORITY_HIGH, ctx);
6581
6582     return (FIB_NODE_BACK_WALK_CONTINUE);
6583 }
6584
6585 static void
6586 fib_test_child_last_lock_gone (fib_node_t *node)
6587 {
6588     fib_node_test_t *tc = (fib_node_test_t *)node;
6589
6590     tc->destroyed = 1;
6591 }
6592
6593 /**
6594  * The FIB walk's graph node virtual function table
6595  */
6596 static const fib_node_vft_t fib_test_child_vft = {
6597     .fnv_get = fib_test_child_get_node,
6598     .fnv_last_lock = fib_test_child_last_lock_gone,
6599     .fnv_back_walk = fib_test_child_back_walk_notify,
6600 };
6601
6602 /*
6603  * the function (that should have been static but isn't so I can do this)
6604  * that processes the walk from the async queue,
6605  */
6606 f64 fib_walk_process_queues(vlib_main_t * vm,
6607                             const f64 quota);
6608 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6609
6610 static int
6611 fib_test_walk (void)
6612 {
6613     fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6614     fib_node_test_t *tc;
6615     vlib_main_t *vm;
6616     u32 ii;
6617
6618     vm = vlib_get_main();
6619     fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6620
6621     /*
6622      * init a fake node on which we will add children
6623      */
6624     fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6625                   FIB_NODE_TYPE_TEST);
6626
6627     FOR_EACH_TEST_CHILD(tc)
6628     {
6629         fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6630         fib_node_lock(&tc->node);
6631         tc->ctxs = NULL;
6632         tc->index = ii;
6633         tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6634                                          PARENT_INDEX,
6635                                          FIB_NODE_TYPE_TEST, ii);
6636     }
6637
6638     /*
6639      * enqueue a walk across the parents children.
6640      */
6641     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6642
6643     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6644                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6645     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6646              "Parent has %d children pre-walk",
6647              fib_node_list_get_size(PARENT()->fn_children));
6648
6649     /*
6650      * give the walk a large amount of time so it gets to the end
6651      */
6652     fib_walk_process_queues(vm, 1);
6653
6654     FOR_EACH_TEST_CHILD(tc)
6655     {
6656         FIB_TEST(1 == vec_len(tc->ctxs),
6657                  "%d child visitsed %d times",
6658                  ii, vec_len(tc->ctxs));
6659         vec_free(tc->ctxs);
6660     }
6661     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6662              "Queue is empty post walk");
6663     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6664              "Parent has %d children post walk",
6665              fib_node_list_get_size(PARENT()->fn_children));
6666
6667     /*
6668      * walk again. should be no increase in the number of visits, since
6669      * the walk will have terminated.
6670      */
6671     fib_walk_process_queues(vm, 1);
6672
6673     FOR_EACH_TEST_CHILD(tc)
6674     {
6675         FIB_TEST(0 == vec_len(tc->ctxs),
6676                  "%d child visitsed %d times",
6677                  ii, vec_len(tc->ctxs));
6678     }
6679
6680     /*
6681      * schedule a low and hig priority walk. expect the high to be performed
6682      * before the low.
6683      * schedule the high prio walk first so that it is further from the head
6684      * of the dependency list. that way it won't merge with the low one.
6685      */
6686     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6687     low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6688
6689     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6690                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6691     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6692                    FIB_WALK_PRIORITY_LOW, &low_ctx);
6693
6694     fib_walk_process_queues(vm, 1);
6695
6696     FOR_EACH_TEST_CHILD(tc)
6697     {
6698         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6699                  "%d child visitsed by high prio walk", ii);
6700         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
6701                  "%d child visitsed by low prio walk", ii);
6702         vec_free(tc->ctxs);
6703     }
6704     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6705              "Queue is empty post prio walk");
6706     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6707              "Parent has %d children post prio walk",
6708              fib_node_list_get_size(PARENT()->fn_children));
6709
6710     /*
6711      * schedule 2 walks of the same priority that can be megred.
6712      * expect that each child is thus visited only once.
6713      */
6714     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6715     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6716
6717     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6718                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6719     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6720                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
6721
6722     fib_walk_process_queues(vm, 1);
6723
6724     FOR_EACH_TEST_CHILD(tc)
6725     {
6726         FIB_TEST(1 == vec_len(tc->ctxs),
6727                  "%d child visitsed %d times during merge walk",
6728                  ii, vec_len(tc->ctxs));
6729         vec_free(tc->ctxs);
6730     }
6731     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6732              "Queue is empty post merge walk");
6733     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6734              "Parent has %d children post merge walk",
6735              fib_node_list_get_size(PARENT()->fn_children));
6736
6737     /*
6738      * schedule 2 walks of the same priority that cannot be megred.
6739      * expect that each child is thus visited twice and in the order
6740      * in which the walks were scheduled.
6741      */
6742     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6743     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6744
6745     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6746                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6747     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6748                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
6749
6750     fib_walk_process_queues(vm, 1);
6751
6752     FOR_EACH_TEST_CHILD(tc)
6753     {
6754         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6755                  "%d child visitsed by high prio walk", ii);
6756         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
6757                  "%d child visitsed by low prio walk", ii);
6758         vec_free(tc->ctxs);
6759     }
6760     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6761              "Queue is empty post no-merge walk");
6762     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6763              "Parent has %d children post no-merge walk",
6764              fib_node_list_get_size(PARENT()->fn_children));
6765
6766     /*
6767      * schedule a walk that makes one one child progress.
6768      * we do this by giving the queue draining process zero
6769      * time quanta. it's a do..while loop, so it does something.
6770      */
6771     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6772
6773     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6774                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6775     fib_walk_process_queues(vm, 0);
6776
6777     FOR_EACH_TEST_CHILD(tc)
6778     {
6779         if (ii == N_TEST_CHILDREN)
6780         {
6781             FIB_TEST(1 == vec_len(tc->ctxs),
6782                      "%d child visitsed %d times in zero quanta walk",
6783                      ii, vec_len(tc->ctxs));
6784         }
6785         else
6786         {
6787             FIB_TEST(0 == vec_len(tc->ctxs),
6788                      "%d child visitsed %d times in 0 quanta walk",
6789                      ii, vec_len(tc->ctxs));
6790         }
6791     }
6792     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6793              "Queue is not empty post zero quanta walk");
6794     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6795              "Parent has %d children post zero qunta walk",
6796              fib_node_list_get_size(PARENT()->fn_children));
6797
6798     /*
6799      * another one step
6800      */
6801     fib_walk_process_queues(vm, 0);
6802
6803     FOR_EACH_TEST_CHILD(tc)
6804     {
6805         if (ii >= N_TEST_CHILDREN-1)
6806         {
6807             FIB_TEST(1 == vec_len(tc->ctxs),
6808                      "%d child visitsed %d times in 2nd zero quanta walk",
6809                      ii, vec_len(tc->ctxs));
6810         }
6811         else
6812         {
6813             FIB_TEST(0 == vec_len(tc->ctxs),
6814                      "%d child visitsed %d times in 2nd 0 quanta walk",
6815                      ii, vec_len(tc->ctxs));
6816         }
6817     }
6818     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6819              "Queue is not empty post zero quanta walk");
6820     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6821              "Parent has %d children post zero qunta walk",
6822              fib_node_list_get_size(PARENT()->fn_children));
6823
6824     /*
6825      * schedule another walk that will catch-up and merge.
6826      */
6827     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6828                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6829     fib_walk_process_queues(vm, 1);
6830
6831     FOR_EACH_TEST_CHILD(tc)
6832     {
6833         if (ii >= N_TEST_CHILDREN-1)
6834         {
6835             FIB_TEST(2 == vec_len(tc->ctxs),
6836                      "%d child visitsed %d times in 2nd zero quanta merge walk",
6837                      ii, vec_len(tc->ctxs));
6838             vec_free(tc->ctxs);
6839         }
6840         else
6841         {
6842             FIB_TEST(1 == vec_len(tc->ctxs),
6843                      "%d child visitsed %d times in 2nd 0 quanta merge walk",
6844                      ii, vec_len(tc->ctxs));
6845             vec_free(tc->ctxs);
6846         }
6847     }
6848     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6849              "Queue is not empty post 2nd zero quanta merge walk");
6850     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6851              "Parent has %d children post 2nd zero qunta merge walk",
6852              fib_node_list_get_size(PARENT()->fn_children));
6853
6854     /*
6855      * park a async walk in the middle of the list, then have an sync walk catch
6856      * it. same expectations as async catches async.
6857      */
6858     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6859
6860     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6861                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6862
6863     fib_walk_process_queues(vm, 0);
6864     fib_walk_process_queues(vm, 0);
6865
6866     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6867
6868     FOR_EACH_TEST_CHILD(tc)
6869     {
6870         if (ii >= N_TEST_CHILDREN-1)
6871         {
6872             FIB_TEST(2 == vec_len(tc->ctxs),
6873                      "%d child visitsed %d times in sync catches async walk",
6874                      ii, vec_len(tc->ctxs));
6875             vec_free(tc->ctxs);
6876         }
6877         else
6878         {
6879             FIB_TEST(1 == vec_len(tc->ctxs),
6880                      "%d child visitsed %d times in sync catches async walk",
6881                      ii, vec_len(tc->ctxs));
6882             vec_free(tc->ctxs);
6883         }
6884     }
6885     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6886              "Queue is not empty post 2nd zero quanta merge walk");
6887     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6888              "Parent has %d children post 2nd zero qunta merge walk",
6889              fib_node_list_get_size(PARENT()->fn_children));
6890
6891     /*
6892      * make the parent a child of one of its children, thus inducing a routing loop.
6893      */
6894     fib_test_nodes[PARENT_INDEX].sibling =
6895         fib_node_child_add(FIB_NODE_TYPE_TEST,
6896                            1, // the first child
6897                            FIB_NODE_TYPE_TEST,
6898                            PARENT_INDEX);
6899
6900     /*
6901      * execute a sync walk from the parent. each child visited spawns more sync
6902      * walks. we expect the walk to terminate.
6903      */
6904     fib_test_walk_spawns_walks = 1;
6905
6906     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6907
6908     FOR_EACH_TEST_CHILD(tc)
6909     {
6910         /*
6911          * child 1 - which is last in the list - has the loop.
6912          * the other children a re thus visitsed first. the we meet
6913          * child 1. we go round the loop again, visting the other children.
6914          * then we meet the walk in the dep list and bail. child 1 is not visitsed
6915          * again.
6916          */
6917         if (1 == ii)
6918         {
6919             FIB_TEST(1 == vec_len(tc->ctxs),
6920                      "child %d visitsed %d times during looped sync walk",
6921                      ii, vec_len(tc->ctxs));
6922         }
6923         else
6924         {
6925             FIB_TEST(2 == vec_len(tc->ctxs),
6926                      "child %d visitsed %d times during looped sync walk",
6927                      ii, vec_len(tc->ctxs));
6928         }
6929         vec_free(tc->ctxs);
6930     }
6931     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6932              "Parent has %d children post sync loop walk",
6933              fib_node_list_get_size(PARENT()->fn_children));
6934
6935     /*
6936      * the walk doesn't reach the max depth because the infra knows that sync
6937      * meets sync implies a loop and bails early.
6938      */
6939     FIB_TEST(high_ctx.fnbw_depth == 9,
6940              "Walk context depth %d post sync loop walk",
6941              high_ctx.fnbw_depth);
6942
6943     /*
6944      * execute an async walk of the graph loop, with each child spawns sync walks
6945      */
6946     high_ctx.fnbw_depth = 0;
6947     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6948                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6949
6950     fib_walk_process_queues(vm, 1);
6951
6952     FOR_EACH_TEST_CHILD(tc)
6953     {
6954         /*
6955          * we don't really care how many times the children are visisted, as long as
6956          * it is more than once.
6957          */
6958         FIB_TEST(1 <= vec_len(tc->ctxs),
6959                  "child %d visitsed %d times during looped aync spawns sync walk",
6960                  ii, vec_len(tc->ctxs));
6961         vec_free(tc->ctxs);
6962     }
6963
6964     /*
6965      * execute an async walk of the graph loop, with each child spawns async walks
6966      */
6967     fib_test_walk_spawns_walks = 2;
6968     high_ctx.fnbw_depth = 0;
6969     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6970                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
6971
6972     fib_walk_process_queues(vm, 1);
6973
6974     FOR_EACH_TEST_CHILD(tc)
6975     {
6976         /*
6977          * we don't really care how many times the children are visisted, as long as
6978          * it is more than once.
6979          */
6980         FIB_TEST(1 <= vec_len(tc->ctxs),
6981                  "child %d visitsed %d times during looped async spawns async walk",
6982                  ii, vec_len(tc->ctxs));
6983                 vec_free(tc->ctxs);
6984     }
6985
6986
6987     fib_node_child_remove(FIB_NODE_TYPE_TEST,
6988                           1, // the first child
6989                           fib_test_nodes[PARENT_INDEX].sibling);
6990
6991     /*
6992      * cleanup
6993      */
6994     FOR_EACH_TEST_CHILD(tc)
6995     {
6996         fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6997                               tc->sibling);
6998         fib_node_deinit(&tc->node);
6999         fib_node_unlock(&tc->node);
7000     }
7001     fib_node_deinit(PARENT());
7002
7003     /*
7004      * The parent will be destroyed when the last lock on it goes.
7005      * this test ensures all the walk objects are unlocking it.
7006      */
7007     FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7008              "Parent was destroyed");
7009
7010     return (0);
7011 }
7012
7013 /*
7014  * declaration of the otherwise static callback functions
7015  */
7016 void fib_bfd_notify (bfd_listen_event_e event,
7017                      const bfd_session_t *session);
7018 void adj_bfd_notify (bfd_listen_event_e event,
7019                      const bfd_session_t *session);
7020
7021 /**
7022  * Test BFD session interaction with FIB
7023  */
7024 static int
7025 fib_test_bfd (void)
7026 {
7027     fib_node_index_t fei;
7028     test_main_t *tm;
7029     int n_feis;
7030
7031     /* via 10.10.10.1 */
7032     ip46_address_t nh_10_10_10_1 = {
7033         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7034     };
7035     /* via 10.10.10.2 */
7036     ip46_address_t nh_10_10_10_2 = {
7037         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7038     };
7039     /* via 10.10.10.10 */
7040     ip46_address_t nh_10_10_10_10 = {
7041         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7042     };
7043     n_feis = fib_entry_pool_size();
7044
7045     tm = &test_main;
7046
7047     /*
7048      * add interface routes. we'll assume this works. it's tested elsewhere
7049      */
7050     fib_prefix_t pfx_10_10_10_10_s_24 = {
7051         .fp_len = 24,
7052         .fp_proto = FIB_PROTOCOL_IP4,
7053         .fp_addr = nh_10_10_10_10,
7054     };
7055
7056     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7057                                     FIB_SOURCE_INTERFACE,
7058                                     (FIB_ENTRY_FLAG_CONNECTED |
7059                                      FIB_ENTRY_FLAG_ATTACHED),
7060                                     FIB_PROTOCOL_IP4,
7061                                     NULL,
7062                                     tm->hw[0]->sw_if_index,
7063                                     ~0, // invalid fib index
7064                                     1, // weight
7065                                     NULL,
7066                                     FIB_ROUTE_PATH_FLAG_NONE);
7067
7068     fib_prefix_t pfx_10_10_10_10_s_32 = {
7069         .fp_len = 32,
7070         .fp_proto = FIB_PROTOCOL_IP4,
7071         .fp_addr = nh_10_10_10_10,
7072     };
7073     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7074                                     FIB_SOURCE_INTERFACE,
7075                                     (FIB_ENTRY_FLAG_CONNECTED |
7076                                      FIB_ENTRY_FLAG_LOCAL),
7077                                     FIB_PROTOCOL_IP4,
7078                                     NULL,
7079                                     tm->hw[0]->sw_if_index,
7080                                     ~0, // invalid fib index
7081                                     1, // weight
7082                                     NULL,
7083                                     FIB_ROUTE_PATH_FLAG_NONE);
7084
7085     /*
7086      * A BFD session via a neighbour we do not yet know
7087      */
7088     bfd_session_t bfd_10_10_10_1 = {
7089         .udp = {
7090             .key = {
7091                 .fib_index = 0,
7092                 .peer_addr = nh_10_10_10_1,
7093             },
7094         },
7095         .hop_type = BFD_HOP_TYPE_MULTI,
7096         .local_state = BFD_STATE_init,
7097     };
7098
7099     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7100
7101     /*
7102      * A new entry will be created that forwards via the adj
7103      */
7104     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7105                                                     VNET_LINK_IP4,
7106                                                     &nh_10_10_10_1,
7107                                                     tm->hw[0]->sw_if_index);
7108     fib_prefix_t pfx_10_10_10_1_s_32 = {
7109         .fp_addr = nh_10_10_10_1,
7110         .fp_len = 32,
7111         .fp_proto = FIB_PROTOCOL_IP4,
7112     };
7113     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7114         .type = FT_LB_ADJ,
7115         .adj = {
7116             .adj = ai_10_10_10_1,
7117         },
7118     };
7119
7120     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7121     FIB_TEST(fib_test_validate_entry(fei,
7122                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7123                                      1,
7124                                      &adj_o_10_10_10_1),
7125              "BFD sourced %U via %U",
7126              format_fib_prefix, &pfx_10_10_10_1_s_32,
7127              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7128
7129     /*
7130      * Delete the BFD session. Expect the fib_entry to be removed
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_NODE_INDEX_INVALID == fei,
7136              "BFD sourced %U removed",
7137              format_fib_prefix, &pfx_10_10_10_1_s_32);
7138
7139     /*
7140      * Add the BFD source back
7141      */
7142     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7143
7144     /*
7145      * source the entry via the ADJ fib
7146      */
7147     fei = fib_table_entry_update_one_path(0,
7148                                           &pfx_10_10_10_1_s_32,
7149                                           FIB_SOURCE_ADJ,
7150                                           FIB_ENTRY_FLAG_ATTACHED,
7151                                           FIB_PROTOCOL_IP4,
7152                                           &nh_10_10_10_1,
7153                                           tm->hw[0]->sw_if_index,
7154                                           ~0, // invalid fib index
7155                                           1,
7156                                           NULL,
7157                                           FIB_ROUTE_PATH_FLAG_NONE);
7158
7159     /*
7160      * Delete the BFD session. Expect the fib_entry to remain
7161      */
7162     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7163
7164     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7165     FIB_TEST(fib_test_validate_entry(fei,
7166                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7167                                      1,
7168                                      &adj_o_10_10_10_1),
7169              "BFD sourced %U remains via %U",
7170              format_fib_prefix, &pfx_10_10_10_1_s_32,
7171              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7172
7173     /*
7174      * Add the BFD source back
7175      */
7176     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7177
7178     /*
7179      * Create another ADJ FIB
7180      */
7181     fib_prefix_t pfx_10_10_10_2_s_32 = {
7182         .fp_addr = nh_10_10_10_2,
7183         .fp_len = 32,
7184         .fp_proto = FIB_PROTOCOL_IP4,
7185     };
7186     fib_table_entry_update_one_path(0,
7187                                     &pfx_10_10_10_2_s_32,
7188                                     FIB_SOURCE_ADJ,
7189                                     FIB_ENTRY_FLAG_ATTACHED,
7190                                     FIB_PROTOCOL_IP4,
7191                                     &nh_10_10_10_2,
7192                                     tm->hw[0]->sw_if_index,
7193                                     ~0, // invalid fib index
7194                                     1,
7195                                     NULL,
7196                                     FIB_ROUTE_PATH_FLAG_NONE);
7197     /*
7198      * A BFD session for the new ADJ FIB
7199      */
7200     bfd_session_t bfd_10_10_10_2 = {
7201         .udp = {
7202             .key = {
7203                 .fib_index = 0,
7204                 .peer_addr = nh_10_10_10_2,
7205             },
7206         },
7207         .hop_type = BFD_HOP_TYPE_MULTI,
7208         .local_state = BFD_STATE_init,
7209     };
7210
7211     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7212
7213     /*
7214      * remove the adj-fib source whilst the session is present
7215      * then add it back
7216      */
7217     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7218     fib_table_entry_update_one_path(0,
7219                                     &pfx_10_10_10_2_s_32,
7220                                     FIB_SOURCE_ADJ,
7221                                     FIB_ENTRY_FLAG_ATTACHED,
7222                                     FIB_PROTOCOL_IP4,
7223                                     &nh_10_10_10_2,
7224                                     tm->hw[0]->sw_if_index,
7225                                     ~0, // invalid fib index
7226                                     1,
7227                                     NULL,
7228                                     FIB_ROUTE_PATH_FLAG_NONE);
7229
7230     /*
7231      * Before adding a recursive via the BFD tracked ADJ-FIBs,
7232      * bring one of the sessions UP, leave the other down
7233      */
7234     bfd_10_10_10_1.local_state = BFD_STATE_up;
7235     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7236     bfd_10_10_10_2.local_state = BFD_STATE_down;
7237     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7238
7239     /*
7240      * A recursive prefix via both of the ADJ FIBs
7241      */
7242     fib_prefix_t pfx_200_0_0_0_s_24 = {
7243         .fp_proto = FIB_PROTOCOL_IP4,
7244         .fp_len = 32,
7245         .fp_addr = {
7246             .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7247         },
7248     };
7249     const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7250
7251     dpo_10_10_10_1 =
7252         fib_entry_contribute_ip_forwarding(
7253             fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7254     dpo_10_10_10_2 =
7255         fib_entry_contribute_ip_forwarding(
7256             fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7257
7258     fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7259         .type = FT_LB_O_LB,
7260         .lb = {
7261             .lb = dpo_10_10_10_1->dpoi_index,
7262         },
7263     };
7264     fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7265         .type = FT_LB_O_LB,
7266         .lb = {
7267             .lb = dpo_10_10_10_2->dpoi_index,
7268         },
7269     };
7270
7271     /*
7272      * A prefix via the adj-fib that is BFD down => DROP
7273      */
7274     fei = fib_table_entry_path_add(0,
7275                                    &pfx_200_0_0_0_s_24,
7276                                    FIB_SOURCE_API,
7277                                    FIB_ENTRY_FLAG_NONE,
7278                                    FIB_PROTOCOL_IP4,
7279                                    &nh_10_10_10_2,
7280                                    ~0, // recursive
7281                                    0, // default fib index
7282                                    1,
7283                                    NULL,
7284                                    FIB_ROUTE_PATH_FLAG_NONE);
7285     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7286              "%U resolves via drop",
7287              format_fib_prefix, &pfx_200_0_0_0_s_24);
7288
7289     /*
7290      * add a path via the UP BFD adj-fib.
7291      *  we expect that the DOWN BFD ADJ FIB is not used.
7292      */
7293     fei = fib_table_entry_path_add(0,
7294                                    &pfx_200_0_0_0_s_24,
7295                                    FIB_SOURCE_API,
7296                                    FIB_ENTRY_FLAG_NONE,
7297                                    FIB_PROTOCOL_IP4,
7298                                    &nh_10_10_10_1,
7299                                    ~0, // recursive
7300                                    0, // default fib index
7301                                    1,
7302                                    NULL,
7303                                    FIB_ROUTE_PATH_FLAG_NONE);
7304
7305     FIB_TEST(fib_test_validate_entry(fei,
7306                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7307                                      1,
7308                                      &lb_o_10_10_10_1),
7309              "Recursive %U only UP BFD adj-fibs",
7310              format_fib_prefix, &pfx_200_0_0_0_s_24);
7311
7312     /*
7313      * Send a BFD state change to UP - both sessions are now up
7314      *  the recursive prefix should LB over both
7315      */
7316     bfd_10_10_10_2.local_state = BFD_STATE_up;
7317     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7318
7319
7320     FIB_TEST(fib_test_validate_entry(fei,
7321                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7322                                      2,
7323                                      &lb_o_10_10_10_1,
7324                                      &lb_o_10_10_10_2),
7325              "Recursive %U via both UP BFD adj-fibs",
7326              format_fib_prefix, &pfx_200_0_0_0_s_24);
7327
7328     /*
7329      * Send a BFD state change to DOWN
7330      *  the recursive prefix should exclude the down
7331      */
7332     bfd_10_10_10_2.local_state = BFD_STATE_down;
7333     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7334
7335
7336     FIB_TEST(fib_test_validate_entry(fei,
7337                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7338                                      1,
7339                                      &lb_o_10_10_10_1),
7340              "Recursive %U via only UP",
7341              format_fib_prefix, &pfx_200_0_0_0_s_24);
7342
7343     /*
7344      * Delete the BFD session while it is in the DOWN state.
7345      *  FIB should consider the entry's state as back up
7346      */
7347     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
7348
7349     FIB_TEST(fib_test_validate_entry(fei,
7350                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7351                                      2,
7352                                      &lb_o_10_10_10_1,
7353                                      &lb_o_10_10_10_2),
7354              "Recursive %U via both UP BFD adj-fibs post down session delete",
7355              format_fib_prefix, &pfx_200_0_0_0_s_24);
7356
7357     /*
7358      * Delete the BFD other session while it is in the UP state.
7359      */
7360     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7361
7362     FIB_TEST(fib_test_validate_entry(fei,
7363                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7364                                      2,
7365                                      &lb_o_10_10_10_1,
7366                                      &lb_o_10_10_10_2),
7367              "Recursive %U via both UP BFD adj-fibs post up session delete",
7368              format_fib_prefix, &pfx_200_0_0_0_s_24);
7369
7370     /*
7371      * cleaup
7372      */
7373     fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
7374     fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
7375     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7376
7377     fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
7378     fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
7379
7380     adj_unlock(ai_10_10_10_1);
7381      /*
7382      * test no-one left behind
7383      */
7384     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7385     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7386
7387     /*
7388      * Single-hop BFD tests
7389      */
7390     bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
7391     bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
7392
7393     adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7394
7395     ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7396                                         VNET_LINK_IP4,
7397                                         &nh_10_10_10_1,
7398                                         tm->hw[0]->sw_if_index);
7399     /*
7400      * whilst the BFD session is not signalled, the adj is up
7401      */
7402     FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
7403
7404     /*
7405      * bring the BFD session up
7406      */
7407     bfd_10_10_10_1.local_state = BFD_STATE_up;
7408     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7409     FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
7410
7411     /*
7412      * bring the BFD session down
7413      */
7414     bfd_10_10_10_1.local_state = BFD_STATE_down;
7415     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7416     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
7417
7418
7419     /*
7420      * add an attached next hop FIB entry via the down adj
7421      */
7422     fib_prefix_t pfx_5_5_5_5_s_32 = {
7423         .fp_addr = {
7424             .ip4 = {
7425                 .as_u32 = clib_host_to_net_u32(0x05050505),
7426             },
7427         },
7428         .fp_len = 32,
7429         .fp_proto = FIB_PROTOCOL_IP4,
7430     };
7431
7432     fei = fib_table_entry_path_add(0,
7433                                    &pfx_5_5_5_5_s_32,
7434                                    FIB_SOURCE_CLI,
7435                                    FIB_ENTRY_FLAG_NONE,
7436                                    FIB_PROTOCOL_IP4,
7437                                    &nh_10_10_10_1,
7438                                    tm->hw[0]->sw_if_index,
7439                                    ~0, // invalid fib index
7440                                    1,
7441                                    NULL,
7442                                    FIB_ROUTE_PATH_FLAG_NONE);
7443     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7444              "%U resolves via drop",
7445              format_fib_prefix, &pfx_5_5_5_5_s_32);
7446
7447     /*
7448      * Add a path via an ADJ that is up
7449      */
7450     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7451                                                     VNET_LINK_IP4,
7452                                                     &nh_10_10_10_2,
7453                                                     tm->hw[0]->sw_if_index);
7454
7455     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
7456         .type = FT_LB_ADJ,
7457         .adj = {
7458             .adj = ai_10_10_10_2,
7459         },
7460     };
7461     adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
7462
7463     fei = fib_table_entry_path_add(0,
7464                                    &pfx_5_5_5_5_s_32,
7465                                    FIB_SOURCE_CLI,
7466                                    FIB_ENTRY_FLAG_NONE,
7467                                    FIB_PROTOCOL_IP4,
7468                                    &nh_10_10_10_2,
7469                                    tm->hw[0]->sw_if_index,
7470                                    ~0, // invalid fib index
7471                                    1,
7472                                    NULL,
7473                                    FIB_ROUTE_PATH_FLAG_NONE);
7474
7475     FIB_TEST(fib_test_validate_entry(fei,
7476                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7477                                      1,
7478                                      &adj_o_10_10_10_2),
7479              "BFD sourced %U via %U",
7480              format_fib_prefix, &pfx_5_5_5_5_s_32,
7481              format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
7482
7483     /*
7484      * Bring up the down session - should now LB
7485      */
7486     bfd_10_10_10_1.local_state = BFD_STATE_up;
7487     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7488     FIB_TEST(fib_test_validate_entry(fei,
7489                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7490                                      2,
7491                                      &adj_o_10_10_10_1,
7492                                      &adj_o_10_10_10_2),
7493              "BFD sourced %U via noth adjs",
7494              format_fib_prefix, &pfx_5_5_5_5_s_32);
7495
7496     /*
7497      * remove the BFD session state from the adj
7498      */
7499     adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7500
7501     /*
7502      * clean-up
7503      */
7504     fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
7505     adj_unlock(ai_10_10_10_1);
7506     adj_unlock(ai_10_10_10_2);
7507
7508     /*
7509      * test no-one left behind
7510      */
7511     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7512     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7513     return (0);
7514 }
7515
7516 static int
7517 lfib_test (void)
7518 {
7519     const mpls_label_t deag_label = 50;
7520     const u32 lfib_index = 0;
7521     const u32 fib_index = 0;
7522     dpo_id_t dpo = DPO_INVALID;
7523     const dpo_id_t *dpo1;
7524     fib_node_index_t lfe;
7525     lookup_dpo_t *lkd;
7526     test_main_t *tm;
7527     int lb_count;
7528     adj_index_t ai_mpls_10_10_10_1;
7529
7530     tm = &test_main;
7531     lb_count = pool_elts(load_balance_pool);
7532
7533     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7534              adj_nbr_db_size());
7535
7536     /*
7537      * MPLS enable an interface so we get the MPLS table created
7538      */
7539     mpls_sw_interface_enable_disable(&mpls_main,
7540                                      tm->hw[0]->sw_if_index,
7541                                      1);
7542
7543     ip46_address_t nh_10_10_10_1 = {
7544         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7545     };
7546     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7547                                              VNET_LINK_MPLS,
7548                                              &nh_10_10_10_1,
7549                                              tm->hw[0]->sw_if_index);
7550
7551     /*
7552      * Test the specials stack properly.
7553      */
7554     fib_prefix_t exp_null_v6_pfx = {
7555         .fp_proto = FIB_PROTOCOL_MPLS,
7556         .fp_eos = MPLS_EOS,
7557         .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7558         .fp_payload_proto = DPO_PROTO_IP6,
7559     };
7560     lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
7561     FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
7562              "%U/%U present",
7563              format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7564              format_mpls_eos_bit, MPLS_EOS);
7565     fib_entry_contribute_forwarding(lfe,
7566                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7567                                     &dpo);
7568     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7569     lkd = lookup_dpo_get(dpo1->dpoi_index);
7570
7571     FIB_TEST((fib_index == lkd->lkd_fib_index),
7572               "%U/%U is deag in %d %U",
7573              format_mpls_unicast_label, deag_label,
7574              format_mpls_eos_bit, MPLS_EOS,
7575              lkd->lkd_fib_index,
7576              format_dpo_id, &dpo, 0);
7577     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7578              "%U/%U is dst deag",
7579              format_mpls_unicast_label, deag_label,
7580              format_mpls_eos_bit, MPLS_EOS);
7581     FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
7582              "%U/%U is lookup in interface's table",
7583              format_mpls_unicast_label, deag_label,
7584              format_mpls_eos_bit, MPLS_EOS);
7585     FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
7586              "%U/%U is %U dst deag",
7587              format_mpls_unicast_label, deag_label,
7588              format_mpls_eos_bit, MPLS_EOS,
7589              format_dpo_proto, lkd->lkd_proto);
7590
7591
7592     /*
7593      * A route deag route for EOS
7594      */
7595     fib_prefix_t pfx = {
7596         .fp_proto = FIB_PROTOCOL_MPLS,
7597         .fp_eos = MPLS_EOS,
7598         .fp_label = deag_label,
7599         .fp_payload_proto = DPO_PROTO_IP4,
7600     };
7601     lfe = fib_table_entry_path_add(lfib_index,
7602                                    &pfx,
7603                                    FIB_SOURCE_CLI,
7604                                    FIB_ENTRY_FLAG_NONE,
7605                                    FIB_PROTOCOL_IP4,
7606                                    &zero_addr,
7607                                    ~0,
7608                                    fib_index,
7609                                    1,
7610                                    NULL,
7611                                    FIB_ROUTE_PATH_FLAG_NONE);
7612
7613     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7614               "%U/%U present",
7615               format_mpls_unicast_label, deag_label,
7616               format_mpls_eos_bit, MPLS_EOS);
7617
7618     fib_entry_contribute_forwarding(lfe,
7619                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7620                                     &dpo);
7621     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7622     lkd = lookup_dpo_get(dpo1->dpoi_index);
7623
7624     FIB_TEST((fib_index == lkd->lkd_fib_index),
7625               "%U/%U is deag in %d %U",
7626              format_mpls_unicast_label, deag_label,
7627              format_mpls_eos_bit, MPLS_EOS,
7628              lkd->lkd_fib_index,
7629              format_dpo_id, &dpo, 0);
7630     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7631              "%U/%U is dst deag",
7632              format_mpls_unicast_label, deag_label,
7633              format_mpls_eos_bit, MPLS_EOS);
7634     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
7635              "%U/%U is %U dst deag",
7636              format_mpls_unicast_label, deag_label,
7637              format_mpls_eos_bit, MPLS_EOS,
7638              format_dpo_proto, lkd->lkd_proto);
7639
7640     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7641
7642     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7643                                                          &pfx)),
7644               "%U/%U not present",
7645               format_mpls_unicast_label, deag_label,
7646               format_mpls_eos_bit, MPLS_EOS);
7647
7648     /*
7649      * A route deag route for non-EOS
7650      */
7651     pfx.fp_eos = MPLS_NON_EOS;
7652     lfe = fib_table_entry_path_add(lfib_index,
7653                                    &pfx,
7654                                    FIB_SOURCE_CLI,
7655                                    FIB_ENTRY_FLAG_NONE,
7656                                    FIB_PROTOCOL_IP4,
7657                                    &zero_addr,
7658                                    ~0,
7659                                    lfib_index,
7660                                    1,
7661                                    NULL,
7662                                    FIB_ROUTE_PATH_FLAG_NONE);
7663
7664     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7665               "%U/%U present",
7666               format_mpls_unicast_label, deag_label,
7667               format_mpls_eos_bit, MPLS_NON_EOS);
7668
7669     fib_entry_contribute_forwarding(lfe,
7670                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7671                                     &dpo);
7672     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7673     lkd = lookup_dpo_get(dpo1->dpoi_index);
7674
7675     FIB_TEST((fib_index == lkd->lkd_fib_index),
7676               "%U/%U is deag in %d %U",
7677              format_mpls_unicast_label, deag_label,
7678              format_mpls_eos_bit, MPLS_NON_EOS,
7679              lkd->lkd_fib_index,
7680              format_dpo_id, &dpo, 0);
7681     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7682              "%U/%U is dst deag",
7683              format_mpls_unicast_label, deag_label,
7684              format_mpls_eos_bit, MPLS_NON_EOS);
7685
7686     FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
7687              "%U/%U is %U dst deag",
7688              format_mpls_unicast_label, deag_label,
7689              format_mpls_eos_bit, MPLS_NON_EOS,
7690              format_dpo_proto, lkd->lkd_proto);
7691
7692     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7693
7694     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7695                                                          &pfx)),
7696               "%U/%U not present",
7697               format_mpls_unicast_label, deag_label,
7698               format_mpls_eos_bit, MPLS_EOS);
7699
7700     dpo_reset(&dpo);
7701
7702     /*
7703      * An MPLS x-connect
7704      */
7705     fib_prefix_t pfx_1200 = {
7706         .fp_len = 21,
7707         .fp_proto = FIB_PROTOCOL_MPLS,
7708         .fp_label = 1200,
7709         .fp_eos = MPLS_NON_EOS,
7710     };
7711     fib_test_lb_bucket_t neos_o_10_10_10_1 = {
7712         .type = FT_LB_LABEL_STACK_O_ADJ,
7713         .label_stack_o_adj = {
7714             .adj = ai_mpls_10_10_10_1,
7715             .label_stack_size = 4,
7716             .label_stack = {
7717                 200, 300, 400, 500,
7718             },
7719             .eos = MPLS_NON_EOS,
7720         },
7721     };
7722     dpo_id_t neos_1200 = DPO_INVALID;
7723     dpo_id_t ip_1200 = DPO_INVALID;
7724     mpls_label_t *l200 = NULL;
7725     vec_add1(l200, 200);
7726     vec_add1(l200, 300);
7727     vec_add1(l200, 400);
7728     vec_add1(l200, 500);
7729
7730     lfe = fib_table_entry_update_one_path(fib_index,
7731                                           &pfx_1200,
7732                                           FIB_SOURCE_API,
7733                                           FIB_ENTRY_FLAG_NONE,
7734                                           FIB_PROTOCOL_IP4,
7735                                           &nh_10_10_10_1,
7736                                           tm->hw[0]->sw_if_index,
7737                                           ~0, // invalid fib index
7738                                           1,
7739                                           l200,
7740                                           FIB_ROUTE_PATH_FLAG_NONE);
7741
7742     FIB_TEST(fib_test_validate_entry(lfe,
7743                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7744                                      1,
7745                                      &neos_o_10_10_10_1),
7746              "1200/0 LB 1 buckets via: "
7747              "adj 10.10.11.1");
7748
7749     /*
7750      * A recursive route via the MPLS x-connect
7751      */
7752     fib_prefix_t pfx_2_2_2_3_s_32 = {
7753         .fp_len = 32,
7754         .fp_proto = FIB_PROTOCOL_IP4,
7755         .fp_addr = {
7756             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7757         },
7758     };
7759     fib_route_path_t *rpaths = NULL, rpath = {
7760         .frp_proto = FIB_PROTOCOL_MPLS,
7761         .frp_local_label = 1200,
7762         .frp_eos = MPLS_NON_EOS,
7763         .frp_sw_if_index = ~0, // recurive
7764         .frp_fib_index = 0, // Default MPLS fib
7765         .frp_weight = 1,
7766         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
7767         .frp_label_stack = NULL,
7768     };
7769     vec_add1(rpaths, rpath);
7770
7771     fib_table_entry_path_add2(fib_index,
7772                               &pfx_2_2_2_3_s_32,
7773                               FIB_SOURCE_API,
7774                               FIB_ENTRY_FLAG_NONE,
7775                               rpaths);
7776
7777     /*
7778      * A labelled recursive route via the MPLS x-connect
7779      */
7780     fib_prefix_t pfx_2_2_2_4_s_32 = {
7781         .fp_len = 32,
7782         .fp_proto = FIB_PROTOCOL_IP4,
7783         .fp_addr = {
7784             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7785         },
7786     };
7787     mpls_label_t *l999 = NULL;
7788     vec_add1(l999, 999);
7789     rpaths[0].frp_label_stack = l999,
7790
7791     fib_table_entry_path_add2(fib_index,
7792                               &pfx_2_2_2_4_s_32,
7793                               FIB_SOURCE_API,
7794                               FIB_ENTRY_FLAG_NONE,
7795                               rpaths);
7796
7797     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7798                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7799                                     &ip_1200);
7800     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7801                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7802                                     &neos_1200);
7803
7804     fib_test_lb_bucket_t ip_o_1200 = {
7805         .type = FT_LB_O_LB,
7806         .lb = {
7807             .lb = ip_1200.dpoi_index,
7808         },
7809     };
7810     fib_test_lb_bucket_t mpls_o_1200 = {
7811         .type = FT_LB_LABEL_O_LB,
7812         .label_o_lb = {
7813             .lb = neos_1200.dpoi_index,
7814             .label = 999,
7815             .eos = MPLS_EOS,
7816         },
7817     };
7818
7819     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7820     FIB_TEST(fib_test_validate_entry(lfe,
7821                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7822                                      1,
7823                                      &ip_o_1200),
7824              "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
7825     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7826     FIB_TEST(fib_test_validate_entry(lfe,
7827                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7828                                      1,
7829                                      &mpls_o_1200),
7830              "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
7831
7832     fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
7833     fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
7834     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7835
7836     dpo_reset(&neos_1200);
7837     dpo_reset(&ip_1200);
7838
7839     /*
7840      * A recursive via a label that does not exist
7841      */
7842     fib_test_lb_bucket_t bucket_drop = {
7843         .type = FT_LB_SPECIAL,
7844         .special = {
7845             .adj = DPO_PROTO_IP4,
7846         },
7847     };
7848     fib_test_lb_bucket_t mpls_bucket_drop = {
7849         .type = FT_LB_SPECIAL,
7850         .special = {
7851             .adj = DPO_PROTO_MPLS,
7852         },
7853     };
7854
7855     rpaths[0].frp_label_stack = NULL;
7856     lfe = fib_table_entry_path_add2(fib_index,
7857                                     &pfx_2_2_2_4_s_32,
7858                                     FIB_SOURCE_API,
7859                                     FIB_ENTRY_FLAG_NONE,
7860                                     rpaths);
7861
7862     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7863                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7864                                     &ip_1200);
7865     ip_o_1200.lb.lb = ip_1200.dpoi_index;
7866
7867     FIB_TEST(fib_test_validate_entry(lfe,
7868                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7869                                      1,
7870                                      &ip_o_1200),
7871              "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
7872     lfe = fib_table_lookup(fib_index, &pfx_1200);
7873     FIB_TEST(fib_test_validate_entry(lfe,
7874                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7875                                      1,
7876                                      &bucket_drop),
7877              "1200/neos LB 1 buckets via: ip4-DROP");
7878     FIB_TEST(fib_test_validate_entry(lfe,
7879                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7880                                      1,
7881                                      &mpls_bucket_drop),
7882              "1200/neos LB 1 buckets via: mpls-DROP");
7883
7884     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7885
7886     dpo_reset(&ip_1200);
7887
7888     /*
7889      * An rx-interface route.
7890      *  like the tail of an mcast LSP
7891      */
7892     dpo_id_t idpo = DPO_INVALID;
7893
7894     interface_dpo_add_or_lock(DPO_PROTO_IP4,
7895                               tm->hw[0]->sw_if_index,
7896                               &idpo);
7897
7898     fib_prefix_t pfx_2500 = {
7899         .fp_len = 21,
7900         .fp_proto = FIB_PROTOCOL_MPLS,
7901         .fp_label = 2500,
7902         .fp_eos = MPLS_EOS,
7903         .fp_payload_proto = DPO_PROTO_IP4,
7904     };
7905     fib_test_lb_bucket_t rx_intf_0 = {
7906         .type = FT_LB_INTF,
7907         .adj = {
7908             .adj = idpo.dpoi_index,
7909         },
7910     };
7911
7912     lfe = fib_table_entry_update_one_path(fib_index,
7913                                           &pfx_2500,
7914                                           FIB_SOURCE_API,
7915                                           FIB_ENTRY_FLAG_NONE,
7916                                           FIB_PROTOCOL_IP4,
7917                                           NULL,
7918                                           tm->hw[0]->sw_if_index,
7919                                           ~0, // invalid fib index
7920                                           0,
7921                                           NULL,
7922                                           FIB_ROUTE_PATH_INTF_RX);
7923     FIB_TEST(fib_test_validate_entry(lfe,
7924                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7925                                      1,
7926                                      &rx_intf_0),
7927              "2500 rx-interface 0");
7928     fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
7929
7930     /*
7931      * An MPLS mulicast entry
7932      */
7933     fib_prefix_t pfx_3500 = {
7934         .fp_len = 21,
7935         .fp_proto = FIB_PROTOCOL_MPLS,
7936         .fp_label = 3500,
7937         .fp_eos = MPLS_EOS,
7938         .fp_payload_proto = DPO_PROTO_IP4,
7939     };
7940     fib_test_rep_bucket_t mc_0 = {
7941         .type = FT_REP_LABEL_O_ADJ,
7942         .label_o_adj = {
7943             .adj = ai_mpls_10_10_10_1,
7944             .label = 3300,
7945             .eos = MPLS_EOS,
7946         },
7947     };
7948     fib_test_rep_bucket_t mc_intf_0 = {
7949         .type = FT_REP_INTF,
7950         .adj = {
7951             .adj = idpo.dpoi_index,
7952         },
7953     };
7954     mpls_label_t *l3300 = NULL;
7955     vec_add1(l3300, 3300);
7956
7957     lfe = fib_table_entry_update_one_path(lfib_index,
7958                                           &pfx_3500,
7959                                           FIB_SOURCE_API,
7960                                           FIB_ENTRY_FLAG_MULTICAST,
7961                                           FIB_PROTOCOL_IP4,
7962                                           &nh_10_10_10_1,
7963                                           tm->hw[0]->sw_if_index,
7964                                           ~0, // invalid fib index
7965                                           1,
7966                                           l3300,
7967                                           FIB_ROUTE_PATH_FLAG_NONE);
7968     FIB_TEST(fib_test_validate_entry(lfe,
7969                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7970                                      1,
7971                                      &mc_0),
7972              "3500 via replicate over 10.10.10.1");
7973
7974     /*
7975      * MPLS Bud-node. Add a replication via an interface-receieve path
7976      */
7977     lfe = fib_table_entry_path_add(lfib_index,
7978                                    &pfx_3500,
7979                                    FIB_SOURCE_API,
7980                                    FIB_ENTRY_FLAG_MULTICAST,
7981                                    FIB_PROTOCOL_IP4,
7982                                    NULL,
7983                                    tm->hw[0]->sw_if_index,
7984                                    ~0, // invalid fib index
7985                                    0,
7986                                    NULL,
7987                                    FIB_ROUTE_PATH_INTF_RX);
7988     FIB_TEST(fib_test_validate_entry(lfe,
7989                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7990                                      2,
7991                                      &mc_0,
7992                                      &mc_intf_0),
7993              "3500 via replicate over 10.10.10.1 and interface-rx");
7994
7995     /*
7996      * Add a replication via an interface-free for-us path
7997      */
7998     fib_test_rep_bucket_t mc_disp = {
7999         .type = FT_REP_DISP_MFIB_LOOKUP,
8000         .adj = {
8001             .adj = idpo.dpoi_index,
8002         },
8003     };
8004     lfe = fib_table_entry_path_add(lfib_index,
8005                                    &pfx_3500,
8006                                    FIB_SOURCE_API,
8007                                    FIB_ENTRY_FLAG_MULTICAST,
8008                                    FIB_PROTOCOL_IP4,
8009                                    NULL,
8010                                    5, // rpf-id
8011                                    0, // default table
8012                                    0,
8013                                    NULL,
8014                                    FIB_ROUTE_PATH_RPF_ID);
8015     FIB_TEST(fib_test_validate_entry(lfe,
8016                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8017                                      3,
8018                                      &mc_0,
8019                                      &mc_disp,
8020                                      &mc_intf_0),
8021              "3500 via replicate over 10.10.10.1 and interface-rx");
8022
8023
8024     
8025     fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8026     dpo_reset(&idpo);
8027
8028     /*
8029      * cleanup
8030      */
8031     mpls_sw_interface_enable_disable(&mpls_main,
8032                                      tm->hw[0]->sw_if_index,
8033                                      0);
8034
8035     FIB_TEST(lb_count == pool_elts(load_balance_pool),
8036              "Load-balance resources freed %d of %d",
8037              lb_count, pool_elts(load_balance_pool));
8038     FIB_TEST(0 == pool_elts(interface_dpo_pool),
8039              "interface_dpo resources freed %d of %d",
8040              0, pool_elts(interface_dpo_pool));
8041
8042     return (0);
8043 }
8044
8045 static clib_error_t *
8046 fib_test (vlib_main_t * vm, 
8047           unformat_input_t * input,
8048           vlib_cli_command_t * cmd_arg)
8049 {
8050     int res;
8051
8052     res = 0;
8053     fib_test_mk_intf(4);
8054
8055     if (unformat (input, "debug"))
8056     {
8057         fib_test_do_debug = 1;
8058     }
8059
8060     if (unformat (input, "ip"))
8061     {
8062         res += fib_test_v4();
8063         res += fib_test_v6();
8064     }
8065     else if (unformat (input, "label"))
8066     {
8067         res += fib_test_label();
8068     }
8069     else if (unformat (input, "ae"))
8070     {
8071         res += fib_test_ae();
8072     }
8073     else if (unformat (input, "lfib"))
8074     {
8075         res += lfib_test();
8076     }
8077     else if (unformat (input, "walk"))
8078     {
8079         res += fib_test_walk();
8080     }
8081     else if (unformat (input, "bfd"))
8082     {
8083         res += fib_test_bfd();
8084     }
8085     else
8086     {
8087         res += fib_test_v4();
8088         res += fib_test_v6();
8089         res += fib_test_ae();
8090         res += fib_test_bfd();
8091         res += fib_test_label();
8092         res += lfib_test();
8093
8094         /*
8095          * fib-walk process must be disabled in order for the walk tests to work
8096          */
8097         fib_walk_process_disable();
8098         res += fib_test_walk();
8099         fib_walk_process_enable();
8100     }
8101
8102     if (res)
8103     {
8104         return clib_error_return(0, "FIB Unit Test Failed");
8105     }
8106     else
8107     {
8108         return (NULL);
8109     }
8110 }
8111
8112 VLIB_CLI_COMMAND (test_fib_command, static) = {
8113     .path = "test fib",
8114     .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8115     .function = fib_test,
8116 };
8117
8118 clib_error_t *
8119 fib_test_init (vlib_main_t *vm)
8120 {
8121     return 0;
8122 }
8123
8124 VLIB_INIT_FUNCTION (fib_test_init);