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