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>
26 #include <vnet/dpo/ip_null_dpo.h>
28 #include <vnet/mpls/mpls.h>
30 #include <vnet/fib/fib_path_list.h>
31 #include <vnet/fib/fib_walk.h>
32 #include <vnet/fib/fib_node_list.h>
33 #include <vnet/fib/fib_urpf_list.h>
35 #define FIB_TEST_I(_cond, _comment, _args...) \
37 int _evald = (_cond); \
39 fformat(stderr, "FAIL:%d: " _comment "\n", \
42 fformat(stderr, "PASS:%d: " _comment "\n", \
47 #define FIB_TEST(_cond, _comment, _args...) \
49 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
51 ASSERT(!("FAIL: " _comment)); \
56 * A 'i'm not fussed is this is not efficient' store of test data
58 typedef struct test_main_t_ {
62 u32 hw_if_indicies[4];
66 vnet_hw_interface_t * hw[4];
69 static test_main_t test_main;
71 /* fake ethernet device class, distinct from "fake-ethX" */
72 static u8 * format_test_interface_name (u8 * s, va_list * args)
74 u32 dev_instance = va_arg (*args, u32);
75 return format (s, "test-eth%d", dev_instance);
78 static uword dummy_interface_tx (vlib_main_t * vm,
79 vlib_node_runtime_t * node,
82 clib_warning ("you shouldn't be here, leaking buffers...");
83 return frame->n_vectors;
86 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
87 .name = "Test interface",
88 .format_device_name = format_test_interface_name,
89 .tx_function = dummy_interface_tx,
92 static u8 *hw_address;
95 fib_test_mk_intf (u32 ninterfaces)
97 clib_error_t * error = NULL;
98 test_main_t *tm = &test_main;
102 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
107 vec_add1(hw_address, byte);
110 for (i = 0; i < ninterfaces; i++)
114 error = ethernet_register_interface(vnet_get_main(),
115 ethernet_hw_interface_class.index,
118 &tm->hw_if_indicies[i],
119 /* flag change */ 0);
121 FIB_TEST((NULL == error), "ADD interface %d", i);
123 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
124 tm->hw_if_indicies[i]);
125 vec_validate (ip4_main.fib_index_by_sw_if_index, tm->hw[i]->sw_if_index);
126 vec_validate (ip6_main.fib_index_by_sw_if_index, tm->hw[i]->sw_if_index);
127 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
128 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
129 error = vnet_sw_interface_set_flags(vnet_get_main(),
130 tm->hw[i]->sw_if_index,
131 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
132 FIB_TEST((NULL == error), "UP interface %d", i);
135 * re-eval after the inevitable realloc
137 for (i = 0; i < ninterfaces; i++)
139 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
140 tm->hw_if_indicies[i]);
144 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
146 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
147 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
148 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
149 fib_table_lookup(fib_index, (_via_prefix))); \
150 FIB_TEST(!dpo_cmp(_via_dpo, \
151 load_balance_get_bucket(_rec_dpo->dpoi_index, \
153 "%U is recursive via %U", \
154 format_fib_prefix, (_rec_prefix), \
155 format_fib_prefix, _via_prefix); \
158 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
160 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
161 fib_table_lookup_exact_match(fib_index, (_prefix))); \
162 const dpo_id_t *_dpo1 = \
163 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
164 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
165 format_dpo_type, _dpo1->dpoi_type); \
166 FIB_TEST((_ai == _dpo1->dpoi_index), \
167 "%U bucket %d resolves via %U", \
168 format_fib_prefix, (_prefix), \
170 format_dpo_id, _dpo1, 0); \
173 #define FIB_TEST_RPF(_cond, _comment, _args...) \
175 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
181 fib_test_urpf_is_equal (fib_node_index_t fei,
182 fib_forward_chain_type_t fct,
185 dpo_id_t dpo = DPO_INVALID;
186 fib_urpf_list_t *urpf;
193 fib_entry_contribute_forwarding(fei, fct, &dpo);
194 ui = load_balance_get_urpf(dpo.dpoi_index);
196 urpf = fib_urpf_list_get(ui);
198 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
199 "RPF:%U len %d == %d",
200 format_fib_urpf_list, ui,
201 num, vec_len(urpf->furpf_itfs));
202 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
203 "RPF:%U check-size %d == %d",
204 format_fib_urpf_list, ui,
205 num, vec_len(urpf->furpf_itfs));
207 for (ii = 0; ii < num; ii++)
209 adj_index_t ai = va_arg(ap, adj_index_t);
211 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
212 "RPF:%d item:%d - %d == %d",
213 ui, ii, ai, urpf->furpf_itfs[ii]);
214 FIB_TEST_RPF(fib_urpf_check(ui, ai),
227 fib_test_build_rewrite (u8 *eth_addr)
231 vec_validate(rewrite, 13);
233 memcpy(rewrite, eth_addr, 6);
234 memcpy(rewrite+6, eth_addr, 6);
243 * In the default table check for the presence and correct forwarding
244 * of the special entries
246 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
247 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
248 const ip_adjacency_t *adj;
249 const load_balance_t *lb;
255 ip46_address_t nh_10_10_10_1 = {
256 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
259 ip46_address_t nh_10_10_10_2 = {
260 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
265 /* Find or create FIB table 11 */
266 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
268 for (ii = 0; ii < 4; ii++)
270 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
273 fib_prefix_t pfx_0_0_0_0_s_0 = {
275 .fp_proto = FIB_PROTOCOL_IP4,
285 .fp_proto = FIB_PROTOCOL_IP4,
293 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
295 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
296 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
297 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
298 "Default route is DROP");
301 fei = fib_table_lookup(fib_index, &pfx);
302 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
303 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
304 "all 0s route is DROP");
306 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
308 fei = fib_table_lookup(fib_index, &pfx);
309 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
310 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
311 "all 1s route is DROP");
313 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
315 fei = fib_table_lookup(fib_index, &pfx);
316 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
317 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
318 "all-mcast route is DROP");
320 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
322 fei = fib_table_lookup(fib_index, &pfx);
323 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
324 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
325 "class-e route is DROP");
328 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
329 * all of which are special sourced and so none of which share path-lists.
330 * There are also 6 entries, and 6 non-shared path-lists, in the v6 default
334 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
335 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
336 fib_path_list_pool_size());
337 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
338 fib_entry_pool_size());
341 * add interface routes.
342 * validate presence of /24 attached and /32 recieve.
343 * test for the presence of the receive address in the glean and local adj
345 fib_prefix_t local_pfx = {
347 .fp_proto = FIB_PROTOCOL_IP4,
350 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
355 fib_table_entry_update_one_path(fib_index, &local_pfx,
356 FIB_SOURCE_INTERFACE,
357 (FIB_ENTRY_FLAG_CONNECTED |
358 FIB_ENTRY_FLAG_ATTACHED),
361 tm->hw[0]->sw_if_index,
362 ~0, // invalid fib index
365 FIB_ROUTE_PATH_FLAG_NONE);
366 fei = fib_table_lookup(fib_index, &local_pfx);
367 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
368 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
369 fib_entry_get_flags(fei)),
370 "Flags set on attached interface");
372 ai = fib_entry_get_adj(fei);
373 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
375 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
376 "attached interface adj is glean");
377 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
378 &adj->sub_type.glean.receive_addr)),
379 "attached interface adj is receive ok");
381 local_pfx.fp_len = 32;
382 fib_table_entry_update_one_path(fib_index, &local_pfx,
383 FIB_SOURCE_INTERFACE,
384 (FIB_ENTRY_FLAG_CONNECTED |
385 FIB_ENTRY_FLAG_LOCAL),
388 tm->hw[0]->sw_if_index,
389 ~0, // invalid fib index
392 FIB_ROUTE_PATH_FLAG_NONE);
393 fei = fib_table_lookup(fib_index, &local_pfx);
394 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
395 fib_entry_get_flags(fei)),
396 "Flags set on local interface");
398 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
400 dpo = fib_entry_contribute_ip_forwarding(fei);
401 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
402 "RPF list for local length 0");
403 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
404 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
405 "local interface adj is local");
406 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
408 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
410 "local interface adj is receive ok");
412 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
414 FIB_SOURCE_INTERFACE)),
415 "2 Interface Source'd prefixes");
418 * +2 interface routes +2 non-shared path-lists
420 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
421 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
422 fib_path_list_pool_size());
423 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
424 fib_entry_pool_size());
427 * Modify the default route to be via an adj not yet known.
428 * this sources the defalut route with the API source, which is
429 * a higher preference to the DEFAULT_ROUTE source
431 pfx.fp_addr.ip4.as_u32 = 0;
433 fib_table_entry_path_add(fib_index, &pfx,
438 tm->hw[0]->sw_if_index,
439 ~0, // invalid fib index
442 FIB_ROUTE_PATH_FLAG_NONE);
443 fei = fib_table_lookup(fib_index, &pfx);
444 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
445 "Flags set on API route");
447 FIB_TEST((fei == dfrt), "default route same index");
448 ai = fib_entry_get_adj(fei);
449 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
451 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
452 "adj is incomplete");
453 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
454 "adj nbr next-hop ok");
455 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
458 "1 API Source'd prefixes");
461 * find the adj in the shared db
463 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
466 tm->hw[0]->sw_if_index);
467 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
468 adj_unlock(locked_ai);
471 * +1 shared path-list
473 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
474 fib_path_list_db_size());
475 FIB_TEST((NBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
476 fib_path_list_pool_size());
477 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
478 fib_entry_pool_size());
481 * remove the API source from the default route. We expected
482 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
484 pfx.fp_addr.ip4.as_u32 = 0;
486 fib_table_entry_path_remove(fib_index, &pfx,
490 tm->hw[0]->sw_if_index,
491 ~0, // non-recursive path, so no FIB index
493 FIB_ROUTE_PATH_FLAG_NONE);
495 fei = fib_table_lookup(fib_index, &pfx);
497 FIB_TEST((fei == dfrt), "default route same index");
498 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
499 "Default route is DROP");
502 * -1 shared-path-list
504 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
505 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
506 fib_path_list_pool_size());
507 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
508 fib_entry_pool_size());
511 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
513 fib_prefix_t pfx_10_10_10_1_s_32 = {
515 .fp_proto = FIB_PROTOCOL_IP4,
518 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
521 fib_prefix_t pfx_10_10_10_2_s_32 = {
523 .fp_proto = FIB_PROTOCOL_IP4,
526 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
529 fib_prefix_t pfx_11_11_11_11_s_32 = {
531 .fp_proto = FIB_PROTOCOL_IP4,
534 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
538 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
541 ip46_address_t nh_12_12_12_12 = {
542 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
544 adj_index_t ai_12_12_12_12;
547 * Add a route via an incomplete ADJ. then complete the ADJ
548 * Expect the route LB is updated to use complete adj type.
550 fei = fib_table_entry_update_one_path(fib_index,
551 &pfx_11_11_11_11_s_32,
553 FIB_ENTRY_FLAG_ATTACHED,
555 &pfx_10_10_10_1_s_32.fp_addr,
556 tm->hw[0]->sw_if_index,
557 ~0, // invalid fib index
560 FIB_ROUTE_PATH_FLAG_NONE);
562 dpo = fib_entry_contribute_ip_forwarding(fei);
563 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
564 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
565 "11.11.11.11/32 via incomplete adj");
567 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
569 &pfx_10_10_10_1_s_32.fp_addr,
570 tm->hw[0]->sw_if_index);
571 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
572 adj = adj_get(ai_01);
573 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
574 "adj is incomplete");
575 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
576 &adj->sub_type.nbr.next_hop)),
577 "adj nbr next-hop ok");
579 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
580 fib_test_build_rewrite(eth_addr));
581 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
583 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
584 &adj->sub_type.nbr.next_hop)),
585 "adj nbr next-hop ok");
586 ai = fib_entry_get_adj(fei);
587 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
589 dpo = fib_entry_contribute_ip_forwarding(fei);
590 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
591 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
592 "11.11.11.11/32 via complete adj");
593 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
594 tm->hw[0]->sw_if_index),
595 "RPF list for adj-fib contains adj");
597 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
600 tm->hw[1]->sw_if_index);
601 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
602 adj = adj_get(ai_12_12_12_12);
603 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
604 "adj is incomplete");
605 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
606 &adj->sub_type.nbr.next_hop)),
607 "adj nbr next-hop ok");
608 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
609 fib_test_build_rewrite(eth_addr));
610 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
616 fei = fib_table_entry_update_one_path(fib_index,
617 &pfx_10_10_10_1_s_32,
619 FIB_ENTRY_FLAG_ATTACHED,
621 &pfx_10_10_10_1_s_32.fp_addr,
622 tm->hw[0]->sw_if_index,
623 ~0, // invalid fib index
626 FIB_ROUTE_PATH_FLAG_NONE);
627 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
628 "Flags set on adj-fib");
629 ai = fib_entry_get_adj(fei);
630 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
632 fib_table_entry_path_remove(fib_index,
633 &pfx_11_11_11_11_s_32,
636 &pfx_10_10_10_1_s_32.fp_addr,
637 tm->hw[0]->sw_if_index,
638 ~0, // invalid fib index
640 FIB_ROUTE_PATH_FLAG_NONE);
644 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
646 &pfx_10_10_10_2_s_32.fp_addr,
647 tm->hw[0]->sw_if_index);
648 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
649 adj = adj_get(ai_02);
650 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
651 "adj is incomplete");
652 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
653 &adj->sub_type.nbr.next_hop)),
654 "adj nbr next-hop ok");
656 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
657 fib_test_build_rewrite(eth_addr));
658 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
660 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
661 &adj->sub_type.nbr.next_hop)),
662 "adj nbr next-hop ok");
663 FIB_TEST((ai_01 != ai_02), "ADJs are different");
665 fib_table_entry_update_one_path(fib_index,
666 &pfx_10_10_10_2_s_32,
670 &pfx_10_10_10_2_s_32.fp_addr,
671 tm->hw[0]->sw_if_index,
672 ~0, // invalid fib index
675 FIB_ROUTE_PATH_FLAG_NONE);
677 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
678 ai = fib_entry_get_adj(fei);
679 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
682 * +2 adj-fibs, and their non-shared path-lists
684 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
685 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
686 fib_path_list_pool_size());
687 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
688 fib_entry_pool_size());
691 * Add 2 routes via the first ADJ. ensure path-list sharing
693 fib_prefix_t pfx_1_1_1_1_s_32 = {
695 .fp_proto = FIB_PROTOCOL_IP4,
698 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
702 fib_table_entry_path_add(fib_index,
708 tm->hw[0]->sw_if_index,
709 ~0, // invalid fib index
712 FIB_ROUTE_PATH_FLAG_NONE);
713 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
714 ai = fib_entry_get_adj(fei);
715 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
718 * +1 entry and a shared path-list
720 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
721 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
722 fib_path_list_pool_size());
723 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
724 fib_entry_pool_size());
727 fib_prefix_t pfx_1_1_2_0_s_24 = {
729 .fp_proto = FIB_PROTOCOL_IP4,
731 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
735 fib_table_entry_path_add(fib_index,
741 tm->hw[0]->sw_if_index,
742 ~0, // invalid fib index
745 FIB_ROUTE_PATH_FLAG_NONE);
746 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
747 ai = fib_entry_get_adj(fei);
748 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
753 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
754 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
755 fib_path_list_pool_size());
756 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
757 fib_entry_pool_size());
760 * modify 1.1.2.0/24 to use multipath.
762 fib_table_entry_path_add(fib_index,
768 tm->hw[0]->sw_if_index,
769 ~0, // invalid fib index
772 FIB_ROUTE_PATH_FLAG_NONE);
773 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
774 dpo = fib_entry_contribute_ip_forwarding(fei);
775 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
776 1, tm->hw[0]->sw_if_index),
777 "RPF list for 1.1.2.0/24 contains both adjs");
779 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
780 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
781 FIB_TEST((ai_01 == dpo1->dpoi_index),
782 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
783 ai_01, dpo1->dpoi_index);
785 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
786 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
787 FIB_TEST((ai_02 == dpo1->dpoi_index),
788 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
793 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
794 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
795 fib_path_list_pool_size());
796 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
797 fib_entry_pool_size());
802 fib_table_entry_path_remove(fib_index,
807 tm->hw[0]->sw_if_index,
810 FIB_ROUTE_PATH_FLAG_NONE);
811 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
812 dpo = fib_entry_contribute_ip_forwarding(fei);
813 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
814 1, tm->hw[0]->sw_if_index),
815 "RPF list for 1.1.2.0/24 contains one adj");
817 ai = fib_entry_get_adj(fei);
818 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
823 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
824 fib_path_list_db_size());
825 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
826 fib_path_list_pool_size());
827 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
828 fib_entry_pool_size());
831 * Add 2 recursive routes:
832 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
833 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
835 fib_prefix_t bgp_100_pfx = {
837 .fp_proto = FIB_PROTOCOL_IP4,
839 /* 100.100.100.100/32 */
840 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
844 ip46_address_t nh_1_1_1_1 = {
845 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
848 fei = fib_table_entry_path_add(fib_index,
854 ~0, // no index provided.
855 fib_index, // nexthop in same fib as route
858 FIB_ROUTE_PATH_FLAG_NONE);
860 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
861 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
862 tm->hw[0]->sw_if_index),
863 "RPF list for adj-fib contains adj");
866 * +1 entry and +1 shared-path-list
868 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
869 fib_path_list_db_size());
870 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
871 fib_path_list_pool_size());
872 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
873 fib_entry_pool_size());
875 fib_prefix_t bgp_101_pfx = {
877 .fp_proto = FIB_PROTOCOL_IP4,
879 /* 100.100.100.101/32 */
880 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
884 fib_table_entry_path_add(fib_index,
890 ~0, // no index provided.
891 fib_index, // nexthop in same fib as route
894 FIB_ROUTE_PATH_FLAG_NONE);
896 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
897 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
898 tm->hw[0]->sw_if_index),
899 "RPF list for adj-fib contains adj");
902 * +1 entry, but the recursive path-list is shared.
904 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
905 fib_path_list_db_size());
906 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
907 fib_path_list_pool_size());
908 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
909 fib_entry_pool_size());
912 * An EXCLUSIVE route; one where the user (me) provides the exclusive
913 * adjacency through which the route will resovle
915 fib_prefix_t ex_pfx = {
917 .fp_proto = FIB_PROTOCOL_IP4,
920 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
924 fib_table_entry_special_add(fib_index,
927 FIB_ENTRY_FLAG_EXCLUSIVE,
929 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
930 FIB_TEST((ai == fib_entry_get_adj(fei)),
931 "Exclusive route links to user adj");
933 fib_table_entry_special_remove(fib_index,
936 FIB_TEST(FIB_NODE_INDEX_INVALID ==
937 fib_table_lookup_exact_match(fib_index, &ex_pfx),
938 "Exclusive reoute removed");
941 * An EXCLUSIVE route; one where the user (me) provides the exclusive
942 * adjacency through which the route will resovle
944 dpo_id_t ex_dpo = DPO_INVALID;
946 lookup_dpo_add_or_lock_w_fib_index(fib_index,
948 LOOKUP_INPUT_DST_ADDR,
949 LOOKUP_TABLE_FROM_CONFIG,
952 fib_table_entry_special_dpo_add(fib_index,
955 FIB_ENTRY_FLAG_EXCLUSIVE,
957 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
958 dpo = fib_entry_contribute_ip_forwarding(fei);
959 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
960 "exclusive remote uses lookup DPO");
963 * update the exclusive to use a different DPO
965 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
966 IP_NULL_ACTION_SEND_ICMP_UNREACH,
968 fib_table_entry_special_dpo_update(fib_index,
971 FIB_ENTRY_FLAG_EXCLUSIVE,
973 dpo = fib_entry_contribute_ip_forwarding(fei);
974 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
975 "exclusive remote uses now uses NULL DPO");
977 fib_table_entry_special_remove(fib_index,
980 FIB_TEST(FIB_NODE_INDEX_INVALID ==
981 fib_table_lookup_exact_match(fib_index, &ex_pfx),
982 "Exclusive reoute removed");
986 * Add a recursive route:
987 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
989 fib_prefix_t bgp_200_pfx = {
991 .fp_proto = FIB_PROTOCOL_IP4,
993 /* 200.200.200.200/32 */
994 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
998 fib_prefix_t pfx_1_1_1_2_s_32 = {
1000 .fp_proto = FIB_PROTOCOL_IP4,
1002 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1006 fib_table_entry_path_add(fib_index,
1009 FIB_ENTRY_FLAG_NONE,
1011 &pfx_1_1_1_2_s_32.fp_addr,
1012 ~0, // no index provided.
1013 fib_index, // nexthop in same fib as route
1016 FIB_ROUTE_PATH_FLAG_NONE);
1018 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1021 * the adj should be recursive via drop, since the route resolves via
1022 * the default route, which is itself a DROP
1024 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1025 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1026 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1027 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1028 "RPF list for 1.1.1.2/32 contains 0 adjs");
1031 * +2 entry and +1 shared-path-list
1033 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1034 fib_path_list_db_size());
1035 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1036 fib_path_list_pool_size());
1037 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1038 fib_entry_pool_size());
1041 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1042 * The paths are sort by NH first. in this case the the path with greater
1043 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1045 fib_prefix_t pfx_1_2_3_4_s_32 = {
1047 .fp_proto = FIB_PROTOCOL_IP4,
1049 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1052 fib_table_entry_path_add(fib_index,
1055 FIB_ENTRY_FLAG_NONE,
1058 tm->hw[0]->sw_if_index,
1062 FIB_ROUTE_PATH_FLAG_NONE);
1063 fei = fib_table_entry_path_add(fib_index,
1066 FIB_ENTRY_FLAG_NONE,
1069 tm->hw[1]->sw_if_index,
1073 FIB_ROUTE_PATH_FLAG_NONE);
1075 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1076 dpo = fib_entry_contribute_ip_forwarding(fei);
1077 lb = load_balance_get(dpo->dpoi_index);
1078 FIB_TEST((lb->lb_n_buckets == 4),
1079 "1.2.3.4/32 LB has %d bucket",
1082 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1083 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1084 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1085 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1087 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1088 tm->hw[0]->sw_if_index,
1089 tm->hw[1]->sw_if_index),
1090 "RPF list for 1.2.3.4/32 contains both adjs");
1094 * Unequal Cost load-balance. 4:1 ratio.
1095 * fits in a 16 bucket LB with ratio 13:3
1097 fib_prefix_t pfx_1_2_3_5_s_32 = {
1099 .fp_proto = FIB_PROTOCOL_IP4,
1101 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1104 fib_table_entry_path_add(fib_index,
1107 FIB_ENTRY_FLAG_NONE,
1110 tm->hw[1]->sw_if_index,
1114 FIB_ROUTE_PATH_FLAG_NONE);
1115 fei = fib_table_entry_path_add(fib_index,
1118 FIB_ENTRY_FLAG_NONE,
1121 tm->hw[0]->sw_if_index,
1125 FIB_ROUTE_PATH_FLAG_NONE);
1127 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1128 dpo = fib_entry_contribute_ip_forwarding(fei);
1129 lb = load_balance_get(dpo->dpoi_index);
1130 FIB_TEST((lb->lb_n_buckets == 16),
1131 "1.2.3.5/32 LB has %d bucket",
1134 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1135 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1136 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1137 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1138 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1139 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1140 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1141 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1142 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1143 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1144 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1145 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1146 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1147 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1148 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1149 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1151 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1152 tm->hw[0]->sw_if_index,
1153 tm->hw[1]->sw_if_index),
1154 "RPF list for 1.2.3.4/32 contains both adjs");
1157 * A recursive via the two unequal cost entries
1159 fib_prefix_t bgp_44_s_32 = {
1161 .fp_proto = FIB_PROTOCOL_IP4,
1163 /* 200.200.200.201/32 */
1164 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1167 fei = fib_table_entry_path_add(fib_index,
1170 FIB_ENTRY_FLAG_NONE,
1172 &pfx_1_2_3_4_s_32.fp_addr,
1177 FIB_ROUTE_PATH_FLAG_NONE);
1178 fei = fib_table_entry_path_add(fib_index,
1181 FIB_ENTRY_FLAG_NONE,
1183 &pfx_1_2_3_5_s_32.fp_addr,
1188 FIB_ROUTE_PATH_FLAG_NONE);
1190 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1191 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1192 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1193 tm->hw[0]->sw_if_index,
1194 tm->hw[1]->sw_if_index),
1195 "RPF list for 1.2.3.4/32 contains both adjs");
1198 * test the uRPF check functions
1200 dpo_id_t dpo_44 = DPO_INVALID;
1203 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1204 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
1206 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
1207 "uRPF check for 68.68.68.68/32 on %d OK",
1208 tm->hw[0]->sw_if_index);
1209 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
1210 "uRPF check for 68.68.68.68/32 on %d OK",
1211 tm->hw[1]->sw_if_index);
1212 FIB_TEST(!fib_urpf_check(urpfi, 99),
1213 "uRPF check for 68.68.68.68/32 on 99 not-OK",
1217 fib_table_entry_delete(fib_index,
1220 fib_table_entry_delete(fib_index,
1223 fib_table_entry_delete(fib_index,
1228 * Add a recursive route:
1229 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
1231 fib_prefix_t bgp_201_pfx = {
1233 .fp_proto = FIB_PROTOCOL_IP4,
1235 /* 200.200.200.201/32 */
1236 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1240 fib_prefix_t pfx_1_1_1_200_s_32 = {
1242 .fp_proto = FIB_PROTOCOL_IP4,
1244 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1248 fib_table_entry_path_add(fib_index,
1251 FIB_ENTRY_FLAG_NONE,
1253 &pfx_1_1_1_200_s_32.fp_addr,
1254 ~0, // no index provided.
1255 fib_index, // nexthop in same fib as route
1258 FIB_ROUTE_PATH_FLAG_NONE);
1260 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1262 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1263 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1264 "Flags set on RR via non-attached");
1265 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1266 "RPF list for BGP route empty");
1269 * +2 entry (BGP & RR) and +1 shared-path-list
1271 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1272 fib_path_list_db_size());
1273 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1274 fib_path_list_pool_size());
1275 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1276 fib_entry_pool_size());
1279 * insert a route that covers the missing 1.1.1.2/32. we epxect
1280 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
1282 fib_prefix_t pfx_1_1_1_0_s_24 = {
1284 .fp_proto = FIB_PROTOCOL_IP4,
1287 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1291 fib_table_entry_path_add(fib_index,
1294 FIB_ENTRY_FLAG_NONE,
1297 tm->hw[0]->sw_if_index,
1298 ~0, // invalid fib index
1301 FIB_ROUTE_PATH_FLAG_NONE);
1302 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
1303 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1304 ai = fib_entry_get_adj(fei);
1305 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
1306 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1307 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1308 ai = fib_entry_get_adj(fei);
1309 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
1310 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1311 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1312 ai = fib_entry_get_adj(fei);
1313 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
1316 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
1318 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1319 fib_path_list_db_size());
1320 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1321 fib_path_list_pool_size());
1322 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1323 fib_entry_pool_size());
1326 * the recursive adj for 200.200.200.200 should be updated.
1328 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1329 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1330 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
1331 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1332 tm->hw[0]->sw_if_index),
1333 "RPF list for BGP route has itf index 0");
1336 * insert a more specific route than 1.1.1.0/24 that also covers the
1337 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
1338 * 200.200.200.200 to resolve through it.
1340 fib_prefix_t pfx_1_1_1_0_s_28 = {
1342 .fp_proto = FIB_PROTOCOL_IP4,
1345 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1349 fib_table_entry_path_add(fib_index,
1352 FIB_ENTRY_FLAG_NONE,
1355 tm->hw[0]->sw_if_index,
1356 ~0, // invalid fib index
1359 FIB_ROUTE_PATH_FLAG_NONE);
1360 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
1361 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1362 ai = fib_entry_get_adj(fei);
1363 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
1366 * +1 entry. +1 shared path-list
1368 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
1369 fib_path_list_db_size());
1370 FIB_TEST((NBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
1371 fib_path_list_pool_size());
1372 FIB_TEST((NBR+14 == fib_entry_pool_size()), "entry pool size is %d",
1373 fib_entry_pool_size());
1376 * the recursive adj for 200.200.200.200 should be updated.
1377 * 200.200.200.201 remains unchanged.
1379 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1380 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1383 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
1385 fib_table_entry_path_remove(fib_index,
1390 tm->hw[0]->sw_if_index,
1393 FIB_ROUTE_PATH_FLAG_NONE);
1394 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
1395 FIB_NODE_INDEX_INVALID),
1396 "1.1.1.0/28 removed");
1397 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
1398 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
1399 "1.1.1.0/28 lookup via /24");
1400 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1401 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1404 * -1 entry. -1 shared path-list
1406 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1407 fib_path_list_db_size());
1408 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1409 fib_path_list_pool_size());
1410 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1411 fib_entry_pool_size());
1414 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
1416 fib_table_entry_path_remove(fib_index,
1421 tm->hw[0]->sw_if_index,
1424 FIB_ROUTE_PATH_FLAG_NONE);
1425 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
1426 FIB_NODE_INDEX_INVALID),
1427 "1.1.1.0/24 removed");
1429 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1430 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1431 "1.1.1.2/32 route is DROP");
1432 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1433 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1434 "1.1.1.200/32 route is DROP");
1436 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1437 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1442 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1443 fib_path_list_db_size());
1444 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1445 fib_path_list_pool_size());
1446 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1447 fib_entry_pool_size());
1450 * insert the missing 1.1.1.2/32
1452 fei = fib_table_entry_path_add(fib_index,
1455 FIB_ENTRY_FLAG_NONE,
1458 tm->hw[0]->sw_if_index,
1459 ~0, // invalid fib index
1462 FIB_ROUTE_PATH_FLAG_NONE);
1463 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1464 ai = fib_entry_get_adj(fei);
1465 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
1467 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1468 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1471 * no change. 1.1.1.2/32 was already there RR sourced.
1473 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1474 fib_path_list_db_size());
1475 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1476 fib_path_list_pool_size());
1477 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1478 fib_entry_pool_size());
1481 * remove 200.200.200.201/32 which does not have a valid via FIB
1483 fib_table_entry_path_remove(fib_index,
1487 &pfx_1_1_1_200_s_32.fp_addr,
1488 ~0, // no index provided.
1491 FIB_ROUTE_PATH_FLAG_NONE);
1494 * -2 entries (BGP and RR). -1 shared path-list;
1496 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1497 FIB_NODE_INDEX_INVALID),
1498 "200.200.200.201/32 removed");
1499 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
1500 FIB_NODE_INDEX_INVALID),
1501 "1.1.1.200/32 removed");
1503 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1504 fib_path_list_db_size());
1505 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1506 fib_path_list_pool_size());
1507 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1508 fib_entry_pool_size());
1511 * remove 200.200.200.200/32 which does have a valid via FIB
1513 fib_table_entry_path_remove(fib_index,
1517 &pfx_1_1_1_2_s_32.fp_addr,
1518 ~0, // no index provided.
1521 FIB_ROUTE_PATH_FLAG_NONE);
1523 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1524 FIB_NODE_INDEX_INVALID),
1525 "200.200.200.200/32 removed");
1526 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
1527 FIB_NODE_INDEX_INVALID),
1528 "1.1.1.2/32 still present");
1531 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
1533 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1534 fib_path_list_db_size());
1535 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1536 fib_path_list_pool_size());
1537 FIB_TEST((NBR+9 == fib_entry_pool_size()), "entry pool size is %d",
1538 fib_entry_pool_size());
1541 * A recursive prefix that has a 2 path load-balance.
1542 * It also shares a next-hop with other BGP prefixes and hence
1543 * test the ref counting of RR sourced prefixes and 2 level LB.
1545 const fib_prefix_t bgp_102 = {
1547 .fp_proto = FIB_PROTOCOL_IP4,
1549 /* 100.100.100.101/32 */
1550 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
1553 fib_table_entry_path_add(fib_index,
1556 FIB_ENTRY_FLAG_NONE,
1558 &pfx_1_1_1_1_s_32.fp_addr,
1559 ~0, // no index provided.
1560 fib_index, // same as route
1563 FIB_ROUTE_PATH_FLAG_NONE);
1564 fib_table_entry_path_add(fib_index,
1567 FIB_ENTRY_FLAG_NONE,
1569 &pfx_1_1_1_2_s_32.fp_addr,
1570 ~0, // no index provided.
1571 fib_index, // same as route's FIB
1574 FIB_ROUTE_PATH_FLAG_NONE);
1575 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1576 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
1577 dpo = fib_entry_contribute_ip_forwarding(fei);
1579 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
1580 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1581 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
1582 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1584 lb = load_balance_get(dpo->dpoi_index);
1585 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
1586 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1587 "First via 10.10.10.1");
1588 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
1589 "Second via 10.10.10.1");
1591 fib_table_entry_path_remove(fib_index,
1595 &pfx_1_1_1_1_s_32.fp_addr,
1596 ~0, // no index provided.
1597 fib_index, // same as route's FIB
1599 FIB_ROUTE_PATH_FLAG_NONE);
1600 fib_table_entry_path_remove(fib_index,
1604 &pfx_1_1_1_2_s_32.fp_addr,
1605 ~0, // no index provided.
1606 fib_index, // same as route's FIB
1608 FIB_ROUTE_PATH_FLAG_NONE);
1609 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1610 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
1613 * remove the remaining recursives
1615 fib_table_entry_path_remove(fib_index,
1619 &pfx_1_1_1_1_s_32.fp_addr,
1620 ~0, // no index provided.
1621 fib_index, // same as route's FIB
1623 FIB_ROUTE_PATH_FLAG_NONE);
1624 fib_table_entry_path_remove(fib_index,
1628 &pfx_1_1_1_1_s_32.fp_addr,
1629 ~0, // no index provided.
1630 fib_index, // same as route's FIB
1632 FIB_ROUTE_PATH_FLAG_NONE);
1633 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
1634 FIB_NODE_INDEX_INVALID),
1635 "100.100.100.100/32 removed");
1636 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
1637 FIB_NODE_INDEX_INVALID),
1638 "100.100.100.101/32 removed");
1641 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
1643 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1644 fib_path_list_db_size());
1645 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1646 fib_path_list_pool_size());
1647 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1648 fib_entry_pool_size());
1651 * Add a recursive route via a connected cover, using an adj-fib that does exist
1653 fib_table_entry_path_add(fib_index,
1656 FIB_ENTRY_FLAG_NONE,
1659 ~0, // no index provided.
1660 fib_index, // Same as route's FIB
1663 FIB_ROUTE_PATH_FLAG_NONE);
1666 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
1668 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1669 fib_path_list_db_size());
1670 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1671 fib_path_list_pool_size());
1672 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1673 fib_entry_pool_size());
1675 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
1676 dpo = fib_entry_contribute_ip_forwarding(fei);
1678 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
1679 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1681 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1682 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
1684 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1685 "Flags set on RR via existing attached");
1688 * Add a recursive route via a connected cover, using and adj-fib that does
1691 ip46_address_t nh_10_10_10_3 = {
1692 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
1694 fib_prefix_t pfx_10_10_10_3 = {
1696 .fp_proto = FIB_PROTOCOL_IP4,
1697 .fp_addr = nh_10_10_10_3,
1700 fib_table_entry_path_add(fib_index,
1703 FIB_ENTRY_FLAG_NONE,
1706 ~0, // no index provided.
1710 FIB_ROUTE_PATH_FLAG_NONE);
1713 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
1714 * one unshared non-recursive via 10.10.10.3
1716 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1717 fib_path_list_db_size());
1718 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1719 fib_path_list_pool_size());
1720 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1721 fib_entry_pool_size());
1723 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1726 tm->hw[0]->sw_if_index);
1728 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
1729 dpo = fib_entry_contribute_ip_forwarding(fei);
1730 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
1731 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1733 ai = fib_entry_get_adj(fei);
1734 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
1735 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
1736 fib_entry_get_flags(fei)),
1737 "Flags set on RR via non-existing attached");
1739 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1740 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
1745 * remove the recursives
1747 fib_table_entry_path_remove(fib_index,
1752 ~0, // no index provided.
1753 fib_index, // same as route's FIB
1755 FIB_ROUTE_PATH_FLAG_NONE);
1756 fib_table_entry_path_remove(fib_index,
1761 ~0, // no index provided.
1762 fib_index, // same as route's FIB
1764 FIB_ROUTE_PATH_FLAG_NONE);
1766 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1767 FIB_NODE_INDEX_INVALID),
1768 "200.200.200.201/32 removed");
1769 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1770 FIB_NODE_INDEX_INVALID),
1771 "200.200.200.200/32 removed");
1772 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
1773 FIB_NODE_INDEX_INVALID),
1774 "10.10.10.3/32 removed");
1777 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
1778 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
1780 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1781 fib_path_list_db_size());
1782 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1783 fib_path_list_pool_size());
1784 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1785 fib_entry_pool_size());
1790 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
1792 fib_prefix_t pfx_5_5_5_5_s_32 = {
1794 .fp_proto = FIB_PROTOCOL_IP4,
1796 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
1799 fib_prefix_t pfx_5_5_5_6_s_32 = {
1801 .fp_proto = FIB_PROTOCOL_IP4,
1803 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
1806 fib_prefix_t pfx_5_5_5_7_s_32 = {
1808 .fp_proto = FIB_PROTOCOL_IP4,
1810 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
1814 fib_table_entry_path_add(fib_index,
1817 FIB_ENTRY_FLAG_NONE,
1819 &pfx_5_5_5_6_s_32.fp_addr,
1820 ~0, // no index provided.
1824 FIB_ROUTE_PATH_FLAG_NONE);
1825 fib_table_entry_path_add(fib_index,
1828 FIB_ENTRY_FLAG_NONE,
1830 &pfx_5_5_5_7_s_32.fp_addr,
1831 ~0, // no index provided.
1835 FIB_ROUTE_PATH_FLAG_NONE);
1836 fib_table_entry_path_add(fib_index,
1839 FIB_ENTRY_FLAG_NONE,
1841 &pfx_5_5_5_5_s_32.fp_addr,
1842 ~0, // no index provided.
1846 FIB_ROUTE_PATH_FLAG_NONE);
1848 * +3 entries, +3 shared path-list
1850 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1851 fib_path_list_db_size());
1852 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1853 fib_path_list_pool_size());
1854 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1855 fib_entry_pool_size());
1858 * All the entries have only looped paths, so they are all drop
1860 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1861 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1862 "LB for 5.5.5.7/32 is via adj for DROP");
1863 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1864 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1865 "LB for 5.5.5.5/32 is via adj for DROP");
1866 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1867 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1868 "LB for 5.5.5.6/32 is via adj for DROP");
1871 * provide 5.5.5.6/32 with alternate path.
1872 * this will allow only 5.5.5.6/32 to forward with this path, the others
1873 * are still drop since the loop is still present.
1875 fib_table_entry_path_add(fib_index,
1878 FIB_ENTRY_FLAG_NONE,
1881 tm->hw[0]->sw_if_index,
1885 FIB_ROUTE_PATH_FLAG_NONE);
1888 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1889 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1891 lb = load_balance_get(dpo1->dpoi_index);
1892 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
1894 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1895 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1896 FIB_TEST((ai_01 == dpo2->dpoi_index),
1897 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
1899 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1900 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1901 "LB for 5.5.5.7/32 is via adj for DROP");
1902 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1903 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1904 "LB for 5.5.5.5/32 is via adj for DROP");
1907 * remove the alternate path for 5.5.5.6/32
1910 fib_table_entry_path_remove(fib_index,
1915 tm->hw[0]->sw_if_index,
1918 FIB_ROUTE_PATH_FLAG_NONE);
1920 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1921 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1922 "LB for 5.5.5.7/32 is via adj for DROP");
1923 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1924 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1925 "LB for 5.5.5.5/32 is via adj for DROP");
1926 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1927 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1928 "LB for 5.5.5.6/32 is via adj for DROP");
1931 * break the loop by giving 5.5.5.5/32 a new set of paths
1932 * expect all to forward via this new path.
1934 fib_table_entry_update_one_path(fib_index,
1937 FIB_ENTRY_FLAG_NONE,
1940 tm->hw[0]->sw_if_index,
1941 ~0, // invalid fib index
1944 FIB_ROUTE_PATH_FLAG_NONE);
1946 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1947 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1948 lb = load_balance_get(dpo1->dpoi_index);
1949 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
1951 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1952 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1953 FIB_TEST((ai_01 == dpo2->dpoi_index),
1954 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
1956 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
1957 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1959 lb = load_balance_get(dpo2->dpoi_index);
1960 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1961 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
1962 "5.5.5.5.7 via 5.5.5.5");
1964 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
1965 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1967 lb = load_balance_get(dpo1->dpoi_index);
1968 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1969 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
1970 "5.5.5.5.6 via 5.5.5.7");
1973 * revert back to the loop. so we can remove the prefixes with
1976 fib_table_entry_update_one_path(fib_index,
1979 FIB_ENTRY_FLAG_NONE,
1981 &pfx_5_5_5_6_s_32.fp_addr,
1982 ~0, // no index provided.
1986 FIB_ROUTE_PATH_FLAG_NONE);
1988 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1989 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1990 "LB for 5.5.5.7/32 is via adj for DROP");
1991 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1992 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1993 "LB for 5.5.5.5/32 is via adj for DROP");
1994 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1995 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1996 "LB for 5.5.5.6/32 is via adj for DROP");
1999 * remove all the 5.5.5.x/32 prefixes
2001 fib_table_entry_path_remove(fib_index,
2005 &pfx_5_5_5_6_s_32.fp_addr,
2006 ~0, // no index provided.
2007 fib_index, // same as route's FIB
2009 FIB_ROUTE_PATH_FLAG_NONE);
2010 fib_table_entry_path_remove(fib_index,
2014 &pfx_5_5_5_7_s_32.fp_addr,
2015 ~0, // no index provided.
2016 fib_index, // same as route's FIB
2018 FIB_ROUTE_PATH_FLAG_NONE);
2019 fib_table_entry_path_remove(fib_index,
2023 &pfx_5_5_5_5_s_32.fp_addr,
2024 ~0, // no index provided.
2025 fib_index, // same as route's FIB
2027 FIB_ROUTE_PATH_FLAG_NONE);
2028 fib_table_entry_path_remove(fib_index,
2033 ~0, // no index provided.
2034 fib_index, // same as route's FIB
2036 FIB_ROUTE_PATH_FLAG_NONE);
2039 * -3 entries, -3 shared path-list
2041 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2042 fib_path_list_db_size());
2043 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2044 fib_path_list_pool_size());
2045 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2046 fib_entry_pool_size());
2049 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2051 fib_table_entry_path_add(fib_index,
2054 FIB_ENTRY_FLAG_NONE,
2056 &pfx_5_5_5_6_s_32.fp_addr,
2057 ~0, // no index provided.
2061 FIB_ROUTE_PATH_FLAG_NONE);
2062 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2063 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2064 "1-level 5.5.5.6/32 loop is via adj for DROP");
2066 fib_table_entry_path_remove(fib_index,
2070 &pfx_5_5_5_6_s_32.fp_addr,
2071 ~0, // no index provided.
2072 fib_index, // same as route's FIB
2074 FIB_ROUTE_PATH_FLAG_NONE);
2075 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2076 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2077 "1-level 5.5.5.6/32 loop is removed");
2080 * A recursive route whose next-hop is covered by the prefix.
2081 * This would mean the via-fib, which inherits forwarding from its
2082 * cover, thus picks up forwarding from the prfix, which is via the
2083 * via-fib, and we have a loop.
2085 fib_prefix_t pfx_23_23_23_0_s_24 = {
2087 .fp_proto = FIB_PROTOCOL_IP4,
2089 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2092 fib_prefix_t pfx_23_23_23_23_s_32 = {
2094 .fp_proto = FIB_PROTOCOL_IP4,
2096 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2099 fei = fib_table_entry_path_add(fib_index,
2100 &pfx_23_23_23_0_s_24,
2102 FIB_ENTRY_FLAG_NONE,
2104 &pfx_23_23_23_23_s_32.fp_addr,
2109 FIB_ROUTE_PATH_FLAG_NONE);
2110 dpo = fib_entry_contribute_ip_forwarding(fei);
2111 FIB_TEST(load_balance_is_drop(dpo),
2112 "23.23.23.0/24 via covered is DROP");
2113 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2116 * add-remove test. no change.
2118 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2119 fib_path_list_db_size());
2120 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2121 fib_path_list_pool_size());
2122 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2123 fib_entry_pool_size());
2126 * A recursive route with recursion constraints.
2127 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2129 fib_table_entry_path_add(fib_index,
2132 FIB_ENTRY_FLAG_NONE,
2139 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2141 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2142 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2144 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2145 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2147 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2148 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2151 * save the load-balance. we expect it to be inplace modified
2153 lb = load_balance_get(dpo1->dpoi_index);
2156 * add a covering prefix for the via fib that would otherwise serve
2157 * as the resolving route when the host is removed
2159 fib_table_entry_path_add(fib_index,
2162 FIB_ENTRY_FLAG_NONE,
2165 tm->hw[0]->sw_if_index,
2166 ~0, // invalid fib index
2169 FIB_ROUTE_PATH_FLAG_NONE);
2170 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
2171 ai = fib_entry_get_adj(fei);
2172 FIB_TEST((ai == ai_01),
2173 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
2176 * remove the host via FIB - expect the BGP prefix to be drop
2178 fib_table_entry_path_remove(fib_index,
2183 tm->hw[0]->sw_if_index,
2184 ~0, // invalid fib index
2186 FIB_ROUTE_PATH_FLAG_NONE);
2188 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2189 "adj for 200.200.200.200/32 is recursive via adj for DROP");
2192 * add the via-entry host reoute back. expect to resolve again
2194 fib_table_entry_path_add(fib_index,
2197 FIB_ENTRY_FLAG_NONE,
2200 tm->hw[0]->sw_if_index,
2201 ~0, // invalid fib index
2204 FIB_ROUTE_PATH_FLAG_NONE);
2205 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2206 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2209 * add another path for the recursive. it will then have 2.
2211 fib_prefix_t pfx_1_1_1_3_s_32 = {
2213 .fp_proto = FIB_PROTOCOL_IP4,
2215 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
2218 fib_table_entry_path_add(fib_index,
2221 FIB_ENTRY_FLAG_NONE,
2224 tm->hw[0]->sw_if_index,
2225 ~0, // invalid fib index
2228 FIB_ROUTE_PATH_FLAG_NONE);
2230 fib_table_entry_path_add(fib_index,
2233 FIB_ENTRY_FLAG_NONE,
2235 &pfx_1_1_1_3_s_32.fp_addr,
2240 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2242 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2243 dpo = fib_entry_contribute_ip_forwarding(fei);
2245 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2246 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2247 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2248 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2249 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2250 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2251 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2252 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2255 * expect the lb-map used by the recursive's load-balance is using both buckets
2257 load_balance_map_t *lbm;
2260 lb = load_balance_get(dpo->dpoi_index);
2262 load_balance_map_lock(lbmi);
2263 lbm = load_balance_map_get(lbmi);
2265 FIB_TEST(lbm->lbm_buckets[0] == 0,
2266 "LB maps's bucket 0 is %d",
2267 lbm->lbm_buckets[0]);
2268 FIB_TEST(lbm->lbm_buckets[1] == 1,
2269 "LB maps's bucket 1 is %d",
2270 lbm->lbm_buckets[1]);
2273 * withdraw one of the /32 via-entrys.
2274 * that ECMP path will be unresolved and forwarding should continue on the
2275 * other available path. this is an iBGP PIC edge failover.
2276 * Test the forwarding changes without re-fetching the adj from the
2277 * recursive entry. this ensures its the same one that is updated; i.e. an
2280 fib_table_entry_path_remove(fib_index,
2285 tm->hw[0]->sw_if_index,
2286 ~0, // invalid fib index
2288 FIB_ROUTE_PATH_FLAG_NONE);
2290 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2291 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
2292 "post PIC 200.200.200.200/32 was inplace modified");
2294 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
2295 "post PIC adj for 200.200.200.200/32 is recursive"
2296 " via adj for 1.1.1.3");
2299 * the LB maps that was locked above should have been modified to remove
2300 * the path that was down, and thus its bucket points to a path that is
2303 FIB_TEST(lbm->lbm_buckets[0] == 1,
2304 "LB maps's bucket 0 is %d",
2305 lbm->lbm_buckets[0]);
2306 FIB_TEST(lbm->lbm_buckets[1] == 1,
2307 "LB maps's bucket 1 is %d",
2308 lbm->lbm_buckets[1]);
2310 load_balance_map_unlock(lb->lb_map);
2313 * add it back. again
2315 fib_table_entry_path_add(fib_index,
2318 FIB_ENTRY_FLAG_NONE,
2321 tm->hw[0]->sw_if_index,
2322 ~0, // invalid fib index
2325 FIB_ROUTE_PATH_FLAG_NONE);
2327 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
2328 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2329 "via adj for 1.1.1.1");
2330 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
2331 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2332 "via adj for 1.1.1.3");
2334 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2335 dpo = fib_entry_contribute_ip_forwarding(fei);
2336 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2337 "post PIC 200.200.200.200/32 was inplace modified");
2340 * add a 3rd path. this makes the LB 16 buckets.
2342 fib_table_entry_path_add(fib_index,
2345 FIB_ENTRY_FLAG_NONE,
2347 &pfx_1_1_1_2_s_32.fp_addr,
2352 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2354 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2355 dpo = fib_entry_contribute_ip_forwarding(fei);
2356 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2357 "200.200.200.200/32 was inplace modified for 3rd path");
2358 FIB_TEST(16 == lb->lb_n_buckets,
2359 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
2362 load_balance_map_lock(lbmi);
2363 lbm = load_balance_map_get(lbmi);
2365 for (ii = 0; ii < 16; ii++)
2367 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2368 "LB Map for 200.200.200.200/32 at %d is %d",
2369 ii, lbm->lbm_buckets[ii]);
2373 * trigger PIC by removing the first via-entry
2374 * the first 6 buckets of the map should map to the next 6
2376 fib_table_entry_path_remove(fib_index,
2381 tm->hw[0]->sw_if_index,
2384 FIB_ROUTE_PATH_FLAG_NONE);
2386 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2387 dpo = fib_entry_contribute_ip_forwarding(fei);
2388 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2389 "200.200.200.200/32 was inplace modified for 3rd path");
2390 FIB_TEST(2 == lb->lb_n_buckets,
2391 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
2393 for (ii = 0; ii < 6; ii++)
2395 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
2396 "LB Map for 200.200.200.200/32 at %d is %d",
2397 ii, lbm->lbm_buckets[ii]);
2399 for (ii = 6; ii < 16; ii++)
2401 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2402 "LB Map for 200.200.200.200/32 at %d is %d",
2403 ii, lbm->lbm_buckets[ii]);
2410 fib_table_entry_path_add(fib_index,
2413 FIB_ENTRY_FLAG_NONE,
2416 tm->hw[0]->sw_if_index,
2420 FIB_ROUTE_PATH_FLAG_NONE);
2422 fib_table_entry_path_remove(fib_index,
2426 &pfx_1_1_1_2_s_32.fp_addr,
2430 MPLS_LABEL_INVALID);
2431 fib_table_entry_path_remove(fib_index,
2439 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2440 fib_table_entry_path_remove(fib_index,
2444 &pfx_1_1_1_3_s_32.fp_addr,
2448 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2449 fib_table_entry_delete(fib_index,
2452 fib_table_entry_delete(fib_index,
2455 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2456 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
2457 "1.1.1.1/28 removed");
2458 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2459 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
2460 "1.1.1.3/32 removed");
2461 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2462 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
2463 "200.200.200.200/32 removed");
2466 * add-remove test. no change.
2468 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2469 fib_path_list_db_size());
2470 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2471 fib_path_list_pool_size());
2472 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2473 fib_entry_pool_size());
2476 * A route whose paths are built up iteratively and then removed
2479 fib_prefix_t pfx_4_4_4_4_s_32 = {
2481 .fp_proto = FIB_PROTOCOL_IP4,
2484 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
2488 fib_table_entry_path_add(fib_index,
2491 FIB_ENTRY_FLAG_NONE,
2494 tm->hw[0]->sw_if_index,
2498 FIB_ROUTE_PATH_FLAG_NONE);
2499 fib_table_entry_path_add(fib_index,
2502 FIB_ENTRY_FLAG_NONE,
2505 tm->hw[0]->sw_if_index,
2509 FIB_ROUTE_PATH_FLAG_NONE);
2510 fib_table_entry_path_add(fib_index,
2513 FIB_ENTRY_FLAG_NONE,
2516 tm->hw[0]->sw_if_index,
2520 FIB_ROUTE_PATH_FLAG_NONE);
2521 FIB_TEST(FIB_NODE_INDEX_INVALID !=
2522 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2523 "4.4.4.4/32 present");
2525 fib_table_entry_delete(fib_index,
2528 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2529 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2530 "4.4.4.4/32 removed");
2533 * add-remove test. no change.
2535 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2536 fib_path_list_db_size());
2537 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2538 fib_path_list_pool_size());
2539 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2540 fib_entry_pool_size());
2543 * A route with multiple paths at once
2545 fib_route_path_t *r_paths = NULL;
2547 for (ii = 0; ii < 4; ii++)
2549 fib_route_path_t r_path = {
2550 .frp_proto = FIB_PROTOCOL_IP4,
2552 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
2554 .frp_sw_if_index = tm->hw[0]->sw_if_index,
2556 .frp_fib_index = ~0,
2558 vec_add1(r_paths, r_path);
2561 fib_table_entry_update(fib_index,
2564 FIB_ENTRY_FLAG_NONE,
2567 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2568 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2569 dpo = fib_entry_contribute_ip_forwarding(fei);
2571 lb = load_balance_get(dpo->dpoi_index);
2572 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
2574 fib_table_entry_delete(fib_index,
2577 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2578 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2579 "4.4.4.4/32 removed");
2583 * add-remove test. no change.
2585 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2586 fib_path_list_db_size());
2587 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2588 fib_path_list_pool_size());
2589 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2590 fib_entry_pool_size());
2593 * A route deag route
2595 fib_table_entry_path_add(fib_index,
2598 FIB_ENTRY_FLAG_NONE,
2605 FIB_ROUTE_PATH_FLAG_NONE);
2607 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2608 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2610 dpo = fib_entry_contribute_ip_forwarding(fei);
2611 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2612 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
2614 FIB_TEST((fib_index == lkd->lkd_fib_index),
2615 "4.4.4.4/32 is deag in %d %U",
2617 format_dpo_id, dpo, 0);
2619 fib_table_entry_delete(fib_index,
2622 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2623 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2624 "4.4.4.4/32 removed");
2628 * add-remove test. no change.
2630 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2631 fib_path_list_db_size());
2632 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2633 fib_path_list_pool_size());
2634 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2635 fib_entry_pool_size());
2639 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
2641 fib_prefix_t pfx_34_1_1_1_s_32 = {
2643 .fp_proto = FIB_PROTOCOL_IP4,
2645 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
2648 fib_prefix_t pfx_34_34_1_1_s_32 = {
2650 .fp_proto = FIB_PROTOCOL_IP4,
2652 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
2655 fei = fib_table_entry_path_add(fib_index,
2658 FIB_ENTRY_FLAG_NONE,
2660 &pfx_34_34_1_1_s_32.fp_addr,
2665 FIB_ROUTE_PATH_FLAG_NONE);
2666 fei = fib_table_entry_path_add(fib_index,
2669 FIB_ENTRY_FLAG_NONE,
2671 &pfx_34_34_1_1_s_32.fp_addr,
2676 FIB_ROUTE_PATH_FLAG_NONE);
2677 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
2678 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2682 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
2683 * all of which are via 10.10.10.1, Itf1
2685 fib_table_entry_path_remove(fib_index,
2690 tm->hw[0]->sw_if_index,
2693 FIB_ROUTE_PATH_FLAG_NONE);
2694 fib_table_entry_path_remove(fib_index,
2699 tm->hw[0]->sw_if_index,
2702 FIB_ROUTE_PATH_FLAG_NONE);
2703 fib_table_entry_path_remove(fib_index,
2708 tm->hw[0]->sw_if_index,
2711 FIB_ROUTE_PATH_FLAG_NONE);
2713 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2714 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
2715 "1.1.1.1/32 removed");
2716 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2717 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
2718 "1.1.1.2/32 removed");
2719 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2720 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
2721 "1.1.2.0/24 removed");
2724 * -3 entries and -1 shared path-list
2726 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2727 fib_path_list_db_size());
2728 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2729 fib_path_list_pool_size());
2730 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2731 fib_entry_pool_size());
2734 * An attached-host route. Expect to link to the incomplete adj
2736 fib_prefix_t pfx_4_1_1_1_s_32 = {
2738 .fp_proto = FIB_PROTOCOL_IP4,
2741 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
2744 fib_table_entry_path_add(fib_index,
2747 FIB_ENTRY_FLAG_NONE,
2750 tm->hw[0]->sw_if_index,
2754 FIB_ROUTE_PATH_FLAG_NONE);
2756 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
2757 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
2758 ai = fib_entry_get_adj(fei);
2760 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2762 &pfx_4_1_1_1_s_32.fp_addr,
2763 tm->hw[0]->sw_if_index);
2764 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
2768 * +1 entry and +1 shared path-list
2770 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2771 fib_path_list_db_size());
2772 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2773 fib_path_list_pool_size());
2774 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
2775 fib_entry_pool_size());
2777 fib_table_entry_delete(fib_index,
2781 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2782 fib_path_list_db_size());
2783 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2784 fib_path_list_pool_size());
2785 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2786 fib_entry_pool_size());
2789 * add a v6 prefix via v4 next-hops
2791 fib_prefix_t pfx_2001_s_64 = {
2793 .fp_proto = FIB_PROTOCOL_IP6,
2795 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
2798 fei = fib_table_entry_path_add(0, //default v6 table
2801 FIB_ENTRY_FLAG_NONE,
2804 tm->hw[0]->sw_if_index,
2808 FIB_ROUTE_PATH_FLAG_NONE);
2810 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
2811 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
2812 ai = fib_entry_get_adj(fei);
2814 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
2815 "2001::/64 via ARP-adj");
2816 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
2817 "2001::/64 is link type v6");
2818 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
2819 "2001::/64 ADJ-adj is NH proto v4");
2820 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
2823 * add a uRPF exempt prefix:
2825 * - it's forwarding is drop
2826 * - it's uRPF list is not empty
2827 * - the uRPF list for the default route (it's cover) is empty
2829 fei = fib_table_entry_special_add(fib_index,
2831 FIB_SOURCE_URPF_EXEMPT,
2832 FIB_ENTRY_FLAG_DROP,
2834 dpo = fib_entry_contribute_ip_forwarding(fei);
2835 FIB_TEST(load_balance_is_drop(dpo),
2836 "uRPF exempt 4.1.1.1/32 DROP");
2837 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
2838 "uRPF list for exempt prefix has itf index 0");
2839 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
2840 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2841 "uRPF list for 0.0.0.0/0 empty");
2843 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
2849 fib_table_entry_delete(fib_index,
2850 &pfx_10_10_10_1_s_32,
2852 fib_table_entry_delete(fib_index,
2853 &pfx_10_10_10_2_s_32,
2855 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2856 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
2857 "10.10.10.1/32 adj-fib removed");
2858 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2859 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
2860 "10.10.10.2/32 adj-fib removed");
2863 * -2 entries and -2 non-shared path-list
2865 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2866 fib_path_list_db_size());
2867 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
2868 fib_path_list_pool_size());
2869 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
2870 fib_entry_pool_size());
2873 * unlock the adjacencies for which this test provided a rewrite.
2874 * These are the last locks on these adjs. they should thus go away.
2878 adj_unlock(ai_12_12_12_12);
2880 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2885 * remove the interface prefixes
2887 local_pfx.fp_len = 32;
2888 fib_table_entry_special_remove(fib_index, &local_pfx,
2889 FIB_SOURCE_INTERFACE);
2890 fei = fib_table_lookup(fib_index, &local_pfx);
2892 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2893 fib_table_lookup_exact_match(fib_index, &local_pfx),
2894 "10.10.10.10/32 adj-fib removed");
2896 local_pfx.fp_len = 24;
2897 fib_table_entry_delete(fib_index, &local_pfx,
2898 FIB_SOURCE_INTERFACE);
2900 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2901 fib_table_lookup_exact_match(fib_index, &local_pfx),
2902 "10.10.10.10/24 adj-fib removed");
2905 * -2 entries and -2 non-shared path-list
2907 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2908 fib_path_list_db_size());
2909 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
2910 fib_path_list_pool_size());
2911 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
2912 fib_entry_pool_size());
2915 * Last but not least, remove the VRF
2917 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2920 "NO API Source'd prefixes");
2921 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2924 "NO RR Source'd prefixes");
2925 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2927 FIB_SOURCE_INTERFACE)),
2928 "NO INterface Source'd prefixes");
2930 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
2932 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2933 fib_path_list_db_size());
2934 FIB_TEST((NBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
2935 fib_path_list_pool_size());
2936 FIB_TEST((NBR-5 == fib_entry_pool_size()), "entry pool size is %d",
2937 fib_entry_pool_size());
2938 FIB_TEST((NBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
2939 pool_elts(fib_urpf_list_pool));
2948 * In the default table check for the presence and correct forwarding
2949 * of the special entries
2951 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
2952 const dpo_id_t *dpo, *dpo_drop;
2953 const ip_adjacency_t *adj;
2954 const receive_dpo_t *rd;
2959 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2962 /* via 2001:0:0:1::2 */
2963 ip46_address_t nh_2001_2 = {
2966 [0] = clib_host_to_net_u64(0x2001000000000001),
2967 [1] = clib_host_to_net_u64(0x0000000000000002),
2974 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
2976 /* Find or create FIB table 11 */
2977 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
2979 for (ii = 0; ii < 4; ii++)
2981 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
2984 fib_prefix_t pfx_0_0 = {
2986 .fp_proto = FIB_PROTOCOL_IP6,
2994 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
2995 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
2996 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
2997 "Default route is DROP");
2999 dpo = fib_entry_contribute_ip_forwarding(dfrt);
3000 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3003 &pfx_0_0.fp_addr.ip6)),
3004 "default-route; fwd and non-fwd tables match");
3006 // FIXME - check specials.
3009 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
3010 * each with 6 entries. All entries are special so no path-list sharing.
3013 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3014 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is %d",
3015 fib_path_list_pool_size());
3016 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
3017 fib_entry_pool_size());
3020 * add interface routes.
3021 * validate presence of /64 attached and /128 recieve.
3022 * test for the presence of the receive address in the glean and local adj
3024 * receive on 2001:0:0:1::1/128
3026 fib_prefix_t local_pfx = {
3028 .fp_proto = FIB_PROTOCOL_IP6,
3032 [0] = clib_host_to_net_u64(0x2001000000000001),
3033 [1] = clib_host_to_net_u64(0x0000000000000001),
3039 fib_table_entry_update_one_path(fib_index, &local_pfx,
3040 FIB_SOURCE_INTERFACE,
3041 (FIB_ENTRY_FLAG_CONNECTED |
3042 FIB_ENTRY_FLAG_ATTACHED),
3045 tm->hw[0]->sw_if_index,
3049 FIB_ROUTE_PATH_FLAG_NONE);
3050 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3052 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3054 ai = fib_entry_get_adj(fei);
3055 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
3057 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3058 "attached interface adj is glean");
3059 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3060 &adj->sub_type.glean.receive_addr)),
3061 "attached interface adj is receive ok");
3062 dpo = fib_entry_contribute_ip_forwarding(fei);
3063 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3066 &local_pfx.fp_addr.ip6)),
3067 "attached-route; fwd and non-fwd tables match");
3069 local_pfx.fp_len = 128;
3070 fib_table_entry_update_one_path(fib_index, &local_pfx,
3071 FIB_SOURCE_INTERFACE,
3072 (FIB_ENTRY_FLAG_CONNECTED |
3073 FIB_ENTRY_FLAG_LOCAL),
3076 tm->hw[0]->sw_if_index,
3077 ~0, // invalid fib index
3080 FIB_ROUTE_PATH_FLAG_NONE);
3081 fei = fib_table_lookup(fib_index, &local_pfx);
3083 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3085 dpo = fib_entry_contribute_ip_forwarding(fei);
3086 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3087 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3088 "local interface adj is local");
3089 rd = receive_dpo_get(dpo->dpoi_index);
3091 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3093 "local interface adj is receive ok");
3095 dpo = fib_entry_contribute_ip_forwarding(fei);
3096 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3099 &local_pfx.fp_addr.ip6)),
3100 "local-route; fwd and non-fwd tables match");
3103 * +2 entries. +2 unshared path-lists
3105 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3106 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3107 fib_path_list_pool_size());
3108 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3109 fib_entry_pool_size());
3112 * Modify the default route to be via an adj not yet known.
3113 * this sources the defalut route with the API source, which is
3114 * a higher preference to the DEFAULT_ROUTE source
3116 fib_table_entry_path_add(fib_index, &pfx_0_0,
3118 FIB_ENTRY_FLAG_NONE,
3121 tm->hw[0]->sw_if_index,
3125 FIB_ROUTE_PATH_FLAG_NONE);
3126 fei = fib_table_lookup(fib_index, &pfx_0_0);
3128 FIB_TEST((fei == dfrt), "default route same index");
3129 ai = fib_entry_get_adj(fei);
3130 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
3132 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3133 "adj is incomplete");
3134 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
3135 "adj nbr next-hop ok");
3138 * find the adj in the shared db
3140 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3143 tm->hw[0]->sw_if_index);
3144 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
3145 adj_unlock(locked_ai);
3148 * no more entires. +1 shared path-list
3150 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3151 fib_path_list_db_size());
3152 FIB_TEST((NPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
3153 fib_path_list_pool_size());
3154 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3155 fib_entry_pool_size());
3158 * remove the API source from the default route. We expected
3159 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
3161 fib_table_entry_path_remove(fib_index, &pfx_0_0,
3165 tm->hw[0]->sw_if_index,
3168 FIB_ROUTE_PATH_FLAG_NONE);
3169 fei = fib_table_lookup(fib_index, &pfx_0_0);
3171 FIB_TEST((fei == dfrt), "default route same index");
3172 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3173 "Default route is DROP");
3176 * no more entires. -1 shared path-list
3178 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3179 fib_path_list_db_size());
3180 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3181 fib_path_list_pool_size());
3182 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3183 fib_entry_pool_size());
3186 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3188 fib_prefix_t pfx_2001_1_2_s_128 = {
3190 .fp_proto = FIB_PROTOCOL_IP6,
3194 [0] = clib_host_to_net_u64(0x2001000000000001),
3195 [1] = clib_host_to_net_u64(0x0000000000000002),
3200 fib_prefix_t pfx_2001_1_3_s_128 = {
3202 .fp_proto = FIB_PROTOCOL_IP6,
3206 [0] = clib_host_to_net_u64(0x2001000000000001),
3207 [1] = clib_host_to_net_u64(0x0000000000000003),
3213 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
3216 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3218 &pfx_2001_1_2_s_128.fp_addr,
3219 tm->hw[0]->sw_if_index);
3220 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
3221 adj = adj_get(ai_01);
3222 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3223 "adj is incomplete");
3224 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3225 &adj->sub_type.nbr.next_hop)),
3226 "adj nbr next-hop ok");
3228 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
3229 fib_test_build_rewrite(eth_addr));
3230 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3232 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3233 &adj->sub_type.nbr.next_hop)),
3234 "adj nbr next-hop ok");
3236 fib_table_entry_update_one_path(fib_index,
3237 &pfx_2001_1_2_s_128,
3239 FIB_ENTRY_FLAG_NONE,
3241 &pfx_2001_1_2_s_128.fp_addr,
3242 tm->hw[0]->sw_if_index,
3246 FIB_ROUTE_PATH_FLAG_NONE);
3248 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
3249 ai = fib_entry_get_adj(fei);
3250 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3254 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3256 &pfx_2001_1_3_s_128.fp_addr,
3257 tm->hw[0]->sw_if_index);
3258 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
3259 adj = adj_get(ai_02);
3260 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3261 "adj is incomplete");
3262 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3263 &adj->sub_type.nbr.next_hop)),
3264 "adj nbr next-hop ok");
3266 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
3267 fib_test_build_rewrite(eth_addr));
3268 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3270 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3271 &adj->sub_type.nbr.next_hop)),
3272 "adj nbr next-hop ok");
3273 FIB_TEST((ai_01 != ai_02), "ADJs are different");
3275 fib_table_entry_update_one_path(fib_index,
3276 &pfx_2001_1_3_s_128,
3278 FIB_ENTRY_FLAG_NONE,
3280 &pfx_2001_1_3_s_128.fp_addr,
3281 tm->hw[0]->sw_if_index,
3285 FIB_ROUTE_PATH_FLAG_NONE);
3287 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
3288 ai = fib_entry_get_adj(fei);
3289 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3292 * +2 entries, +2 unshread path-lists.
3294 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3295 fib_path_list_db_size());
3296 FIB_TEST((NPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
3297 fib_path_list_pool_size());
3298 FIB_TEST((NPS+4 == fib_entry_pool_size()), "entry pool size is %d",
3299 fib_entry_pool_size());
3302 * Add a 2 routes via the first ADJ. ensure path-list sharing
3304 fib_prefix_t pfx_2001_a_s_64 = {
3306 .fp_proto = FIB_PROTOCOL_IP6,
3310 [0] = clib_host_to_net_u64(0x200100000000000a),
3311 [1] = clib_host_to_net_u64(0x0000000000000000),
3316 fib_prefix_t pfx_2001_b_s_64 = {
3318 .fp_proto = FIB_PROTOCOL_IP6,
3322 [0] = clib_host_to_net_u64(0x200100000000000b),
3323 [1] = clib_host_to_net_u64(0x0000000000000000),
3329 fib_table_entry_path_add(fib_index,
3332 FIB_ENTRY_FLAG_NONE,
3335 tm->hw[0]->sw_if_index,
3339 FIB_ROUTE_PATH_FLAG_NONE);
3340 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
3341 ai = fib_entry_get_adj(fei);
3342 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3343 fib_table_entry_path_add(fib_index,
3346 FIB_ENTRY_FLAG_NONE,
3349 tm->hw[0]->sw_if_index,
3353 FIB_ROUTE_PATH_FLAG_NONE);
3354 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
3355 ai = fib_entry_get_adj(fei);
3356 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3359 * +2 entries, +1 shared path-list.
3361 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3362 fib_path_list_db_size());
3363 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3364 fib_path_list_pool_size());
3365 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3366 fib_entry_pool_size());
3369 * add a v4 prefix via a v6 next-hop
3371 fib_prefix_t pfx_1_1_1_1_s_32 = {
3373 .fp_proto = FIB_PROTOCOL_IP4,
3375 .ip4.as_u32 = 0x01010101,
3378 fei = fib_table_entry_path_add(0, // default table
3381 FIB_ENTRY_FLAG_NONE,
3384 tm->hw[0]->sw_if_index,
3388 FIB_ROUTE_PATH_FLAG_NONE);
3389 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
3390 "1.1.1.1/32 o v6 route present");
3391 ai = fib_entry_get_adj(fei);
3393 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3394 "1.1.1.1/32 via ARP-adj");
3395 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
3396 "1.1.1.1/32 ADJ-adj is link type v4");
3397 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
3398 "1.1.1.1/32 ADJ-adj is NH proto v6");
3399 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
3404 fib_prefix_t pfx_2001_c_s_64 = {
3406 .fp_proto = FIB_PROTOCOL_IP6,
3410 [0] = clib_host_to_net_u64(0x200100000000000c),
3411 [1] = clib_host_to_net_u64(0x0000000000000000),
3416 fib_table_entry_path_add(fib_index,
3419 FIB_ENTRY_FLAG_ATTACHED,
3422 tm->hw[0]->sw_if_index,
3426 FIB_ROUTE_PATH_FLAG_NONE);
3427 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3428 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
3429 ai = fib_entry_get_adj(fei);
3431 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
3432 "2001:0:0:c/64 attached resolves via glean");
3434 fib_table_entry_path_remove(fib_index,
3439 tm->hw[0]->sw_if_index,
3442 FIB_ROUTE_PATH_FLAG_NONE);
3443 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3444 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
3447 * Shutdown the interface on which we have a connected and through
3448 * which the routes are reachable.
3449 * This will result in the connected, adj-fibs, and routes linking to drop
3450 * The local/for-us prefix continues to receive.
3452 clib_error_t * error;
3454 error = vnet_sw_interface_set_flags(vnet_get_main(),
3455 tm->hw[0]->sw_if_index,
3456 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3457 FIB_TEST((NULL == error), "Interface shutdown OK");
3459 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3460 dpo = fib_entry_contribute_ip_forwarding(fei);
3461 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3462 "2001::b/64 resolves via drop");
3464 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3465 dpo = fib_entry_contribute_ip_forwarding(fei);
3466 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3467 "2001::a/64 resolves via drop");
3468 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3469 dpo = fib_entry_contribute_ip_forwarding(fei);
3470 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3471 "2001:0:0:1::3/64 resolves via drop");
3472 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3473 dpo = fib_entry_contribute_ip_forwarding(fei);
3474 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3475 "2001:0:0:1::2/64 resolves via drop");
3476 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3477 dpo = fib_entry_contribute_ip_forwarding(fei);
3478 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3479 "2001:0:0:1::1/128 not drop");
3480 local_pfx.fp_len = 64;
3481 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3482 dpo = fib_entry_contribute_ip_forwarding(fei);
3483 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3484 "2001:0:0:1/64 resolves via drop");
3489 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3490 fib_path_list_db_size());
3491 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3492 fib_path_list_pool_size());
3493 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3494 fib_entry_pool_size());
3497 * shutdown one of the other interfaces, then add a connected.
3498 * and swap one of the routes to it.
3500 error = vnet_sw_interface_set_flags(vnet_get_main(),
3501 tm->hw[1]->sw_if_index,
3502 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3503 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
3505 fib_prefix_t connected_pfx = {
3507 .fp_proto = FIB_PROTOCOL_IP6,
3510 /* 2001:0:0:2::1/64 */
3512 [0] = clib_host_to_net_u64(0x2001000000000002),
3513 [1] = clib_host_to_net_u64(0x0000000000000001),
3518 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3519 FIB_SOURCE_INTERFACE,
3520 (FIB_ENTRY_FLAG_CONNECTED |
3521 FIB_ENTRY_FLAG_ATTACHED),
3524 tm->hw[1]->sw_if_index,
3528 FIB_ROUTE_PATH_FLAG_NONE);
3529 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
3530 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3531 dpo = fib_entry_contribute_ip_forwarding(fei);
3532 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3533 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
3534 "2001:0:0:2/64 not resolves via drop");
3536 connected_pfx.fp_len = 128;
3537 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3538 FIB_SOURCE_INTERFACE,
3539 (FIB_ENTRY_FLAG_CONNECTED |
3540 FIB_ENTRY_FLAG_LOCAL),
3543 tm->hw[0]->sw_if_index,
3544 ~0, // invalid fib index
3547 FIB_ROUTE_PATH_FLAG_NONE);
3548 fei = fib_table_lookup(fib_index, &connected_pfx);
3550 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3551 dpo = fib_entry_contribute_ip_forwarding(fei);
3552 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3553 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3554 "local interface adj is local");
3555 rd = receive_dpo_get(dpo->dpoi_index);
3556 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
3558 "local interface adj is receive ok");
3561 * +2 entries, +2 unshared path-lists
3563 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3564 fib_path_list_db_size());
3565 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3566 fib_path_list_pool_size());
3567 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3568 fib_entry_pool_size());
3572 * bring the interface back up. we expected the routes to return
3573 * to normal forwarding.
3575 error = vnet_sw_interface_set_flags(vnet_get_main(),
3576 tm->hw[0]->sw_if_index,
3577 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3578 FIB_TEST((NULL == error), "Interface bring-up OK");
3579 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3580 ai = fib_entry_get_adj(fei);
3581 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3582 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3583 ai = fib_entry_get_adj(fei);
3584 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3585 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3586 ai = fib_entry_get_adj(fei);
3587 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3588 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3589 ai = fib_entry_get_adj(fei);
3590 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3591 local_pfx.fp_len = 64;
3592 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3593 ai = fib_entry_get_adj(fei);
3595 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3596 "attached interface adj is glean");
3599 * Delete the interface that the routes reolve through.
3600 * Again no routes are removed. They all point to drop.
3602 * This is considered an error case. The control plane should
3603 * not remove interfaces through which routes resolve, but
3604 * such things can happen. ALL affected routes will drop.
3606 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
3608 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3609 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3610 "2001::b/64 resolves via drop");
3611 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3612 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3613 "2001::b/64 resolves via drop");
3614 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3615 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3616 "2001:0:0:1::3/64 resolves via drop");
3617 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3618 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3619 "2001:0:0:1::2/64 resolves via drop");
3620 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3621 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3622 "2001:0:0:1::1/128 is drop");
3623 local_pfx.fp_len = 64;
3624 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3625 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3626 "2001:0:0:1/64 resolves via drop");
3631 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3632 fib_path_list_db_size());
3633 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3634 fib_path_list_pool_size());
3635 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3636 fib_entry_pool_size());
3639 * Add the interface back. routes stay unresolved.
3641 error = ethernet_register_interface(vnet_get_main(),
3642 test_interface_device_class.index,
3645 &tm->hw_if_indicies[0],
3646 /* flag change */ 0);
3648 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3649 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3650 "2001::b/64 resolves via drop");
3651 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3652 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3653 "2001::b/64 resolves via drop");
3654 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3655 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3656 "2001:0:0:1::3/64 resolves via drop");
3657 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3658 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3659 "2001:0:0:1::2/64 resolves via drop");
3660 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3661 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3662 "2001:0:0:1::1/128 is drop");
3663 local_pfx.fp_len = 64;
3664 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3665 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3666 "2001:0:0:1/64 resolves via drop");
3669 * CLEANUP ALL the routes
3671 fib_table_entry_delete(fib_index,
3674 fib_table_entry_delete(fib_index,
3677 fib_table_entry_delete(fib_index,
3680 fib_table_entry_delete(fib_index,
3681 &pfx_2001_1_3_s_128,
3683 fib_table_entry_delete(fib_index,
3684 &pfx_2001_1_2_s_128,
3686 local_pfx.fp_len = 64;
3687 fib_table_entry_delete(fib_index, &local_pfx,
3688 FIB_SOURCE_INTERFACE);
3689 local_pfx.fp_len = 128;
3690 fib_table_entry_special_remove(fib_index, &local_pfx,
3691 FIB_SOURCE_INTERFACE);
3692 connected_pfx.fp_len = 64;
3693 fib_table_entry_delete(fib_index, &connected_pfx,
3694 FIB_SOURCE_INTERFACE);
3695 connected_pfx.fp_len = 128;
3696 fib_table_entry_special_remove(fib_index, &connected_pfx,
3697 FIB_SOURCE_INTERFACE);
3699 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3700 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
3701 "2001::a/64 removed");
3702 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3703 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
3704 "2001::b/64 removed");
3705 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3706 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
3707 "2001:0:0:1::3/128 removed");
3708 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3709 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
3710 "2001:0:0:1::3/128 removed");
3711 local_pfx.fp_len = 64;
3712 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3713 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3714 "2001:0:0:1/64 removed");
3715 local_pfx.fp_len = 128;
3716 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3717 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3718 "2001:0:0:1::1/128 removed");
3719 connected_pfx.fp_len = 64;
3720 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3721 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3722 "2001:0:0:2/64 removed");
3723 connected_pfx.fp_len = 128;
3724 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3725 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3726 "2001:0:0:2::1/128 removed");
3729 * -8 entries. -7 path-lists (1 was shared).
3731 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3732 fib_path_list_db_size());
3733 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is%d",
3734 fib_path_list_pool_size());
3735 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
3736 fib_entry_pool_size());
3739 * now remove the VRF
3741 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
3743 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3744 fib_path_list_db_size());
3745 FIB_TEST((NPS-6 == fib_path_list_pool_size()), "path list pool size is%d",
3746 fib_path_list_pool_size());
3747 FIB_TEST((NPS-6 == fib_entry_pool_size()), "entry pool size is %d",
3748 fib_entry_pool_size());
3754 * return the interfaces to up state
3756 error = vnet_sw_interface_set_flags(vnet_get_main(),
3757 tm->hw[0]->sw_if_index,
3758 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3759 error = vnet_sw_interface_set_flags(vnet_get_main(),
3760 tm->hw[1]->sw_if_index,
3761 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3763 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3768 * Test the recursive route route handling for GRE tunnels
3773 /* fib_node_index_t fei; */
3774 /* u32 fib_index = 0; */
3775 /* test_main_t *tm; */
3778 /* tm = &test_main; */
3780 /* for (ii = 0; ii < 4; ii++) */
3782 /* ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = 0; */
3786 /* * add interface routes. We'll assume this works. It's more rigorously */
3787 /* * tested elsewhere. */
3789 /* fib_prefix_t local_pfx = { */
3791 /* .fp_proto = FIB_PROTOCOL_IP4, */
3794 /* /\* 10.10.10.10 *\/ */
3795 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3800 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3801 /* FIB_SOURCE_INTERFACE, */
3802 /* (FIB_ENTRY_FLAG_CONNECTED | */
3803 /* FIB_ENTRY_FLAG_ATTACHED), */
3805 /* tm->hw[0]->sw_if_index, */
3808 /* FIB_ROUTE_PATH_FLAG_NONE); */
3809 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3810 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3811 /* "attached interface route present"); */
3813 /* local_pfx.fp_len = 32; */
3814 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3815 /* FIB_SOURCE_INTERFACE, */
3816 /* (FIB_ENTRY_FLAG_CONNECTED | */
3817 /* FIB_ENTRY_FLAG_LOCAL), */
3819 /* tm->hw[0]->sw_if_index, */
3820 /* ~0, // invalid fib index */
3822 /* FIB_ROUTE_PATH_FLAG_NONE); */
3823 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3825 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3826 /* "local interface route present"); */
3828 /* fib_prefix_t local2_pfx = { */
3830 /* .fp_proto = FIB_PROTOCOL_IP4, */
3833 /* /\* 10.10.11.11 *\/ */
3834 /* .as_u32 = clib_host_to_net_u32(0x0a0a0b0b), */
3839 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3840 /* FIB_SOURCE_INTERFACE, */
3841 /* (FIB_ENTRY_FLAG_CONNECTED | */
3842 /* FIB_ENTRY_FLAG_ATTACHED), */
3844 /* tm->hw[1]->sw_if_index, */
3847 /* FIB_ROUTE_PATH_FLAG_NONE); */
3848 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3849 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3850 /* "attached interface route present"); */
3852 /* local2_pfx.fp_len = 32; */
3853 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3854 /* FIB_SOURCE_INTERFACE, */
3855 /* (FIB_ENTRY_FLAG_CONNECTED | */
3856 /* FIB_ENTRY_FLAG_LOCAL), */
3858 /* tm->hw[0]->sw_if_index, */
3859 /* ~0, // invalid fib index */
3861 /* FIB_ROUTE_PATH_FLAG_NONE); */
3862 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3864 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3865 /* "local interface route present"); */
3868 /* * Add the route that will be used to resolve the tunnel's destination */
3870 /* fib_prefix_t route_pfx = { */
3872 /* .fp_proto = FIB_PROTOCOL_IP4, */
3875 /* /\* 1.1.1.0/24 *\/ */
3876 /* .as_u32 = clib_host_to_net_u32(0x01010100), */
3880 /* /\* 10.10.10.2 *\/ */
3881 /* ip46_address_t nh_10_10_10_2 = { */
3882 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02), */
3885 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3886 /* FIB_SOURCE_API, */
3887 /* FIB_ENTRY_FLAG_NONE, */
3888 /* &nh_10_10_10_2, */
3889 /* tm->hw[0]->sw_if_index, */
3892 /* FIB_ROUTE_PATH_FLAG_NONE); */
3893 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
3894 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
3895 /* "route present"); */
3898 /* * Add a tunnel */
3900 /* /\* 1.1.1.1 *\/ */
3901 /* fib_prefix_t tun_dst_pfx = { */
3903 /* .fp_proto = FIB_PROTOCOL_IP4, */
3905 /* .ip4.as_u32 = clib_host_to_net_u32(0x01010101), */
3908 /* /\* 10.10.10.10 *\/ */
3909 /* ip4_address_t tun_src = { */
3910 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3912 /* /\* 172.16.0.1 *\/ */
3913 /* ip4_address_t tun_itf = { */
3914 /* .as_u32 = clib_host_to_net_u32(0xac100001), */
3916 /* fib_prefix_t tun_itf_pfx = { */
3918 /* .fp_proto = FIB_PROTOCOL_IP4, */
3920 /* .ip4 = tun_itf, */
3923 /* u32 *encap_labels = NULL; */
3924 /* u32 label = 0xbaba; */
3925 /* u32 encap_index; */
3926 /* u32 tunnel_sw_if_index; */
3931 /* * First we need the MPLS Encap present */
3933 /* * Pretty sure this is broken. the wiki say the 1st aparamter address */
3934 /* * should be the tunnel's interface address, which makes some sense. But */
3935 /* * the code for tunnel creation checks for the tunnel's destination */
3936 /* * address. curious... */
3938 /* vec_add1(encap_labels, label); */
3939 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
3940 /* 0, // inner VRF */
3942 /* ~0, // policy_tunnel_index, */
3943 /* 0, // no_dst_hash, */
3946 /* FIB_TEST((0 == rv), "MPLS encap created"); */
3949 /* * now create the tunnel */
3951 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3952 /* &tun_dst_pfx.fp_addr.ip4, */
3953 /* &tun_itf_pfx.fp_addr.ip4, */
3954 /* tun_itf_pfx.fp_len, */
3955 /* 0, // inner VRF */
3956 /* 0, // outer VRF */
3957 /* &tunnel_sw_if_index, */
3960 /* FIB_TEST((0 == rv), "Tunnel created"); */
3963 /* * add it again. just for giggles. */
3965 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3966 /* &tun_dst_pfx.fp_addr.ip4, */
3967 /* &tun_itf_pfx.fp_addr.ip4, */
3968 /* tun_itf_pfx.fp_len, */
3969 /* 0, // inner VRF */
3970 /* 0, // outer VRF */
3971 /* &tunnel_sw_if_index, */
3974 /* FIB_TEST((0 != rv), "Duplicate Tunnel not created"); */
3977 /* * Find the route added for the tunnel subnet and check that */
3978 /* * it has a midchin adj that is stacked on the adj used to reach the */
3979 /* * tunnel destination */
3981 /* ip_adjacency_t *midchain_adj, *route_adj, *adjfib_adj; */
3982 /* adj_index_t midchain_ai, route_ai, adjfib_ai1, adjfib_ai2; */
3983 /* ip_lookup_main_t *lm; */
3985 /* lm = &ip4_main.lookup_main; */
3987 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
3988 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "tun itf route present"); */
3989 /* midchain_ai = fib_entry_contribute_forwarding(fei); */
3990 /* midchain_adj = adj_get(midchain_ai); */
3992 /* FIB_TEST((IP_LOOKUP_NEXT_MIDCHAIN == midchain_adj->lookup_next_index), */
3993 /* "Tunnel interface links to midchain"); */
3995 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3996 /* route_ai = fib_entry_contribute_forwarding(fei); */
3997 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3998 /* "tunnel midchain it stacked on route adj"); */
4001 /* * update the route to the tunnel's destination to load-balance via */
4002 /* * interface 1. */
4004 /* /\* 10.10.11.2 *\/ */
4005 /* ip46_address_t nh_10_10_11_2 = { */
4006 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02), */
4009 /* fib_table_entry_path_add(fib_index, &route_pfx, */
4010 /* FIB_SOURCE_API, */
4011 /* FIB_ENTRY_FLAG_NONE, */
4012 /* &nh_10_10_11_2, */
4013 /* tm->hw[1]->sw_if_index, */
4016 /* FIB_ROUTE_PATH_FLAG_NONE); */
4019 /* * the tunnels midchain should have re-stacked. This tests that the */
4020 /* * route re-resolution backwalk works to a tunnel interface. */
4022 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
4023 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
4024 /* route_ai = fib_entry_contribute_forwarding(fei); */
4026 /* midchain_adj = adj_get(midchain_ai); */
4028 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
4029 /* "tunnel midchain has re-stacked on route adj"); */
4031 /* route_adj = adj_get(route_ai); */
4033 /* FIB_TEST((2 == route_adj->n_adj), "Route adj is multipath"); */
4036 /* * At this stage both nieghbour adjs are incomplete, so the same should */
4037 /* * be true of the multipath adj */
4039 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == route_adj->lookup_next_index), */
4040 /* "Adj0 is ARP: %d", route_adj->lookup_next_index); */
4041 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == (route_adj+1)->lookup_next_index), */
4042 /* "Adj1 is ARP"); */
4045 /* * do the equivalent of creating an ARP entry for 10.10.10.2. */
4046 /* * This will complete the adj, and this */
4047 /* * change should be refelct in the multipath too. */
4049 /* u8* rewrite = NULL, byte = 0xd; */
4050 /* vec_add(rewrite, &byte, 6); */
4052 /* adjfib_ai1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
4053 /* VNET_LINK_IP4, */
4054 /* &nh_10_10_10_2, */
4055 /* tm->hw[0]->sw_if_index); */
4056 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
4059 /* adjfib_adj = adj_get(adjfib_ai1); */
4060 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
4061 /* "Adj-fib10 adj is rewrite"); */
4063 /* adjfib_ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
4064 /* VNET_LINK_IP4, */
4065 /* &nh_10_10_11_2, */
4066 /* tm->hw[1]->sw_if_index); */
4067 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
4071 /* adjfib_adj = adj_get(adjfib_ai2); */
4073 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
4074 /* "Adj-fib11 adj is rewrite"); */
4076 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
4077 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
4078 /* route_ai = fib_entry_contribute_forwarding(fei); */
4079 /* route_adj = adj_get(route_ai); */
4080 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == route_adj->lookup_next_index), */
4081 /* "Adj0 is rewrite"); */
4082 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == (route_adj+1)->lookup_next_index), */
4083 /* "Adj1 is rewrite"); */
4088 /* adj_index_t drop_ai = adj_get_special(FIB_PROTOCOL_IP4, */
4089 /* ADJ_SPECIAL_TYPE_DROP); */
4092 /* * remove the route that the tunnel resovles via. expect */
4093 /* * it to now resolve via the default route, which is drop */
4095 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
4096 /* FIB_SOURCE_API, */
4097 /* &nh_10_10_10_2, */
4098 /* tm->hw[0]->sw_if_index, */
4101 /* FIB_ROUTE_PATH_FLAG_NONE); */
4102 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
4103 /* FIB_SOURCE_API, */
4104 /* &nh_10_10_11_2, */
4105 /* tm->hw[1]->sw_if_index, */
4108 /* FIB_ROUTE_PATH_FLAG_NONE); */
4109 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
4110 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
4111 /* "route present"); */
4112 /* midchain_adj = adj_get(midchain_ai); */
4113 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == drop_ai), */
4114 /* "tunnel midchain has re-stacked on drop"); */
4117 /* * remove the tunnel and its MPLS encaps */
4119 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
4120 /* &tun_dst_pfx.fp_addr.ip4, */
4121 /* &tun_itf_pfx.fp_addr.ip4, */
4122 /* tun_itf_pfx.fp_len, */
4123 /* 0, // inner VRF */
4124 /* 0, // outer VRF */
4125 /* &tunnel_sw_if_index, */
4128 /* FIB_TEST((0 == rv), "Tunnel removed"); */
4129 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
4130 /* &tun_dst_pfx.fp_addr.ip4, */
4131 /* &tun_itf_pfx.fp_addr.ip4, */
4132 /* tun_itf_pfx.fp_len, */
4133 /* 0, // inner VRF */
4134 /* 0, // outer VRF */
4135 /* &tunnel_sw_if_index, */
4138 /* FIB_TEST((0 != rv), "No existant Tunnel not removed"); */
4140 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
4141 /* 0, // inner VRF */
4143 /* ~0, // policy_tunnel_index, */
4144 /* 0, // no_dst_hash, */
4147 /* FIB_TEST((0 == rv), "MPLS encap deleted"); */
4149 /* vec_free(encap_labels); */
4152 /* * no more FIB entries expected */
4154 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
4155 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun itf route removed"); */
4156 /* fei = fib_table_lookup_exact_match(fib_index, &tun_dst_pfx); */
4157 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun dst route removed"); */
4160 /* * CLEANUP the connecteds */
4162 /* local2_pfx.fp_len = 24; */
4163 /* fib_table_entry_delete(fib_index, &local2_pfx, */
4164 /* FIB_SOURCE_INTERFACE); */
4165 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
4166 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4167 /* "attached interface route remove"); */
4169 /* local2_pfx.fp_len = 32; */
4170 /* fib_table_entry_special_remove(fib_index, &local2_pfx, */
4171 /* FIB_SOURCE_INTERFACE); */
4172 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
4173 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4174 /* "local interface route removed"); */
4175 /* local_pfx.fp_len = 24; */
4176 /* fib_table_entry_delete(fib_index, &local_pfx, */
4177 /* FIB_SOURCE_INTERFACE); */
4178 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
4179 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4180 /* "attached interface route remove"); */
4182 /* local_pfx.fp_len = 32; */
4183 /* fib_table_entry_special_remove(fib_index, &local_pfx, */
4184 /* FIB_SOURCE_INTERFACE); */
4185 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
4186 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4187 /* "local interface route removed"); */
4191 * Test Attached Exports
4196 const dpo_id_t *dpo, *dpo_drop;
4197 const u32 fib_index = 0;
4198 fib_node_index_t fei;
4205 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4209 * add interface routes. We'll assume this works. It's more rigorously
4212 fib_prefix_t local_pfx = {
4214 .fp_proto = FIB_PROTOCOL_IP4,
4218 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4223 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4224 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4226 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4228 fib_table_entry_update_one_path(fib_index, &local_pfx,
4229 FIB_SOURCE_INTERFACE,
4230 (FIB_ENTRY_FLAG_CONNECTED |
4231 FIB_ENTRY_FLAG_ATTACHED),
4234 tm->hw[0]->sw_if_index,
4238 FIB_ROUTE_PATH_FLAG_NONE);
4239 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4240 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4241 "attached interface route present");
4243 local_pfx.fp_len = 32;
4244 fib_table_entry_update_one_path(fib_index, &local_pfx,
4245 FIB_SOURCE_INTERFACE,
4246 (FIB_ENTRY_FLAG_CONNECTED |
4247 FIB_ENTRY_FLAG_LOCAL),
4250 tm->hw[0]->sw_if_index,
4251 ~0, // invalid fib index
4254 FIB_ROUTE_PATH_FLAG_NONE);
4255 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4257 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4258 "local interface route present");
4261 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4263 fib_prefix_t pfx_10_10_10_1_s_32 = {
4265 .fp_proto = FIB_PROTOCOL_IP4,
4268 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4271 fib_node_index_t ai;
4273 fib_table_entry_update_one_path(fib_index,
4274 &pfx_10_10_10_1_s_32,
4276 FIB_ENTRY_FLAG_NONE,
4278 &pfx_10_10_10_1_s_32.fp_addr,
4279 tm->hw[0]->sw_if_index,
4280 ~0, // invalid fib index
4283 FIB_ROUTE_PATH_FLAG_NONE);
4285 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4286 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4287 ai = fib_entry_get_adj(fei);
4290 * create another FIB table into which routes will be imported
4292 u32 import_fib_index1;
4294 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4297 * Add an attached route in the import FIB
4299 local_pfx.fp_len = 24;
4300 fib_table_entry_update_one_path(import_fib_index1,
4303 FIB_ENTRY_FLAG_NONE,
4306 tm->hw[0]->sw_if_index,
4307 ~0, // invalid fib index
4310 FIB_ROUTE_PATH_FLAG_NONE);
4311 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4312 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4315 * check for the presence of the adj-fibs in the import table
4317 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4318 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4319 FIB_TEST((ai == fib_entry_get_adj(fei)),
4320 "adj-fib1 Import uses same adj as export");
4323 * check for the presence of the local in the import table
4325 local_pfx.fp_len = 32;
4326 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4327 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4330 * Add another adj-fin in the export table. Expect this
4331 * to get magically exported;
4333 fib_prefix_t pfx_10_10_10_2_s_32 = {
4335 .fp_proto = FIB_PROTOCOL_IP4,
4338 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4342 fib_table_entry_update_one_path(fib_index,
4343 &pfx_10_10_10_2_s_32,
4345 FIB_ENTRY_FLAG_NONE,
4347 &pfx_10_10_10_2_s_32.fp_addr,
4348 tm->hw[0]->sw_if_index,
4349 ~0, // invalid fib index
4352 FIB_ROUTE_PATH_FLAG_NONE);
4353 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4354 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4355 ai = fib_entry_get_adj(fei);
4357 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4358 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4359 FIB_TEST((ai == fib_entry_get_adj(fei)),
4360 "Import uses same adj as export");
4363 * create a 2nd FIB table into which routes will be imported
4365 u32 import_fib_index2;
4367 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4370 * Add an attached route in the import FIB
4372 local_pfx.fp_len = 24;
4373 fib_table_entry_update_one_path(import_fib_index2,
4376 FIB_ENTRY_FLAG_NONE,
4379 tm->hw[0]->sw_if_index,
4380 ~0, // invalid fib index
4383 FIB_ROUTE_PATH_FLAG_NONE);
4384 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4385 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4388 * check for the presence of all the adj-fibs and local in the import table
4390 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4391 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4392 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4393 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4394 local_pfx.fp_len = 32;
4395 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4396 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4399 * add a 3rd adj-fib. expect it to be exported to both tables.
4401 fib_prefix_t pfx_10_10_10_3_s_32 = {
4403 .fp_proto = FIB_PROTOCOL_IP4,
4406 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4410 fib_table_entry_update_one_path(fib_index,
4411 &pfx_10_10_10_3_s_32,
4413 FIB_ENTRY_FLAG_NONE,
4415 &pfx_10_10_10_3_s_32.fp_addr,
4416 tm->hw[0]->sw_if_index,
4417 ~0, // invalid fib index
4420 FIB_ROUTE_PATH_FLAG_NONE);
4421 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4422 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4423 ai = fib_entry_get_adj(fei);
4425 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4426 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4427 FIB_TEST((ai == fib_entry_get_adj(fei)),
4428 "Import uses same adj as export");
4429 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4430 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4431 FIB_TEST((ai == fib_entry_get_adj(fei)),
4432 "Import uses same adj as export");
4435 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4437 fib_table_entry_delete(fib_index,
4438 &pfx_10_10_10_3_s_32,
4441 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4442 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4444 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4445 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
4447 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4448 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4451 * remove the attached route from the 2nd FIB. expect the imported
4452 * entires to be removed
4454 local_pfx.fp_len = 24;
4455 fib_table_entry_delete(import_fib_index2,
4458 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4459 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4461 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4462 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4463 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4464 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4465 local_pfx.fp_len = 32;
4466 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4467 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4469 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4470 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4471 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4472 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4473 local_pfx.fp_len = 32;
4474 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4475 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4478 * modify the route in FIB1 so it is no longer attached. expect the imported
4479 * entires to be removed
4481 local_pfx.fp_len = 24;
4482 fib_table_entry_update_one_path(import_fib_index1,
4485 FIB_ENTRY_FLAG_NONE,
4487 &pfx_10_10_10_2_s_32.fp_addr,
4488 tm->hw[0]->sw_if_index,
4489 ~0, // invalid fib index
4492 FIB_ROUTE_PATH_FLAG_NONE);
4493 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4494 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4495 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4496 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4497 local_pfx.fp_len = 32;
4498 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4499 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4502 * modify it back to attached. expect the adj-fibs back
4504 local_pfx.fp_len = 24;
4505 fib_table_entry_update_one_path(import_fib_index1,
4508 FIB_ENTRY_FLAG_NONE,
4511 tm->hw[0]->sw_if_index,
4512 ~0, // invalid fib index
4515 FIB_ROUTE_PATH_FLAG_NONE);
4516 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4517 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4518 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4519 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4520 local_pfx.fp_len = 32;
4521 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4522 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4525 * add a covering attached next-hop for the interface address, so we have
4526 * a valid adj to find when we check the forwarding tables
4528 fib_prefix_t pfx_10_0_0_0_s_8 = {
4530 .fp_proto = FIB_PROTOCOL_IP4,
4533 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4537 fei = fib_table_entry_update_one_path(fib_index,
4540 FIB_ENTRY_FLAG_NONE,
4542 &pfx_10_10_10_3_s_32.fp_addr,
4543 tm->hw[0]->sw_if_index,
4544 ~0, // invalid fib index
4547 FIB_ROUTE_PATH_FLAG_NONE);
4548 dpo = fib_entry_contribute_ip_forwarding(fei);
4551 * remove the route in the export fib. expect the adj-fibs to be removed
4553 local_pfx.fp_len = 24;
4554 fib_table_entry_delete(fib_index,
4556 FIB_SOURCE_INTERFACE);
4558 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4559 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4560 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4561 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4562 local_pfx.fp_len = 32;
4563 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4564 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4567 * the adj-fibs in the export VRF are present in the FIB table,
4568 * but not installed in forwarding, since they have no attached cover.
4569 * Consequently a lookup in the MTRIE gives the adj for the covering
4572 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4573 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4576 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4577 FIB_TEST(lbi == dpo->dpoi_index,
4578 "10.10.10.1 forwards on \n%U not \n%U",
4579 format_load_balance, lbi, 0,
4580 format_dpo_id, dpo, 0);
4581 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4582 FIB_TEST(lbi == dpo->dpoi_index,
4583 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4584 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
4585 FIB_TEST(lbi == dpo->dpoi_index,
4586 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
4589 * add the export prefix back, but not as attached.
4590 * No adj-fibs in export nor import tables
4592 local_pfx.fp_len = 24;
4593 fei = fib_table_entry_update_one_path(fib_index,
4596 FIB_ENTRY_FLAG_NONE,
4598 &pfx_10_10_10_1_s_32.fp_addr,
4599 tm->hw[0]->sw_if_index,
4600 ~0, // invalid fib index
4603 FIB_ROUTE_PATH_FLAG_NONE);
4604 dpo = fib_entry_contribute_ip_forwarding(fei);
4606 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4607 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
4608 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4609 FIB_TEST(lbi == dpo->dpoi_index,
4610 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
4611 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4612 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4613 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4614 FIB_TEST(lbi == dpo->dpoi_index,
4615 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4617 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4618 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4619 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4620 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4621 local_pfx.fp_len = 32;
4622 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4623 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4626 * modify the export prefix so it is attached. expect all covereds to return
4628 local_pfx.fp_len = 24;
4629 fib_table_entry_update_one_path(fib_index,
4632 FIB_ENTRY_FLAG_NONE,
4635 tm->hw[0]->sw_if_index,
4636 ~0, // invalid fib index
4639 FIB_ROUTE_PATH_FLAG_NONE);
4641 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4642 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4643 dpo = fib_entry_contribute_ip_forwarding(fei);
4644 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4645 "Adj-fib1 is not drop in export");
4646 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4647 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4648 local_pfx.fp_len = 32;
4649 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4650 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4651 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4652 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4653 dpo = fib_entry_contribute_ip_forwarding(fei);
4654 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4655 "Adj-fib1 is not drop in export");
4656 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4657 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4658 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4659 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4660 local_pfx.fp_len = 32;
4661 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4662 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4665 * modify the export prefix so connected. no change.
4667 local_pfx.fp_len = 24;
4668 fib_table_entry_update_one_path(fib_index, &local_pfx,
4669 FIB_SOURCE_INTERFACE,
4670 (FIB_ENTRY_FLAG_CONNECTED |
4671 FIB_ENTRY_FLAG_ATTACHED),
4674 tm->hw[0]->sw_if_index,
4678 FIB_ROUTE_PATH_FLAG_NONE);
4680 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4681 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4682 dpo = fib_entry_contribute_ip_forwarding(fei);
4683 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4684 "Adj-fib1 is not drop in export");
4685 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4686 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4687 local_pfx.fp_len = 32;
4688 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4689 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4690 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4691 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4692 dpo = fib_entry_contribute_ip_forwarding(fei);
4693 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4694 "Adj-fib1 is not drop in export");
4695 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4696 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4697 local_pfx.fp_len = 32;
4698 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4699 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4704 fib_table_entry_delete(fib_index,
4707 fib_table_entry_delete(fib_index,
4708 &pfx_10_10_10_1_s_32,
4710 fib_table_entry_delete(fib_index,
4711 &pfx_10_10_10_2_s_32,
4713 local_pfx.fp_len = 32;
4714 fib_table_entry_delete(fib_index,
4716 FIB_SOURCE_INTERFACE);
4717 local_pfx.fp_len = 24;
4718 fib_table_entry_delete(fib_index,
4721 fib_table_entry_delete(fib_index,
4723 FIB_SOURCE_INTERFACE);
4724 local_pfx.fp_len = 24;
4725 fib_table_entry_delete(import_fib_index1,
4729 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
4730 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
4732 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4736 typedef enum fib_test_lb_bucket_type_t_ {
4742 } fib_test_lb_bucket_type_t;
4744 typedef struct fib_test_lb_bucket_t_ {
4745 fib_test_lb_bucket_type_t type;
4776 } fib_test_lb_bucket_t;
4778 #define FIB_TEST_LB(_cond, _comment, _args...) \
4780 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
4786 fib_test_validate_lb_v (const load_balance_t *lb,
4790 const dpo_id_t *dpo;
4793 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
4795 for (bucket = 0; bucket < n_buckets; bucket++)
4797 const fib_test_lb_bucket_t *exp;
4799 exp = va_arg(ap, fib_test_lb_bucket_t*);
4800 dpo = load_balance_get_bucket_i(lb, bucket);
4804 case FT_LB_LABEL_O_ADJ:
4806 const mpls_label_dpo_t *mld;
4808 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4809 "bucket %d stacks on %U",
4811 format_dpo_type, dpo->dpoi_type);
4813 mld = mpls_label_dpo_get(dpo->dpoi_index);
4814 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4816 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4817 exp->label_o_adj.label),
4818 "bucket %d stacks on label %d",
4820 exp->label_o_adj.label);
4822 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4823 exp->label_o_adj.eos),
4824 "bucket %d stacks on label %d %U",
4826 exp->label_o_adj.label,
4827 format_mpls_eos_bit, exp->label_o_adj.eos);
4829 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
4830 "bucket %d label stacks on %U",
4832 format_dpo_type, mld->mld_dpo.dpoi_type);
4834 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
4835 "bucket %d label stacks on adj %d",
4837 exp->label_o_adj.adj);
4840 case FT_LB_LABEL_O_LB:
4842 const mpls_label_dpo_t *mld;
4845 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4846 "bucket %d stacks on %U",
4848 format_dpo_type, dpo->dpoi_type);
4850 mld = mpls_label_dpo_get(dpo->dpoi_index);
4851 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4853 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4854 exp->label_o_lb.label),
4855 "bucket %d stacks on label %d",
4857 exp->label_o_lb.label);
4859 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4860 exp->label_o_lb.eos),
4861 "bucket %d stacks on label %d %U",
4863 exp->label_o_lb.label,
4864 format_mpls_eos_bit, exp->label_o_lb.eos);
4866 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
4867 "bucket %d label stacks on %U",
4869 format_dpo_type, mld->mld_dpo.dpoi_type);
4871 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
4872 "bucket %d label stacks on LB %d",
4874 exp->label_o_lb.lb);
4878 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
4879 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
4880 "bucket %d stacks on %U",
4882 format_dpo_type, dpo->dpoi_type);
4883 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
4884 "bucket %d stacks on adj %d",
4889 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
4890 "bucket %d stacks on %U",
4892 format_dpo_type, dpo->dpoi_type);
4893 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
4894 "bucket %d stacks on lb %d",
4899 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
4900 "bucket %d stacks on %U",
4902 format_dpo_type, dpo->dpoi_type);
4903 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
4904 "bucket %d stacks on drop %d",
4914 fib_test_validate_entry (fib_node_index_t fei,
4915 fib_forward_chain_type_t fct,
4919 const load_balance_t *lb;
4920 dpo_id_t dpo = DPO_INVALID;
4927 va_start(ap, n_buckets);
4929 fib_entry_get_prefix(fei, &pfx);
4930 fib_index = fib_entry_get_fib_index(fei);
4931 fib_entry_contribute_forwarding(fei, fct, &dpo);
4933 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
4934 "Entry links to %U",
4935 format_dpo_type, dpo.dpoi_type);
4936 lb = load_balance_get(dpo.dpoi_index);
4938 res = fib_test_validate_lb_v(lb, n_buckets, ap);
4941 * ensure that the LB contributed by the entry is the
4942 * same as the LB in the forwarding tables
4944 switch (pfx.fp_proto)
4946 case FIB_PROTOCOL_IP4:
4947 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
4949 case FIB_PROTOCOL_IP6:
4950 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
4952 case FIB_PROTOCOL_MPLS:
4954 mpls_unicast_header_t hdr = {
4955 .label_exp_s_ttl = 0,
4958 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
4959 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
4960 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
4962 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
4968 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
4969 "Contributed LB = FW LB: %U\n %U",
4970 format_load_balance, fw_lbi, 0,
4971 format_load_balance, dpo.dpoi_index, 0);
4981 * Test the recursive route route handling for GRE tunnels
4984 fib_test_label (void)
4986 fib_node_index_t fei, ai_mpls_10_10_10_1, ai_v4_10_10_11_1, ai_v4_10_10_11_2, ai_mpls_10_10_11_2, ai_mpls_10_10_11_1;
4987 const u32 fib_index = 0;
4992 lb_count = pool_elts(load_balance_pool);
4997 * add interface routes. We'll assume this works. It's more rigorously
5000 fib_prefix_t local0_pfx = {
5002 .fp_proto = FIB_PROTOCOL_IP4,
5006 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5011 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5014 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5015 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5017 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5018 FIB_SOURCE_INTERFACE,
5019 (FIB_ENTRY_FLAG_CONNECTED |
5020 FIB_ENTRY_FLAG_ATTACHED),
5023 tm->hw[0]->sw_if_index,
5027 FIB_ROUTE_PATH_FLAG_NONE);
5028 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5029 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5030 "attached interface route present");
5032 local0_pfx.fp_len = 32;
5033 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5034 FIB_SOURCE_INTERFACE,
5035 (FIB_ENTRY_FLAG_CONNECTED |
5036 FIB_ENTRY_FLAG_LOCAL),
5039 tm->hw[0]->sw_if_index,
5040 ~0, // invalid fib index
5043 FIB_ROUTE_PATH_FLAG_NONE);
5044 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5046 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5047 "local interface route present");
5049 fib_prefix_t local1_pfx = {
5051 .fp_proto = FIB_PROTOCOL_IP4,
5055 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5060 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5061 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5063 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5064 FIB_SOURCE_INTERFACE,
5065 (FIB_ENTRY_FLAG_CONNECTED |
5066 FIB_ENTRY_FLAG_ATTACHED),
5069 tm->hw[1]->sw_if_index,
5073 FIB_ROUTE_PATH_FLAG_NONE);
5074 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5075 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5076 "attached interface route present");
5078 local1_pfx.fp_len = 32;
5079 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5080 FIB_SOURCE_INTERFACE,
5081 (FIB_ENTRY_FLAG_CONNECTED |
5082 FIB_ENTRY_FLAG_LOCAL),
5085 tm->hw[1]->sw_if_index,
5086 ~0, // invalid fib index
5089 FIB_ROUTE_PATH_FLAG_NONE);
5090 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5092 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5093 "local interface route present");
5095 ip46_address_t nh_10_10_10_1 = {
5097 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5100 ip46_address_t nh_10_10_11_1 = {
5102 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5105 ip46_address_t nh_10_10_11_2 = {
5107 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5111 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5114 tm->hw[1]->sw_if_index);
5115 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5118 tm->hw[1]->sw_if_index);
5119 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5122 tm->hw[0]->sw_if_index);
5123 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5126 tm->hw[1]->sw_if_index);
5127 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5130 tm->hw[1]->sw_if_index);
5133 * Add an etry with one path with a real out-going label
5135 fib_prefix_t pfx_1_1_1_1_s_32 = {
5137 .fp_proto = FIB_PROTOCOL_IP4,
5139 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5142 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5143 .type = FT_LB_LABEL_O_ADJ,
5145 .adj = ai_mpls_10_10_10_1,
5150 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5151 .type = FT_LB_LABEL_O_ADJ,
5153 .adj = ai_mpls_10_10_10_1,
5155 .eos = MPLS_NON_EOS,
5158 fib_table_entry_update_one_path(fib_index,
5161 FIB_ENTRY_FLAG_NONE,
5164 tm->hw[0]->sw_if_index,
5165 ~0, // invalid fib index
5168 FIB_ROUTE_PATH_FLAG_NONE);
5170 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5171 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5173 FIB_TEST(fib_test_validate_entry(fei,
5174 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5176 &l99_eos_o_10_10_10_1),
5177 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5180 * add a path with an implicit NULL label
5182 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5185 .adj = ai_v4_10_10_11_1,
5188 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5191 .adj = ai_mpls_10_10_11_1,
5195 fei = fib_table_entry_path_add(fib_index,
5198 FIB_ENTRY_FLAG_NONE,
5201 tm->hw[1]->sw_if_index,
5202 ~0, // invalid fib index
5204 MPLS_IETF_IMPLICIT_NULL_LABEL,
5205 FIB_ROUTE_PATH_FLAG_NONE);
5207 FIB_TEST(fib_test_validate_entry(fei,
5208 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5210 &l99_eos_o_10_10_10_1,
5212 "1.1.1.1/32 LB 2 buckets via: "
5213 "label 99 over 10.10.10.1, "
5214 "adj over 10.10.11.1");
5217 * assign the route a local label
5219 fib_table_entry_local_label_add(fib_index,
5223 fib_prefix_t pfx_24001_eos = {
5224 .fp_proto = FIB_PROTOCOL_MPLS,
5228 fib_prefix_t pfx_24001_neos = {
5229 .fp_proto = FIB_PROTOCOL_MPLS,
5231 .fp_eos = MPLS_NON_EOS,
5235 * The EOS entry should link to both the paths,
5236 * and use an ip adj for the imp-null
5237 * The NON-EOS entry should link to both the paths,
5238 * and use an mpls adj for the imp-null
5240 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5242 FIB_TEST(fib_test_validate_entry(fei,
5243 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5245 &l99_eos_o_10_10_10_1,
5247 "24001/eos LB 2 buckets via: "
5248 "label 99 over 10.10.10.1, "
5249 "adj over 10.10.11.1");
5252 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5254 FIB_TEST(fib_test_validate_entry(fei,
5255 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5257 &l99_neos_o_10_10_10_1,
5258 &a_mpls_o_10_10_11_1),
5259 "24001/neos LB 1 bucket via: "
5260 "label 99 over 10.10.10.1 ",
5261 "mpls-adj via 10.10.11.1");
5264 * add an unlabelled path, this is excluded from the neos chains,
5266 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5269 .adj = ai_v4_10_10_11_2,
5273 fei = fib_table_entry_path_add(fib_index,
5276 FIB_ENTRY_FLAG_NONE,
5279 tm->hw[1]->sw_if_index,
5280 ~0, // invalid fib index
5283 FIB_ROUTE_PATH_FLAG_NONE);
5285 FIB_TEST(fib_test_validate_entry(fei,
5286 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5287 16, // 3 choices spread over 16 buckets
5288 &l99_eos_o_10_10_10_1,
5289 &l99_eos_o_10_10_10_1,
5290 &l99_eos_o_10_10_10_1,
5291 &l99_eos_o_10_10_10_1,
5292 &l99_eos_o_10_10_10_1,
5293 &l99_eos_o_10_10_10_1,
5304 "1.1.1.1/32 LB 16 buckets via: "
5305 "label 99 over 10.10.10.1, "
5306 "adj over 10.10.11.1",
5307 "adj over 10.10.11.2");
5310 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5312 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5313 fib_entry_contribute_forwarding(fei,
5314 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5318 * n-eos has only the 2 labelled paths
5320 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5323 FIB_TEST(fib_test_validate_entry(fei,
5324 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5326 &l99_neos_o_10_10_10_1,
5327 &a_mpls_o_10_10_11_1),
5328 "24001/neos LB 2 buckets via: "
5329 "label 99 over 10.10.10.1, "
5330 "adj-mpls over 10.10.11.2");
5333 * A labelled recursive
5335 fib_prefix_t pfx_2_2_2_2_s_32 = {
5337 .fp_proto = FIB_PROTOCOL_IP4,
5339 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5342 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5343 .type = FT_LB_LABEL_O_LB,
5345 .lb = non_eos_1_1_1_1.dpoi_index,
5351 fib_table_entry_update_one_path(fib_index,
5354 FIB_ENTRY_FLAG_NONE,
5356 &pfx_1_1_1_1_s_32.fp_addr,
5361 FIB_ROUTE_PATH_FLAG_NONE);
5363 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5364 FIB_TEST(fib_test_validate_entry(fei,
5365 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5367 &l1600_eos_o_1_1_1_1),
5368 "2.2.2.2.2/32 LB 1 buckets via: "
5369 "label 1600 over 1.1.1.1");
5371 dpo_id_t dpo_44 = DPO_INVALID;
5374 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5375 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5377 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5378 "uRPF check for 2.2.2.2/32 on %d OK",
5379 tm->hw[0]->sw_if_index);
5380 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5381 "uRPF check for 2.2.2.2/32 on %d OK",
5382 tm->hw[1]->sw_if_index);
5383 FIB_TEST(!fib_urpf_check(urpfi, 99),
5384 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5387 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5388 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5389 "Shared uRPF on IP and non-EOS chain");
5394 * we are holding a lock on the non-eos LB of the via-entry.
5395 * do a PIC-core failover by shutting the link of the via-entry.
5397 * shut down the link with the valid label
5399 vnet_sw_interface_set_flags(vnet_get_main(),
5400 tm->hw[0]->sw_if_index,
5403 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5404 FIB_TEST(fib_test_validate_entry(fei,
5405 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5409 "1.1.1.1/32 LB 2 buckets via: "
5410 "adj over 10.10.11.1, ",
5411 "adj-v4 over 10.10.11.2");
5413 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5415 FIB_TEST(fib_test_validate_entry(fei,
5416 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5420 "24001/eos LB 2 buckets via: "
5421 "adj over 10.10.11.1, ",
5422 "adj-v4 over 10.10.11.2");
5424 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5426 FIB_TEST(fib_test_validate_entry(fei,
5427 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5429 &a_mpls_o_10_10_11_1),
5430 "24001/neos LB 1 buckets via: "
5431 "adj-mpls over 10.10.11.2");
5434 * test that the pre-failover load-balance has been in-place
5437 dpo_id_t current = DPO_INVALID;
5438 fib_entry_contribute_forwarding(fei,
5439 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5442 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5444 "PIC-core LB inplace modified %U %U",
5445 format_dpo_id, &non_eos_1_1_1_1, 0,
5446 format_dpo_id, ¤t, 0);
5448 dpo_reset(&non_eos_1_1_1_1);
5449 dpo_reset(¤t);
5452 * no-shut the link with the valid label
5454 vnet_sw_interface_set_flags(vnet_get_main(),
5455 tm->hw[0]->sw_if_index,
5456 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5458 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5459 FIB_TEST(fib_test_validate_entry(fei,
5460 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5461 16, // 3 choices spread over 16 buckets
5462 &l99_eos_o_10_10_10_1,
5463 &l99_eos_o_10_10_10_1,
5464 &l99_eos_o_10_10_10_1,
5465 &l99_eos_o_10_10_10_1,
5466 &l99_eos_o_10_10_10_1,
5467 &l99_eos_o_10_10_10_1,
5478 "1.1.1.1/32 LB 16 buckets via: "
5479 "label 99 over 10.10.10.1, "
5480 "adj over 10.10.11.1",
5481 "adj-v4 over 10.10.11.2");
5484 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5486 FIB_TEST(fib_test_validate_entry(fei,
5487 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5488 16, // 3 choices spread over 16 buckets
5489 &l99_eos_o_10_10_10_1,
5490 &l99_eos_o_10_10_10_1,
5491 &l99_eos_o_10_10_10_1,
5492 &l99_eos_o_10_10_10_1,
5493 &l99_eos_o_10_10_10_1,
5494 &l99_eos_o_10_10_10_1,
5505 "24001/eos LB 16 buckets via: "
5506 "label 99 over 10.10.10.1, "
5507 "adj over 10.10.11.1",
5508 "adj-v4 over 10.10.11.2");
5510 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5512 FIB_TEST(fib_test_validate_entry(fei,
5513 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5515 &l99_neos_o_10_10_10_1,
5516 &a_mpls_o_10_10_11_1),
5517 "24001/neos LB 2 buckets via: "
5518 "label 99 over 10.10.10.1, "
5519 "adj-mpls over 10.10.11.2");
5522 * remove the first path with the valid label
5524 fib_table_entry_path_remove(fib_index,
5529 tm->hw[0]->sw_if_index,
5530 ~0, // invalid fib index
5532 FIB_ROUTE_PATH_FLAG_NONE);
5534 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5535 FIB_TEST(fib_test_validate_entry(fei,
5536 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5540 "1.1.1.1/32 LB 2 buckets via: "
5541 "adj over 10.10.11.1",
5542 "adj-v4 over 10.10.11.2");
5544 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5546 FIB_TEST(fib_test_validate_entry(fei,
5547 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5551 "24001/eos LB 2 buckets via: "
5552 "adj over 10.10.11.1",
5553 "adj-v4 over 10.10.11.2");
5555 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5558 FIB_TEST(fib_test_validate_entry(fei,
5559 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5561 &a_mpls_o_10_10_11_1),
5562 "24001/neos LB 1 buckets via: "
5563 "adj-mpls over 10.10.11.2");
5566 * remove the other path with a valid label
5568 fib_test_lb_bucket_t bucket_drop = {
5569 .type = FT_LB_SPECIAL,
5571 .adj = DPO_PROTO_IP4,
5575 fib_table_entry_path_remove(fib_index,
5580 tm->hw[1]->sw_if_index,
5581 ~0, // invalid fib index
5583 FIB_ROUTE_PATH_FLAG_NONE);
5585 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5586 FIB_TEST(fib_test_validate_entry(fei,
5587 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5590 "1.1.1.1/32 LB 1 buckets via: "
5591 "adj over 10.10.11.2");
5593 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5595 FIB_TEST(fib_test_validate_entry(fei,
5596 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5599 "24001/eos LB 1 buckets via: "
5600 "adj over 10.10.11.2");
5602 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5604 FIB_TEST(fib_test_validate_entry(fei,
5605 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5608 "24001/eos LB 1 buckets via: DROP");
5611 * add back the path with the valid label
5613 fib_table_entry_path_add(fib_index,
5616 FIB_ENTRY_FLAG_NONE,
5619 tm->hw[0]->sw_if_index,
5620 ~0, // invalid fib index
5623 FIB_ROUTE_PATH_FLAG_NONE);
5625 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5626 FIB_TEST(fib_test_validate_entry(fei,
5627 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5629 &l99_eos_o_10_10_10_1,
5631 "1.1.1.1/32 LB 2 buckets via: "
5632 "label 99 over 10.10.10.1, "
5633 "adj over 10.10.11.2");
5635 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5637 FIB_TEST(fib_test_validate_entry(fei,
5638 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5640 &l99_eos_o_10_10_10_1,
5642 "24001/eos LB 2 buckets via: "
5643 "label 99 over 10.10.10.1, "
5644 "adj over 10.10.11.2");
5646 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5648 FIB_TEST(fib_test_validate_entry(fei,
5649 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5651 &l99_neos_o_10_10_10_1),
5652 "24001/neos LB 1 buckets via: "
5653 "label 99 over 10.10.10.1");
5656 * change the local label
5658 fib_table_entry_local_label_add(fib_index,
5662 fib_prefix_t pfx_25005_eos = {
5663 .fp_proto = FIB_PROTOCOL_MPLS,
5667 fib_prefix_t pfx_25005_neos = {
5668 .fp_proto = FIB_PROTOCOL_MPLS,
5670 .fp_eos = MPLS_NON_EOS,
5673 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5674 fib_table_lookup(fib_index, &pfx_24001_eos)),
5675 "24001/eos removed after label change");
5676 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5677 fib_table_lookup(fib_index, &pfx_24001_neos)),
5678 "24001/eos removed after label change");
5680 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5682 FIB_TEST(fib_test_validate_entry(fei,
5683 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5685 &l99_eos_o_10_10_10_1,
5687 "25005/eos LB 2 buckets via: "
5688 "label 99 over 10.10.10.1, "
5689 "adj over 10.10.11.2");
5691 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5693 FIB_TEST(fib_test_validate_entry(fei,
5694 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5696 &l99_neos_o_10_10_10_1),
5697 "25005/neos LB 1 buckets via: "
5698 "label 99 over 10.10.10.1");
5701 * remove the local label.
5702 * the check that the MPLS entries are gone is done by the fact the
5703 * MPLS table is no longer present.
5705 fib_table_entry_local_label_remove(fib_index,
5709 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5710 FIB_TEST(fib_test_validate_entry(fei,
5711 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5713 &l99_eos_o_10_10_10_1,
5715 "24001/eos LB 2 buckets via: "
5716 "label 99 over 10.10.10.1, "
5717 "adj over 10.10.11.2");
5719 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5720 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5721 "No more MPLS FIB entries => table removed");
5724 * add another via-entry for the recursive
5726 fib_prefix_t pfx_1_1_1_2_s_32 = {
5728 .fp_proto = FIB_PROTOCOL_IP4,
5730 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5733 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5734 .type = FT_LB_LABEL_O_ADJ,
5736 .adj = ai_mpls_10_10_10_1,
5742 fei = fib_table_entry_update_one_path(fib_index,
5745 FIB_ENTRY_FLAG_NONE,
5748 tm->hw[0]->sw_if_index,
5749 ~0, // invalid fib index
5752 FIB_ROUTE_PATH_FLAG_NONE);
5754 FIB_TEST(fib_test_validate_entry(fei,
5755 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5757 &l101_eos_o_10_10_10_1),
5758 "1.1.1.2/32 LB 1 buckets via: "
5759 "label 101 over 10.10.10.1");
5761 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
5762 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5764 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5766 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5768 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5771 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5772 .type = FT_LB_LABEL_O_LB,
5774 .lb = non_eos_1_1_1_2.dpoi_index,
5779 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5781 fei = fib_table_entry_path_add(fib_index,
5784 FIB_ENTRY_FLAG_NONE,
5786 &pfx_1_1_1_2_s_32.fp_addr,
5791 FIB_ROUTE_PATH_FLAG_NONE);
5793 FIB_TEST(fib_test_validate_entry(fei,
5794 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5796 &l1600_eos_o_1_1_1_1,
5797 &l1601_eos_o_1_1_1_2),
5798 "2.2.2.2/32 LB 2 buckets via: "
5799 "label 1600 via 1.1,1.1, "
5800 "label 16001 via 1.1.1.2");
5803 * update the via-entry so it no longer has an imp-null path.
5804 * the LB for the recursive can use an imp-null
5806 fei = fib_table_entry_update_one_path(fib_index,
5809 FIB_ENTRY_FLAG_NONE,
5812 tm->hw[1]->sw_if_index,
5813 ~0, // invalid fib index
5815 MPLS_IETF_IMPLICIT_NULL_LABEL,
5816 FIB_ROUTE_PATH_FLAG_NONE);
5818 FIB_TEST(fib_test_validate_entry(fei,
5819 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5822 "1.1.1.2/32 LB 1 buckets via: "
5825 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5826 FIB_TEST(fib_test_validate_entry(fei,
5827 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5829 &l1600_eos_o_1_1_1_1,
5830 &l1601_eos_o_1_1_1_2),
5831 "2.2.2.2/32 LB 2 buckets via: "
5832 "label 1600 via 1.1,1.1, "
5833 "label 16001 via 1.1.1.2");
5836 * update the via-entry so it no longer has labelled paths.
5837 * the LB for the recursive should exclue this via form its LB
5839 fei = fib_table_entry_update_one_path(fib_index,
5842 FIB_ENTRY_FLAG_NONE,
5845 tm->hw[1]->sw_if_index,
5846 ~0, // invalid fib index
5849 FIB_ROUTE_PATH_FLAG_NONE);
5851 FIB_TEST(fib_test_validate_entry(fei,
5852 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5855 "1.1.1.2/32 LB 1 buckets via: "
5858 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5859 FIB_TEST(fib_test_validate_entry(fei,
5860 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5862 &l1600_eos_o_1_1_1_1),
5863 "2.2.2.2/32 LB 1 buckets via: "
5864 "label 1600 via 1.1,1.1");
5866 dpo_reset(&non_eos_1_1_1_1);
5867 dpo_reset(&non_eos_1_1_1_2);
5870 * Add a recursive with no out-labels. We expect to use the IP of the via
5872 fib_prefix_t pfx_2_2_2_3_s_32 = {
5874 .fp_proto = FIB_PROTOCOL_IP4,
5876 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
5879 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5881 fib_table_entry_update_one_path(fib_index,
5884 FIB_ENTRY_FLAG_NONE,
5886 &pfx_1_1_1_1_s_32.fp_addr,
5891 FIB_ROUTE_PATH_FLAG_NONE);
5893 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5895 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5898 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5901 .lb = ip_1_1_1_1.dpoi_index,
5905 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
5906 FIB_TEST(fib_test_validate_entry(fei,
5907 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5910 "2.2.2.2.3/32 LB 1 buckets via: "
5914 * Add a recursive with an imp-null out-label.
5915 * We expect to use the IP of the via
5917 fib_prefix_t pfx_2_2_2_4_s_32 = {
5919 .fp_proto = FIB_PROTOCOL_IP4,
5921 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
5925 fib_table_entry_update_one_path(fib_index,
5928 FIB_ENTRY_FLAG_NONE,
5930 &pfx_1_1_1_1_s_32.fp_addr,
5935 FIB_ROUTE_PATH_FLAG_NONE);
5937 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
5938 FIB_TEST(fib_test_validate_entry(fei,
5939 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5942 "2.2.2.2.4/32 LB 1 buckets via: "
5945 dpo_reset(&ip_1_1_1_1);
5950 fib_table_entry_delete(fib_index,
5954 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5955 FIB_TEST(fib_test_validate_entry(fei,
5956 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5958 &l1600_eos_o_1_1_1_1),
5959 "2.2.2.2/32 LB 1 buckets via: "
5960 "label 1600 via 1.1,1.1");
5962 fib_table_entry_delete(fib_index,
5966 FIB_TEST(fib_test_validate_entry(fei,
5967 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5970 "2.2.2.2/32 LB 1 buckets via: DROP");
5972 fib_table_entry_delete(fib_index,
5975 fib_table_entry_delete(fib_index,
5978 fib_table_entry_delete(fib_index,
5982 adj_unlock(ai_mpls_10_10_10_1);
5983 adj_unlock(ai_mpls_10_10_11_2);
5984 adj_unlock(ai_v4_10_10_11_1);
5985 adj_unlock(ai_v4_10_10_11_2);
5986 adj_unlock(ai_mpls_10_10_11_1);
5988 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5991 local0_pfx.fp_len = 32;
5992 fib_table_entry_delete(fib_index,
5994 FIB_SOURCE_INTERFACE);
5995 local0_pfx.fp_len = 24;
5996 fib_table_entry_delete(fib_index,
5998 FIB_SOURCE_INTERFACE);
5999 local1_pfx.fp_len = 32;
6000 fib_table_entry_delete(fib_index,
6002 FIB_SOURCE_INTERFACE);
6003 local1_pfx.fp_len = 24;
6004 fib_table_entry_delete(fib_index,
6006 FIB_SOURCE_INTERFACE);
6009 * +1 for the drop LB in the MPLS tables.
6011 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6012 "Load-balance resources freed %d of %d",
6013 lb_count+1, pool_elts(load_balance_pool));
6016 #define N_TEST_CHILDREN 4
6017 #define PARENT_INDEX 0
6019 typedef struct fib_node_test_t_
6024 fib_node_back_walk_ctx_t *ctxs;
6028 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6030 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6032 #define FOR_EACH_TEST_CHILD(_tc) \
6033 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
6034 ii < N_TEST_CHILDREN+1; \
6035 ii++, (_tc) = &fib_test_nodes[ii])
6038 fib_test_child_get_node (fib_node_index_t index)
6040 return (&fib_test_nodes[index].node);
6043 static int fib_test_walk_spawns_walks;
6045 static fib_node_back_walk_rc_t
6046 fib_test_child_back_walk_notify (fib_node_t *node,
6047 fib_node_back_walk_ctx_t *ctx)
6049 fib_node_test_t *tc = (fib_node_test_t*) node;
6051 vec_add1(tc->ctxs, *ctx);
6053 if (1 == fib_test_walk_spawns_walks)
6054 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6055 if (2 == fib_test_walk_spawns_walks)
6056 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6057 FIB_WALK_PRIORITY_HIGH, ctx);
6059 return (FIB_NODE_BACK_WALK_CONTINUE);
6063 fib_test_child_last_lock_gone (fib_node_t *node)
6065 fib_node_test_t *tc = (fib_node_test_t *)node;
6071 * The FIB walk's graph node virtual function table
6073 static const fib_node_vft_t fib_test_child_vft = {
6074 .fnv_get = fib_test_child_get_node,
6075 .fnv_last_lock = fib_test_child_last_lock_gone,
6076 .fnv_back_walk = fib_test_child_back_walk_notify,
6080 * the function (that should have been static but isn't so I can do this)
6081 * that processes the walk from the async queue,
6083 f64 fib_walk_process_queues(vlib_main_t * vm,
6085 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6088 fib_test_walk (void)
6090 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6091 fib_node_test_t *tc;
6095 vm = vlib_get_main();
6096 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6099 * init a fake node on which we will add children
6101 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6102 FIB_NODE_TYPE_TEST);
6104 FOR_EACH_TEST_CHILD(tc)
6106 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6107 fib_node_lock(&tc->node);
6110 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6112 FIB_NODE_TYPE_TEST, ii);
6116 * enqueue a walk across the parents children.
6118 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6120 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6121 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6122 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6123 "Parent has %d children pre-walk",
6124 fib_node_list_get_size(PARENT()->fn_children));
6127 * give the walk a large amount of time so it gets to the end
6129 fib_walk_process_queues(vm, 1);
6131 FOR_EACH_TEST_CHILD(tc)
6133 FIB_TEST(1 == vec_len(tc->ctxs),
6134 "%d child visitsed %d times",
6135 ii, vec_len(tc->ctxs));
6138 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6139 "Queue is empty post walk");
6140 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6141 "Parent has %d children post walk",
6142 fib_node_list_get_size(PARENT()->fn_children));
6145 * walk again. should be no increase in the number of visits, since
6146 * the walk will have terminated.
6148 fib_walk_process_queues(vm, 1);
6150 FOR_EACH_TEST_CHILD(tc)
6152 FIB_TEST(0 == vec_len(tc->ctxs),
6153 "%d child visitsed %d times",
6154 ii, vec_len(tc->ctxs));
6158 * schedule a low and hig priority walk. expect the high to be performed
6160 * schedule the high prio walk first so that it is further from the head
6161 * of the dependency list. that way it won't merge with the low one.
6163 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6164 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6166 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6167 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6168 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6169 FIB_WALK_PRIORITY_LOW, &low_ctx);
6171 fib_walk_process_queues(vm, 1);
6173 FOR_EACH_TEST_CHILD(tc)
6175 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6176 "%d child visitsed by high prio walk", ii);
6177 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6178 "%d child visitsed by low prio walk", ii);
6181 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6182 "Queue is empty post prio walk");
6183 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6184 "Parent has %d children post prio walk",
6185 fib_node_list_get_size(PARENT()->fn_children));
6188 * schedule 2 walks of the same priority that can be megred.
6189 * expect that each child is thus visited only once.
6191 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6192 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6194 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6195 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6196 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6197 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6199 fib_walk_process_queues(vm, 1);
6201 FOR_EACH_TEST_CHILD(tc)
6203 FIB_TEST(1 == vec_len(tc->ctxs),
6204 "%d child visitsed %d times during merge walk",
6205 ii, vec_len(tc->ctxs));
6208 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6209 "Queue is empty post merge walk");
6210 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6211 "Parent has %d children post merge walk",
6212 fib_node_list_get_size(PARENT()->fn_children));
6215 * schedule 2 walks of the same priority that cannot be megred.
6216 * expect that each child is thus visited twice and in the order
6217 * in which the walks were scheduled.
6219 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6220 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6222 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6223 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6224 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6225 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6227 fib_walk_process_queues(vm, 1);
6229 FOR_EACH_TEST_CHILD(tc)
6231 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6232 "%d child visitsed by high prio walk", ii);
6233 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6234 "%d child visitsed by low prio walk", ii);
6237 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6238 "Queue is empty post no-merge walk");
6239 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6240 "Parent has %d children post no-merge walk",
6241 fib_node_list_get_size(PARENT()->fn_children));
6244 * schedule a walk that makes one one child progress.
6245 * we do this by giving the queue draining process zero
6246 * time quanta. it's a do..while loop, so it does something.
6248 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6250 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6251 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6252 fib_walk_process_queues(vm, 0);
6254 FOR_EACH_TEST_CHILD(tc)
6256 if (ii == N_TEST_CHILDREN)
6258 FIB_TEST(1 == vec_len(tc->ctxs),
6259 "%d child visitsed %d times in zero quanta walk",
6260 ii, vec_len(tc->ctxs));
6264 FIB_TEST(0 == vec_len(tc->ctxs),
6265 "%d child visitsed %d times in 0 quanta walk",
6266 ii, vec_len(tc->ctxs));
6269 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6270 "Queue is not empty post zero quanta walk");
6271 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6272 "Parent has %d children post zero qunta walk",
6273 fib_node_list_get_size(PARENT()->fn_children));
6278 fib_walk_process_queues(vm, 0);
6280 FOR_EACH_TEST_CHILD(tc)
6282 if (ii >= N_TEST_CHILDREN-1)
6284 FIB_TEST(1 == vec_len(tc->ctxs),
6285 "%d child visitsed %d times in 2nd zero quanta walk",
6286 ii, vec_len(tc->ctxs));
6290 FIB_TEST(0 == vec_len(tc->ctxs),
6291 "%d child visitsed %d times in 2nd 0 quanta walk",
6292 ii, vec_len(tc->ctxs));
6295 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6296 "Queue is not empty post zero quanta walk");
6297 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6298 "Parent has %d children post zero qunta walk",
6299 fib_node_list_get_size(PARENT()->fn_children));
6302 * schedule another walk that will catch-up and merge.
6304 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6305 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6306 fib_walk_process_queues(vm, 1);
6308 FOR_EACH_TEST_CHILD(tc)
6310 if (ii >= N_TEST_CHILDREN-1)
6312 FIB_TEST(2 == vec_len(tc->ctxs),
6313 "%d child visitsed %d times in 2nd zero quanta merge walk",
6314 ii, vec_len(tc->ctxs));
6319 FIB_TEST(1 == vec_len(tc->ctxs),
6320 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6321 ii, vec_len(tc->ctxs));
6325 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6326 "Queue is not empty post 2nd zero quanta merge walk");
6327 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6328 "Parent has %d children post 2nd zero qunta merge walk",
6329 fib_node_list_get_size(PARENT()->fn_children));
6332 * park a async walk in the middle of the list, then have an sync walk catch
6333 * it. same expectations as async catches async.
6335 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6337 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6338 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6340 fib_walk_process_queues(vm, 0);
6341 fib_walk_process_queues(vm, 0);
6343 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6345 FOR_EACH_TEST_CHILD(tc)
6347 if (ii >= N_TEST_CHILDREN-1)
6349 FIB_TEST(2 == vec_len(tc->ctxs),
6350 "%d child visitsed %d times in sync catches async walk",
6351 ii, vec_len(tc->ctxs));
6356 FIB_TEST(1 == vec_len(tc->ctxs),
6357 "%d child visitsed %d times in sync catches async walk",
6358 ii, vec_len(tc->ctxs));
6362 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6363 "Queue is not empty post 2nd zero quanta merge walk");
6364 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6365 "Parent has %d children post 2nd zero qunta merge walk",
6366 fib_node_list_get_size(PARENT()->fn_children));
6369 * make the parent a child of one of its children, thus inducing a routing loop.
6371 fib_test_nodes[PARENT_INDEX].sibling =
6372 fib_node_child_add(FIB_NODE_TYPE_TEST,
6373 1, // the first child
6378 * execute a sync walk from the parent. each child visited spawns more sync
6379 * walks. we expect the walk to terminate.
6381 fib_test_walk_spawns_walks = 1;
6383 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6385 FOR_EACH_TEST_CHILD(tc)
6388 * child 1 - which is last in the list - has the loop.
6389 * the other children a re thus visitsed first. the we meet
6390 * child 1. we go round the loop again, visting the other children.
6391 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6396 FIB_TEST(1 == vec_len(tc->ctxs),
6397 "child %d visitsed %d times during looped sync walk",
6398 ii, vec_len(tc->ctxs));
6402 FIB_TEST(2 == vec_len(tc->ctxs),
6403 "child %d visitsed %d times during looped sync walk",
6404 ii, vec_len(tc->ctxs));
6408 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6409 "Parent has %d children post sync loop walk",
6410 fib_node_list_get_size(PARENT()->fn_children));
6413 * the walk doesn't reach the max depth because the infra knows that sync
6414 * meets sync implies a loop and bails early.
6416 FIB_TEST(high_ctx.fnbw_depth == 9,
6417 "Walk context depth %d post sync loop walk",
6418 high_ctx.fnbw_depth);
6421 * execute an async walk of the graph loop, with each child spawns sync walks
6423 high_ctx.fnbw_depth = 0;
6424 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6425 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6427 fib_walk_process_queues(vm, 1);
6429 FOR_EACH_TEST_CHILD(tc)
6432 * we don't really care how many times the children are visisted, as long as
6433 * it is more than once.
6435 FIB_TEST(1 <= vec_len(tc->ctxs),
6436 "child %d visitsed %d times during looped aync spawns sync walk",
6437 ii, vec_len(tc->ctxs));
6442 * execute an async walk of the graph loop, with each child spawns async walks
6444 fib_test_walk_spawns_walks = 2;
6445 high_ctx.fnbw_depth = 0;
6446 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6447 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6449 fib_walk_process_queues(vm, 1);
6451 FOR_EACH_TEST_CHILD(tc)
6454 * we don't really care how many times the children are visisted, as long as
6455 * it is more than once.
6457 FIB_TEST(1 <= vec_len(tc->ctxs),
6458 "child %d visitsed %d times during looped async spawns async walk",
6459 ii, vec_len(tc->ctxs));
6464 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6465 1, // the first child
6466 fib_test_nodes[PARENT_INDEX].sibling);
6471 FOR_EACH_TEST_CHILD(tc)
6473 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6475 fib_node_deinit(&tc->node);
6476 fib_node_unlock(&tc->node);
6478 fib_node_deinit(PARENT());
6481 * The parent will be destroyed when the last lock on it goes.
6482 * this test ensures all the walk objects are unlocking it.
6484 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6485 "Parent was destroyed");
6489 lfib_test_deagg (void)
6491 const mpls_label_t deag_label = 50;
6492 const u32 lfib_index = 0;
6493 const u32 fib_index = 0;
6494 dpo_id_t dpo = DPO_INVALID;
6495 const dpo_id_t *dpo1;
6496 fib_node_index_t lfe;
6502 lb_count = pool_elts(load_balance_pool);
6504 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6508 * MPLS enable an interface so we get the MPLS table created
6510 mpls_sw_interface_enable_disable(&mpls_main,
6511 tm->hw[0]->sw_if_index,
6515 * Test the specials stack properly.
6517 fib_prefix_t exp_null_v6_pfx = {
6518 .fp_proto = FIB_PROTOCOL_MPLS,
6520 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6521 .fp_payload_proto = DPO_PROTO_IP6,
6523 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
6524 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
6526 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6527 format_mpls_eos_bit, MPLS_EOS);
6528 fib_entry_contribute_forwarding(lfe,
6529 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6531 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6532 lkd = lookup_dpo_get(dpo1->dpoi_index);
6534 FIB_TEST((fib_index == lkd->lkd_fib_index),
6535 "%U/%U is deag in %d %U",
6536 format_mpls_unicast_label, deag_label,
6537 format_mpls_eos_bit, MPLS_EOS,
6539 format_dpo_id, &dpo, 0);
6540 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6541 "%U/%U is dst deag",
6542 format_mpls_unicast_label, deag_label,
6543 format_mpls_eos_bit, MPLS_EOS);
6544 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
6545 "%U/%U is lookup in interface's table",
6546 format_mpls_unicast_label, deag_label,
6547 format_mpls_eos_bit, MPLS_EOS);
6548 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
6549 "%U/%U is %U dst deag",
6550 format_mpls_unicast_label, deag_label,
6551 format_mpls_eos_bit, MPLS_EOS,
6552 format_dpo_proto, lkd->lkd_proto);
6556 * A route deag route for EOS
6558 fib_prefix_t pfx = {
6559 .fp_proto = FIB_PROTOCOL_MPLS,
6561 .fp_label = deag_label,
6562 .fp_payload_proto = DPO_PROTO_IP4,
6564 lfe = fib_table_entry_path_add(lfib_index,
6567 FIB_ENTRY_FLAG_NONE,
6574 FIB_ROUTE_PATH_FLAG_NONE);
6576 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6578 format_mpls_unicast_label, deag_label,
6579 format_mpls_eos_bit, MPLS_EOS);
6581 fib_entry_contribute_forwarding(lfe,
6582 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6584 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6585 lkd = lookup_dpo_get(dpo1->dpoi_index);
6587 FIB_TEST((fib_index == lkd->lkd_fib_index),
6588 "%U/%U is deag in %d %U",
6589 format_mpls_unicast_label, deag_label,
6590 format_mpls_eos_bit, MPLS_EOS,
6592 format_dpo_id, &dpo, 0);
6593 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6594 "%U/%U is dst deag",
6595 format_mpls_unicast_label, deag_label,
6596 format_mpls_eos_bit, MPLS_EOS);
6597 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
6598 "%U/%U is %U dst deag",
6599 format_mpls_unicast_label, deag_label,
6600 format_mpls_eos_bit, MPLS_EOS,
6601 format_dpo_proto, lkd->lkd_proto);
6603 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6605 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6607 "%U/%U not present",
6608 format_mpls_unicast_label, deag_label,
6609 format_mpls_eos_bit, MPLS_EOS);
6612 * A route deag route for non-EOS
6614 pfx.fp_eos = MPLS_NON_EOS;
6615 lfe = fib_table_entry_path_add(lfib_index,
6618 FIB_ENTRY_FLAG_NONE,
6625 FIB_ROUTE_PATH_FLAG_NONE);
6627 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6629 format_mpls_unicast_label, deag_label,
6630 format_mpls_eos_bit, MPLS_NON_EOS);
6632 fib_entry_contribute_forwarding(lfe,
6633 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6635 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6636 lkd = lookup_dpo_get(dpo1->dpoi_index);
6638 FIB_TEST((fib_index == lkd->lkd_fib_index),
6639 "%U/%U is deag in %d %U",
6640 format_mpls_unicast_label, deag_label,
6641 format_mpls_eos_bit, MPLS_NON_EOS,
6643 format_dpo_id, &dpo, 0);
6644 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6645 "%U/%U is dst deag",
6646 format_mpls_unicast_label, deag_label,
6647 format_mpls_eos_bit, MPLS_NON_EOS);
6649 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
6650 "%U/%U is %U dst deag",
6651 format_mpls_unicast_label, deag_label,
6652 format_mpls_eos_bit, MPLS_NON_EOS,
6653 format_dpo_proto, lkd->lkd_proto);
6655 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6657 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6659 "%U/%U not present",
6660 format_mpls_unicast_label, deag_label,
6661 format_mpls_eos_bit, MPLS_EOS);
6664 mpls_sw_interface_enable_disable(&mpls_main,
6665 tm->hw[0]->sw_if_index,
6670 * +1 for the drop LB in the MPLS tables.
6672 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6673 "Load-balance resources freed %d of %d",
6674 lb_count+1, pool_elts(load_balance_pool));
6677 static clib_error_t *
6678 lfib_test (vlib_main_t * vm,
6679 unformat_input_t * input,
6680 vlib_cli_command_t * cmd_arg)
6682 fib_test_mk_intf(4);
6689 static clib_error_t *
6690 fib_test (vlib_main_t * vm,
6691 unformat_input_t * input,
6692 vlib_cli_command_t * cmd_arg)
6694 fib_test_mk_intf(4);
6696 if (unformat (input, "ip"))
6701 else if (unformat (input, "gre"))
6705 else if (unformat (input, "label"))
6709 else if (unformat (input, "ae"))
6713 else if (unformat (input, "walk"))
6720 * These walk UT aren't run as part of the full suite, since the
6721 * fib-walk process must be disabled in order for the tests to work
6735 VLIB_CLI_COMMAND (test_fib_command, static) = {
6737 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6738 .function = fib_test,
6741 VLIB_CLI_COMMAND (test_lfib_command, static) = {
6742 .path = "test lfib",
6743 .short_help = "mpls label fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6744 .function = lfib_test,
6748 fib_test_init (vlib_main_t *vm)
6753 VLIB_INIT_FUNCTION (fib_test_init);