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