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