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>
32 #include <vnet/fib/fib_urpf_list.h>
34 #define FIB_TEST_I(_cond, _comment, _args...) \
36 int _evald = (_cond); \
38 fformat(stderr, "FAIL:%d: " _comment "\n", \
41 fformat(stderr, "PASS:%d: " _comment "\n", \
46 #define FIB_TEST(_cond, _comment, _args...) \
48 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
50 ASSERT(!("FAIL: " _comment)); \
55 * A 'i'm not fussed is this is not efficient' store of test data
57 typedef struct test_main_t_ {
61 u32 hw_if_indicies[4];
65 vnet_hw_interface_t * hw[4];
68 static test_main_t test_main;
70 /* fake ethernet device class, distinct from "fake-ethX" */
71 static u8 * format_test_interface_name (u8 * s, va_list * args)
73 u32 dev_instance = va_arg (*args, u32);
74 return format (s, "test-eth%d", dev_instance);
77 static uword dummy_interface_tx (vlib_main_t * vm,
78 vlib_node_runtime_t * node,
81 clib_warning ("you shouldn't be here, leaking buffers...");
82 return frame->n_vectors;
85 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
86 .name = "Test interface",
87 .format_device_name = format_test_interface_name,
88 .tx_function = dummy_interface_tx,
91 static u8 *hw_address;
94 fib_test_mk_intf (u32 ninterfaces)
96 clib_error_t * error = NULL;
97 test_main_t *tm = &test_main;
101 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
106 vec_add1(hw_address, byte);
109 for (i = 0; i < ninterfaces; i++)
113 error = ethernet_register_interface(vnet_get_main(),
114 ethernet_hw_interface_class.index,
117 &tm->hw_if_indicies[i],
118 /* flag change */ 0);
120 FIB_TEST((NULL == error), "ADD interface %d", i);
122 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
123 tm->hw_if_indicies[i]);
124 vec_validate (ip4_main.fib_index_by_sw_if_index, tm->hw[i]->sw_if_index);
125 vec_validate (ip6_main.fib_index_by_sw_if_index, tm->hw[i]->sw_if_index);
126 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
127 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
128 error = vnet_sw_interface_set_flags(vnet_get_main(),
129 tm->hw[i]->sw_if_index,
130 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
131 FIB_TEST((NULL == error), "UP interface %d", i);
134 * re-eval after the inevitable realloc
136 for (i = 0; i < ninterfaces; i++)
138 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
139 tm->hw_if_indicies[i]);
143 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
145 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
146 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
147 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
148 fib_table_lookup(fib_index, (_via_prefix))); \
149 FIB_TEST(!dpo_cmp(_via_dpo, \
150 load_balance_get_bucket(_rec_dpo->dpoi_index, \
152 "%U is recursive via %U", \
153 format_fib_prefix, (_rec_prefix), \
154 format_fib_prefix, _via_prefix); \
157 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
159 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
160 fib_table_lookup_exact_match(fib_index, (_prefix))); \
161 const dpo_id_t *_dpo1 = \
162 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
163 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
164 format_dpo_type, _dpo1->dpoi_type); \
165 FIB_TEST((_ai == _dpo1->dpoi_index), \
166 "%U bucket %d resolves via %U", \
167 format_fib_prefix, (_prefix), \
169 format_dpo_id, _dpo1, 0); \
172 #define FIB_TEST_RPF(_cond, _comment, _args...) \
174 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
180 fib_test_urpf_is_equal (fib_node_index_t fei,
181 fib_forward_chain_type_t fct,
184 dpo_id_t dpo = DPO_NULL;
185 fib_urpf_list_t *urpf;
192 fib_entry_contribute_forwarding(fei, fct, &dpo);
193 ui = load_balance_get_urpf(dpo.dpoi_index);
195 urpf = fib_urpf_list_get(ui);
197 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
198 "RPF:%U len %d == %d",
199 format_fib_urpf_list, ui,
200 num, vec_len(urpf->furpf_itfs));
201 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
202 "RPF:%U check-size %d == %d",
203 format_fib_urpf_list, ui,
204 num, vec_len(urpf->furpf_itfs));
206 for (ii = 0; ii < num; ii++)
208 adj_index_t ai = va_arg(ap, adj_index_t);
210 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
211 "RPF:%d item:%d - %d == %d",
212 ui, ii, ai, urpf->furpf_itfs[ii]);
213 FIB_TEST_RPF(fib_urpf_check(ui, ai),
227 * In the default table check for the presence and correct forwarding
228 * of the special entries
230 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
231 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
232 const ip_adjacency_t *adj;
233 const load_balance_t *lb;
239 ip46_address_t nh_10_10_10_1 = {
240 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
243 ip46_address_t nh_10_10_10_2 = {
244 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
249 /* Find or create FIB table 11 */
250 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
252 for (ii = 0; ii < 4; ii++)
254 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
257 fib_prefix_t pfx_0_0_0_0_s_0 = {
259 .fp_proto = FIB_PROTOCOL_IP4,
269 .fp_proto = FIB_PROTOCOL_IP4,
277 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
279 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
280 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
281 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
282 "Default route is DROP");
285 fei = fib_table_lookup(fib_index, &pfx);
286 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
287 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
288 "all 0s route is DROP");
290 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
292 fei = fib_table_lookup(fib_index, &pfx);
293 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
294 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
295 "all 1s route is DROP");
297 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
299 fei = fib_table_lookup(fib_index, &pfx);
300 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
301 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
302 "all-mcast route is DROP");
304 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
306 fei = fib_table_lookup(fib_index, &pfx);
307 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
308 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
309 "class-e route is DROP");
312 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
313 * all of which are special sourced and so none of which share path-lists.
314 * There are also 6 entries, and 6 non-shared path-lists, in the v6 default
318 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
319 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
320 fib_path_list_pool_size());
321 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
322 fib_entry_pool_size());
325 * add interface routes.
326 * validate presence of /24 attached and /32 recieve.
327 * test for the presence of the receive address in the glean and local adj
329 fib_prefix_t local_pfx = {
331 .fp_proto = FIB_PROTOCOL_IP4,
334 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
339 fib_table_entry_update_one_path(fib_index, &local_pfx,
340 FIB_SOURCE_INTERFACE,
341 (FIB_ENTRY_FLAG_CONNECTED |
342 FIB_ENTRY_FLAG_ATTACHED),
345 tm->hw[0]->sw_if_index,
346 ~0, // invalid fib index
349 FIB_ROUTE_PATH_FLAG_NONE);
350 fei = fib_table_lookup(fib_index, &local_pfx);
351 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
352 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
353 fib_entry_get_flags(fei)),
354 "Flags set on attached interface");
356 ai = fib_entry_get_adj(fei);
357 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
359 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
360 "attached interface adj is glean");
361 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
362 &adj->sub_type.glean.receive_addr)),
363 "attached interface adj is receive ok");
365 local_pfx.fp_len = 32;
366 fib_table_entry_update_one_path(fib_index, &local_pfx,
367 FIB_SOURCE_INTERFACE,
368 (FIB_ENTRY_FLAG_CONNECTED |
369 FIB_ENTRY_FLAG_LOCAL),
372 tm->hw[0]->sw_if_index,
373 ~0, // invalid fib index
376 FIB_ROUTE_PATH_FLAG_NONE);
377 fei = fib_table_lookup(fib_index, &local_pfx);
378 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
379 fib_entry_get_flags(fei)),
380 "Flags set on local interface");
382 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
384 dpo = fib_entry_contribute_ip_forwarding(fei);
385 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
386 "RPF list for local length 0");
387 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
388 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
389 "local interface adj is local");
390 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
392 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
394 "local interface adj is receive ok");
396 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
398 FIB_SOURCE_INTERFACE)),
399 "2 Interface Source'd prefixes");
402 * +2 interface routes +2 non-shared path-lists
404 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
405 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
406 fib_path_list_pool_size());
407 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
408 fib_entry_pool_size());
411 * Modify the default route to be via an adj not yet known.
412 * this sources the defalut route with the API source, which is
413 * a higher preference to the DEFAULT_ROUTE source
415 pfx.fp_addr.ip4.as_u32 = 0;
417 fib_table_entry_path_add(fib_index, &pfx,
422 tm->hw[0]->sw_if_index,
423 ~0, // invalid fib index
426 FIB_ROUTE_PATH_FLAG_NONE);
427 fei = fib_table_lookup(fib_index, &pfx);
428 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
429 "Flags set on API route");
431 FIB_TEST((fei == dfrt), "default route same index");
432 ai = fib_entry_get_adj(fei);
433 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
435 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
436 "adj is incomplete");
437 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
438 "adj nbr next-hop ok");
439 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
442 "1 API Source'd prefixes");
445 * find the adj in the shared db
447 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
450 tm->hw[0]->sw_if_index);
451 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
452 adj_unlock(locked_ai);
455 * +1 shared path-list
457 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
458 fib_path_list_db_size());
459 FIB_TEST((NBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
460 fib_path_list_pool_size());
461 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
462 fib_entry_pool_size());
465 * remove the API source from the default route. We expected
466 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
468 pfx.fp_addr.ip4.as_u32 = 0;
470 fib_table_entry_path_remove(fib_index, &pfx,
474 tm->hw[0]->sw_if_index,
475 ~0, // non-recursive path, so no FIB index
477 FIB_ROUTE_PATH_FLAG_NONE);
479 fei = fib_table_lookup(fib_index, &pfx);
481 FIB_TEST((fei == dfrt), "default route same index");
482 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
483 "Default route is DROP");
486 * -1 shared-path-list
488 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
489 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
490 fib_path_list_pool_size());
491 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
492 fib_entry_pool_size());
495 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
497 fib_prefix_t pfx_10_10_10_1_s_32 = {
499 .fp_proto = FIB_PROTOCOL_IP4,
502 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
505 fib_prefix_t pfx_10_10_10_2_s_32 = {
507 .fp_proto = FIB_PROTOCOL_IP4,
510 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
513 fib_prefix_t pfx_11_11_11_11_s_32 = {
515 .fp_proto = FIB_PROTOCOL_IP4,
518 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
522 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
524 ip46_address_t nh_12_12_12_12 = {
525 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
527 adj_index_t ai_12_12_12_12;
530 * Add a route via an incomplete ADJ. then complete the ADJ
531 * Expect the route LB is updated to use complete adj type.
533 fei = fib_table_entry_update_one_path(fib_index,
534 &pfx_11_11_11_11_s_32,
536 FIB_ENTRY_FLAG_ATTACHED,
538 &pfx_10_10_10_1_s_32.fp_addr,
539 tm->hw[0]->sw_if_index,
540 ~0, // invalid fib index
543 FIB_ROUTE_PATH_FLAG_NONE);
545 dpo = fib_entry_contribute_ip_forwarding(fei);
546 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
547 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
548 "11.11.11.11/32 via incomplete adj");
550 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
552 &pfx_10_10_10_1_s_32.fp_addr,
553 tm->hw[0]->sw_if_index);
554 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
555 adj = adj_get(ai_01);
556 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
557 "adj is incomplete");
558 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
559 &adj->sub_type.nbr.next_hop)),
560 "adj nbr next-hop ok");
562 adj_nbr_update_rewrite(ai_01, eth_addr);
563 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
565 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
566 &adj->sub_type.nbr.next_hop)),
567 "adj nbr next-hop ok");
568 ai = fib_entry_get_adj(fei);
569 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
571 dpo = fib_entry_contribute_ip_forwarding(fei);
572 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
573 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
574 "11.11.11.11/32 via complete adj");
575 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
576 tm->hw[0]->sw_if_index),
577 "RPF list for adj-fib contains adj");
579 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
582 tm->hw[1]->sw_if_index);
583 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
584 adj = adj_get(ai_12_12_12_12);
585 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
586 "adj is incomplete");
587 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
588 &adj->sub_type.nbr.next_hop)),
589 "adj nbr next-hop ok");
590 adj_nbr_update_rewrite(ai_12_12_12_12, eth_addr);
591 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
597 fei = fib_table_entry_update_one_path(fib_index,
598 &pfx_10_10_10_1_s_32,
600 FIB_ENTRY_FLAG_ATTACHED,
602 &pfx_10_10_10_1_s_32.fp_addr,
603 tm->hw[0]->sw_if_index,
604 ~0, // invalid fib index
607 FIB_ROUTE_PATH_FLAG_NONE);
608 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
609 "Flags set on adj-fib");
610 ai = fib_entry_get_adj(fei);
611 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
613 fib_table_entry_path_remove(fib_index,
614 &pfx_11_11_11_11_s_32,
617 &pfx_10_10_10_1_s_32.fp_addr,
618 tm->hw[0]->sw_if_index,
619 ~0, // invalid fib index
621 FIB_ROUTE_PATH_FLAG_NONE);
625 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
627 &pfx_10_10_10_2_s_32.fp_addr,
628 tm->hw[0]->sw_if_index);
629 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
630 adj = adj_get(ai_02);
631 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
632 "adj is incomplete");
633 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
634 &adj->sub_type.nbr.next_hop)),
635 "adj nbr next-hop ok");
637 adj_nbr_update_rewrite(ai_02, eth_addr);
638 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
640 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
641 &adj->sub_type.nbr.next_hop)),
642 "adj nbr next-hop ok");
643 FIB_TEST((ai_01 != ai_02), "ADJs are different");
645 fib_table_entry_update_one_path(fib_index,
646 &pfx_10_10_10_2_s_32,
650 &pfx_10_10_10_2_s_32.fp_addr,
651 tm->hw[0]->sw_if_index,
652 ~0, // invalid fib index
655 FIB_ROUTE_PATH_FLAG_NONE);
657 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
658 ai = fib_entry_get_adj(fei);
659 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
662 * +2 adj-fibs, and their non-shared path-lists
664 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
665 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
666 fib_path_list_pool_size());
667 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
668 fib_entry_pool_size());
671 * Add 2 routes via the first ADJ. ensure path-list sharing
673 fib_prefix_t pfx_1_1_1_1_s_32 = {
675 .fp_proto = FIB_PROTOCOL_IP4,
678 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
682 fib_table_entry_path_add(fib_index,
688 tm->hw[0]->sw_if_index,
689 ~0, // invalid fib index
692 FIB_ROUTE_PATH_FLAG_NONE);
693 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
694 ai = fib_entry_get_adj(fei);
695 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
698 * +1 entry and a shared path-list
700 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
701 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
702 fib_path_list_pool_size());
703 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
704 fib_entry_pool_size());
707 fib_prefix_t pfx_1_1_2_0_s_24 = {
709 .fp_proto = FIB_PROTOCOL_IP4,
711 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
715 fib_table_entry_path_add(fib_index,
721 tm->hw[0]->sw_if_index,
722 ~0, // invalid fib index
725 FIB_ROUTE_PATH_FLAG_NONE);
726 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
727 ai = fib_entry_get_adj(fei);
728 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
733 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
734 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
735 fib_path_list_pool_size());
736 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
737 fib_entry_pool_size());
740 * modify 1.1.2.0/24 to use multipath.
742 fib_table_entry_path_add(fib_index,
748 tm->hw[0]->sw_if_index,
749 ~0, // invalid fib index
752 FIB_ROUTE_PATH_FLAG_NONE);
753 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
754 dpo = fib_entry_contribute_ip_forwarding(fei);
755 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
756 1, tm->hw[0]->sw_if_index),
757 "RPF list for 1.1.2.0/24 contains both adjs");
759 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
760 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
761 FIB_TEST((ai_01 == dpo1->dpoi_index),
762 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
763 ai_01, dpo1->dpoi_index);
765 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
766 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
767 FIB_TEST((ai_02 == dpo1->dpoi_index),
768 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
773 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
774 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
775 fib_path_list_pool_size());
776 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
777 fib_entry_pool_size());
782 fib_table_entry_path_remove(fib_index,
787 tm->hw[0]->sw_if_index,
790 FIB_ROUTE_PATH_FLAG_NONE);
791 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
792 dpo = fib_entry_contribute_ip_forwarding(fei);
793 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
794 1, tm->hw[0]->sw_if_index),
795 "RPF list for 1.1.2.0/24 contains one adj");
797 ai = fib_entry_get_adj(fei);
798 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
803 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
804 fib_path_list_db_size());
805 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
806 fib_path_list_pool_size());
807 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
808 fib_entry_pool_size());
811 * Add 2 recursive routes:
812 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
813 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
815 fib_prefix_t bgp_100_pfx = {
817 .fp_proto = FIB_PROTOCOL_IP4,
819 /* 100.100.100.100/32 */
820 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
824 ip46_address_t nh_1_1_1_1 = {
825 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
828 fei = fib_table_entry_path_add(fib_index,
834 ~0, // no index provided.
835 fib_index, // nexthop in same fib as route
838 FIB_ROUTE_PATH_FLAG_NONE);
840 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
841 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
842 tm->hw[0]->sw_if_index),
843 "RPF list for adj-fib contains adj");
846 * +1 entry and +1 shared-path-list
848 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
849 fib_path_list_db_size());
850 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
851 fib_path_list_pool_size());
852 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
853 fib_entry_pool_size());
855 fib_prefix_t bgp_101_pfx = {
857 .fp_proto = FIB_PROTOCOL_IP4,
859 /* 100.100.100.101/32 */
860 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
864 fib_table_entry_path_add(fib_index,
870 ~0, // no index provided.
871 fib_index, // nexthop in same fib as route
874 FIB_ROUTE_PATH_FLAG_NONE);
876 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
877 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
878 tm->hw[0]->sw_if_index),
879 "RPF list for adj-fib contains adj");
882 * +1 entry, but the recursive path-list is shared.
884 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
885 fib_path_list_db_size());
886 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
887 fib_path_list_pool_size());
888 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
889 fib_entry_pool_size());
892 * An EXCLUSIVE route; one where the user (me) provides the exclusive
893 * adjacency through which the route will resovle
895 fib_prefix_t ex_pfx = {
897 .fp_proto = FIB_PROTOCOL_IP4,
900 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
904 fib_table_entry_special_add(fib_index,
907 FIB_ENTRY_FLAG_EXCLUSIVE,
909 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
910 FIB_TEST((ai == fib_entry_get_adj(fei)),
911 "Exclusive route links to user adj");
913 fib_table_entry_special_remove(fib_index,
916 FIB_TEST(FIB_NODE_INDEX_INVALID ==
917 fib_table_lookup_exact_match(fib_index, &ex_pfx),
918 "Exclusive reoute removed");
921 * An EXCLUSIVE route; one where the user (me) provides the exclusive
922 * adjacency through which the route will resovle
924 dpo_id_t ex_dpo = DPO_NULL;
926 lookup_dpo_add_or_lock_w_fib_index(fib_index,
928 LOOKUP_INPUT_DST_ADDR,
929 LOOKUP_TABLE_FROM_CONFIG,
932 fib_table_entry_special_dpo_add(fib_index,
935 FIB_ENTRY_FLAG_EXCLUSIVE,
937 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
938 dpo = fib_entry_contribute_ip_forwarding(fei);
939 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
940 "exclusive remote uses lookup DPO");
942 fib_table_entry_special_remove(fib_index,
945 FIB_TEST(FIB_NODE_INDEX_INVALID ==
946 fib_table_lookup_exact_match(fib_index, &ex_pfx),
947 "Exclusive reoute removed");
951 * Add a recursive route:
952 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
954 fib_prefix_t bgp_200_pfx = {
956 .fp_proto = FIB_PROTOCOL_IP4,
958 /* 200.200.200.200/32 */
959 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
963 fib_prefix_t pfx_1_1_1_2_s_32 = {
965 .fp_proto = FIB_PROTOCOL_IP4,
967 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
971 fib_table_entry_path_add(fib_index,
976 &pfx_1_1_1_2_s_32.fp_addr,
977 ~0, // no index provided.
978 fib_index, // nexthop in same fib as route
981 FIB_ROUTE_PATH_FLAG_NONE);
983 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
986 * the adj should be recursive via drop, since the route resolves via
987 * the default route, which is itself a DROP
989 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
990 dpo1 = fib_entry_contribute_ip_forwarding(fei);
991 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
992 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
993 "RPF list for 1.1.1.2/32 contains 0 adjs");
996 * +2 entry and +1 shared-path-list
998 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
999 fib_path_list_db_size());
1000 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1001 fib_path_list_pool_size());
1002 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1003 fib_entry_pool_size());
1006 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1007 * The paths are sort by NH first. in this case the the path with greater
1008 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1010 fib_prefix_t pfx_1_2_3_4_s_32 = {
1012 .fp_proto = FIB_PROTOCOL_IP4,
1014 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1017 fib_table_entry_path_add(fib_index,
1020 FIB_ENTRY_FLAG_NONE,
1023 tm->hw[0]->sw_if_index,
1027 FIB_ROUTE_PATH_FLAG_NONE);
1028 fei = fib_table_entry_path_add(fib_index,
1031 FIB_ENTRY_FLAG_NONE,
1034 tm->hw[1]->sw_if_index,
1038 FIB_ROUTE_PATH_FLAG_NONE);
1040 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1041 dpo = fib_entry_contribute_ip_forwarding(fei);
1042 lb = load_balance_get(dpo->dpoi_index);
1043 FIB_TEST((lb->lb_n_buckets == 4),
1044 "1.2.3.4/32 LB has %d bucket",
1047 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1048 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1049 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1050 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1052 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1053 tm->hw[0]->sw_if_index,
1054 tm->hw[1]->sw_if_index),
1055 "RPF list for 1.2.3.4/32 contains both adjs");
1059 * Unequal Cost load-balance. 4:1 ratio.
1060 * fits in a 16 bucket LB with ratio 13:3
1062 fib_prefix_t pfx_1_2_3_5_s_32 = {
1064 .fp_proto = FIB_PROTOCOL_IP4,
1066 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1069 fib_table_entry_path_add(fib_index,
1072 FIB_ENTRY_FLAG_NONE,
1075 tm->hw[1]->sw_if_index,
1079 FIB_ROUTE_PATH_FLAG_NONE);
1080 fei = fib_table_entry_path_add(fib_index,
1083 FIB_ENTRY_FLAG_NONE,
1086 tm->hw[0]->sw_if_index,
1090 FIB_ROUTE_PATH_FLAG_NONE);
1092 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1093 dpo = fib_entry_contribute_ip_forwarding(fei);
1094 lb = load_balance_get(dpo->dpoi_index);
1095 FIB_TEST((lb->lb_n_buckets == 16),
1096 "1.2.3.5/32 LB has %d bucket",
1099 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1100 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1101 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1102 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1103 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1104 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1105 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1106 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1107 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1108 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1109 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1110 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1111 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1112 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1113 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1114 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1116 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1117 tm->hw[0]->sw_if_index,
1118 tm->hw[1]->sw_if_index),
1119 "RPF list for 1.2.3.4/32 contains both adjs");
1122 * A recursive via the two unequal cost entries
1124 fib_prefix_t bgp_44_s_32 = {
1126 .fp_proto = FIB_PROTOCOL_IP4,
1128 /* 200.200.200.201/32 */
1129 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1132 fei = fib_table_entry_path_add(fib_index,
1135 FIB_ENTRY_FLAG_NONE,
1137 &pfx_1_2_3_4_s_32.fp_addr,
1142 FIB_ROUTE_PATH_FLAG_NONE);
1143 fei = fib_table_entry_path_add(fib_index,
1146 FIB_ENTRY_FLAG_NONE,
1148 &pfx_1_2_3_5_s_32.fp_addr,
1153 FIB_ROUTE_PATH_FLAG_NONE);
1155 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1156 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1157 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1158 tm->hw[0]->sw_if_index,
1159 tm->hw[1]->sw_if_index),
1160 "RPF list for 1.2.3.4/32 contains both adjs");
1163 * test the uRPF check functions
1165 dpo_id_t dpo_44 = DPO_NULL;
1168 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1169 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
1171 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
1172 "uRPF check for 68.68.68.68/32 on %d OK",
1173 tm->hw[0]->sw_if_index);
1174 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
1175 "uRPF check for 68.68.68.68/32 on %d OK",
1176 tm->hw[1]->sw_if_index);
1177 FIB_TEST(!fib_urpf_check(urpfi, 99),
1178 "uRPF check for 68.68.68.68/32 on 99 not-OK",
1182 fib_table_entry_delete(fib_index,
1185 fib_table_entry_delete(fib_index,
1188 fib_table_entry_delete(fib_index,
1193 * Add a recursive route:
1194 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
1196 fib_prefix_t bgp_201_pfx = {
1198 .fp_proto = FIB_PROTOCOL_IP4,
1200 /* 200.200.200.201/32 */
1201 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1205 fib_prefix_t pfx_1_1_1_200_s_32 = {
1207 .fp_proto = FIB_PROTOCOL_IP4,
1209 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1213 fib_table_entry_path_add(fib_index,
1216 FIB_ENTRY_FLAG_NONE,
1218 &pfx_1_1_1_200_s_32.fp_addr,
1219 ~0, // no index provided.
1220 fib_index, // nexthop in same fib as route
1223 FIB_ROUTE_PATH_FLAG_NONE);
1225 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1227 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1228 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1229 "Flags set on RR via non-attached");
1230 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1231 "RPF list for BGP route empty");
1234 * +2 entry (BGP & RR) and +1 shared-path-list
1236 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1237 fib_path_list_db_size());
1238 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1239 fib_path_list_pool_size());
1240 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1241 fib_entry_pool_size());
1244 * insert a route that covers the missing 1.1.1.2/32. we epxect
1245 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
1247 fib_prefix_t pfx_1_1_1_0_s_24 = {
1249 .fp_proto = FIB_PROTOCOL_IP4,
1252 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1256 fib_table_entry_path_add(fib_index,
1259 FIB_ENTRY_FLAG_NONE,
1262 tm->hw[0]->sw_if_index,
1263 ~0, // invalid fib index
1266 FIB_ROUTE_PATH_FLAG_NONE);
1267 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
1268 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1269 ai = fib_entry_get_adj(fei);
1270 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
1271 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1272 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1273 ai = fib_entry_get_adj(fei);
1274 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
1275 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1276 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1277 ai = fib_entry_get_adj(fei);
1278 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
1281 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
1283 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1284 fib_path_list_db_size());
1285 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1286 fib_path_list_pool_size());
1287 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1288 fib_entry_pool_size());
1291 * the recursive adj for 200.200.200.200 should be updated.
1293 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1294 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1295 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
1296 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1297 tm->hw[0]->sw_if_index),
1298 "RPF list for BGP route has itf index 0");
1301 * insert a more specific route than 1.1.1.0/24 that also covers the
1302 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
1303 * 200.200.200.200 to resolve through it.
1305 fib_prefix_t pfx_1_1_1_0_s_28 = {
1307 .fp_proto = FIB_PROTOCOL_IP4,
1310 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1314 fib_table_entry_path_add(fib_index,
1317 FIB_ENTRY_FLAG_NONE,
1320 tm->hw[0]->sw_if_index,
1321 ~0, // invalid fib index
1324 FIB_ROUTE_PATH_FLAG_NONE);
1325 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
1326 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1327 ai = fib_entry_get_adj(fei);
1328 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
1331 * +1 entry. +1 shared path-list
1333 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
1334 fib_path_list_db_size());
1335 FIB_TEST((NBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
1336 fib_path_list_pool_size());
1337 FIB_TEST((NBR+14 == fib_entry_pool_size()), "entry pool size is %d",
1338 fib_entry_pool_size());
1341 * the recursive adj for 200.200.200.200 should be updated.
1342 * 200.200.200.201 remains unchanged.
1344 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1345 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1348 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
1350 fib_table_entry_path_remove(fib_index,
1355 tm->hw[0]->sw_if_index,
1358 FIB_ROUTE_PATH_FLAG_NONE);
1359 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
1360 FIB_NODE_INDEX_INVALID),
1361 "1.1.1.0/28 removed");
1362 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
1363 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
1364 "1.1.1.0/28 lookup via /24");
1365 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1366 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1369 * -1 entry. -1 shared path-list
1371 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1372 fib_path_list_db_size());
1373 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1374 fib_path_list_pool_size());
1375 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1376 fib_entry_pool_size());
1379 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
1381 fib_table_entry_path_remove(fib_index,
1386 tm->hw[0]->sw_if_index,
1389 FIB_ROUTE_PATH_FLAG_NONE);
1390 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
1391 FIB_NODE_INDEX_INVALID),
1392 "1.1.1.0/24 removed");
1394 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1395 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1396 "1.1.1.2/32 route is DROP");
1397 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1398 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1399 "1.1.1.200/32 route is DROP");
1401 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1402 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1407 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1408 fib_path_list_db_size());
1409 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1410 fib_path_list_pool_size());
1411 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1412 fib_entry_pool_size());
1415 * insert the missing 1.1.1.2/32
1417 fei = fib_table_entry_path_add(fib_index,
1420 FIB_ENTRY_FLAG_NONE,
1423 tm->hw[0]->sw_if_index,
1424 ~0, // invalid fib index
1427 FIB_ROUTE_PATH_FLAG_NONE);
1428 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1429 ai = fib_entry_get_adj(fei);
1430 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
1432 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1433 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1436 * no change. 1.1.1.2/32 was already there RR sourced.
1438 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1439 fib_path_list_db_size());
1440 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1441 fib_path_list_pool_size());
1442 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1443 fib_entry_pool_size());
1446 * remove 200.200.200.201/32 which does not have a valid via FIB
1448 fib_table_entry_path_remove(fib_index,
1452 &pfx_1_1_1_200_s_32.fp_addr,
1453 ~0, // no index provided.
1456 FIB_ROUTE_PATH_FLAG_NONE);
1459 * -2 entries (BGP and RR). -1 shared path-list;
1461 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1462 FIB_NODE_INDEX_INVALID),
1463 "200.200.200.201/32 removed");
1464 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
1465 FIB_NODE_INDEX_INVALID),
1466 "1.1.1.200/32 removed");
1468 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1469 fib_path_list_db_size());
1470 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1471 fib_path_list_pool_size());
1472 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1473 fib_entry_pool_size());
1476 * remove 200.200.200.200/32 which does have a valid via FIB
1478 fib_table_entry_path_remove(fib_index,
1482 &pfx_1_1_1_2_s_32.fp_addr,
1483 ~0, // no index provided.
1486 FIB_ROUTE_PATH_FLAG_NONE);
1488 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1489 FIB_NODE_INDEX_INVALID),
1490 "200.200.200.200/32 removed");
1491 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
1492 FIB_NODE_INDEX_INVALID),
1493 "1.1.1.2/32 still present");
1496 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
1498 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1499 fib_path_list_db_size());
1500 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1501 fib_path_list_pool_size());
1502 FIB_TEST((NBR+9 == fib_entry_pool_size()), "entry pool size is %d",
1503 fib_entry_pool_size());
1506 * A recursive prefix that has a 2 path load-balance.
1507 * It also shares a next-hop with other BGP prefixes and hence
1508 * test the ref counting of RR sourced prefixes and 2 level LB.
1510 const fib_prefix_t bgp_102 = {
1512 .fp_proto = FIB_PROTOCOL_IP4,
1514 /* 100.100.100.101/32 */
1515 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
1518 fib_table_entry_path_add(fib_index,
1521 FIB_ENTRY_FLAG_NONE,
1523 &pfx_1_1_1_1_s_32.fp_addr,
1524 ~0, // no index provided.
1525 fib_index, // same as route
1528 FIB_ROUTE_PATH_FLAG_NONE);
1529 fib_table_entry_path_add(fib_index,
1532 FIB_ENTRY_FLAG_NONE,
1534 &pfx_1_1_1_2_s_32.fp_addr,
1535 ~0, // no index provided.
1536 fib_index, // same as route's FIB
1539 FIB_ROUTE_PATH_FLAG_NONE);
1540 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1541 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
1542 dpo = fib_entry_contribute_ip_forwarding(fei);
1544 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
1545 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1546 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
1547 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1549 lb = load_balance_get(dpo->dpoi_index);
1550 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
1551 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1552 "First via 10.10.10.1");
1553 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
1554 "Second via 10.10.10.1");
1556 fib_table_entry_path_remove(fib_index,
1560 &pfx_1_1_1_1_s_32.fp_addr,
1561 ~0, // no index provided.
1562 fib_index, // same as route's FIB
1564 FIB_ROUTE_PATH_FLAG_NONE);
1565 fib_table_entry_path_remove(fib_index,
1569 &pfx_1_1_1_2_s_32.fp_addr,
1570 ~0, // no index provided.
1571 fib_index, // same as route's FIB
1573 FIB_ROUTE_PATH_FLAG_NONE);
1574 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1575 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
1578 * remove the remaining recursives
1580 fib_table_entry_path_remove(fib_index,
1584 &pfx_1_1_1_1_s_32.fp_addr,
1585 ~0, // no index provided.
1586 fib_index, // same as route's FIB
1588 FIB_ROUTE_PATH_FLAG_NONE);
1589 fib_table_entry_path_remove(fib_index,
1593 &pfx_1_1_1_1_s_32.fp_addr,
1594 ~0, // no index provided.
1595 fib_index, // same as route's FIB
1597 FIB_ROUTE_PATH_FLAG_NONE);
1598 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
1599 FIB_NODE_INDEX_INVALID),
1600 "100.100.100.100/32 removed");
1601 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
1602 FIB_NODE_INDEX_INVALID),
1603 "100.100.100.101/32 removed");
1606 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
1608 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1609 fib_path_list_db_size());
1610 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1611 fib_path_list_pool_size());
1612 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1613 fib_entry_pool_size());
1616 * Add a recursive route via a connected cover, using an adj-fib that does exist
1618 fib_table_entry_path_add(fib_index,
1621 FIB_ENTRY_FLAG_NONE,
1624 ~0, // no index provided.
1625 fib_index, // Same as route's FIB
1628 FIB_ROUTE_PATH_FLAG_NONE);
1631 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
1633 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1634 fib_path_list_db_size());
1635 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1636 fib_path_list_pool_size());
1637 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1638 fib_entry_pool_size());
1640 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
1641 dpo = fib_entry_contribute_ip_forwarding(fei);
1643 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
1644 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1646 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1647 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
1649 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1650 "Flags set on RR via existing attached");
1653 * Add a recursive route via a connected cover, using and adj-fib that does
1656 ip46_address_t nh_10_10_10_3 = {
1657 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
1659 fib_prefix_t pfx_10_10_10_3 = {
1661 .fp_proto = FIB_PROTOCOL_IP4,
1662 .fp_addr = nh_10_10_10_3,
1665 fib_table_entry_path_add(fib_index,
1668 FIB_ENTRY_FLAG_NONE,
1671 ~0, // no index provided.
1675 FIB_ROUTE_PATH_FLAG_NONE);
1678 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
1679 * one unshared non-recursive via 10.10.10.3
1681 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1682 fib_path_list_db_size());
1683 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1684 fib_path_list_pool_size());
1685 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1686 fib_entry_pool_size());
1688 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1691 tm->hw[0]->sw_if_index);
1693 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
1694 dpo = fib_entry_contribute_ip_forwarding(fei);
1695 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
1696 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1698 ai = fib_entry_get_adj(fei);
1699 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
1700 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
1701 fib_entry_get_flags(fei)),
1702 "Flags set on RR via non-existing attached");
1704 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1705 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
1710 * remove the recursives
1712 fib_table_entry_path_remove(fib_index,
1717 ~0, // no index provided.
1718 fib_index, // same as route's FIB
1720 FIB_ROUTE_PATH_FLAG_NONE);
1721 fib_table_entry_path_remove(fib_index,
1726 ~0, // no index provided.
1727 fib_index, // same as route's FIB
1729 FIB_ROUTE_PATH_FLAG_NONE);
1731 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1732 FIB_NODE_INDEX_INVALID),
1733 "200.200.200.201/32 removed");
1734 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1735 FIB_NODE_INDEX_INVALID),
1736 "200.200.200.200/32 removed");
1737 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
1738 FIB_NODE_INDEX_INVALID),
1739 "10.10.10.3/32 removed");
1742 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
1743 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
1745 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1746 fib_path_list_db_size());
1747 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1748 fib_path_list_pool_size());
1749 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1750 fib_entry_pool_size());
1755 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
1757 fib_prefix_t pfx_5_5_5_5_s_32 = {
1759 .fp_proto = FIB_PROTOCOL_IP4,
1761 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
1764 fib_prefix_t pfx_5_5_5_6_s_32 = {
1766 .fp_proto = FIB_PROTOCOL_IP4,
1768 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
1771 fib_prefix_t pfx_5_5_5_7_s_32 = {
1773 .fp_proto = FIB_PROTOCOL_IP4,
1775 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
1779 fib_table_entry_path_add(fib_index,
1782 FIB_ENTRY_FLAG_NONE,
1784 &pfx_5_5_5_6_s_32.fp_addr,
1785 ~0, // no index provided.
1789 FIB_ROUTE_PATH_FLAG_NONE);
1790 fib_table_entry_path_add(fib_index,
1793 FIB_ENTRY_FLAG_NONE,
1795 &pfx_5_5_5_7_s_32.fp_addr,
1796 ~0, // no index provided.
1800 FIB_ROUTE_PATH_FLAG_NONE);
1801 fib_table_entry_path_add(fib_index,
1804 FIB_ENTRY_FLAG_NONE,
1806 &pfx_5_5_5_5_s_32.fp_addr,
1807 ~0, // no index provided.
1811 FIB_ROUTE_PATH_FLAG_NONE);
1813 * +3 entries, +3 shared path-list
1815 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1816 fib_path_list_db_size());
1817 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1818 fib_path_list_pool_size());
1819 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1820 fib_entry_pool_size());
1823 * All the entries have only looped paths, so they are all drop
1825 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1826 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1827 "LB for 5.5.5.7/32 is via adj for DROP");
1828 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1829 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1830 "LB for 5.5.5.5/32 is via adj for DROP");
1831 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1832 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1833 "LB for 5.5.5.6/32 is via adj for DROP");
1836 * provide 5.5.5.6/32 with alternate path.
1837 * this will allow only 5.5.5.6/32 to forward with this path, the others
1838 * are still drop since the loop is still present.
1840 fib_table_entry_path_add(fib_index,
1843 FIB_ENTRY_FLAG_NONE,
1846 tm->hw[0]->sw_if_index,
1850 FIB_ROUTE_PATH_FLAG_NONE);
1853 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1854 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1856 lb = load_balance_get(dpo1->dpoi_index);
1857 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
1859 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1860 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1861 FIB_TEST((ai_01 == dpo2->dpoi_index),
1862 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
1864 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1865 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1866 "LB for 5.5.5.7/32 is via adj for DROP");
1867 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1868 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1869 "LB for 5.5.5.5/32 is via adj for DROP");
1872 * remove the alternate path for 5.5.5.6/32
1875 fib_table_entry_path_remove(fib_index,
1880 tm->hw[0]->sw_if_index,
1883 FIB_ROUTE_PATH_FLAG_NONE);
1885 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1886 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1887 "LB for 5.5.5.7/32 is via adj for DROP");
1888 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1889 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1890 "LB for 5.5.5.5/32 is via adj for DROP");
1891 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1892 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1893 "LB for 5.5.5.6/32 is via adj for DROP");
1896 * break the loop by giving 5.5.5.5/32 a new set of paths
1897 * expect all to forward via this new path.
1899 fib_table_entry_update_one_path(fib_index,
1902 FIB_ENTRY_FLAG_NONE,
1905 tm->hw[0]->sw_if_index,
1906 ~0, // invalid fib index
1909 FIB_ROUTE_PATH_FLAG_NONE);
1911 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1912 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1913 lb = load_balance_get(dpo1->dpoi_index);
1914 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
1916 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1917 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1918 FIB_TEST((ai_01 == dpo2->dpoi_index),
1919 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
1921 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
1922 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1924 lb = load_balance_get(dpo2->dpoi_index);
1925 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1926 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
1927 "5.5.5.5.7 via 5.5.5.5");
1929 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
1930 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1932 lb = load_balance_get(dpo1->dpoi_index);
1933 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1934 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
1935 "5.5.5.5.6 via 5.5.5.7");
1938 * revert back to the loop. so we can remove the prefixes with
1941 fib_table_entry_update_one_path(fib_index,
1944 FIB_ENTRY_FLAG_NONE,
1946 &pfx_5_5_5_6_s_32.fp_addr,
1947 ~0, // no index provided.
1951 FIB_ROUTE_PATH_FLAG_NONE);
1953 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1954 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1955 "LB for 5.5.5.7/32 is via adj for DROP");
1956 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1957 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1958 "LB for 5.5.5.5/32 is via adj for DROP");
1959 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1960 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1961 "LB for 5.5.5.6/32 is via adj for DROP");
1964 * remove all the 5.5.5.x/32 prefixes
1966 fib_table_entry_path_remove(fib_index,
1970 &pfx_5_5_5_6_s_32.fp_addr,
1971 ~0, // no index provided.
1972 fib_index, // same as route's FIB
1974 FIB_ROUTE_PATH_FLAG_NONE);
1975 fib_table_entry_path_remove(fib_index,
1979 &pfx_5_5_5_7_s_32.fp_addr,
1980 ~0, // no index provided.
1981 fib_index, // same as route's FIB
1983 FIB_ROUTE_PATH_FLAG_NONE);
1984 fib_table_entry_path_remove(fib_index,
1988 &pfx_5_5_5_5_s_32.fp_addr,
1989 ~0, // no index provided.
1990 fib_index, // same as route's FIB
1992 FIB_ROUTE_PATH_FLAG_NONE);
1993 fib_table_entry_path_remove(fib_index,
1998 ~0, // no index provided.
1999 fib_index, // same as route's FIB
2001 FIB_ROUTE_PATH_FLAG_NONE);
2004 * -3 entries, -3 shared path-list
2006 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2007 fib_path_list_db_size());
2008 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2009 fib_path_list_pool_size());
2010 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2011 fib_entry_pool_size());
2014 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2016 fib_table_entry_path_add(fib_index,
2019 FIB_ENTRY_FLAG_NONE,
2021 &pfx_5_5_5_6_s_32.fp_addr,
2022 ~0, // no index provided.
2026 FIB_ROUTE_PATH_FLAG_NONE);
2027 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2028 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2029 "1-level 5.5.5.6/32 loop is via adj for DROP");
2031 fib_table_entry_path_remove(fib_index,
2035 &pfx_5_5_5_6_s_32.fp_addr,
2036 ~0, // no index provided.
2037 fib_index, // same as route's FIB
2039 FIB_ROUTE_PATH_FLAG_NONE);
2040 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2041 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2042 "1-level 5.5.5.6/32 loop is removed");
2045 * add-remove test. no change.
2047 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2048 fib_path_list_db_size());
2049 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2050 fib_path_list_pool_size());
2051 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2052 fib_entry_pool_size());
2055 * A recursive route with recursion constraints.
2056 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2058 fib_table_entry_path_add(fib_index,
2061 FIB_ENTRY_FLAG_NONE,
2068 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2070 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2071 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2073 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2074 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2076 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2077 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2080 * save the load-balance. we expect it to be inplace modified
2082 lb = load_balance_get(dpo1->dpoi_index);
2085 * add a covering prefix for the via fib that would otherwise serve
2086 * as the resolving route when the host is removed
2088 fib_table_entry_path_add(fib_index,
2091 FIB_ENTRY_FLAG_NONE,
2094 tm->hw[0]->sw_if_index,
2095 ~0, // invalid fib index
2098 FIB_ROUTE_PATH_FLAG_NONE);
2099 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
2100 ai = fib_entry_get_adj(fei);
2101 FIB_TEST((ai == ai_01),
2102 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
2105 * remove the host via FIB - expect the BGP prefix to be drop
2107 fib_table_entry_path_remove(fib_index,
2112 tm->hw[0]->sw_if_index,
2113 ~0, // invalid fib index
2115 FIB_ROUTE_PATH_FLAG_NONE);
2117 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2118 "adj for 200.200.200.200/32 is recursive via adj for DROP");
2121 * add the via-entry host reoute back. expect to resolve again
2123 fib_table_entry_path_add(fib_index,
2126 FIB_ENTRY_FLAG_NONE,
2129 tm->hw[0]->sw_if_index,
2130 ~0, // invalid fib index
2133 FIB_ROUTE_PATH_FLAG_NONE);
2134 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2135 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2138 * add another path for the recursive. it will then have 2.
2140 fib_prefix_t pfx_1_1_1_3_s_32 = {
2142 .fp_proto = FIB_PROTOCOL_IP4,
2144 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
2147 fib_table_entry_path_add(fib_index,
2150 FIB_ENTRY_FLAG_NONE,
2153 tm->hw[0]->sw_if_index,
2154 ~0, // invalid fib index
2157 FIB_ROUTE_PATH_FLAG_NONE);
2159 fib_table_entry_path_add(fib_index,
2162 FIB_ENTRY_FLAG_NONE,
2164 &pfx_1_1_1_3_s_32.fp_addr,
2169 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2171 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2172 dpo = fib_entry_contribute_ip_forwarding(fei);
2174 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2175 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2176 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2177 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2178 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2179 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2180 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2181 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2184 * expect the lb-map used by the recursive's load-balance is using both buckets
2186 load_balance_map_t *lbm;
2189 lb = load_balance_get(dpo->dpoi_index);
2191 load_balance_map_lock(lbmi);
2192 lbm = load_balance_map_get(lbmi);
2194 FIB_TEST(lbm->lbm_buckets[0] == 0,
2195 "LB maps's bucket 0 is %d",
2196 lbm->lbm_buckets[0]);
2197 FIB_TEST(lbm->lbm_buckets[1] == 1,
2198 "LB maps's bucket 1 is %d",
2199 lbm->lbm_buckets[1]);
2202 * withdraw one of the /32 via-entrys.
2203 * that ECMP path will be unresolved and forwarding should continue on the
2204 * other available path. this is an iBGP PIC edge failover.
2205 * Test the forwarding changes without re-fetching the adj from the
2206 * recursive entry. this ensures its the same one that is updated; i.e. an
2209 fib_table_entry_path_remove(fib_index,
2214 tm->hw[0]->sw_if_index,
2215 ~0, // invalid fib index
2217 FIB_ROUTE_PATH_FLAG_NONE);
2219 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2220 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
2221 "post PIC 200.200.200.200/32 was inplace modified");
2223 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
2224 "post PIC adj for 200.200.200.200/32 is recursive"
2225 " via adj for 1.1.1.3");
2228 * the LB maps that was locked above should have been modified to remove
2229 * the path that was down, and thus its bucket points to a path that is
2232 FIB_TEST(lbm->lbm_buckets[0] == 1,
2233 "LB maps's bucket 0 is %d",
2234 lbm->lbm_buckets[0]);
2235 FIB_TEST(lbm->lbm_buckets[1] == 1,
2236 "LB maps's bucket 1 is %d",
2237 lbm->lbm_buckets[1]);
2239 load_balance_map_unlock(lb->lb_map);
2242 * add it back. again
2244 fib_table_entry_path_add(fib_index,
2247 FIB_ENTRY_FLAG_NONE,
2250 tm->hw[0]->sw_if_index,
2251 ~0, // invalid fib index
2254 FIB_ROUTE_PATH_FLAG_NONE);
2256 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
2257 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2258 "via adj for 1.1.1.1");
2259 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
2260 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2261 "via adj for 1.1.1.3");
2263 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2264 dpo = fib_entry_contribute_ip_forwarding(fei);
2265 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2266 "post PIC 200.200.200.200/32 was inplace modified");
2269 * add a 3rd path. this makes the LB 16 buckets.
2271 fib_table_entry_path_add(fib_index,
2274 FIB_ENTRY_FLAG_NONE,
2276 &pfx_1_1_1_2_s_32.fp_addr,
2281 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2283 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2284 dpo = fib_entry_contribute_ip_forwarding(fei);
2285 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2286 "200.200.200.200/32 was inplace modified for 3rd path");
2287 FIB_TEST(16 == lb->lb_n_buckets,
2288 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
2291 load_balance_map_lock(lbmi);
2292 lbm = load_balance_map_get(lbmi);
2294 for (ii = 0; ii < 16; ii++)
2296 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2297 "LB Map for 200.200.200.200/32 at %d is %d",
2298 ii, lbm->lbm_buckets[ii]);
2302 * trigger PIC by removing the first via-entry
2303 * the first 6 buckets of the map should map to the next 6
2305 fib_table_entry_path_remove(fib_index,
2310 tm->hw[0]->sw_if_index,
2313 FIB_ROUTE_PATH_FLAG_NONE);
2315 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2316 dpo = fib_entry_contribute_ip_forwarding(fei);
2317 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2318 "200.200.200.200/32 was inplace modified for 3rd path");
2319 FIB_TEST(2 == lb->lb_n_buckets,
2320 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
2322 for (ii = 0; ii < 6; ii++)
2324 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
2325 "LB Map for 200.200.200.200/32 at %d is %d",
2326 ii, lbm->lbm_buckets[ii]);
2328 for (ii = 6; ii < 16; ii++)
2330 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2331 "LB Map for 200.200.200.200/32 at %d is %d",
2332 ii, lbm->lbm_buckets[ii]);
2339 fib_table_entry_path_add(fib_index,
2342 FIB_ENTRY_FLAG_NONE,
2345 tm->hw[0]->sw_if_index,
2349 FIB_ROUTE_PATH_FLAG_NONE);
2351 fib_table_entry_path_remove(fib_index,
2355 &pfx_1_1_1_2_s_32.fp_addr,
2359 MPLS_LABEL_INVALID);
2360 fib_table_entry_path_remove(fib_index,
2368 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2369 fib_table_entry_path_remove(fib_index,
2373 &pfx_1_1_1_3_s_32.fp_addr,
2377 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2378 fib_table_entry_delete(fib_index,
2381 fib_table_entry_delete(fib_index,
2384 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2385 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
2386 "1.1.1.1/28 removed");
2387 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2388 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
2389 "1.1.1.3/32 removed");
2390 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2391 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
2392 "200.200.200.200/32 removed");
2395 * add-remove test. no change.
2397 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2398 fib_path_list_db_size());
2399 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2400 fib_path_list_pool_size());
2401 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2402 fib_entry_pool_size());
2405 * A route whose paths are built up iteratively and then removed
2408 fib_prefix_t pfx_4_4_4_4_s_32 = {
2410 .fp_proto = FIB_PROTOCOL_IP4,
2413 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
2417 fib_table_entry_path_add(fib_index,
2420 FIB_ENTRY_FLAG_NONE,
2423 tm->hw[0]->sw_if_index,
2427 FIB_ROUTE_PATH_FLAG_NONE);
2428 fib_table_entry_path_add(fib_index,
2431 FIB_ENTRY_FLAG_NONE,
2434 tm->hw[0]->sw_if_index,
2438 FIB_ROUTE_PATH_FLAG_NONE);
2439 fib_table_entry_path_add(fib_index,
2442 FIB_ENTRY_FLAG_NONE,
2445 tm->hw[0]->sw_if_index,
2449 FIB_ROUTE_PATH_FLAG_NONE);
2450 FIB_TEST(FIB_NODE_INDEX_INVALID !=
2451 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2452 "4.4.4.4/32 present");
2454 fib_table_entry_delete(fib_index,
2457 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2458 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2459 "4.4.4.4/32 removed");
2462 * add-remove test. no change.
2464 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2465 fib_path_list_db_size());
2466 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2467 fib_path_list_pool_size());
2468 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2469 fib_entry_pool_size());
2472 * A route with multiple paths at once
2474 fib_route_path_t *r_paths = NULL;
2476 for (ii = 0; ii < 4; ii++)
2478 fib_route_path_t r_path = {
2479 .frp_proto = FIB_PROTOCOL_IP4,
2481 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
2483 .frp_sw_if_index = tm->hw[0]->sw_if_index,
2485 .frp_fib_index = ~0,
2487 vec_add1(r_paths, r_path);
2490 fib_table_entry_update(fib_index,
2493 FIB_ENTRY_FLAG_NONE,
2496 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2497 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2498 dpo = fib_entry_contribute_ip_forwarding(fei);
2500 lb = load_balance_get(dpo->dpoi_index);
2501 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
2503 fib_table_entry_delete(fib_index,
2506 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2507 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2508 "4.4.4.4/32 removed");
2512 * add-remove test. no change.
2514 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2515 fib_path_list_db_size());
2516 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2517 fib_path_list_pool_size());
2518 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2519 fib_entry_pool_size());
2522 * A route deag route
2524 fib_table_entry_path_add(fib_index,
2527 FIB_ENTRY_FLAG_NONE,
2534 FIB_ROUTE_PATH_FLAG_NONE);
2536 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2537 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2539 dpo = fib_entry_contribute_ip_forwarding(fei);
2540 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2541 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
2543 FIB_TEST((fib_index == lkd->lkd_fib_index),
2544 "4.4.4.4/32 is deag in %d %U",
2546 format_dpo_id, dpo, 0);
2548 fib_table_entry_delete(fib_index,
2551 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2552 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2553 "4.4.4.4/32 removed");
2557 * add-remove test. no change.
2559 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2560 fib_path_list_db_size());
2561 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2562 fib_path_list_pool_size());
2563 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2564 fib_entry_pool_size());
2568 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
2569 * all of which are via 10.10.10.1, Itf1
2571 fib_table_entry_path_remove(fib_index,
2576 tm->hw[0]->sw_if_index,
2579 FIB_ROUTE_PATH_FLAG_NONE);
2580 fib_table_entry_path_remove(fib_index,
2585 tm->hw[0]->sw_if_index,
2588 FIB_ROUTE_PATH_FLAG_NONE);
2589 fib_table_entry_path_remove(fib_index,
2594 tm->hw[0]->sw_if_index,
2597 FIB_ROUTE_PATH_FLAG_NONE);
2599 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2600 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
2601 "1.1.1.1/32 removed");
2602 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2603 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
2604 "1.1.1.2/32 removed");
2605 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2606 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
2607 "1.1.2.0/24 removed");
2610 * -3 entries and -1 shared path-list
2612 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2613 fib_path_list_db_size());
2614 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2615 fib_path_list_pool_size());
2616 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2617 fib_entry_pool_size());
2620 * An attached-host route. Expect to link to the incomplete adj
2622 fib_prefix_t pfx_4_1_1_1_s_32 = {
2624 .fp_proto = FIB_PROTOCOL_IP4,
2627 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
2630 fib_table_entry_path_add(fib_index,
2633 FIB_ENTRY_FLAG_NONE,
2636 tm->hw[0]->sw_if_index,
2640 FIB_ROUTE_PATH_FLAG_NONE);
2642 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
2643 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
2644 ai = fib_entry_get_adj(fei);
2646 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2648 &pfx_4_1_1_1_s_32.fp_addr,
2649 tm->hw[0]->sw_if_index);
2650 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
2654 * +1 entry and +1 shared path-list
2656 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2657 fib_path_list_db_size());
2658 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2659 fib_path_list_pool_size());
2660 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
2661 fib_entry_pool_size());
2663 fib_table_entry_delete(fib_index,
2667 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2668 fib_path_list_db_size());
2669 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2670 fib_path_list_pool_size());
2671 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2672 fib_entry_pool_size());
2675 * add a v6 prefix via v4 next-hops
2677 fib_prefix_t pfx_2001_s_64 = {
2679 .fp_proto = FIB_PROTOCOL_IP6,
2681 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
2684 fei = fib_table_entry_path_add(0, //default v6 table
2687 FIB_ENTRY_FLAG_NONE,
2690 tm->hw[0]->sw_if_index,
2694 FIB_ROUTE_PATH_FLAG_NONE);
2696 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
2697 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
2698 ai = fib_entry_get_adj(fei);
2700 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
2701 "2001::/64 via ARP-adj");
2702 FIB_TEST((adj->ia_link == FIB_LINK_IP6),
2703 "2001::/64 is link type v6");
2704 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
2705 "2001::/64 ADJ-adj is NH proto v4");
2706 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
2709 * add a uRPF exempt prefix:
2711 * - it's forwarding is drop
2712 * - it's uRPF list is not empty
2713 * - the uRPF list for the default route (it's cover) is empty
2715 fei = fib_table_entry_special_add(fib_index,
2717 FIB_SOURCE_URPF_EXEMPT,
2718 FIB_ENTRY_FLAG_DROP,
2720 dpo = fib_entry_contribute_ip_forwarding(fei);
2721 FIB_TEST(load_balance_is_drop(dpo),
2722 "uRPF exempt 4.1.1.1/32 DROP");
2723 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
2724 "uRPF list for exempt prefix has itf index 0");
2725 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
2726 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2727 "uRPF list for 0.0.0.0/0 empty");
2729 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
2735 fib_table_entry_delete(fib_index,
2736 &pfx_10_10_10_1_s_32,
2738 fib_table_entry_delete(fib_index,
2739 &pfx_10_10_10_2_s_32,
2741 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2742 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
2743 "10.10.10.1/32 adj-fib removed");
2744 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2745 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
2746 "10.10.10.2/32 adj-fib removed");
2749 * -2 entries and -2 non-shared path-list
2751 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2752 fib_path_list_db_size());
2753 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
2754 fib_path_list_pool_size());
2755 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
2756 fib_entry_pool_size());
2759 * unlock the adjacencies for which this test provided a rewrite.
2760 * These are the last locks on these adjs. they should thus go away.
2764 adj_unlock(ai_12_12_12_12);
2766 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2771 * remove the interface prefixes
2773 local_pfx.fp_len = 32;
2774 fib_table_entry_special_remove(fib_index, &local_pfx,
2775 FIB_SOURCE_INTERFACE);
2776 fei = fib_table_lookup(fib_index, &local_pfx);
2778 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2779 fib_table_lookup_exact_match(fib_index, &local_pfx),
2780 "10.10.10.10/32 adj-fib removed");
2782 local_pfx.fp_len = 24;
2783 fib_table_entry_delete(fib_index, &local_pfx,
2784 FIB_SOURCE_INTERFACE);
2786 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2787 fib_table_lookup_exact_match(fib_index, &local_pfx),
2788 "10.10.10.10/24 adj-fib removed");
2791 * -2 entries and -2 non-shared path-list
2793 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2794 fib_path_list_db_size());
2795 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
2796 fib_path_list_pool_size());
2797 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
2798 fib_entry_pool_size());
2801 * Last but not least, remove the VRF
2803 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2806 "NO API Source'd prefixes");
2807 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2810 "NO RR Source'd prefixes");
2811 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2813 FIB_SOURCE_INTERFACE)),
2814 "NO INterface Source'd prefixes");
2816 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
2818 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2819 fib_path_list_db_size());
2820 FIB_TEST((NBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
2821 fib_path_list_pool_size());
2822 FIB_TEST((NBR-5 == fib_entry_pool_size()), "entry pool size is %d",
2823 fib_entry_pool_size());
2824 FIB_TEST((NBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
2825 pool_elts(fib_urpf_list_pool));
2834 * In the default table check for the presence and correct forwarding
2835 * of the special entries
2837 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
2838 const dpo_id_t *dpo, *dpo_drop;
2839 const ip_adjacency_t *adj;
2840 const receive_dpo_t *rd;
2845 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2848 /* via 2001:0:0:1::2 */
2849 ip46_address_t nh_2001_2 = {
2852 [0] = clib_host_to_net_u64(0x2001000000000001),
2853 [1] = clib_host_to_net_u64(0x0000000000000002),
2860 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
2862 /* Find or create FIB table 11 */
2863 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
2865 for (ii = 0; ii < 4; ii++)
2867 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
2870 fib_prefix_t pfx_0_0 = {
2872 .fp_proto = FIB_PROTOCOL_IP6,
2880 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
2881 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
2882 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
2883 "Default route is DROP");
2885 dpo = fib_entry_contribute_ip_forwarding(dfrt);
2886 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2889 &pfx_0_0.fp_addr.ip6)),
2890 "default-route; fwd and non-fwd tables match");
2892 // FIXME - check specials.
2895 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
2896 * each with 6 entries. All entries are special so no path-list sharing.
2899 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
2900 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is %d",
2901 fib_path_list_pool_size());
2902 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
2903 fib_entry_pool_size());
2906 * add interface routes.
2907 * validate presence of /64 attached and /128 recieve.
2908 * test for the presence of the receive address in the glean and local adj
2910 * receive on 2001:0:0:1::1/128
2912 fib_prefix_t local_pfx = {
2914 .fp_proto = FIB_PROTOCOL_IP6,
2918 [0] = clib_host_to_net_u64(0x2001000000000001),
2919 [1] = clib_host_to_net_u64(0x0000000000000001),
2925 fib_table_entry_update_one_path(fib_index, &local_pfx,
2926 FIB_SOURCE_INTERFACE,
2927 (FIB_ENTRY_FLAG_CONNECTED |
2928 FIB_ENTRY_FLAG_ATTACHED),
2931 tm->hw[0]->sw_if_index,
2935 FIB_ROUTE_PATH_FLAG_NONE);
2936 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
2938 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
2940 ai = fib_entry_get_adj(fei);
2941 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
2943 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
2944 "attached interface adj is glean");
2945 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
2946 &adj->sub_type.glean.receive_addr)),
2947 "attached interface adj is receive ok");
2948 dpo = fib_entry_contribute_ip_forwarding(fei);
2949 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2952 &local_pfx.fp_addr.ip6)),
2953 "attached-route; fwd and non-fwd tables match");
2955 local_pfx.fp_len = 128;
2956 fib_table_entry_update_one_path(fib_index, &local_pfx,
2957 FIB_SOURCE_INTERFACE,
2958 (FIB_ENTRY_FLAG_CONNECTED |
2959 FIB_ENTRY_FLAG_LOCAL),
2962 tm->hw[0]->sw_if_index,
2963 ~0, // invalid fib index
2966 FIB_ROUTE_PATH_FLAG_NONE);
2967 fei = fib_table_lookup(fib_index, &local_pfx);
2969 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
2971 dpo = fib_entry_contribute_ip_forwarding(fei);
2972 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2973 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
2974 "local interface adj is local");
2975 rd = receive_dpo_get(dpo->dpoi_index);
2977 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
2979 "local interface adj is receive ok");
2981 dpo = fib_entry_contribute_ip_forwarding(fei);
2982 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2985 &local_pfx.fp_addr.ip6)),
2986 "local-route; fwd and non-fwd tables match");
2989 * +2 entries. +2 unshared path-lists
2991 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
2992 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
2993 fib_path_list_pool_size());
2994 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
2995 fib_entry_pool_size());
2998 * Modify the default route to be via an adj not yet known.
2999 * this sources the defalut route with the API source, which is
3000 * a higher preference to the DEFAULT_ROUTE source
3002 fib_table_entry_path_add(fib_index, &pfx_0_0,
3004 FIB_ENTRY_FLAG_NONE,
3007 tm->hw[0]->sw_if_index,
3011 FIB_ROUTE_PATH_FLAG_NONE);
3012 fei = fib_table_lookup(fib_index, &pfx_0_0);
3014 FIB_TEST((fei == dfrt), "default route same index");
3015 ai = fib_entry_get_adj(fei);
3016 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
3018 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3019 "adj is incomplete");
3020 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
3021 "adj nbr next-hop ok");
3024 * find the adj in the shared db
3026 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3029 tm->hw[0]->sw_if_index);
3030 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
3031 adj_unlock(locked_ai);
3034 * no more entires. +1 shared path-list
3036 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3037 fib_path_list_db_size());
3038 FIB_TEST((NPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
3039 fib_path_list_pool_size());
3040 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3041 fib_entry_pool_size());
3044 * remove the API source from the default route. We expected
3045 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
3047 fib_table_entry_path_remove(fib_index, &pfx_0_0,
3051 tm->hw[0]->sw_if_index,
3054 FIB_ROUTE_PATH_FLAG_NONE);
3055 fei = fib_table_lookup(fib_index, &pfx_0_0);
3057 FIB_TEST((fei == dfrt), "default route same index");
3058 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3059 "Default route is DROP");
3062 * no more entires. -1 shared path-list
3064 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3065 fib_path_list_db_size());
3066 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3067 fib_path_list_pool_size());
3068 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3069 fib_entry_pool_size());
3072 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3074 fib_prefix_t pfx_2001_1_2_s_128 = {
3076 .fp_proto = FIB_PROTOCOL_IP6,
3080 [0] = clib_host_to_net_u64(0x2001000000000001),
3081 [1] = clib_host_to_net_u64(0x0000000000000002),
3086 fib_prefix_t pfx_2001_1_3_s_128 = {
3088 .fp_proto = FIB_PROTOCOL_IP6,
3092 [0] = clib_host_to_net_u64(0x2001000000000001),
3093 [1] = clib_host_to_net_u64(0x0000000000000003),
3099 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
3102 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3104 &pfx_2001_1_2_s_128.fp_addr,
3105 tm->hw[0]->sw_if_index);
3106 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
3107 adj = adj_get(ai_01);
3108 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3109 "adj is incomplete");
3110 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3111 &adj->sub_type.nbr.next_hop)),
3112 "adj nbr next-hop ok");
3114 adj_nbr_update_rewrite(ai_01, eth_addr);
3115 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3117 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3118 &adj->sub_type.nbr.next_hop)),
3119 "adj nbr next-hop ok");
3121 fib_table_entry_update_one_path(fib_index,
3122 &pfx_2001_1_2_s_128,
3124 FIB_ENTRY_FLAG_NONE,
3126 &pfx_2001_1_2_s_128.fp_addr,
3127 tm->hw[0]->sw_if_index,
3131 FIB_ROUTE_PATH_FLAG_NONE);
3133 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
3134 ai = fib_entry_get_adj(fei);
3135 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3139 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3141 &pfx_2001_1_3_s_128.fp_addr,
3142 tm->hw[0]->sw_if_index);
3143 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
3144 adj = adj_get(ai_02);
3145 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3146 "adj is incomplete");
3147 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3148 &adj->sub_type.nbr.next_hop)),
3149 "adj nbr next-hop ok");
3151 adj_nbr_update_rewrite(ai_02, eth_addr);
3152 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3154 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3155 &adj->sub_type.nbr.next_hop)),
3156 "adj nbr next-hop ok");
3157 FIB_TEST((ai_01 != ai_02), "ADJs are different");
3159 fib_table_entry_update_one_path(fib_index,
3160 &pfx_2001_1_3_s_128,
3162 FIB_ENTRY_FLAG_NONE,
3164 &pfx_2001_1_3_s_128.fp_addr,
3165 tm->hw[0]->sw_if_index,
3169 FIB_ROUTE_PATH_FLAG_NONE);
3171 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
3172 ai = fib_entry_get_adj(fei);
3173 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3176 * +2 entries, +2 unshread path-lists.
3178 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3179 fib_path_list_db_size());
3180 FIB_TEST((NPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
3181 fib_path_list_pool_size());
3182 FIB_TEST((NPS+4 == fib_entry_pool_size()), "entry pool size is %d",
3183 fib_entry_pool_size());
3186 * Add a 2 routes via the first ADJ. ensure path-list sharing
3188 fib_prefix_t pfx_2001_a_s_64 = {
3190 .fp_proto = FIB_PROTOCOL_IP6,
3194 [0] = clib_host_to_net_u64(0x200100000000000a),
3195 [1] = clib_host_to_net_u64(0x0000000000000000),
3200 fib_prefix_t pfx_2001_b_s_64 = {
3202 .fp_proto = FIB_PROTOCOL_IP6,
3206 [0] = clib_host_to_net_u64(0x200100000000000b),
3207 [1] = clib_host_to_net_u64(0x0000000000000000),
3213 fib_table_entry_path_add(fib_index,
3216 FIB_ENTRY_FLAG_NONE,
3219 tm->hw[0]->sw_if_index,
3223 FIB_ROUTE_PATH_FLAG_NONE);
3224 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
3225 ai = fib_entry_get_adj(fei);
3226 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3227 fib_table_entry_path_add(fib_index,
3230 FIB_ENTRY_FLAG_NONE,
3233 tm->hw[0]->sw_if_index,
3237 FIB_ROUTE_PATH_FLAG_NONE);
3238 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
3239 ai = fib_entry_get_adj(fei);
3240 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3243 * +2 entries, +1 shared path-list.
3245 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3246 fib_path_list_db_size());
3247 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3248 fib_path_list_pool_size());
3249 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3250 fib_entry_pool_size());
3253 * add a v4 prefix via a v6 next-hop
3255 fib_prefix_t pfx_1_1_1_1_s_32 = {
3257 .fp_proto = FIB_PROTOCOL_IP4,
3259 .ip4.as_u32 = 0x01010101,
3262 fei = fib_table_entry_path_add(0, // default table
3265 FIB_ENTRY_FLAG_NONE,
3268 tm->hw[0]->sw_if_index,
3272 FIB_ROUTE_PATH_FLAG_NONE);
3273 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
3274 "1.1.1.1/32 o v6 route present");
3275 ai = fib_entry_get_adj(fei);
3277 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3278 "1.1.1.1/32 via ARP-adj");
3279 FIB_TEST((adj->ia_link == FIB_LINK_IP4),
3280 "1.1.1.1/32 ADJ-adj is link type v4");
3281 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
3282 "1.1.1.1/32 ADJ-adj is NH proto v6");
3283 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
3288 fib_prefix_t pfx_2001_c_s_64 = {
3290 .fp_proto = FIB_PROTOCOL_IP6,
3294 [0] = clib_host_to_net_u64(0x200100000000000c),
3295 [1] = clib_host_to_net_u64(0x0000000000000000),
3300 fib_table_entry_path_add(fib_index,
3303 FIB_ENTRY_FLAG_ATTACHED,
3306 tm->hw[0]->sw_if_index,
3310 FIB_ROUTE_PATH_FLAG_NONE);
3311 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3312 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
3313 ai = fib_entry_get_adj(fei);
3315 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
3316 "2001:0:0:c/64 attached resolves via glean");
3318 fib_table_entry_path_remove(fib_index,
3323 tm->hw[0]->sw_if_index,
3326 FIB_ROUTE_PATH_FLAG_NONE);
3327 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3328 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
3331 * Shutdown the interface on which we have a connected and through
3332 * which the routes are reachable.
3333 * This will result in the connected, adj-fibs, and routes linking to drop
3334 * The local/for-us prefix continues to receive.
3336 clib_error_t * error;
3338 error = vnet_sw_interface_set_flags(vnet_get_main(),
3339 tm->hw[0]->sw_if_index,
3340 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3341 FIB_TEST((NULL == error), "Interface shutdown OK");
3343 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3344 dpo = fib_entry_contribute_ip_forwarding(fei);
3345 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3346 "2001::b/64 resolves via drop");
3348 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3349 dpo = fib_entry_contribute_ip_forwarding(fei);
3350 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3351 "2001::a/64 resolves via drop");
3352 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3353 dpo = fib_entry_contribute_ip_forwarding(fei);
3354 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3355 "2001:0:0:1::3/64 resolves via drop");
3356 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3357 dpo = fib_entry_contribute_ip_forwarding(fei);
3358 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3359 "2001:0:0:1::2/64 resolves via drop");
3360 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3361 dpo = fib_entry_contribute_ip_forwarding(fei);
3362 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3363 "2001:0:0:1::1/128 not drop");
3364 local_pfx.fp_len = 64;
3365 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3366 dpo = fib_entry_contribute_ip_forwarding(fei);
3367 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3368 "2001:0:0:1/64 resolves via drop");
3373 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3374 fib_path_list_db_size());
3375 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3376 fib_path_list_pool_size());
3377 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3378 fib_entry_pool_size());
3381 * shutdown one of the other interfaces, then add a connected.
3382 * and swap one of the routes to it.
3384 error = vnet_sw_interface_set_flags(vnet_get_main(),
3385 tm->hw[1]->sw_if_index,
3386 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3387 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
3389 fib_prefix_t connected_pfx = {
3391 .fp_proto = FIB_PROTOCOL_IP6,
3394 /* 2001:0:0:2::1/64 */
3396 [0] = clib_host_to_net_u64(0x2001000000000002),
3397 [1] = clib_host_to_net_u64(0x0000000000000001),
3402 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3403 FIB_SOURCE_INTERFACE,
3404 (FIB_ENTRY_FLAG_CONNECTED |
3405 FIB_ENTRY_FLAG_ATTACHED),
3408 tm->hw[1]->sw_if_index,
3412 FIB_ROUTE_PATH_FLAG_NONE);
3413 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
3414 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3415 dpo = fib_entry_contribute_ip_forwarding(fei);
3416 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3417 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
3418 "2001:0:0:2/64 not resolves via drop");
3420 connected_pfx.fp_len = 128;
3421 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3422 FIB_SOURCE_INTERFACE,
3423 (FIB_ENTRY_FLAG_CONNECTED |
3424 FIB_ENTRY_FLAG_LOCAL),
3427 tm->hw[0]->sw_if_index,
3428 ~0, // invalid fib index
3431 FIB_ROUTE_PATH_FLAG_NONE);
3432 fei = fib_table_lookup(fib_index, &connected_pfx);
3434 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3435 dpo = fib_entry_contribute_ip_forwarding(fei);
3436 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3437 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3438 "local interface adj is local");
3439 rd = receive_dpo_get(dpo->dpoi_index);
3440 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
3442 "local interface adj is receive ok");
3445 * +2 entries, +2 unshared path-lists
3447 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3448 fib_path_list_db_size());
3449 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3450 fib_path_list_pool_size());
3451 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3452 fib_entry_pool_size());
3456 * bring the interface back up. we expected the routes to return
3457 * to normal forwarding.
3459 error = vnet_sw_interface_set_flags(vnet_get_main(),
3460 tm->hw[0]->sw_if_index,
3461 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3462 FIB_TEST((NULL == error), "Interface bring-up OK");
3463 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3464 ai = fib_entry_get_adj(fei);
3465 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3466 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3467 ai = fib_entry_get_adj(fei);
3468 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3469 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3470 ai = fib_entry_get_adj(fei);
3471 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3472 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3473 ai = fib_entry_get_adj(fei);
3474 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3475 local_pfx.fp_len = 64;
3476 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3477 ai = fib_entry_get_adj(fei);
3479 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3480 "attached interface adj is glean");
3483 * Delete the interface that the routes reolve through.
3484 * Again no routes are removed. They all point to drop.
3486 * This is considered an error case. The control plane should
3487 * not remove interfaces through which routes resolve, but
3488 * such things can happen. ALL affected routes will drop.
3490 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
3492 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3493 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3494 "2001::b/64 resolves via drop");
3495 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3496 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3497 "2001::b/64 resolves via drop");
3498 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3499 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3500 "2001:0:0:1::3/64 resolves via drop");
3501 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3502 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3503 "2001:0:0:1::2/64 resolves via drop");
3504 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3505 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3506 "2001:0:0:1::1/128 is drop");
3507 local_pfx.fp_len = 64;
3508 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3509 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3510 "2001:0:0:1/64 resolves via drop");
3515 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3516 fib_path_list_db_size());
3517 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3518 fib_path_list_pool_size());
3519 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3520 fib_entry_pool_size());
3523 * Add the interface back. routes stay unresolved.
3525 error = ethernet_register_interface(vnet_get_main(),
3526 test_interface_device_class.index,
3529 &tm->hw_if_indicies[0],
3530 /* flag change */ 0);
3532 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3533 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3534 "2001::b/64 resolves via drop");
3535 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3536 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3537 "2001::b/64 resolves via drop");
3538 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3539 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3540 "2001:0:0:1::3/64 resolves via drop");
3541 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3542 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3543 "2001:0:0:1::2/64 resolves via drop");
3544 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3545 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3546 "2001:0:0:1::1/128 is drop");
3547 local_pfx.fp_len = 64;
3548 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3549 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3550 "2001:0:0:1/64 resolves via drop");
3553 * CLEANUP ALL the routes
3555 fib_table_entry_delete(fib_index,
3558 fib_table_entry_delete(fib_index,
3561 fib_table_entry_delete(fib_index,
3564 fib_table_entry_delete(fib_index,
3565 &pfx_2001_1_3_s_128,
3567 fib_table_entry_delete(fib_index,
3568 &pfx_2001_1_2_s_128,
3570 local_pfx.fp_len = 64;
3571 fib_table_entry_delete(fib_index, &local_pfx,
3572 FIB_SOURCE_INTERFACE);
3573 local_pfx.fp_len = 128;
3574 fib_table_entry_special_remove(fib_index, &local_pfx,
3575 FIB_SOURCE_INTERFACE);
3576 connected_pfx.fp_len = 64;
3577 fib_table_entry_delete(fib_index, &connected_pfx,
3578 FIB_SOURCE_INTERFACE);
3579 connected_pfx.fp_len = 128;
3580 fib_table_entry_special_remove(fib_index, &connected_pfx,
3581 FIB_SOURCE_INTERFACE);
3583 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3584 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
3585 "2001::a/64 removed");
3586 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3587 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
3588 "2001::b/64 removed");
3589 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3590 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
3591 "2001:0:0:1::3/128 removed");
3592 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3593 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
3594 "2001:0:0:1::3/128 removed");
3595 local_pfx.fp_len = 64;
3596 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3597 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3598 "2001:0:0:1/64 removed");
3599 local_pfx.fp_len = 128;
3600 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3601 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3602 "2001:0:0:1::1/128 removed");
3603 connected_pfx.fp_len = 64;
3604 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3605 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3606 "2001:0:0:2/64 removed");
3607 connected_pfx.fp_len = 128;
3608 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3609 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3610 "2001:0:0:2::1/128 removed");
3613 * -8 entries. -7 path-lists (1 was shared).
3615 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3616 fib_path_list_db_size());
3617 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is%d",
3618 fib_path_list_pool_size());
3619 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
3620 fib_entry_pool_size());
3623 * now remove the VRF
3625 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
3627 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3628 fib_path_list_db_size());
3629 FIB_TEST((NPS-6 == fib_path_list_pool_size()), "path list pool size is%d",
3630 fib_path_list_pool_size());
3631 FIB_TEST((NPS-6 == fib_entry_pool_size()), "entry pool size is %d",
3632 fib_entry_pool_size());
3638 * return the interfaces to up state
3640 error = vnet_sw_interface_set_flags(vnet_get_main(),
3641 tm->hw[0]->sw_if_index,
3642 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3643 error = vnet_sw_interface_set_flags(vnet_get_main(),
3644 tm->hw[1]->sw_if_index,
3645 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3647 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3652 * Test the recursive route route handling for GRE tunnels
3657 /* fib_node_index_t fei; */
3658 /* u32 fib_index = 0; */
3659 /* test_main_t *tm; */
3662 /* tm = &test_main; */
3664 /* for (ii = 0; ii < 4; ii++) */
3666 /* ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = 0; */
3670 /* * add interface routes. We'll assume this works. It's more rigorously */
3671 /* * tested elsewhere. */
3673 /* fib_prefix_t local_pfx = { */
3675 /* .fp_proto = FIB_PROTOCOL_IP4, */
3678 /* /\* 10.10.10.10 *\/ */
3679 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3684 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3685 /* FIB_SOURCE_INTERFACE, */
3686 /* (FIB_ENTRY_FLAG_CONNECTED | */
3687 /* FIB_ENTRY_FLAG_ATTACHED), */
3689 /* tm->hw[0]->sw_if_index, */
3692 /* FIB_ROUTE_PATH_FLAG_NONE); */
3693 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3694 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3695 /* "attached interface route present"); */
3697 /* local_pfx.fp_len = 32; */
3698 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3699 /* FIB_SOURCE_INTERFACE, */
3700 /* (FIB_ENTRY_FLAG_CONNECTED | */
3701 /* FIB_ENTRY_FLAG_LOCAL), */
3703 /* tm->hw[0]->sw_if_index, */
3704 /* ~0, // invalid fib index */
3706 /* FIB_ROUTE_PATH_FLAG_NONE); */
3707 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3709 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3710 /* "local interface route present"); */
3712 /* fib_prefix_t local2_pfx = { */
3714 /* .fp_proto = FIB_PROTOCOL_IP4, */
3717 /* /\* 10.10.11.11 *\/ */
3718 /* .as_u32 = clib_host_to_net_u32(0x0a0a0b0b), */
3723 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3724 /* FIB_SOURCE_INTERFACE, */
3725 /* (FIB_ENTRY_FLAG_CONNECTED | */
3726 /* FIB_ENTRY_FLAG_ATTACHED), */
3728 /* tm->hw[1]->sw_if_index, */
3731 /* FIB_ROUTE_PATH_FLAG_NONE); */
3732 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3733 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3734 /* "attached interface route present"); */
3736 /* local2_pfx.fp_len = 32; */
3737 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3738 /* FIB_SOURCE_INTERFACE, */
3739 /* (FIB_ENTRY_FLAG_CONNECTED | */
3740 /* FIB_ENTRY_FLAG_LOCAL), */
3742 /* tm->hw[0]->sw_if_index, */
3743 /* ~0, // invalid fib index */
3745 /* FIB_ROUTE_PATH_FLAG_NONE); */
3746 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3748 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3749 /* "local interface route present"); */
3752 /* * Add the route that will be used to resolve the tunnel's destination */
3754 /* fib_prefix_t route_pfx = { */
3756 /* .fp_proto = FIB_PROTOCOL_IP4, */
3759 /* /\* 1.1.1.0/24 *\/ */
3760 /* .as_u32 = clib_host_to_net_u32(0x01010100), */
3764 /* /\* 10.10.10.2 *\/ */
3765 /* ip46_address_t nh_10_10_10_2 = { */
3766 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02), */
3769 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3770 /* FIB_SOURCE_API, */
3771 /* FIB_ENTRY_FLAG_NONE, */
3772 /* &nh_10_10_10_2, */
3773 /* tm->hw[0]->sw_if_index, */
3776 /* FIB_ROUTE_PATH_FLAG_NONE); */
3777 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
3778 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
3779 /* "route present"); */
3782 /* * Add a tunnel */
3784 /* /\* 1.1.1.1 *\/ */
3785 /* fib_prefix_t tun_dst_pfx = { */
3787 /* .fp_proto = FIB_PROTOCOL_IP4, */
3789 /* .ip4.as_u32 = clib_host_to_net_u32(0x01010101), */
3792 /* /\* 10.10.10.10 *\/ */
3793 /* ip4_address_t tun_src = { */
3794 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3796 /* /\* 172.16.0.1 *\/ */
3797 /* ip4_address_t tun_itf = { */
3798 /* .as_u32 = clib_host_to_net_u32(0xac100001), */
3800 /* fib_prefix_t tun_itf_pfx = { */
3802 /* .fp_proto = FIB_PROTOCOL_IP4, */
3804 /* .ip4 = tun_itf, */
3807 /* u32 *encap_labels = NULL; */
3808 /* u32 label = 0xbaba; */
3809 /* u32 encap_index; */
3810 /* u32 tunnel_sw_if_index; */
3815 /* * First we need the MPLS Encap present */
3817 /* * Pretty sure this is broken. the wiki say the 1st aparamter address */
3818 /* * should be the tunnel's interface address, which makes some sense. But */
3819 /* * the code for tunnel creation checks for the tunnel's destination */
3820 /* * address. curious... */
3822 /* vec_add1(encap_labels, label); */
3823 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
3824 /* 0, // inner VRF */
3826 /* ~0, // policy_tunnel_index, */
3827 /* 0, // no_dst_hash, */
3830 /* FIB_TEST((0 == rv), "MPLS encap created"); */
3833 /* * now create the tunnel */
3835 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3836 /* &tun_dst_pfx.fp_addr.ip4, */
3837 /* &tun_itf_pfx.fp_addr.ip4, */
3838 /* tun_itf_pfx.fp_len, */
3839 /* 0, // inner VRF */
3840 /* 0, // outer VRF */
3841 /* &tunnel_sw_if_index, */
3844 /* FIB_TEST((0 == rv), "Tunnel created"); */
3847 /* * add it again. just for giggles. */
3849 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3850 /* &tun_dst_pfx.fp_addr.ip4, */
3851 /* &tun_itf_pfx.fp_addr.ip4, */
3852 /* tun_itf_pfx.fp_len, */
3853 /* 0, // inner VRF */
3854 /* 0, // outer VRF */
3855 /* &tunnel_sw_if_index, */
3858 /* FIB_TEST((0 != rv), "Duplicate Tunnel not created"); */
3861 /* * Find the route added for the tunnel subnet and check that */
3862 /* * it has a midchin adj that is stacked on the adj used to reach the */
3863 /* * tunnel destination */
3865 /* ip_adjacency_t *midchain_adj, *route_adj, *adjfib_adj; */
3866 /* adj_index_t midchain_ai, route_ai, adjfib_ai1, adjfib_ai2; */
3867 /* ip_lookup_main_t *lm; */
3869 /* lm = &ip4_main.lookup_main; */
3871 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
3872 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "tun itf route present"); */
3873 /* midchain_ai = fib_entry_contribute_forwarding(fei); */
3874 /* midchain_adj = adj_get(midchain_ai); */
3876 /* FIB_TEST((IP_LOOKUP_NEXT_MIDCHAIN == midchain_adj->lookup_next_index), */
3877 /* "Tunnel interface links to midchain"); */
3879 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3880 /* route_ai = fib_entry_contribute_forwarding(fei); */
3881 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3882 /* "tunnel midchain it stacked on route adj"); */
3885 /* * update the route to the tunnel's destination to load-balance via */
3886 /* * interface 1. */
3888 /* /\* 10.10.11.2 *\/ */
3889 /* ip46_address_t nh_10_10_11_2 = { */
3890 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02), */
3893 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3894 /* FIB_SOURCE_API, */
3895 /* FIB_ENTRY_FLAG_NONE, */
3896 /* &nh_10_10_11_2, */
3897 /* tm->hw[1]->sw_if_index, */
3900 /* FIB_ROUTE_PATH_FLAG_NONE); */
3903 /* * the tunnels midchain should have re-stacked. This tests that the */
3904 /* * route re-resolution backwalk works to a tunnel interface. */
3906 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3907 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
3908 /* route_ai = fib_entry_contribute_forwarding(fei); */
3910 /* midchain_adj = adj_get(midchain_ai); */
3912 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3913 /* "tunnel midchain has re-stacked on route adj"); */
3915 /* route_adj = adj_get(route_ai); */
3917 /* FIB_TEST((2 == route_adj->n_adj), "Route adj is multipath"); */
3920 /* * At this stage both nieghbour adjs are incomplete, so the same should */
3921 /* * be true of the multipath adj */
3923 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == route_adj->lookup_next_index), */
3924 /* "Adj0 is ARP: %d", route_adj->lookup_next_index); */
3925 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == (route_adj+1)->lookup_next_index), */
3926 /* "Adj1 is ARP"); */
3929 /* * do the equivalent of creating an ARP entry for 10.10.10.2. */
3930 /* * This will complete the adj, and this */
3931 /* * change should be refelct in the multipath too. */
3933 /* u8* rewrite = NULL, byte = 0xd; */
3934 /* vec_add(rewrite, &byte, 6); */
3936 /* adjfib_ai1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
3938 /* &nh_10_10_10_2, */
3939 /* tm->hw[0]->sw_if_index); */
3940 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
3943 /* adjfib_adj = adj_get(adjfib_ai1); */
3944 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
3945 /* "Adj-fib10 adj is rewrite"); */
3947 /* adjfib_ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
3949 /* &nh_10_10_11_2, */
3950 /* tm->hw[1]->sw_if_index); */
3951 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
3955 /* adjfib_adj = adj_get(adjfib_ai2); */
3957 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
3958 /* "Adj-fib11 adj is rewrite"); */
3960 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3961 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
3962 /* route_ai = fib_entry_contribute_forwarding(fei); */
3963 /* route_adj = adj_get(route_ai); */
3964 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == route_adj->lookup_next_index), */
3965 /* "Adj0 is rewrite"); */
3966 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == (route_adj+1)->lookup_next_index), */
3967 /* "Adj1 is rewrite"); */
3972 /* adj_index_t drop_ai = adj_get_special(FIB_PROTOCOL_IP4, */
3973 /* ADJ_SPECIAL_TYPE_DROP); */
3976 /* * remove the route that the tunnel resovles via. expect */
3977 /* * it to now resolve via the default route, which is drop */
3979 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
3980 /* FIB_SOURCE_API, */
3981 /* &nh_10_10_10_2, */
3982 /* tm->hw[0]->sw_if_index, */
3985 /* FIB_ROUTE_PATH_FLAG_NONE); */
3986 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
3987 /* FIB_SOURCE_API, */
3988 /* &nh_10_10_11_2, */
3989 /* tm->hw[1]->sw_if_index, */
3992 /* FIB_ROUTE_PATH_FLAG_NONE); */
3993 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
3994 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
3995 /* "route present"); */
3996 /* midchain_adj = adj_get(midchain_ai); */
3997 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == drop_ai), */
3998 /* "tunnel midchain has re-stacked on drop"); */
4001 /* * remove the tunnel and its MPLS encaps */
4003 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
4004 /* &tun_dst_pfx.fp_addr.ip4, */
4005 /* &tun_itf_pfx.fp_addr.ip4, */
4006 /* tun_itf_pfx.fp_len, */
4007 /* 0, // inner VRF */
4008 /* 0, // outer VRF */
4009 /* &tunnel_sw_if_index, */
4012 /* FIB_TEST((0 == rv), "Tunnel removed"); */
4013 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
4014 /* &tun_dst_pfx.fp_addr.ip4, */
4015 /* &tun_itf_pfx.fp_addr.ip4, */
4016 /* tun_itf_pfx.fp_len, */
4017 /* 0, // inner VRF */
4018 /* 0, // outer VRF */
4019 /* &tunnel_sw_if_index, */
4022 /* FIB_TEST((0 != rv), "No existant Tunnel not removed"); */
4024 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
4025 /* 0, // inner VRF */
4027 /* ~0, // policy_tunnel_index, */
4028 /* 0, // no_dst_hash, */
4031 /* FIB_TEST((0 == rv), "MPLS encap deleted"); */
4033 /* vec_free(encap_labels); */
4036 /* * no more FIB entries expected */
4038 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
4039 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun itf route removed"); */
4040 /* fei = fib_table_lookup_exact_match(fib_index, &tun_dst_pfx); */
4041 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun dst route removed"); */
4044 /* * CLEANUP the connecteds */
4046 /* local2_pfx.fp_len = 24; */
4047 /* fib_table_entry_delete(fib_index, &local2_pfx, */
4048 /* FIB_SOURCE_INTERFACE); */
4049 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
4050 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4051 /* "attached interface route remove"); */
4053 /* local2_pfx.fp_len = 32; */
4054 /* fib_table_entry_special_remove(fib_index, &local2_pfx, */
4055 /* FIB_SOURCE_INTERFACE); */
4056 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
4057 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4058 /* "local interface route removed"); */
4059 /* local_pfx.fp_len = 24; */
4060 /* fib_table_entry_delete(fib_index, &local_pfx, */
4061 /* FIB_SOURCE_INTERFACE); */
4062 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
4063 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4064 /* "attached interface route remove"); */
4066 /* local_pfx.fp_len = 32; */
4067 /* fib_table_entry_special_remove(fib_index, &local_pfx, */
4068 /* FIB_SOURCE_INTERFACE); */
4069 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
4070 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4071 /* "local interface route removed"); */
4075 * Test Attached Exports
4080 const dpo_id_t *dpo, *dpo_drop;
4081 const u32 fib_index = 0;
4082 fib_node_index_t fei;
4089 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4093 * add interface routes. We'll assume this works. It's more rigorously
4096 fib_prefix_t local_pfx = {
4098 .fp_proto = FIB_PROTOCOL_IP4,
4102 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4107 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4108 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4110 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4112 fib_table_entry_update_one_path(fib_index, &local_pfx,
4113 FIB_SOURCE_INTERFACE,
4114 (FIB_ENTRY_FLAG_CONNECTED |
4115 FIB_ENTRY_FLAG_ATTACHED),
4118 tm->hw[0]->sw_if_index,
4122 FIB_ROUTE_PATH_FLAG_NONE);
4123 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4124 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4125 "attached interface route present");
4127 local_pfx.fp_len = 32;
4128 fib_table_entry_update_one_path(fib_index, &local_pfx,
4129 FIB_SOURCE_INTERFACE,
4130 (FIB_ENTRY_FLAG_CONNECTED |
4131 FIB_ENTRY_FLAG_LOCAL),
4134 tm->hw[0]->sw_if_index,
4135 ~0, // invalid fib index
4138 FIB_ROUTE_PATH_FLAG_NONE);
4139 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4141 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4142 "local interface route present");
4145 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4147 fib_prefix_t pfx_10_10_10_1_s_32 = {
4149 .fp_proto = FIB_PROTOCOL_IP4,
4152 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4155 fib_node_index_t ai;
4157 fib_table_entry_update_one_path(fib_index,
4158 &pfx_10_10_10_1_s_32,
4160 FIB_ENTRY_FLAG_NONE,
4162 &pfx_10_10_10_1_s_32.fp_addr,
4163 tm->hw[0]->sw_if_index,
4164 ~0, // invalid fib index
4167 FIB_ROUTE_PATH_FLAG_NONE);
4169 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4170 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4171 ai = fib_entry_get_adj(fei);
4174 * create another FIB table into which routes will be imported
4176 u32 import_fib_index1;
4178 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4181 * Add an attached route in the import FIB
4183 local_pfx.fp_len = 24;
4184 fib_table_entry_update_one_path(import_fib_index1,
4187 FIB_ENTRY_FLAG_NONE,
4190 tm->hw[0]->sw_if_index,
4191 ~0, // invalid fib index
4194 FIB_ROUTE_PATH_FLAG_NONE);
4195 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4196 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4199 * check for the presence of the adj-fibs in the import table
4201 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4202 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4203 FIB_TEST((ai == fib_entry_get_adj(fei)),
4204 "adj-fib1 Import uses same adj as export");
4207 * check for the presence of the local in the import table
4209 local_pfx.fp_len = 32;
4210 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4211 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4214 * Add another adj-fin in the export table. Expect this
4215 * to get magically exported;
4217 fib_prefix_t pfx_10_10_10_2_s_32 = {
4219 .fp_proto = FIB_PROTOCOL_IP4,
4222 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4226 fib_table_entry_update_one_path(fib_index,
4227 &pfx_10_10_10_2_s_32,
4229 FIB_ENTRY_FLAG_NONE,
4231 &pfx_10_10_10_2_s_32.fp_addr,
4232 tm->hw[0]->sw_if_index,
4233 ~0, // invalid fib index
4236 FIB_ROUTE_PATH_FLAG_NONE);
4237 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4238 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4239 ai = fib_entry_get_adj(fei);
4241 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4242 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4243 FIB_TEST((ai == fib_entry_get_adj(fei)),
4244 "Import uses same adj as export");
4247 * create a 2nd FIB table into which routes will be imported
4249 u32 import_fib_index2;
4251 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4254 * Add an attached route in the import FIB
4256 local_pfx.fp_len = 24;
4257 fib_table_entry_update_one_path(import_fib_index2,
4260 FIB_ENTRY_FLAG_NONE,
4263 tm->hw[0]->sw_if_index,
4264 ~0, // invalid fib index
4267 FIB_ROUTE_PATH_FLAG_NONE);
4268 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4269 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4272 * check for the presence of all the adj-fibs and local in the import table
4274 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4275 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4276 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4277 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4278 local_pfx.fp_len = 32;
4279 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4280 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4283 * add a 3rd adj-fib. expect it to be exported to both tables.
4285 fib_prefix_t pfx_10_10_10_3_s_32 = {
4287 .fp_proto = FIB_PROTOCOL_IP4,
4290 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4294 fib_table_entry_update_one_path(fib_index,
4295 &pfx_10_10_10_3_s_32,
4297 FIB_ENTRY_FLAG_NONE,
4299 &pfx_10_10_10_3_s_32.fp_addr,
4300 tm->hw[0]->sw_if_index,
4301 ~0, // invalid fib index
4304 FIB_ROUTE_PATH_FLAG_NONE);
4305 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4306 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4307 ai = fib_entry_get_adj(fei);
4309 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4310 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4311 FIB_TEST((ai == fib_entry_get_adj(fei)),
4312 "Import uses same adj as export");
4313 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4314 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4315 FIB_TEST((ai == fib_entry_get_adj(fei)),
4316 "Import uses same adj as export");
4319 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4321 fib_table_entry_delete(fib_index,
4322 &pfx_10_10_10_3_s_32,
4325 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4326 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4328 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4329 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
4331 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4332 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4335 * remove the attached route from the 2nd FIB. expect the imported
4336 * entires to be removed
4338 local_pfx.fp_len = 24;
4339 fib_table_entry_delete(import_fib_index2,
4342 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4343 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4345 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4346 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4347 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4348 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4349 local_pfx.fp_len = 32;
4350 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4351 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4353 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4354 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4355 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4356 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4357 local_pfx.fp_len = 32;
4358 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4359 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4362 * modify the route in FIB1 so it is no longer attached. expect the imported
4363 * entires to be removed
4365 local_pfx.fp_len = 24;
4366 fib_table_entry_update_one_path(import_fib_index1,
4369 FIB_ENTRY_FLAG_NONE,
4371 &pfx_10_10_10_2_s_32.fp_addr,
4372 tm->hw[0]->sw_if_index,
4373 ~0, // invalid fib index
4376 FIB_ROUTE_PATH_FLAG_NONE);
4377 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4378 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
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 removed from FIB1");
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 removed from FIB1");
4386 * modify it back to attached. expect the adj-fibs back
4388 local_pfx.fp_len = 24;
4389 fib_table_entry_update_one_path(import_fib_index1,
4392 FIB_ENTRY_FLAG_NONE,
4395 tm->hw[0]->sw_if_index,
4396 ~0, // invalid fib index
4399 FIB_ROUTE_PATH_FLAG_NONE);
4400 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4401 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4402 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4403 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4404 local_pfx.fp_len = 32;
4405 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4406 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4409 * add a covering attached next-hop for the interface address, so we have
4410 * a valid adj to find when we check the forwarding tables
4412 fib_prefix_t pfx_10_0_0_0_s_8 = {
4414 .fp_proto = FIB_PROTOCOL_IP4,
4417 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4421 fei = fib_table_entry_update_one_path(fib_index,
4424 FIB_ENTRY_FLAG_NONE,
4426 &pfx_10_10_10_3_s_32.fp_addr,
4427 tm->hw[0]->sw_if_index,
4428 ~0, // invalid fib index
4431 FIB_ROUTE_PATH_FLAG_NONE);
4432 dpo = fib_entry_contribute_ip_forwarding(fei);
4435 * remove the route in the export fib. expect the adj-fibs to be removed
4437 local_pfx.fp_len = 24;
4438 fib_table_entry_delete(fib_index,
4440 FIB_SOURCE_INTERFACE);
4442 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4443 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4444 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4445 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4446 local_pfx.fp_len = 32;
4447 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4448 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4451 * the adj-fibs in the export VRF are present in the FIB table,
4452 * but not installed in forwarding, since they have no attached cover.
4453 * Consequently a lookup in the MTRIE gives the adj for the covering
4456 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4457 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4460 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4461 FIB_TEST(lbi == dpo->dpoi_index,
4462 "10.10.10.1 forwards on \n%U not \n%U",
4463 format_load_balance, lbi, 0,
4464 format_dpo_id, dpo, 0);
4465 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4466 FIB_TEST(lbi == dpo->dpoi_index,
4467 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4468 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
4469 FIB_TEST(lbi == dpo->dpoi_index,
4470 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
4473 * add the export prefix back, but not as attached.
4474 * No adj-fibs in export nor import tables
4476 local_pfx.fp_len = 24;
4477 fei = fib_table_entry_update_one_path(fib_index,
4480 FIB_ENTRY_FLAG_NONE,
4482 &pfx_10_10_10_1_s_32.fp_addr,
4483 tm->hw[0]->sw_if_index,
4484 ~0, // invalid fib index
4487 FIB_ROUTE_PATH_FLAG_NONE);
4488 dpo = fib_entry_contribute_ip_forwarding(fei);
4490 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4491 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
4492 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4493 FIB_TEST(lbi == dpo->dpoi_index,
4494 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
4495 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4496 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4497 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4498 FIB_TEST(lbi == dpo->dpoi_index,
4499 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4501 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4502 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4503 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4504 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4505 local_pfx.fp_len = 32;
4506 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4507 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4510 * modify the export prefix so it is attached. expect all covereds to return
4512 local_pfx.fp_len = 24;
4513 fib_table_entry_update_one_path(fib_index,
4516 FIB_ENTRY_FLAG_NONE,
4519 tm->hw[0]->sw_if_index,
4520 ~0, // invalid fib index
4523 FIB_ROUTE_PATH_FLAG_NONE);
4525 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4526 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4527 dpo = fib_entry_contribute_ip_forwarding(fei);
4528 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4529 "Adj-fib1 is not drop in export");
4530 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4531 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4532 local_pfx.fp_len = 32;
4533 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4534 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4535 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4536 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4537 dpo = fib_entry_contribute_ip_forwarding(fei);
4538 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4539 "Adj-fib1 is not drop in export");
4540 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4541 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4542 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4543 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4544 local_pfx.fp_len = 32;
4545 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4546 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4549 * modify the export prefix so connected. no change.
4551 local_pfx.fp_len = 24;
4552 fib_table_entry_update_one_path(fib_index, &local_pfx,
4553 FIB_SOURCE_INTERFACE,
4554 (FIB_ENTRY_FLAG_CONNECTED |
4555 FIB_ENTRY_FLAG_ATTACHED),
4558 tm->hw[0]->sw_if_index,
4562 FIB_ROUTE_PATH_FLAG_NONE);
4564 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4565 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4566 dpo = fib_entry_contribute_ip_forwarding(fei);
4567 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4568 "Adj-fib1 is not drop in export");
4569 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4570 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4571 local_pfx.fp_len = 32;
4572 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4573 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4574 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4575 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4576 dpo = fib_entry_contribute_ip_forwarding(fei);
4577 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4578 "Adj-fib1 is not drop in export");
4579 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4580 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4581 local_pfx.fp_len = 32;
4582 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4583 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4588 fib_table_entry_delete(fib_index,
4591 fib_table_entry_delete(fib_index,
4592 &pfx_10_10_10_1_s_32,
4594 fib_table_entry_delete(fib_index,
4595 &pfx_10_10_10_2_s_32,
4597 local_pfx.fp_len = 32;
4598 fib_table_entry_delete(fib_index,
4600 FIB_SOURCE_INTERFACE);
4601 local_pfx.fp_len = 24;
4602 fib_table_entry_delete(fib_index,
4605 fib_table_entry_delete(fib_index,
4607 FIB_SOURCE_INTERFACE);
4608 local_pfx.fp_len = 24;
4609 fib_table_entry_delete(import_fib_index1,
4613 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
4614 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
4616 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4620 typedef enum fib_test_lb_bucket_type_t_ {
4626 } fib_test_lb_bucket_type_t;
4628 typedef struct fib_test_lb_bucket_t_ {
4629 fib_test_lb_bucket_type_t type;
4660 } fib_test_lb_bucket_t;
4662 #define FIB_TEST_LB(_cond, _comment, _args...) \
4664 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
4670 fib_test_validate_lb_v (const load_balance_t *lb,
4674 const dpo_id_t *dpo;
4677 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
4679 for (bucket = 0; bucket < n_buckets; bucket++)
4681 const fib_test_lb_bucket_t *exp;
4683 exp = va_arg(ap, fib_test_lb_bucket_t*);
4684 dpo = load_balance_get_bucket_i(lb, bucket);
4688 case FT_LB_LABEL_O_ADJ:
4690 const mpls_label_dpo_t *mld;
4692 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4693 "bucket %d stacks on %U",
4695 format_dpo_type, dpo->dpoi_type);
4697 mld = mpls_label_dpo_get(dpo->dpoi_index);
4698 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4700 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4701 exp->label_o_adj.label),
4702 "bucket %d stacks on label %d",
4704 exp->label_o_adj.label);
4706 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4707 exp->label_o_adj.eos),
4708 "bucket %d stacks on label %d %U",
4710 exp->label_o_adj.label,
4711 format_mpls_eos_bit, exp->label_o_adj.eos);
4713 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
4714 "bucket %d label stacks on %U",
4716 format_dpo_type, mld->mld_dpo.dpoi_type);
4718 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
4719 "bucket %d label stacks on adj %d",
4721 exp->label_o_adj.adj);
4724 case FT_LB_LABEL_O_LB:
4726 const mpls_label_dpo_t *mld;
4729 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4730 "bucket %d stacks on %U",
4732 format_dpo_type, dpo->dpoi_type);
4734 mld = mpls_label_dpo_get(dpo->dpoi_index);
4735 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4737 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4738 exp->label_o_lb.label),
4739 "bucket %d stacks on label %d",
4741 exp->label_o_lb.label);
4743 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4744 exp->label_o_lb.eos),
4745 "bucket %d stacks on label %d %U",
4747 exp->label_o_lb.label,
4748 format_mpls_eos_bit, exp->label_o_lb.eos);
4750 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
4751 "bucket %d label stacks on %U",
4753 format_dpo_type, mld->mld_dpo.dpoi_type);
4755 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
4756 "bucket %d label stacks on LB %d",
4758 exp->label_o_lb.lb);
4762 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
4763 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
4764 "bucket %d stacks on %U",
4766 format_dpo_type, dpo->dpoi_type);
4767 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
4768 "bucket %d stacks on adj %d",
4773 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
4774 "bucket %d stacks on %U",
4776 format_dpo_type, dpo->dpoi_type);
4777 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
4778 "bucket %d stacks on lb %d",
4783 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
4784 "bucket %d stacks on %U",
4786 format_dpo_type, dpo->dpoi_type);
4787 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
4788 "bucket %d stacks on drop %d",
4798 fib_test_validate_entry (fib_node_index_t fei,
4799 fib_forward_chain_type_t fct,
4803 const load_balance_t *lb;
4804 dpo_id_t dpo = DPO_NULL;
4811 va_start(ap, n_buckets);
4813 fib_entry_get_prefix(fei, &pfx);
4814 fib_index = fib_entry_get_fib_index(fei);
4815 fib_entry_contribute_forwarding(fei, fct, &dpo);
4817 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
4818 "Entry links to %U",
4819 format_dpo_type, dpo.dpoi_type);
4820 lb = load_balance_get(dpo.dpoi_index);
4822 res = fib_test_validate_lb_v(lb, n_buckets, ap);
4825 * ensure that the LB contributed by the entry is the
4826 * same as the LB in the forwarding tables
4828 switch (pfx.fp_proto)
4830 case FIB_PROTOCOL_IP4:
4831 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
4833 case FIB_PROTOCOL_IP6:
4834 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
4836 case FIB_PROTOCOL_MPLS:
4838 mpls_unicast_header_t hdr;
4840 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
4841 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
4842 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
4844 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
4850 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
4851 "Contributed LB = FW LB: %U\n %U",
4852 format_load_balance, fw_lbi, 0,
4853 format_load_balance, dpo.dpoi_index, 0);
4863 * Test the recursive route route handling for GRE tunnels
4866 fib_test_label (void)
4868 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;
4869 const u32 fib_index = 0;
4874 lb_count = pool_elts(load_balance_pool);
4879 * add interface routes. We'll assume this works. It's more rigorously
4882 fib_prefix_t local0_pfx = {
4884 .fp_proto = FIB_PROTOCOL_IP4,
4888 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4893 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4896 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4897 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4899 fib_table_entry_update_one_path(fib_index, &local0_pfx,
4900 FIB_SOURCE_INTERFACE,
4901 (FIB_ENTRY_FLAG_CONNECTED |
4902 FIB_ENTRY_FLAG_ATTACHED),
4905 tm->hw[0]->sw_if_index,
4909 FIB_ROUTE_PATH_FLAG_NONE);
4910 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
4911 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4912 "attached interface route present");
4914 local0_pfx.fp_len = 32;
4915 fib_table_entry_update_one_path(fib_index, &local0_pfx,
4916 FIB_SOURCE_INTERFACE,
4917 (FIB_ENTRY_FLAG_CONNECTED |
4918 FIB_ENTRY_FLAG_LOCAL),
4921 tm->hw[0]->sw_if_index,
4922 ~0, // invalid fib index
4925 FIB_ROUTE_PATH_FLAG_NONE);
4926 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
4928 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4929 "local interface route present");
4931 fib_prefix_t local1_pfx = {
4933 .fp_proto = FIB_PROTOCOL_IP4,
4937 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
4942 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
4943 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
4945 fib_table_entry_update_one_path(fib_index, &local1_pfx,
4946 FIB_SOURCE_INTERFACE,
4947 (FIB_ENTRY_FLAG_CONNECTED |
4948 FIB_ENTRY_FLAG_ATTACHED),
4951 tm->hw[1]->sw_if_index,
4955 FIB_ROUTE_PATH_FLAG_NONE);
4956 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
4957 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4958 "attached interface route present");
4960 local1_pfx.fp_len = 32;
4961 fib_table_entry_update_one_path(fib_index, &local1_pfx,
4962 FIB_SOURCE_INTERFACE,
4963 (FIB_ENTRY_FLAG_CONNECTED |
4964 FIB_ENTRY_FLAG_LOCAL),
4967 tm->hw[1]->sw_if_index,
4968 ~0, // invalid fib index
4971 FIB_ROUTE_PATH_FLAG_NONE);
4972 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
4974 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4975 "local interface route present");
4977 ip46_address_t nh_10_10_10_1 = {
4979 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4982 ip46_address_t nh_10_10_11_1 = {
4984 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
4987 ip46_address_t nh_10_10_11_2 = {
4989 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
4993 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4996 tm->hw[1]->sw_if_index);
4997 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5000 tm->hw[1]->sw_if_index);
5001 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5004 tm->hw[0]->sw_if_index);
5005 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5008 tm->hw[1]->sw_if_index);
5009 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5012 tm->hw[1]->sw_if_index);
5015 * Add an etry with one path with a real out-going label
5017 fib_prefix_t pfx_1_1_1_1_s_32 = {
5019 .fp_proto = FIB_PROTOCOL_IP4,
5021 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5024 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5025 .type = FT_LB_LABEL_O_ADJ,
5027 .adj = ai_mpls_10_10_10_1,
5032 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5033 .type = FT_LB_LABEL_O_ADJ,
5035 .adj = ai_mpls_10_10_10_1,
5037 .eos = MPLS_NON_EOS,
5040 fib_table_entry_update_one_path(fib_index,
5043 FIB_ENTRY_FLAG_NONE,
5046 tm->hw[0]->sw_if_index,
5047 ~0, // invalid fib index
5050 FIB_ROUTE_PATH_FLAG_NONE);
5052 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5053 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5055 FIB_TEST(fib_test_validate_entry(fei,
5056 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5058 &l99_eos_o_10_10_10_1),
5059 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5062 * add a path with an implicit NULL label
5064 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5067 .adj = ai_v4_10_10_11_1,
5070 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5073 .adj = ai_mpls_10_10_11_1,
5077 fei = fib_table_entry_path_add(fib_index,
5080 FIB_ENTRY_FLAG_NONE,
5083 tm->hw[1]->sw_if_index,
5084 ~0, // invalid fib index
5086 MPLS_IETF_IMPLICIT_NULL_LABEL,
5087 FIB_ROUTE_PATH_FLAG_NONE);
5089 FIB_TEST(fib_test_validate_entry(fei,
5090 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5092 &l99_eos_o_10_10_10_1,
5094 "1.1.1.1/32 LB 2 buckets via: "
5095 "label 99 over 10.10.10.1, "
5096 "adj over 10.10.11.1");
5099 * assign the route a local label
5101 fib_table_entry_local_label_add(fib_index,
5105 fib_prefix_t pfx_24001_eos = {
5106 .fp_proto = FIB_PROTOCOL_MPLS,
5110 fib_prefix_t pfx_24001_neos = {
5111 .fp_proto = FIB_PROTOCOL_MPLS,
5113 .fp_eos = MPLS_NON_EOS,
5117 * The EOS entry should link to both the paths,
5118 * and use an ip adj for the imp-null
5119 * The NON-EOS entry should link to both the paths,
5120 * and use an mpls adj for the imp-null
5122 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5124 FIB_TEST(fib_test_validate_entry(fei,
5125 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5127 &l99_eos_o_10_10_10_1,
5129 "24001/eos LB 2 buckets via: "
5130 "label 99 over 10.10.10.1, "
5131 "adj over 10.10.11.1");
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 1 bucket via: "
5142 "label 99 over 10.10.10.1 ",
5143 "mpls-adj via 10.10.11.1");
5146 * add an unlabelled path, this is excluded from the neos chains,
5148 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5151 .adj = ai_v4_10_10_11_2,
5155 fei = fib_table_entry_path_add(fib_index,
5158 FIB_ENTRY_FLAG_NONE,
5161 tm->hw[1]->sw_if_index,
5162 ~0, // invalid fib index
5165 FIB_ROUTE_PATH_FLAG_NONE);
5167 FIB_TEST(fib_test_validate_entry(fei,
5168 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5169 16, // 3 choices spread over 16 buckets
5170 &l99_eos_o_10_10_10_1,
5171 &l99_eos_o_10_10_10_1,
5172 &l99_eos_o_10_10_10_1,
5173 &l99_eos_o_10_10_10_1,
5174 &l99_eos_o_10_10_10_1,
5175 &l99_eos_o_10_10_10_1,
5186 "1.1.1.1/32 LB 16 buckets via: "
5187 "label 99 over 10.10.10.1, "
5188 "adj over 10.10.11.1",
5189 "adj over 10.10.11.2");
5192 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5194 dpo_id_t non_eos_1_1_1_1 = DPO_NULL;
5195 fib_entry_contribute_forwarding(fei,
5196 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5200 * n-eos has only the 2 labelled paths
5202 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5205 FIB_TEST(fib_test_validate_entry(fei,
5206 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5208 &l99_neos_o_10_10_10_1,
5209 &a_mpls_o_10_10_11_1),
5210 "24001/neos LB 2 buckets via: "
5211 "label 99 over 10.10.10.1, "
5212 "adj-mpls over 10.10.11.2");
5215 * A labelled recursive
5217 fib_prefix_t pfx_2_2_2_2_s_32 = {
5219 .fp_proto = FIB_PROTOCOL_IP4,
5221 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5224 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5225 .type = FT_LB_LABEL_O_LB,
5227 .lb = non_eos_1_1_1_1.dpoi_index,
5233 fib_table_entry_update_one_path(fib_index,
5236 FIB_ENTRY_FLAG_NONE,
5238 &pfx_1_1_1_1_s_32.fp_addr,
5243 FIB_ROUTE_PATH_FLAG_NONE);
5245 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5246 FIB_TEST(fib_test_validate_entry(fei,
5247 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5249 &l1600_eos_o_1_1_1_1),
5250 "2.2.2.2.2/32 LB 1 buckets via: "
5251 "label 1600 over 1.1.1.1");
5253 dpo_id_t dpo_44 = DPO_NULL;
5256 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5257 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5259 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5260 "uRPF check for 2.2.2.2/32 on %d OK",
5261 tm->hw[0]->sw_if_index);
5262 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5263 "uRPF check for 2.2.2.2/32 on %d OK",
5264 tm->hw[1]->sw_if_index);
5265 FIB_TEST(!fib_urpf_check(urpfi, 99),
5266 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5269 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5270 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5271 "Shared uRPF on IP and non-EOS chain");
5276 * we are holding a lock on the non-eos LB of the via-entry.
5277 * do a PIC-core failover by shutting the link of the via-entry.
5279 * shut down the link with the valid label
5281 vnet_sw_interface_set_flags(vnet_get_main(),
5282 tm->hw[0]->sw_if_index,
5285 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5286 FIB_TEST(fib_test_validate_entry(fei,
5287 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5291 "1.1.1.1/32 LB 2 buckets via: "
5292 "adj over 10.10.11.1, ",
5293 "adj-v4 over 10.10.11.2");
5295 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5297 FIB_TEST(fib_test_validate_entry(fei,
5298 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5302 "24001/eos LB 2 buckets via: "
5303 "adj over 10.10.11.1, ",
5304 "adj-v4 over 10.10.11.2");
5306 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5308 FIB_TEST(fib_test_validate_entry(fei,
5309 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5311 &a_mpls_o_10_10_11_1),
5312 "24001/neos LB 1 buckets via: "
5313 "adj-mpls over 10.10.11.2");
5316 * test that the pre-failover load-balance has been in-place
5319 dpo_id_t current = DPO_NULL;
5320 fib_entry_contribute_forwarding(fei,
5321 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5324 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5326 "PIC-core LB inplace modified %U %U",
5327 format_dpo_id, &non_eos_1_1_1_1, 0,
5328 format_dpo_id, ¤t, 0);
5330 dpo_reset(&non_eos_1_1_1_1);
5331 dpo_reset(¤t);
5334 * no-shut the link with the valid label
5336 vnet_sw_interface_set_flags(vnet_get_main(),
5337 tm->hw[0]->sw_if_index,
5338 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5340 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5341 FIB_TEST(fib_test_validate_entry(fei,
5342 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5343 16, // 3 choices spread over 16 buckets
5344 &l99_eos_o_10_10_10_1,
5345 &l99_eos_o_10_10_10_1,
5346 &l99_eos_o_10_10_10_1,
5347 &l99_eos_o_10_10_10_1,
5348 &l99_eos_o_10_10_10_1,
5349 &l99_eos_o_10_10_10_1,
5360 "1.1.1.1/32 LB 16 buckets via: "
5361 "label 99 over 10.10.10.1, "
5362 "adj over 10.10.11.1",
5363 "adj-v4 over 10.10.11.2");
5366 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5368 FIB_TEST(fib_test_validate_entry(fei,
5369 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5370 16, // 3 choices spread over 16 buckets
5371 &l99_eos_o_10_10_10_1,
5372 &l99_eos_o_10_10_10_1,
5373 &l99_eos_o_10_10_10_1,
5374 &l99_eos_o_10_10_10_1,
5375 &l99_eos_o_10_10_10_1,
5376 &l99_eos_o_10_10_10_1,
5387 "24001/eos LB 16 buckets via: "
5388 "label 99 over 10.10.10.1, "
5389 "adj over 10.10.11.1",
5390 "adj-v4 over 10.10.11.2");
5392 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5394 FIB_TEST(fib_test_validate_entry(fei,
5395 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5397 &l99_neos_o_10_10_10_1,
5398 &a_mpls_o_10_10_11_1),
5399 "24001/neos LB 2 buckets via: "
5400 "label 99 over 10.10.10.1, "
5401 "adj-mpls over 10.10.11.2");
5404 * remove the first path with the valid label
5406 fib_table_entry_path_remove(fib_index,
5411 tm->hw[0]->sw_if_index,
5412 ~0, // invalid fib index
5414 FIB_ROUTE_PATH_FLAG_NONE);
5416 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5417 FIB_TEST(fib_test_validate_entry(fei,
5418 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5422 "1.1.1.1/32 LB 2 buckets via: "
5423 "adj over 10.10.11.1",
5424 "adj-v4 over 10.10.11.2");
5426 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5428 FIB_TEST(fib_test_validate_entry(fei,
5429 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5433 "24001/eos LB 2 buckets via: "
5434 "adj over 10.10.11.1",
5435 "adj-v4 over 10.10.11.2");
5437 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5440 FIB_TEST(fib_test_validate_entry(fei,
5441 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5443 &a_mpls_o_10_10_11_1),
5444 "24001/neos LB 1 buckets via: "
5445 "adj-mpls over 10.10.11.2");
5448 * remove the other path with a valid label
5450 fib_test_lb_bucket_t bucket_drop = {
5451 .type = FT_LB_SPECIAL,
5457 fib_table_entry_path_remove(fib_index,
5462 tm->hw[1]->sw_if_index,
5463 ~0, // invalid fib index
5465 FIB_ROUTE_PATH_FLAG_NONE);
5467 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5468 FIB_TEST(fib_test_validate_entry(fei,
5469 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5472 "1.1.1.1/32 LB 1 buckets via: "
5473 "adj over 10.10.11.2");
5475 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5477 FIB_TEST(fib_test_validate_entry(fei,
5478 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5481 "24001/eos LB 1 buckets via: "
5482 "adj over 10.10.11.2");
5484 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5486 FIB_TEST(fib_test_validate_entry(fei,
5487 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5490 "24001/eos LB 1 buckets via: DROP");
5493 * add back the path with the valid label
5495 fib_table_entry_path_add(fib_index,
5498 FIB_ENTRY_FLAG_NONE,
5501 tm->hw[0]->sw_if_index,
5502 ~0, // invalid fib index
5505 FIB_ROUTE_PATH_FLAG_NONE);
5507 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5508 FIB_TEST(fib_test_validate_entry(fei,
5509 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5511 &l99_eos_o_10_10_10_1,
5513 "1.1.1.1/32 LB 2 buckets via: "
5514 "label 99 over 10.10.10.1, "
5515 "adj over 10.10.11.2");
5517 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5519 FIB_TEST(fib_test_validate_entry(fei,
5520 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5522 &l99_eos_o_10_10_10_1,
5524 "24001/eos LB 2 buckets via: "
5525 "label 99 over 10.10.10.1, "
5526 "adj over 10.10.11.2");
5528 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5530 FIB_TEST(fib_test_validate_entry(fei,
5531 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5533 &l99_neos_o_10_10_10_1),
5534 "24001/neos LB 1 buckets via: "
5535 "label 99 over 10.10.10.1");
5538 * remove the local label
5540 fib_table_entry_local_label_remove(fib_index,
5544 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5545 FIB_TEST(fib_test_validate_entry(fei,
5546 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5548 &l99_eos_o_10_10_10_1,
5550 "24001/eos LB 2 buckets via: "
5551 "label 99 over 10.10.10.1, "
5552 "adj over 10.10.11.2");
5554 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5555 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5556 "No more MPLS FIB entries => table removed");
5559 * add another via-entry for the recursive
5561 fib_prefix_t pfx_1_1_1_2_s_32 = {
5563 .fp_proto = FIB_PROTOCOL_IP4,
5565 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5568 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5569 .type = FT_LB_LABEL_O_ADJ,
5571 .adj = ai_mpls_10_10_10_1,
5577 fei = fib_table_entry_update_one_path(fib_index,
5580 FIB_ENTRY_FLAG_NONE,
5583 tm->hw[0]->sw_if_index,
5584 ~0, // invalid fib index
5587 FIB_ROUTE_PATH_FLAG_NONE);
5589 FIB_TEST(fib_test_validate_entry(fei,
5590 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5592 &l101_eos_o_10_10_10_1),
5593 "1.1.1.2/32 LB 1 buckets via: "
5594 "label 101 over 10.10.10.1");
5596 dpo_id_t non_eos_1_1_1_2 = DPO_NULL;
5597 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5599 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5601 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5603 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5606 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5607 .type = FT_LB_LABEL_O_LB,
5609 .lb = non_eos_1_1_1_2.dpoi_index,
5614 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5616 fei = fib_table_entry_path_add(fib_index,
5619 FIB_ENTRY_FLAG_NONE,
5621 &pfx_1_1_1_2_s_32.fp_addr,
5626 FIB_ROUTE_PATH_FLAG_NONE);
5628 FIB_TEST(fib_test_validate_entry(fei,
5629 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5631 &l1600_eos_o_1_1_1_1,
5632 &l1601_eos_o_1_1_1_2),
5633 "2.2.2.2/32 LB 2 buckets via: "
5634 "label 1600 via 1.1,1.1, "
5635 "label 16001 via 1.1.1.2");
5638 * update the via-entry so it no longer has an imp-null path.
5639 * the LB for the recursive can use an imp-null
5641 fei = fib_table_entry_update_one_path(fib_index,
5644 FIB_ENTRY_FLAG_NONE,
5647 tm->hw[1]->sw_if_index,
5648 ~0, // invalid fib index
5650 MPLS_IETF_IMPLICIT_NULL_LABEL,
5651 FIB_ROUTE_PATH_FLAG_NONE);
5653 FIB_TEST(fib_test_validate_entry(fei,
5654 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5657 "1.1.1.2/32 LB 1 buckets via: "
5660 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5661 FIB_TEST(fib_test_validate_entry(fei,
5662 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5664 &l1600_eos_o_1_1_1_1,
5665 &l1601_eos_o_1_1_1_2),
5666 "2.2.2.2/32 LB 2 buckets via: "
5667 "label 1600 via 1.1,1.1, "
5668 "label 16001 via 1.1.1.2");
5671 * update the via-entry so it no longer has labelled paths.
5672 * the LB for the recursive should exclue this via form its LB
5674 fei = fib_table_entry_update_one_path(fib_index,
5677 FIB_ENTRY_FLAG_NONE,
5680 tm->hw[1]->sw_if_index,
5681 ~0, // invalid fib index
5684 FIB_ROUTE_PATH_FLAG_NONE);
5686 FIB_TEST(fib_test_validate_entry(fei,
5687 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5690 "1.1.1.2/32 LB 1 buckets via: "
5693 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5694 FIB_TEST(fib_test_validate_entry(fei,
5695 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5697 &l1600_eos_o_1_1_1_1),
5698 "2.2.2.2/32 LB 1 buckets via: "
5699 "label 1600 via 1.1,1.1");
5701 dpo_reset(&non_eos_1_1_1_1);
5702 dpo_reset(&non_eos_1_1_1_2);
5705 * Add a recursive with no out-labels. We expect to use the IP of the via
5707 fib_prefix_t pfx_2_2_2_3_s_32 = {
5709 .fp_proto = FIB_PROTOCOL_IP4,
5711 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
5714 dpo_id_t ip_1_1_1_1 = DPO_NULL;
5716 fib_table_entry_update_one_path(fib_index,
5719 FIB_ENTRY_FLAG_NONE,
5721 &pfx_1_1_1_1_s_32.fp_addr,
5726 FIB_ROUTE_PATH_FLAG_NONE);
5728 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5730 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5733 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5736 .lb = ip_1_1_1_1.dpoi_index,
5740 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
5741 FIB_TEST(fib_test_validate_entry(fei,
5742 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5745 "2.2.2.2.3/32 LB 1 buckets via: "
5749 * Add a recursive with an imp-null out-label.
5750 * We expect to use the IP of the via
5752 fib_prefix_t pfx_2_2_2_4_s_32 = {
5754 .fp_proto = FIB_PROTOCOL_IP4,
5756 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
5760 fib_table_entry_update_one_path(fib_index,
5763 FIB_ENTRY_FLAG_NONE,
5765 &pfx_1_1_1_1_s_32.fp_addr,
5770 FIB_ROUTE_PATH_FLAG_NONE);
5772 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
5773 FIB_TEST(fib_test_validate_entry(fei,
5774 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5777 "2.2.2.2.4/32 LB 1 buckets via: "
5780 dpo_reset(&ip_1_1_1_1);
5785 fib_table_entry_delete(fib_index,
5789 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5790 FIB_TEST(fib_test_validate_entry(fei,
5791 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5793 &l1600_eos_o_1_1_1_1),
5794 "2.2.2.2/32 LB 1 buckets via: "
5795 "label 1600 via 1.1,1.1");
5797 fib_table_entry_delete(fib_index,
5801 FIB_TEST(fib_test_validate_entry(fei,
5802 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5805 "2.2.2.2/32 LB 1 buckets via: DROP");
5807 fib_table_entry_delete(fib_index,
5810 fib_table_entry_delete(fib_index,
5813 fib_table_entry_delete(fib_index,
5817 adj_unlock(ai_mpls_10_10_10_1);
5818 adj_unlock(ai_mpls_10_10_11_2);
5819 adj_unlock(ai_v4_10_10_11_1);
5820 adj_unlock(ai_v4_10_10_11_2);
5821 adj_unlock(ai_mpls_10_10_11_1);
5823 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5826 local0_pfx.fp_len = 32;
5827 fib_table_entry_delete(fib_index,
5829 FIB_SOURCE_INTERFACE);
5830 local0_pfx.fp_len = 24;
5831 fib_table_entry_delete(fib_index,
5833 FIB_SOURCE_INTERFACE);
5834 local1_pfx.fp_len = 32;
5835 fib_table_entry_delete(fib_index,
5837 FIB_SOURCE_INTERFACE);
5838 local1_pfx.fp_len = 24;
5839 fib_table_entry_delete(fib_index,
5841 FIB_SOURCE_INTERFACE);
5844 * +1 for the drop LB in the MPLS tables.
5846 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
5847 "Load-balance resources freed %d of %d",
5848 lb_count+1, pool_elts(load_balance_pool));
5851 #define N_TEST_CHILDREN 4
5852 #define PARENT_INDEX 0
5854 typedef struct fib_node_test_t_
5859 fib_node_back_walk_ctx_t *ctxs;
5863 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
5865 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
5867 #define FOR_EACH_TEST_CHILD(_tc) \
5868 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
5869 ii < N_TEST_CHILDREN+1; \
5870 ii++, (_tc) = &fib_test_nodes[ii])
5873 fib_test_child_get_node (fib_node_index_t index)
5875 return (&fib_test_nodes[index].node);
5878 static int fib_test_walk_spawns_walks;
5880 static fib_node_back_walk_rc_t
5881 fib_test_child_back_walk_notify (fib_node_t *node,
5882 fib_node_back_walk_ctx_t *ctx)
5884 fib_node_test_t *tc = (fib_node_test_t*) node;
5886 vec_add1(tc->ctxs, *ctx);
5888 if (1 == fib_test_walk_spawns_walks)
5889 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
5890 if (2 == fib_test_walk_spawns_walks)
5891 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
5892 FIB_WALK_PRIORITY_HIGH, ctx);
5894 return (FIB_NODE_BACK_WALK_CONTINUE);
5898 fib_test_child_last_lock_gone (fib_node_t *node)
5900 fib_node_test_t *tc = (fib_node_test_t *)node;
5906 * The FIB walk's graph node virtual function table
5908 static const fib_node_vft_t fib_test_child_vft = {
5909 .fnv_get = fib_test_child_get_node,
5910 .fnv_last_lock = fib_test_child_last_lock_gone,
5911 .fnv_back_walk = fib_test_child_back_walk_notify,
5915 * the function (that should have been static but isn't so I can do this)
5916 * that processes the walk from the async queue,
5918 f64 fib_walk_process_queues(vlib_main_t * vm,
5920 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
5923 fib_test_walk (void)
5925 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
5926 fib_node_test_t *tc;
5930 vm = vlib_get_main();
5931 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
5934 * init a fake node on which we will add children
5936 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
5937 FIB_NODE_TYPE_TEST);
5939 FOR_EACH_TEST_CHILD(tc)
5941 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
5942 fib_node_lock(&tc->node);
5945 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
5947 FIB_NODE_TYPE_TEST, ii);
5951 * enqueue a walk across the parents children.
5953 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
5955 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5956 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5957 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
5958 "Parent has %d children pre-walk",
5959 fib_node_list_get_size(PARENT()->fn_children));
5962 * give the walk a large amount of time so it gets to the end
5964 fib_walk_process_queues(vm, 1);
5966 FOR_EACH_TEST_CHILD(tc)
5968 FIB_TEST(1 == vec_len(tc->ctxs),
5969 "%d child visitsed %d times",
5970 ii, vec_len(tc->ctxs));
5973 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5974 "Queue is empty post walk");
5975 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5976 "Parent has %d children post walk",
5977 fib_node_list_get_size(PARENT()->fn_children));
5980 * walk again. should be no increase in the number of visits, since
5981 * the walk will have terminated.
5983 fib_walk_process_queues(vm, 1);
5985 FOR_EACH_TEST_CHILD(tc)
5987 FIB_TEST(0 == vec_len(tc->ctxs),
5988 "%d child visitsed %d times",
5989 ii, vec_len(tc->ctxs));
5993 * schedule a low and hig priority walk. expect the high to be performed
5995 * schedule the high prio walk first so that it is further from the head
5996 * of the dependency list. that way it won't merge with the low one.
5998 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
5999 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6001 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6002 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6003 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6004 FIB_WALK_PRIORITY_LOW, &low_ctx);
6006 fib_walk_process_queues(vm, 1);
6008 FOR_EACH_TEST_CHILD(tc)
6010 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6011 "%d child visitsed by high prio walk", ii);
6012 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6013 "%d child visitsed by low prio walk", ii);
6016 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6017 "Queue is empty post prio walk");
6018 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6019 "Parent has %d children post prio walk",
6020 fib_node_list_get_size(PARENT()->fn_children));
6023 * schedule 2 walks of the same priority that can be megred.
6024 * expect that each child is thus visited only once.
6026 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6027 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6029 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6030 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6031 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6032 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6034 fib_walk_process_queues(vm, 1);
6036 FOR_EACH_TEST_CHILD(tc)
6038 FIB_TEST(1 == vec_len(tc->ctxs),
6039 "%d child visitsed %d times during merge walk",
6040 ii, vec_len(tc->ctxs));
6043 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6044 "Queue is empty post merge walk");
6045 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6046 "Parent has %d children post merge walk",
6047 fib_node_list_get_size(PARENT()->fn_children));
6050 * schedule 2 walks of the same priority that cannot be megred.
6051 * expect that each child is thus visited twice and in the order
6052 * in which the walks were scheduled.
6054 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6055 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6057 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6058 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6059 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6060 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6062 fib_walk_process_queues(vm, 1);
6064 FOR_EACH_TEST_CHILD(tc)
6066 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6067 "%d child visitsed by high prio walk", ii);
6068 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6069 "%d child visitsed by low prio walk", ii);
6072 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6073 "Queue is empty post no-merge walk");
6074 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6075 "Parent has %d children post no-merge walk",
6076 fib_node_list_get_size(PARENT()->fn_children));
6079 * schedule a walk that makes one one child progress.
6080 * we do this by giving the queue draining process zero
6081 * time quanta. it's a do..while loop, so it does something.
6083 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
6085 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6086 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6087 fib_walk_process_queues(vm, 0);
6089 FOR_EACH_TEST_CHILD(tc)
6091 if (ii == N_TEST_CHILDREN)
6093 FIB_TEST(1 == vec_len(tc->ctxs),
6094 "%d child visitsed %d times in zero quanta walk",
6095 ii, vec_len(tc->ctxs));
6099 FIB_TEST(0 == vec_len(tc->ctxs),
6100 "%d child visitsed %d times in 0 quanta walk",
6101 ii, vec_len(tc->ctxs));
6104 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6105 "Queue is not empty post zero quanta walk");
6106 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6107 "Parent has %d children post zero qunta walk",
6108 fib_node_list_get_size(PARENT()->fn_children));
6113 fib_walk_process_queues(vm, 0);
6115 FOR_EACH_TEST_CHILD(tc)
6117 if (ii >= N_TEST_CHILDREN-1)
6119 FIB_TEST(1 == vec_len(tc->ctxs),
6120 "%d child visitsed %d times in 2nd zero quanta walk",
6121 ii, vec_len(tc->ctxs));
6125 FIB_TEST(0 == vec_len(tc->ctxs),
6126 "%d child visitsed %d times in 2nd 0 quanta walk",
6127 ii, vec_len(tc->ctxs));
6130 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6131 "Queue is not empty post zero quanta walk");
6132 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6133 "Parent has %d children post zero qunta walk",
6134 fib_node_list_get_size(PARENT()->fn_children));
6137 * schedule another walk that will catch-up and merge.
6139 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6140 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6141 fib_walk_process_queues(vm, 1);
6143 FOR_EACH_TEST_CHILD(tc)
6145 if (ii >= N_TEST_CHILDREN-1)
6147 FIB_TEST(2 == vec_len(tc->ctxs),
6148 "%d child visitsed %d times in 2nd zero quanta merge walk",
6149 ii, vec_len(tc->ctxs));
6154 FIB_TEST(1 == vec_len(tc->ctxs),
6155 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6156 ii, vec_len(tc->ctxs));
6160 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6161 "Queue is not empty post 2nd zero quanta merge walk");
6162 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6163 "Parent has %d children post 2nd zero qunta merge walk",
6164 fib_node_list_get_size(PARENT()->fn_children));
6167 * park a async walk in the middle of the list, then have an sync walk catch
6168 * it. same expectations as async catches async.
6170 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
6172 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6173 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6175 fib_walk_process_queues(vm, 0);
6176 fib_walk_process_queues(vm, 0);
6178 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6180 FOR_EACH_TEST_CHILD(tc)
6182 if (ii >= N_TEST_CHILDREN-1)
6184 FIB_TEST(2 == vec_len(tc->ctxs),
6185 "%d child visitsed %d times in sync catches async walk",
6186 ii, vec_len(tc->ctxs));
6191 FIB_TEST(1 == vec_len(tc->ctxs),
6192 "%d child visitsed %d times in sync catches async walk",
6193 ii, vec_len(tc->ctxs));
6197 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6198 "Queue is not empty post 2nd zero quanta merge walk");
6199 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6200 "Parent has %d children post 2nd zero qunta merge walk",
6201 fib_node_list_get_size(PARENT()->fn_children));
6204 * make the parent a child of one of its children, thus inducing a routing loop.
6206 fib_test_nodes[PARENT_INDEX].sibling =
6207 fib_node_child_add(FIB_NODE_TYPE_TEST,
6208 1, // the first child
6213 * execute a sync walk from the parent. each child visited spawns more sync
6214 * walks. we expect the walk to terminate.
6216 fib_test_walk_spawns_walks = 1;
6218 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6220 FOR_EACH_TEST_CHILD(tc)
6223 * child 1 - which is last in the list - has the loop.
6224 * the other children a re thus visitsed first. the we meet
6225 * child 1. we go round the loop again, visting the other children.
6226 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6231 FIB_TEST(1 == vec_len(tc->ctxs),
6232 "child %d visitsed %d times during looped sync walk",
6233 ii, vec_len(tc->ctxs));
6237 FIB_TEST(2 == vec_len(tc->ctxs),
6238 "child %d visitsed %d times during looped sync walk",
6239 ii, vec_len(tc->ctxs));
6243 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6244 "Parent has %d children post sync loop walk",
6245 fib_node_list_get_size(PARENT()->fn_children));
6248 * the walk doesn't reach the max depth because the infra knows that sync
6249 * meets sync implies a loop and bails early.
6251 FIB_TEST(high_ctx.fnbw_depth == 9,
6252 "Walk context depth %d post sync loop walk",
6253 high_ctx.fnbw_depth);
6256 * execute an async walk of the graph loop, with each child spawns sync walks
6258 high_ctx.fnbw_depth = 0;
6259 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6260 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6262 fib_walk_process_queues(vm, 1);
6264 FOR_EACH_TEST_CHILD(tc)
6267 * we don't really care how many times the children are visisted, as long as
6268 * it is more than once.
6270 FIB_TEST(1 <= vec_len(tc->ctxs),
6271 "child %d visitsed %d times during looped aync spawns sync walk",
6272 ii, vec_len(tc->ctxs));
6277 * execute an async walk of the graph loop, with each child spawns async walks
6279 fib_test_walk_spawns_walks = 2;
6280 high_ctx.fnbw_depth = 0;
6281 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6282 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6284 fib_walk_process_queues(vm, 1);
6286 FOR_EACH_TEST_CHILD(tc)
6289 * we don't really care how many times the children are visisted, as long as
6290 * it is more than once.
6292 FIB_TEST(1 <= vec_len(tc->ctxs),
6293 "child %d visitsed %d times during looped async spawns async walk",
6294 ii, vec_len(tc->ctxs));
6299 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6300 1, // the first child
6301 fib_test_nodes[PARENT_INDEX].sibling);
6306 FOR_EACH_TEST_CHILD(tc)
6308 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6310 fib_node_deinit(&tc->node);
6311 fib_node_unlock(&tc->node);
6313 fib_node_deinit(PARENT());
6316 * The parent will be destroyed when the last lock on it goes.
6317 * this test ensures all the walk objects are unlocking it.
6319 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6320 "Parent was destroyed");
6324 lfib_test_deagg (void)
6326 const mpls_label_t deag_label = 50;
6327 const u32 lfib_index = 0;
6328 const u32 fib_index = 0;
6329 dpo_id_t dpo = DPO_NULL;
6330 const dpo_id_t *dpo1;
6331 fib_node_index_t lfe;
6337 lb_count = pool_elts(load_balance_pool);
6339 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6343 * MPLS enable an interface so we get the MPLS table created
6345 mpls_sw_interface_enable_disable(&mpls_main,
6346 tm->hw[0]->sw_if_index,
6350 * Test the specials stack properly.
6352 fib_prefix_t exp_null_v6_pfx = {
6353 .fp_proto = FIB_PROTOCOL_MPLS,
6355 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6356 .fp_payload_proto = DPO_PROTO_IP6,
6358 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
6359 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
6361 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6362 format_mpls_eos_bit, MPLS_EOS);
6363 fib_entry_contribute_forwarding(lfe,
6364 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6366 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6367 lkd = lookup_dpo_get(dpo1->dpoi_index);
6369 FIB_TEST((fib_index == lkd->lkd_fib_index),
6370 "%U/%U is deag in %d %U",
6371 format_mpls_unicast_label, deag_label,
6372 format_mpls_eos_bit, MPLS_EOS,
6374 format_dpo_id, &dpo, 0);
6375 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6376 "%U/%U is dst deag",
6377 format_mpls_unicast_label, deag_label,
6378 format_mpls_eos_bit, MPLS_EOS);
6379 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
6380 "%U/%U is lookup in interface's table",
6381 format_mpls_unicast_label, deag_label,
6382 format_mpls_eos_bit, MPLS_EOS);
6383 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
6384 "%U/%U is %U dst deag",
6385 format_mpls_unicast_label, deag_label,
6386 format_mpls_eos_bit, MPLS_EOS,
6387 format_dpo_proto, lkd->lkd_proto);
6391 * A route deag route for EOS
6393 fib_prefix_t pfx = {
6394 .fp_proto = FIB_PROTOCOL_MPLS,
6396 .fp_label = deag_label,
6397 .fp_payload_proto = DPO_PROTO_IP4,
6399 lfe = fib_table_entry_path_add(lfib_index,
6402 FIB_ENTRY_FLAG_NONE,
6409 FIB_ROUTE_PATH_FLAG_NONE);
6411 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6413 format_mpls_unicast_label, deag_label,
6414 format_mpls_eos_bit, MPLS_EOS);
6416 fib_entry_contribute_forwarding(lfe,
6417 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6419 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6420 lkd = lookup_dpo_get(dpo1->dpoi_index);
6422 FIB_TEST((fib_index == lkd->lkd_fib_index),
6423 "%U/%U is deag in %d %U",
6424 format_mpls_unicast_label, deag_label,
6425 format_mpls_eos_bit, MPLS_EOS,
6427 format_dpo_id, &dpo, 0);
6428 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6429 "%U/%U is dst deag",
6430 format_mpls_unicast_label, deag_label,
6431 format_mpls_eos_bit, MPLS_EOS);
6432 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
6433 "%U/%U is %U dst deag",
6434 format_mpls_unicast_label, deag_label,
6435 format_mpls_eos_bit, MPLS_EOS,
6436 format_dpo_proto, lkd->lkd_proto);
6438 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6440 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6442 "%U/%U not present",
6443 format_mpls_unicast_label, deag_label,
6444 format_mpls_eos_bit, MPLS_EOS);
6447 * A route deag route for non-EOS
6449 pfx.fp_eos = MPLS_NON_EOS;
6450 lfe = fib_table_entry_path_add(lfib_index,
6453 FIB_ENTRY_FLAG_NONE,
6460 FIB_ROUTE_PATH_FLAG_NONE);
6462 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6464 format_mpls_unicast_label, deag_label,
6465 format_mpls_eos_bit, MPLS_NON_EOS);
6467 fib_entry_contribute_forwarding(lfe,
6468 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6470 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6471 lkd = lookup_dpo_get(dpo1->dpoi_index);
6473 FIB_TEST((fib_index == lkd->lkd_fib_index),
6474 "%U/%U is deag in %d %U",
6475 format_mpls_unicast_label, deag_label,
6476 format_mpls_eos_bit, MPLS_NON_EOS,
6478 format_dpo_id, &dpo, 0);
6479 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6480 "%U/%U is dst deag",
6481 format_mpls_unicast_label, deag_label,
6482 format_mpls_eos_bit, MPLS_NON_EOS);
6484 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
6485 "%U/%U is %U dst deag",
6486 format_mpls_unicast_label, deag_label,
6487 format_mpls_eos_bit, MPLS_NON_EOS,
6488 format_dpo_proto, lkd->lkd_proto);
6490 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6492 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6494 "%U/%U not present",
6495 format_mpls_unicast_label, deag_label,
6496 format_mpls_eos_bit, MPLS_EOS);
6499 mpls_sw_interface_enable_disable(&mpls_main,
6500 tm->hw[0]->sw_if_index,
6505 * +1 for the drop LB in the MPLS tables.
6507 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6508 "Load-balance resources freed %d of %d",
6509 lb_count+1, pool_elts(load_balance_pool));
6512 static clib_error_t *
6513 lfib_test (vlib_main_t * vm,
6514 unformat_input_t * input,
6515 vlib_cli_command_t * cmd_arg)
6517 fib_test_mk_intf(4);
6524 static clib_error_t *
6525 fib_test (vlib_main_t * vm,
6526 unformat_input_t * input,
6527 vlib_cli_command_t * cmd_arg)
6529 fib_test_mk_intf(4);
6531 if (unformat (input, "ip"))
6536 else if (unformat (input, "gre"))
6540 else if (unformat (input, "label"))
6544 else if (unformat (input, "ae"))
6548 else if (unformat (input, "walk"))
6555 * These walk UT aren't run as part of the full suite, since the
6556 * fib-walk process must be disabled in order for the tests to work
6570 VLIB_CLI_COMMAND (test_fib_command, static) = {
6572 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6573 .function = fib_test,
6576 VLIB_CLI_COMMAND (test_lfib_command, static) = {
6577 .path = "test lfib",
6578 .short_help = "mpls label fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6579 .function = lfib_test,
6583 fib_test_init (vlib_main_t *vm)
6588 VLIB_INIT_FUNCTION (fib_test_init);