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