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