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