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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
27 #include <vnet/mpls/mpls.h>
29 #include <vnet/fib/fib_path_list.h>
30 #include <vnet/fib/fib_walk.h>
31 #include <vnet/fib/fib_node_list.h>
33 #define FIB_TEST_I(_cond, _comment, _args...) \
35 int _evald = (_cond); \
37 fformat(stderr, "FAIL:%d: " _comment "\n", \
40 fformat(stderr, "PASS:%d: " _comment "\n", \
45 #define FIB_TEST(_cond, _comment, _args...) \
47 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
49 ASSERT(!("FAIL: " _comment)); \
54 * A 'i'm not fussed is this is not efficient' store of test data
56 typedef struct test_main_t_ {
60 u32 hw_if_indicies[4];
64 vnet_hw_interface_t * hw[4];
67 static test_main_t test_main;
69 /* fake ethernet device class, distinct from "fake-ethX" */
70 static u8 * format_test_interface_name (u8 * s, va_list * args)
72 u32 dev_instance = va_arg (*args, u32);
73 return format (s, "test-eth%d", dev_instance);
76 static uword dummy_interface_tx (vlib_main_t * vm,
77 vlib_node_runtime_t * node,
80 clib_warning ("you shouldn't be here, leaking buffers...");
81 return frame->n_vectors;
84 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
85 .name = "Test interface",
86 .format_device_name = format_test_interface_name,
87 .tx_function = dummy_interface_tx,
90 static u8 *hw_address;
93 fib_test_mk_intf (u32 ninterfaces)
95 clib_error_t * error = NULL;
96 test_main_t *tm = &test_main;
100 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
105 vec_add1(hw_address, byte);
108 for (i = 0; i < ninterfaces; i++)
112 error = ethernet_register_interface(vnet_get_main(),
113 ethernet_hw_interface_class.index,
116 &tm->hw_if_indicies[i],
117 /* flag change */ 0);
119 FIB_TEST((NULL == error), "ADD interface %d", i);
121 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
122 tm->hw_if_indicies[i]);
123 vec_validate (ip4_main.fib_index_by_sw_if_index, tm->hw[i]->sw_if_index);
124 vec_validate (ip6_main.fib_index_by_sw_if_index, tm->hw[i]->sw_if_index);
125 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
126 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
127 error = vnet_sw_interface_set_flags(vnet_get_main(),
128 tm->hw[i]->sw_if_index,
129 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
130 FIB_TEST((NULL == error), "UP interface %d", i);
133 * re-eval after the inevitable realloc
135 for (i = 0; i < ninterfaces; i++)
137 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
138 tm->hw_if_indicies[i]);
142 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix) \
144 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
145 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
146 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
147 fib_table_lookup(fib_index, (_via_prefix))); \
148 FIB_TEST(!dpo_cmp(_via_dpo, \
149 load_balance_get_bucket(_rec_dpo->dpoi_index, 0)), \
150 "%U is recursive via %U", \
151 format_fib_prefix, (_rec_prefix), \
152 format_fib_prefix, _via_prefix); \
155 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
157 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
158 fib_table_lookup_exact_match(fib_index, (_prefix))); \
159 const dpo_id_t *_dpo1 = \
160 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
161 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
162 format_dpo_type, _dpo1->dpoi_type); \
163 FIB_TEST((_ai == _dpo1->dpoi_index), \
164 "%U bucket %d resolves via %U", \
165 format_fib_prefix, (_prefix), \
167 format_dpo_id, _dpo1, 0); \
174 * In the default table check for the presence and correct forwarding
175 * of the special entries
177 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
178 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
179 const ip_adjacency_t *adj;
180 const load_balance_t *lb;
186 ip46_address_t nh_10_10_10_1 = {
187 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
190 ip46_address_t nh_10_10_10_2 = {
191 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
196 /* Find or create FIB table 11 */
197 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
199 for (ii = 0; ii < 4; ii++)
201 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
204 fib_prefix_t pfx_0_0_0_0_s_0 = {
206 .fp_proto = FIB_PROTOCOL_IP4,
216 .fp_proto = FIB_PROTOCOL_IP4,
224 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
226 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
227 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
228 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
229 "Default route is DROP");
232 fei = fib_table_lookup(fib_index, &pfx);
233 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
234 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
235 "all 0s route is DROP");
237 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
239 fei = fib_table_lookup(fib_index, &pfx);
240 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
241 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
242 "all 1s route is DROP");
244 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
246 fei = fib_table_lookup(fib_index, &pfx);
247 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
248 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
249 "all-mcast route is DROP");
251 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
253 fei = fib_table_lookup(fib_index, &pfx);
254 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
255 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
256 "class-e route is DROP");
259 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
260 * all of which are special sourced and so none of which share path-lists.
261 * There are also 6 entries, and 6 non-shared path-lists, in the v6 default
265 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
266 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
267 fib_path_list_pool_size());
268 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
269 fib_entry_pool_size());
272 * add interface routes.
273 * validate presence of /24 attached and /32 recieve.
274 * test for the presence of the receive address in the glean and local adj
276 fib_prefix_t local_pfx = {
278 .fp_proto = FIB_PROTOCOL_IP4,
281 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
286 fib_table_entry_update_one_path(fib_index, &local_pfx,
287 FIB_SOURCE_INTERFACE,
288 (FIB_ENTRY_FLAG_CONNECTED |
289 FIB_ENTRY_FLAG_ATTACHED),
292 tm->hw[0]->sw_if_index,
293 ~0, // invalid fib index
296 FIB_ROUTE_PATH_FLAG_NONE);
297 fei = fib_table_lookup(fib_index, &local_pfx);
298 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
299 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
300 fib_entry_get_flags(fei)),
301 "Flags set on attached interface");
303 ai = fib_entry_get_adj(fei);
304 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
306 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
307 "attached interface adj is glean");
308 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
309 &adj->sub_type.glean.receive_addr)),
310 "attached interface adj is receive ok");
312 local_pfx.fp_len = 32;
313 fib_table_entry_update_one_path(fib_index, &local_pfx,
314 FIB_SOURCE_INTERFACE,
315 (FIB_ENTRY_FLAG_CONNECTED |
316 FIB_ENTRY_FLAG_LOCAL),
319 tm->hw[0]->sw_if_index,
320 ~0, // invalid fib index
323 FIB_ROUTE_PATH_FLAG_NONE);
324 fei = fib_table_lookup(fib_index, &local_pfx);
325 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
326 fib_entry_get_flags(fei)),
327 "Flags set on local interface");
329 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
331 dpo = fib_entry_contribute_ip_forwarding(fei);
332 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
333 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
334 "local interface adj is local");
335 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
337 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
339 "local interface adj is receive ok");
341 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
343 FIB_SOURCE_INTERFACE)),
344 "2 Interface Source'd prefixes");
347 * +2 interface routes +2 non-shared path-lists
349 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
350 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
351 fib_path_list_pool_size());
352 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
353 fib_entry_pool_size());
356 * Modify the default route to be via an adj not yet known.
357 * this sources the defalut route with the API source, which is
358 * a higher preference to the DEFAULT_ROUTE source
360 pfx.fp_addr.ip4.as_u32 = 0;
362 fib_table_entry_path_add(fib_index, &pfx,
367 tm->hw[0]->sw_if_index,
368 ~0, // invalid fib index
371 FIB_ROUTE_PATH_FLAG_NONE);
372 fei = fib_table_lookup(fib_index, &pfx);
373 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
374 "Flags set on API route");
376 FIB_TEST((fei == dfrt), "default route same index");
377 ai = fib_entry_get_adj(fei);
378 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
380 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
381 "adj is incomplete");
382 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
383 "adj nbr next-hop ok");
384 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
387 "1 API Source'd prefixes");
390 * find the adj in the shared db
392 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
395 tm->hw[0]->sw_if_index);
396 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
397 adj_unlock(locked_ai);
400 * +1 shared path-list
402 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
403 fib_path_list_db_size());
404 FIB_TEST((NBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
405 fib_path_list_pool_size());
406 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
407 fib_entry_pool_size());
410 * remove the API source from the default route. We expected
411 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
413 pfx.fp_addr.ip4.as_u32 = 0;
415 fib_table_entry_path_remove(fib_index, &pfx,
419 tm->hw[0]->sw_if_index,
420 ~0, // non-recursive path, so no FIB index
422 FIB_ROUTE_PATH_FLAG_NONE);
424 fei = fib_table_lookup(fib_index, &pfx);
426 FIB_TEST((fei == dfrt), "default route same index");
427 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
428 "Default route is DROP");
431 * -1 shared-path-list
433 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
434 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
435 fib_path_list_pool_size());
436 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
437 fib_entry_pool_size());
440 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
442 fib_prefix_t pfx_10_10_10_1_s_32 = {
444 .fp_proto = FIB_PROTOCOL_IP4,
447 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
450 fib_prefix_t pfx_10_10_10_2_s_32 = {
452 .fp_proto = FIB_PROTOCOL_IP4,
455 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
458 fib_prefix_t pfx_11_11_11_11_s_32 = {
460 .fp_proto = FIB_PROTOCOL_IP4,
463 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
467 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
471 * Add a route via an incomplete ADJ. then complete the ADJ
472 * Expect the route LB is updated to use complete adj type.
474 fei = fib_table_entry_update_one_path(fib_index,
475 &pfx_11_11_11_11_s_32,
477 FIB_ENTRY_FLAG_ATTACHED,
479 &pfx_10_10_10_1_s_32.fp_addr,
480 tm->hw[0]->sw_if_index,
481 ~0, // invalid fib index
484 FIB_ROUTE_PATH_FLAG_NONE);
486 dpo = fib_entry_contribute_ip_forwarding(fei);
487 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
488 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
489 "11.11.11.11/32 via incomplete adj");
491 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
493 &pfx_10_10_10_1_s_32.fp_addr,
494 tm->hw[0]->sw_if_index);
495 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
496 adj = adj_get(ai_01);
497 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
498 "adj is incomplete");
499 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
500 &adj->sub_type.nbr.next_hop)),
501 "adj nbr next-hop ok");
503 adj_nbr_update_rewrite(ai_01, eth_addr);
504 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
506 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
507 &adj->sub_type.nbr.next_hop)),
508 "adj nbr next-hop ok");
509 ai = fib_entry_get_adj(fei);
510 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
512 dpo = fib_entry_contribute_ip_forwarding(fei);
513 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
514 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
515 "11.11.11.11/32 via complete adj");
520 fei = fib_table_entry_update_one_path(fib_index,
521 &pfx_10_10_10_1_s_32,
523 FIB_ENTRY_FLAG_ATTACHED,
525 &pfx_10_10_10_1_s_32.fp_addr,
526 tm->hw[0]->sw_if_index,
527 ~0, // invalid fib index
530 FIB_ROUTE_PATH_FLAG_NONE);
531 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
532 "Flags set on adj-fib");
533 ai = fib_entry_get_adj(fei);
534 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
536 fib_table_entry_path_remove(fib_index,
537 &pfx_11_11_11_11_s_32,
540 &pfx_10_10_10_1_s_32.fp_addr,
541 tm->hw[0]->sw_if_index,
542 ~0, // invalid fib index
544 FIB_ROUTE_PATH_FLAG_NONE);
548 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
550 &pfx_10_10_10_2_s_32.fp_addr,
551 tm->hw[0]->sw_if_index);
552 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
553 adj = adj_get(ai_02);
554 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
555 "adj is incomplete");
556 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
557 &adj->sub_type.nbr.next_hop)),
558 "adj nbr next-hop ok");
560 adj_nbr_update_rewrite(ai_02, eth_addr);
561 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
563 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
564 &adj->sub_type.nbr.next_hop)),
565 "adj nbr next-hop ok");
566 FIB_TEST((ai_01 != ai_02), "ADJs are different");
568 fib_table_entry_update_one_path(fib_index,
569 &pfx_10_10_10_2_s_32,
573 &pfx_10_10_10_2_s_32.fp_addr,
574 tm->hw[0]->sw_if_index,
575 ~0, // invalid fib index
578 FIB_ROUTE_PATH_FLAG_NONE);
580 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
581 ai = fib_entry_get_adj(fei);
582 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
585 * +2 adj-fibs, and their non-shared path-lists
587 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
588 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
589 fib_path_list_pool_size());
590 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
591 fib_entry_pool_size());
594 * Add a 2 routes via the first ADJ. ensure path-list sharing
596 fib_prefix_t pfx_1_1_1_1_s_32 = {
598 .fp_proto = FIB_PROTOCOL_IP4,
601 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
605 fib_table_entry_path_add(fib_index,
611 tm->hw[0]->sw_if_index,
612 ~0, // invalid fib index
615 FIB_ROUTE_PATH_FLAG_NONE);
616 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
617 ai = fib_entry_get_adj(fei);
618 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
621 * +1 entry and a shared path-list
623 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
624 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
625 fib_path_list_pool_size());
626 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
627 fib_entry_pool_size());
630 fib_prefix_t pfx_1_1_2_0_s_24 = {
632 .fp_proto = FIB_PROTOCOL_IP4,
634 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
638 fib_table_entry_path_add(fib_index,
644 tm->hw[0]->sw_if_index,
645 ~0, // invalid fib index
648 FIB_ROUTE_PATH_FLAG_NONE);
649 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
650 ai = fib_entry_get_adj(fei);
651 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
656 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
657 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
658 fib_path_list_pool_size());
659 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
660 fib_entry_pool_size());
663 * modify 1.1.2.0/24 to use multipath.
665 fib_table_entry_path_add(fib_index,
671 tm->hw[0]->sw_if_index,
672 ~0, // invalid fib index
675 FIB_ROUTE_PATH_FLAG_NONE);
676 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
677 dpo = fib_entry_contribute_ip_forwarding(fei);
679 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
680 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
681 FIB_TEST((ai_01 == dpo1->dpoi_index),
682 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
683 ai_01, dpo1->dpoi_index);
685 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
686 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
687 FIB_TEST((ai_02 == dpo1->dpoi_index),
688 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
693 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
694 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
695 fib_path_list_pool_size());
696 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
697 fib_entry_pool_size());
702 fib_table_entry_path_remove(fib_index,
707 tm->hw[0]->sw_if_index,
710 FIB_ROUTE_PATH_FLAG_NONE);
711 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
712 ai = fib_entry_get_adj(fei);
713 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
718 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
719 fib_path_list_db_size());
720 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
721 fib_path_list_pool_size());
722 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
723 fib_entry_pool_size());
726 * Add 2 recursive routes:
727 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
728 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
730 fib_prefix_t bgp_100_pfx = {
732 .fp_proto = FIB_PROTOCOL_IP4,
734 /* 100.100.100.100/32 */
735 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
739 ip46_address_t nh_1_1_1_1 = {
740 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
743 fib_table_entry_path_add(fib_index,
749 ~0, // no index provided.
750 fib_index, // nexthop in same fib as route
753 FIB_ROUTE_PATH_FLAG_NONE);
755 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32);
758 * +1 entry and +1 shared-path-list
760 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
761 fib_path_list_db_size());
762 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
763 fib_path_list_pool_size());
764 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
765 fib_entry_pool_size());
767 fib_prefix_t bgp_101_pfx = {
769 .fp_proto = FIB_PROTOCOL_IP4,
771 /* 100.100.100.101/32 */
772 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
776 fib_table_entry_path_add(fib_index,
782 ~0, // no index provided.
783 fib_index, // nexthop in same fib as route
786 FIB_ROUTE_PATH_FLAG_NONE);
788 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32);
791 * +1 entry, but the recursive path-list is shared.
793 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
794 fib_path_list_db_size());
795 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
796 fib_path_list_pool_size());
797 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
798 fib_entry_pool_size());
801 * An EXCLUSIVE route; one where the user (me) provides the exclusive
802 * adjacency through which the route will resovle
804 fib_prefix_t ex_pfx = {
806 .fp_proto = FIB_PROTOCOL_IP4,
809 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
813 fib_table_entry_special_add(fib_index,
816 FIB_ENTRY_FLAG_EXCLUSIVE,
818 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
819 FIB_TEST((ai == fib_entry_get_adj(fei)),
820 "Exclusive route links to user adj");
822 fib_table_entry_special_remove(fib_index,
825 FIB_TEST(FIB_NODE_INDEX_INVALID ==
826 fib_table_lookup_exact_match(fib_index, &ex_pfx),
827 "Exclusive reoute removed");
830 * An EXCLUSIVE route; one where the user (me) provides the exclusive
831 * adjacency through which the route will resovle
833 dpo_id_t ex_dpo = DPO_NULL;
835 lookup_dpo_add_or_lock_w_fib_index(fib_index,
837 LOOKUP_INPUT_DST_ADDR,
838 LOOKUP_TABLE_FROM_CONFIG,
841 fib_table_entry_special_dpo_add(fib_index,
844 FIB_ENTRY_FLAG_EXCLUSIVE,
846 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
847 dpo = fib_entry_contribute_ip_forwarding(fei);
848 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
849 "exclusive remote uses lookup DPO");
851 fib_table_entry_special_remove(fib_index,
854 FIB_TEST(FIB_NODE_INDEX_INVALID ==
855 fib_table_lookup_exact_match(fib_index, &ex_pfx),
856 "Exclusive reoute removed");
860 * Add a recursive route:
861 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
863 fib_prefix_t bgp_200_pfx = {
865 .fp_proto = FIB_PROTOCOL_IP4,
867 /* 200.200.200.200/32 */
868 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
872 fib_prefix_t pfx_1_1_1_2_s_32 = {
874 .fp_proto = FIB_PROTOCOL_IP4,
876 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
880 fib_table_entry_path_add(fib_index,
885 &pfx_1_1_1_2_s_32.fp_addr,
886 ~0, // no index provided.
887 fib_index, // nexthop in same fib as route
890 FIB_ROUTE_PATH_FLAG_NONE);
892 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32);
895 * the adj should be recursive via drop, since the route resolves via
896 * the default route, which is itself a DROP
898 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
899 dpo1 = fib_entry_contribute_ip_forwarding(fei);
900 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
903 * +2 entry and +1 shared-path-list
905 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
906 fib_path_list_db_size());
907 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
908 fib_path_list_pool_size());
909 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
910 fib_entry_pool_size());
913 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
915 fib_prefix_t pfx_1_2_3_4_s_32 = {
917 .fp_proto = FIB_PROTOCOL_IP4,
919 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
922 fib_table_entry_path_add(fib_index,
928 tm->hw[0]->sw_if_index,
932 FIB_ROUTE_PATH_FLAG_NONE);
933 fei = fib_table_entry_path_add(fib_index,
939 tm->hw[0]->sw_if_index,
943 FIB_ROUTE_PATH_FLAG_NONE);
945 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
946 dpo = fib_entry_contribute_ip_forwarding(fei);
947 lb = load_balance_get(dpo->dpoi_index);
948 FIB_TEST((lb->lb_n_buckets == 4),
949 "1.2.3.4/32 LB has %d bucket",
952 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_01);
953 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_01);
954 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_01);
955 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_02);
957 fib_table_entry_delete(fib_index,
962 * Unequal Cost load-balance. 4:1 ratio.
963 * fits in a 16 bucket LB with ratio 13:3
965 fib_prefix_t pfx_1_2_3_5_s_32 = {
967 .fp_proto = FIB_PROTOCOL_IP4,
969 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
972 fib_table_entry_path_add(fib_index,
978 tm->hw[0]->sw_if_index,
982 FIB_ROUTE_PATH_FLAG_NONE);
983 fei = fib_table_entry_path_add(fib_index,
989 tm->hw[0]->sw_if_index,
993 FIB_ROUTE_PATH_FLAG_NONE);
995 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
996 dpo = fib_entry_contribute_ip_forwarding(fei);
997 lb = load_balance_get(dpo->dpoi_index);
998 FIB_TEST((lb->lb_n_buckets == 16),
999 "1.2.3.5/32 LB has %d bucket",
1002 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1003 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1004 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1005 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1006 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1007 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1008 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1009 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1010 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1011 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1012 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1013 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1014 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1015 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_02);
1016 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_02);
1017 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_02);
1019 fib_table_entry_delete(fib_index,
1024 * Add a recursive route:
1025 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
1027 fib_prefix_t bgp_201_pfx = {
1029 .fp_proto = FIB_PROTOCOL_IP4,
1031 /* 200.200.200.201/32 */
1032 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1036 fib_prefix_t pfx_1_1_1_200_s_32 = {
1038 .fp_proto = FIB_PROTOCOL_IP4,
1040 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1044 fib_table_entry_path_add(fib_index,
1047 FIB_ENTRY_FLAG_NONE,
1049 &pfx_1_1_1_200_s_32.fp_addr,
1050 ~0, // no index provided.
1051 fib_index, // nexthop in same fib as route
1054 FIB_ROUTE_PATH_FLAG_NONE);
1056 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32);
1058 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1059 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1060 "Flags set on RR via non-attached");
1063 * +2 entry (BGP & RR) and +1 shared-path-list
1065 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1066 fib_path_list_db_size());
1067 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1068 fib_path_list_pool_size());
1069 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1070 fib_entry_pool_size());
1073 * insert a route that covers the missing 1.1.1.2/32. we epxect
1074 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
1076 fib_prefix_t pfx_1_1_1_0_s_24 = {
1078 .fp_proto = FIB_PROTOCOL_IP4,
1081 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1085 fib_table_entry_path_add(fib_index,
1088 FIB_ENTRY_FLAG_NONE,
1091 tm->hw[0]->sw_if_index,
1092 ~0, // invalid fib index
1095 FIB_ROUTE_PATH_FLAG_NONE);
1096 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
1097 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1098 ai = fib_entry_get_adj(fei);
1099 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
1100 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1101 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1102 ai = fib_entry_get_adj(fei);
1103 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
1104 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1105 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1106 ai = fib_entry_get_adj(fei);
1107 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
1110 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
1112 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1113 fib_path_list_db_size());
1114 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1115 fib_path_list_pool_size());
1116 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1117 fib_entry_pool_size());
1120 * the recursive adj for 200.200.200.200 should be updated.
1122 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32);
1123 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32);
1126 * insert a more specific route than 1.1.1.0/24 that also covers the
1127 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
1128 * 200.200.200.200 to resolve through it.
1130 fib_prefix_t pfx_1_1_1_0_s_28 = {
1132 .fp_proto = FIB_PROTOCOL_IP4,
1135 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1139 fib_table_entry_path_add(fib_index,
1142 FIB_ENTRY_FLAG_NONE,
1145 tm->hw[0]->sw_if_index,
1146 ~0, // invalid fib index
1149 FIB_ROUTE_PATH_FLAG_NONE);
1150 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
1151 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1152 ai = fib_entry_get_adj(fei);
1153 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
1156 * +1 entry. +1 shared path-list
1158 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
1159 fib_path_list_db_size());
1160 FIB_TEST((NBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
1161 fib_path_list_pool_size());
1162 FIB_TEST((NBR+14 == fib_entry_pool_size()), "entry pool size is %d",
1163 fib_entry_pool_size());
1166 * the recursive adj for 200.200.200.200 should be updated.
1167 * 200.200.200.201 remains unchanged.
1169 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32);
1170 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32);
1173 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
1175 fib_table_entry_path_remove(fib_index,
1180 tm->hw[0]->sw_if_index,
1183 FIB_ROUTE_PATH_FLAG_NONE);
1184 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
1185 FIB_NODE_INDEX_INVALID),
1186 "1.1.1.0/28 removed");
1187 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
1188 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
1189 "1.1.1.0/28 lookup via /24");
1190 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32);
1191 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32);
1194 * -1 entry. -1 shared path-list
1196 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1197 fib_path_list_db_size());
1198 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1199 fib_path_list_pool_size());
1200 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1201 fib_entry_pool_size());
1204 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
1206 fib_table_entry_path_remove(fib_index,
1211 tm->hw[0]->sw_if_index,
1214 FIB_ROUTE_PATH_FLAG_NONE);
1215 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
1216 FIB_NODE_INDEX_INVALID),
1217 "1.1.1.0/24 removed");
1219 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1220 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1221 "1.1.1.2/32 route is DROP");
1222 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1223 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1224 "1.1.1.200/32 route is DROP");
1226 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32);
1227 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32);
1232 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1233 fib_path_list_db_size());
1234 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1235 fib_path_list_pool_size());
1236 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1237 fib_entry_pool_size());
1240 * insert the missing 1.1.1.2/32
1242 fei = fib_table_entry_path_add(fib_index,
1245 FIB_ENTRY_FLAG_NONE,
1248 tm->hw[0]->sw_if_index,
1249 ~0, // invalid fib index
1252 FIB_ROUTE_PATH_FLAG_NONE);
1253 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1254 ai = fib_entry_get_adj(fei);
1255 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
1257 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32);
1258 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32);
1261 * no change. 1.1.1.2/32 was already there RR sourced.
1263 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1264 fib_path_list_db_size());
1265 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1266 fib_path_list_pool_size());
1267 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1268 fib_entry_pool_size());
1271 * remove 200.200.200.201/32 which does not have a valid via FIB
1273 fib_table_entry_path_remove(fib_index,
1277 &pfx_1_1_1_200_s_32.fp_addr,
1278 ~0, // no index provided.
1281 FIB_ROUTE_PATH_FLAG_NONE);
1284 * -2 entries (BGP and RR). -1 shared path-list;
1286 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1287 FIB_NODE_INDEX_INVALID),
1288 "200.200.200.201/32 removed");
1289 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
1290 FIB_NODE_INDEX_INVALID),
1291 "1.1.1.200/32 removed");
1293 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1294 fib_path_list_db_size());
1295 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1296 fib_path_list_pool_size());
1297 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1298 fib_entry_pool_size());
1301 * remove 200.200.200.200/32 which does have a valid via FIB
1303 fib_table_entry_path_remove(fib_index,
1307 &pfx_1_1_1_2_s_32.fp_addr,
1308 ~0, // no index provided.
1311 FIB_ROUTE_PATH_FLAG_NONE);
1313 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1314 FIB_NODE_INDEX_INVALID),
1315 "200.200.200.200/32 removed");
1316 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
1317 FIB_NODE_INDEX_INVALID),
1318 "1.1.1.2/32 still present");
1321 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
1323 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1324 fib_path_list_db_size());
1325 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1326 fib_path_list_pool_size());
1327 FIB_TEST((NBR+9 == fib_entry_pool_size()), "entry pool size is %d",
1328 fib_entry_pool_size());
1331 * A recursive prefix that has a 2 path load-balance.
1332 * It also shares a next-hop with other BGP prefixes and hence
1333 * test the ref counting of RR sourced prefixes and 2 level LB.
1335 const fib_prefix_t bgp_102 = {
1337 .fp_proto = FIB_PROTOCOL_IP4,
1339 /* 100.100.100.101/32 */
1340 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
1343 fib_table_entry_path_add(fib_index,
1346 FIB_ENTRY_FLAG_NONE,
1348 &pfx_1_1_1_1_s_32.fp_addr,
1349 ~0, // no index provided.
1350 fib_index, // same as route
1353 FIB_ROUTE_PATH_FLAG_NONE);
1354 fib_table_entry_path_add(fib_index,
1357 FIB_ENTRY_FLAG_NONE,
1359 &pfx_1_1_1_2_s_32.fp_addr,
1360 ~0, // no index provided.
1361 fib_index, // same as route's FIB
1364 FIB_ROUTE_PATH_FLAG_NONE);
1365 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1366 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
1367 dpo = fib_entry_contribute_ip_forwarding(fei);
1369 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
1370 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1371 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
1372 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1374 lb = load_balance_get(dpo->dpoi_index);
1375 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
1376 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1377 "First via 10.10.10.1");
1378 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
1379 "Second via 10.10.10.1");
1381 fib_table_entry_path_remove(fib_index,
1385 &pfx_1_1_1_1_s_32.fp_addr,
1386 ~0, // no index provided.
1387 fib_index, // same as route's FIB
1389 FIB_ROUTE_PATH_FLAG_NONE);
1390 fib_table_entry_path_remove(fib_index,
1394 &pfx_1_1_1_2_s_32.fp_addr,
1395 ~0, // no index provided.
1396 fib_index, // same as route's FIB
1398 FIB_ROUTE_PATH_FLAG_NONE);
1399 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1400 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
1403 * remove the remaining recursives
1405 fib_table_entry_path_remove(fib_index,
1409 &pfx_1_1_1_1_s_32.fp_addr,
1410 ~0, // no index provided.
1411 fib_index, // same as route's FIB
1413 FIB_ROUTE_PATH_FLAG_NONE);
1414 fib_table_entry_path_remove(fib_index,
1418 &pfx_1_1_1_1_s_32.fp_addr,
1419 ~0, // no index provided.
1420 fib_index, // same as route's FIB
1422 FIB_ROUTE_PATH_FLAG_NONE);
1423 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
1424 FIB_NODE_INDEX_INVALID),
1425 "100.100.100.100/32 removed");
1426 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
1427 FIB_NODE_INDEX_INVALID),
1428 "100.100.100.101/32 removed");
1431 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
1433 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1434 fib_path_list_db_size());
1435 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1436 fib_path_list_pool_size());
1437 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1438 fib_entry_pool_size());
1441 * Add a recursive route via a connected cover, using an adj-fib that does exist
1443 fib_table_entry_path_add(fib_index,
1446 FIB_ENTRY_FLAG_NONE,
1449 ~0, // no index provided.
1450 fib_index, // Same as route's FIB
1453 FIB_ROUTE_PATH_FLAG_NONE);
1456 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
1458 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1459 fib_path_list_db_size());
1460 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1461 fib_path_list_pool_size());
1462 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1463 fib_entry_pool_size());
1465 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
1466 dpo = fib_entry_contribute_ip_forwarding(fei);
1468 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
1469 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1471 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1472 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
1474 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1475 "Flags set on RR via existing attached");
1478 * Add a recursive route via a connected cover, using and adj-fib that does
1481 ip46_address_t nh_10_10_10_3 = {
1482 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
1484 fib_prefix_t pfx_10_10_10_3 = {
1486 .fp_proto = FIB_PROTOCOL_IP4,
1487 .fp_addr = nh_10_10_10_3,
1490 fib_table_entry_path_add(fib_index,
1493 FIB_ENTRY_FLAG_NONE,
1496 ~0, // no index provided.
1500 FIB_ROUTE_PATH_FLAG_NONE);
1503 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
1504 * one unshared non-recursive via 10.10.10.3
1506 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1507 fib_path_list_db_size());
1508 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1509 fib_path_list_pool_size());
1510 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1511 fib_entry_pool_size());
1513 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1516 tm->hw[0]->sw_if_index);
1518 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
1519 dpo = fib_entry_contribute_ip_forwarding(fei);
1520 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
1521 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1523 ai = fib_entry_get_adj(fei);
1524 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
1525 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
1526 fib_entry_get_flags(fei)),
1527 "Flags set on RR via non-existing attached");
1529 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1530 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
1535 * remove the recursives
1537 fib_table_entry_path_remove(fib_index,
1542 ~0, // no index provided.
1543 fib_index, // same as route's FIB
1545 FIB_ROUTE_PATH_FLAG_NONE);
1546 fib_table_entry_path_remove(fib_index,
1551 ~0, // no index provided.
1552 fib_index, // same as route's FIB
1554 FIB_ROUTE_PATH_FLAG_NONE);
1556 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1557 FIB_NODE_INDEX_INVALID),
1558 "200.200.200.201/32 removed");
1559 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1560 FIB_NODE_INDEX_INVALID),
1561 "200.200.200.200/32 removed");
1562 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
1563 FIB_NODE_INDEX_INVALID),
1564 "10.10.10.3/32 removed");
1567 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
1568 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
1570 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1571 fib_path_list_db_size());
1572 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1573 fib_path_list_pool_size());
1574 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1575 fib_entry_pool_size());
1580 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
1582 fib_prefix_t pfx_5_5_5_5_s_32 = {
1584 .fp_proto = FIB_PROTOCOL_IP4,
1586 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
1589 fib_prefix_t pfx_5_5_5_6_s_32 = {
1591 .fp_proto = FIB_PROTOCOL_IP4,
1593 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
1596 fib_prefix_t pfx_5_5_5_7_s_32 = {
1598 .fp_proto = FIB_PROTOCOL_IP4,
1600 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
1604 fib_table_entry_path_add(fib_index,
1607 FIB_ENTRY_FLAG_NONE,
1609 &pfx_5_5_5_6_s_32.fp_addr,
1610 ~0, // no index provided.
1614 FIB_ROUTE_PATH_FLAG_NONE);
1615 fib_table_entry_path_add(fib_index,
1618 FIB_ENTRY_FLAG_NONE,
1620 &pfx_5_5_5_7_s_32.fp_addr,
1621 ~0, // no index provided.
1625 FIB_ROUTE_PATH_FLAG_NONE);
1626 fib_table_entry_path_add(fib_index,
1629 FIB_ENTRY_FLAG_NONE,
1631 &pfx_5_5_5_5_s_32.fp_addr,
1632 ~0, // no index provided.
1636 FIB_ROUTE_PATH_FLAG_NONE);
1638 * +3 entries, +3 shared path-list
1640 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1641 fib_path_list_db_size());
1642 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1643 fib_path_list_pool_size());
1644 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1645 fib_entry_pool_size());
1648 * All the entries have only looped paths, so they are all drop
1650 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1651 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1652 "LB for 5.5.5.7/32 is via adj for DROP");
1653 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1654 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1655 "LB for 5.5.5.5/32 is via adj for DROP");
1656 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1657 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1658 "LB for 5.5.5.6/32 is via adj for DROP");
1661 * provide 5.5.5.6/32 with alternate path.
1662 * this will allow only 5.5.5.6/32 to forward with this path, the others
1663 * are still drop since the loop is still present.
1665 fib_table_entry_path_add(fib_index,
1668 FIB_ENTRY_FLAG_NONE,
1671 tm->hw[0]->sw_if_index,
1675 FIB_ROUTE_PATH_FLAG_NONE);
1678 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1679 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1681 lb = load_balance_get(dpo1->dpoi_index);
1682 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
1684 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1685 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1686 FIB_TEST((ai_01 == dpo2->dpoi_index),
1687 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
1689 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1690 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1691 "LB for 5.5.5.7/32 is via adj for DROP");
1692 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1693 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1694 "LB for 5.5.5.5/32 is via adj for DROP");
1697 * remove the alternate path for 5.5.5.6/32
1700 fib_table_entry_path_remove(fib_index,
1705 tm->hw[0]->sw_if_index,
1708 FIB_ROUTE_PATH_FLAG_NONE);
1710 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1711 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1712 "LB for 5.5.5.7/32 is via adj for DROP");
1713 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1714 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1715 "LB for 5.5.5.5/32 is via adj for DROP");
1716 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1717 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1718 "LB for 5.5.5.6/32 is via adj for DROP");
1721 * break the loop by giving 5.5.5.5/32 a new set of paths
1722 * expect all to forward via this new path.
1724 fib_table_entry_update_one_path(fib_index,
1727 FIB_ENTRY_FLAG_NONE,
1730 tm->hw[0]->sw_if_index,
1731 ~0, // invalid fib index
1734 FIB_ROUTE_PATH_FLAG_NONE);
1736 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1737 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1738 lb = load_balance_get(dpo1->dpoi_index);
1739 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
1741 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1742 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1743 FIB_TEST((ai_01 == dpo2->dpoi_index),
1744 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
1746 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
1747 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1749 lb = load_balance_get(dpo2->dpoi_index);
1750 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1751 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
1752 "5.5.5.5.7 via 5.5.5.5");
1754 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
1755 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1757 lb = load_balance_get(dpo1->dpoi_index);
1758 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1759 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
1760 "5.5.5.5.6 via 5.5.5.7");
1763 * revert back to the loop. so we can remove the prefixes with
1766 fib_table_entry_update_one_path(fib_index,
1769 FIB_ENTRY_FLAG_NONE,
1771 &pfx_5_5_5_6_s_32.fp_addr,
1772 ~0, // no index provided.
1776 FIB_ROUTE_PATH_FLAG_NONE);
1778 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1779 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1780 "LB for 5.5.5.7/32 is via adj for DROP");
1781 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1782 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1783 "LB for 5.5.5.5/32 is via adj for DROP");
1784 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1785 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1786 "LB for 5.5.5.6/32 is via adj for DROP");
1789 * remove all the 5.5.5.x/32 prefixes
1791 fib_table_entry_path_remove(fib_index,
1795 &pfx_5_5_5_6_s_32.fp_addr,
1796 ~0, // no index provided.
1797 fib_index, // same as route's FIB
1799 FIB_ROUTE_PATH_FLAG_NONE);
1800 fib_table_entry_path_remove(fib_index,
1804 &pfx_5_5_5_7_s_32.fp_addr,
1805 ~0, // no index provided.
1806 fib_index, // same as route's FIB
1808 FIB_ROUTE_PATH_FLAG_NONE);
1809 fib_table_entry_path_remove(fib_index,
1813 &pfx_5_5_5_5_s_32.fp_addr,
1814 ~0, // no index provided.
1815 fib_index, // same as route's FIB
1817 FIB_ROUTE_PATH_FLAG_NONE);
1818 fib_table_entry_path_remove(fib_index,
1823 ~0, // no index provided.
1824 fib_index, // same as route's FIB
1826 FIB_ROUTE_PATH_FLAG_NONE);
1829 * -3 entries, -3 shared path-list
1831 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1832 fib_path_list_db_size());
1833 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1834 fib_path_list_pool_size());
1835 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1836 fib_entry_pool_size());
1839 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
1841 fib_table_entry_path_add(fib_index,
1844 FIB_ENTRY_FLAG_NONE,
1846 &pfx_5_5_5_6_s_32.fp_addr,
1847 ~0, // no index provided.
1851 FIB_ROUTE_PATH_FLAG_NONE);
1852 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1853 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1854 "1-level 5.5.5.6/32 loop is via adj for DROP");
1856 fib_table_entry_path_remove(fib_index,
1860 &pfx_5_5_5_6_s_32.fp_addr,
1861 ~0, // no index provided.
1862 fib_index, // same as route's FIB
1864 FIB_ROUTE_PATH_FLAG_NONE);
1865 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1866 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
1867 "1-level 5.5.5.6/32 loop is removed");
1870 * add-remove test. no change.
1872 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1873 fib_path_list_db_size());
1874 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1875 fib_path_list_pool_size());
1876 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1877 fib_entry_pool_size());
1880 * A recursive route with recursion constraints.
1881 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
1883 fib_table_entry_path_add(fib_index,
1886 FIB_ENTRY_FLAG_NONE,
1893 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
1895 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
1896 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1898 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
1899 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1901 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
1902 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
1905 * save the load-balance. we expect it to be inplace modified
1907 lb = load_balance_get(dpo1->dpoi_index);
1910 * add a covering prefix for the via fib that would otherwise serve
1911 * as the resolving route when the host is removed
1913 fib_table_entry_path_add(fib_index,
1916 FIB_ENTRY_FLAG_NONE,
1919 tm->hw[0]->sw_if_index,
1920 ~0, // invalid fib index
1923 FIB_ROUTE_PATH_FLAG_NONE);
1924 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
1925 ai = fib_entry_get_adj(fei);
1926 FIB_TEST((ai == ai_01),
1927 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
1930 * remove the host via FIB - expect the BGP prefix to be drop
1932 fib_table_entry_path_remove(fib_index,
1937 tm->hw[0]->sw_if_index,
1938 ~0, // invalid fib index
1940 FIB_ROUTE_PATH_FLAG_NONE);
1942 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
1943 "adj for 200.200.200.200/32 is recursive via adj for DROP");
1946 * add the via-entry host reoute back. expect to resolve again
1948 fib_table_entry_path_add(fib_index,
1951 FIB_ENTRY_FLAG_NONE,
1954 tm->hw[0]->sw_if_index,
1955 ~0, // invalid fib index
1958 FIB_ROUTE_PATH_FLAG_NONE);
1959 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
1960 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
1963 * add another path for the recursive. it will then have 2.
1965 fib_prefix_t pfx_1_1_1_3_s_32 = {
1967 .fp_proto = FIB_PROTOCOL_IP4,
1969 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
1972 fib_table_entry_path_add(fib_index,
1975 FIB_ENTRY_FLAG_NONE,
1978 tm->hw[0]->sw_if_index,
1979 ~0, // invalid fib index
1982 FIB_ROUTE_PATH_FLAG_NONE);
1984 fib_table_entry_path_add(fib_index,
1987 FIB_ENTRY_FLAG_NONE,
1989 &pfx_1_1_1_3_s_32.fp_addr,
1994 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
1996 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
1997 dpo = fib_entry_contribute_ip_forwarding(fei);
1999 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2000 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2001 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2002 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2003 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2004 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2005 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2006 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2009 * expect the lb-map used by the recursive's load-balance is using both buckets
2011 load_balance_map_t *lbm;
2014 lb = load_balance_get(dpo->dpoi_index);
2016 load_balance_map_lock(lbmi);
2017 lbm = load_balance_map_get(lbmi);
2019 FIB_TEST(lbm->lbm_buckets[0] == 0,
2020 "LB maps's bucket 0 is %d",
2021 lbm->lbm_buckets[0]);
2022 FIB_TEST(lbm->lbm_buckets[1] == 1,
2023 "LB maps's bucket 1 is %d",
2024 lbm->lbm_buckets[1]);
2027 * withdraw one of the /32 via-entrys.
2028 * that ECMP path will be unresolved and forwarding should continue on the
2029 * other available path. this is an iBGP PIC edge failover.
2030 * Test the forwarding changes without re-fetching the adj from the
2031 * recursive entry. this ensures its the same one that is updated; i.e. an
2034 fib_table_entry_path_remove(fib_index,
2039 tm->hw[0]->sw_if_index,
2040 ~0, // invalid fib index
2042 FIB_ROUTE_PATH_FLAG_NONE);
2044 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2045 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
2046 "post PIC 200.200.200.200/32 was inplace modified");
2048 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
2049 "post PIC adj for 200.200.200.200/32 is recursive"
2050 " via adj for 1.1.1.3");
2053 * the LB maps that was locked above should have been modified to remove
2054 * the path that was down, and thus its bucket points to a path that is
2057 FIB_TEST(lbm->lbm_buckets[0] == 1,
2058 "LB maps's bucket 0 is %d",
2059 lbm->lbm_buckets[0]);
2060 FIB_TEST(lbm->lbm_buckets[1] == 1,
2061 "LB maps's bucket 1 is %d",
2062 lbm->lbm_buckets[1]);
2064 load_balance_map_unlock(lb->lb_map);
2067 * add it back. again
2069 fib_table_entry_path_add(fib_index,
2072 FIB_ENTRY_FLAG_NONE,
2075 tm->hw[0]->sw_if_index,
2076 ~0, // invalid fib index
2079 FIB_ROUTE_PATH_FLAG_NONE);
2081 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
2082 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2083 "via adj for 1.1.1.1");
2084 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
2085 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2086 "via adj for 1.1.1.3");
2088 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2089 dpo = fib_entry_contribute_ip_forwarding(fei);
2090 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2091 "post PIC 200.200.200.200/32 was inplace modified");
2094 * add a 3rd path. this makes the LB 16 buckets.
2096 fib_table_entry_path_add(fib_index,
2099 FIB_ENTRY_FLAG_NONE,
2101 &pfx_1_1_1_2_s_32.fp_addr,
2106 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2108 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2109 dpo = fib_entry_contribute_ip_forwarding(fei);
2110 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2111 "200.200.200.200/32 was inplace modified for 3rd path");
2112 FIB_TEST(16 == lb->lb_n_buckets,
2113 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
2116 load_balance_map_lock(lbmi);
2117 lbm = load_balance_map_get(lbmi);
2119 for (ii = 0; ii < 16; ii++)
2121 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2122 "LB Map for 200.200.200.200/32 at %d is %d",
2123 ii, lbm->lbm_buckets[ii]);
2127 * trigger PIC by removing the first via-entry
2128 * the first 6 buckets of the map should map to the next 6
2130 fib_table_entry_path_remove(fib_index,
2135 tm->hw[0]->sw_if_index,
2138 FIB_ROUTE_PATH_FLAG_NONE);
2140 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2141 dpo = fib_entry_contribute_ip_forwarding(fei);
2142 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2143 "200.200.200.200/32 was inplace modified for 3rd path");
2144 FIB_TEST(2 == lb->lb_n_buckets,
2145 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
2147 for (ii = 0; ii < 6; ii++)
2149 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
2150 "LB Map for 200.200.200.200/32 at %d is %d",
2151 ii, lbm->lbm_buckets[ii]);
2153 for (ii = 6; ii < 16; ii++)
2155 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2156 "LB Map for 200.200.200.200/32 at %d is %d",
2157 ii, lbm->lbm_buckets[ii]);
2164 fib_table_entry_path_add(fib_index,
2167 FIB_ENTRY_FLAG_NONE,
2170 tm->hw[0]->sw_if_index,
2174 FIB_ROUTE_PATH_FLAG_NONE);
2176 fib_table_entry_path_remove(fib_index,
2180 &pfx_1_1_1_2_s_32.fp_addr,
2184 MPLS_LABEL_INVALID);
2185 fib_table_entry_path_remove(fib_index,
2193 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2194 fib_table_entry_path_remove(fib_index,
2198 &pfx_1_1_1_3_s_32.fp_addr,
2202 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2203 fib_table_entry_delete(fib_index,
2206 fib_table_entry_delete(fib_index,
2209 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2210 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
2211 "1.1.1.1/28 removed");
2212 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2213 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
2214 "1.1.1.3/32 removed");
2215 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2216 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
2217 "200.200.200.200/32 removed");
2220 * add-remove test. no change.
2222 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2223 fib_path_list_db_size());
2224 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2225 fib_path_list_pool_size());
2226 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2227 fib_entry_pool_size());
2230 * A route whose paths are built up iteratively and then removed
2233 fib_prefix_t pfx_4_4_4_4_s_32 = {
2235 .fp_proto = FIB_PROTOCOL_IP4,
2238 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
2242 fib_table_entry_path_add(fib_index,
2245 FIB_ENTRY_FLAG_NONE,
2248 tm->hw[0]->sw_if_index,
2252 FIB_ROUTE_PATH_FLAG_NONE);
2253 fib_table_entry_path_add(fib_index,
2256 FIB_ENTRY_FLAG_NONE,
2259 tm->hw[0]->sw_if_index,
2263 FIB_ROUTE_PATH_FLAG_NONE);
2264 fib_table_entry_path_add(fib_index,
2267 FIB_ENTRY_FLAG_NONE,
2270 tm->hw[0]->sw_if_index,
2274 FIB_ROUTE_PATH_FLAG_NONE);
2275 FIB_TEST(FIB_NODE_INDEX_INVALID !=
2276 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2277 "4.4.4.4/32 present");
2279 fib_table_entry_delete(fib_index,
2282 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2283 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2284 "4.4.4.4/32 removed");
2287 * add-remove test. no change.
2289 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2290 fib_path_list_db_size());
2291 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2292 fib_path_list_pool_size());
2293 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2294 fib_entry_pool_size());
2297 * A route with multiple paths at once
2299 fib_route_path_t *r_paths = NULL;
2301 for (ii = 0; ii < 4; ii++)
2303 fib_route_path_t r_path = {
2304 .frp_proto = FIB_PROTOCOL_IP4,
2306 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
2308 .frp_sw_if_index = tm->hw[0]->sw_if_index,
2310 .frp_fib_index = ~0,
2312 vec_add1(r_paths, r_path);
2315 fib_table_entry_update(fib_index,
2318 FIB_ENTRY_FLAG_NONE,
2321 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2322 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2323 dpo = fib_entry_contribute_ip_forwarding(fei);
2325 lb = load_balance_get(dpo->dpoi_index);
2326 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
2328 fib_table_entry_delete(fib_index,
2331 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2332 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2333 "4.4.4.4/32 removed");
2337 * add-remove test. no change.
2339 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2340 fib_path_list_db_size());
2341 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2342 fib_path_list_pool_size());
2343 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2344 fib_entry_pool_size());
2347 * A route deag route
2349 fib_table_entry_path_add(fib_index,
2352 FIB_ENTRY_FLAG_NONE,
2359 FIB_ROUTE_PATH_FLAG_NONE);
2361 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2362 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2364 dpo = fib_entry_contribute_ip_forwarding(fei);
2365 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2366 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
2368 FIB_TEST((fib_index == lkd->lkd_fib_index),
2369 "4.4.4.4/32 is deag in %d %U",
2371 format_dpo_id, dpo, 0);
2373 fib_table_entry_delete(fib_index,
2376 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2377 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2378 "4.4.4.4/32 removed");
2382 * add-remove test. no change.
2384 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2385 fib_path_list_db_size());
2386 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2387 fib_path_list_pool_size());
2388 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2389 fib_entry_pool_size());
2393 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
2394 * all of which are via 10.10.10.1, Itf1
2396 fib_table_entry_path_remove(fib_index,
2401 tm->hw[0]->sw_if_index,
2404 FIB_ROUTE_PATH_FLAG_NONE);
2405 fib_table_entry_path_remove(fib_index,
2410 tm->hw[0]->sw_if_index,
2413 FIB_ROUTE_PATH_FLAG_NONE);
2414 fib_table_entry_path_remove(fib_index,
2419 tm->hw[0]->sw_if_index,
2422 FIB_ROUTE_PATH_FLAG_NONE);
2424 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2425 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
2426 "1.1.1.1/32 removed");
2427 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2428 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
2429 "1.1.1.2/32 removed");
2430 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2431 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
2432 "1.1.2.0/24 removed");
2435 * -3 entries and -1 shared path-list
2437 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2438 fib_path_list_db_size());
2439 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2440 fib_path_list_pool_size());
2441 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2442 fib_entry_pool_size());
2445 * An attached-host route. Expect to link to the incomplete adj
2447 fib_prefix_t pfx_4_1_1_1_s_32 = {
2449 .fp_proto = FIB_PROTOCOL_IP4,
2452 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
2455 fib_table_entry_path_add(fib_index,
2458 FIB_ENTRY_FLAG_NONE,
2461 tm->hw[0]->sw_if_index,
2465 FIB_ROUTE_PATH_FLAG_NONE);
2467 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
2468 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
2469 ai = fib_entry_get_adj(fei);
2471 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2473 &pfx_4_1_1_1_s_32.fp_addr,
2474 tm->hw[0]->sw_if_index);
2475 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
2479 * +1 entry and +1 shared path-list
2481 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2482 fib_path_list_db_size());
2483 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2484 fib_path_list_pool_size());
2485 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
2486 fib_entry_pool_size());
2488 fib_table_entry_delete(fib_index,
2492 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2493 fib_path_list_db_size());
2494 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2495 fib_path_list_pool_size());
2496 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2497 fib_entry_pool_size());
2500 * add a v6 prefix via v4 next-hops
2502 fib_prefix_t pfx_2001_s_64 = {
2504 .fp_proto = FIB_PROTOCOL_IP6,
2506 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
2509 fei = fib_table_entry_path_add(0, //default v6 table
2512 FIB_ENTRY_FLAG_NONE,
2515 tm->hw[0]->sw_if_index,
2519 FIB_ROUTE_PATH_FLAG_NONE);
2521 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
2522 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
2523 ai = fib_entry_get_adj(fei);
2525 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
2526 "2001::/64 via ARP-adj");
2527 FIB_TEST((adj->ia_link == FIB_LINK_IP6),
2528 "2001::/64 is link type v6");
2529 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
2530 "2001::/64 ADJ-adj is NH proto v4");
2531 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
2538 fib_table_entry_delete(fib_index,
2539 &pfx_10_10_10_1_s_32,
2541 fib_table_entry_delete(fib_index,
2542 &pfx_10_10_10_2_s_32,
2544 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2545 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
2546 "10.10.10.1/32 adj-fib removed");
2547 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2548 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
2549 "10.10.10.2/32 adj-fib removed");
2552 * -2 entries and -2 non-shared path-list
2554 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2555 fib_path_list_db_size());
2556 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
2557 fib_path_list_pool_size());
2558 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
2559 fib_entry_pool_size());
2562 * unlock the 2 adjacencies for which this test provided a rewrite.
2563 * These are the last locks on these adjs. they should thus go away.
2568 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2573 * remove the interface prefixes
2575 local_pfx.fp_len = 32;
2576 fib_table_entry_special_remove(fib_index, &local_pfx,
2577 FIB_SOURCE_INTERFACE);
2578 fei = fib_table_lookup(fib_index, &local_pfx);
2580 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2581 fib_table_lookup_exact_match(fib_index, &local_pfx),
2582 "10.10.10.10/32 adj-fib removed");
2584 local_pfx.fp_len = 24;
2585 fib_table_entry_delete(fib_index, &local_pfx,
2586 FIB_SOURCE_INTERFACE);
2588 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2589 fib_table_lookup_exact_match(fib_index, &local_pfx),
2590 "10.10.10.10/24 adj-fib removed");
2593 * -2 entries and -2 non-shared path-list
2595 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2596 fib_path_list_db_size());
2597 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
2598 fib_path_list_pool_size());
2599 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
2600 fib_entry_pool_size());
2603 * Last but not least, remove the VRF
2605 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2608 "NO API Source'd prefixes");
2609 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2612 "NO RR Source'd prefixes");
2613 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2615 FIB_SOURCE_INTERFACE)),
2616 "NO INterface Source'd prefixes");
2618 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
2620 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2621 fib_path_list_db_size());
2622 FIB_TEST((NBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
2623 fib_path_list_pool_size());
2624 FIB_TEST((NBR-5 == fib_entry_pool_size()), "entry pool size is %d",
2625 fib_entry_pool_size());
2634 * In the default table check for the presence and correct forwarding
2635 * of the special entries
2637 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
2638 const dpo_id_t *dpo, *dpo_drop;
2639 const ip_adjacency_t *adj;
2640 const receive_dpo_t *rd;
2645 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2648 /* via 2001:0:0:1::2 */
2649 ip46_address_t nh_2001_2 = {
2652 [0] = clib_host_to_net_u64(0x2001000000000001),
2653 [1] = clib_host_to_net_u64(0x0000000000000002),
2660 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
2662 /* Find or create FIB table 11 */
2663 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
2665 for (ii = 0; ii < 4; ii++)
2667 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
2670 fib_prefix_t pfx_0_0 = {
2672 .fp_proto = FIB_PROTOCOL_IP6,
2680 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
2681 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
2682 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
2683 "Default route is DROP");
2685 dpo = fib_entry_contribute_ip_forwarding(dfrt);
2686 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2689 &pfx_0_0.fp_addr.ip6)),
2690 "default-route; fwd and non-fwd tables match");
2692 // FIXME - check specials.
2695 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
2696 * each with 6 entries. All entries are special so no path-list sharing.
2699 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
2700 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is %d",
2701 fib_path_list_pool_size());
2702 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
2703 fib_entry_pool_size());
2706 * add interface routes.
2707 * validate presence of /64 attached and /128 recieve.
2708 * test for the presence of the receive address in the glean and local adj
2710 * receive on 2001:0:0:1::1/128
2712 fib_prefix_t local_pfx = {
2714 .fp_proto = FIB_PROTOCOL_IP6,
2718 [0] = clib_host_to_net_u64(0x2001000000000001),
2719 [1] = clib_host_to_net_u64(0x0000000000000001),
2725 fib_table_entry_update_one_path(fib_index, &local_pfx,
2726 FIB_SOURCE_INTERFACE,
2727 (FIB_ENTRY_FLAG_CONNECTED |
2728 FIB_ENTRY_FLAG_ATTACHED),
2731 tm->hw[0]->sw_if_index,
2735 FIB_ROUTE_PATH_FLAG_NONE);
2736 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
2738 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
2740 ai = fib_entry_get_adj(fei);
2741 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
2743 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
2744 "attached interface adj is glean");
2745 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
2746 &adj->sub_type.glean.receive_addr)),
2747 "attached interface adj is receive ok");
2748 dpo = fib_entry_contribute_ip_forwarding(fei);
2749 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2752 &local_pfx.fp_addr.ip6)),
2753 "attached-route; fwd and non-fwd tables match");
2755 local_pfx.fp_len = 128;
2756 fib_table_entry_update_one_path(fib_index, &local_pfx,
2757 FIB_SOURCE_INTERFACE,
2758 (FIB_ENTRY_FLAG_CONNECTED |
2759 FIB_ENTRY_FLAG_LOCAL),
2762 tm->hw[0]->sw_if_index,
2763 ~0, // invalid fib index
2766 FIB_ROUTE_PATH_FLAG_NONE);
2767 fei = fib_table_lookup(fib_index, &local_pfx);
2769 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
2771 dpo = fib_entry_contribute_ip_forwarding(fei);
2772 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2773 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
2774 "local interface adj is local");
2775 rd = receive_dpo_get(dpo->dpoi_index);
2777 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
2779 "local interface adj is receive ok");
2781 dpo = fib_entry_contribute_ip_forwarding(fei);
2782 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2785 &local_pfx.fp_addr.ip6)),
2786 "local-route; fwd and non-fwd tables match");
2789 * +2 entries. +2 unshared path-lists
2791 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
2792 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
2793 fib_path_list_pool_size());
2794 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
2795 fib_entry_pool_size());
2798 * Modify the default route to be via an adj not yet known.
2799 * this sources the defalut route with the API source, which is
2800 * a higher preference to the DEFAULT_ROUTE source
2802 fib_table_entry_path_add(fib_index, &pfx_0_0,
2804 FIB_ENTRY_FLAG_NONE,
2807 tm->hw[0]->sw_if_index,
2811 FIB_ROUTE_PATH_FLAG_NONE);
2812 fei = fib_table_lookup(fib_index, &pfx_0_0);
2814 FIB_TEST((fei == dfrt), "default route same index");
2815 ai = fib_entry_get_adj(fei);
2816 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
2818 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
2819 "adj is incomplete");
2820 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
2821 "adj nbr next-hop ok");
2824 * find the adj in the shared db
2826 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
2829 tm->hw[0]->sw_if_index);
2830 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
2831 adj_unlock(locked_ai);
2834 * no more entires. +1 shared path-list
2836 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2837 fib_path_list_db_size());
2838 FIB_TEST((NPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
2839 fib_path_list_pool_size());
2840 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
2841 fib_entry_pool_size());
2844 * remove the API source from the default route. We expected
2845 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
2847 fib_table_entry_path_remove(fib_index, &pfx_0_0,
2851 tm->hw[0]->sw_if_index,
2854 FIB_ROUTE_PATH_FLAG_NONE);
2855 fei = fib_table_lookup(fib_index, &pfx_0_0);
2857 FIB_TEST((fei == dfrt), "default route same index");
2858 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
2859 "Default route is DROP");
2862 * no more entires. -1 shared path-list
2864 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2865 fib_path_list_db_size());
2866 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
2867 fib_path_list_pool_size());
2868 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
2869 fib_entry_pool_size());
2872 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
2874 fib_prefix_t pfx_2001_1_2_s_128 = {
2876 .fp_proto = FIB_PROTOCOL_IP6,
2880 [0] = clib_host_to_net_u64(0x2001000000000001),
2881 [1] = clib_host_to_net_u64(0x0000000000000002),
2886 fib_prefix_t pfx_2001_1_3_s_128 = {
2888 .fp_proto = FIB_PROTOCOL_IP6,
2892 [0] = clib_host_to_net_u64(0x2001000000000001),
2893 [1] = clib_host_to_net_u64(0x0000000000000003),
2899 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
2902 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
2904 &pfx_2001_1_2_s_128.fp_addr,
2905 tm->hw[0]->sw_if_index);
2906 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
2907 adj = adj_get(ai_01);
2908 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
2909 "adj is incomplete");
2910 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
2911 &adj->sub_type.nbr.next_hop)),
2912 "adj nbr next-hop ok");
2914 adj_nbr_update_rewrite(ai_01, eth_addr);
2915 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
2917 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
2918 &adj->sub_type.nbr.next_hop)),
2919 "adj nbr next-hop ok");
2921 fib_table_entry_update_one_path(fib_index,
2922 &pfx_2001_1_2_s_128,
2924 FIB_ENTRY_FLAG_NONE,
2926 &pfx_2001_1_2_s_128.fp_addr,
2927 tm->hw[0]->sw_if_index,
2931 FIB_ROUTE_PATH_FLAG_NONE);
2933 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
2934 ai = fib_entry_get_adj(fei);
2935 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
2939 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
2941 &pfx_2001_1_3_s_128.fp_addr,
2942 tm->hw[0]->sw_if_index);
2943 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
2944 adj = adj_get(ai_02);
2945 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
2946 "adj is incomplete");
2947 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
2948 &adj->sub_type.nbr.next_hop)),
2949 "adj nbr next-hop ok");
2951 adj_nbr_update_rewrite(ai_02, eth_addr);
2952 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
2954 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
2955 &adj->sub_type.nbr.next_hop)),
2956 "adj nbr next-hop ok");
2957 FIB_TEST((ai_01 != ai_02), "ADJs are different");
2959 fib_table_entry_update_one_path(fib_index,
2960 &pfx_2001_1_3_s_128,
2962 FIB_ENTRY_FLAG_NONE,
2964 &pfx_2001_1_3_s_128.fp_addr,
2965 tm->hw[0]->sw_if_index,
2969 FIB_ROUTE_PATH_FLAG_NONE);
2971 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
2972 ai = fib_entry_get_adj(fei);
2973 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
2976 * +2 entries, +2 unshread path-lists.
2978 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2979 fib_path_list_db_size());
2980 FIB_TEST((NPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
2981 fib_path_list_pool_size());
2982 FIB_TEST((NPS+4 == fib_entry_pool_size()), "entry pool size is %d",
2983 fib_entry_pool_size());
2986 * Add a 2 routes via the first ADJ. ensure path-list sharing
2988 fib_prefix_t pfx_2001_a_s_64 = {
2990 .fp_proto = FIB_PROTOCOL_IP6,
2994 [0] = clib_host_to_net_u64(0x200100000000000a),
2995 [1] = clib_host_to_net_u64(0x0000000000000000),
3000 fib_prefix_t pfx_2001_b_s_64 = {
3002 .fp_proto = FIB_PROTOCOL_IP6,
3006 [0] = clib_host_to_net_u64(0x200100000000000b),
3007 [1] = clib_host_to_net_u64(0x0000000000000000),
3013 fib_table_entry_path_add(fib_index,
3016 FIB_ENTRY_FLAG_NONE,
3019 tm->hw[0]->sw_if_index,
3023 FIB_ROUTE_PATH_FLAG_NONE);
3024 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
3025 ai = fib_entry_get_adj(fei);
3026 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3027 fib_table_entry_path_add(fib_index,
3030 FIB_ENTRY_FLAG_NONE,
3033 tm->hw[0]->sw_if_index,
3037 FIB_ROUTE_PATH_FLAG_NONE);
3038 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
3039 ai = fib_entry_get_adj(fei);
3040 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3043 * +2 entries, +1 shared path-list.
3045 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3046 fib_path_list_db_size());
3047 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3048 fib_path_list_pool_size());
3049 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3050 fib_entry_pool_size());
3053 * add a v4 prefix via a v6 next-hop
3055 fib_prefix_t pfx_1_1_1_1_s_32 = {
3057 .fp_proto = FIB_PROTOCOL_IP4,
3059 .ip4.as_u32 = 0x01010101,
3062 fei = fib_table_entry_path_add(0, // default table
3065 FIB_ENTRY_FLAG_NONE,
3068 tm->hw[0]->sw_if_index,
3072 FIB_ROUTE_PATH_FLAG_NONE);
3073 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
3074 "1.1.1.1/32 o v6 route present");
3075 ai = fib_entry_get_adj(fei);
3077 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3078 "1.1.1.1/32 via ARP-adj");
3079 FIB_TEST((adj->ia_link == FIB_LINK_IP4),
3080 "1.1.1.1/32 ADJ-adj is link type v4");
3081 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
3082 "1.1.1.1/32 ADJ-adj is NH proto v6");
3083 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
3088 fib_prefix_t pfx_2001_c_s_64 = {
3090 .fp_proto = FIB_PROTOCOL_IP6,
3094 [0] = clib_host_to_net_u64(0x200100000000000c),
3095 [1] = clib_host_to_net_u64(0x0000000000000000),
3100 fib_table_entry_path_add(fib_index,
3103 FIB_ENTRY_FLAG_ATTACHED,
3106 tm->hw[0]->sw_if_index,
3110 FIB_ROUTE_PATH_FLAG_NONE);
3111 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3112 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
3113 ai = fib_entry_get_adj(fei);
3115 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
3116 "2001:0:0:c/64 attached resolves via glean");
3118 fib_table_entry_path_remove(fib_index,
3123 tm->hw[0]->sw_if_index,
3126 FIB_ROUTE_PATH_FLAG_NONE);
3127 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3128 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
3131 * Shutdown the interface on which we have a connected and through
3132 * which the routes are reachable.
3133 * This will result in the connected, adj-fibs, and routes linking to drop
3134 * The local/for-us prefix continues to receive.
3136 clib_error_t * error;
3138 error = vnet_sw_interface_set_flags(vnet_get_main(),
3139 tm->hw[0]->sw_if_index,
3140 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3141 FIB_TEST((NULL == error), "Interface shutdown OK");
3143 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3144 dpo = fib_entry_contribute_ip_forwarding(fei);
3145 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3146 "2001::b/64 resolves via drop");
3148 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3149 dpo = fib_entry_contribute_ip_forwarding(fei);
3150 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3151 "2001::a/64 resolves via drop");
3152 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3153 dpo = fib_entry_contribute_ip_forwarding(fei);
3154 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3155 "2001:0:0:1::3/64 resolves via drop");
3156 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3157 dpo = fib_entry_contribute_ip_forwarding(fei);
3158 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3159 "2001:0:0:1::2/64 resolves via drop");
3160 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3161 dpo = fib_entry_contribute_ip_forwarding(fei);
3162 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3163 "2001:0:0:1::1/128 not drop");
3164 local_pfx.fp_len = 64;
3165 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3166 dpo = fib_entry_contribute_ip_forwarding(fei);
3167 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3168 "2001:0:0:1/64 resolves via drop");
3173 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3174 fib_path_list_db_size());
3175 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3176 fib_path_list_pool_size());
3177 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3178 fib_entry_pool_size());
3181 * shutdown one of the other interfaces, then add a connected.
3182 * and swap one of the routes to it.
3184 error = vnet_sw_interface_set_flags(vnet_get_main(),
3185 tm->hw[1]->sw_if_index,
3186 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3187 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
3189 fib_prefix_t connected_pfx = {
3191 .fp_proto = FIB_PROTOCOL_IP6,
3194 /* 2001:0:0:2::1/64 */
3196 [0] = clib_host_to_net_u64(0x2001000000000002),
3197 [1] = clib_host_to_net_u64(0x0000000000000001),
3202 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3203 FIB_SOURCE_INTERFACE,
3204 (FIB_ENTRY_FLAG_CONNECTED |
3205 FIB_ENTRY_FLAG_ATTACHED),
3208 tm->hw[1]->sw_if_index,
3212 FIB_ROUTE_PATH_FLAG_NONE);
3213 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
3214 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3215 dpo = fib_entry_contribute_ip_forwarding(fei);
3216 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3217 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
3218 "2001:0:0:2/64 not resolves via drop");
3220 connected_pfx.fp_len = 128;
3221 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3222 FIB_SOURCE_INTERFACE,
3223 (FIB_ENTRY_FLAG_CONNECTED |
3224 FIB_ENTRY_FLAG_LOCAL),
3227 tm->hw[0]->sw_if_index,
3228 ~0, // invalid fib index
3231 FIB_ROUTE_PATH_FLAG_NONE);
3232 fei = fib_table_lookup(fib_index, &connected_pfx);
3234 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3235 dpo = fib_entry_contribute_ip_forwarding(fei);
3236 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3237 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3238 "local interface adj is local");
3239 rd = receive_dpo_get(dpo->dpoi_index);
3240 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
3242 "local interface adj is receive ok");
3245 * +2 entries, +2 unshared path-lists
3247 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3248 fib_path_list_db_size());
3249 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3250 fib_path_list_pool_size());
3251 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3252 fib_entry_pool_size());
3256 * bring the interface back up. we expected the routes to return
3257 * to normal forwarding.
3259 error = vnet_sw_interface_set_flags(vnet_get_main(),
3260 tm->hw[0]->sw_if_index,
3261 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3262 FIB_TEST((NULL == error), "Interface bring-up OK");
3263 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3264 ai = fib_entry_get_adj(fei);
3265 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3266 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3267 ai = fib_entry_get_adj(fei);
3268 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3269 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3270 ai = fib_entry_get_adj(fei);
3271 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3272 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3273 ai = fib_entry_get_adj(fei);
3274 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3275 local_pfx.fp_len = 64;
3276 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3277 ai = fib_entry_get_adj(fei);
3279 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3280 "attached interface adj is glean");
3283 * Delete the interface that the routes reolve through.
3284 * Again no routes are removed. They all point to drop.
3286 * This is considered an error case. The control plane should
3287 * not remove interfaces through which routes resolve, but
3288 * such things can happen. ALL affected routes will drop.
3290 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
3292 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3293 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3294 "2001::b/64 resolves via drop");
3295 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3296 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3297 "2001::b/64 resolves via drop");
3298 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3299 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3300 "2001:0:0:1::3/64 resolves via drop");
3301 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3302 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3303 "2001:0:0:1::2/64 resolves via drop");
3304 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3305 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3306 "2001:0:0:1::1/128 is drop");
3307 local_pfx.fp_len = 64;
3308 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3309 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3310 "2001:0:0:1/64 resolves via drop");
3315 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3316 fib_path_list_db_size());
3317 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3318 fib_path_list_pool_size());
3319 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3320 fib_entry_pool_size());
3323 * Add the interface back. routes stay unresolved.
3325 error = ethernet_register_interface(vnet_get_main(),
3326 test_interface_device_class.index,
3329 &tm->hw_if_indicies[0],
3330 /* flag change */ 0);
3332 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3333 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3334 "2001::b/64 resolves via drop");
3335 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3336 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3337 "2001::b/64 resolves via drop");
3338 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3339 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3340 "2001:0:0:1::3/64 resolves via drop");
3341 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3342 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3343 "2001:0:0:1::2/64 resolves via drop");
3344 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3345 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3346 "2001:0:0:1::1/128 is drop");
3347 local_pfx.fp_len = 64;
3348 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3349 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3350 "2001:0:0:1/64 resolves via drop");
3353 * CLEANUP ALL the routes
3355 fib_table_entry_delete(fib_index,
3358 fib_table_entry_delete(fib_index,
3361 fib_table_entry_delete(fib_index,
3364 fib_table_entry_delete(fib_index,
3365 &pfx_2001_1_3_s_128,
3367 fib_table_entry_delete(fib_index,
3368 &pfx_2001_1_2_s_128,
3370 local_pfx.fp_len = 64;
3371 fib_table_entry_delete(fib_index, &local_pfx,
3372 FIB_SOURCE_INTERFACE);
3373 local_pfx.fp_len = 128;
3374 fib_table_entry_special_remove(fib_index, &local_pfx,
3375 FIB_SOURCE_INTERFACE);
3376 connected_pfx.fp_len = 64;
3377 fib_table_entry_delete(fib_index, &connected_pfx,
3378 FIB_SOURCE_INTERFACE);
3379 connected_pfx.fp_len = 128;
3380 fib_table_entry_special_remove(fib_index, &connected_pfx,
3381 FIB_SOURCE_INTERFACE);
3383 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3384 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
3385 "2001::a/64 removed");
3386 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3387 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
3388 "2001::b/64 removed");
3389 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3390 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
3391 "2001:0:0:1::3/128 removed");
3392 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3393 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
3394 "2001:0:0:1::3/128 removed");
3395 local_pfx.fp_len = 64;
3396 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3397 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3398 "2001:0:0:1/64 removed");
3399 local_pfx.fp_len = 128;
3400 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3401 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3402 "2001:0:0:1::1/128 removed");
3403 connected_pfx.fp_len = 64;
3404 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3405 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3406 "2001:0:0:2/64 removed");
3407 connected_pfx.fp_len = 128;
3408 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3409 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3410 "2001:0:0:2::1/128 removed");
3413 * -8 entries. -7 path-lists (1 was shared).
3415 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3416 fib_path_list_db_size());
3417 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is%d",
3418 fib_path_list_pool_size());
3419 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
3420 fib_entry_pool_size());
3423 * now remove the VRF
3425 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
3427 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3428 fib_path_list_db_size());
3429 FIB_TEST((NPS-6 == fib_path_list_pool_size()), "path list pool size is%d",
3430 fib_path_list_pool_size());
3431 FIB_TEST((NPS-6 == fib_entry_pool_size()), "entry pool size is %d",
3432 fib_entry_pool_size());
3438 * return the interfaces to up state
3440 error = vnet_sw_interface_set_flags(vnet_get_main(),
3441 tm->hw[0]->sw_if_index,
3442 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3443 error = vnet_sw_interface_set_flags(vnet_get_main(),
3444 tm->hw[1]->sw_if_index,
3445 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3447 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3452 * Test the recursive route route handling for GRE tunnels
3457 /* fib_node_index_t fei; */
3458 /* u32 fib_index = 0; */
3459 /* test_main_t *tm; */
3462 /* tm = &test_main; */
3464 /* for (ii = 0; ii < 4; ii++) */
3466 /* ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = 0; */
3470 /* * add interface routes. We'll assume this works. It's more rigorously */
3471 /* * tested elsewhere. */
3473 /* fib_prefix_t local_pfx = { */
3475 /* .fp_proto = FIB_PROTOCOL_IP4, */
3478 /* /\* 10.10.10.10 *\/ */
3479 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3484 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3485 /* FIB_SOURCE_INTERFACE, */
3486 /* (FIB_ENTRY_FLAG_CONNECTED | */
3487 /* FIB_ENTRY_FLAG_ATTACHED), */
3489 /* tm->hw[0]->sw_if_index, */
3492 /* FIB_ROUTE_PATH_FLAG_NONE); */
3493 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3494 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3495 /* "attached interface route present"); */
3497 /* local_pfx.fp_len = 32; */
3498 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3499 /* FIB_SOURCE_INTERFACE, */
3500 /* (FIB_ENTRY_FLAG_CONNECTED | */
3501 /* FIB_ENTRY_FLAG_LOCAL), */
3503 /* tm->hw[0]->sw_if_index, */
3504 /* ~0, // invalid fib index */
3506 /* FIB_ROUTE_PATH_FLAG_NONE); */
3507 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3509 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3510 /* "local interface route present"); */
3512 /* fib_prefix_t local2_pfx = { */
3514 /* .fp_proto = FIB_PROTOCOL_IP4, */
3517 /* /\* 10.10.11.11 *\/ */
3518 /* .as_u32 = clib_host_to_net_u32(0x0a0a0b0b), */
3523 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3524 /* FIB_SOURCE_INTERFACE, */
3525 /* (FIB_ENTRY_FLAG_CONNECTED | */
3526 /* FIB_ENTRY_FLAG_ATTACHED), */
3528 /* tm->hw[1]->sw_if_index, */
3531 /* FIB_ROUTE_PATH_FLAG_NONE); */
3532 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3533 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3534 /* "attached interface route present"); */
3536 /* local2_pfx.fp_len = 32; */
3537 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3538 /* FIB_SOURCE_INTERFACE, */
3539 /* (FIB_ENTRY_FLAG_CONNECTED | */
3540 /* FIB_ENTRY_FLAG_LOCAL), */
3542 /* tm->hw[0]->sw_if_index, */
3543 /* ~0, // invalid fib index */
3545 /* FIB_ROUTE_PATH_FLAG_NONE); */
3546 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3548 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3549 /* "local interface route present"); */
3552 /* * Add the route that will be used to resolve the tunnel's destination */
3554 /* fib_prefix_t route_pfx = { */
3556 /* .fp_proto = FIB_PROTOCOL_IP4, */
3559 /* /\* 1.1.1.0/24 *\/ */
3560 /* .as_u32 = clib_host_to_net_u32(0x01010100), */
3564 /* /\* 10.10.10.2 *\/ */
3565 /* ip46_address_t nh_10_10_10_2 = { */
3566 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02), */
3569 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3570 /* FIB_SOURCE_API, */
3571 /* FIB_ENTRY_FLAG_NONE, */
3572 /* &nh_10_10_10_2, */
3573 /* tm->hw[0]->sw_if_index, */
3576 /* FIB_ROUTE_PATH_FLAG_NONE); */
3577 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
3578 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
3579 /* "route present"); */
3582 /* * Add a tunnel */
3584 /* /\* 1.1.1.1 *\/ */
3585 /* fib_prefix_t tun_dst_pfx = { */
3587 /* .fp_proto = FIB_PROTOCOL_IP4, */
3589 /* .ip4.as_u32 = clib_host_to_net_u32(0x01010101), */
3592 /* /\* 10.10.10.10 *\/ */
3593 /* ip4_address_t tun_src = { */
3594 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3596 /* /\* 172.16.0.1 *\/ */
3597 /* ip4_address_t tun_itf = { */
3598 /* .as_u32 = clib_host_to_net_u32(0xac100001), */
3600 /* fib_prefix_t tun_itf_pfx = { */
3602 /* .fp_proto = FIB_PROTOCOL_IP4, */
3604 /* .ip4 = tun_itf, */
3607 /* u32 *encap_labels = NULL; */
3608 /* u32 label = 0xbaba; */
3609 /* u32 encap_index; */
3610 /* u32 tunnel_sw_if_index; */
3615 /* * First we need the MPLS Encap present */
3617 /* * Pretty sure this is broken. the wiki say the 1st aparamter address */
3618 /* * should be the tunnel's interface address, which makes some sense. But */
3619 /* * the code for tunnel creation checks for the tunnel's destination */
3620 /* * address. curious... */
3622 /* vec_add1(encap_labels, label); */
3623 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
3624 /* 0, // inner VRF */
3626 /* ~0, // policy_tunnel_index, */
3627 /* 0, // no_dst_hash, */
3630 /* FIB_TEST((0 == rv), "MPLS encap created"); */
3633 /* * now create the tunnel */
3635 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3636 /* &tun_dst_pfx.fp_addr.ip4, */
3637 /* &tun_itf_pfx.fp_addr.ip4, */
3638 /* tun_itf_pfx.fp_len, */
3639 /* 0, // inner VRF */
3640 /* 0, // outer VRF */
3641 /* &tunnel_sw_if_index, */
3644 /* FIB_TEST((0 == rv), "Tunnel created"); */
3647 /* * add it again. just for giggles. */
3649 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3650 /* &tun_dst_pfx.fp_addr.ip4, */
3651 /* &tun_itf_pfx.fp_addr.ip4, */
3652 /* tun_itf_pfx.fp_len, */
3653 /* 0, // inner VRF */
3654 /* 0, // outer VRF */
3655 /* &tunnel_sw_if_index, */
3658 /* FIB_TEST((0 != rv), "Duplicate Tunnel not created"); */
3661 /* * Find the route added for the tunnel subnet and check that */
3662 /* * it has a midchin adj that is stacked on the adj used to reach the */
3663 /* * tunnel destination */
3665 /* ip_adjacency_t *midchain_adj, *route_adj, *adjfib_adj; */
3666 /* adj_index_t midchain_ai, route_ai, adjfib_ai1, adjfib_ai2; */
3667 /* ip_lookup_main_t *lm; */
3669 /* lm = &ip4_main.lookup_main; */
3671 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
3672 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "tun itf route present"); */
3673 /* midchain_ai = fib_entry_contribute_forwarding(fei); */
3674 /* midchain_adj = adj_get(midchain_ai); */
3676 /* FIB_TEST((IP_LOOKUP_NEXT_MIDCHAIN == midchain_adj->lookup_next_index), */
3677 /* "Tunnel interface links to midchain"); */
3679 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3680 /* route_ai = fib_entry_contribute_forwarding(fei); */
3681 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3682 /* "tunnel midchain it stacked on route adj"); */
3685 /* * update the route to the tunnel's destination to load-balance via */
3686 /* * interface 1. */
3688 /* /\* 10.10.11.2 *\/ */
3689 /* ip46_address_t nh_10_10_11_2 = { */
3690 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02), */
3693 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3694 /* FIB_SOURCE_API, */
3695 /* FIB_ENTRY_FLAG_NONE, */
3696 /* &nh_10_10_11_2, */
3697 /* tm->hw[1]->sw_if_index, */
3700 /* FIB_ROUTE_PATH_FLAG_NONE); */
3703 /* * the tunnels midchain should have re-stacked. This tests that the */
3704 /* * route re-resolution backwalk works to a tunnel interface. */
3706 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3707 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
3708 /* route_ai = fib_entry_contribute_forwarding(fei); */
3710 /* midchain_adj = adj_get(midchain_ai); */
3712 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3713 /* "tunnel midchain has re-stacked on route adj"); */
3715 /* route_adj = adj_get(route_ai); */
3717 /* FIB_TEST((2 == route_adj->n_adj), "Route adj is multipath"); */
3720 /* * At this stage both nieghbour adjs are incomplete, so the same should */
3721 /* * be true of the multipath adj */
3723 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == route_adj->lookup_next_index), */
3724 /* "Adj0 is ARP: %d", route_adj->lookup_next_index); */
3725 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == (route_adj+1)->lookup_next_index), */
3726 /* "Adj1 is ARP"); */
3729 /* * do the equivalent of creating an ARP entry for 10.10.10.2. */
3730 /* * This will complete the adj, and this */
3731 /* * change should be refelct in the multipath too. */
3733 /* u8* rewrite = NULL, byte = 0xd; */
3734 /* vec_add(rewrite, &byte, 6); */
3736 /* adjfib_ai1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
3738 /* &nh_10_10_10_2, */
3739 /* tm->hw[0]->sw_if_index); */
3740 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
3743 /* adjfib_adj = adj_get(adjfib_ai1); */
3744 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
3745 /* "Adj-fib10 adj is rewrite"); */
3747 /* adjfib_ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
3749 /* &nh_10_10_11_2, */
3750 /* tm->hw[1]->sw_if_index); */
3751 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
3755 /* adjfib_adj = adj_get(adjfib_ai2); */
3757 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
3758 /* "Adj-fib11 adj is rewrite"); */
3760 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3761 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
3762 /* route_ai = fib_entry_contribute_forwarding(fei); */
3763 /* route_adj = adj_get(route_ai); */
3764 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == route_adj->lookup_next_index), */
3765 /* "Adj0 is rewrite"); */
3766 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == (route_adj+1)->lookup_next_index), */
3767 /* "Adj1 is rewrite"); */
3772 /* adj_index_t drop_ai = adj_get_special(FIB_PROTOCOL_IP4, */
3773 /* ADJ_SPECIAL_TYPE_DROP); */
3776 /* * remove the route that the tunnel resovles via. expect */
3777 /* * it to now resolve via the default route, which is drop */
3779 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
3780 /* FIB_SOURCE_API, */
3781 /* &nh_10_10_10_2, */
3782 /* tm->hw[0]->sw_if_index, */
3785 /* FIB_ROUTE_PATH_FLAG_NONE); */
3786 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
3787 /* FIB_SOURCE_API, */
3788 /* &nh_10_10_11_2, */
3789 /* tm->hw[1]->sw_if_index, */
3792 /* FIB_ROUTE_PATH_FLAG_NONE); */
3793 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
3794 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
3795 /* "route present"); */
3796 /* midchain_adj = adj_get(midchain_ai); */
3797 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == drop_ai), */
3798 /* "tunnel midchain has re-stacked on drop"); */
3801 /* * remove the tunnel and its MPLS encaps */
3803 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3804 /* &tun_dst_pfx.fp_addr.ip4, */
3805 /* &tun_itf_pfx.fp_addr.ip4, */
3806 /* tun_itf_pfx.fp_len, */
3807 /* 0, // inner VRF */
3808 /* 0, // outer VRF */
3809 /* &tunnel_sw_if_index, */
3812 /* FIB_TEST((0 == rv), "Tunnel removed"); */
3813 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3814 /* &tun_dst_pfx.fp_addr.ip4, */
3815 /* &tun_itf_pfx.fp_addr.ip4, */
3816 /* tun_itf_pfx.fp_len, */
3817 /* 0, // inner VRF */
3818 /* 0, // outer VRF */
3819 /* &tunnel_sw_if_index, */
3822 /* FIB_TEST((0 != rv), "No existant Tunnel not removed"); */
3824 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
3825 /* 0, // inner VRF */
3827 /* ~0, // policy_tunnel_index, */
3828 /* 0, // no_dst_hash, */
3831 /* FIB_TEST((0 == rv), "MPLS encap deleted"); */
3833 /* vec_free(encap_labels); */
3836 /* * no more FIB entries expected */
3838 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
3839 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun itf route removed"); */
3840 /* fei = fib_table_lookup_exact_match(fib_index, &tun_dst_pfx); */
3841 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun dst route removed"); */
3844 /* * CLEANUP the connecteds */
3846 /* local2_pfx.fp_len = 24; */
3847 /* fib_table_entry_delete(fib_index, &local2_pfx, */
3848 /* FIB_SOURCE_INTERFACE); */
3849 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3850 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
3851 /* "attached interface route remove"); */
3853 /* local2_pfx.fp_len = 32; */
3854 /* fib_table_entry_special_remove(fib_index, &local2_pfx, */
3855 /* FIB_SOURCE_INTERFACE); */
3856 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3857 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
3858 /* "local interface route removed"); */
3859 /* local_pfx.fp_len = 24; */
3860 /* fib_table_entry_delete(fib_index, &local_pfx, */
3861 /* FIB_SOURCE_INTERFACE); */
3862 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3863 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
3864 /* "attached interface route remove"); */
3866 /* local_pfx.fp_len = 32; */
3867 /* fib_table_entry_special_remove(fib_index, &local_pfx, */
3868 /* FIB_SOURCE_INTERFACE); */
3869 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3870 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
3871 /* "local interface route removed"); */
3875 * Test Attached Exports
3880 const dpo_id_t *dpo, *dpo_drop;
3881 const u32 fib_index = 0;
3882 fib_node_index_t fei;
3889 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3893 * add interface routes. We'll assume this works. It's more rigorously
3896 fib_prefix_t local_pfx = {
3898 .fp_proto = FIB_PROTOCOL_IP4,
3902 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
3907 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
3908 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
3910 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
3912 fib_table_entry_update_one_path(fib_index, &local_pfx,
3913 FIB_SOURCE_INTERFACE,
3914 (FIB_ENTRY_FLAG_CONNECTED |
3915 FIB_ENTRY_FLAG_ATTACHED),
3918 tm->hw[0]->sw_if_index,
3922 FIB_ROUTE_PATH_FLAG_NONE);
3923 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3924 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
3925 "attached interface route present");
3927 local_pfx.fp_len = 32;
3928 fib_table_entry_update_one_path(fib_index, &local_pfx,
3929 FIB_SOURCE_INTERFACE,
3930 (FIB_ENTRY_FLAG_CONNECTED |
3931 FIB_ENTRY_FLAG_LOCAL),
3934 tm->hw[0]->sw_if_index,
3935 ~0, // invalid fib index
3938 FIB_ROUTE_PATH_FLAG_NONE);
3939 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3941 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
3942 "local interface route present");
3945 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3947 fib_prefix_t pfx_10_10_10_1_s_32 = {
3949 .fp_proto = FIB_PROTOCOL_IP4,
3952 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
3955 fib_node_index_t ai;
3957 fib_table_entry_update_one_path(fib_index,
3958 &pfx_10_10_10_1_s_32,
3960 FIB_ENTRY_FLAG_NONE,
3962 &pfx_10_10_10_1_s_32.fp_addr,
3963 tm->hw[0]->sw_if_index,
3964 ~0, // invalid fib index
3967 FIB_ROUTE_PATH_FLAG_NONE);
3969 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
3970 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
3971 ai = fib_entry_get_adj(fei);
3974 * create another FIB table into which routes will be imported
3976 u32 import_fib_index1;
3978 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
3981 * Add an attached route in the import FIB
3983 local_pfx.fp_len = 24;
3984 fib_table_entry_update_one_path(import_fib_index1,
3987 FIB_ENTRY_FLAG_NONE,
3990 tm->hw[0]->sw_if_index,
3991 ~0, // invalid fib index
3994 FIB_ROUTE_PATH_FLAG_NONE);
3995 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
3996 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
3999 * check for the presence of the adj-fibs in the import table
4001 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4002 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4003 FIB_TEST((ai == fib_entry_get_adj(fei)),
4004 "adj-fib1 Import uses same adj as export");
4007 * check for the presence of the local in the import table
4009 local_pfx.fp_len = 32;
4010 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4011 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4014 * Add another adj-fin in the export table. Expect this
4015 * to get magically exported;
4017 fib_prefix_t pfx_10_10_10_2_s_32 = {
4019 .fp_proto = FIB_PROTOCOL_IP4,
4022 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4026 fib_table_entry_update_one_path(fib_index,
4027 &pfx_10_10_10_2_s_32,
4029 FIB_ENTRY_FLAG_NONE,
4031 &pfx_10_10_10_2_s_32.fp_addr,
4032 tm->hw[0]->sw_if_index,
4033 ~0, // invalid fib index
4036 FIB_ROUTE_PATH_FLAG_NONE);
4037 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4038 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4039 ai = fib_entry_get_adj(fei);
4041 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4042 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4043 FIB_TEST((ai == fib_entry_get_adj(fei)),
4044 "Import uses same adj as export");
4047 * create a 2nd FIB table into which routes will be imported
4049 u32 import_fib_index2;
4051 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4054 * Add an attached route in the import FIB
4056 local_pfx.fp_len = 24;
4057 fib_table_entry_update_one_path(import_fib_index2,
4060 FIB_ENTRY_FLAG_NONE,
4063 tm->hw[0]->sw_if_index,
4064 ~0, // invalid fib index
4067 FIB_ROUTE_PATH_FLAG_NONE);
4068 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4069 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4072 * check for the presence of all the adj-fibs and local in the import table
4074 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4075 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4076 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4077 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4078 local_pfx.fp_len = 32;
4079 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4080 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4083 * add a 3rd adj-fib. expect it to be exported to both tables.
4085 fib_prefix_t pfx_10_10_10_3_s_32 = {
4087 .fp_proto = FIB_PROTOCOL_IP4,
4090 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4094 fib_table_entry_update_one_path(fib_index,
4095 &pfx_10_10_10_3_s_32,
4097 FIB_ENTRY_FLAG_NONE,
4099 &pfx_10_10_10_3_s_32.fp_addr,
4100 tm->hw[0]->sw_if_index,
4101 ~0, // invalid fib index
4104 FIB_ROUTE_PATH_FLAG_NONE);
4105 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4106 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4107 ai = fib_entry_get_adj(fei);
4109 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4110 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4111 FIB_TEST((ai == fib_entry_get_adj(fei)),
4112 "Import uses same adj as export");
4113 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4114 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4115 FIB_TEST((ai == fib_entry_get_adj(fei)),
4116 "Import uses same adj as export");
4119 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4121 fib_table_entry_delete(fib_index,
4122 &pfx_10_10_10_3_s_32,
4125 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4126 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4128 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4129 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
4131 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4132 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4135 * remove the attached route from the 2nd FIB. expect the imported
4136 * entires to be removed
4138 local_pfx.fp_len = 24;
4139 fib_table_entry_delete(import_fib_index2,
4142 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4143 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4145 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4146 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4147 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4148 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4149 local_pfx.fp_len = 32;
4150 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4151 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4153 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4154 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4155 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4156 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4157 local_pfx.fp_len = 32;
4158 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4159 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4162 * modify the route in FIB1 so it is no longer attached. expect the imported
4163 * entires to be removed
4165 local_pfx.fp_len = 24;
4166 fib_table_entry_update_one_path(import_fib_index1,
4169 FIB_ENTRY_FLAG_NONE,
4171 &pfx_10_10_10_2_s_32.fp_addr,
4172 tm->hw[0]->sw_if_index,
4173 ~0, // invalid fib index
4176 FIB_ROUTE_PATH_FLAG_NONE);
4177 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4178 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4179 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4180 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4181 local_pfx.fp_len = 32;
4182 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4183 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4186 * modify it back to attached. expect the adj-fibs back
4188 local_pfx.fp_len = 24;
4189 fib_table_entry_update_one_path(import_fib_index1,
4192 FIB_ENTRY_FLAG_NONE,
4195 tm->hw[0]->sw_if_index,
4196 ~0, // invalid fib index
4199 FIB_ROUTE_PATH_FLAG_NONE);
4200 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4201 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4202 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4203 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4204 local_pfx.fp_len = 32;
4205 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4206 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4209 * add a covering attached next-hop for the interface address, so we have
4210 * a valid adj to find when we check the forwarding tables
4212 fib_prefix_t pfx_10_0_0_0_s_8 = {
4214 .fp_proto = FIB_PROTOCOL_IP4,
4217 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4221 fei = fib_table_entry_update_one_path(fib_index,
4224 FIB_ENTRY_FLAG_NONE,
4226 &pfx_10_10_10_3_s_32.fp_addr,
4227 tm->hw[0]->sw_if_index,
4228 ~0, // invalid fib index
4231 FIB_ROUTE_PATH_FLAG_NONE);
4232 dpo = fib_entry_contribute_ip_forwarding(fei);
4235 * remove the route in the export fib. expect the adj-fibs to be removed
4237 local_pfx.fp_len = 24;
4238 fib_table_entry_delete(fib_index,
4240 FIB_SOURCE_INTERFACE);
4242 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4243 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4244 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4245 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4246 local_pfx.fp_len = 32;
4247 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4248 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4251 * the adj-fibs in the export VRF are present in the FIB table,
4252 * but not installed in forwarding, since they have no attached cover.
4253 * Consequently a lookup in the MTRIE gives the adj for the covering
4256 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4257 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4260 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4261 FIB_TEST(lbi == dpo->dpoi_index,
4262 "10.10.10.1 forwards on \n%U not \n%U",
4263 format_load_balance, lbi, 0,
4264 format_dpo_id, dpo, 0);
4265 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4266 FIB_TEST(lbi == dpo->dpoi_index,
4267 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4268 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
4269 FIB_TEST(lbi == dpo->dpoi_index,
4270 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
4273 * add the export prefix back, but not as attached.
4274 * No adj-fibs in export nor import tables
4276 local_pfx.fp_len = 24;
4277 fei = fib_table_entry_update_one_path(fib_index,
4280 FIB_ENTRY_FLAG_NONE,
4282 &pfx_10_10_10_1_s_32.fp_addr,
4283 tm->hw[0]->sw_if_index,
4284 ~0, // invalid fib index
4287 FIB_ROUTE_PATH_FLAG_NONE);
4288 dpo = fib_entry_contribute_ip_forwarding(fei);
4290 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4291 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
4292 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4293 FIB_TEST(lbi == dpo->dpoi_index,
4294 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
4295 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4296 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4297 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4298 FIB_TEST(lbi == dpo->dpoi_index,
4299 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4301 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4302 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4303 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4304 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4305 local_pfx.fp_len = 32;
4306 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4307 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4310 * modify the export prefix so it is attached. expect all covereds to return
4312 local_pfx.fp_len = 24;
4313 fib_table_entry_update_one_path(fib_index,
4316 FIB_ENTRY_FLAG_NONE,
4319 tm->hw[0]->sw_if_index,
4320 ~0, // invalid fib index
4323 FIB_ROUTE_PATH_FLAG_NONE);
4325 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4326 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4327 dpo = fib_entry_contribute_ip_forwarding(fei);
4328 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4329 "Adj-fib1 is not drop in export");
4330 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4331 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4332 local_pfx.fp_len = 32;
4333 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4334 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4335 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4336 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4337 dpo = fib_entry_contribute_ip_forwarding(fei);
4338 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4339 "Adj-fib1 is not drop in export");
4340 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4341 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4342 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4343 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4344 local_pfx.fp_len = 32;
4345 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4346 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4349 * modify the export prefix so connected. no change.
4351 local_pfx.fp_len = 24;
4352 fib_table_entry_update_one_path(fib_index, &local_pfx,
4353 FIB_SOURCE_INTERFACE,
4354 (FIB_ENTRY_FLAG_CONNECTED |
4355 FIB_ENTRY_FLAG_ATTACHED),
4358 tm->hw[0]->sw_if_index,
4362 FIB_ROUTE_PATH_FLAG_NONE);
4364 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4365 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4366 dpo = fib_entry_contribute_ip_forwarding(fei);
4367 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4368 "Adj-fib1 is not drop in export");
4369 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4370 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4371 local_pfx.fp_len = 32;
4372 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4373 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4374 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4375 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4376 dpo = fib_entry_contribute_ip_forwarding(fei);
4377 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4378 "Adj-fib1 is not drop in export");
4379 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4380 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4381 local_pfx.fp_len = 32;
4382 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4383 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4388 fib_table_entry_delete(fib_index,
4391 fib_table_entry_delete(fib_index,
4392 &pfx_10_10_10_1_s_32,
4394 fib_table_entry_delete(fib_index,
4395 &pfx_10_10_10_2_s_32,
4397 local_pfx.fp_len = 32;
4398 fib_table_entry_delete(fib_index,
4400 FIB_SOURCE_INTERFACE);
4401 local_pfx.fp_len = 24;
4402 fib_table_entry_delete(fib_index,
4405 fib_table_entry_delete(fib_index,
4407 FIB_SOURCE_INTERFACE);
4408 local_pfx.fp_len = 24;
4409 fib_table_entry_delete(import_fib_index1,
4413 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
4414 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
4416 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4420 typedef enum fib_test_lb_bucket_type_t_ {
4426 } fib_test_lb_bucket_type_t;
4428 typedef struct fib_test_lb_bucket_t_ {
4429 fib_test_lb_bucket_type_t type;
4460 } fib_test_lb_bucket_t;
4462 #define FIB_TEST_LB(_cond, _comment, _args...) \
4464 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
4470 fib_test_validate_lb_v (const load_balance_t *lb,
4474 const dpo_id_t *dpo;
4477 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
4479 for (bucket = 0; bucket < n_buckets; bucket++)
4481 const fib_test_lb_bucket_t *exp;
4483 exp = va_arg(ap, fib_test_lb_bucket_t*);
4484 dpo = load_balance_get_bucket_i(lb, bucket);
4488 case FT_LB_LABEL_O_ADJ:
4490 const mpls_label_dpo_t *mld;
4492 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4493 "bucket %d stacks on %U",
4495 format_dpo_type, dpo->dpoi_type);
4497 mld = mpls_label_dpo_get(dpo->dpoi_index);
4498 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4500 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4501 exp->label_o_adj.label),
4502 "bucket %d stacks on label %d",
4504 exp->label_o_adj.label);
4506 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4507 exp->label_o_adj.eos),
4508 "bucket %d stacks on label %d %U",
4510 exp->label_o_adj.label,
4511 format_mpls_eos_bit, exp->label_o_adj.eos);
4513 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
4514 "bucket %d label stacks on %U",
4516 format_dpo_type, mld->mld_dpo.dpoi_type);
4518 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
4519 "bucket %d label stacks on adj %d",
4521 exp->label_o_adj.adj);
4524 case FT_LB_LABEL_O_LB:
4526 const mpls_label_dpo_t *mld;
4529 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4530 "bucket %d stacks on %U",
4532 format_dpo_type, dpo->dpoi_type);
4534 mld = mpls_label_dpo_get(dpo->dpoi_index);
4535 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4537 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4538 exp->label_o_lb.label),
4539 "bucket %d stacks on label %d",
4541 exp->label_o_lb.label);
4543 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4544 exp->label_o_lb.eos),
4545 "bucket %d stacks on label %d %U",
4547 exp->label_o_lb.label,
4548 format_mpls_eos_bit, exp->label_o_lb.eos);
4550 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
4551 "bucket %d label stacks on %U",
4553 format_dpo_type, mld->mld_dpo.dpoi_type);
4555 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
4556 "bucket %d label stacks on LB %d",
4558 exp->label_o_lb.lb);
4562 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
4563 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
4564 "bucket %d stacks on %U",
4566 format_dpo_type, dpo->dpoi_type);
4567 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
4568 "bucket %d stacks on adj %d",
4573 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
4574 "bucket %d stacks on %U",
4576 format_dpo_type, dpo->dpoi_type);
4577 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
4578 "bucket %d stacks on lb %d",
4583 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
4584 "bucket %d stacks on %U",
4586 format_dpo_type, dpo->dpoi_type);
4587 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
4588 "bucket %d stacks on drop %d",
4598 fib_test_validate_entry (fib_node_index_t fei,
4599 fib_forward_chain_type_t fct,
4603 const load_balance_t *lb;
4604 dpo_id_t dpo = DPO_NULL;
4608 va_start(ap, n_buckets);
4610 fib_entry_contribute_forwarding(fei, fct, &dpo);
4612 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
4613 "Entry links to %U",
4614 format_dpo_type, dpo.dpoi_type);
4615 lb = load_balance_get(dpo.dpoi_index);
4617 res = fib_test_validate_lb_v(lb, n_buckets, ap);
4627 * Test the recursive route route handling for GRE tunnels
4630 fib_test_label (void)
4632 fib_node_index_t fei, ai_mpls_10_10_10_1, ai_v4_10_10_11_1, ai_v4_10_10_11_2, ai_mpls_10_10_11_2, ai_mpls_10_10_11_1;
4633 const u32 fib_index = 0;
4638 lb_count = pool_elts(load_balance_pool);
4643 * add interface routes. We'll assume this works. It's more rigorously
4646 fib_prefix_t local0_pfx = {
4648 .fp_proto = FIB_PROTOCOL_IP4,
4652 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4657 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4660 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4661 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4663 fib_table_entry_update_one_path(fib_index, &local0_pfx,
4664 FIB_SOURCE_INTERFACE,
4665 (FIB_ENTRY_FLAG_CONNECTED |
4666 FIB_ENTRY_FLAG_ATTACHED),
4669 tm->hw[0]->sw_if_index,
4673 FIB_ROUTE_PATH_FLAG_NONE);
4674 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
4675 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4676 "attached interface route present");
4678 local0_pfx.fp_len = 32;
4679 fib_table_entry_update_one_path(fib_index, &local0_pfx,
4680 FIB_SOURCE_INTERFACE,
4681 (FIB_ENTRY_FLAG_CONNECTED |
4682 FIB_ENTRY_FLAG_LOCAL),
4685 tm->hw[0]->sw_if_index,
4686 ~0, // invalid fib index
4689 FIB_ROUTE_PATH_FLAG_NONE);
4690 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
4692 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4693 "local interface route present");
4695 fib_prefix_t local1_pfx = {
4697 .fp_proto = FIB_PROTOCOL_IP4,
4701 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
4706 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
4707 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
4709 fib_table_entry_update_one_path(fib_index, &local1_pfx,
4710 FIB_SOURCE_INTERFACE,
4711 (FIB_ENTRY_FLAG_CONNECTED |
4712 FIB_ENTRY_FLAG_ATTACHED),
4715 tm->hw[1]->sw_if_index,
4719 FIB_ROUTE_PATH_FLAG_NONE);
4720 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
4721 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4722 "attached interface route present");
4724 local1_pfx.fp_len = 32;
4725 fib_table_entry_update_one_path(fib_index, &local1_pfx,
4726 FIB_SOURCE_INTERFACE,
4727 (FIB_ENTRY_FLAG_CONNECTED |
4728 FIB_ENTRY_FLAG_LOCAL),
4731 tm->hw[1]->sw_if_index,
4732 ~0, // invalid fib index
4735 FIB_ROUTE_PATH_FLAG_NONE);
4736 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
4738 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4739 "local interface route present");
4741 ip46_address_t nh_10_10_10_1 = {
4743 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4746 ip46_address_t nh_10_10_11_1 = {
4748 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
4751 ip46_address_t nh_10_10_11_2 = {
4753 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
4757 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4760 tm->hw[1]->sw_if_index);
4761 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4764 tm->hw[1]->sw_if_index);
4765 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4768 tm->hw[0]->sw_if_index);
4769 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4772 tm->hw[1]->sw_if_index);
4773 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4776 tm->hw[1]->sw_if_index);
4779 * Add an etry with one path with a real out-going label
4781 fib_prefix_t pfx_1_1_1_1_s_32 = {
4783 .fp_proto = FIB_PROTOCOL_IP4,
4785 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
4788 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
4789 .type = FT_LB_LABEL_O_ADJ,
4791 .adj = ai_mpls_10_10_10_1,
4796 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
4797 .type = FT_LB_LABEL_O_ADJ,
4799 .adj = ai_mpls_10_10_10_1,
4801 .eos = MPLS_NON_EOS,
4804 fib_table_entry_update_one_path(fib_index,
4807 FIB_ENTRY_FLAG_NONE,
4810 tm->hw[0]->sw_if_index,
4811 ~0, // invalid fib index
4814 FIB_ROUTE_PATH_FLAG_NONE);
4816 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
4817 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
4819 FIB_TEST(fib_test_validate_entry(fei,
4820 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4822 &l99_eos_o_10_10_10_1),
4823 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
4826 * add a path with an implicit NULL label
4828 fib_test_lb_bucket_t a_o_10_10_11_1 = {
4831 .adj = ai_v4_10_10_11_1,
4834 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
4837 .adj = ai_mpls_10_10_11_1,
4841 fei = fib_table_entry_path_add(fib_index,
4844 FIB_ENTRY_FLAG_NONE,
4847 tm->hw[1]->sw_if_index,
4848 ~0, // invalid fib index
4850 MPLS_IETF_IMPLICIT_NULL_LABEL,
4851 FIB_ROUTE_PATH_FLAG_NONE);
4853 FIB_TEST(fib_test_validate_entry(fei,
4854 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4856 &l99_eos_o_10_10_10_1,
4858 "1.1.1.1/32 LB 2 buckets via: "
4859 "label 99 over 10.10.10.1, "
4860 "adj over 10.10.11.1");
4863 * assign the route a local label
4865 fib_table_entry_local_label_add(fib_index,
4869 fib_prefix_t pfx_24001_eos = {
4870 .fp_proto = FIB_PROTOCOL_MPLS,
4874 fib_prefix_t pfx_24001_neos = {
4875 .fp_proto = FIB_PROTOCOL_MPLS,
4877 .fp_eos = MPLS_NON_EOS,
4881 * The EOS entry should link to both the paths,
4882 * and use an ip adj for the imp-null
4883 * The NON-EOS entry should link to both the paths,
4884 * and use an mpls adj for the imp-null
4886 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
4888 FIB_TEST(fib_test_validate_entry(fei,
4889 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
4891 &l99_eos_o_10_10_10_1,
4893 "24001/eos LB 2 buckets via: "
4894 "label 99 over 10.10.10.1, "
4895 "adj over 10.10.11.1");
4898 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
4900 FIB_TEST(fib_test_validate_entry(fei,
4901 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
4903 &l99_neos_o_10_10_10_1,
4904 &a_mpls_o_10_10_11_1),
4905 "24001/neos LB 1 bucket via: "
4906 "label 99 over 10.10.10.1 ",
4907 "mpls-adj via 10.10.11.1");
4910 * add an unlabelled path, this is excluded from the neos chains,
4912 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
4915 .adj = ai_v4_10_10_11_2,
4919 fei = fib_table_entry_path_add(fib_index,
4922 FIB_ENTRY_FLAG_NONE,
4925 tm->hw[1]->sw_if_index,
4926 ~0, // invalid fib index
4929 FIB_ROUTE_PATH_FLAG_NONE);
4931 FIB_TEST(fib_test_validate_entry(fei,
4932 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4933 16, // 3 choices spread over 16 buckets
4934 &l99_eos_o_10_10_10_1,
4935 &l99_eos_o_10_10_10_1,
4936 &l99_eos_o_10_10_10_1,
4937 &l99_eos_o_10_10_10_1,
4938 &l99_eos_o_10_10_10_1,
4939 &l99_eos_o_10_10_10_1,
4950 "1.1.1.1/32 LB 16 buckets via: "
4951 "label 99 over 10.10.10.1, "
4952 "adj over 10.10.11.1",
4953 "adj over 10.10.11.2");
4956 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
4958 dpo_id_t non_eos_1_1_1_1 = DPO_NULL;
4959 fib_entry_contribute_forwarding(fei,
4960 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
4964 * n-eos has only the 2 labelled paths
4966 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
4969 FIB_TEST(fib_test_validate_entry(fei,
4970 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
4972 &l99_neos_o_10_10_10_1,
4973 &a_mpls_o_10_10_11_1),
4974 "24001/neos LB 2 buckets via: "
4975 "label 99 over 10.10.10.1, "
4976 "adj-mpls over 10.10.11.2");
4979 * A labelled recursive
4981 fib_prefix_t pfx_2_2_2_2_s_32 = {
4983 .fp_proto = FIB_PROTOCOL_IP4,
4985 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
4988 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
4989 .type = FT_LB_LABEL_O_LB,
4991 .lb = non_eos_1_1_1_1.dpoi_index,
4997 fib_table_entry_update_one_path(fib_index,
5000 FIB_ENTRY_FLAG_NONE,
5002 &pfx_1_1_1_1_s_32.fp_addr,
5007 FIB_ROUTE_PATH_FLAG_NONE);
5009 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5010 FIB_TEST(fib_test_validate_entry(fei,
5011 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5013 &l1600_eos_o_1_1_1_1),
5014 "2.2.2.2.2/32 LB 1 buckets via: "
5015 "label 1600 over 1.1.1.1");
5018 * we are holding a lock on the non-eos LB of the via-entry.
5019 * do a PIC-core failover by shutting the link of the via-entry.
5021 * shut down the link with the valid label
5023 vnet_sw_interface_set_flags(vnet_get_main(),
5024 tm->hw[0]->sw_if_index,
5027 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5028 FIB_TEST(fib_test_validate_entry(fei,
5029 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5033 "1.1.1.1/32 LB 2 buckets via: "
5034 "adj over 10.10.11.1, ",
5035 "adj-v4 over 10.10.11.2");
5037 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5039 FIB_TEST(fib_test_validate_entry(fei,
5040 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5044 "24001/eos LB 2 buckets via: "
5045 "adj over 10.10.11.1, ",
5046 "adj-v4 over 10.10.11.2");
5048 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5050 FIB_TEST(fib_test_validate_entry(fei,
5051 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5053 &a_mpls_o_10_10_11_1),
5054 "24001/neos LB 1 buckets via: "
5055 "adj-mpls over 10.10.11.2");
5058 * test that the pre-failover load-balance has been in-place
5061 dpo_id_t current = DPO_NULL;
5062 fib_entry_contribute_forwarding(fei,
5063 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5066 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5068 "PIC-core LB inplace modified %U %U",
5069 format_dpo_id, &non_eos_1_1_1_1, 0,
5070 format_dpo_id, ¤t, 0);
5072 dpo_reset(&non_eos_1_1_1_1);
5073 dpo_reset(¤t);
5076 * no-shut the link with the valid label
5078 vnet_sw_interface_set_flags(vnet_get_main(),
5079 tm->hw[0]->sw_if_index,
5080 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5082 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5083 FIB_TEST(fib_test_validate_entry(fei,
5084 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5085 16, // 3 choices spread over 16 buckets
5086 &l99_eos_o_10_10_10_1,
5087 &l99_eos_o_10_10_10_1,
5088 &l99_eos_o_10_10_10_1,
5089 &l99_eos_o_10_10_10_1,
5090 &l99_eos_o_10_10_10_1,
5091 &l99_eos_o_10_10_10_1,
5102 "1.1.1.1/32 LB 16 buckets via: "
5103 "label 99 over 10.10.10.1, "
5104 "adj over 10.10.11.1",
5105 "adj-v4 over 10.10.11.2");
5108 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5110 FIB_TEST(fib_test_validate_entry(fei,
5111 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5112 16, // 3 choices spread over 16 buckets
5113 &l99_eos_o_10_10_10_1,
5114 &l99_eos_o_10_10_10_1,
5115 &l99_eos_o_10_10_10_1,
5116 &l99_eos_o_10_10_10_1,
5117 &l99_eos_o_10_10_10_1,
5118 &l99_eos_o_10_10_10_1,
5129 "24001/eos LB 16 buckets via: "
5130 "label 99 over 10.10.10.1, "
5131 "adj over 10.10.11.1",
5132 "adj-v4 over 10.10.11.2");
5134 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5136 FIB_TEST(fib_test_validate_entry(fei,
5137 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5139 &l99_neos_o_10_10_10_1,
5140 &a_mpls_o_10_10_11_1),
5141 "24001/neos LB 2 buckets via: "
5142 "label 99 over 10.10.10.1, "
5143 "adj-mpls over 10.10.11.2");
5146 * remove the first path with the valid label
5148 fib_table_entry_path_remove(fib_index,
5153 tm->hw[0]->sw_if_index,
5154 ~0, // invalid fib index
5156 FIB_ROUTE_PATH_FLAG_NONE);
5158 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5159 FIB_TEST(fib_test_validate_entry(fei,
5160 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5164 "1.1.1.1/32 LB 2 buckets via: "
5165 "adj over 10.10.11.1",
5166 "adj-v4 over 10.10.11.2");
5168 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5170 FIB_TEST(fib_test_validate_entry(fei,
5171 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5175 "24001/eos LB 2 buckets via: "
5176 "adj over 10.10.11.1",
5177 "adj-v4 over 10.10.11.2");
5179 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5182 FIB_TEST(fib_test_validate_entry(fei,
5183 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5185 &a_mpls_o_10_10_11_1),
5186 "24001/neos LB 1 buckets via: "
5187 "adj-mpls over 10.10.11.2");
5190 * remove the other path with a valid label
5192 fib_test_lb_bucket_t bucket_drop = {
5193 .type = FT_LB_SPECIAL,
5199 fib_table_entry_path_remove(fib_index,
5204 tm->hw[1]->sw_if_index,
5205 ~0, // invalid fib index
5207 FIB_ROUTE_PATH_FLAG_NONE);
5209 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5210 FIB_TEST(fib_test_validate_entry(fei,
5211 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5214 "1.1.1.1/32 LB 1 buckets via: "
5215 "adj over 10.10.11.2");
5217 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5219 FIB_TEST(fib_test_validate_entry(fei,
5220 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5223 "24001/eos LB 1 buckets via: "
5224 "adj over 10.10.11.2");
5226 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5228 FIB_TEST(fib_test_validate_entry(fei,
5229 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5232 "24001/eos LB 1 buckets via: DROP");
5235 * add back the path with the valid label
5237 fib_table_entry_path_add(fib_index,
5240 FIB_ENTRY_FLAG_NONE,
5243 tm->hw[0]->sw_if_index,
5244 ~0, // invalid fib index
5247 FIB_ROUTE_PATH_FLAG_NONE);
5249 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5250 FIB_TEST(fib_test_validate_entry(fei,
5251 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5253 &l99_eos_o_10_10_10_1,
5255 "1.1.1.1/32 LB 2 buckets via: "
5256 "label 99 over 10.10.10.1, "
5257 "adj over 10.10.11.2");
5259 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5261 FIB_TEST(fib_test_validate_entry(fei,
5262 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5264 &l99_eos_o_10_10_10_1,
5266 "24001/eos LB 2 buckets via: "
5267 "label 99 over 10.10.10.1, "
5268 "adj over 10.10.11.2");
5270 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5272 FIB_TEST(fib_test_validate_entry(fei,
5273 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5275 &l99_neos_o_10_10_10_1),
5276 "24001/neos LB 1 buckets via: "
5277 "label 99 over 10.10.10.1");
5280 * remove the local label
5282 fib_table_entry_local_label_remove(fib_index,
5286 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5287 FIB_TEST(fib_test_validate_entry(fei,
5288 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5290 &l99_eos_o_10_10_10_1,
5292 "24001/eos LB 2 buckets via: "
5293 "label 99 over 10.10.10.1, "
5294 "adj over 10.10.11.2");
5296 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5297 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5298 "No more MPLS FIB entries => table removed");
5301 * add another via-entry for the recursive
5303 fib_prefix_t pfx_1_1_1_2_s_32 = {
5305 .fp_proto = FIB_PROTOCOL_IP4,
5307 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5310 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5311 .type = FT_LB_LABEL_O_ADJ,
5313 .adj = ai_mpls_10_10_10_1,
5319 fei = fib_table_entry_update_one_path(fib_index,
5322 FIB_ENTRY_FLAG_NONE,
5325 tm->hw[0]->sw_if_index,
5326 ~0, // invalid fib index
5329 FIB_ROUTE_PATH_FLAG_NONE);
5331 FIB_TEST(fib_test_validate_entry(fei,
5332 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5334 &l101_eos_o_10_10_10_1),
5335 "1.1.1.2/32 LB 1 buckets via: "
5336 "label 101 over 10.10.10.1");
5338 dpo_id_t non_eos_1_1_1_2 = DPO_NULL;
5339 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5341 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5343 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5345 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5348 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5349 .type = FT_LB_LABEL_O_LB,
5351 .lb = non_eos_1_1_1_2.dpoi_index,
5356 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5358 fei = fib_table_entry_path_add(fib_index,
5361 FIB_ENTRY_FLAG_NONE,
5363 &pfx_1_1_1_2_s_32.fp_addr,
5368 FIB_ROUTE_PATH_FLAG_NONE);
5370 FIB_TEST(fib_test_validate_entry(fei,
5371 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5373 &l1600_eos_o_1_1_1_1,
5374 &l1601_eos_o_1_1_1_2),
5375 "2.2.2.2/32 LB 2 buckets via: "
5376 "label 1600 via 1.1,1.1, "
5377 "label 16001 via 1.1.1.2");
5380 * update the via-entry so it no longer has an imp-null path.
5381 * the LB for the recursive can use an imp-null
5383 fei = fib_table_entry_update_one_path(fib_index,
5386 FIB_ENTRY_FLAG_NONE,
5389 tm->hw[1]->sw_if_index,
5390 ~0, // invalid fib index
5392 MPLS_IETF_IMPLICIT_NULL_LABEL,
5393 FIB_ROUTE_PATH_FLAG_NONE);
5395 FIB_TEST(fib_test_validate_entry(fei,
5396 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5399 "1.1.1.2/32 LB 1 buckets via: "
5402 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5403 FIB_TEST(fib_test_validate_entry(fei,
5404 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5406 &l1600_eos_o_1_1_1_1,
5407 &l1601_eos_o_1_1_1_2),
5408 "2.2.2.2/32 LB 2 buckets via: "
5409 "label 1600 via 1.1,1.1, "
5410 "label 16001 via 1.1.1.2");
5413 * update the via-entry so it no longer has labelled paths.
5414 * the LB for the recursive should exclue this via form its LB
5416 fei = fib_table_entry_update_one_path(fib_index,
5419 FIB_ENTRY_FLAG_NONE,
5422 tm->hw[1]->sw_if_index,
5423 ~0, // invalid fib index
5426 FIB_ROUTE_PATH_FLAG_NONE);
5428 FIB_TEST(fib_test_validate_entry(fei,
5429 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5432 "1.1.1.2/32 LB 1 buckets via: "
5435 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5436 FIB_TEST(fib_test_validate_entry(fei,
5437 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5439 &l1600_eos_o_1_1_1_1),
5440 "2.2.2.2/32 LB 1 buckets via: "
5441 "label 1600 via 1.1,1.1");
5443 dpo_reset(&non_eos_1_1_1_1);
5444 dpo_reset(&non_eos_1_1_1_2);
5447 * Add a recursive with no out-labels. We expect to use the IP of the via
5449 fib_prefix_t pfx_2_2_2_3_s_32 = {
5451 .fp_proto = FIB_PROTOCOL_IP4,
5453 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
5456 dpo_id_t ip_1_1_1_1 = DPO_NULL;
5458 fib_table_entry_update_one_path(fib_index,
5461 FIB_ENTRY_FLAG_NONE,
5463 &pfx_1_1_1_1_s_32.fp_addr,
5468 FIB_ROUTE_PATH_FLAG_NONE);
5470 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5472 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5475 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5478 .lb = ip_1_1_1_1.dpoi_index,
5482 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
5483 FIB_TEST(fib_test_validate_entry(fei,
5484 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5487 "2.2.2.2.3/32 LB 1 buckets via: "
5491 * Add a recursive with an imp-null out-label.
5492 * We expect to use the IP of the via
5494 fib_prefix_t pfx_2_2_2_4_s_32 = {
5496 .fp_proto = FIB_PROTOCOL_IP4,
5498 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
5502 fib_table_entry_update_one_path(fib_index,
5505 FIB_ENTRY_FLAG_NONE,
5507 &pfx_1_1_1_1_s_32.fp_addr,
5512 FIB_ROUTE_PATH_FLAG_NONE);
5514 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
5515 FIB_TEST(fib_test_validate_entry(fei,
5516 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5519 "2.2.2.2.4/32 LB 1 buckets via: "
5522 dpo_reset(&ip_1_1_1_1);
5527 fib_table_entry_delete(fib_index,
5531 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5532 FIB_TEST(fib_test_validate_entry(fei,
5533 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5535 &l1600_eos_o_1_1_1_1),
5536 "2.2.2.2/32 LB 1 buckets via: "
5537 "label 1600 via 1.1,1.1");
5539 fib_table_entry_delete(fib_index,
5543 FIB_TEST(fib_test_validate_entry(fei,
5544 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5547 "2.2.2.2/32 LB 1 buckets via: DROP");
5549 fib_table_entry_delete(fib_index,
5552 fib_table_entry_delete(fib_index,
5555 fib_table_entry_delete(fib_index,
5559 adj_unlock(ai_mpls_10_10_10_1);
5560 adj_unlock(ai_mpls_10_10_11_2);
5561 adj_unlock(ai_v4_10_10_11_1);
5562 adj_unlock(ai_v4_10_10_11_2);
5563 adj_unlock(ai_mpls_10_10_11_1);
5565 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5568 local0_pfx.fp_len = 32;
5569 fib_table_entry_delete(fib_index,
5571 FIB_SOURCE_INTERFACE);
5572 local0_pfx.fp_len = 24;
5573 fib_table_entry_delete(fib_index,
5575 FIB_SOURCE_INTERFACE);
5576 local1_pfx.fp_len = 32;
5577 fib_table_entry_delete(fib_index,
5579 FIB_SOURCE_INTERFACE);
5580 local1_pfx.fp_len = 24;
5581 fib_table_entry_delete(fib_index,
5583 FIB_SOURCE_INTERFACE);
5586 * +1 for the drop LB in the MPLS tables.
5588 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
5589 "Load-balance resources freed %d of %d",
5590 lb_count+1, pool_elts(load_balance_pool));
5593 #define N_TEST_CHILDREN 4
5594 #define PARENT_INDEX 0
5596 typedef struct fib_node_test_t_
5601 fib_node_back_walk_ctx_t *ctxs;
5605 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
5607 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
5609 #define FOR_EACH_TEST_CHILD(_tc) \
5610 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
5611 ii < N_TEST_CHILDREN+1; \
5612 ii++, (_tc) = &fib_test_nodes[ii])
5615 fib_test_child_get_node (fib_node_index_t index)
5617 return (&fib_test_nodes[index].node);
5620 static int fib_test_walk_spawns_walks;
5622 static fib_node_back_walk_rc_t
5623 fib_test_child_back_walk_notify (fib_node_t *node,
5624 fib_node_back_walk_ctx_t *ctx)
5626 fib_node_test_t *tc = (fib_node_test_t*) node;
5628 vec_add1(tc->ctxs, *ctx);
5630 if (1 == fib_test_walk_spawns_walks)
5631 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
5632 if (2 == fib_test_walk_spawns_walks)
5633 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
5634 FIB_WALK_PRIORITY_HIGH, ctx);
5636 return (FIB_NODE_BACK_WALK_CONTINUE);
5640 fib_test_child_last_lock_gone (fib_node_t *node)
5642 fib_node_test_t *tc = (fib_node_test_t *)node;
5648 * The FIB walk's graph node virtual function table
5650 static const fib_node_vft_t fib_test_child_vft = {
5651 .fnv_get = fib_test_child_get_node,
5652 .fnv_last_lock = fib_test_child_last_lock_gone,
5653 .fnv_back_walk = fib_test_child_back_walk_notify,
5657 * the function (that should have been static but isn't so I can do this)
5658 * that processes the walk from the async queue,
5660 f64 fib_walk_process_queues(vlib_main_t * vm,
5662 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
5665 fib_test_walk (void)
5667 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
5668 fib_node_test_t *tc;
5672 vm = vlib_get_main();
5673 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
5676 * init a fake node on which we will add children
5678 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
5679 FIB_NODE_TYPE_TEST);
5681 FOR_EACH_TEST_CHILD(tc)
5683 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
5684 fib_node_lock(&tc->node);
5687 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
5689 FIB_NODE_TYPE_TEST, ii);
5693 * enqueue a walk across the parents children.
5695 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
5697 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5698 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5699 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
5700 "Parent has %d children pre-walk",
5701 fib_node_list_get_size(PARENT()->fn_children));
5704 * give the walk a large amount of time so it gets to the end
5706 fib_walk_process_queues(vm, 1);
5708 FOR_EACH_TEST_CHILD(tc)
5710 FIB_TEST(1 == vec_len(tc->ctxs),
5711 "%d child visitsed %d times",
5712 ii, vec_len(tc->ctxs));
5715 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5716 "Queue is empty post walk");
5717 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5718 "Parent has %d children post walk",
5719 fib_node_list_get_size(PARENT()->fn_children));
5722 * walk again. should be no increase in the number of visits, since
5723 * the walk will have terminated.
5725 fib_walk_process_queues(vm, 1);
5727 FOR_EACH_TEST_CHILD(tc)
5729 FIB_TEST(0 == vec_len(tc->ctxs),
5730 "%d child visitsed %d times",
5731 ii, vec_len(tc->ctxs));
5735 * schedule a low and hig priority walk. expect the high to be performed
5737 * schedule the high prio walk first so that it is further from the head
5738 * of the dependency list. that way it won't merge with the low one.
5740 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
5741 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
5743 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5744 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5745 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5746 FIB_WALK_PRIORITY_LOW, &low_ctx);
5748 fib_walk_process_queues(vm, 1);
5750 FOR_EACH_TEST_CHILD(tc)
5752 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
5753 "%d child visitsed by high prio walk", ii);
5754 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
5755 "%d child visitsed by low prio walk", ii);
5758 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5759 "Queue is empty post prio walk");
5760 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5761 "Parent has %d children post prio walk",
5762 fib_node_list_get_size(PARENT()->fn_children));
5765 * schedule 2 walks of the same priority that can be megred.
5766 * expect that each child is thus visited only once.
5768 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
5769 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
5771 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5772 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5773 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5774 FIB_WALK_PRIORITY_HIGH, &low_ctx);
5776 fib_walk_process_queues(vm, 1);
5778 FOR_EACH_TEST_CHILD(tc)
5780 FIB_TEST(1 == vec_len(tc->ctxs),
5781 "%d child visitsed %d times during merge walk",
5782 ii, vec_len(tc->ctxs));
5785 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5786 "Queue is empty post merge walk");
5787 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5788 "Parent has %d children post merge walk",
5789 fib_node_list_get_size(PARENT()->fn_children));
5792 * schedule 2 walks of the same priority that cannot be megred.
5793 * expect that each child is thus visited twice and in the order
5794 * in which the walks were scheduled.
5796 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
5797 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
5799 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5800 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5801 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5802 FIB_WALK_PRIORITY_HIGH, &low_ctx);
5804 fib_walk_process_queues(vm, 1);
5806 FOR_EACH_TEST_CHILD(tc)
5808 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
5809 "%d child visitsed by high prio walk", ii);
5810 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
5811 "%d child visitsed by low prio walk", ii);
5814 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5815 "Queue is empty post no-merge walk");
5816 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5817 "Parent has %d children post no-merge walk",
5818 fib_node_list_get_size(PARENT()->fn_children));
5821 * schedule a walk that makes one one child progress.
5822 * we do this by giving the queue draining process zero
5823 * time quanta. it's a do..while loop, so it does something.
5825 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
5827 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5828 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5829 fib_walk_process_queues(vm, 0);
5831 FOR_EACH_TEST_CHILD(tc)
5833 if (ii == N_TEST_CHILDREN)
5835 FIB_TEST(1 == vec_len(tc->ctxs),
5836 "%d child visitsed %d times in zero quanta walk",
5837 ii, vec_len(tc->ctxs));
5841 FIB_TEST(0 == vec_len(tc->ctxs),
5842 "%d child visitsed %d times in 0 quanta walk",
5843 ii, vec_len(tc->ctxs));
5846 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5847 "Queue is not empty post zero quanta walk");
5848 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
5849 "Parent has %d children post zero qunta walk",
5850 fib_node_list_get_size(PARENT()->fn_children));
5855 fib_walk_process_queues(vm, 0);
5857 FOR_EACH_TEST_CHILD(tc)
5859 if (ii >= N_TEST_CHILDREN-1)
5861 FIB_TEST(1 == vec_len(tc->ctxs),
5862 "%d child visitsed %d times in 2nd zero quanta walk",
5863 ii, vec_len(tc->ctxs));
5867 FIB_TEST(0 == vec_len(tc->ctxs),
5868 "%d child visitsed %d times in 2nd 0 quanta walk",
5869 ii, vec_len(tc->ctxs));
5872 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5873 "Queue is not empty post zero quanta walk");
5874 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
5875 "Parent has %d children post zero qunta walk",
5876 fib_node_list_get_size(PARENT()->fn_children));
5879 * schedule another walk that will catch-up and merge.
5881 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5882 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5883 fib_walk_process_queues(vm, 1);
5885 FOR_EACH_TEST_CHILD(tc)
5887 if (ii >= N_TEST_CHILDREN-1)
5889 FIB_TEST(2 == vec_len(tc->ctxs),
5890 "%d child visitsed %d times in 2nd zero quanta merge walk",
5891 ii, vec_len(tc->ctxs));
5896 FIB_TEST(1 == vec_len(tc->ctxs),
5897 "%d child visitsed %d times in 2nd 0 quanta merge walk",
5898 ii, vec_len(tc->ctxs));
5902 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5903 "Queue is not empty post 2nd zero quanta merge walk");
5904 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5905 "Parent has %d children post 2nd zero qunta merge walk",
5906 fib_node_list_get_size(PARENT()->fn_children));
5909 * park a async walk in the middle of the list, then have an sync walk catch
5910 * it. same expectations as async catches async.
5912 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
5914 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5915 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5917 fib_walk_process_queues(vm, 0);
5918 fib_walk_process_queues(vm, 0);
5920 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
5922 FOR_EACH_TEST_CHILD(tc)
5924 if (ii >= N_TEST_CHILDREN-1)
5926 FIB_TEST(2 == vec_len(tc->ctxs),
5927 "%d child visitsed %d times in sync catches async walk",
5928 ii, vec_len(tc->ctxs));
5933 FIB_TEST(1 == vec_len(tc->ctxs),
5934 "%d child visitsed %d times in sync catches async walk",
5935 ii, vec_len(tc->ctxs));
5939 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5940 "Queue is not empty post 2nd zero quanta merge walk");
5941 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5942 "Parent has %d children post 2nd zero qunta merge walk",
5943 fib_node_list_get_size(PARENT()->fn_children));
5946 * make the parent a child of one of its children, thus inducing a routing loop.
5948 fib_test_nodes[PARENT_INDEX].sibling =
5949 fib_node_child_add(FIB_NODE_TYPE_TEST,
5950 1, // the first child
5955 * execute a sync walk from the parent. each child visited spawns more sync
5956 * walks. we expect the walk to terminate.
5958 fib_test_walk_spawns_walks = 1;
5960 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
5962 FOR_EACH_TEST_CHILD(tc)
5965 * child 1 - which is last in the list - has the loop.
5966 * the other children a re thus visitsed first. the we meet
5967 * child 1. we go round the loop again, visting the other children.
5968 * then we meet the walk in the dep list and bail. child 1 is not visitsed
5973 FIB_TEST(1 == vec_len(tc->ctxs),
5974 "child %d visitsed %d times during looped sync walk",
5975 ii, vec_len(tc->ctxs));
5979 FIB_TEST(2 == vec_len(tc->ctxs),
5980 "child %d visitsed %d times during looped sync walk",
5981 ii, vec_len(tc->ctxs));
5985 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5986 "Parent has %d children post sync loop walk",
5987 fib_node_list_get_size(PARENT()->fn_children));
5990 * the walk doesn't reach the max depth because the infra knows that sync
5991 * meets sync implies a loop and bails early.
5993 FIB_TEST(high_ctx.fnbw_depth == 9,
5994 "Walk context depth %d post sync loop walk",
5995 high_ctx.fnbw_depth);
5998 * execute an async walk of the graph loop, with each child spawns sync walks
6000 high_ctx.fnbw_depth = 0;
6001 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6002 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6004 fib_walk_process_queues(vm, 1);
6006 FOR_EACH_TEST_CHILD(tc)
6009 * we don't really care how many times the children are visisted, as long as
6010 * it is more than once.
6012 FIB_TEST(1 <= vec_len(tc->ctxs),
6013 "child %d visitsed %d times during looped aync spawns sync walk",
6014 ii, vec_len(tc->ctxs));
6019 * execute an async walk of the graph loop, with each child spawns async walks
6021 fib_test_walk_spawns_walks = 2;
6022 high_ctx.fnbw_depth = 0;
6023 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6024 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6026 fib_walk_process_queues(vm, 1);
6028 FOR_EACH_TEST_CHILD(tc)
6031 * we don't really care how many times the children are visisted, as long as
6032 * it is more than once.
6034 FIB_TEST(1 <= vec_len(tc->ctxs),
6035 "child %d visitsed %d times during looped async spawns async walk",
6036 ii, vec_len(tc->ctxs));
6041 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6042 1, // the first child
6043 fib_test_nodes[PARENT_INDEX].sibling);
6048 FOR_EACH_TEST_CHILD(tc)
6050 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6052 fib_node_deinit(&tc->node);
6053 fib_node_unlock(&tc->node);
6055 fib_node_deinit(PARENT());
6058 * The parent will be destroyed when the last lock on it goes.
6059 * this test ensures all the walk objects are unlocking it.
6061 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6062 "Parent was destroyed");
6066 lfib_test_deagg (void)
6068 const mpls_label_t deag_label = 50;
6069 const u32 lfib_index = 0;
6070 const u32 fib_index = 0;
6071 dpo_id_t dpo = DPO_NULL;
6072 const dpo_id_t *dpo1;
6073 fib_node_index_t lfe;
6079 lb_count = pool_elts(load_balance_pool);
6081 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6085 * MPLS enable an interface so we get the MPLS table created
6087 mpls_sw_interface_enable_disable(&mpls_main,
6088 tm->hw[0]->sw_if_index,
6092 * Test the specials stack properly.
6094 fib_prefix_t exp_null_v6_pfx = {
6095 .fp_proto = FIB_PROTOCOL_MPLS,
6097 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6098 .fp_payload_proto = DPO_PROTO_IP6,
6100 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
6101 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
6103 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6104 format_mpls_eos_bit, MPLS_EOS);
6105 fib_entry_contribute_forwarding(lfe,
6106 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6108 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6109 lkd = lookup_dpo_get(dpo1->dpoi_index);
6111 FIB_TEST((fib_index == lkd->lkd_fib_index),
6112 "%U/%U is deag in %d %U",
6113 format_mpls_unicast_label, deag_label,
6114 format_mpls_eos_bit, MPLS_EOS,
6116 format_dpo_id, &dpo, 0);
6117 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6118 "%U/%U is dst deag",
6119 format_mpls_unicast_label, deag_label,
6120 format_mpls_eos_bit, MPLS_EOS);
6121 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
6122 "%U/%U is lookup in interface's table",
6123 format_mpls_unicast_label, deag_label,
6124 format_mpls_eos_bit, MPLS_EOS);
6125 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
6126 "%U/%U is %U dst deag",
6127 format_mpls_unicast_label, deag_label,
6128 format_mpls_eos_bit, MPLS_EOS,
6129 format_dpo_proto, lkd->lkd_proto);
6133 * A route deag route for EOS
6135 fib_prefix_t pfx = {
6136 .fp_proto = FIB_PROTOCOL_MPLS,
6138 .fp_label = deag_label,
6139 .fp_payload_proto = DPO_PROTO_IP4,
6141 lfe = fib_table_entry_path_add(lfib_index,
6144 FIB_ENTRY_FLAG_NONE,
6151 FIB_ROUTE_PATH_FLAG_NONE);
6153 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6155 format_mpls_unicast_label, deag_label,
6156 format_mpls_eos_bit, MPLS_EOS);
6158 fib_entry_contribute_forwarding(lfe,
6159 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6161 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6162 lkd = lookup_dpo_get(dpo1->dpoi_index);
6164 FIB_TEST((fib_index == lkd->lkd_fib_index),
6165 "%U/%U is deag in %d %U",
6166 format_mpls_unicast_label, deag_label,
6167 format_mpls_eos_bit, MPLS_EOS,
6169 format_dpo_id, &dpo, 0);
6170 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6171 "%U/%U is dst deag",
6172 format_mpls_unicast_label, deag_label,
6173 format_mpls_eos_bit, MPLS_EOS);
6174 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
6175 "%U/%U is %U dst deag",
6176 format_mpls_unicast_label, deag_label,
6177 format_mpls_eos_bit, MPLS_EOS,
6178 format_dpo_proto, lkd->lkd_proto);
6180 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6182 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6184 "%U/%U not present",
6185 format_mpls_unicast_label, deag_label,
6186 format_mpls_eos_bit, MPLS_EOS);
6189 * A route deag route for non-EOS
6191 pfx.fp_eos = MPLS_NON_EOS;
6192 lfe = fib_table_entry_path_add(lfib_index,
6195 FIB_ENTRY_FLAG_NONE,
6202 FIB_ROUTE_PATH_FLAG_NONE);
6204 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6206 format_mpls_unicast_label, deag_label,
6207 format_mpls_eos_bit, MPLS_NON_EOS);
6209 fib_entry_contribute_forwarding(lfe,
6210 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6212 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6213 lkd = lookup_dpo_get(dpo1->dpoi_index);
6215 FIB_TEST((fib_index == lkd->lkd_fib_index),
6216 "%U/%U is deag in %d %U",
6217 format_mpls_unicast_label, deag_label,
6218 format_mpls_eos_bit, MPLS_NON_EOS,
6220 format_dpo_id, &dpo, 0);
6221 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6222 "%U/%U is dst deag",
6223 format_mpls_unicast_label, deag_label,
6224 format_mpls_eos_bit, MPLS_NON_EOS);
6226 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
6227 "%U/%U is %U dst deag",
6228 format_mpls_unicast_label, deag_label,
6229 format_mpls_eos_bit, MPLS_NON_EOS,
6230 format_dpo_proto, lkd->lkd_proto);
6232 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6234 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6236 "%U/%U not present",
6237 format_mpls_unicast_label, deag_label,
6238 format_mpls_eos_bit, MPLS_EOS);
6241 mpls_sw_interface_enable_disable(&mpls_main,
6242 tm->hw[0]->sw_if_index,
6247 * +1 for the drop LB in the MPLS tables.
6249 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6250 "Load-balance resources freed %d of %d",
6251 lb_count+1, pool_elts(load_balance_pool));
6254 static clib_error_t *
6255 lfib_test (vlib_main_t * vm,
6256 unformat_input_t * input,
6257 vlib_cli_command_t * cmd_arg)
6259 fib_test_mk_intf(4);
6266 static clib_error_t *
6267 fib_test (vlib_main_t * vm,
6268 unformat_input_t * input,
6269 vlib_cli_command_t * cmd_arg)
6271 fib_test_mk_intf(4);
6273 if (unformat (input, "ip"))
6278 else if (unformat (input, "gre"))
6282 else if (unformat (input, "label"))
6286 else if (unformat (input, "ae"))
6290 else if (unformat (input, "walk"))
6297 * These walk UT aren't run as part of the full suite, since the
6298 * fib-walk process must be disabled in order for the tests to work
6312 VLIB_CLI_COMMAND (test_fib_command, static) = {
6314 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6315 .function = fib_test,
6318 VLIB_CLI_COMMAND (test_lfib_command, static) = {
6319 .path = "test lfib",
6320 .short_help = "mpls label fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6321 .function = lfib_test,
6325 fib_test_init (vlib_main_t *vm)
6330 VLIB_INIT_FUNCTION (fib_test_init);