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