66a38236216de558ba8a2453edd18e7c9bf5a750
[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                          int 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     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
3547              "4.4.4.4/32 is source deag in %d %U",
3548              lkd->lkd_input,
3549              format_dpo_id, dpo, 0);
3550
3551     fib_table_entry_delete(fib_index,
3552                            &pfx_4_4_4_4_s_32,
3553                            FIB_SOURCE_API);
3554     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3555              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3556              "4.4.4.4/32 removed");
3557     vec_free(r_paths);
3558
3559     /*
3560      * A route deag route in a source lookup table
3561      */
3562     fib_table_entry_path_add(fib_index,
3563                              &pfx_4_4_4_4_s_32,
3564                              FIB_SOURCE_API,
3565                              FIB_ENTRY_FLAG_NONE,
3566                              DPO_PROTO_IP4,
3567                              &zero_addr,
3568                              ~0,
3569                              fib_index,
3570                              1,
3571                              NULL,
3572                              FIB_ROUTE_PATH_SOURCE_LOOKUP);
3573
3574     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3575     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3576
3577     dpo = fib_entry_contribute_ip_forwarding(fei);
3578     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3579     lkd = lookup_dpo_get(dpo->dpoi_index);
3580
3581     FIB_TEST((fib_index == lkd->lkd_fib_index),
3582              "4.4.4.4/32 is deag in %d %U",
3583              lkd->lkd_fib_index,
3584              format_dpo_id, dpo, 0);
3585     FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
3586              "4.4.4.4/32 is source deag in %d %U",
3587              lkd->lkd_input,
3588              format_dpo_id, dpo, 0);
3589
3590     fib_table_entry_delete(fib_index,
3591                            &pfx_4_4_4_4_s_32,
3592                            FIB_SOURCE_API);
3593     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3594              fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3595              "4.4.4.4/32 removed");
3596     vec_free(r_paths);
3597
3598     /*
3599      * add-remove test. no change.
3600      */
3601     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3602              fib_path_list_db_size());
3603     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3604              fib_path_list_pool_size());
3605     FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3606              fib_entry_pool_size());
3607
3608     /*
3609      * Duplicate paths:
3610      *  add a recursive with duplicate paths. Expect the duplicate to be ignored.
3611      */
3612     fib_prefix_t pfx_34_1_1_1_s_32 = {
3613         .fp_len = 32,
3614         .fp_proto = FIB_PROTOCOL_IP4,
3615         .fp_addr = {
3616             .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3617         },
3618     };
3619     fib_prefix_t pfx_34_34_1_1_s_32 = {
3620         .fp_len = 32,
3621         .fp_proto = FIB_PROTOCOL_IP4,
3622         .fp_addr = {
3623             .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3624         },
3625     };
3626     fei = fib_table_entry_path_add(fib_index,
3627                                    &pfx_34_34_1_1_s_32,
3628                                    FIB_SOURCE_API,
3629                                    FIB_ENTRY_FLAG_NONE,
3630                                    DPO_PROTO_IP4,
3631                                    &nh_10_10_10_1,
3632                                    tm->hw[0]->sw_if_index,
3633                                    0,
3634                                    1,
3635                                    NULL,
3636                                    FIB_ROUTE_PATH_FLAG_NONE);
3637     fei = fib_table_entry_path_add(fib_index,
3638                                    &pfx_34_1_1_1_s_32,
3639                                    FIB_SOURCE_API,
3640                                    FIB_ENTRY_FLAG_NONE,
3641                                    DPO_PROTO_IP4,
3642                                    &pfx_34_34_1_1_s_32.fp_addr,
3643                                    ~0,
3644                                    fib_index,
3645                                    1,
3646                                    NULL,
3647                                    FIB_ROUTE_PATH_FLAG_NONE);
3648     fei = fib_table_entry_path_add(fib_index,
3649                                    &pfx_34_1_1_1_s_32,
3650                                    FIB_SOURCE_API,
3651                                    FIB_ENTRY_FLAG_NONE,
3652                                    DPO_PROTO_IP4,
3653                                    &pfx_34_34_1_1_s_32.fp_addr,
3654                                    ~0,
3655                                    fib_index,
3656                                    1,
3657                                    NULL,
3658                                    FIB_ROUTE_PATH_FLAG_NONE);
3659     FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3660     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3661     fib_table_entry_delete(fib_index,
3662                            &pfx_34_34_1_1_s_32,
3663                            FIB_SOURCE_API);
3664
3665     /*
3666      * CLEANUP
3667      *   remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3668      *           all of which are via 10.10.10.1, Itf1
3669      */
3670     fib_table_entry_path_remove(fib_index,
3671                                 &pfx_1_1_1_2_s_32,
3672                                 FIB_SOURCE_API,
3673                                 DPO_PROTO_IP4,
3674                                 &nh_10_10_10_1,
3675                                 tm->hw[0]->sw_if_index,
3676                                 ~0,
3677                                 1,
3678                                 FIB_ROUTE_PATH_FLAG_NONE);
3679     fib_table_entry_path_remove(fib_index,
3680                                 &pfx_1_1_1_1_s_32,
3681                                 FIB_SOURCE_API,
3682                                 DPO_PROTO_IP4,
3683                                 &nh_10_10_10_1,
3684                                 tm->hw[0]->sw_if_index,
3685                                 ~0,
3686                                 1,
3687                                 FIB_ROUTE_PATH_FLAG_NONE);
3688     fib_table_entry_path_remove(fib_index,
3689                                 &pfx_1_1_2_0_s_24,
3690                                 FIB_SOURCE_API,
3691                                 DPO_PROTO_IP4,
3692                                 &nh_10_10_10_1,
3693                                 tm->hw[0]->sw_if_index,
3694                                 ~0,
3695                                 1,
3696                                 FIB_ROUTE_PATH_FLAG_NONE);
3697
3698     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3699              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3700              "1.1.1.1/32 removed");
3701     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3702              fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3703              "1.1.1.2/32 removed");
3704     FIB_TEST(FIB_NODE_INDEX_INVALID ==
3705              fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3706              "1.1.2.0/24 removed");
3707
3708     /*
3709      * -3 entries and -1 shared path-list
3710      */
3711     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3712              fib_path_list_db_size());
3713     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3714              fib_path_list_pool_size());
3715     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3716              fib_entry_pool_size());
3717
3718     /*
3719      * An attached-host route. Expect to link to the incomplete adj
3720      */
3721     fib_prefix_t pfx_4_1_1_1_s_32 = {
3722         .fp_len = 32,
3723         .fp_proto = FIB_PROTOCOL_IP4,
3724         .fp_addr = {
3725             /* 4.1.1.1/32 */
3726             .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3727         },
3728     };
3729     fib_table_entry_path_add(fib_index,
3730                              &pfx_4_1_1_1_s_32,
3731                              FIB_SOURCE_API,
3732                              FIB_ENTRY_FLAG_NONE,
3733                              DPO_PROTO_IP4,
3734                              &zero_addr,
3735                              tm->hw[0]->sw_if_index,
3736                              fib_index,
3737                              1,
3738                              NULL,
3739                              FIB_ROUTE_PATH_FLAG_NONE);
3740
3741     fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3742     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3743     ai = fib_entry_get_adj(fei);
3744
3745     ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3746                               VNET_LINK_IP4,
3747                               &pfx_4_1_1_1_s_32.fp_addr,
3748                               tm->hw[0]->sw_if_index);
3749     FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3750     adj_unlock(ai2);
3751
3752     /*
3753      * +1 entry and +1 shared path-list
3754      */
3755     FIB_TEST((1  == fib_path_list_db_size()),   "path list DB population:%d",
3756              fib_path_list_db_size());
3757     FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3758              fib_path_list_pool_size());
3759     FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3760              fib_entry_pool_size());
3761
3762     fib_table_entry_delete(fib_index,
3763                            &pfx_4_1_1_1_s_32,
3764                            FIB_SOURCE_API);
3765
3766     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
3767              fib_path_list_db_size());
3768     FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3769              fib_path_list_pool_size());
3770     FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3771              fib_entry_pool_size());
3772
3773     /*
3774      * add a v6 prefix via v4 next-hops
3775      */
3776     fib_prefix_t pfx_2001_s_64 = {
3777         .fp_len = 64,
3778         .fp_proto = FIB_PROTOCOL_IP6,
3779         .fp_addr = {
3780             .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3781         },
3782     };
3783     fei = fib_table_entry_path_add(0, //default v6 table
3784                                    &pfx_2001_s_64,
3785                                    FIB_SOURCE_API,
3786                                    FIB_ENTRY_FLAG_NONE,
3787                                    DPO_PROTO_IP4,
3788                                    &nh_10_10_10_1,
3789                                    tm->hw[0]->sw_if_index,
3790                                    fib_index,
3791                                    1,
3792                                    NULL,
3793                                    FIB_ROUTE_PATH_FLAG_NONE);
3794
3795     fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3796     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3797     ai = fib_entry_get_adj(fei);
3798     adj = adj_get(ai);
3799     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3800              "2001::/64 via ARP-adj");
3801     FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3802              "2001::/64 is link type v6");
3803     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3804              "2001::/64 ADJ-adj is NH proto v4");
3805     fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3806
3807     /*
3808      * add a uRPF exempt prefix:
3809      *  test:
3810      *   - it's forwarding is drop
3811      *   - it's uRPF list is not empty
3812      *   - the uRPF list for the default route (it's cover) is empty
3813      */
3814     fei = fib_table_entry_special_add(fib_index,
3815                                       &pfx_4_1_1_1_s_32,
3816                                       FIB_SOURCE_URPF_EXEMPT,
3817                                       FIB_ENTRY_FLAG_DROP);
3818     dpo = fib_entry_contribute_ip_forwarding(fei);
3819     FIB_TEST(load_balance_is_drop(dpo),
3820              "uRPF exempt 4.1.1.1/32 DROP");
3821     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3822              "uRPF list for exempt prefix has itf index 0");
3823     fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3824     FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3825              "uRPF list for 0.0.0.0/0 empty");
3826
3827     fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3828
3829     /*
3830      * An adj-fib that fails the refinement criteria - no connected cover
3831      */
3832     fib_prefix_t pfx_12_10_10_2_s_32 = {
3833         .fp_len = 32,
3834         .fp_proto = FIB_PROTOCOL_IP4,
3835         .fp_addr = {
3836             /* 12.10.10.2 */
3837             .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3838         },
3839     };
3840
3841     fib_table_entry_path_add(fib_index,
3842                              &pfx_12_10_10_2_s_32,
3843                              FIB_SOURCE_ADJ,
3844                              FIB_ENTRY_FLAG_ATTACHED,
3845                              DPO_PROTO_IP4,
3846                              &pfx_12_10_10_2_s_32.fp_addr,
3847                              tm->hw[0]->sw_if_index,
3848                              ~0, // invalid fib index
3849                              1,
3850                              NULL,
3851                              FIB_ROUTE_PATH_FLAG_NONE);
3852
3853     fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3854     dpo = fib_entry_contribute_ip_forwarding(fei);
3855     FIB_TEST(!dpo_id_is_valid(dpo),
3856              "no connected cover adj-fib fails refinement");
3857
3858     fib_table_entry_delete(fib_index,
3859                            &pfx_12_10_10_2_s_32,
3860                            FIB_SOURCE_ADJ);
3861
3862     /*
3863      * An adj-fib that fails the refinement criteria - cover is connected
3864      * but on a different interface
3865      */
3866     fib_prefix_t pfx_10_10_10_127_s_32 = {
3867         .fp_len = 32,
3868         .fp_proto = FIB_PROTOCOL_IP4,
3869         .fp_addr = {
3870             /* 10.10.10.127 */
3871             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3872         },
3873     };
3874
3875     fib_table_entry_path_add(fib_index,
3876                              &pfx_10_10_10_127_s_32,
3877                              FIB_SOURCE_ADJ,
3878                              FIB_ENTRY_FLAG_ATTACHED,
3879                              DPO_PROTO_IP4,
3880                              &pfx_10_10_10_127_s_32.fp_addr,
3881                              tm->hw[1]->sw_if_index,
3882                              ~0, // invalid fib index
3883                              1,
3884                              NULL,
3885                              FIB_ROUTE_PATH_FLAG_NONE);
3886
3887     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3888     dpo = fib_entry_contribute_ip_forwarding(fei);
3889     FIB_TEST(!dpo_id_is_valid(dpo),
3890              "wrong interface adj-fib fails refinement");
3891
3892     fib_table_entry_delete(fib_index,
3893                            &pfx_10_10_10_127_s_32,
3894                            FIB_SOURCE_ADJ);
3895
3896     /*
3897      * add a second path to an adj-fib
3898      * this is a sumiluation of another ARP entry created
3899      * on an interface on which the connected prefi does not exist.
3900      * The second path fails refinement. Expect to forward through the
3901      * first.
3902      */
3903     fib_prefix_t pfx_10_10_10_3_s_32 = {
3904         .fp_len = 32,
3905         .fp_proto = FIB_PROTOCOL_IP4,
3906         .fp_addr = {
3907             /* 10.10.10.3 */
3908             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
3909         },
3910     };
3911
3912     ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3913                                 VNET_LINK_IP4,
3914                                 &nh_10_10_10_3,
3915                                 tm->hw[0]->sw_if_index);
3916
3917     fib_test_lb_bucket_t ip_o_10_10_10_3 = {
3918         .type = FT_LB_ADJ,
3919         .adj = {
3920             .adj = ai_03,
3921         },
3922     };
3923     fei = fib_table_entry_path_add(fib_index,
3924                                    &pfx_10_10_10_3_s_32,
3925                                    FIB_SOURCE_ADJ,
3926                                    FIB_ENTRY_FLAG_NONE,
3927                                    DPO_PROTO_IP4,
3928                                    &nh_10_10_10_3,
3929                                    tm->hw[0]->sw_if_index,
3930                                    fib_index,
3931                                    1,
3932                                    NULL,
3933                                    FIB_ROUTE_PATH_FLAG_NONE);
3934     fei = fib_table_entry_path_add(fib_index,
3935                                    &pfx_10_10_10_3_s_32,
3936                                    FIB_SOURCE_ADJ,
3937                                    FIB_ENTRY_FLAG_NONE,
3938                                    DPO_PROTO_IP4,
3939                                    &nh_12_12_12_12,
3940                                    tm->hw[1]->sw_if_index,
3941                                    fib_index,
3942                                    1,
3943                                    NULL,
3944                                    FIB_ROUTE_PATH_FLAG_NONE);
3945     FIB_TEST(fib_test_validate_entry(fei,
3946                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3947                                      1,
3948                                      &ip_o_10_10_10_3),
3949              "10.10.10.3 via 10.10.10.3/Eth0 only");
3950
3951     /*
3952      * remove the path that refines the cover, should go unresolved
3953      */
3954     fib_table_entry_path_remove(fib_index,
3955                                 &pfx_10_10_10_3_s_32,
3956                                 FIB_SOURCE_ADJ,
3957                                 DPO_PROTO_IP4,
3958                                 &nh_10_10_10_3,
3959                                 tm->hw[0]->sw_if_index,
3960                                 fib_index,
3961                                 1,
3962                                 FIB_ROUTE_PATH_FLAG_NONE);
3963     dpo = fib_entry_contribute_ip_forwarding(fei);
3964     FIB_TEST(!dpo_id_is_valid(dpo),
3965              "wrong interface adj-fib fails refinement");
3966
3967     /*
3968      * add back the path that refines the cover
3969      */
3970     fei = fib_table_entry_path_add(fib_index,
3971                                    &pfx_10_10_10_3_s_32,
3972                                    FIB_SOURCE_ADJ,
3973                                    FIB_ENTRY_FLAG_NONE,
3974                                    DPO_PROTO_IP4,
3975                                    &nh_10_10_10_3,
3976                                    tm->hw[0]->sw_if_index,
3977                                    fib_index,
3978                                    1,
3979                                    NULL,
3980                                    FIB_ROUTE_PATH_FLAG_NONE);
3981     FIB_TEST(fib_test_validate_entry(fei,
3982                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3983                                      1,
3984                                      &ip_o_10_10_10_3),
3985              "10.10.10.3 via 10.10.10.3/Eth0 only");
3986
3987     /*
3988      * remove the path that does not refine the cover
3989      */
3990     fib_table_entry_path_remove(fib_index,
3991                                 &pfx_10_10_10_3_s_32,
3992                                 FIB_SOURCE_ADJ,
3993                                 DPO_PROTO_IP4,
3994                                 &nh_12_12_12_12,
3995                                 tm->hw[1]->sw_if_index,
3996                                 fib_index,
3997                                 1,
3998                                 FIB_ROUTE_PATH_FLAG_NONE);
3999     FIB_TEST(fib_test_validate_entry(fei,
4000                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4001                                      1,
4002                                      &ip_o_10_10_10_3),
4003              "10.10.10.3 via 10.10.10.3/Eth0 only");
4004
4005     /*
4006      * remove the path that does refine, it's the last path, so
4007      * the entry should be gone
4008      */
4009     fib_table_entry_path_remove(fib_index,
4010                                 &pfx_10_10_10_3_s_32,
4011                                 FIB_SOURCE_ADJ,
4012                                 DPO_PROTO_IP4,
4013                                 &nh_10_10_10_3,
4014                                 tm->hw[0]->sw_if_index,
4015                                 fib_index,
4016                                 1,
4017                                 FIB_ROUTE_PATH_FLAG_NONE);
4018     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4019     FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4020
4021     adj_unlock(ai_03);
4022
4023     /*
4024      * change the table's flow-hash config - expect the update to propagete to
4025      * the entries' load-balance objects
4026      */
4027     flow_hash_config_t old_hash_config, new_hash_config;
4028
4029     old_hash_config = fib_table_get_flow_hash_config(fib_index,
4030                                                      FIB_PROTOCOL_IP4);
4031     new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4032                        IP_FLOW_HASH_DST_ADDR);
4033
4034     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4035     dpo = fib_entry_contribute_ip_forwarding(fei);
4036     lb = load_balance_get(dpo->dpoi_index);
4037     FIB_TEST((lb->lb_hash_config == old_hash_config),
4038              "Table and LB hash config match: %U",
4039              format_ip_flow_hash_config, lb->lb_hash_config);
4040
4041     fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4042
4043     FIB_TEST((lb->lb_hash_config == new_hash_config),
4044              "Table and LB newhash config match: %U",
4045              format_ip_flow_hash_config, lb->lb_hash_config);
4046
4047     /*
4048      * A route via an L2 Bridge
4049      */
4050     fei = fib_table_entry_path_add(fib_index,
4051                                    &pfx_10_10_10_3_s_32,
4052                                    FIB_SOURCE_API,
4053                                    FIB_ENTRY_FLAG_NONE,
4054                                    DPO_PROTO_ETHERNET,
4055                                    &zero_addr,
4056                                    tm->hw[0]->sw_if_index,
4057                                    ~0,
4058                                    1,
4059                                    NULL,
4060                                    FIB_ROUTE_PATH_FLAG_NONE);
4061     dpo_id_t l2_dpo = DPO_INVALID;
4062     l2_bridge_dpo_add_or_lock(tm->hw[0]->sw_if_index, &l2_dpo);
4063     fib_test_lb_bucket_t ip_o_l2 = {
4064         .type = FT_LB_L2,
4065         .adj = {
4066             .adj = l2_dpo.dpoi_index,
4067         },
4068     };
4069
4070     FIB_TEST(fib_test_validate_entry(fei,
4071                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4072                                      1,
4073                                      &ip_o_l2),
4074              "10.10.10.3 via L2 on Eth0");
4075     fib_table_entry_path_remove(fib_index,
4076                                 &pfx_10_10_10_3_s_32,
4077                                 FIB_SOURCE_API,
4078                                 DPO_PROTO_ETHERNET,
4079                                 &zero_addr,
4080                                 tm->hw[0]->sw_if_index,
4081                                 fib_index,
4082                                 1,
4083                                 FIB_ROUTE_PATH_FLAG_NONE);
4084     dpo_reset(&l2_dpo);
4085
4086     /*
4087      * CLEANUP
4088      *    remove adj-fibs: 
4089      */
4090     fib_table_entry_delete(fib_index,
4091                            &pfx_10_10_10_1_s_32,
4092                            FIB_SOURCE_ADJ);
4093     fib_table_entry_delete(fib_index,
4094                            &pfx_10_10_10_2_s_32,
4095                            FIB_SOURCE_ADJ);
4096     FIB_TEST(FIB_NODE_INDEX_INVALID ==
4097              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4098              "10.10.10.1/32 adj-fib removed");
4099     FIB_TEST(FIB_NODE_INDEX_INVALID ==
4100              fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4101              "10.10.10.2/32 adj-fib removed");
4102
4103     /*
4104      * -2 entries and -2 non-shared path-list
4105      */
4106     FIB_TEST((0  == fib_path_list_db_size()),   "path list DB population:%d",
4107              fib_path_list_db_size());
4108     FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4109              fib_path_list_pool_size());
4110     FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4111              fib_entry_pool_size());
4112
4113     /*
4114      * unlock the adjacencies for which this test provided a rewrite.
4115      * These are the last locks on these adjs. they should thus go away.
4116      */
4117     adj_unlock(ai_02);
4118     adj_unlock(ai_01);
4119     adj_unlock(ai_12_12_12_12);
4120
4121     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4122              adj_nbr_db_size());
4123
4124     /*
4125      * CLEANUP
4126      *   remove the interface prefixes
4127      */
4128     local_pfx.fp_len = 32;
4129     fib_table_entry_special_remove(fib_index, &local_pfx,
4130                                    FIB_SOURCE_INTERFACE);
4131     fei = fib_table_lookup(fib_index, &local_pfx);
4132
4133     FIB_TEST(FIB_NODE_INDEX_INVALID ==
4134              fib_table_lookup_exact_match(fib_index, &local_pfx),
4135              "10.10.10.10/32 adj-fib removed");
4136
4137     local_pfx.fp_len = 24;
4138     fib_table_entry_delete(fib_index, &local_pfx,
4139                            FIB_SOURCE_INTERFACE);
4140
4141     FIB_TEST(FIB_NODE_INDEX_INVALID ==
4142              fib_table_lookup_exact_match(fib_index, &local_pfx),
4143              "10.10.10.10/24 adj-fib removed");
4144
4145     /*
4146      * -2 entries and -2 non-shared path-list
4147      */
4148     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4149              fib_path_list_db_size());
4150     FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4151              fib_path_list_pool_size());
4152     FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4153              fib_entry_pool_size());
4154
4155     /*
4156      * Last but not least, remove the VRF
4157      */
4158     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4159                                              FIB_PROTOCOL_IP4,
4160                                              FIB_SOURCE_API)),
4161              "NO API Source'd prefixes");
4162     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4163                                              FIB_PROTOCOL_IP4,
4164                                              FIB_SOURCE_RR)),
4165              "NO RR Source'd prefixes");
4166     FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4167                                              FIB_PROTOCOL_IP4,
4168                                              FIB_SOURCE_INTERFACE)),
4169              "NO INterface Source'd prefixes");
4170
4171     fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4172
4173     FIB_TEST((0  == fib_path_list_db_size()), "path list DB population:%d",
4174              fib_path_list_db_size());
4175     FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4176              fib_path_list_pool_size());
4177     FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4178              fib_entry_pool_size());
4179     FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4180              pool_elts(fib_urpf_list_pool));
4181     FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4182              pool_elts(load_balance_map_pool));
4183     FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4184              pool_elts(load_balance_pool));
4185     FIB_TEST((0 == pool_elts(l2_bridge_dpo_pool)), "L2 DPO pool size is %d",
4186              pool_elts(l2_bridge_dpo_pool));
4187
4188     return 0;
4189 }
4190
4191 static int
4192 fib_test_v6 (void)
4193 {
4194     /*
4195      * In the default table check for the presence and correct forwarding
4196      * of the special entries
4197      */
4198     fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4199     const dpo_id_t *dpo, *dpo_drop;
4200     const ip_adjacency_t *adj;
4201     const receive_dpo_t *rd;
4202     test_main_t *tm;
4203     u32 fib_index;
4204     int ii;
4205
4206     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4207              adj_nbr_db_size());
4208
4209     /* via 2001:0:0:1::2 */
4210     ip46_address_t nh_2001_2 = {
4211         .ip6 = {
4212             .as_u64 = {
4213                 [0] = clib_host_to_net_u64(0x2001000000000001),
4214                 [1] = clib_host_to_net_u64(0x0000000000000002),
4215             },
4216         },
4217     };
4218
4219     tm = &test_main;
4220
4221     dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4222
4223     /* Find or create FIB table 11 */
4224     fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4225                                                   FIB_SOURCE_API);
4226
4227     for (ii = 0; ii < 4; ii++)
4228     {
4229         ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4230     }
4231
4232     fib_prefix_t pfx_0_0 = {
4233         .fp_len = 0,
4234         .fp_proto = FIB_PROTOCOL_IP6,
4235         .fp_addr = {
4236             .ip6 = {
4237                 {0, 0},
4238             },
4239         },
4240     };
4241
4242     dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4243     FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4244     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4245              "Default route is DROP");
4246
4247     dpo = fib_entry_contribute_ip_forwarding(dfrt);
4248     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4249                                      &ip6_main,
4250                                      1,
4251                                      &pfx_0_0.fp_addr.ip6)),
4252              "default-route; fwd and non-fwd tables match");
4253
4254     // FIXME - check specials.
4255
4256     /*
4257      * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4258      * each with 2 entries and a v6 mfib with 4 path-lists.
4259      * All entries are special so no path-list sharing.
4260      */
4261 #define ENPS (5+4)
4262 #define PNPS (5+4+4)
4263     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
4264     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4265              fib_path_list_pool_size());
4266     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4267              fib_entry_pool_size());
4268
4269     /*
4270      * add interface routes.
4271      *  validate presence of /64 attached and /128 recieve.
4272      *  test for the presence of the receive address in the glean and local adj
4273      *
4274      * receive on 2001:0:0:1::1/128
4275      */
4276     fib_prefix_t local_pfx = {
4277         .fp_len = 64,
4278         .fp_proto = FIB_PROTOCOL_IP6,
4279         .fp_addr = {
4280             .ip6 = {
4281                 .as_u64 = {
4282                     [0] = clib_host_to_net_u64(0x2001000000000001),
4283                     [1] = clib_host_to_net_u64(0x0000000000000001),
4284                 },
4285             },
4286         }
4287     };
4288
4289     fib_table_entry_update_one_path(fib_index, &local_pfx,
4290                                     FIB_SOURCE_INTERFACE,
4291                                     (FIB_ENTRY_FLAG_CONNECTED |
4292                                      FIB_ENTRY_FLAG_ATTACHED),
4293                                     DPO_PROTO_IP6,
4294                                     NULL,
4295                                     tm->hw[0]->sw_if_index,
4296                                     ~0,
4297                                     1,
4298                                     NULL,
4299                                     FIB_ROUTE_PATH_FLAG_NONE);
4300     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4301
4302     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4303
4304     ai = fib_entry_get_adj(fei);
4305     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4306     adj = adj_get(ai);
4307     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4308              "attached interface adj is glean");
4309     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4310                                     &adj->sub_type.glean.receive_addr)),
4311               "attached interface adj is receive ok");
4312     dpo = fib_entry_contribute_ip_forwarding(fei);
4313     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4314                                      &ip6_main,
4315                                      1,
4316                                      &local_pfx.fp_addr.ip6)),
4317              "attached-route; fwd and non-fwd tables match");
4318
4319     local_pfx.fp_len = 128;
4320     fib_table_entry_update_one_path(fib_index, &local_pfx,
4321                                     FIB_SOURCE_INTERFACE,
4322                                     (FIB_ENTRY_FLAG_CONNECTED |
4323                                      FIB_ENTRY_FLAG_LOCAL),
4324                                     DPO_PROTO_IP6,
4325                                     NULL,
4326                                     tm->hw[0]->sw_if_index,
4327                                     ~0, // invalid fib index
4328                                     1,
4329                                     NULL,
4330                                     FIB_ROUTE_PATH_FLAG_NONE);
4331     fei = fib_table_lookup(fib_index, &local_pfx);
4332
4333     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4334
4335     dpo = fib_entry_contribute_ip_forwarding(fei);
4336     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4337     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4338              "local interface adj is local");
4339     rd = receive_dpo_get(dpo->dpoi_index);
4340
4341     FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4342                                     &rd->rd_addr)),
4343               "local interface adj is receive ok");
4344
4345     dpo = fib_entry_contribute_ip_forwarding(fei);
4346     FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4347                                      &ip6_main,
4348                                      1,
4349                                      &local_pfx.fp_addr.ip6)),
4350              "local-route; fwd and non-fwd tables match");
4351
4352     /*
4353      * +2 entries. +2 unshared path-lists
4354      */
4355     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB is empty");
4356     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4357              fib_path_list_pool_size());
4358     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4359              fib_entry_pool_size());
4360
4361     /*
4362      * Modify the default route to be via an adj not yet known.
4363      * this sources the defalut route with the API source, which is
4364      * a higher preference to the DEFAULT_ROUTE source
4365      */
4366     fib_table_entry_path_add(fib_index, &pfx_0_0,
4367                              FIB_SOURCE_API,
4368                              FIB_ENTRY_FLAG_NONE,
4369                              DPO_PROTO_IP6,
4370                              &nh_2001_2,
4371                              tm->hw[0]->sw_if_index,
4372                              ~0,
4373                              1,
4374                              NULL,
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     ai = fib_entry_get_adj(fei);
4380     FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4381     adj = adj_get(ai);
4382     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4383              "adj is incomplete");
4384     FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4385               "adj nbr next-hop ok");
4386
4387     /*
4388      * find the adj in the shared db
4389      */
4390     locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4391                                     VNET_LINK_IP6,
4392                                     &nh_2001_2,
4393                                     tm->hw[0]->sw_if_index);
4394     FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4395     adj_unlock(locked_ai);
4396
4397     /*
4398      * no more entires. +1 shared path-list
4399      */
4400     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4401              fib_path_list_db_size());
4402     FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4403              fib_path_list_pool_size());
4404     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4405              fib_entry_pool_size());
4406
4407     /*
4408      * remove the API source from the default route. We expected
4409      * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4410      */
4411     fib_table_entry_path_remove(fib_index, &pfx_0_0,
4412                                 FIB_SOURCE_API, 
4413                                 DPO_PROTO_IP6,
4414                                 &nh_2001_2,
4415                                 tm->hw[0]->sw_if_index,
4416                                 ~0,
4417                                 1,
4418                                 FIB_ROUTE_PATH_FLAG_NONE);
4419     fei = fib_table_lookup(fib_index, &pfx_0_0);
4420
4421     FIB_TEST((fei == dfrt), "default route same index");
4422     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4423              "Default route is DROP");
4424
4425     /*
4426      * no more entires. -1 shared path-list
4427      */
4428     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4429              fib_path_list_db_size());
4430     FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4431              fib_path_list_pool_size());
4432     FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4433              fib_entry_pool_size());
4434
4435     /*
4436      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4437      */
4438     fib_prefix_t pfx_2001_1_2_s_128 = {
4439         .fp_len   = 128,
4440         .fp_proto = FIB_PROTOCOL_IP6,
4441         .fp_addr  = {
4442             .ip6 = {
4443                 .as_u64 = {
4444                     [0] = clib_host_to_net_u64(0x2001000000000001),
4445                     [1] = clib_host_to_net_u64(0x0000000000000002),
4446                 },
4447             },
4448         }
4449     };
4450     fib_prefix_t pfx_2001_1_3_s_128 = {
4451         .fp_len   = 128,
4452         .fp_proto = FIB_PROTOCOL_IP6,
4453         .fp_addr  = {
4454             .ip6 = {
4455                 .as_u64 = {
4456                     [0] = clib_host_to_net_u64(0x2001000000000001),
4457                     [1] = clib_host_to_net_u64(0x0000000000000003),
4458                 },
4459             },
4460         }
4461     };
4462     u8 eth_addr[] = {
4463         0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4464     };
4465
4466     ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4467                                 VNET_LINK_IP6,
4468                                 &pfx_2001_1_2_s_128.fp_addr,
4469                                 tm->hw[0]->sw_if_index);
4470     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4471     adj = adj_get(ai_01);
4472     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4473              "adj is incomplete");
4474     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4475                                     &adj->sub_type.nbr.next_hop)),
4476               "adj nbr next-hop ok");
4477
4478     adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4479                            fib_test_build_rewrite(eth_addr));
4480     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4481              "adj is complete");
4482     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4483                                     &adj->sub_type.nbr.next_hop)),
4484               "adj nbr next-hop ok");
4485
4486     fib_table_entry_path_add(fib_index,
4487                              &pfx_2001_1_2_s_128,
4488                              FIB_SOURCE_ADJ,
4489                              FIB_ENTRY_FLAG_ATTACHED,
4490                              DPO_PROTO_IP6,
4491                              &pfx_2001_1_2_s_128.fp_addr,
4492                              tm->hw[0]->sw_if_index,
4493                              ~0,
4494                              1,
4495                              NULL,
4496                              FIB_ROUTE_PATH_FLAG_NONE);
4497
4498     fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4499     ai = fib_entry_get_adj(fei);
4500     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4501
4502     eth_addr[5] = 0xb2;
4503
4504     ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4505                                 VNET_LINK_IP6,
4506                                 &pfx_2001_1_3_s_128.fp_addr,
4507                                 tm->hw[0]->sw_if_index);
4508     FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4509     adj = adj_get(ai_02);
4510     FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4511              "adj is incomplete");
4512     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4513                                     &adj->sub_type.nbr.next_hop)),
4514               "adj nbr next-hop ok");
4515
4516     adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4517                            fib_test_build_rewrite(eth_addr));
4518     FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4519              "adj is complete");
4520     FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4521                                     &adj->sub_type.nbr.next_hop)),
4522               "adj nbr next-hop ok");
4523     FIB_TEST((ai_01 != ai_02), "ADJs are different");
4524
4525     fib_table_entry_path_add(fib_index,
4526                              &pfx_2001_1_3_s_128,
4527                              FIB_SOURCE_ADJ,
4528                              FIB_ENTRY_FLAG_ATTACHED,
4529                              DPO_PROTO_IP6,
4530                              &pfx_2001_1_3_s_128.fp_addr,
4531                              tm->hw[0]->sw_if_index,
4532                              ~0,
4533                              1,
4534                              NULL,
4535                              FIB_ROUTE_PATH_FLAG_NONE);
4536
4537     fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4538     ai = fib_entry_get_adj(fei);
4539     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4540
4541     /*
4542      * +2 entries, +2 unshread path-lists.
4543      */
4544     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
4545              fib_path_list_db_size());
4546     FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4547              fib_path_list_pool_size());
4548     FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4549              fib_entry_pool_size());
4550
4551     /*
4552      * Add a 2 routes via the first ADJ. ensure path-list sharing
4553      */
4554     fib_prefix_t pfx_2001_a_s_64 = {
4555         .fp_len   = 64,
4556         .fp_proto = FIB_PROTOCOL_IP6,
4557         .fp_addr  = {
4558             .ip6 = {
4559                 .as_u64 = {
4560                     [0] = clib_host_to_net_u64(0x200100000000000a),
4561                     [1] = clib_host_to_net_u64(0x0000000000000000),
4562                 },
4563             },
4564         }
4565     };
4566     fib_prefix_t pfx_2001_b_s_64 = {
4567         .fp_len   = 64,
4568         .fp_proto = FIB_PROTOCOL_IP6,
4569         .fp_addr  = {
4570             .ip6 = {
4571                 .as_u64 = {
4572                     [0] = clib_host_to_net_u64(0x200100000000000b),
4573                     [1] = clib_host_to_net_u64(0x0000000000000000),
4574                 },
4575             },
4576         }
4577     };
4578
4579     fib_table_entry_path_add(fib_index,
4580                              &pfx_2001_a_s_64,
4581                              FIB_SOURCE_API,
4582                              FIB_ENTRY_FLAG_NONE,
4583                              DPO_PROTO_IP6,
4584                              &nh_2001_2,
4585                              tm->hw[0]->sw_if_index,
4586                              ~0,
4587                              1,
4588                              NULL,
4589                              FIB_ROUTE_PATH_FLAG_NONE);
4590     fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4591     ai = fib_entry_get_adj(fei);
4592     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4593     fib_table_entry_path_add(fib_index,
4594                              &pfx_2001_b_s_64,
4595                              FIB_SOURCE_API,
4596                              FIB_ENTRY_FLAG_NONE,
4597                              DPO_PROTO_IP6,
4598                              &nh_2001_2,
4599                              tm->hw[0]->sw_if_index,
4600                              ~0,
4601                              1,
4602                              NULL,
4603                              FIB_ROUTE_PATH_FLAG_NONE);
4604     fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4605     ai = fib_entry_get_adj(fei);
4606     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4607
4608     /*
4609      * +2 entries, +1 shared path-list.
4610      */
4611     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4612              fib_path_list_db_size());
4613     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4614              fib_path_list_pool_size());
4615     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4616              fib_entry_pool_size());
4617
4618     /*
4619      * add a v4 prefix via a v6 next-hop
4620      */
4621     fib_prefix_t pfx_1_1_1_1_s_32 = {
4622         .fp_len = 32,
4623         .fp_proto = FIB_PROTOCOL_IP4,
4624         .fp_addr = {
4625             .ip4.as_u32 = 0x01010101,
4626         },
4627     };
4628     fei = fib_table_entry_path_add(0, // default table
4629                                    &pfx_1_1_1_1_s_32,
4630                                    FIB_SOURCE_API,
4631                                    FIB_ENTRY_FLAG_NONE,
4632                                    DPO_PROTO_IP6,
4633                                    &nh_2001_2,
4634                                    tm->hw[0]->sw_if_index,
4635                                    ~0,
4636                                    1,
4637                                    NULL,
4638                                    FIB_ROUTE_PATH_FLAG_NONE);
4639     FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4640              "1.1.1.1/32 o v6 route present");
4641     ai = fib_entry_get_adj(fei);
4642     adj = adj_get(ai);
4643     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4644              "1.1.1.1/32 via ARP-adj");
4645     FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4646              "1.1.1.1/32 ADJ-adj is link type v4");
4647     FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4648              "1.1.1.1/32 ADJ-adj is NH proto v6");
4649     fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4650
4651     /*
4652      * An attached route
4653      */
4654     fib_prefix_t pfx_2001_c_s_64 = {
4655         .fp_len   = 64,
4656         .fp_proto = FIB_PROTOCOL_IP6,
4657         .fp_addr  = {
4658             .ip6 = {
4659                 .as_u64 = {
4660                     [0] = clib_host_to_net_u64(0x200100000000000c),
4661                     [1] = clib_host_to_net_u64(0x0000000000000000),
4662                 },
4663             },
4664         }
4665     };
4666     fib_table_entry_path_add(fib_index,
4667                              &pfx_2001_c_s_64,
4668                              FIB_SOURCE_CLI,
4669                              FIB_ENTRY_FLAG_ATTACHED,
4670                              DPO_PROTO_IP6,
4671                              NULL,
4672                              tm->hw[0]->sw_if_index,
4673                              ~0,
4674                              1,
4675                              NULL,
4676                              FIB_ROUTE_PATH_FLAG_NONE);
4677     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4678     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4679     ai = fib_entry_get_adj(fei);
4680     adj = adj_get(ai);
4681     FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4682              "2001:0:0:c/64 attached resolves via glean");
4683
4684     fib_table_entry_path_remove(fib_index,
4685                                 &pfx_2001_c_s_64,
4686                                 FIB_SOURCE_CLI,
4687                                 DPO_PROTO_IP6,
4688                                 NULL,
4689                                 tm->hw[0]->sw_if_index,
4690                                 ~0,
4691                                 1,
4692                                 FIB_ROUTE_PATH_FLAG_NONE);
4693     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4694     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4695
4696     /*
4697      * Shutdown the interface on which we have a connected and through
4698      * which the routes are reachable.
4699      * This will result in the connected, adj-fibs, and routes linking to drop
4700      * The local/for-us prefix continues to receive.
4701      */
4702     clib_error_t * error;
4703
4704     error = vnet_sw_interface_set_flags(vnet_get_main(),
4705                                         tm->hw[0]->sw_if_index,
4706                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4707     FIB_TEST((NULL == error), "Interface shutdown OK");
4708
4709     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4710     dpo = fib_entry_contribute_ip_forwarding(fei);
4711     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4712              "2001::b/64 resolves via drop");
4713
4714     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4715     dpo = fib_entry_contribute_ip_forwarding(fei);
4716     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4717              "2001::a/64 resolves via drop");
4718     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4719     dpo = fib_entry_contribute_ip_forwarding(fei);
4720     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4721              "2001:0:0:1::3/64 resolves via drop");
4722     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4723     dpo = fib_entry_contribute_ip_forwarding(fei);
4724     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4725              "2001:0:0:1::2/64 resolves via drop");
4726     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4727     dpo = fib_entry_contribute_ip_forwarding(fei);
4728     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4729              "2001:0:0:1::1/128 not drop");
4730     local_pfx.fp_len = 64;
4731     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4732     dpo = fib_entry_contribute_ip_forwarding(fei);
4733     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4734              "2001:0:0:1/64 resolves via drop");
4735
4736     /*
4737      * no change
4738      */
4739     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4740              fib_path_list_db_size());
4741     FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4742              fib_path_list_pool_size());
4743     FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4744              fib_entry_pool_size());
4745
4746     /*
4747      * shutdown one of the other interfaces, then add a connected.
4748      * and swap one of the routes to it.
4749      */
4750     error = vnet_sw_interface_set_flags(vnet_get_main(),
4751                                         tm->hw[1]->sw_if_index,
4752                                         ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4753     FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4754
4755     fib_prefix_t connected_pfx = {
4756         .fp_len = 64,
4757         .fp_proto = FIB_PROTOCOL_IP6,
4758         .fp_addr = {
4759             .ip6 = {
4760                 /* 2001:0:0:2::1/64 */
4761                 .as_u64 = {
4762                     [0] = clib_host_to_net_u64(0x2001000000000002),
4763                     [1] = clib_host_to_net_u64(0x0000000000000001),
4764                 },
4765             },
4766         }
4767     };
4768     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4769                                     FIB_SOURCE_INTERFACE,
4770                                     (FIB_ENTRY_FLAG_CONNECTED |
4771                                      FIB_ENTRY_FLAG_ATTACHED),
4772                                     DPO_PROTO_IP6,
4773                                     NULL,
4774                                     tm->hw[1]->sw_if_index,
4775                                     ~0,
4776                                     1,
4777                                     NULL,
4778                                     FIB_ROUTE_PATH_FLAG_NONE);
4779     fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4780     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4781     dpo = fib_entry_contribute_ip_forwarding(fei);
4782     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4783     FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4784              "2001:0:0:2/64 not resolves via drop");
4785
4786     connected_pfx.fp_len = 128;
4787     fib_table_entry_update_one_path(fib_index, &connected_pfx,
4788                                     FIB_SOURCE_INTERFACE,
4789                                     (FIB_ENTRY_FLAG_CONNECTED |
4790                                      FIB_ENTRY_FLAG_LOCAL),
4791                                     DPO_PROTO_IP6,
4792                                     NULL,
4793                                     tm->hw[0]->sw_if_index,
4794                                     ~0, // invalid fib index
4795                                     1,
4796                                     NULL,
4797                                     FIB_ROUTE_PATH_FLAG_NONE);
4798     fei = fib_table_lookup(fib_index, &connected_pfx);
4799
4800     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4801     dpo = fib_entry_contribute_ip_forwarding(fei);
4802     dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4803     FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4804              "local interface adj is local");
4805     rd = receive_dpo_get(dpo->dpoi_index);
4806     FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4807                                     &rd->rd_addr)),
4808               "local interface adj is receive ok");
4809
4810     /*
4811      * +2 entries, +2 unshared path-lists
4812      */
4813     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4814              fib_path_list_db_size());
4815     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4816              fib_path_list_pool_size());
4817     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4818              fib_entry_pool_size());
4819
4820
4821     /*
4822      * bring the interface back up. we expected the routes to return
4823      * to normal forwarding.
4824      */
4825     error = vnet_sw_interface_set_flags(vnet_get_main(),
4826                                         tm->hw[0]->sw_if_index,
4827                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4828     FIB_TEST((NULL == error), "Interface bring-up OK");
4829     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4830     ai = fib_entry_get_adj(fei);
4831     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4832     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4833     ai = fib_entry_get_adj(fei);
4834     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4835     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4836     ai = fib_entry_get_adj(fei);
4837     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4838     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4839     ai = fib_entry_get_adj(fei);
4840     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4841     local_pfx.fp_len = 64;
4842     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4843     ai = fib_entry_get_adj(fei);
4844     adj = adj_get(ai);
4845     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4846              "attached interface adj is glean");
4847
4848     /*
4849      * Same test as above, but this time the HW interface goes down
4850      */
4851     error = vnet_hw_interface_set_flags(vnet_get_main(),
4852                                         tm->hw_if_indicies[0],
4853                                         ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4854     FIB_TEST((NULL == error), "Interface shutdown OK");
4855
4856     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4857     dpo = fib_entry_contribute_ip_forwarding(fei);
4858     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4859              "2001::b/64 resolves via drop");
4860     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4861     dpo = fib_entry_contribute_ip_forwarding(fei);
4862     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4863              "2001::a/64 resolves via drop");
4864     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4865     dpo = fib_entry_contribute_ip_forwarding(fei);
4866     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4867              "2001:0:0:1::3/128 resolves via drop");
4868     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4869     dpo = fib_entry_contribute_ip_forwarding(fei);
4870     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4871              "2001:0:0:1::2/128 resolves via drop");
4872     local_pfx.fp_len = 128;
4873     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4874     dpo = fib_entry_contribute_ip_forwarding(fei);
4875     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4876              "2001:0:0:1::1/128 not drop");
4877     local_pfx.fp_len = 64;
4878     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4879     dpo = fib_entry_contribute_ip_forwarding(fei);
4880     FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4881              "2001:0:0:1/64 resolves via drop");
4882
4883     error = vnet_hw_interface_set_flags(vnet_get_main(),
4884                                         tm->hw_if_indicies[0],
4885                                         VNET_HW_INTERFACE_FLAG_LINK_UP);
4886     FIB_TEST((NULL == error), "Interface bring-up OK");
4887     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4888     ai = fib_entry_get_adj(fei);
4889     FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4890     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4891     ai = fib_entry_get_adj(fei);
4892     FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4893     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4894     ai = fib_entry_get_adj(fei);
4895     FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4896     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4897     ai = fib_entry_get_adj(fei);
4898     FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4899     local_pfx.fp_len = 64;
4900     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4901     ai = fib_entry_get_adj(fei);
4902     adj = adj_get(ai);
4903     FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4904              "attached interface adj is glean");
4905
4906     /*
4907      * Delete the interface that the routes reolve through.
4908      * Again no routes are removed. They all point to drop.
4909      *
4910      * This is considered an error case. The control plane should
4911      * not remove interfaces through which routes resolve, but
4912      * such things can happen. ALL affected routes will drop.
4913      */
4914     vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4915
4916     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_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_a_s_64);
4920     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4921              "2001::b/64 resolves via drop");
4922     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4923     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4924              "2001:0:0:1::3/64 resolves via drop");
4925     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4926     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4927              "2001:0:0:1::2/64 resolves via drop");
4928     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4929     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4930              "2001:0:0:1::1/128 is drop");
4931     local_pfx.fp_len = 64;
4932     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4933     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4934              "2001:0:0:1/64 resolves via drop");
4935
4936     /*
4937      * no change
4938      */
4939     FIB_TEST((1 == fib_path_list_db_size()),   "path list DB population:%d",
4940              fib_path_list_db_size());
4941     FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4942              fib_path_list_pool_size());
4943     FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4944              fib_entry_pool_size());
4945
4946     /*
4947      * Add the interface back. routes stay unresolved.
4948      */
4949     error = ethernet_register_interface(vnet_get_main(),
4950                                         test_interface_device_class.index,
4951                                         0 /* instance */,
4952                                         hw_address,
4953                                         &tm->hw_if_indicies[0],
4954                                         /* flag change */ 0);
4955
4956     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4957     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4958              "2001::b/64 resolves via drop");
4959     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4960     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4961              "2001::b/64 resolves via drop");
4962     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4963     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4964              "2001:0:0:1::3/64 resolves via drop");
4965     fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4966     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4967              "2001:0:0:1::2/64 resolves via drop");
4968     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4969     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4970              "2001:0:0:1::1/128 is drop");
4971     local_pfx.fp_len = 64;
4972     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4973     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4974              "2001:0:0:1/64 resolves via drop");
4975
4976     /*
4977      * CLEANUP ALL the routes
4978      */
4979     fib_table_entry_delete(fib_index,
4980                            &pfx_2001_c_s_64,
4981                            FIB_SOURCE_API);
4982     fib_table_entry_delete(fib_index,
4983                            &pfx_2001_a_s_64,
4984                            FIB_SOURCE_API);
4985     fib_table_entry_delete(fib_index,
4986                            &pfx_2001_b_s_64,
4987                            FIB_SOURCE_API);
4988     fib_table_entry_delete(fib_index,
4989                            &pfx_2001_1_3_s_128,
4990                            FIB_SOURCE_ADJ);
4991     fib_table_entry_delete(fib_index,
4992                            &pfx_2001_1_2_s_128,
4993                            FIB_SOURCE_ADJ);
4994     local_pfx.fp_len = 64;
4995     fib_table_entry_delete(fib_index, &local_pfx,
4996                            FIB_SOURCE_INTERFACE);
4997     local_pfx.fp_len = 128;
4998     fib_table_entry_special_remove(fib_index, &local_pfx,
4999                                    FIB_SOURCE_INTERFACE);
5000     connected_pfx.fp_len = 64;
5001     fib_table_entry_delete(fib_index, &connected_pfx,
5002                            FIB_SOURCE_INTERFACE);
5003     connected_pfx.fp_len = 128;
5004     fib_table_entry_special_remove(fib_index, &connected_pfx,
5005                                    FIB_SOURCE_INTERFACE);
5006
5007     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5008               fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5009              "2001::a/64 removed");
5010     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5011               fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5012              "2001::b/64 removed");
5013     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5014               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5015              "2001:0:0:1::3/128 removed");
5016     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5017               fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5018              "2001:0:0:1::3/128 removed");
5019     local_pfx.fp_len = 64;
5020     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5021               fib_table_lookup_exact_match(fib_index, &local_pfx)),
5022              "2001:0:0:1/64 removed");
5023     local_pfx.fp_len = 128;
5024     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5025               fib_table_lookup_exact_match(fib_index, &local_pfx)),
5026              "2001:0:0:1::1/128 removed");
5027     connected_pfx.fp_len = 64;
5028     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5029               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5030              "2001:0:0:2/64 removed");
5031     connected_pfx.fp_len = 128;
5032     FIB_TEST((FIB_NODE_INDEX_INVALID ==
5033               fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5034              "2001:0:0:2::1/128 removed");
5035
5036     /*
5037      * -8 entries. -7 path-lists (1 was shared).
5038      */
5039     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
5040              fib_path_list_db_size());
5041     FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5042              fib_path_list_pool_size());
5043     FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5044              fib_entry_pool_size());
5045
5046     /*
5047      * now remove the VRF
5048      */
5049     fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5050
5051     FIB_TEST((0 == fib_path_list_db_size()),   "path list DB population:%d",
5052              fib_path_list_db_size());
5053     FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5054              fib_path_list_pool_size());
5055     FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5056              fib_entry_pool_size());
5057
5058     adj_unlock(ai_02);
5059     adj_unlock(ai_01);
5060
5061     /*
5062      * return the interfaces to up state
5063      */
5064     error = vnet_sw_interface_set_flags(vnet_get_main(),
5065                                         tm->hw[0]->sw_if_index,
5066                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5067     error = vnet_sw_interface_set_flags(vnet_get_main(),
5068                                         tm->hw[1]->sw_if_index,
5069                                         VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5070
5071     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5072              adj_nbr_db_size());
5073
5074     return (0);
5075 }
5076
5077 /*
5078  * Test Attached Exports
5079  */
5080 static int
5081 fib_test_ae (void)
5082 {
5083     const dpo_id_t *dpo, *dpo_drop;
5084     const u32 fib_index = 0;
5085     fib_node_index_t fei;
5086     test_main_t *tm;
5087     ip4_main_t *im;
5088
5089     tm = &test_main;
5090     im = &ip4_main;
5091
5092     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5093              adj_nbr_db_size());
5094
5095     /*
5096      * add interface routes. We'll assume this works. It's more rigorously
5097      * tested elsewhere.
5098      */
5099     fib_prefix_t local_pfx = {
5100         .fp_len = 24,
5101         .fp_proto = FIB_PROTOCOL_IP4,
5102         .fp_addr = {
5103             .ip4 = {
5104                 /* 10.10.10.10 */
5105                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5106             },
5107         },
5108     };
5109
5110     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5111     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5112
5113     dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5114
5115     fib_table_entry_update_one_path(fib_index, &local_pfx,
5116                                     FIB_SOURCE_INTERFACE,
5117                                     (FIB_ENTRY_FLAG_CONNECTED |
5118                                      FIB_ENTRY_FLAG_ATTACHED),
5119                                     DPO_PROTO_IP4,
5120                                     NULL,
5121                                     tm->hw[0]->sw_if_index,
5122                                     ~0,
5123                                     1,
5124                                     NULL,
5125                                     FIB_ROUTE_PATH_FLAG_NONE);
5126     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5127     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5128              "attached interface route present");
5129
5130     local_pfx.fp_len = 32;
5131     fib_table_entry_update_one_path(fib_index, &local_pfx,
5132                                     FIB_SOURCE_INTERFACE,
5133                                     (FIB_ENTRY_FLAG_CONNECTED |
5134                                      FIB_ENTRY_FLAG_LOCAL),
5135                                     DPO_PROTO_IP4,
5136                                     NULL,
5137                                     tm->hw[0]->sw_if_index,
5138                                     ~0, // invalid fib index
5139                                     1,
5140                                     NULL,
5141                                     FIB_ROUTE_PATH_FLAG_NONE);
5142     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5143
5144     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5145              "local interface route present");
5146
5147     /*
5148      * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5149      */
5150     fib_prefix_t pfx_10_10_10_1_s_32 = {
5151         .fp_len = 32,
5152         .fp_proto = FIB_PROTOCOL_IP4,
5153         .fp_addr = {
5154             /* 10.10.10.1 */
5155             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5156         },
5157     };
5158     fib_node_index_t ai;
5159
5160     fib_table_entry_path_add(fib_index,
5161                              &pfx_10_10_10_1_s_32,
5162                              FIB_SOURCE_ADJ,
5163                              FIB_ENTRY_FLAG_ATTACHED,
5164                              DPO_PROTO_IP4,
5165                              &pfx_10_10_10_1_s_32.fp_addr,
5166                              tm->hw[0]->sw_if_index,
5167                              ~0, // invalid fib index
5168                              1,
5169                              NULL,
5170                              FIB_ROUTE_PATH_FLAG_NONE);
5171
5172     fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5173     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5174     ai = fib_entry_get_adj(fei);
5175
5176     /*
5177      * create another FIB table into which routes will be imported
5178      */
5179     u32 import_fib_index1;
5180
5181     import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5182                                                           11,
5183                                                           FIB_SOURCE_CLI);
5184
5185     /*
5186      * Add an attached route in the import FIB
5187      */
5188     local_pfx.fp_len = 24;
5189     fib_table_entry_update_one_path(import_fib_index1,
5190                                     &local_pfx,
5191                                     FIB_SOURCE_API,
5192                                     FIB_ENTRY_FLAG_NONE,
5193                                     DPO_PROTO_IP4,
5194                                     NULL,
5195                                     tm->hw[0]->sw_if_index,
5196                                     ~0, // invalid fib index
5197                                     1,
5198                                     NULL,
5199                                     FIB_ROUTE_PATH_FLAG_NONE);
5200     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5201     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5202
5203     /*
5204      * check for the presence of the adj-fibs in the import table
5205      */
5206     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5207     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5208     FIB_TEST((ai == fib_entry_get_adj(fei)),
5209              "adj-fib1 Import uses same adj as export");
5210
5211     /*
5212      * check for the presence of the local in the import table
5213      */
5214     local_pfx.fp_len = 32;
5215     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5216     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5217
5218     /*
5219      * Add another adj-fin in the export table. Expect this
5220      * to get magically exported;
5221      */
5222     fib_prefix_t pfx_10_10_10_2_s_32 = {
5223         .fp_len = 32,
5224         .fp_proto = FIB_PROTOCOL_IP4,
5225         .fp_addr = {
5226             /* 10.10.10.2 */
5227             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5228         },
5229     };
5230
5231     fib_table_entry_path_add(fib_index,
5232                              &pfx_10_10_10_2_s_32,
5233                              FIB_SOURCE_ADJ,
5234                              FIB_ENTRY_FLAG_ATTACHED,
5235                              DPO_PROTO_IP4,
5236                              &pfx_10_10_10_2_s_32.fp_addr,
5237                              tm->hw[0]->sw_if_index,
5238                              ~0, // invalid fib index
5239                              1,
5240                              NULL,
5241                              FIB_ROUTE_PATH_FLAG_NONE);
5242     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5243     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5244     ai = fib_entry_get_adj(fei);
5245
5246     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5247     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5248     FIB_TEST((ai == fib_entry_get_adj(fei)),
5249              "Import uses same adj as export");
5250     FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5251              "ADJ-fib2 imported flags %d",
5252              fib_entry_get_flags(fei));
5253
5254     /*
5255      * create a 2nd FIB table into which routes will be imported
5256      */
5257     u32 import_fib_index2;
5258
5259     import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5260                                                           FIB_SOURCE_CLI);
5261
5262     /*
5263      * Add an attached route in the import FIB
5264      */
5265     local_pfx.fp_len = 24;
5266     fib_table_entry_update_one_path(import_fib_index2,
5267                                     &local_pfx,
5268                                     FIB_SOURCE_API,
5269                                     FIB_ENTRY_FLAG_NONE,
5270                                     DPO_PROTO_IP4,
5271                                     NULL,
5272                                     tm->hw[0]->sw_if_index,
5273                                     ~0, // invalid fib index
5274                                     1,
5275                                     NULL,
5276                                     FIB_ROUTE_PATH_FLAG_NONE);
5277     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5278     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5279
5280     /*
5281      * check for the presence of all the adj-fibs and local in the import table
5282      */
5283     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5284     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5285     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5286     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5287     local_pfx.fp_len = 32;
5288     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5289     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5290
5291     /*
5292      * add a 3rd adj-fib. expect it to be exported to both tables.
5293      */
5294     fib_prefix_t pfx_10_10_10_3_s_32 = {
5295         .fp_len = 32,
5296         .fp_proto = FIB_PROTOCOL_IP4,
5297         .fp_addr = {
5298             /* 10.10.10.3 */
5299             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5300         },
5301     };
5302
5303     fib_table_entry_path_add(fib_index,
5304                              &pfx_10_10_10_3_s_32,
5305                              FIB_SOURCE_ADJ,
5306                              FIB_ENTRY_FLAG_ATTACHED,
5307                              DPO_PROTO_IP4,
5308                              &pfx_10_10_10_3_s_32.fp_addr,
5309                              tm->hw[0]->sw_if_index,
5310                              ~0, // invalid fib index
5311                              1,
5312                              NULL,
5313                              FIB_ROUTE_PATH_FLAG_NONE);
5314     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5315     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5316     ai = fib_entry_get_adj(fei);
5317
5318     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5319     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5320     FIB_TEST((ai == fib_entry_get_adj(fei)),
5321              "Import uses same adj as export");
5322     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5323     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5324     FIB_TEST((ai == fib_entry_get_adj(fei)),
5325              "Import uses same adj as export");
5326
5327     /*
5328      * remove the 3rd adj fib. we expect it to be removed from both FIBs
5329      */
5330     fib_table_entry_delete(fib_index,
5331                            &pfx_10_10_10_3_s_32,
5332                            FIB_SOURCE_ADJ);
5333
5334     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5335     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5336
5337     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5338     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5339
5340     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5341     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5342
5343     /*
5344      * remove the attached route from the 2nd FIB. expect the imported
5345      * entires to be removed
5346      */
5347     local_pfx.fp_len = 24;
5348     fib_table_entry_delete(import_fib_index2,
5349                            &local_pfx,
5350                            FIB_SOURCE_API);
5351     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5352     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5353
5354     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5355     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5356     fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5357     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5358     local_pfx.fp_len = 32;
5359     fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5360     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5361
5362     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5363     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5364     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5365     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5366     local_pfx.fp_len = 32;
5367     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5368     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5369
5370     /*
5371      * modify the route in FIB1 so it is no longer attached. expect the imported
5372      * entires to be removed
5373      */
5374     local_pfx.fp_len = 24;
5375     fib_table_entry_update_one_path(import_fib_index1,
5376                                     &local_pfx,
5377                                     FIB_SOURCE_API,
5378                                     FIB_ENTRY_FLAG_NONE,
5379                                     DPO_PROTO_IP4,
5380                                     &pfx_10_10_10_2_s_32.fp_addr,
5381                                     tm->hw[0]->sw_if_index,
5382                                     ~0, // invalid fib index
5383                                     1,
5384                                     NULL,
5385                                     FIB_ROUTE_PATH_FLAG_NONE);
5386     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5387     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5388     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5389     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5390     local_pfx.fp_len = 32;
5391     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5392     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5393
5394     /*
5395      * modify it back to attached. expect the adj-fibs back
5396      */
5397     local_pfx.fp_len = 24;
5398     fib_table_entry_update_one_path(import_fib_index1,
5399                                     &local_pfx,
5400                                     FIB_SOURCE_API,
5401                                     FIB_ENTRY_FLAG_NONE,
5402                                     DPO_PROTO_IP4,
5403                                     NULL,
5404                                     tm->hw[0]->sw_if_index,
5405                                     ~0, // invalid fib index
5406                                     1,
5407                                     NULL,
5408                                     FIB_ROUTE_PATH_FLAG_NONE);
5409     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5410     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5411     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5412     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5413     local_pfx.fp_len = 32;
5414     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5415     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5416
5417     /*
5418      * add a covering attached next-hop for the interface address, so we have
5419      * a valid adj to find when we check the forwarding tables
5420      */
5421     fib_prefix_t pfx_10_0_0_0_s_8 = {
5422         .fp_len = 8,
5423         .fp_proto = FIB_PROTOCOL_IP4,
5424         .fp_addr = {
5425             /* 10.0.0.0 */
5426             .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5427         },
5428     };
5429
5430     fei = fib_table_entry_update_one_path(fib_index,
5431                                           &pfx_10_0_0_0_s_8,
5432                                           FIB_SOURCE_API,
5433                                           FIB_ENTRY_FLAG_NONE,
5434                                           DPO_PROTO_IP4,
5435                                           &pfx_10_10_10_3_s_32.fp_addr,
5436                                           tm->hw[0]->sw_if_index,
5437                                           ~0, // invalid fib index
5438                                           1,
5439                                           NULL,
5440                                           FIB_ROUTE_PATH_FLAG_NONE);
5441     dpo = fib_entry_contribute_ip_forwarding(fei);
5442
5443     /*
5444      * remove the route in the export fib. expect the adj-fibs to be removed
5445      */
5446     local_pfx.fp_len = 24;
5447     fib_table_entry_delete(fib_index,
5448                            &local_pfx,
5449                            FIB_SOURCE_INTERFACE);
5450
5451     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5452     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5453     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5454     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5455     local_pfx.fp_len = 32;
5456     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5457     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5458
5459     /*
5460      * the adj-fibs in the export VRF are present in the FIB table,
5461      * but not installed in forwarding, since they have no attached cover.
5462      * Consequently a lookup in the MTRIE gives the adj for the covering
5463      * route 10.0.0.0/8.
5464      */
5465     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5466     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5467
5468     index_t lbi;
5469     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5470     FIB_TEST(lbi == dpo->dpoi_index,
5471              "10.10.10.1 forwards on \n%U not \n%U",
5472              format_load_balance, lbi, 0,
5473              format_dpo_id, dpo, 0);
5474     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5475     FIB_TEST(lbi == dpo->dpoi_index,
5476              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5477     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5478     FIB_TEST(lbi == dpo->dpoi_index,
5479              "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5480
5481     /*
5482      * add the export prefix back, but not as attached.
5483      * No adj-fibs in export nor import tables
5484      */
5485     local_pfx.fp_len = 24;
5486     fei = fib_table_entry_update_one_path(fib_index,
5487                                           &local_pfx,
5488                                           FIB_SOURCE_API,
5489                                           FIB_ENTRY_FLAG_NONE,
5490                                           DPO_PROTO_IP4,
5491                                           &pfx_10_10_10_1_s_32.fp_addr,
5492                                           tm->hw[0]->sw_if_index,
5493                                           ~0, // invalid fib index
5494                                           1,
5495                                           NULL,
5496                                           FIB_ROUTE_PATH_FLAG_NONE);
5497     dpo = fib_entry_contribute_ip_forwarding(fei);
5498
5499     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5500     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5501     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5502     FIB_TEST(lbi == dpo->dpoi_index,
5503              "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5504     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5505     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5506     lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5507     FIB_TEST(lbi == dpo->dpoi_index,
5508              "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5509
5510     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5511     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5512     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5513     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5514     local_pfx.fp_len = 32;
5515     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5516     FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5517
5518     /*
5519      * modify the export prefix so it is attached. expect all covereds to return
5520      */
5521     local_pfx.fp_len = 24;
5522     fib_table_entry_update_one_path(fib_index,
5523                                     &local_pfx,
5524                                     FIB_SOURCE_API,
5525                                     FIB_ENTRY_FLAG_NONE,
5526                                     DPO_PROTO_IP4,
5527                                     NULL,
5528                                     tm->hw[0]->sw_if_index,
5529                                     ~0, // invalid fib index
5530                                     1,
5531                                     NULL,
5532                                     FIB_ROUTE_PATH_FLAG_NONE);
5533
5534     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5535     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5536     dpo = fib_entry_contribute_ip_forwarding(fei);
5537     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5538              "Adj-fib1 is not drop in export");
5539     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5540     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5541     local_pfx.fp_len = 32;
5542     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5543     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5544     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5545     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5546     dpo = fib_entry_contribute_ip_forwarding(fei);
5547     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5548              "Adj-fib1 is not drop in export");
5549     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5550     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5551     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5552     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5553     local_pfx.fp_len = 32;
5554     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5555     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5556
5557     /*
5558      * modify the export prefix so connected. no change.
5559      */
5560     local_pfx.fp_len = 24;
5561     fib_table_entry_update_one_path(fib_index, &local_pfx,
5562                                     FIB_SOURCE_INTERFACE,
5563                                     (FIB_ENTRY_FLAG_CONNECTED |
5564                                      FIB_ENTRY_FLAG_ATTACHED),
5565                                     DPO_PROTO_IP4,
5566                                     NULL,
5567                                     tm->hw[0]->sw_if_index,
5568                                     ~0,
5569                                     1,
5570                                     NULL,
5571                                     FIB_ROUTE_PATH_FLAG_NONE);
5572
5573     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5574     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5575     dpo = fib_entry_contribute_ip_forwarding(fei);
5576     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5577              "Adj-fib1 is not drop in export");
5578     fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5579     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5580     local_pfx.fp_len = 32;
5581     fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5582     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5583     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5584     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5585     dpo = fib_entry_contribute_ip_forwarding(fei);
5586     FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5587              "Adj-fib1 is not drop in export");
5588     fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5589     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5590     local_pfx.fp_len = 32;
5591     fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5592     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5593
5594     /*
5595      * CLEANUP
5596      */
5597     fib_table_entry_delete(fib_index,
5598                            &pfx_10_0_0_0_s_8,
5599                            FIB_SOURCE_API);
5600     fib_table_entry_delete(fib_index,
5601                            &pfx_10_10_10_1_s_32,
5602                            FIB_SOURCE_ADJ);
5603     fib_table_entry_delete(fib_index,
5604                            &pfx_10_10_10_2_s_32,
5605                            FIB_SOURCE_ADJ);
5606     local_pfx.fp_len = 32;
5607     fib_table_entry_delete(fib_index,
5608                            &local_pfx,
5609                            FIB_SOURCE_INTERFACE);
5610     local_pfx.fp_len = 24;
5611     fib_table_entry_delete(fib_index,
5612                            &local_pfx,
5613                            FIB_SOURCE_API);
5614     fib_table_entry_delete(fib_index,
5615                            &local_pfx,
5616                            FIB_SOURCE_INTERFACE);
5617     local_pfx.fp_len = 24;
5618     fib_table_entry_delete(import_fib_index1,
5619                            &local_pfx,
5620                            FIB_SOURCE_API);
5621
5622     fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5623     fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5624
5625     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5626              adj_nbr_db_size());
5627
5628     return (0);
5629 }
5630
5631 /*
5632  * Test Path Preference
5633  */
5634 static int
5635 fib_test_pref (void)
5636 {
5637     test_main_t *tm = &test_main;
5638
5639     const fib_prefix_t pfx_1_1_1_1_s_32 = {
5640         .fp_len = 32,
5641         .fp_proto = FIB_PROTOCOL_IP4,
5642         .fp_addr = {
5643             .ip4 = {
5644                 .as_u32 = clib_host_to_net_u32(0x01010101),
5645             },
5646         },
5647     };
5648
5649     /*
5650      * 2 high, 2 medium and 2 low preference non-recursive paths
5651      */
5652     fib_route_path_t nr_path_hi_1 = {
5653         .frp_proto = DPO_PROTO_IP4,
5654         .frp_sw_if_index = tm->hw[0]->sw_if_index,
5655         .frp_fib_index = ~0,
5656         .frp_weight = 1,
5657         .frp_preference = 0,
5658         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5659         .frp_addr = {
5660             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5661         },
5662     };
5663     fib_route_path_t nr_path_hi_2 = {
5664         .frp_proto = DPO_PROTO_IP4,
5665         .frp_sw_if_index = tm->hw[0]->sw_if_index,
5666         .frp_fib_index = ~0,
5667         .frp_weight = 1,
5668         .frp_preference = 0,
5669         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5670         .frp_addr = {
5671             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5672         },
5673     };
5674     fib_route_path_t nr_path_med_1 = {
5675         .frp_proto = DPO_PROTO_IP4,
5676         .frp_sw_if_index = tm->hw[1]->sw_if_index,
5677         .frp_fib_index = ~0,
5678         .frp_weight = 1,
5679         .frp_preference = 1,
5680         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5681         .frp_addr = {
5682             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5683         },
5684     };
5685     fib_route_path_t nr_path_med_2 = {
5686         .frp_proto = DPO_PROTO_IP4,
5687         .frp_sw_if_index = tm->hw[1]->sw_if_index,
5688         .frp_fib_index = ~0,
5689         .frp_weight = 1,
5690         .frp_preference = 1,
5691         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5692         .frp_addr = {
5693             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5694         },
5695     };
5696     fib_route_path_t nr_path_low_1 = {
5697         .frp_proto = DPO_PROTO_IP4,
5698         .frp_sw_if_index = tm->hw[2]->sw_if_index,
5699         .frp_fib_index = ~0,
5700         .frp_weight = 1,
5701         .frp_preference = 2,
5702         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5703         .frp_addr = {
5704             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5705         },
5706     };
5707     fib_route_path_t nr_path_low_2 = {
5708         .frp_proto = DPO_PROTO_IP4,
5709         .frp_sw_if_index = tm->hw[2]->sw_if_index,
5710         .frp_fib_index = ~0,
5711         .frp_weight = 1,
5712         .frp_preference = 2,
5713         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5714         .frp_addr = {
5715             .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5716         },
5717     };
5718     fib_route_path_t *nr_paths = NULL;
5719
5720     vec_add1(nr_paths, nr_path_hi_1);
5721     vec_add1(nr_paths, nr_path_hi_2);
5722     vec_add1(nr_paths, nr_path_med_1);
5723     vec_add1(nr_paths, nr_path_med_2);
5724     vec_add1(nr_paths, nr_path_low_1);
5725     vec_add1(nr_paths, nr_path_low_2);
5726
5727     adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5728                                               VNET_LINK_IP4,
5729                                               &nr_path_hi_1.frp_addr,
5730                                               nr_path_hi_1.frp_sw_if_index);
5731     adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5732                                               VNET_LINK_IP4,
5733                                               &nr_path_hi_2.frp_addr,
5734                                               nr_path_hi_2.frp_sw_if_index);
5735     adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5736                                                VNET_LINK_IP4,
5737                                                &nr_path_med_1.frp_addr,
5738                                                nr_path_med_1.frp_sw_if_index);
5739     adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5740                                                VNET_LINK_IP4,
5741                                                &nr_path_med_2.frp_addr,
5742                                                nr_path_med_2.frp_sw_if_index);
5743     adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5744                                                VNET_LINK_IP4,
5745                                                &nr_path_low_1.frp_addr,
5746                                                nr_path_low_1.frp_sw_if_index);
5747     adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5748                                                VNET_LINK_IP4,
5749                                                &nr_path_low_2.frp_addr,
5750                                                nr_path_low_2.frp_sw_if_index);
5751
5752     fib_test_lb_bucket_t ip_hi_1 = {
5753         .type = FT_LB_ADJ,
5754         .adj = {
5755             .adj = ai_hi_1,
5756         },
5757     };
5758     fib_test_lb_bucket_t ip_hi_2 = {
5759         .type = FT_LB_ADJ,
5760         .adj = {
5761             .adj = ai_hi_2,
5762         },
5763     };
5764     fib_test_lb_bucket_t ip_med_1 = {
5765         .type = FT_LB_ADJ,
5766         .adj = {
5767             .adj = ai_med_1,
5768         },
5769     };
5770     fib_test_lb_bucket_t ip_med_2 = {
5771         .type = FT_LB_ADJ,
5772         .adj = {
5773             .adj = ai_med_2,
5774         },
5775     };
5776     fib_test_lb_bucket_t ip_low_1 = {
5777         .type = FT_LB_ADJ,
5778         .adj = {
5779             .adj = ai_low_1,
5780         },
5781     };
5782     fib_test_lb_bucket_t ip_low_2 = {
5783         .type = FT_LB_ADJ,
5784         .adj = {
5785             .adj = ai_low_2,
5786         },
5787     };
5788
5789     fib_node_index_t fei;
5790
5791     fei = fib_table_entry_path_add2(0,
5792                                     &pfx_1_1_1_1_s_32,
5793                                     FIB_SOURCE_API,
5794                                     FIB_ENTRY_FLAG_NONE,
5795                                     nr_paths);
5796
5797     FIB_TEST(fib_test_validate_entry(fei,
5798                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5799                                      2,
5800                                      &ip_hi_1,
5801                                      &ip_hi_2),
5802              "1.1.1.1/32 via high preference paths");
5803
5804     /*
5805      * bring down the interface on which the high preference path lie
5806      */
5807     vnet_sw_interface_set_flags(vnet_get_main(),
5808                                 tm->hw[0]->sw_if_index,
5809                                 0);
5810
5811     FIB_TEST(fib_test_validate_entry(fei,
5812                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5813                                      2,
5814                                      &ip_med_1,
5815                                      &ip_med_2),
5816              "1.1.1.1/32 via medium preference paths");
5817
5818     /*
5819      * bring down the interface on which the medium preference path lie
5820      */
5821     vnet_sw_interface_set_flags(vnet_get_main(),
5822                                 tm->hw[1]->sw_if_index,
5823                                 0);
5824
5825     FIB_TEST(fib_test_validate_entry(fei,
5826                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5827                                      2,
5828                                      &ip_low_1,
5829                                      &ip_low_2),
5830              "1.1.1.1/32 via low preference paths");
5831
5832     /*
5833      * bring up the interface on which the high preference path lie
5834      */
5835     vnet_sw_interface_set_flags(vnet_get_main(),
5836                                 tm->hw[0]->sw_if_index,
5837                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5838
5839     FIB_TEST(fib_test_validate_entry(fei,
5840                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5841                                      2,
5842                                      &ip_hi_1,
5843                                      &ip_hi_2),
5844              "1.1.1.1/32 via high preference paths");
5845
5846     /*
5847      * bring up the interface on which the medium preference path lie
5848      */
5849     vnet_sw_interface_set_flags(vnet_get_main(),
5850                                 tm->hw[1]->sw_if_index,
5851                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5852
5853     FIB_TEST(fib_test_validate_entry(fei,
5854                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5855                                      2,
5856                                      &ip_hi_1,
5857                                      &ip_hi_2),
5858              "1.1.1.1/32 via high preference paths");
5859
5860     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5861     fib_entry_contribute_forwarding(fei,
5862                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5863                                     &ip_1_1_1_1);
5864
5865     /*
5866      * 3 recursive paths of different preference
5867      */
5868     const fib_prefix_t pfx_1_1_1_2_s_32 = {
5869         .fp_len = 32,
5870         .fp_proto = FIB_PROTOCOL_IP4,
5871         .fp_addr = {
5872             .ip4 = {
5873                 .as_u32 = clib_host_to_net_u32(0x01010102),
5874             },
5875         },
5876     };
5877     const fib_prefix_t pfx_1_1_1_3_s_32 = {
5878         .fp_len = 32,
5879         .fp_proto = FIB_PROTOCOL_IP4,
5880         .fp_addr = {
5881             .ip4 = {
5882                 .as_u32 = clib_host_to_net_u32(0x01010103),
5883             },
5884         },
5885     };
5886     fei = fib_table_entry_path_add2(0,
5887                                     &pfx_1_1_1_2_s_32,
5888                                     FIB_SOURCE_API,
5889                                     FIB_ENTRY_FLAG_NONE,
5890                                     nr_paths);
5891     dpo_id_t ip_1_1_1_2 = DPO_INVALID;
5892     fib_entry_contribute_forwarding(fei,
5893                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5894                                     &ip_1_1_1_2);
5895     fei = fib_table_entry_path_add2(0,
5896                                     &pfx_1_1_1_3_s_32,
5897                                     FIB_SOURCE_API,
5898                                     FIB_ENTRY_FLAG_NONE,
5899                                     nr_paths);
5900     dpo_id_t ip_1_1_1_3 = DPO_INVALID;
5901     fib_entry_contribute_forwarding(fei,
5902                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5903                                     &ip_1_1_1_3);
5904
5905     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5906         .type = FT_LB_O_LB,
5907         .lb = {
5908             .lb = ip_1_1_1_1.dpoi_index,
5909         },
5910     };
5911     fib_test_lb_bucket_t ip_o_1_1_1_2 = {
5912         .type = FT_LB_O_LB,
5913         .lb = {
5914             .lb = ip_1_1_1_2.dpoi_index,
5915         },
5916     };
5917     fib_test_lb_bucket_t ip_o_1_1_1_3 = {
5918         .type = FT_LB_O_LB,
5919         .lb = {
5920             .lb = ip_1_1_1_3.dpoi_index,
5921         },
5922     };
5923     fib_route_path_t r_path_hi = {
5924         .frp_proto = DPO_PROTO_IP4,
5925         .frp_sw_if_index = ~0,
5926         .frp_fib_index = 0,
5927         .frp_weight = 1,
5928         .frp_preference = 0,
5929         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5930         .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
5931     };
5932     fib_route_path_t r_path_med = {
5933         .frp_proto = DPO_PROTO_IP4,
5934         .frp_sw_if_index = ~0,
5935         .frp_fib_index = 0,
5936         .frp_weight = 1,
5937         .frp_preference = 10,
5938         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5939         .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
5940     };
5941     fib_route_path_t r_path_low = {
5942         .frp_proto = DPO_PROTO_IP4,
5943         .frp_sw_if_index = ~0,
5944         .frp_fib_index = 0,
5945         .frp_weight = 1,
5946         .frp_preference = 255,
5947         .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5948         .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
5949     };
5950     fib_route_path_t *r_paths = NULL;
5951
5952     vec_add1(r_paths, r_path_hi);
5953     vec_add1(r_paths, r_path_low);
5954     vec_add1(r_paths, r_path_med);
5955
5956     /*
5957      * add many recursive so we get the LB MAp created
5958      */
5959     #define N_PFXS 64
5960     fib_prefix_t pfx_r[N_PFXS];
5961     unsigned int n_pfxs;
5962     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
5963     {
5964         pfx_r[n_pfxs].fp_len = 32;
5965         pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
5966         pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
5967             clib_host_to_net_u32(0x02000000 + n_pfxs);
5968
5969         fei = fib_table_entry_path_add2(0,
5970                                         &pfx_r[n_pfxs],
5971                                         FIB_SOURCE_API,
5972                                         FIB_ENTRY_FLAG_NONE,
5973                                         r_paths);
5974
5975         FIB_TEST(fib_test_validate_entry(fei,
5976                                          FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5977                                          1,
5978                                          &ip_o_1_1_1_1),
5979                  "recursive via high preference paths");
5980
5981         /*
5982          * withdraw hig pref resolving entry
5983          */
5984         fib_table_entry_delete(0,
5985                                &pfx_1_1_1_1_s_32,
5986                                FIB_SOURCE_API);
5987
5988         /* suspend so the update walk kicks int */
5989         vlib_process_suspend(vlib_get_main(), 1e-5);
5990
5991         FIB_TEST(fib_test_validate_entry(fei,
5992                                          FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5993                                          1,
5994                                          &ip_o_1_1_1_2),
5995                  "recursive via medium preference paths");
5996
5997         /*
5998          * withdraw medium pref resolving entry
5999          */
6000         fib_table_entry_delete(0,
6001                                &pfx_1_1_1_2_s_32,
6002                                FIB_SOURCE_API);
6003
6004         /* suspend so the update walk kicks int */
6005         vlib_process_suspend(vlib_get_main(), 1e-5);
6006
6007         FIB_TEST(fib_test_validate_entry(fei,
6008                                          FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6009                                          1,
6010                                          &ip_o_1_1_1_3),
6011                  "recursive via low preference paths");
6012
6013         /*
6014          * add back paths for next iteration
6015          */
6016         fei = fib_table_entry_update(0,
6017                                      &pfx_1_1_1_2_s_32,
6018                                      FIB_SOURCE_API,
6019                                      FIB_ENTRY_FLAG_NONE,
6020                                      nr_paths);
6021         fei = fib_table_entry_update(0,
6022                                      &pfx_1_1_1_1_s_32,
6023                                      FIB_SOURCE_API,
6024                                      FIB_ENTRY_FLAG_NONE,
6025                                      nr_paths);
6026
6027         /* suspend so the update walk kicks int */
6028         vlib_process_suspend(vlib_get_main(), 1e-5);
6029
6030         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6031         FIB_TEST(fib_test_validate_entry(fei,
6032                                          FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6033                                          1,
6034                                          &ip_o_1_1_1_1),
6035                  "recursive via high preference paths");
6036     }
6037
6038
6039     fib_table_entry_delete(0,
6040                            &pfx_1_1_1_1_s_32,
6041                            FIB_SOURCE_API);
6042
6043     /* suspend so the update walk kicks int */
6044     vlib_process_suspend(vlib_get_main(), 1e-5);
6045
6046     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6047     {
6048         fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6049
6050         FIB_TEST(fib_test_validate_entry(fei,
6051                                          FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6052                                          1,
6053                                          &ip_o_1_1_1_2),
6054                  "recursive via medium preference paths");
6055     }
6056     for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6057     {
6058         fib_table_entry_delete(0,
6059                                &pfx_r[n_pfxs],
6060                                FIB_SOURCE_API);
6061     }
6062
6063     /*
6064      * Cleanup
6065      */
6066     fib_table_entry_delete(0,
6067                            &pfx_1_1_1_2_s_32,
6068                            FIB_SOURCE_API);
6069     fib_table_entry_delete(0,
6070                            &pfx_1_1_1_3_s_32,
6071                            FIB_SOURCE_API);
6072
6073     dpo_reset(&ip_1_1_1_1);
6074     dpo_reset(&ip_1_1_1_2);
6075     dpo_reset(&ip_1_1_1_3);
6076     adj_unlock(ai_low_2);
6077     adj_unlock(ai_low_1);
6078     adj_unlock(ai_med_2);
6079     adj_unlock(ai_med_1);
6080     adj_unlock(ai_hi_2);
6081     adj_unlock(ai_hi_1);
6082     return (0);
6083 }
6084
6085 /*
6086  * Test the recursive route route handling for GRE tunnels
6087  */
6088 static int
6089 fib_test_label (void)
6090 {
6091     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;
6092     const u32 fib_index = 0;
6093     test_main_t *tm;
6094     ip4_main_t *im;
6095     int lb_count, ii;
6096
6097     lb_count = pool_elts(load_balance_pool);
6098     tm = &test_main;
6099     im = &ip4_main;
6100
6101     /*
6102      * add interface routes. We'll assume this works. It's more rigorously
6103      * tested elsewhere.
6104      */
6105     fib_prefix_t local0_pfx = {
6106         .fp_len = 24,
6107         .fp_proto = FIB_PROTOCOL_IP4,
6108         .fp_addr = {
6109             .ip4 = {
6110                 /* 10.10.10.10 */
6111                 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6112             },
6113         },
6114     };
6115
6116     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6117              adj_nbr_db_size());
6118
6119     vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6120     im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6121
6122     fib_table_entry_update_one_path(fib_index, &local0_pfx,
6123                                     FIB_SOURCE_INTERFACE,
6124                                     (FIB_ENTRY_FLAG_CONNECTED |
6125                                      FIB_ENTRY_FLAG_ATTACHED),
6126                                     DPO_PROTO_IP4,
6127                                     NULL,
6128                                     tm->hw[0]->sw_if_index,
6129                                     ~0,
6130                                     1,
6131                                     NULL,
6132                                     FIB_ROUTE_PATH_FLAG_NONE);
6133     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6134     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6135              "attached interface route present");
6136
6137     local0_pfx.fp_len = 32;
6138     fib_table_entry_update_one_path(fib_index, &local0_pfx,
6139                                     FIB_SOURCE_INTERFACE,
6140                                     (FIB_ENTRY_FLAG_CONNECTED |
6141                                      FIB_ENTRY_FLAG_LOCAL),
6142                                     DPO_PROTO_IP4,
6143                                     NULL,
6144                                     tm->hw[0]->sw_if_index,
6145                                     ~0, // invalid fib index
6146                                     1,
6147                                     NULL,
6148                                     FIB_ROUTE_PATH_FLAG_NONE);
6149     fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6150
6151     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6152              "local interface route present");
6153
6154     fib_prefix_t local1_pfx = {
6155         .fp_len = 24,
6156         .fp_proto = FIB_PROTOCOL_IP4,
6157         .fp_addr = {
6158             .ip4 = {
6159                 /* 10.10.11.10 */
6160                 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6161             },
6162         },
6163     };
6164
6165     vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6166     im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6167
6168     fib_table_entry_update_one_path(fib_index, &local1_pfx,
6169                                     FIB_SOURCE_INTERFACE,
6170                                     (FIB_ENTRY_FLAG_CONNECTED |
6171                                      FIB_ENTRY_FLAG_ATTACHED),
6172                                     DPO_PROTO_IP4,
6173                                     NULL,
6174                                     tm->hw[1]->sw_if_index,
6175                                     ~0,
6176                                     1,
6177                                     NULL,
6178                                     FIB_ROUTE_PATH_FLAG_NONE);
6179     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6180     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6181              "attached interface route present");
6182
6183     local1_pfx.fp_len = 32;
6184     fib_table_entry_update_one_path(fib_index, &local1_pfx,
6185                                     FIB_SOURCE_INTERFACE,
6186                                     (FIB_ENTRY_FLAG_CONNECTED |
6187                                      FIB_ENTRY_FLAG_LOCAL),
6188                                     DPO_PROTO_IP4,
6189                                     NULL,
6190                                     tm->hw[1]->sw_if_index,
6191                                     ~0, // invalid fib index
6192                                     1,
6193                                     NULL,
6194                                     FIB_ROUTE_PATH_FLAG_NONE);
6195     fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6196
6197     FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6198              "local interface route present");
6199
6200     ip46_address_t nh_10_10_10_1 = {
6201         .ip4 = {
6202             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6203         },
6204     };
6205     ip46_address_t nh_10_10_11_1 = {
6206         .ip4 = {
6207             .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6208         },
6209     };
6210     ip46_address_t nh_10_10_11_2 = {
6211         .ip4 = {
6212             .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6213         },
6214     };
6215
6216     ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6217                                            VNET_LINK_IP4,
6218                                            &nh_10_10_11_1,
6219                                            tm->hw[1]->sw_if_index);
6220     ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6221                                            VNET_LINK_IP4,
6222                                            &nh_10_10_11_2,
6223                                            tm->hw[1]->sw_if_index);
6224     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6225                                              VNET_LINK_MPLS,
6226                                              &nh_10_10_10_1,
6227                                              tm->hw[0]->sw_if_index);
6228     ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6229                                              VNET_LINK_MPLS,
6230                                              &nh_10_10_11_2,
6231                                              tm->hw[1]->sw_if_index);
6232     ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6233                                              VNET_LINK_MPLS,
6234                                              &nh_10_10_11_1,
6235                                              tm->hw[1]->sw_if_index);
6236
6237     /*
6238      * Add an etry with one path with a real out-going label
6239      */
6240     fib_prefix_t pfx_1_1_1_1_s_32 = {
6241         .fp_len = 32,
6242         .fp_proto = FIB_PROTOCOL_IP4,
6243         .fp_addr = {
6244             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6245         },
6246     };
6247     fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6248         .type = FT_LB_LABEL_O_ADJ,
6249         .label_o_adj = {
6250             .adj = ai_mpls_10_10_10_1,
6251             .label = 99,
6252             .eos = MPLS_EOS,
6253         },
6254     };
6255     fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6256         .type = FT_LB_LABEL_O_ADJ,
6257         .label_o_adj = {
6258             .adj = ai_mpls_10_10_10_1,
6259             .label = 99,
6260             .eos = MPLS_NON_EOS,
6261         },
6262     };
6263     mpls_label_t *l99 = NULL;
6264     vec_add1(l99, 99);
6265
6266     fib_table_entry_update_one_path(fib_index,
6267                                     &pfx_1_1_1_1_s_32,
6268                                     FIB_SOURCE_API,
6269                                     FIB_ENTRY_FLAG_NONE,
6270                                     DPO_PROTO_IP4,
6271                                     &nh_10_10_10_1,
6272                                     tm->hw[0]->sw_if_index,
6273                                     ~0, // invalid fib index
6274                                     1,
6275                                     l99,
6276                                     FIB_ROUTE_PATH_FLAG_NONE);
6277
6278     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6279     FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6280
6281     FIB_TEST(fib_test_validate_entry(fei, 
6282                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6283                                      1,
6284                                      &l99_eos_o_10_10_10_1),
6285              "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6286
6287     /*
6288      * add a path with an implicit NULL label
6289      */
6290     fib_test_lb_bucket_t a_o_10_10_11_1 = {
6291         .type = FT_LB_ADJ,
6292         .adj = {
6293             .adj = ai_v4_10_10_11_1,
6294         },
6295     };
6296     fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6297         .type = FT_LB_ADJ,
6298         .adj = {
6299             .adj = ai_mpls_10_10_11_1,
6300         },
6301     };
6302     mpls_label_t *l_imp_null = NULL;
6303     vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6304
6305     fei = fib_table_entry_path_add(fib_index,
6306                                    &pfx_1_1_1_1_s_32,
6307                                    FIB_SOURCE_API,
6308                                    FIB_ENTRY_FLAG_NONE,
6309                                    DPO_PROTO_IP4,
6310                                    &nh_10_10_11_1,
6311                                    tm->hw[1]->sw_if_index,
6312                                    ~0, // invalid fib index
6313                                    1,
6314                                    l_imp_null,
6315                                    FIB_ROUTE_PATH_FLAG_NONE);
6316
6317     FIB_TEST(fib_test_validate_entry(fei, 
6318                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6319                                      2,
6320                                      &l99_eos_o_10_10_10_1,
6321                                      &a_o_10_10_11_1),
6322              "1.1.1.1/32 LB 2 buckets via: "
6323              "label 99 over 10.10.10.1, "
6324              "adj over 10.10.11.1");
6325
6326     /*
6327      * assign the route a local label
6328      */
6329     fib_table_entry_local_label_add(fib_index,
6330                                     &pfx_1_1_1_1_s_32,
6331                                     24001);
6332
6333     fib_prefix_t pfx_24001_eos = {
6334         .fp_proto = FIB_PROTOCOL_MPLS,
6335         .fp_label = 24001,
6336         .fp_eos = MPLS_EOS,
6337     };
6338     fib_prefix_t pfx_24001_neos = {
6339         .fp_proto = FIB_PROTOCOL_MPLS,
6340         .fp_label = 24001,
6341         .fp_eos = MPLS_NON_EOS,
6342     };
6343
6344     /*
6345      * The EOS entry should link to both the paths,
6346      *  and use an ip adj for the imp-null
6347      * The NON-EOS entry should link to both the paths,
6348      *  and use an mpls adj for the imp-null
6349      */
6350     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6351                            &pfx_24001_eos);
6352     FIB_TEST(fib_test_validate_entry(fei, 
6353                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6354                                      2,
6355                                      &l99_eos_o_10_10_10_1,
6356                                      &a_o_10_10_11_1),
6357              "24001/eos LB 2 buckets via: "
6358              "label 99 over 10.10.10.1, "
6359              "adj over 10.10.11.1");
6360
6361
6362     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6363                            &pfx_24001_neos);
6364     FIB_TEST(fib_test_validate_entry(fei, 
6365                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6366                                      2,
6367                                      &l99_neos_o_10_10_10_1,
6368                                      &a_mpls_o_10_10_11_1),
6369              "24001/neos LB 1 bucket via: "
6370              "label 99 over 10.10.10.1 ",
6371              "mpls-adj via 10.10.11.1");
6372
6373     /*
6374      * add an unlabelled path, this is excluded from the neos chains,
6375      */
6376     fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6377         .type = FT_LB_ADJ,
6378         .adj = {
6379             .adj = ai_v4_10_10_11_2,
6380         },
6381     };
6382
6383     fei = fib_table_entry_path_add(fib_index,
6384                                    &pfx_1_1_1_1_s_32,
6385                                    FIB_SOURCE_API,
6386                                    FIB_ENTRY_FLAG_NONE,
6387                                    DPO_PROTO_IP4,
6388                                    &nh_10_10_11_2,
6389                                    tm->hw[1]->sw_if_index,
6390                                    ~0, // invalid fib index
6391                                    1,
6392                                    NULL,
6393                                    FIB_ROUTE_PATH_FLAG_NONE);
6394
6395     FIB_TEST(fib_test_validate_entry(fei, 
6396                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6397                                      16, // 3 choices spread over 16 buckets
6398                                      &l99_eos_o_10_10_10_1,
6399                                      &l99_eos_o_10_10_10_1,
6400                                      &l99_eos_o_10_10_10_1,
6401                                      &l99_eos_o_10_10_10_1,
6402                                      &l99_eos_o_10_10_10_1,
6403                                      &l99_eos_o_10_10_10_1,
6404                                      &a_o_10_10_11_1,
6405                                      &a_o_10_10_11_1,
6406                                      &a_o_10_10_11_1,
6407                                      &a_o_10_10_11_1,
6408                                      &a_o_10_10_11_1,
6409                                      &adj_o_10_10_11_2,
6410                                      &adj_o_10_10_11_2,
6411                                      &adj_o_10_10_11_2,
6412                                      &adj_o_10_10_11_2,
6413                                      &adj_o_10_10_11_2),
6414              "1.1.1.1/32 LB 16 buckets via: "
6415              "label 99 over 10.10.10.1, "
6416              "adj over 10.10.11.1",
6417              "adj over 10.10.11.2");
6418
6419     /*
6420      * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6421      */
6422     dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6423     fib_entry_contribute_forwarding(fei,
6424                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6425                                     &non_eos_1_1_1_1);
6426
6427     /*
6428      * n-eos has only the 2 labelled paths
6429      */
6430     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6431                            &pfx_24001_neos);
6432
6433     FIB_TEST(fib_test_validate_entry(fei,
6434                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6435                                      2,
6436                                      &l99_neos_o_10_10_10_1,
6437                                      &a_mpls_o_10_10_11_1),
6438              "24001/neos LB 2 buckets via: "
6439              "label 99 over 10.10.10.1, "
6440              "adj-mpls over 10.10.11.2");
6441
6442     /*
6443      * A labelled recursive
6444      */
6445     fib_prefix_t pfx_2_2_2_2_s_32 = {
6446         .fp_len = 32,
6447         .fp_proto = FIB_PROTOCOL_IP4,
6448         .fp_addr = {
6449             .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6450         },
6451     };
6452     fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6453         .type = FT_LB_LABEL_O_LB,
6454         .label_o_lb = {
6455             .lb = non_eos_1_1_1_1.dpoi_index,
6456             .label = 1600,
6457             .eos = MPLS_EOS,
6458         },
6459     };
6460     mpls_label_t *l1600 = NULL;
6461     vec_add1(l1600, 1600);
6462
6463     fib_table_entry_update_one_path(fib_index,
6464                                     &pfx_2_2_2_2_s_32,
6465                                     FIB_SOURCE_API,
6466                                     FIB_ENTRY_FLAG_NONE,
6467                                     DPO_PROTO_IP4,
6468                                     &pfx_1_1_1_1_s_32.fp_addr,
6469                                     ~0,
6470                                     fib_index,
6471                                     1,
6472                                     l1600,
6473                                     FIB_ROUTE_PATH_FLAG_NONE);
6474
6475     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6476     FIB_TEST(fib_test_validate_entry(fei, 
6477                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6478                                      1,
6479                                      &l1600_eos_o_1_1_1_1),
6480              "2.2.2.2.2/32 LB 1 buckets via: "
6481              "label 1600 over 1.1.1.1");
6482
6483     dpo_id_t dpo_44 = DPO_INVALID;
6484     index_t urpfi;
6485
6486     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6487     urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6488
6489     FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6490              "uRPF check for 2.2.2.2/32 on %d OK",
6491              tm->hw[0]->sw_if_index);
6492     FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6493              "uRPF check for 2.2.2.2/32 on %d OK",
6494              tm->hw[1]->sw_if_index);
6495     FIB_TEST(!fib_urpf_check(urpfi, 99),
6496              "uRPF check for 2.2.2.2/32 on 99 not-OK",
6497              99);
6498
6499     fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6500     FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6501              "Shared uRPF on IP and non-EOS chain");
6502
6503     dpo_reset(&dpo_44);
6504
6505     /*
6506      * we are holding a lock on the non-eos LB of the via-entry.
6507      * do a PIC-core failover by shutting the link of the via-entry.
6508      *
6509      * shut down the link with the valid label
6510      */
6511     vnet_sw_interface_set_flags(vnet_get_main(),
6512                                 tm->hw[0]->sw_if_index,
6513                                 0);
6514
6515     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6516     FIB_TEST(fib_test_validate_entry(fei, 
6517                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6518                                      2,
6519                                      &a_o_10_10_11_1,
6520                                      &adj_o_10_10_11_2),
6521              "1.1.1.1/32 LB 2 buckets via: "
6522              "adj over 10.10.11.1, ",
6523              "adj-v4 over 10.10.11.2");
6524
6525     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6526                            &pfx_24001_eos);
6527     FIB_TEST(fib_test_validate_entry(fei, 
6528                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6529                                      2,
6530                                      &a_o_10_10_11_1,
6531                                      &adj_o_10_10_11_2),
6532              "24001/eos LB 2 buckets via: "
6533              "adj over 10.10.11.1, ",
6534              "adj-v4 over 10.10.11.2");
6535
6536     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6537                            &pfx_24001_neos);
6538     FIB_TEST(fib_test_validate_entry(fei,
6539                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6540                                      1,
6541                                      &a_mpls_o_10_10_11_1),
6542              "24001/neos LB 1 buckets via: "
6543              "adj-mpls over 10.10.11.2");
6544
6545     /*
6546      * test that the pre-failover load-balance has been in-place
6547      * modified
6548      */
6549     dpo_id_t current = DPO_INVALID;
6550     fib_entry_contribute_forwarding(fei,
6551                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6552                                     &current);
6553
6554     FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6555                       &current),
6556              "PIC-core LB inplace modified %U %U",
6557              format_dpo_id, &non_eos_1_1_1_1, 0,
6558              format_dpo_id, &current, 0);
6559
6560     dpo_reset(&non_eos_1_1_1_1);
6561     dpo_reset(&current);
6562
6563     /*
6564      * no-shut the link with the valid label
6565      */
6566     vnet_sw_interface_set_flags(vnet_get_main(),
6567                                 tm->hw[0]->sw_if_index,
6568                                 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6569
6570     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6571     FIB_TEST(fib_test_validate_entry(fei, 
6572                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6573                                      16, // 3 choices spread over 16 buckets
6574                                      &l99_eos_o_10_10_10_1,
6575                                      &l99_eos_o_10_10_10_1,
6576                                      &l99_eos_o_10_10_10_1,
6577                                      &l99_eos_o_10_10_10_1,
6578                                      &l99_eos_o_10_10_10_1,
6579                                      &l99_eos_o_10_10_10_1,
6580                                      &a_o_10_10_11_1,
6581                                      &a_o_10_10_11_1,
6582                                      &a_o_10_10_11_1,
6583                                      &a_o_10_10_11_1,
6584                                      &a_o_10_10_11_1,
6585                                      &adj_o_10_10_11_2,
6586                                      &adj_o_10_10_11_2,
6587                                      &adj_o_10_10_11_2,
6588                                      &adj_o_10_10_11_2,
6589                                      &adj_o_10_10_11_2),
6590              "1.1.1.1/32 LB 16 buckets via: "
6591              "label 99 over 10.10.10.1, "
6592              "adj over 10.10.11.1",
6593              "adj-v4 over 10.10.11.2");
6594
6595
6596     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6597                            &pfx_24001_eos);
6598     FIB_TEST(fib_test_validate_entry(fei, 
6599                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6600                                      16, // 3 choices spread over 16 buckets
6601                                      &l99_eos_o_10_10_10_1,
6602                                      &l99_eos_o_10_10_10_1,
6603                                      &l99_eos_o_10_10_10_1,
6604                                      &l99_eos_o_10_10_10_1,
6605                                      &l99_eos_o_10_10_10_1,
6606                                      &l99_eos_o_10_10_10_1,
6607                                      &a_o_10_10_11_1,
6608                                      &a_o_10_10_11_1,
6609                                      &a_o_10_10_11_1,
6610                                      &a_o_10_10_11_1,
6611                                      &a_o_10_10_11_1,
6612                                      &adj_o_10_10_11_2,
6613                                      &adj_o_10_10_11_2,
6614                                      &adj_o_10_10_11_2,
6615                                      &adj_o_10_10_11_2,
6616                                      &adj_o_10_10_11_2),
6617              "24001/eos LB 16 buckets via: "
6618              "label 99 over 10.10.10.1, "
6619              "adj over 10.10.11.1",
6620              "adj-v4 over 10.10.11.2");
6621
6622     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6623                            &pfx_24001_neos);
6624     FIB_TEST(fib_test_validate_entry(fei, 
6625                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6626                                      2,
6627                                      &l99_neos_o_10_10_10_1,
6628                                      &a_mpls_o_10_10_11_1),
6629              "24001/neos LB 2 buckets via: "
6630              "label 99 over 10.10.10.1, "
6631              "adj-mpls over 10.10.11.2");
6632
6633     /*
6634      * remove the first path with the valid label
6635      */
6636     fib_table_entry_path_remove(fib_index,
6637                                 &pfx_1_1_1_1_s_32,
6638                                 FIB_SOURCE_API,
6639                                 DPO_PROTO_IP4,
6640                                 &nh_10_10_10_1,
6641                                 tm->hw[0]->sw_if_index,
6642                                 ~0, // invalid fib index
6643                                 1,
6644                                 FIB_ROUTE_PATH_FLAG_NONE);
6645
6646     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6647     FIB_TEST(fib_test_validate_entry(fei, 
6648                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6649                                      2,
6650                                      &a_o_10_10_11_1,
6651                                      &adj_o_10_10_11_2),
6652              "1.1.1.1/32 LB 2 buckets via: "
6653              "adj over 10.10.11.1, "
6654              "adj-v4 over 10.10.11.2");
6655
6656     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6657                            &pfx_24001_eos);
6658     FIB_TEST(fib_test_validate_entry(fei, 
6659                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6660                                      2,
6661                                      &a_o_10_10_11_1,
6662                                      &adj_o_10_10_11_2),
6663              "24001/eos LB 2 buckets via: "
6664              "adj over 10.10.11.1, "
6665              "adj-v4 over 10.10.11.2");
6666
6667     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6668                            &pfx_24001_neos);
6669
6670     FIB_TEST(fib_test_validate_entry(fei, 
6671                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6672                                      1,
6673                                      &a_mpls_o_10_10_11_1),
6674              "24001/neos LB 1 buckets via: "
6675              "adj-mpls over 10.10.11.2");
6676
6677     /*
6678      * remove the other path with a valid label
6679      */
6680     fib_test_lb_bucket_t bucket_drop = {
6681         .type = FT_LB_SPECIAL,
6682         .special = {
6683             .adj = DPO_PROTO_IP4,
6684         },
6685     };
6686     fib_test_lb_bucket_t mpls_bucket_drop = {
6687         .type = FT_LB_SPECIAL,
6688         .special = {
6689             .adj = DPO_PROTO_MPLS,
6690         },
6691     };
6692
6693     fib_table_entry_path_remove(fib_index,
6694                                 &pfx_1_1_1_1_s_32,
6695                                 FIB_SOURCE_API,
6696                                 DPO_PROTO_IP4,
6697                                 &nh_10_10_11_1,
6698                                 tm->hw[1]->sw_if_index,
6699                                 ~0, // invalid fib index
6700                                 1,
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                                      1,
6707                                      &adj_o_10_10_11_2),
6708              "1.1.1.1/32 LB 1 buckets via: "
6709              "adj over 10.10.11.2");
6710
6711     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6712                            &pfx_24001_eos);
6713     FIB_TEST(fib_test_validate_entry(fei, 
6714                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6715                                      1,
6716                                      &adj_o_10_10_11_2),
6717              "24001/eos LB 1 buckets via: "
6718              "adj over 10.10.11.2");
6719
6720     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6721                            &pfx_24001_neos);
6722     FIB_TEST(fib_test_validate_entry(fei, 
6723                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6724                                      1,
6725                                      &mpls_bucket_drop),
6726              "24001/neos LB 1 buckets via: DROP");
6727
6728     /*
6729      * add back the path with the valid label
6730      */
6731     l99 = NULL;
6732     vec_add1(l99, 99);
6733
6734     fib_table_entry_path_add(fib_index,
6735                              &pfx_1_1_1_1_s_32,
6736                              FIB_SOURCE_API,
6737                              FIB_ENTRY_FLAG_NONE,
6738                              DPO_PROTO_IP4,
6739                              &nh_10_10_10_1,
6740                              tm->hw[0]->sw_if_index,
6741                              ~0, // invalid fib index
6742                              1,
6743                              l99,
6744                              FIB_ROUTE_PATH_FLAG_NONE);
6745
6746     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6747     FIB_TEST(fib_test_validate_entry(fei,
6748                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6749                                      2,
6750                                      &l99_eos_o_10_10_10_1,
6751                                      &adj_o_10_10_11_2),
6752              "1.1.1.1/32 LB 2 buckets via: "
6753              "label 99 over 10.10.10.1, "
6754              "adj over 10.10.11.2");
6755
6756     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6757                            &pfx_24001_eos);
6758     FIB_TEST(fib_test_validate_entry(fei, 
6759                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6760                                      2,
6761                                      &l99_eos_o_10_10_10_1,
6762                                      &adj_o_10_10_11_2),
6763              "24001/eos LB 2 buckets via: "
6764              "label 99 over 10.10.10.1, "
6765              "adj over 10.10.11.2");
6766
6767     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6768                            &pfx_24001_neos);
6769     FIB_TEST(fib_test_validate_entry(fei, 
6770                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6771                                      1,
6772                                      &l99_neos_o_10_10_10_1),
6773              "24001/neos LB 1 buckets via: "
6774              "label 99 over 10.10.10.1");
6775
6776     /*
6777      * change the local label
6778      */
6779     fib_table_entry_local_label_add(fib_index,
6780                                     &pfx_1_1_1_1_s_32,
6781                                     25005);
6782
6783     fib_prefix_t pfx_25005_eos = {
6784         .fp_proto = FIB_PROTOCOL_MPLS,
6785         .fp_label = 25005,
6786         .fp_eos = MPLS_EOS,
6787     };
6788     fib_prefix_t pfx_25005_neos = {
6789         .fp_proto = FIB_PROTOCOL_MPLS,
6790         .fp_label = 25005,
6791         .fp_eos = MPLS_NON_EOS,
6792     };
6793
6794     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6795               fib_table_lookup(fib_index, &pfx_24001_eos)),
6796              "24001/eos removed after label change");
6797     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6798               fib_table_lookup(fib_index, &pfx_24001_neos)),
6799              "24001/eos removed after label change");
6800
6801     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6802                            &pfx_25005_eos);
6803     FIB_TEST(fib_test_validate_entry(fei,
6804                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6805                                      2,
6806                                      &l99_eos_o_10_10_10_1,
6807                                      &adj_o_10_10_11_2),
6808              "25005/eos LB 2 buckets via: "
6809              "label 99 over 10.10.10.1, "
6810              "adj over 10.10.11.2");
6811
6812     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6813                            &pfx_25005_neos);
6814     FIB_TEST(fib_test_validate_entry(fei,
6815                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6816                                      1,
6817                                      &l99_neos_o_10_10_10_1),
6818              "25005/neos LB 1 buckets via: "
6819              "label 99 over 10.10.10.1");
6820
6821     /*
6822      * remove the local label.
6823      * the check that the MPLS entries are gone is done by the fact the
6824      * MPLS table is no longer present.
6825      */
6826     fib_table_entry_local_label_remove(fib_index,
6827                                        &pfx_1_1_1_1_s_32,
6828                                        25005);
6829
6830     fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6831     FIB_TEST(fib_test_validate_entry(fei, 
6832                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6833                                      2,
6834                                      &l99_eos_o_10_10_10_1,
6835                                      &adj_o_10_10_11_2),
6836              "24001/eos LB 2 buckets via: "
6837              "label 99 over 10.10.10.1, "
6838              "adj over 10.10.11.2");
6839
6840     FIB_TEST((FIB_NODE_INDEX_INVALID ==
6841               mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6842              "No more MPLS FIB entries => table removed");
6843
6844     /*
6845      * add another via-entry for the recursive
6846      */
6847     fib_prefix_t pfx_1_1_1_2_s_32 = {
6848         .fp_len = 32,
6849         .fp_proto = FIB_PROTOCOL_IP4,
6850         .fp_addr = {
6851             .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6852         },
6853     };
6854     fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6855         .type = FT_LB_LABEL_O_ADJ,
6856         .label_o_adj = {
6857             .adj = ai_mpls_10_10_10_1,
6858             .label = 101,
6859             .eos = MPLS_EOS,
6860         },
6861     };
6862     mpls_label_t *l101 = NULL;
6863     vec_add1(l101, 101);
6864
6865     fei = fib_table_entry_update_one_path(fib_index,
6866                                           &pfx_1_1_1_2_s_32,
6867                                           FIB_SOURCE_API,
6868                                           FIB_ENTRY_FLAG_NONE,
6869                                           DPO_PROTO_IP4,
6870                                           &nh_10_10_10_1,
6871                                           tm->hw[0]->sw_if_index,
6872                                           ~0, // invalid fib index
6873                                           1,
6874                                           l101,
6875                                           FIB_ROUTE_PATH_FLAG_NONE);
6876
6877     FIB_TEST(fib_test_validate_entry(fei,
6878                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6879                                      1,
6880                                      &l101_eos_o_10_10_10_1),
6881              "1.1.1.2/32 LB 1 buckets via: "
6882              "label 101 over 10.10.10.1");
6883
6884     dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6885     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6886                                                      &pfx_1_1_1_1_s_32),
6887                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6888                                     &non_eos_1_1_1_1);
6889     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6890                                                      &pfx_1_1_1_2_s_32),
6891                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6892                                     &non_eos_1_1_1_2);
6893
6894     fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6895         .type = FT_LB_LABEL_O_LB,
6896         .label_o_lb = {
6897             .lb = non_eos_1_1_1_2.dpoi_index,
6898             .label = 1601,
6899             .eos = MPLS_EOS,
6900         },
6901     };
6902     mpls_label_t *l1601 = NULL;
6903     vec_add1(l1601, 1601);
6904
6905     l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6906
6907     fei = fib_table_entry_path_add(fib_index,
6908                                    &pfx_2_2_2_2_s_32,
6909                                    FIB_SOURCE_API,
6910                                    FIB_ENTRY_FLAG_NONE,
6911                                    DPO_PROTO_IP4,
6912                                    &pfx_1_1_1_2_s_32.fp_addr,
6913                                    ~0,
6914                                    fib_index,
6915                                    1,
6916                                    l1601,
6917                                    FIB_ROUTE_PATH_FLAG_NONE);
6918
6919     FIB_TEST(fib_test_validate_entry(fei, 
6920                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6921                                      2,
6922                                      &l1600_eos_o_1_1_1_1,
6923                                      &l1601_eos_o_1_1_1_2),
6924              "2.2.2.2/32 LB 2 buckets via: "
6925              "label 1600 via 1.1,1.1, "
6926              "label 16001 via 1.1.1.2");
6927
6928     /*
6929      * update the via-entry so it no longer has an imp-null path.
6930      * the LB for the recursive can use an imp-null
6931      */
6932     l_imp_null = NULL;
6933     vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6934
6935     fei = fib_table_entry_update_one_path(fib_index,
6936                                           &pfx_1_1_1_2_s_32,
6937                                           FIB_SOURCE_API,
6938                                           FIB_ENTRY_FLAG_NONE,
6939                                           DPO_PROTO_IP4,
6940                                           &nh_10_10_11_1,
6941                                           tm->hw[1]->sw_if_index,
6942                                           ~0, // invalid fib index
6943                                           1,
6944                                           l_imp_null,
6945                                           FIB_ROUTE_PATH_FLAG_NONE);
6946
6947     FIB_TEST(fib_test_validate_entry(fei,
6948                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6949                                      1,
6950                                      &a_o_10_10_11_1),
6951              "1.1.1.2/32 LB 1 buckets via: "
6952              "adj 10.10.11.1");
6953  
6954     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6955     FIB_TEST(fib_test_validate_entry(fei, 
6956                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6957                                      2,
6958                                      &l1600_eos_o_1_1_1_1,
6959                                      &l1601_eos_o_1_1_1_2),
6960              "2.2.2.2/32 LB 2 buckets via: "
6961              "label 1600 via 1.1,1.1, "
6962              "label 16001 via 1.1.1.2");
6963
6964     /*
6965      * update the via-entry so it no longer has labelled paths.
6966      * the LB for the recursive should exclue this via form its LB
6967      */
6968     fei = fib_table_entry_update_one_path(fib_index,
6969                                           &pfx_1_1_1_2_s_32,
6970                                           FIB_SOURCE_API,
6971                                           FIB_ENTRY_FLAG_NONE,
6972                                           DPO_PROTO_IP4,
6973                                           &nh_10_10_11_1,
6974                                           tm->hw[1]->sw_if_index,
6975                                           ~0, // invalid fib index
6976                                           1,
6977                                           NULL,
6978                                           FIB_ROUTE_PATH_FLAG_NONE);
6979
6980     FIB_TEST(fib_test_validate_entry(fei,
6981                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6982                                      1,
6983                                      &a_o_10_10_11_1),
6984              "1.1.1.2/32 LB 1 buckets via: "
6985              "adj 10.10.11.1");
6986  
6987     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6988     FIB_TEST(fib_test_validate_entry(fei, 
6989                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6990                                      1,
6991                                      &l1600_eos_o_1_1_1_1),
6992              "2.2.2.2/32 LB 1 buckets via: "
6993              "label 1600 via 1.1,1.1");
6994
6995     dpo_reset(&non_eos_1_1_1_1);
6996     dpo_reset(&non_eos_1_1_1_2);
6997
6998     /*
6999      * Add a recursive with no out-labels. We expect to use the IP of the via
7000      */
7001     fib_prefix_t pfx_2_2_2_3_s_32 = {
7002         .fp_len = 32,
7003         .fp_proto = FIB_PROTOCOL_IP4,
7004         .fp_addr = {
7005             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7006         },
7007     };
7008     dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7009
7010     fib_table_entry_update_one_path(fib_index,
7011                                     &pfx_2_2_2_3_s_32,
7012                                     FIB_SOURCE_API,
7013                                     FIB_ENTRY_FLAG_NONE,
7014                                     DPO_PROTO_IP4,
7015                                     &pfx_1_1_1_1_s_32.fp_addr,
7016                                     ~0,
7017                                     fib_index,
7018                                     1,
7019                                     NULL,
7020                                     FIB_ROUTE_PATH_FLAG_NONE);
7021
7022     fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7023                                                      &pfx_1_1_1_1_s_32),
7024                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7025                                     &ip_1_1_1_1);
7026
7027     fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7028         .type = FT_LB_O_LB,
7029         .lb = {
7030             .lb = ip_1_1_1_1.dpoi_index,
7031         },
7032     };
7033
7034     fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7035     FIB_TEST(fib_test_validate_entry(fei, 
7036                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7037                                      1,
7038                                      &ip_o_1_1_1_1),
7039              "2.2.2.2.3/32 LB 1 buckets via: "
7040              "ip 1.1.1.1");
7041
7042     /*
7043      * Add a recursive with an imp-null out-label. 
7044      * We expect to use the IP of the via
7045      */
7046     fib_prefix_t pfx_2_2_2_4_s_32 = {
7047         .fp_len = 32,
7048         .fp_proto = FIB_PROTOCOL_IP4,
7049         .fp_addr = {
7050             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7051         },
7052     };
7053
7054     fib_table_entry_update_one_path(fib_index,
7055                                     &pfx_2_2_2_4_s_32,
7056                                     FIB_SOURCE_API,
7057                                     FIB_ENTRY_FLAG_NONE,
7058                                     DPO_PROTO_IP4,
7059                                     &pfx_1_1_1_1_s_32.fp_addr,
7060                                     ~0,
7061                                     fib_index,
7062                                     1,
7063                                     NULL,
7064                                     FIB_ROUTE_PATH_FLAG_NONE);
7065
7066     fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7067     FIB_TEST(fib_test_validate_entry(fei, 
7068                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7069                                      1,
7070                                      &ip_o_1_1_1_1),
7071              "2.2.2.2.4/32 LB 1 buckets via: "
7072              "ip 1.1.1.1");
7073
7074     dpo_reset(&ip_1_1_1_1);
7075
7076     /*
7077      * Create an entry with a deep label stack
7078      */
7079     fib_prefix_t pfx_2_2_5_5_s_32 = {
7080         .fp_len = 32,
7081         .fp_proto = FIB_PROTOCOL_IP4,
7082         .fp_addr = {
7083             .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7084         },
7085     };
7086     fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7087         .type = FT_LB_LABEL_STACK_O_ADJ,
7088         .label_stack_o_adj = {
7089             .adj = ai_mpls_10_10_11_1,
7090             .label_stack_size = 8,
7091             .label_stack = {
7092                 200, 201, 202, 203, 204, 205, 206, 207
7093             },
7094             .eos = MPLS_EOS,
7095         },
7096     };
7097     mpls_label_t *label_stack = NULL;
7098     vec_validate(label_stack, 7);
7099     for (ii = 0; ii < 8; ii++)
7100     {
7101         label_stack[ii] = ii + 200;
7102     }
7103
7104     fei = fib_table_entry_update_one_path(fib_index,
7105                                           &pfx_2_2_5_5_s_32,
7106                                           FIB_SOURCE_API,
7107                                           FIB_ENTRY_FLAG_NONE,
7108                                           DPO_PROTO_IP4,
7109                                           &nh_10_10_11_1,
7110                                           tm->hw[1]->sw_if_index,
7111                                           ~0, // invalid fib index
7112                                           1,
7113                                           label_stack,
7114                                           FIB_ROUTE_PATH_FLAG_NONE);
7115
7116     FIB_TEST(fib_test_validate_entry(fei,
7117                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7118                                      1,
7119                                      &ls_eos_o_10_10_10_1),
7120              "2.2.5.5/32 LB 1 buckets via: "
7121              "adj 10.10.11.1");
7122     fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7123
7124     /*
7125      * cleanup
7126      */
7127     fib_table_entry_delete(fib_index,
7128                            &pfx_1_1_1_2_s_32,
7129                            FIB_SOURCE_API);
7130
7131     fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7132     FIB_TEST(fib_test_validate_entry(fei, 
7133                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7134                                      1,
7135                                      &l1600_eos_o_1_1_1_1),
7136              "2.2.2.2/32 LB 1 buckets via: "
7137              "label 1600 via 1.1,1.1");
7138
7139     fib_table_entry_delete(fib_index,
7140                            &pfx_1_1_1_1_s_32,
7141                            FIB_SOURCE_API);
7142
7143     FIB_TEST(fib_test_validate_entry(fei, 
7144                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7145                                      1,
7146                                      &bucket_drop),
7147              "2.2.2.2/32 LB 1 buckets via: DROP");
7148
7149     fib_table_entry_delete(fib_index,
7150                            &pfx_2_2_2_2_s_32,
7151                            FIB_SOURCE_API);
7152     fib_table_entry_delete(fib_index,
7153                            &pfx_2_2_2_3_s_32,
7154                            FIB_SOURCE_API);
7155     fib_table_entry_delete(fib_index,
7156                            &pfx_2_2_2_4_s_32,
7157                            FIB_SOURCE_API);
7158
7159     adj_unlock(ai_mpls_10_10_10_1);
7160     adj_unlock(ai_mpls_10_10_11_2);
7161     adj_unlock(ai_v4_10_10_11_1);
7162     adj_unlock(ai_v4_10_10_11_2);
7163     adj_unlock(ai_mpls_10_10_11_1);
7164
7165     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7166              adj_nbr_db_size());
7167
7168     local0_pfx.fp_len = 32;
7169     fib_table_entry_delete(fib_index,
7170                            &local0_pfx,
7171                            FIB_SOURCE_INTERFACE);
7172     local0_pfx.fp_len = 24;
7173     fib_table_entry_delete(fib_index,
7174                            &local0_pfx,
7175                            FIB_SOURCE_INTERFACE);
7176     local1_pfx.fp_len = 32;
7177     fib_table_entry_delete(fib_index,
7178                            &local1_pfx,
7179                            FIB_SOURCE_INTERFACE);
7180     local1_pfx.fp_len = 24;
7181     fib_table_entry_delete(fib_index,
7182                            &local1_pfx,
7183                            FIB_SOURCE_INTERFACE);
7184
7185     /*
7186      * +1 for the drop LB in the MPLS tables.
7187      */
7188     FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7189              "Load-balance resources freed %d of %d",
7190              lb_count+1, pool_elts(load_balance_pool));
7191
7192     return (0);
7193 }
7194
7195 #define N_TEST_CHILDREN 4
7196 #define PARENT_INDEX 0
7197
7198 typedef struct fib_node_test_t_
7199 {
7200     fib_node_t node;
7201     u32 sibling;
7202     u32 index;
7203     fib_node_back_walk_ctx_t *ctxs;
7204     u32 destroyed;
7205 } fib_node_test_t;
7206
7207 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7208
7209 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7210
7211 #define FOR_EACH_TEST_CHILD(_tc)                     \
7212     for (ii = 1, (_tc) = &fib_test_nodes[1];         \
7213          ii < N_TEST_CHILDREN+1;                     \
7214          ii++, (_tc) = &fib_test_nodes[ii])
7215
7216 static fib_node_t *
7217 fib_test_child_get_node (fib_node_index_t index)
7218 {
7219     return (&fib_test_nodes[index].node);
7220 }
7221
7222 static int fib_test_walk_spawns_walks;
7223
7224 static fib_node_back_walk_rc_t
7225 fib_test_child_back_walk_notify (fib_node_t *node,
7226                                  fib_node_back_walk_ctx_t *ctx)
7227 {
7228     fib_node_test_t *tc = (fib_node_test_t*) node;
7229
7230     vec_add1(tc->ctxs, *ctx);
7231
7232     if (1 == fib_test_walk_spawns_walks)
7233         fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7234     if (2 == fib_test_walk_spawns_walks)
7235         fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7236                        FIB_WALK_PRIORITY_HIGH, ctx);
7237
7238     return (FIB_NODE_BACK_WALK_CONTINUE);
7239 }
7240
7241 static void
7242 fib_test_child_last_lock_gone (fib_node_t *node)
7243 {
7244     fib_node_test_t *tc = (fib_node_test_t *)node;
7245
7246     tc->destroyed = 1;
7247 }
7248
7249 /**
7250  * The FIB walk's graph node virtual function table
7251  */
7252 static const fib_node_vft_t fib_test_child_vft = {
7253     .fnv_get = fib_test_child_get_node,
7254     .fnv_last_lock = fib_test_child_last_lock_gone,
7255     .fnv_back_walk = fib_test_child_back_walk_notify,
7256 };
7257
7258 /*
7259  * the function (that should have been static but isn't so I can do this)
7260  * that processes the walk from the async queue,
7261  */
7262 f64 fib_walk_process_queues(vlib_main_t * vm,
7263                             const f64 quota);
7264 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7265
7266 static int
7267 fib_test_walk (void)
7268 {
7269     fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7270     fib_node_test_t *tc;
7271     vlib_main_t *vm;
7272     u32 ii;
7273
7274     vm = vlib_get_main();
7275     fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7276
7277     /*
7278      * init a fake node on which we will add children
7279      */
7280     fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7281                   FIB_NODE_TYPE_TEST);
7282
7283     FOR_EACH_TEST_CHILD(tc)
7284     {
7285         fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7286         fib_node_lock(&tc->node);
7287         tc->ctxs = NULL;
7288         tc->index = ii;
7289         tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7290                                          PARENT_INDEX,
7291                                          FIB_NODE_TYPE_TEST, ii);
7292     }
7293
7294     /*
7295      * enqueue a walk across the parents children.
7296      */
7297     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7298
7299     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7300                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7301     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7302              "Parent has %d children pre-walk",
7303              fib_node_list_get_size(PARENT()->fn_children));
7304
7305     /*
7306      * give the walk a large amount of time so it gets to the end
7307      */
7308     fib_walk_process_queues(vm, 1);
7309
7310     FOR_EACH_TEST_CHILD(tc)
7311     {
7312         FIB_TEST(1 == vec_len(tc->ctxs),
7313                  "%d child visitsed %d times",
7314                  ii, vec_len(tc->ctxs));
7315         vec_free(tc->ctxs);
7316     }
7317     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7318              "Queue is empty post walk");
7319     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7320              "Parent has %d children post walk",
7321              fib_node_list_get_size(PARENT()->fn_children));
7322
7323     /*
7324      * walk again. should be no increase in the number of visits, since
7325      * the walk will have terminated.
7326      */
7327     fib_walk_process_queues(vm, 1);
7328
7329     FOR_EACH_TEST_CHILD(tc)
7330     {
7331         FIB_TEST(0 == vec_len(tc->ctxs),
7332                  "%d child visitsed %d times",
7333                  ii, vec_len(tc->ctxs));
7334     }
7335
7336     /*
7337      * schedule a low and hig priority walk. expect the high to be performed
7338      * before the low.
7339      * schedule the high prio walk first so that it is further from the head
7340      * of the dependency list. that way it won't merge with the low one.
7341      */
7342     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7343     low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7344
7345     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7346                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7347     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7348                    FIB_WALK_PRIORITY_LOW, &low_ctx);
7349
7350     fib_walk_process_queues(vm, 1);
7351
7352     FOR_EACH_TEST_CHILD(tc)
7353     {
7354         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7355                  "%d child visitsed by high prio walk", ii);
7356         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
7357                  "%d child visitsed by low prio walk", ii);
7358         vec_free(tc->ctxs);
7359     }
7360     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7361              "Queue is empty post prio walk");
7362     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7363              "Parent has %d children post prio walk",
7364              fib_node_list_get_size(PARENT()->fn_children));
7365
7366     /*
7367      * schedule 2 walks of the same priority that can be megred.
7368      * expect that each child is thus visited only once.
7369      */
7370     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7371     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7372
7373     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7374                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7375     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7376                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
7377
7378     fib_walk_process_queues(vm, 1);
7379
7380     FOR_EACH_TEST_CHILD(tc)
7381     {
7382         FIB_TEST(1 == vec_len(tc->ctxs),
7383                  "%d child visitsed %d times during merge walk",
7384                  ii, vec_len(tc->ctxs));
7385         vec_free(tc->ctxs);
7386     }
7387     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7388              "Queue is empty post merge walk");
7389     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7390              "Parent has %d children post merge walk",
7391              fib_node_list_get_size(PARENT()->fn_children));
7392
7393     /*
7394      * schedule 2 walks of the same priority that cannot be megred.
7395      * expect that each child is thus visited twice and in the order
7396      * in which the walks were scheduled.
7397      */
7398     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7399     low_ctx.fnbw_reason  = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7400
7401     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7402                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7403     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7404                    FIB_WALK_PRIORITY_HIGH, &low_ctx);
7405
7406     fib_walk_process_queues(vm, 1);
7407
7408     FOR_EACH_TEST_CHILD(tc)
7409     {
7410         FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7411                  "%d child visitsed by high prio walk", ii);
7412         FIB_TEST(low_ctx.fnbw_reason  == tc->ctxs[1].fnbw_reason,
7413                  "%d child visitsed by low prio walk", ii);
7414         vec_free(tc->ctxs);
7415     }
7416     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7417              "Queue is empty post no-merge walk");
7418     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7419              "Parent has %d children post no-merge walk",
7420              fib_node_list_get_size(PARENT()->fn_children));
7421
7422     /*
7423      * schedule a walk that makes one one child progress.
7424      * we do this by giving the queue draining process zero
7425      * time quanta. it's a do..while loop, so it does something.
7426      */
7427     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7428
7429     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7430                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7431     fib_walk_process_queues(vm, 0);
7432
7433     FOR_EACH_TEST_CHILD(tc)
7434     {
7435         if (ii == N_TEST_CHILDREN)
7436         {
7437             FIB_TEST(1 == vec_len(tc->ctxs),
7438                      "%d child visitsed %d times in zero quanta walk",
7439                      ii, vec_len(tc->ctxs));
7440         }
7441         else
7442         {
7443             FIB_TEST(0 == vec_len(tc->ctxs),
7444                      "%d child visitsed %d times in 0 quanta walk",
7445                      ii, vec_len(tc->ctxs));
7446         }
7447     }
7448     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7449              "Queue is not empty post zero quanta walk");
7450     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7451              "Parent has %d children post zero qunta walk",
7452              fib_node_list_get_size(PARENT()->fn_children));
7453
7454     /*
7455      * another one step
7456      */
7457     fib_walk_process_queues(vm, 0);
7458
7459     FOR_EACH_TEST_CHILD(tc)
7460     {
7461         if (ii >= N_TEST_CHILDREN-1)
7462         {
7463             FIB_TEST(1 == vec_len(tc->ctxs),
7464                      "%d child visitsed %d times in 2nd zero quanta walk",
7465                      ii, vec_len(tc->ctxs));
7466         }
7467         else
7468         {
7469             FIB_TEST(0 == vec_len(tc->ctxs),
7470                      "%d child visitsed %d times in 2nd 0 quanta walk",
7471                      ii, vec_len(tc->ctxs));
7472         }
7473     }
7474     FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7475              "Queue is not empty post zero quanta walk");
7476     FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7477              "Parent has %d children post zero qunta walk",
7478              fib_node_list_get_size(PARENT()->fn_children));
7479
7480     /*
7481      * schedule another walk that will catch-up and merge.
7482      */
7483     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7484                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7485     fib_walk_process_queues(vm, 1);
7486
7487     FOR_EACH_TEST_CHILD(tc)
7488     {
7489         if (ii >= N_TEST_CHILDREN-1)
7490         {
7491             FIB_TEST(2 == vec_len(tc->ctxs),
7492                      "%d child visitsed %d times in 2nd zero quanta merge walk",
7493                      ii, vec_len(tc->ctxs));
7494             vec_free(tc->ctxs);
7495         }
7496         else
7497         {
7498             FIB_TEST(1 == vec_len(tc->ctxs),
7499                      "%d child visitsed %d times in 2nd 0 quanta merge walk",
7500                      ii, vec_len(tc->ctxs));
7501             vec_free(tc->ctxs);
7502         }
7503     }
7504     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7505              "Queue is not empty post 2nd zero quanta merge walk");
7506     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7507              "Parent has %d children post 2nd zero qunta merge walk",
7508              fib_node_list_get_size(PARENT()->fn_children));
7509
7510     /*
7511      * park a async walk in the middle of the list, then have an sync walk catch
7512      * it. same expectations as async catches async.
7513      */
7514     high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7515
7516     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7517                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7518
7519     fib_walk_process_queues(vm, 0);
7520     fib_walk_process_queues(vm, 0);
7521
7522     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7523
7524     FOR_EACH_TEST_CHILD(tc)
7525     {
7526         if (ii >= N_TEST_CHILDREN-1)
7527         {
7528             FIB_TEST(2 == vec_len(tc->ctxs),
7529                      "%d child visitsed %d times in sync catches async walk",
7530                      ii, vec_len(tc->ctxs));
7531             vec_free(tc->ctxs);
7532         }
7533         else
7534         {
7535             FIB_TEST(1 == vec_len(tc->ctxs),
7536                      "%d child visitsed %d times in sync catches async walk",
7537                      ii, vec_len(tc->ctxs));
7538             vec_free(tc->ctxs);
7539         }
7540     }
7541     FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7542              "Queue is not empty post 2nd zero quanta merge walk");
7543     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7544              "Parent has %d children post 2nd zero qunta merge walk",
7545              fib_node_list_get_size(PARENT()->fn_children));
7546
7547     /*
7548      * make the parent a child of one of its children, thus inducing a routing loop.
7549      */
7550     fib_test_nodes[PARENT_INDEX].sibling =
7551         fib_node_child_add(FIB_NODE_TYPE_TEST,
7552                            1, // the first child
7553                            FIB_NODE_TYPE_TEST,
7554                            PARENT_INDEX);
7555
7556     /*
7557      * execute a sync walk from the parent. each child visited spawns more sync
7558      * walks. we expect the walk to terminate.
7559      */
7560     fib_test_walk_spawns_walks = 1;
7561
7562     fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7563
7564     FOR_EACH_TEST_CHILD(tc)
7565     {
7566         /*
7567          * child 1 - which is last in the list - has the loop.
7568          * the other children a re thus visitsed first. the we meet
7569          * child 1. we go round the loop again, visting the other children.
7570          * then we meet the walk in the dep list and bail. child 1 is not visitsed
7571          * again.
7572          */
7573         if (1 == ii)
7574         {
7575             FIB_TEST(1 == vec_len(tc->ctxs),
7576                      "child %d visitsed %d times during looped sync walk",
7577                      ii, vec_len(tc->ctxs));
7578         }
7579         else
7580         {
7581             FIB_TEST(2 == vec_len(tc->ctxs),
7582                      "child %d visitsed %d times during looped sync walk",
7583                      ii, vec_len(tc->ctxs));
7584         }
7585         vec_free(tc->ctxs);
7586     }
7587     FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7588              "Parent has %d children post sync loop walk",
7589              fib_node_list_get_size(PARENT()->fn_children));
7590
7591     /*
7592      * the walk doesn't reach the max depth because the infra knows that sync
7593      * meets sync implies a loop and bails early.
7594      */
7595     FIB_TEST(high_ctx.fnbw_depth == 9,
7596              "Walk context depth %d post sync loop walk",
7597              high_ctx.fnbw_depth);
7598
7599     /*
7600      * execute an async walk of the graph loop, with each child spawns sync walks
7601      */
7602     high_ctx.fnbw_depth = 0;
7603     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7604                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7605
7606     fib_walk_process_queues(vm, 1);
7607
7608     FOR_EACH_TEST_CHILD(tc)
7609     {
7610         /*
7611          * we don't really care how many times the children are visisted, as long as
7612          * it is more than once.
7613          */
7614         FIB_TEST(1 <= vec_len(tc->ctxs),
7615                  "child %d visitsed %d times during looped aync spawns sync walk",
7616                  ii, vec_len(tc->ctxs));
7617         vec_free(tc->ctxs);
7618     }
7619
7620     /*
7621      * execute an async walk of the graph loop, with each child spawns async walks
7622      */
7623     fib_test_walk_spawns_walks = 2;
7624     high_ctx.fnbw_depth = 0;
7625     fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7626                    FIB_WALK_PRIORITY_HIGH, &high_ctx);
7627
7628     fib_walk_process_queues(vm, 1);
7629
7630     FOR_EACH_TEST_CHILD(tc)
7631     {
7632         /*
7633          * we don't really care how many times the children are visisted, as long as
7634          * it is more than once.
7635          */
7636         FIB_TEST(1 <= vec_len(tc->ctxs),
7637                  "child %d visitsed %d times during looped async spawns async walk",
7638                  ii, vec_len(tc->ctxs));
7639                 vec_free(tc->ctxs);
7640     }
7641
7642
7643     fib_node_child_remove(FIB_NODE_TYPE_TEST,
7644                           1, // the first child
7645                           fib_test_nodes[PARENT_INDEX].sibling);
7646
7647     /*
7648      * cleanup
7649      */
7650     FOR_EACH_TEST_CHILD(tc)
7651     {
7652         fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7653                               tc->sibling);
7654         fib_node_deinit(&tc->node);
7655         fib_node_unlock(&tc->node);
7656     }
7657     fib_node_deinit(PARENT());
7658
7659     /*
7660      * The parent will be destroyed when the last lock on it goes.
7661      * this test ensures all the walk objects are unlocking it.
7662      */
7663     FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7664              "Parent was destroyed");
7665
7666     return (0);
7667 }
7668
7669 /*
7670  * declaration of the otherwise static callback functions
7671  */
7672 void fib_bfd_notify (bfd_listen_event_e event,
7673                      const bfd_session_t *session);
7674 void adj_bfd_notify (bfd_listen_event_e event,
7675                      const bfd_session_t *session);
7676
7677 /**
7678  * Test BFD session interaction with FIB
7679  */
7680 static int
7681 fib_test_bfd (void)
7682 {
7683     fib_node_index_t fei;
7684     test_main_t *tm;
7685     int n_feis;
7686
7687     /* via 10.10.10.1 */
7688     ip46_address_t nh_10_10_10_1 = {
7689         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7690     };
7691     /* via 10.10.10.2 */
7692     ip46_address_t nh_10_10_10_2 = {
7693         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7694     };
7695     /* via 10.10.10.10 */
7696     ip46_address_t nh_10_10_10_10 = {
7697         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7698     };
7699     n_feis = fib_entry_pool_size();
7700
7701     tm = &test_main;
7702
7703     /*
7704      * add interface routes. we'll assume this works. it's tested elsewhere
7705      */
7706     fib_prefix_t pfx_10_10_10_10_s_24 = {
7707         .fp_len = 24,
7708         .fp_proto = FIB_PROTOCOL_IP4,
7709         .fp_addr = nh_10_10_10_10,
7710     };
7711
7712     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7713                                     FIB_SOURCE_INTERFACE,
7714                                     (FIB_ENTRY_FLAG_CONNECTED |
7715                                      FIB_ENTRY_FLAG_ATTACHED),
7716                                     DPO_PROTO_IP4,
7717                                     NULL,
7718                                     tm->hw[0]->sw_if_index,
7719                                     ~0, // invalid fib index
7720                                     1, // weight
7721                                     NULL,
7722                                     FIB_ROUTE_PATH_FLAG_NONE);
7723
7724     fib_prefix_t pfx_10_10_10_10_s_32 = {
7725         .fp_len = 32,
7726         .fp_proto = FIB_PROTOCOL_IP4,
7727         .fp_addr = nh_10_10_10_10,
7728     };
7729     fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7730                                     FIB_SOURCE_INTERFACE,
7731                                     (FIB_ENTRY_FLAG_CONNECTED |
7732                                      FIB_ENTRY_FLAG_LOCAL),
7733                                     DPO_PROTO_IP4,
7734                                     NULL,
7735                                     tm->hw[0]->sw_if_index,
7736                                     ~0, // invalid fib index
7737                                     1, // weight
7738                                     NULL,
7739                                     FIB_ROUTE_PATH_FLAG_NONE);
7740
7741     /*
7742      * A BFD session via a neighbour we do not yet know
7743      */
7744     bfd_session_t bfd_10_10_10_1 = {
7745         .udp = {
7746             .key = {
7747                 .fib_index = 0,
7748                 .peer_addr = nh_10_10_10_1,
7749             },
7750         },
7751         .hop_type = BFD_HOP_TYPE_MULTI,
7752         .local_state = BFD_STATE_init,
7753     };
7754
7755     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7756
7757     /*
7758      * A new entry will be created that forwards via the adj
7759      */
7760     adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7761                                                     VNET_LINK_IP4,
7762                                                     &nh_10_10_10_1,
7763                                                     tm->hw[0]->sw_if_index);
7764     fib_prefix_t pfx_10_10_10_1_s_32 = {
7765         .fp_addr = nh_10_10_10_1,
7766         .fp_len = 32,
7767         .fp_proto = FIB_PROTOCOL_IP4,
7768     };
7769     fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7770         .type = FT_LB_ADJ,
7771         .adj = {
7772             .adj = ai_10_10_10_1,
7773         },
7774     };
7775
7776     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7777     FIB_TEST(fib_test_validate_entry(fei,
7778                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7779                                      1,
7780                                      &adj_o_10_10_10_1),
7781              "BFD sourced %U via %U",
7782              format_fib_prefix, &pfx_10_10_10_1_s_32,
7783              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7784
7785     /*
7786      * Delete the BFD session. Expect the fib_entry to be removed
7787      */
7788     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7789
7790     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7791     FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7792              "BFD sourced %U removed",
7793              format_fib_prefix, &pfx_10_10_10_1_s_32);
7794
7795     /*
7796      * Add the BFD source back
7797      */
7798     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7799
7800     /*
7801      * source the entry via the ADJ fib
7802      */
7803     fei = fib_table_entry_path_add(0,
7804                                    &pfx_10_10_10_1_s_32,
7805                                    FIB_SOURCE_ADJ,
7806                                    FIB_ENTRY_FLAG_ATTACHED,
7807                                    DPO_PROTO_IP4,
7808                                    &nh_10_10_10_1,
7809                                    tm->hw[0]->sw_if_index,
7810                                    ~0, // invalid fib index
7811                                    1,
7812                                    NULL,
7813                                    FIB_ROUTE_PATH_FLAG_NONE);
7814
7815     /*
7816      * Delete the BFD session. Expect the fib_entry to remain
7817      */
7818     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7819
7820     fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7821     FIB_TEST(fib_test_validate_entry(fei,
7822                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7823                                      1,
7824                                      &adj_o_10_10_10_1),
7825              "BFD sourced %U remains via %U",
7826              format_fib_prefix, &pfx_10_10_10_1_s_32,
7827              format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7828
7829     /*
7830      * Add the BFD source back
7831      */
7832     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7833
7834     /*
7835      * Create another ADJ FIB
7836      */
7837     fib_prefix_t pfx_10_10_10_2_s_32 = {
7838         .fp_addr = nh_10_10_10_2,
7839         .fp_len = 32,
7840         .fp_proto = FIB_PROTOCOL_IP4,
7841     };
7842     fib_table_entry_path_add(0,
7843                              &pfx_10_10_10_2_s_32,
7844                              FIB_SOURCE_ADJ,
7845                              FIB_ENTRY_FLAG_ATTACHED,
7846                              DPO_PROTO_IP4,
7847                              &nh_10_10_10_2,
7848                              tm->hw[0]->sw_if_index,
7849                              ~0, // invalid fib index
7850                              1,
7851                              NULL,
7852                              FIB_ROUTE_PATH_FLAG_NONE);
7853     /*
7854      * A BFD session for the new ADJ FIB
7855      */
7856     bfd_session_t bfd_10_10_10_2 = {
7857         .udp = {
7858             .key = {
7859                 .fib_index = 0,
7860                 .peer_addr = nh_10_10_10_2,
7861             },
7862         },
7863         .hop_type = BFD_HOP_TYPE_MULTI,
7864         .local_state = BFD_STATE_init,
7865     };
7866
7867     fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7868
7869     /*
7870      * remove the adj-fib source whilst the session is present
7871      * then add it back
7872      */
7873     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7874     fib_table_entry_path_add(0,
7875                              &pfx_10_10_10_2_s_32,
7876                              FIB_SOURCE_ADJ,
7877                              FIB_ENTRY_FLAG_ATTACHED,
7878                              DPO_PROTO_IP4,
7879                              &nh_10_10_10_2,
7880                              tm->hw[0]->sw_if_index,
7881                              ~0, // invalid fib index
7882                              1,
7883                              NULL,
7884                              FIB_ROUTE_PATH_FLAG_NONE);
7885
7886     /*
7887      * Before adding a recursive via the BFD tracked ADJ-FIBs,
7888      * bring one of the sessions UP, leave the other down
7889      */
7890     bfd_10_10_10_1.local_state = BFD_STATE_up;
7891     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7892     bfd_10_10_10_2.local_state = BFD_STATE_down;
7893     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7894
7895     /*
7896      * A recursive prefix via both of the ADJ FIBs
7897      */
7898     fib_prefix_t pfx_200_0_0_0_s_24 = {
7899         .fp_proto = FIB_PROTOCOL_IP4,
7900         .fp_len = 32,
7901         .fp_addr = {
7902             .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7903         },
7904     };
7905     const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7906
7907     dpo_10_10_10_1 =
7908         fib_entry_contribute_ip_forwarding(
7909             fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7910     dpo_10_10_10_2 =
7911         fib_entry_contribute_ip_forwarding(
7912             fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7913
7914     fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7915         .type = FT_LB_O_LB,
7916         .lb = {
7917             .lb = dpo_10_10_10_1->dpoi_index,
7918         },
7919     };
7920     fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7921         .type = FT_LB_O_LB,
7922         .lb = {
7923             .lb = dpo_10_10_10_2->dpoi_index,
7924         },
7925     };
7926
7927     /*
7928      * A prefix via the adj-fib that is BFD down => DROP
7929      */
7930     fei = fib_table_entry_path_add(0,
7931                                    &pfx_200_0_0_0_s_24,
7932                                    FIB_SOURCE_API,
7933                                    FIB_ENTRY_FLAG_NONE,
7934                                    DPO_PROTO_IP4,
7935                                    &nh_10_10_10_2,
7936                                    ~0, // recursive
7937                                    0, // default fib index
7938                                    1,
7939                                    NULL,
7940                                    FIB_ROUTE_PATH_FLAG_NONE);
7941     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7942              "%U resolves via drop",
7943              format_fib_prefix, &pfx_200_0_0_0_s_24);
7944
7945     /*
7946      * add a path via the UP BFD adj-fib.
7947      *  we expect that the DOWN BFD ADJ FIB is not used.
7948      */
7949     fei = fib_table_entry_path_add(0,
7950                                    &pfx_200_0_0_0_s_24,
7951                                    FIB_SOURCE_API,
7952                                    FIB_ENTRY_FLAG_NONE,
7953                                    DPO_PROTO_IP4,
7954                                    &nh_10_10_10_1,
7955                                    ~0, // recursive
7956                                    0, // default fib index
7957                                    1,
7958                                    NULL,
7959                                    FIB_ROUTE_PATH_FLAG_NONE);
7960
7961     FIB_TEST(fib_test_validate_entry(fei,
7962                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7963                                      1,
7964                                      &lb_o_10_10_10_1),
7965              "Recursive %U only UP BFD adj-fibs",
7966              format_fib_prefix, &pfx_200_0_0_0_s_24);
7967
7968     /*
7969      * Send a BFD state change to UP - both sessions are now up
7970      *  the recursive prefix should LB over both
7971      */
7972     bfd_10_10_10_2.local_state = BFD_STATE_up;
7973     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7974
7975
7976     FIB_TEST(fib_test_validate_entry(fei,
7977                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7978                                      2,
7979                                      &lb_o_10_10_10_1,
7980                                      &lb_o_10_10_10_2),
7981              "Recursive %U via both UP BFD adj-fibs",
7982              format_fib_prefix, &pfx_200_0_0_0_s_24);
7983
7984     /*
7985      * Send a BFD state change to DOWN
7986      *  the recursive prefix should exclude the down
7987      */
7988     bfd_10_10_10_2.local_state = BFD_STATE_down;
7989     fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7990
7991
7992     FIB_TEST(fib_test_validate_entry(fei,
7993                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7994                                      1,
7995                                      &lb_o_10_10_10_1),
7996              "Recursive %U via only UP",
7997              format_fib_prefix, &pfx_200_0_0_0_s_24);
7998
7999     /*
8000      * Delete the BFD session while it is in the DOWN state.
8001      *  FIB should consider the entry's state as back up
8002      */
8003     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8004
8005     FIB_TEST(fib_test_validate_entry(fei,
8006                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8007                                      2,
8008                                      &lb_o_10_10_10_1,
8009                                      &lb_o_10_10_10_2),
8010              "Recursive %U via both UP BFD adj-fibs post down session delete",
8011              format_fib_prefix, &pfx_200_0_0_0_s_24);
8012
8013     /*
8014      * Delete the BFD other session while it is in the UP state.
8015      */
8016     fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8017
8018     FIB_TEST(fib_test_validate_entry(fei,
8019                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8020                                      2,
8021                                      &lb_o_10_10_10_1,
8022                                      &lb_o_10_10_10_2),
8023              "Recursive %U via both UP BFD adj-fibs post up session delete",
8024              format_fib_prefix, &pfx_200_0_0_0_s_24);
8025
8026     /*
8027      * cleaup
8028      */
8029     fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8030     fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8031     fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8032
8033     fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8034     fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8035
8036     adj_unlock(ai_10_10_10_1);
8037      /*
8038      * test no-one left behind
8039      */
8040     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8041     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8042
8043     /*
8044      * Single-hop BFD tests
8045      */
8046     bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8047     bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8048
8049     adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8050
8051     ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8052                                         VNET_LINK_IP4,
8053                                         &nh_10_10_10_1,
8054                                         tm->hw[0]->sw_if_index);
8055     /*
8056      * whilst the BFD session is not signalled, the adj is up
8057      */
8058     FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
8059
8060     /*
8061      * bring the BFD session up
8062      */
8063     bfd_10_10_10_1.local_state = BFD_STATE_up;
8064     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8065     FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8066
8067     /*
8068      * bring the BFD session down
8069      */
8070     bfd_10_10_10_1.local_state = BFD_STATE_down;
8071     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8072     FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8073
8074
8075     /*
8076      * add an attached next hop FIB entry via the down adj
8077      */
8078     fib_prefix_t pfx_5_5_5_5_s_32 = {
8079         .fp_addr = {
8080             .ip4 = {
8081                 .as_u32 = clib_host_to_net_u32(0x05050505),
8082             },
8083         },
8084         .fp_len = 32,
8085         .fp_proto = FIB_PROTOCOL_IP4,
8086     };
8087
8088     fei = fib_table_entry_path_add(0,
8089                                    &pfx_5_5_5_5_s_32,
8090                                    FIB_SOURCE_CLI,
8091                                    FIB_ENTRY_FLAG_NONE,
8092                                    DPO_PROTO_IP4,
8093                                    &nh_10_10_10_1,
8094                                    tm->hw[0]->sw_if_index,
8095                                    ~0, // invalid fib index
8096                                    1,
8097                                    NULL,
8098                                    FIB_ROUTE_PATH_FLAG_NONE);
8099     FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8100              "%U resolves via drop",
8101              format_fib_prefix, &pfx_5_5_5_5_s_32);
8102
8103     /*
8104      * Add a path via an ADJ that is up
8105      */
8106     adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8107                                                     VNET_LINK_IP4,
8108                                                     &nh_10_10_10_2,
8109                                                     tm->hw[0]->sw_if_index);
8110
8111     fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8112         .type = FT_LB_ADJ,
8113         .adj = {
8114             .adj = ai_10_10_10_2,
8115         },
8116     };
8117     adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8118
8119     fei = fib_table_entry_path_add(0,
8120                                    &pfx_5_5_5_5_s_32,
8121                                    FIB_SOURCE_CLI,
8122                                    FIB_ENTRY_FLAG_NONE,
8123                                    DPO_PROTO_IP4,
8124                                    &nh_10_10_10_2,
8125                                    tm->hw[0]->sw_if_index,
8126                                    ~0, // invalid fib index
8127                                    1,
8128                                    NULL,
8129                                    FIB_ROUTE_PATH_FLAG_NONE);
8130
8131     FIB_TEST(fib_test_validate_entry(fei,
8132                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8133                                      1,
8134                                      &adj_o_10_10_10_2),
8135              "BFD sourced %U via %U",
8136              format_fib_prefix, &pfx_5_5_5_5_s_32,
8137              format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8138
8139     /*
8140      * Bring up the down session - should now LB
8141      */
8142     bfd_10_10_10_1.local_state = BFD_STATE_up;
8143     adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8144     FIB_TEST(fib_test_validate_entry(fei,
8145                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8146                                      2,
8147                                      &adj_o_10_10_10_1,
8148                                      &adj_o_10_10_10_2),
8149              "BFD sourced %U via noth adjs",
8150              format_fib_prefix, &pfx_5_5_5_5_s_32);
8151
8152     /*
8153      * remove the BFD session state from the adj
8154      */
8155     adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8156
8157     /*
8158      * clean-up
8159      */
8160     fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8161     adj_unlock(ai_10_10_10_1);
8162     adj_unlock(ai_10_10_10_2);
8163
8164     /*
8165      * test no-one left behind
8166      */
8167     FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8168     FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8169     return (0);
8170 }
8171
8172 static int
8173 lfib_test (void)
8174 {
8175     const mpls_label_t deag_label = 50;
8176     const u32 lfib_index = 0;
8177     const u32 fib_index = 0;
8178     dpo_id_t dpo = DPO_INVALID;
8179     const dpo_id_t *dpo1;
8180     fib_node_index_t lfe;
8181     lookup_dpo_t *lkd;
8182     test_main_t *tm;
8183     int lb_count;
8184     adj_index_t ai_mpls_10_10_10_1;
8185
8186     tm = &test_main;
8187     lb_count = pool_elts(load_balance_pool);
8188
8189     FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8190              adj_nbr_db_size());
8191
8192     /*
8193      * MPLS enable an interface so we get the MPLS table created
8194      */
8195     mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8196     mpls_sw_interface_enable_disable(&mpls_main,
8197                                      tm->hw[0]->sw_if_index,
8198                                      1, 1);
8199
8200     ip46_address_t nh_10_10_10_1 = {
8201         .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8202     };
8203     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8204                                              VNET_LINK_MPLS,
8205                                              &nh_10_10_10_1,
8206                                              tm->hw[0]->sw_if_index);
8207
8208     /*
8209      * Test the specials stack properly.
8210      */
8211     fib_prefix_t exp_null_v6_pfx = {
8212         .fp_proto = FIB_PROTOCOL_MPLS,
8213         .fp_eos = MPLS_EOS,
8214         .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8215         .fp_payload_proto = DPO_PROTO_IP6,
8216     };
8217     lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8218     FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8219              "%U/%U present",
8220              format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8221              format_mpls_eos_bit, MPLS_EOS);
8222     fib_entry_contribute_forwarding(lfe,
8223                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8224                                     &dpo);
8225     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8226     lkd = lookup_dpo_get(dpo1->dpoi_index);
8227
8228     FIB_TEST((fib_index == lkd->lkd_fib_index),
8229               "%U/%U is deag in %d %U",
8230              format_mpls_unicast_label, deag_label,
8231              format_mpls_eos_bit, MPLS_EOS,
8232              lkd->lkd_fib_index,
8233              format_dpo_id, &dpo, 0);
8234     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8235              "%U/%U is dst deag",
8236              format_mpls_unicast_label, deag_label,
8237              format_mpls_eos_bit, MPLS_EOS);
8238     FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8239              "%U/%U is lookup in interface's table",
8240              format_mpls_unicast_label, deag_label,
8241              format_mpls_eos_bit, MPLS_EOS);
8242     FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8243              "%U/%U is %U dst deag",
8244              format_mpls_unicast_label, deag_label,
8245              format_mpls_eos_bit, MPLS_EOS,
8246              format_dpo_proto, lkd->lkd_proto);
8247
8248
8249     /*
8250      * A route deag route for EOS
8251      */
8252     fib_prefix_t pfx = {
8253         .fp_proto = FIB_PROTOCOL_MPLS,
8254         .fp_eos = MPLS_EOS,
8255         .fp_label = deag_label,
8256         .fp_payload_proto = DPO_PROTO_IP4,
8257     };
8258     lfe = fib_table_entry_path_add(lfib_index,
8259                                    &pfx,
8260                                    FIB_SOURCE_CLI,
8261                                    FIB_ENTRY_FLAG_NONE,
8262                                    DPO_PROTO_IP4,
8263                                    &zero_addr,
8264                                    ~0,
8265                                    fib_index,
8266                                    1,
8267                                    NULL,
8268                                    FIB_ROUTE_PATH_FLAG_NONE);
8269
8270     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8271               "%U/%U present",
8272               format_mpls_unicast_label, deag_label,
8273               format_mpls_eos_bit, MPLS_EOS);
8274
8275     fib_entry_contribute_forwarding(lfe,
8276                                     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8277                                     &dpo);
8278     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8279     lkd = lookup_dpo_get(dpo1->dpoi_index);
8280
8281     FIB_TEST((fib_index == lkd->lkd_fib_index),
8282               "%U/%U is deag in %d %U",
8283              format_mpls_unicast_label, deag_label,
8284              format_mpls_eos_bit, MPLS_EOS,
8285              lkd->lkd_fib_index,
8286              format_dpo_id, &dpo, 0);
8287     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8288              "%U/%U is dst deag",
8289              format_mpls_unicast_label, deag_label,
8290              format_mpls_eos_bit, MPLS_EOS);
8291     FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8292              "%U/%U is %U dst deag",
8293              format_mpls_unicast_label, deag_label,
8294              format_mpls_eos_bit, MPLS_EOS,
8295              format_dpo_proto, lkd->lkd_proto);
8296
8297     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8298
8299     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8300                                                          &pfx)),
8301               "%U/%U not present",
8302               format_mpls_unicast_label, deag_label,
8303               format_mpls_eos_bit, MPLS_EOS);
8304
8305     /*
8306      * A route deag route for non-EOS
8307      */
8308     pfx.fp_eos = MPLS_NON_EOS;
8309     lfe = fib_table_entry_path_add(lfib_index,
8310                                    &pfx,
8311                                    FIB_SOURCE_CLI,
8312                                    FIB_ENTRY_FLAG_NONE,
8313                                    DPO_PROTO_IP4,
8314                                    &zero_addr,
8315                                    ~0,
8316                                    lfib_index,
8317                                    1,
8318                                    NULL,
8319                                    FIB_ROUTE_PATH_FLAG_NONE);
8320
8321     FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8322               "%U/%U present",
8323               format_mpls_unicast_label, deag_label,
8324               format_mpls_eos_bit, MPLS_NON_EOS);
8325
8326     fib_entry_contribute_forwarding(lfe,
8327                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8328                                     &dpo);
8329     dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8330     lkd = lookup_dpo_get(dpo1->dpoi_index);
8331
8332     FIB_TEST((fib_index == lkd->lkd_fib_index),
8333               "%U/%U is deag in %d %U",
8334              format_mpls_unicast_label, deag_label,
8335              format_mpls_eos_bit, MPLS_NON_EOS,
8336              lkd->lkd_fib_index,
8337              format_dpo_id, &dpo, 0);
8338     FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8339              "%U/%U is dst deag",
8340              format_mpls_unicast_label, deag_label,
8341              format_mpls_eos_bit, MPLS_NON_EOS);
8342
8343     FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8344              "%U/%U is %U dst deag",
8345              format_mpls_unicast_label, deag_label,
8346              format_mpls_eos_bit, MPLS_NON_EOS,
8347              format_dpo_proto, lkd->lkd_proto);
8348
8349     fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8350
8351     FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8352                                                          &pfx)),
8353               "%U/%U not present",
8354               format_mpls_unicast_label, deag_label,
8355               format_mpls_eos_bit, MPLS_EOS);
8356
8357     dpo_reset(&dpo);
8358
8359     /*
8360      * An MPLS x-connect
8361      */
8362     fib_prefix_t pfx_1200 = {
8363         .fp_len = 21,
8364         .fp_proto = FIB_PROTOCOL_MPLS,
8365         .fp_label = 1200,
8366         .fp_eos = MPLS_NON_EOS,
8367     };
8368     fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8369         .type = FT_LB_LABEL_STACK_O_ADJ,
8370         .label_stack_o_adj = {
8371             .adj = ai_mpls_10_10_10_1,
8372             .label_stack_size = 4,
8373             .label_stack = {
8374                 200, 300, 400, 500,
8375             },
8376             .eos = MPLS_NON_EOS,
8377         },
8378     };
8379     dpo_id_t neos_1200 = DPO_INVALID;
8380     dpo_id_t ip_1200 = DPO_INVALID;
8381     mpls_label_t *l200 = NULL;
8382     vec_add1(l200, 200);
8383     vec_add1(l200, 300);
8384     vec_add1(l200, 400);
8385     vec_add1(l200, 500);
8386
8387     lfe = fib_table_entry_update_one_path(fib_index,
8388                                           &pfx_1200,
8389                                           FIB_SOURCE_API,
8390                                           FIB_ENTRY_FLAG_NONE,
8391                                           DPO_PROTO_IP4,
8392                                           &nh_10_10_10_1,
8393                                           tm->hw[0]->sw_if_index,
8394                                           ~0, // invalid fib index
8395                                           1,
8396                                           l200,
8397                                           FIB_ROUTE_PATH_FLAG_NONE);
8398
8399     FIB_TEST(fib_test_validate_entry(lfe,
8400                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8401                                      1,
8402                                      &neos_o_10_10_10_1),
8403              "1200/0 LB 1 buckets via: "
8404              "adj 10.10.11.1");
8405
8406     /*
8407      * A recursive route via the MPLS x-connect
8408      */
8409     fib_prefix_t pfx_2_2_2_3_s_32 = {
8410         .fp_len = 32,
8411         .fp_proto = FIB_PROTOCOL_IP4,
8412         .fp_addr = {
8413             .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8414         },
8415     };
8416     fib_route_path_t *rpaths = NULL, rpath = {
8417         .frp_proto = DPO_PROTO_MPLS,
8418         .frp_local_label = 1200,
8419         .frp_eos = MPLS_NON_EOS,
8420         .frp_sw_if_index = ~0, // recurive
8421         .frp_fib_index = 0, // Default MPLS fib
8422         .frp_weight = 1,
8423         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8424         .frp_label_stack = NULL,
8425     };
8426     vec_add1(rpaths, rpath);
8427
8428     fib_table_entry_path_add2(fib_index,
8429                               &pfx_2_2_2_3_s_32,
8430                               FIB_SOURCE_API,
8431                               FIB_ENTRY_FLAG_NONE,
8432                               rpaths);
8433
8434     /*
8435      * A labelled recursive route via the MPLS x-connect
8436      */
8437     fib_prefix_t pfx_2_2_2_4_s_32 = {
8438         .fp_len = 32,
8439         .fp_proto = FIB_PROTOCOL_IP4,
8440         .fp_addr = {
8441             .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8442         },
8443     };
8444     mpls_label_t *l999 = NULL;
8445     vec_add1(l999, 999);
8446     rpaths[0].frp_label_stack = l999,
8447
8448     fib_table_entry_path_add2(fib_index,
8449                               &pfx_2_2_2_4_s_32,
8450                               FIB_SOURCE_API,
8451                               FIB_ENTRY_FLAG_NONE,
8452                               rpaths);
8453
8454     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8455                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8456                                     &ip_1200);
8457     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8458                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8459                                     &neos_1200);
8460
8461     fib_test_lb_bucket_t ip_o_1200 = {
8462         .type = FT_LB_O_LB,
8463         .lb = {
8464             .lb = ip_1200.dpoi_index,
8465         },
8466     };
8467     fib_test_lb_bucket_t mpls_o_1200 = {
8468         .type = FT_LB_LABEL_O_LB,
8469         .label_o_lb = {
8470             .lb = neos_1200.dpoi_index,
8471             .label = 999,
8472             .eos = MPLS_EOS,
8473         },
8474     };
8475
8476     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8477     FIB_TEST(fib_test_validate_entry(lfe,
8478                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8479                                      1,
8480                                      &ip_o_1200),
8481              "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8482     lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8483     FIB_TEST(fib_test_validate_entry(lfe,
8484                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8485                                      1,
8486                                      &mpls_o_1200),
8487              "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8488
8489     fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8490     fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8491     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8492
8493     dpo_reset(&neos_1200);
8494     dpo_reset(&ip_1200);
8495
8496     /*
8497      * A recursive via a label that does not exist
8498      */
8499     fib_test_lb_bucket_t bucket_drop = {
8500         .type = FT_LB_SPECIAL,
8501         .special = {
8502             .adj = DPO_PROTO_IP4,
8503         },
8504     };
8505     fib_test_lb_bucket_t mpls_bucket_drop = {
8506         .type = FT_LB_SPECIAL,
8507         .special = {
8508             .adj = DPO_PROTO_MPLS,
8509         },
8510     };
8511
8512     rpaths[0].frp_label_stack = NULL;
8513     lfe = fib_table_entry_path_add2(fib_index,
8514                                     &pfx_2_2_2_4_s_32,
8515                                     FIB_SOURCE_API,
8516                                     FIB_ENTRY_FLAG_NONE,
8517                                     rpaths);
8518
8519     fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8520                                     FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8521                                     &ip_1200);
8522     ip_o_1200.lb.lb = ip_1200.dpoi_index;
8523
8524     FIB_TEST(fib_test_validate_entry(lfe,
8525                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8526                                      1,
8527                                      &bucket_drop),
8528              "2.2.2.2.4/32 LB 1 buckets via: drop");
8529     lfe = fib_table_lookup(fib_index, &pfx_1200);
8530     FIB_TEST(fib_test_validate_entry(lfe,
8531                                      FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8532                                      1,
8533                                      &bucket_drop),
8534              "1200/neos LB 1 buckets via: ip4-DROP");
8535     FIB_TEST(fib_test_validate_entry(lfe,
8536                                      FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8537                                      1,
8538                                      &mpls_bucket_drop),
8539              "1200/neos LB 1 buckets via: mpls-DROP");
8540
8541     fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8542
8543     dpo_reset(&ip_1200);
8544
8545     /*
8546      * An rx-interface route.
8547      *  like the tail of an mcast LSP
8548      */
8549     dpo_id_t idpo = DPO_INVALID;
8550
8551     interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8552                               tm->hw[0]->sw_if_index,
8553                               &idpo);
8554
8555     fib_prefix_t pfx_2500 = {
8556         .fp_len = 21,
8557         .fp_proto = FIB_PROTOCOL_MPLS,
8558         .fp_label = 2500,
8559         .fp_eos = MPLS_EOS,
8560         .fp_payload_proto = DPO_PROTO_IP4,
8561     };
8562     fib_test_lb_bucket_t rx_intf_0 = {
8563         .type = FT_LB_INTF,
8564         .adj = {
8565             .adj = idpo.dpoi_index,
8566         },
8567     };
8568
8569     lfe = fib_table_entry_update_one_path(fib_index,
8570                                           &pfx_2500,
8571                                           FIB_SOURCE_API,
8572                                           FIB_ENTRY_FLAG_NONE,
8573                                           DPO_PROTO_IP4,
8574                                           NULL,
8575                                           tm->hw[0]->sw_if_index,
8576                                           ~0, // invalid fib index
8577                                           0,
8578                                           NULL,
8579                                           FIB_ROUTE_PATH_INTF_RX);
8580     FIB_TEST(fib_test_validate_entry(lfe,
8581                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8582                                      1,
8583                                      &rx_intf_0),
8584              "2500 rx-interface 0");
8585     fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8586
8587     /*
8588      * An MPLS mulicast entry
8589      */
8590     fib_prefix_t pfx_3500 = {
8591         .fp_len = 21,
8592         .fp_proto = FIB_PROTOCOL_MPLS,
8593         .fp_label = 3500,
8594         .fp_eos = MPLS_EOS,
8595         .fp_payload_proto = DPO_PROTO_IP4,
8596     };
8597     fib_test_rep_bucket_t mc_0 = {
8598         .type = FT_REP_LABEL_O_ADJ,
8599         .label_o_adj = {
8600             .adj = ai_mpls_10_10_10_1,
8601             .label = 3300,
8602             .eos = MPLS_EOS,
8603         },
8604     };
8605     fib_test_rep_bucket_t mc_intf_0 = {
8606         .type = FT_REP_INTF,
8607         .adj = {
8608             .adj = idpo.dpoi_index,
8609         },
8610     };
8611     mpls_label_t *l3300 = NULL;
8612     vec_add1(l3300, 3300);
8613
8614     lfe = fib_table_entry_update_one_path(lfib_index,
8615                                           &pfx_3500,
8616                                           FIB_SOURCE_API,
8617                                           FIB_ENTRY_FLAG_MULTICAST,
8618                                           DPO_PROTO_IP4,
8619                                           &nh_10_10_10_1,
8620                                           tm->hw[0]->sw_if_index,
8621                                           ~0, // invalid fib index
8622                                           1,
8623                                           l3300,
8624                                           FIB_ROUTE_PATH_FLAG_NONE);
8625     FIB_TEST(fib_test_validate_entry(lfe,
8626                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8627                                      1,
8628                                      &mc_0),
8629              "3500 via replicate over 10.10.10.1");
8630
8631     /*
8632      * MPLS Bud-node. Add a replication via an interface-receieve path
8633      */
8634     lfe = fib_table_entry_path_add(lfib_index,
8635                                    &pfx_3500,
8636                                    FIB_SOURCE_API,
8637                                    FIB_ENTRY_FLAG_MULTICAST,
8638                                    DPO_PROTO_IP4,
8639                                    NULL,
8640                                    tm->hw[0]->sw_if_index,
8641                                    ~0, // invalid fib index
8642                                    0,
8643                                    NULL,
8644                                    FIB_ROUTE_PATH_INTF_RX);
8645     FIB_TEST(fib_test_validate_entry(lfe,
8646                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8647                                      2,
8648                                      &mc_0,
8649                                      &mc_intf_0),
8650              "3500 via replicate over 10.10.10.1 and interface-rx");
8651
8652     /*
8653      * Add a replication via an interface-free for-us path
8654      */
8655     fib_test_rep_bucket_t mc_disp = {
8656         .type = FT_REP_DISP_MFIB_LOOKUP,
8657         .adj = {
8658             .adj = idpo.dpoi_index,
8659         },
8660     };
8661     lfe = fib_table_entry_path_add(lfib_index,
8662                                    &pfx_3500,
8663                                    FIB_SOURCE_API,
8664                                    FIB_ENTRY_FLAG_MULTICAST,
8665                                    DPO_PROTO_IP4,
8666                                    NULL,
8667                                    5, // rpf-id
8668                                    0, // default table
8669                                    0,
8670                                    NULL,
8671                                    FIB_ROUTE_PATH_RPF_ID);
8672     FIB_TEST(fib_test_validate_entry(lfe,
8673                                      FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8674                                      3,
8675                                      &mc_0,
8676                                      &mc_disp,
8677                                      &mc_intf_0),
8678              "3500 via replicate over 10.10.10.1 and interface-rx");
8679
8680
8681     
8682     fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8683     dpo_reset(&idpo);
8684
8685     /*
8686      * cleanup
8687      */
8688     mpls_sw_interface_enable_disable(&mpls_main,
8689                                      tm->hw[0]->sw_if_index,
8690                                      0, 1);
8691     mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
8692
8693     FIB_TEST(lb_count == pool_elts(load_balance_pool),
8694              "Load-balance resources freed %d of %d",
8695              lb_count, pool_elts(load_balance_pool));
8696     FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
8697              "interface_rx_dpo resources freed %d of %d",
8698              0, pool_elts(interface_rx_dpo_pool));
8699
8700     return (0);
8701 }
8702
8703 static clib_error_t *
8704 fib_test (vlib_main_t * vm, 
8705           unformat_input_t * input,
8706           vlib_cli_command_t * cmd_arg)
8707 {
8708     int res;
8709
8710     res = 0;
8711     fib_test_mk_intf(4);
8712
8713     if (unformat (input, "debug"))
8714     {
8715         fib_test_do_debug = 1;
8716     }
8717
8718     if (unformat (input, "ip"))
8719     {
8720         res += fib_test_v4();
8721         res += fib_test_v6();
8722     }
8723     else if (unformat (input, "label"))
8724     {
8725         res += fib_test_label();
8726     }
8727     else if (unformat (input, "ae"))
8728     {
8729         res += fib_test_ae();
8730     }
8731     else if (unformat (input, "pref"))
8732     {
8733         res += fib_test_pref();
8734     }
8735     else if (unformat (input, "lfib"))
8736     {
8737         res += lfib_test();
8738     }
8739     else if (unformat (input, "walk"))
8740     {
8741         res += fib_test_walk();
8742     }
8743     else if (unformat (input, "bfd"))
8744     {
8745         res += fib_test_bfd();
8746     }
8747     else
8748     {
8749         res += fib_test_v4();
8750         res += fib_test_v6();
8751         res += fib_test_ae();
8752         res += fib_test_bfd();
8753         res += fib_test_pref();
8754         res += fib_test_label();
8755         res += lfib_test();
8756
8757         /*
8758          * fib-walk process must be disabled in order for the walk tests to work
8759          */
8760         fib_walk_process_disable();
8761         res += fib_test_walk();
8762         fib_walk_process_enable();
8763     }
8764
8765     if (res)
8766     {
8767         return clib_error_return(0, "FIB Unit Test Failed");
8768     }
8769     else
8770     {
8771         return (NULL);
8772     }
8773 }
8774
8775 VLIB_CLI_COMMAND (test_fib_command, static) = {
8776     .path = "test fib",
8777     .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8778     .function = fib_test,
8779 };
8780
8781 clib_error_t *
8782 fib_test_init (vlib_main_t *vm)
8783 {
8784     return 0;
8785 }
8786
8787 VLIB_INIT_FUNCTION (fib_test_init);