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