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