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