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