2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/fib/ip6_fib.h>
17 #include <vnet/fib/ip4_fib.h>
18 #include <vnet/fib/mpls_fib.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/dpo/load_balance_map.h>
22 #include <vnet/dpo/mpls_label_dpo.h>
23 #include <vnet/dpo/lookup_dpo.h>
24 #include <vnet/dpo/drop_dpo.h>
25 #include <vnet/dpo/receive_dpo.h>
27 #include <vnet/mpls/mpls.h>
29 #include <vnet/fib/fib_path_list.h>
30 #include <vnet/fib/fib_walk.h>
31 #include <vnet/fib/fib_node_list.h>
32 #include <vnet/fib/fib_urpf_list.h>
34 #define FIB_TEST_I(_cond, _comment, _args...) \
36 int _evald = (_cond); \
38 fformat(stderr, "FAIL:%d: " _comment "\n", \
41 fformat(stderr, "PASS:%d: " _comment "\n", \
46 #define FIB_TEST(_cond, _comment, _args...) \
48 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
50 ASSERT(!("FAIL: " _comment)); \
55 * A 'i'm not fussed is this is not efficient' store of test data
57 typedef struct test_main_t_ {
61 u32 hw_if_indicies[4];
65 vnet_hw_interface_t * hw[4];
68 static test_main_t test_main;
70 /* fake ethernet device class, distinct from "fake-ethX" */
71 static u8 * format_test_interface_name (u8 * s, va_list * args)
73 u32 dev_instance = va_arg (*args, u32);
74 return format (s, "test-eth%d", dev_instance);
77 static uword dummy_interface_tx (vlib_main_t * vm,
78 vlib_node_runtime_t * node,
81 clib_warning ("you shouldn't be here, leaking buffers...");
82 return frame->n_vectors;
85 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
86 .name = "Test interface",
87 .format_device_name = format_test_interface_name,
88 .tx_function = dummy_interface_tx,
91 static u8 *hw_address;
94 fib_test_mk_intf (u32 ninterfaces)
96 clib_error_t * error = NULL;
97 test_main_t *tm = &test_main;
101 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
106 vec_add1(hw_address, byte);
109 for (i = 0; i < ninterfaces; i++)
113 error = ethernet_register_interface(vnet_get_main(),
114 ethernet_hw_interface_class.index,
117 &tm->hw_if_indicies[i],
118 /* flag change */ 0);
120 FIB_TEST((NULL == error), "ADD interface %d", i);
122 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
123 tm->hw_if_indicies[i]);
124 vec_validate (ip4_main.fib_index_by_sw_if_index, tm->hw[i]->sw_if_index);
125 vec_validate (ip6_main.fib_index_by_sw_if_index, tm->hw[i]->sw_if_index);
126 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
127 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
128 error = vnet_sw_interface_set_flags(vnet_get_main(),
129 tm->hw[i]->sw_if_index,
130 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
131 FIB_TEST((NULL == error), "UP interface %d", i);
134 * re-eval after the inevitable realloc
136 for (i = 0; i < ninterfaces; i++)
138 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
139 tm->hw_if_indicies[i]);
143 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
145 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
146 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
147 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
148 fib_table_lookup(fib_index, (_via_prefix))); \
149 FIB_TEST(!dpo_cmp(_via_dpo, \
150 load_balance_get_bucket(_rec_dpo->dpoi_index, \
152 "%U is recursive via %U", \
153 format_fib_prefix, (_rec_prefix), \
154 format_fib_prefix, _via_prefix); \
157 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
159 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
160 fib_table_lookup_exact_match(fib_index, (_prefix))); \
161 const dpo_id_t *_dpo1 = \
162 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
163 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
164 format_dpo_type, _dpo1->dpoi_type); \
165 FIB_TEST((_ai == _dpo1->dpoi_index), \
166 "%U bucket %d resolves via %U", \
167 format_fib_prefix, (_prefix), \
169 format_dpo_id, _dpo1, 0); \
172 #define FIB_TEST_RPF(_cond, _comment, _args...) \
174 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
180 fib_test_urpf_is_equal (fib_node_index_t fei,
181 fib_forward_chain_type_t fct,
184 dpo_id_t dpo = DPO_NULL;
185 fib_urpf_list_t *urpf;
192 fib_entry_contribute_forwarding(fei, fct, &dpo);
193 ui = load_balance_get_urpf(dpo.dpoi_index);
195 urpf = fib_urpf_list_get(ui);
197 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
198 "RPF:%U len %d == %d",
199 format_fib_urpf_list, ui,
200 num, vec_len(urpf->furpf_itfs));
201 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
202 "RPF:%U check-size %d == %d",
203 format_fib_urpf_list, ui,
204 num, vec_len(urpf->furpf_itfs));
206 for (ii = 0; ii < num; ii++)
208 adj_index_t ai = va_arg(ap, adj_index_t);
210 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
211 "RPF:%d item:%d - %d == %d",
212 ui, ii, ai, urpf->furpf_itfs[ii]);
213 FIB_TEST_RPF(fib_urpf_check(ui, ai),
226 fib_test_build_rewrite (u8 *eth_addr)
230 vec_validate(rewrite, 13);
232 memcpy(rewrite, eth_addr, 6);
233 memcpy(rewrite+6, eth_addr, 6);
242 * In the default table check for the presence and correct forwarding
243 * of the special entries
245 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
246 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
247 const ip_adjacency_t *adj;
248 const load_balance_t *lb;
254 ip46_address_t nh_10_10_10_1 = {
255 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
258 ip46_address_t nh_10_10_10_2 = {
259 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
264 /* Find or create FIB table 11 */
265 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
267 for (ii = 0; ii < 4; ii++)
269 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
272 fib_prefix_t pfx_0_0_0_0_s_0 = {
274 .fp_proto = FIB_PROTOCOL_IP4,
284 .fp_proto = FIB_PROTOCOL_IP4,
292 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
294 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
295 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
296 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
297 "Default route is DROP");
300 fei = fib_table_lookup(fib_index, &pfx);
301 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
302 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
303 "all 0s route is DROP");
305 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
307 fei = fib_table_lookup(fib_index, &pfx);
308 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
309 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
310 "all 1s route is DROP");
312 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
314 fei = fib_table_lookup(fib_index, &pfx);
315 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
316 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
317 "all-mcast route is DROP");
319 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
321 fei = fib_table_lookup(fib_index, &pfx);
322 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
323 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
324 "class-e route is DROP");
327 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
328 * all of which are special sourced and so none of which share path-lists.
329 * There are also 6 entries, and 6 non-shared path-lists, in the v6 default
333 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
334 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
335 fib_path_list_pool_size());
336 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
337 fib_entry_pool_size());
340 * add interface routes.
341 * validate presence of /24 attached and /32 recieve.
342 * test for the presence of the receive address in the glean and local adj
344 fib_prefix_t local_pfx = {
346 .fp_proto = FIB_PROTOCOL_IP4,
349 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
354 fib_table_entry_update_one_path(fib_index, &local_pfx,
355 FIB_SOURCE_INTERFACE,
356 (FIB_ENTRY_FLAG_CONNECTED |
357 FIB_ENTRY_FLAG_ATTACHED),
360 tm->hw[0]->sw_if_index,
361 ~0, // invalid fib index
364 FIB_ROUTE_PATH_FLAG_NONE);
365 fei = fib_table_lookup(fib_index, &local_pfx);
366 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
367 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
368 fib_entry_get_flags(fei)),
369 "Flags set on attached interface");
371 ai = fib_entry_get_adj(fei);
372 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
374 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
375 "attached interface adj is glean");
376 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
377 &adj->sub_type.glean.receive_addr)),
378 "attached interface adj is receive ok");
380 local_pfx.fp_len = 32;
381 fib_table_entry_update_one_path(fib_index, &local_pfx,
382 FIB_SOURCE_INTERFACE,
383 (FIB_ENTRY_FLAG_CONNECTED |
384 FIB_ENTRY_FLAG_LOCAL),
387 tm->hw[0]->sw_if_index,
388 ~0, // invalid fib index
391 FIB_ROUTE_PATH_FLAG_NONE);
392 fei = fib_table_lookup(fib_index, &local_pfx);
393 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
394 fib_entry_get_flags(fei)),
395 "Flags set on local interface");
397 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
399 dpo = fib_entry_contribute_ip_forwarding(fei);
400 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
401 "RPF list for local length 0");
402 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
403 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
404 "local interface adj is local");
405 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
407 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
409 "local interface adj is receive ok");
411 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
413 FIB_SOURCE_INTERFACE)),
414 "2 Interface Source'd prefixes");
417 * +2 interface routes +2 non-shared path-lists
419 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
420 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
421 fib_path_list_pool_size());
422 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
423 fib_entry_pool_size());
426 * Modify the default route to be via an adj not yet known.
427 * this sources the defalut route with the API source, which is
428 * a higher preference to the DEFAULT_ROUTE source
430 pfx.fp_addr.ip4.as_u32 = 0;
432 fib_table_entry_path_add(fib_index, &pfx,
437 tm->hw[0]->sw_if_index,
438 ~0, // invalid fib index
441 FIB_ROUTE_PATH_FLAG_NONE);
442 fei = fib_table_lookup(fib_index, &pfx);
443 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
444 "Flags set on API route");
446 FIB_TEST((fei == dfrt), "default route same index");
447 ai = fib_entry_get_adj(fei);
448 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
450 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
451 "adj is incomplete");
452 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
453 "adj nbr next-hop ok");
454 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
457 "1 API Source'd prefixes");
460 * find the adj in the shared db
462 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
465 tm->hw[0]->sw_if_index);
466 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
467 adj_unlock(locked_ai);
470 * +1 shared path-list
472 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
473 fib_path_list_db_size());
474 FIB_TEST((NBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
475 fib_path_list_pool_size());
476 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
477 fib_entry_pool_size());
480 * remove the API source from the default route. We expected
481 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
483 pfx.fp_addr.ip4.as_u32 = 0;
485 fib_table_entry_path_remove(fib_index, &pfx,
489 tm->hw[0]->sw_if_index,
490 ~0, // non-recursive path, so no FIB index
492 FIB_ROUTE_PATH_FLAG_NONE);
494 fei = fib_table_lookup(fib_index, &pfx);
496 FIB_TEST((fei == dfrt), "default route same index");
497 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
498 "Default route is DROP");
501 * -1 shared-path-list
503 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
504 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
505 fib_path_list_pool_size());
506 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
507 fib_entry_pool_size());
510 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
512 fib_prefix_t pfx_10_10_10_1_s_32 = {
514 .fp_proto = FIB_PROTOCOL_IP4,
517 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
520 fib_prefix_t pfx_10_10_10_2_s_32 = {
522 .fp_proto = FIB_PROTOCOL_IP4,
525 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
528 fib_prefix_t pfx_11_11_11_11_s_32 = {
530 .fp_proto = FIB_PROTOCOL_IP4,
533 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
537 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
540 ip46_address_t nh_12_12_12_12 = {
541 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
543 adj_index_t ai_12_12_12_12;
546 * Add a route via an incomplete ADJ. then complete the ADJ
547 * Expect the route LB is updated to use complete adj type.
549 fei = fib_table_entry_update_one_path(fib_index,
550 &pfx_11_11_11_11_s_32,
552 FIB_ENTRY_FLAG_ATTACHED,
554 &pfx_10_10_10_1_s_32.fp_addr,
555 tm->hw[0]->sw_if_index,
556 ~0, // invalid fib index
559 FIB_ROUTE_PATH_FLAG_NONE);
561 dpo = fib_entry_contribute_ip_forwarding(fei);
562 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
563 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
564 "11.11.11.11/32 via incomplete adj");
566 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
568 &pfx_10_10_10_1_s_32.fp_addr,
569 tm->hw[0]->sw_if_index);
570 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
571 adj = adj_get(ai_01);
572 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
573 "adj is incomplete");
574 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
575 &adj->sub_type.nbr.next_hop)),
576 "adj nbr next-hop ok");
578 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
579 fib_test_build_rewrite(eth_addr));
580 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
582 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
583 &adj->sub_type.nbr.next_hop)),
584 "adj nbr next-hop ok");
585 ai = fib_entry_get_adj(fei);
586 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
588 dpo = fib_entry_contribute_ip_forwarding(fei);
589 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
590 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
591 "11.11.11.11/32 via complete adj");
592 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
593 tm->hw[0]->sw_if_index),
594 "RPF list for adj-fib contains adj");
596 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
599 tm->hw[1]->sw_if_index);
600 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
601 adj = adj_get(ai_12_12_12_12);
602 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
603 "adj is incomplete");
604 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
605 &adj->sub_type.nbr.next_hop)),
606 "adj nbr next-hop ok");
607 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
608 fib_test_build_rewrite(eth_addr));
609 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
615 fei = fib_table_entry_update_one_path(fib_index,
616 &pfx_10_10_10_1_s_32,
618 FIB_ENTRY_FLAG_ATTACHED,
620 &pfx_10_10_10_1_s_32.fp_addr,
621 tm->hw[0]->sw_if_index,
622 ~0, // invalid fib index
625 FIB_ROUTE_PATH_FLAG_NONE);
626 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
627 "Flags set on adj-fib");
628 ai = fib_entry_get_adj(fei);
629 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
631 fib_table_entry_path_remove(fib_index,
632 &pfx_11_11_11_11_s_32,
635 &pfx_10_10_10_1_s_32.fp_addr,
636 tm->hw[0]->sw_if_index,
637 ~0, // invalid fib index
639 FIB_ROUTE_PATH_FLAG_NONE);
643 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
645 &pfx_10_10_10_2_s_32.fp_addr,
646 tm->hw[0]->sw_if_index);
647 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
648 adj = adj_get(ai_02);
649 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
650 "adj is incomplete");
651 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
652 &adj->sub_type.nbr.next_hop)),
653 "adj nbr next-hop ok");
655 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
656 fib_test_build_rewrite(eth_addr));
657 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
659 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
660 &adj->sub_type.nbr.next_hop)),
661 "adj nbr next-hop ok");
662 FIB_TEST((ai_01 != ai_02), "ADJs are different");
664 fib_table_entry_update_one_path(fib_index,
665 &pfx_10_10_10_2_s_32,
669 &pfx_10_10_10_2_s_32.fp_addr,
670 tm->hw[0]->sw_if_index,
671 ~0, // invalid fib index
674 FIB_ROUTE_PATH_FLAG_NONE);
676 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
677 ai = fib_entry_get_adj(fei);
678 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
681 * +2 adj-fibs, and their non-shared path-lists
683 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
684 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
685 fib_path_list_pool_size());
686 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
687 fib_entry_pool_size());
690 * Add 2 routes via the first ADJ. ensure path-list sharing
692 fib_prefix_t pfx_1_1_1_1_s_32 = {
694 .fp_proto = FIB_PROTOCOL_IP4,
697 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
701 fib_table_entry_path_add(fib_index,
707 tm->hw[0]->sw_if_index,
708 ~0, // invalid fib index
711 FIB_ROUTE_PATH_FLAG_NONE);
712 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
713 ai = fib_entry_get_adj(fei);
714 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
717 * +1 entry and a shared path-list
719 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
720 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
721 fib_path_list_pool_size());
722 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
723 fib_entry_pool_size());
726 fib_prefix_t pfx_1_1_2_0_s_24 = {
728 .fp_proto = FIB_PROTOCOL_IP4,
730 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
734 fib_table_entry_path_add(fib_index,
740 tm->hw[0]->sw_if_index,
741 ~0, // invalid fib index
744 FIB_ROUTE_PATH_FLAG_NONE);
745 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
746 ai = fib_entry_get_adj(fei);
747 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
752 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
753 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
754 fib_path_list_pool_size());
755 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
756 fib_entry_pool_size());
759 * modify 1.1.2.0/24 to use multipath.
761 fib_table_entry_path_add(fib_index,
767 tm->hw[0]->sw_if_index,
768 ~0, // invalid fib index
771 FIB_ROUTE_PATH_FLAG_NONE);
772 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
773 dpo = fib_entry_contribute_ip_forwarding(fei);
774 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
775 1, tm->hw[0]->sw_if_index),
776 "RPF list for 1.1.2.0/24 contains both adjs");
778 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
779 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
780 FIB_TEST((ai_01 == dpo1->dpoi_index),
781 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
782 ai_01, dpo1->dpoi_index);
784 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
785 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
786 FIB_TEST((ai_02 == dpo1->dpoi_index),
787 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
792 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
793 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
794 fib_path_list_pool_size());
795 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
796 fib_entry_pool_size());
801 fib_table_entry_path_remove(fib_index,
806 tm->hw[0]->sw_if_index,
809 FIB_ROUTE_PATH_FLAG_NONE);
810 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
811 dpo = fib_entry_contribute_ip_forwarding(fei);
812 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
813 1, tm->hw[0]->sw_if_index),
814 "RPF list for 1.1.2.0/24 contains one adj");
816 ai = fib_entry_get_adj(fei);
817 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
822 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
823 fib_path_list_db_size());
824 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
825 fib_path_list_pool_size());
826 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
827 fib_entry_pool_size());
830 * Add 2 recursive routes:
831 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
832 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
834 fib_prefix_t bgp_100_pfx = {
836 .fp_proto = FIB_PROTOCOL_IP4,
838 /* 100.100.100.100/32 */
839 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
843 ip46_address_t nh_1_1_1_1 = {
844 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
847 fei = fib_table_entry_path_add(fib_index,
853 ~0, // no index provided.
854 fib_index, // nexthop in same fib as route
857 FIB_ROUTE_PATH_FLAG_NONE);
859 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
860 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
861 tm->hw[0]->sw_if_index),
862 "RPF list for adj-fib contains adj");
865 * +1 entry and +1 shared-path-list
867 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
868 fib_path_list_db_size());
869 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
870 fib_path_list_pool_size());
871 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
872 fib_entry_pool_size());
874 fib_prefix_t bgp_101_pfx = {
876 .fp_proto = FIB_PROTOCOL_IP4,
878 /* 100.100.100.101/32 */
879 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
883 fib_table_entry_path_add(fib_index,
889 ~0, // no index provided.
890 fib_index, // nexthop in same fib as route
893 FIB_ROUTE_PATH_FLAG_NONE);
895 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
896 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
897 tm->hw[0]->sw_if_index),
898 "RPF list for adj-fib contains adj");
901 * +1 entry, but the recursive path-list is shared.
903 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
904 fib_path_list_db_size());
905 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
906 fib_path_list_pool_size());
907 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
908 fib_entry_pool_size());
911 * An EXCLUSIVE route; one where the user (me) provides the exclusive
912 * adjacency through which the route will resovle
914 fib_prefix_t ex_pfx = {
916 .fp_proto = FIB_PROTOCOL_IP4,
919 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
923 fib_table_entry_special_add(fib_index,
926 FIB_ENTRY_FLAG_EXCLUSIVE,
928 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
929 FIB_TEST((ai == fib_entry_get_adj(fei)),
930 "Exclusive route links to user adj");
932 fib_table_entry_special_remove(fib_index,
935 FIB_TEST(FIB_NODE_INDEX_INVALID ==
936 fib_table_lookup_exact_match(fib_index, &ex_pfx),
937 "Exclusive reoute removed");
940 * An EXCLUSIVE route; one where the user (me) provides the exclusive
941 * adjacency through which the route will resovle
943 dpo_id_t ex_dpo = DPO_NULL;
945 lookup_dpo_add_or_lock_w_fib_index(fib_index,
947 LOOKUP_INPUT_DST_ADDR,
948 LOOKUP_TABLE_FROM_CONFIG,
951 fib_table_entry_special_dpo_add(fib_index,
954 FIB_ENTRY_FLAG_EXCLUSIVE,
956 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
957 dpo = fib_entry_contribute_ip_forwarding(fei);
958 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
959 "exclusive remote uses lookup DPO");
961 fib_table_entry_special_remove(fib_index,
964 FIB_TEST(FIB_NODE_INDEX_INVALID ==
965 fib_table_lookup_exact_match(fib_index, &ex_pfx),
966 "Exclusive reoute removed");
970 * Add a recursive route:
971 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
973 fib_prefix_t bgp_200_pfx = {
975 .fp_proto = FIB_PROTOCOL_IP4,
977 /* 200.200.200.200/32 */
978 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
982 fib_prefix_t pfx_1_1_1_2_s_32 = {
984 .fp_proto = FIB_PROTOCOL_IP4,
986 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
990 fib_table_entry_path_add(fib_index,
995 &pfx_1_1_1_2_s_32.fp_addr,
996 ~0, // no index provided.
997 fib_index, // nexthop in same fib as route
1000 FIB_ROUTE_PATH_FLAG_NONE);
1002 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1005 * the adj should be recursive via drop, since the route resolves via
1006 * the default route, which is itself a DROP
1008 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1009 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1010 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1011 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1012 "RPF list for 1.1.1.2/32 contains 0 adjs");
1015 * +2 entry and +1 shared-path-list
1017 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1018 fib_path_list_db_size());
1019 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1020 fib_path_list_pool_size());
1021 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1022 fib_entry_pool_size());
1025 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1026 * The paths are sort by NH first. in this case the the path with greater
1027 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1029 fib_prefix_t pfx_1_2_3_4_s_32 = {
1031 .fp_proto = FIB_PROTOCOL_IP4,
1033 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1036 fib_table_entry_path_add(fib_index,
1039 FIB_ENTRY_FLAG_NONE,
1042 tm->hw[0]->sw_if_index,
1046 FIB_ROUTE_PATH_FLAG_NONE);
1047 fei = fib_table_entry_path_add(fib_index,
1050 FIB_ENTRY_FLAG_NONE,
1053 tm->hw[1]->sw_if_index,
1057 FIB_ROUTE_PATH_FLAG_NONE);
1059 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1060 dpo = fib_entry_contribute_ip_forwarding(fei);
1061 lb = load_balance_get(dpo->dpoi_index);
1062 FIB_TEST((lb->lb_n_buckets == 4),
1063 "1.2.3.4/32 LB has %d bucket",
1066 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1067 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1068 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1069 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1071 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1072 tm->hw[0]->sw_if_index,
1073 tm->hw[1]->sw_if_index),
1074 "RPF list for 1.2.3.4/32 contains both adjs");
1078 * Unequal Cost load-balance. 4:1 ratio.
1079 * fits in a 16 bucket LB with ratio 13:3
1081 fib_prefix_t pfx_1_2_3_5_s_32 = {
1083 .fp_proto = FIB_PROTOCOL_IP4,
1085 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1088 fib_table_entry_path_add(fib_index,
1091 FIB_ENTRY_FLAG_NONE,
1094 tm->hw[1]->sw_if_index,
1098 FIB_ROUTE_PATH_FLAG_NONE);
1099 fei = fib_table_entry_path_add(fib_index,
1102 FIB_ENTRY_FLAG_NONE,
1105 tm->hw[0]->sw_if_index,
1109 FIB_ROUTE_PATH_FLAG_NONE);
1111 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1112 dpo = fib_entry_contribute_ip_forwarding(fei);
1113 lb = load_balance_get(dpo->dpoi_index);
1114 FIB_TEST((lb->lb_n_buckets == 16),
1115 "1.2.3.5/32 LB has %d bucket",
1118 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1119 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1120 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1121 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1122 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1123 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1124 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1125 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1126 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1127 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1128 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1129 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1130 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1131 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1132 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1133 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1135 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1136 tm->hw[0]->sw_if_index,
1137 tm->hw[1]->sw_if_index),
1138 "RPF list for 1.2.3.4/32 contains both adjs");
1141 * A recursive via the two unequal cost entries
1143 fib_prefix_t bgp_44_s_32 = {
1145 .fp_proto = FIB_PROTOCOL_IP4,
1147 /* 200.200.200.201/32 */
1148 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1151 fei = fib_table_entry_path_add(fib_index,
1154 FIB_ENTRY_FLAG_NONE,
1156 &pfx_1_2_3_4_s_32.fp_addr,
1161 FIB_ROUTE_PATH_FLAG_NONE);
1162 fei = fib_table_entry_path_add(fib_index,
1165 FIB_ENTRY_FLAG_NONE,
1167 &pfx_1_2_3_5_s_32.fp_addr,
1172 FIB_ROUTE_PATH_FLAG_NONE);
1174 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1175 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1176 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1177 tm->hw[0]->sw_if_index,
1178 tm->hw[1]->sw_if_index),
1179 "RPF list for 1.2.3.4/32 contains both adjs");
1182 * test the uRPF check functions
1184 dpo_id_t dpo_44 = DPO_NULL;
1187 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1188 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
1190 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
1191 "uRPF check for 68.68.68.68/32 on %d OK",
1192 tm->hw[0]->sw_if_index);
1193 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
1194 "uRPF check for 68.68.68.68/32 on %d OK",
1195 tm->hw[1]->sw_if_index);
1196 FIB_TEST(!fib_urpf_check(urpfi, 99),
1197 "uRPF check for 68.68.68.68/32 on 99 not-OK",
1201 fib_table_entry_delete(fib_index,
1204 fib_table_entry_delete(fib_index,
1207 fib_table_entry_delete(fib_index,
1212 * Add a recursive route:
1213 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
1215 fib_prefix_t bgp_201_pfx = {
1217 .fp_proto = FIB_PROTOCOL_IP4,
1219 /* 200.200.200.201/32 */
1220 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1224 fib_prefix_t pfx_1_1_1_200_s_32 = {
1226 .fp_proto = FIB_PROTOCOL_IP4,
1228 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1232 fib_table_entry_path_add(fib_index,
1235 FIB_ENTRY_FLAG_NONE,
1237 &pfx_1_1_1_200_s_32.fp_addr,
1238 ~0, // no index provided.
1239 fib_index, // nexthop in same fib as route
1242 FIB_ROUTE_PATH_FLAG_NONE);
1244 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1246 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1247 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1248 "Flags set on RR via non-attached");
1249 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1250 "RPF list for BGP route empty");
1253 * +2 entry (BGP & RR) and +1 shared-path-list
1255 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1256 fib_path_list_db_size());
1257 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1258 fib_path_list_pool_size());
1259 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1260 fib_entry_pool_size());
1263 * insert a route that covers the missing 1.1.1.2/32. we epxect
1264 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
1266 fib_prefix_t pfx_1_1_1_0_s_24 = {
1268 .fp_proto = FIB_PROTOCOL_IP4,
1271 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1275 fib_table_entry_path_add(fib_index,
1278 FIB_ENTRY_FLAG_NONE,
1281 tm->hw[0]->sw_if_index,
1282 ~0, // invalid fib index
1285 FIB_ROUTE_PATH_FLAG_NONE);
1286 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
1287 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1288 ai = fib_entry_get_adj(fei);
1289 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
1290 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1291 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1292 ai = fib_entry_get_adj(fei);
1293 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
1294 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1295 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1296 ai = fib_entry_get_adj(fei);
1297 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
1300 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
1302 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1303 fib_path_list_db_size());
1304 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1305 fib_path_list_pool_size());
1306 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1307 fib_entry_pool_size());
1310 * the recursive adj for 200.200.200.200 should be updated.
1312 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1313 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1314 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
1315 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1316 tm->hw[0]->sw_if_index),
1317 "RPF list for BGP route has itf index 0");
1320 * insert a more specific route than 1.1.1.0/24 that also covers the
1321 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
1322 * 200.200.200.200 to resolve through it.
1324 fib_prefix_t pfx_1_1_1_0_s_28 = {
1326 .fp_proto = FIB_PROTOCOL_IP4,
1329 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1333 fib_table_entry_path_add(fib_index,
1336 FIB_ENTRY_FLAG_NONE,
1339 tm->hw[0]->sw_if_index,
1340 ~0, // invalid fib index
1343 FIB_ROUTE_PATH_FLAG_NONE);
1344 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
1345 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1346 ai = fib_entry_get_adj(fei);
1347 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
1350 * +1 entry. +1 shared path-list
1352 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
1353 fib_path_list_db_size());
1354 FIB_TEST((NBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
1355 fib_path_list_pool_size());
1356 FIB_TEST((NBR+14 == fib_entry_pool_size()), "entry pool size is %d",
1357 fib_entry_pool_size());
1360 * the recursive adj for 200.200.200.200 should be updated.
1361 * 200.200.200.201 remains unchanged.
1363 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1364 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1367 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
1369 fib_table_entry_path_remove(fib_index,
1374 tm->hw[0]->sw_if_index,
1377 FIB_ROUTE_PATH_FLAG_NONE);
1378 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
1379 FIB_NODE_INDEX_INVALID),
1380 "1.1.1.0/28 removed");
1381 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
1382 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
1383 "1.1.1.0/28 lookup via /24");
1384 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1385 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1388 * -1 entry. -1 shared path-list
1390 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1391 fib_path_list_db_size());
1392 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1393 fib_path_list_pool_size());
1394 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1395 fib_entry_pool_size());
1398 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
1400 fib_table_entry_path_remove(fib_index,
1405 tm->hw[0]->sw_if_index,
1408 FIB_ROUTE_PATH_FLAG_NONE);
1409 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
1410 FIB_NODE_INDEX_INVALID),
1411 "1.1.1.0/24 removed");
1413 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1414 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1415 "1.1.1.2/32 route is DROP");
1416 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1417 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1418 "1.1.1.200/32 route is DROP");
1420 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1421 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1426 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1427 fib_path_list_db_size());
1428 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1429 fib_path_list_pool_size());
1430 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1431 fib_entry_pool_size());
1434 * insert the missing 1.1.1.2/32
1436 fei = fib_table_entry_path_add(fib_index,
1439 FIB_ENTRY_FLAG_NONE,
1442 tm->hw[0]->sw_if_index,
1443 ~0, // invalid fib index
1446 FIB_ROUTE_PATH_FLAG_NONE);
1447 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1448 ai = fib_entry_get_adj(fei);
1449 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
1451 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1452 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1455 * no change. 1.1.1.2/32 was already there RR sourced.
1457 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1458 fib_path_list_db_size());
1459 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1460 fib_path_list_pool_size());
1461 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1462 fib_entry_pool_size());
1465 * remove 200.200.200.201/32 which does not have a valid via FIB
1467 fib_table_entry_path_remove(fib_index,
1471 &pfx_1_1_1_200_s_32.fp_addr,
1472 ~0, // no index provided.
1475 FIB_ROUTE_PATH_FLAG_NONE);
1478 * -2 entries (BGP and RR). -1 shared path-list;
1480 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1481 FIB_NODE_INDEX_INVALID),
1482 "200.200.200.201/32 removed");
1483 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
1484 FIB_NODE_INDEX_INVALID),
1485 "1.1.1.200/32 removed");
1487 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1488 fib_path_list_db_size());
1489 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1490 fib_path_list_pool_size());
1491 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1492 fib_entry_pool_size());
1495 * remove 200.200.200.200/32 which does have a valid via FIB
1497 fib_table_entry_path_remove(fib_index,
1501 &pfx_1_1_1_2_s_32.fp_addr,
1502 ~0, // no index provided.
1505 FIB_ROUTE_PATH_FLAG_NONE);
1507 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1508 FIB_NODE_INDEX_INVALID),
1509 "200.200.200.200/32 removed");
1510 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
1511 FIB_NODE_INDEX_INVALID),
1512 "1.1.1.2/32 still present");
1515 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
1517 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1518 fib_path_list_db_size());
1519 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1520 fib_path_list_pool_size());
1521 FIB_TEST((NBR+9 == fib_entry_pool_size()), "entry pool size is %d",
1522 fib_entry_pool_size());
1525 * A recursive prefix that has a 2 path load-balance.
1526 * It also shares a next-hop with other BGP prefixes and hence
1527 * test the ref counting of RR sourced prefixes and 2 level LB.
1529 const fib_prefix_t bgp_102 = {
1531 .fp_proto = FIB_PROTOCOL_IP4,
1533 /* 100.100.100.101/32 */
1534 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
1537 fib_table_entry_path_add(fib_index,
1540 FIB_ENTRY_FLAG_NONE,
1542 &pfx_1_1_1_1_s_32.fp_addr,
1543 ~0, // no index provided.
1544 fib_index, // same as route
1547 FIB_ROUTE_PATH_FLAG_NONE);
1548 fib_table_entry_path_add(fib_index,
1551 FIB_ENTRY_FLAG_NONE,
1553 &pfx_1_1_1_2_s_32.fp_addr,
1554 ~0, // no index provided.
1555 fib_index, // same as route's FIB
1558 FIB_ROUTE_PATH_FLAG_NONE);
1559 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1560 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
1561 dpo = fib_entry_contribute_ip_forwarding(fei);
1563 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
1564 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1565 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
1566 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1568 lb = load_balance_get(dpo->dpoi_index);
1569 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
1570 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1571 "First via 10.10.10.1");
1572 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
1573 "Second via 10.10.10.1");
1575 fib_table_entry_path_remove(fib_index,
1579 &pfx_1_1_1_1_s_32.fp_addr,
1580 ~0, // no index provided.
1581 fib_index, // same as route's FIB
1583 FIB_ROUTE_PATH_FLAG_NONE);
1584 fib_table_entry_path_remove(fib_index,
1588 &pfx_1_1_1_2_s_32.fp_addr,
1589 ~0, // no index provided.
1590 fib_index, // same as route's FIB
1592 FIB_ROUTE_PATH_FLAG_NONE);
1593 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1594 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
1597 * remove the remaining recursives
1599 fib_table_entry_path_remove(fib_index,
1603 &pfx_1_1_1_1_s_32.fp_addr,
1604 ~0, // no index provided.
1605 fib_index, // same as route's FIB
1607 FIB_ROUTE_PATH_FLAG_NONE);
1608 fib_table_entry_path_remove(fib_index,
1612 &pfx_1_1_1_1_s_32.fp_addr,
1613 ~0, // no index provided.
1614 fib_index, // same as route's FIB
1616 FIB_ROUTE_PATH_FLAG_NONE);
1617 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
1618 FIB_NODE_INDEX_INVALID),
1619 "100.100.100.100/32 removed");
1620 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
1621 FIB_NODE_INDEX_INVALID),
1622 "100.100.100.101/32 removed");
1625 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
1627 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1628 fib_path_list_db_size());
1629 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1630 fib_path_list_pool_size());
1631 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1632 fib_entry_pool_size());
1635 * Add a recursive route via a connected cover, using an adj-fib that does exist
1637 fib_table_entry_path_add(fib_index,
1640 FIB_ENTRY_FLAG_NONE,
1643 ~0, // no index provided.
1644 fib_index, // Same as route's FIB
1647 FIB_ROUTE_PATH_FLAG_NONE);
1650 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
1652 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1653 fib_path_list_db_size());
1654 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1655 fib_path_list_pool_size());
1656 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1657 fib_entry_pool_size());
1659 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
1660 dpo = fib_entry_contribute_ip_forwarding(fei);
1662 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
1663 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1665 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1666 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
1668 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1669 "Flags set on RR via existing attached");
1672 * Add a recursive route via a connected cover, using and adj-fib that does
1675 ip46_address_t nh_10_10_10_3 = {
1676 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
1678 fib_prefix_t pfx_10_10_10_3 = {
1680 .fp_proto = FIB_PROTOCOL_IP4,
1681 .fp_addr = nh_10_10_10_3,
1684 fib_table_entry_path_add(fib_index,
1687 FIB_ENTRY_FLAG_NONE,
1690 ~0, // no index provided.
1694 FIB_ROUTE_PATH_FLAG_NONE);
1697 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
1698 * one unshared non-recursive via 10.10.10.3
1700 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1701 fib_path_list_db_size());
1702 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1703 fib_path_list_pool_size());
1704 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1705 fib_entry_pool_size());
1707 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1710 tm->hw[0]->sw_if_index);
1712 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
1713 dpo = fib_entry_contribute_ip_forwarding(fei);
1714 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
1715 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1717 ai = fib_entry_get_adj(fei);
1718 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
1719 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
1720 fib_entry_get_flags(fei)),
1721 "Flags set on RR via non-existing attached");
1723 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1724 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
1729 * remove the recursives
1731 fib_table_entry_path_remove(fib_index,
1736 ~0, // no index provided.
1737 fib_index, // same as route's FIB
1739 FIB_ROUTE_PATH_FLAG_NONE);
1740 fib_table_entry_path_remove(fib_index,
1745 ~0, // no index provided.
1746 fib_index, // same as route's FIB
1748 FIB_ROUTE_PATH_FLAG_NONE);
1750 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1751 FIB_NODE_INDEX_INVALID),
1752 "200.200.200.201/32 removed");
1753 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1754 FIB_NODE_INDEX_INVALID),
1755 "200.200.200.200/32 removed");
1756 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
1757 FIB_NODE_INDEX_INVALID),
1758 "10.10.10.3/32 removed");
1761 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
1762 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
1764 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1765 fib_path_list_db_size());
1766 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1767 fib_path_list_pool_size());
1768 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1769 fib_entry_pool_size());
1774 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
1776 fib_prefix_t pfx_5_5_5_5_s_32 = {
1778 .fp_proto = FIB_PROTOCOL_IP4,
1780 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
1783 fib_prefix_t pfx_5_5_5_6_s_32 = {
1785 .fp_proto = FIB_PROTOCOL_IP4,
1787 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
1790 fib_prefix_t pfx_5_5_5_7_s_32 = {
1792 .fp_proto = FIB_PROTOCOL_IP4,
1794 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
1798 fib_table_entry_path_add(fib_index,
1801 FIB_ENTRY_FLAG_NONE,
1803 &pfx_5_5_5_6_s_32.fp_addr,
1804 ~0, // no index provided.
1808 FIB_ROUTE_PATH_FLAG_NONE);
1809 fib_table_entry_path_add(fib_index,
1812 FIB_ENTRY_FLAG_NONE,
1814 &pfx_5_5_5_7_s_32.fp_addr,
1815 ~0, // no index provided.
1819 FIB_ROUTE_PATH_FLAG_NONE);
1820 fib_table_entry_path_add(fib_index,
1823 FIB_ENTRY_FLAG_NONE,
1825 &pfx_5_5_5_5_s_32.fp_addr,
1826 ~0, // no index provided.
1830 FIB_ROUTE_PATH_FLAG_NONE);
1832 * +3 entries, +3 shared path-list
1834 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1835 fib_path_list_db_size());
1836 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1837 fib_path_list_pool_size());
1838 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1839 fib_entry_pool_size());
1842 * All the entries have only looped paths, so they are all drop
1844 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1845 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1846 "LB for 5.5.5.7/32 is via adj for DROP");
1847 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1848 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1849 "LB for 5.5.5.5/32 is via adj for DROP");
1850 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1851 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1852 "LB for 5.5.5.6/32 is via adj for DROP");
1855 * provide 5.5.5.6/32 with alternate path.
1856 * this will allow only 5.5.5.6/32 to forward with this path, the others
1857 * are still drop since the loop is still present.
1859 fib_table_entry_path_add(fib_index,
1862 FIB_ENTRY_FLAG_NONE,
1865 tm->hw[0]->sw_if_index,
1869 FIB_ROUTE_PATH_FLAG_NONE);
1872 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1873 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1875 lb = load_balance_get(dpo1->dpoi_index);
1876 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
1878 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1879 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1880 FIB_TEST((ai_01 == dpo2->dpoi_index),
1881 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
1883 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1884 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1885 "LB for 5.5.5.7/32 is via adj for DROP");
1886 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1887 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1888 "LB for 5.5.5.5/32 is via adj for DROP");
1891 * remove the alternate path for 5.5.5.6/32
1894 fib_table_entry_path_remove(fib_index,
1899 tm->hw[0]->sw_if_index,
1902 FIB_ROUTE_PATH_FLAG_NONE);
1904 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1905 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1906 "LB for 5.5.5.7/32 is via adj for DROP");
1907 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1908 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1909 "LB for 5.5.5.5/32 is via adj for DROP");
1910 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1911 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1912 "LB for 5.5.5.6/32 is via adj for DROP");
1915 * break the loop by giving 5.5.5.5/32 a new set of paths
1916 * expect all to forward via this new path.
1918 fib_table_entry_update_one_path(fib_index,
1921 FIB_ENTRY_FLAG_NONE,
1924 tm->hw[0]->sw_if_index,
1925 ~0, // invalid fib index
1928 FIB_ROUTE_PATH_FLAG_NONE);
1930 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1931 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1932 lb = load_balance_get(dpo1->dpoi_index);
1933 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
1935 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1936 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1937 FIB_TEST((ai_01 == dpo2->dpoi_index),
1938 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
1940 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
1941 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1943 lb = load_balance_get(dpo2->dpoi_index);
1944 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1945 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
1946 "5.5.5.5.7 via 5.5.5.5");
1948 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
1949 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1951 lb = load_balance_get(dpo1->dpoi_index);
1952 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1953 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
1954 "5.5.5.5.6 via 5.5.5.7");
1957 * revert back to the loop. so we can remove the prefixes with
1960 fib_table_entry_update_one_path(fib_index,
1963 FIB_ENTRY_FLAG_NONE,
1965 &pfx_5_5_5_6_s_32.fp_addr,
1966 ~0, // no index provided.
1970 FIB_ROUTE_PATH_FLAG_NONE);
1972 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1973 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1974 "LB for 5.5.5.7/32 is via adj for DROP");
1975 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1976 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1977 "LB for 5.5.5.5/32 is via adj for DROP");
1978 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1979 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1980 "LB for 5.5.5.6/32 is via adj for DROP");
1983 * remove all the 5.5.5.x/32 prefixes
1985 fib_table_entry_path_remove(fib_index,
1989 &pfx_5_5_5_6_s_32.fp_addr,
1990 ~0, // no index provided.
1991 fib_index, // same as route's FIB
1993 FIB_ROUTE_PATH_FLAG_NONE);
1994 fib_table_entry_path_remove(fib_index,
1998 &pfx_5_5_5_7_s_32.fp_addr,
1999 ~0, // no index provided.
2000 fib_index, // same as route's FIB
2002 FIB_ROUTE_PATH_FLAG_NONE);
2003 fib_table_entry_path_remove(fib_index,
2007 &pfx_5_5_5_5_s_32.fp_addr,
2008 ~0, // no index provided.
2009 fib_index, // same as route's FIB
2011 FIB_ROUTE_PATH_FLAG_NONE);
2012 fib_table_entry_path_remove(fib_index,
2017 ~0, // no index provided.
2018 fib_index, // same as route's FIB
2020 FIB_ROUTE_PATH_FLAG_NONE);
2023 * -3 entries, -3 shared path-list
2025 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2026 fib_path_list_db_size());
2027 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2028 fib_path_list_pool_size());
2029 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2030 fib_entry_pool_size());
2033 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2035 fib_table_entry_path_add(fib_index,
2038 FIB_ENTRY_FLAG_NONE,
2040 &pfx_5_5_5_6_s_32.fp_addr,
2041 ~0, // no index provided.
2045 FIB_ROUTE_PATH_FLAG_NONE);
2046 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2047 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2048 "1-level 5.5.5.6/32 loop is via adj for DROP");
2050 fib_table_entry_path_remove(fib_index,
2054 &pfx_5_5_5_6_s_32.fp_addr,
2055 ~0, // no index provided.
2056 fib_index, // same as route's FIB
2058 FIB_ROUTE_PATH_FLAG_NONE);
2059 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2060 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2061 "1-level 5.5.5.6/32 loop is removed");
2064 * add-remove test. no change.
2066 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2067 fib_path_list_db_size());
2068 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2069 fib_path_list_pool_size());
2070 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2071 fib_entry_pool_size());
2074 * A recursive route with recursion constraints.
2075 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2077 fib_table_entry_path_add(fib_index,
2080 FIB_ENTRY_FLAG_NONE,
2087 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2089 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2090 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2092 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2093 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2095 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2096 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2099 * save the load-balance. we expect it to be inplace modified
2101 lb = load_balance_get(dpo1->dpoi_index);
2104 * add a covering prefix for the via fib that would otherwise serve
2105 * as the resolving route when the host is removed
2107 fib_table_entry_path_add(fib_index,
2110 FIB_ENTRY_FLAG_NONE,
2113 tm->hw[0]->sw_if_index,
2114 ~0, // invalid fib index
2117 FIB_ROUTE_PATH_FLAG_NONE);
2118 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
2119 ai = fib_entry_get_adj(fei);
2120 FIB_TEST((ai == ai_01),
2121 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
2124 * remove the host via FIB - expect the BGP prefix to be drop
2126 fib_table_entry_path_remove(fib_index,
2131 tm->hw[0]->sw_if_index,
2132 ~0, // invalid fib index
2134 FIB_ROUTE_PATH_FLAG_NONE);
2136 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2137 "adj for 200.200.200.200/32 is recursive via adj for DROP");
2140 * add the via-entry host reoute back. expect to resolve again
2142 fib_table_entry_path_add(fib_index,
2145 FIB_ENTRY_FLAG_NONE,
2148 tm->hw[0]->sw_if_index,
2149 ~0, // invalid fib index
2152 FIB_ROUTE_PATH_FLAG_NONE);
2153 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2154 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2157 * add another path for the recursive. it will then have 2.
2159 fib_prefix_t pfx_1_1_1_3_s_32 = {
2161 .fp_proto = FIB_PROTOCOL_IP4,
2163 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
2166 fib_table_entry_path_add(fib_index,
2169 FIB_ENTRY_FLAG_NONE,
2172 tm->hw[0]->sw_if_index,
2173 ~0, // invalid fib index
2176 FIB_ROUTE_PATH_FLAG_NONE);
2178 fib_table_entry_path_add(fib_index,
2181 FIB_ENTRY_FLAG_NONE,
2183 &pfx_1_1_1_3_s_32.fp_addr,
2188 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2190 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2191 dpo = fib_entry_contribute_ip_forwarding(fei);
2193 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2194 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2195 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2196 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2197 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2198 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2199 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2200 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2203 * expect the lb-map used by the recursive's load-balance is using both buckets
2205 load_balance_map_t *lbm;
2208 lb = load_balance_get(dpo->dpoi_index);
2210 load_balance_map_lock(lbmi);
2211 lbm = load_balance_map_get(lbmi);
2213 FIB_TEST(lbm->lbm_buckets[0] == 0,
2214 "LB maps's bucket 0 is %d",
2215 lbm->lbm_buckets[0]);
2216 FIB_TEST(lbm->lbm_buckets[1] == 1,
2217 "LB maps's bucket 1 is %d",
2218 lbm->lbm_buckets[1]);
2221 * withdraw one of the /32 via-entrys.
2222 * that ECMP path will be unresolved and forwarding should continue on the
2223 * other available path. this is an iBGP PIC edge failover.
2224 * Test the forwarding changes without re-fetching the adj from the
2225 * recursive entry. this ensures its the same one that is updated; i.e. an
2228 fib_table_entry_path_remove(fib_index,
2233 tm->hw[0]->sw_if_index,
2234 ~0, // invalid fib index
2236 FIB_ROUTE_PATH_FLAG_NONE);
2238 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2239 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
2240 "post PIC 200.200.200.200/32 was inplace modified");
2242 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
2243 "post PIC adj for 200.200.200.200/32 is recursive"
2244 " via adj for 1.1.1.3");
2247 * the LB maps that was locked above should have been modified to remove
2248 * the path that was down, and thus its bucket points to a path that is
2251 FIB_TEST(lbm->lbm_buckets[0] == 1,
2252 "LB maps's bucket 0 is %d",
2253 lbm->lbm_buckets[0]);
2254 FIB_TEST(lbm->lbm_buckets[1] == 1,
2255 "LB maps's bucket 1 is %d",
2256 lbm->lbm_buckets[1]);
2258 load_balance_map_unlock(lb->lb_map);
2261 * add it back. again
2263 fib_table_entry_path_add(fib_index,
2266 FIB_ENTRY_FLAG_NONE,
2269 tm->hw[0]->sw_if_index,
2270 ~0, // invalid fib index
2273 FIB_ROUTE_PATH_FLAG_NONE);
2275 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
2276 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2277 "via adj for 1.1.1.1");
2278 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
2279 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2280 "via adj for 1.1.1.3");
2282 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2283 dpo = fib_entry_contribute_ip_forwarding(fei);
2284 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2285 "post PIC 200.200.200.200/32 was inplace modified");
2288 * add a 3rd path. this makes the LB 16 buckets.
2290 fib_table_entry_path_add(fib_index,
2293 FIB_ENTRY_FLAG_NONE,
2295 &pfx_1_1_1_2_s_32.fp_addr,
2300 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2302 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2303 dpo = fib_entry_contribute_ip_forwarding(fei);
2304 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2305 "200.200.200.200/32 was inplace modified for 3rd path");
2306 FIB_TEST(16 == lb->lb_n_buckets,
2307 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
2310 load_balance_map_lock(lbmi);
2311 lbm = load_balance_map_get(lbmi);
2313 for (ii = 0; ii < 16; ii++)
2315 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2316 "LB Map for 200.200.200.200/32 at %d is %d",
2317 ii, lbm->lbm_buckets[ii]);
2321 * trigger PIC by removing the first via-entry
2322 * the first 6 buckets of the map should map to the next 6
2324 fib_table_entry_path_remove(fib_index,
2329 tm->hw[0]->sw_if_index,
2332 FIB_ROUTE_PATH_FLAG_NONE);
2334 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2335 dpo = fib_entry_contribute_ip_forwarding(fei);
2336 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2337 "200.200.200.200/32 was inplace modified for 3rd path");
2338 FIB_TEST(2 == lb->lb_n_buckets,
2339 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
2341 for (ii = 0; ii < 6; ii++)
2343 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
2344 "LB Map for 200.200.200.200/32 at %d is %d",
2345 ii, lbm->lbm_buckets[ii]);
2347 for (ii = 6; ii < 16; ii++)
2349 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2350 "LB Map for 200.200.200.200/32 at %d is %d",
2351 ii, lbm->lbm_buckets[ii]);
2358 fib_table_entry_path_add(fib_index,
2361 FIB_ENTRY_FLAG_NONE,
2364 tm->hw[0]->sw_if_index,
2368 FIB_ROUTE_PATH_FLAG_NONE);
2370 fib_table_entry_path_remove(fib_index,
2374 &pfx_1_1_1_2_s_32.fp_addr,
2378 MPLS_LABEL_INVALID);
2379 fib_table_entry_path_remove(fib_index,
2387 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2388 fib_table_entry_path_remove(fib_index,
2392 &pfx_1_1_1_3_s_32.fp_addr,
2396 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2397 fib_table_entry_delete(fib_index,
2400 fib_table_entry_delete(fib_index,
2403 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2404 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
2405 "1.1.1.1/28 removed");
2406 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2407 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
2408 "1.1.1.3/32 removed");
2409 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2410 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
2411 "200.200.200.200/32 removed");
2414 * add-remove test. no change.
2416 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2417 fib_path_list_db_size());
2418 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2419 fib_path_list_pool_size());
2420 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2421 fib_entry_pool_size());
2424 * A route whose paths are built up iteratively and then removed
2427 fib_prefix_t pfx_4_4_4_4_s_32 = {
2429 .fp_proto = FIB_PROTOCOL_IP4,
2432 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
2436 fib_table_entry_path_add(fib_index,
2439 FIB_ENTRY_FLAG_NONE,
2442 tm->hw[0]->sw_if_index,
2446 FIB_ROUTE_PATH_FLAG_NONE);
2447 fib_table_entry_path_add(fib_index,
2450 FIB_ENTRY_FLAG_NONE,
2453 tm->hw[0]->sw_if_index,
2457 FIB_ROUTE_PATH_FLAG_NONE);
2458 fib_table_entry_path_add(fib_index,
2461 FIB_ENTRY_FLAG_NONE,
2464 tm->hw[0]->sw_if_index,
2468 FIB_ROUTE_PATH_FLAG_NONE);
2469 FIB_TEST(FIB_NODE_INDEX_INVALID !=
2470 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2471 "4.4.4.4/32 present");
2473 fib_table_entry_delete(fib_index,
2476 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2477 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2478 "4.4.4.4/32 removed");
2481 * add-remove test. no change.
2483 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2484 fib_path_list_db_size());
2485 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2486 fib_path_list_pool_size());
2487 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2488 fib_entry_pool_size());
2491 * A route with multiple paths at once
2493 fib_route_path_t *r_paths = NULL;
2495 for (ii = 0; ii < 4; ii++)
2497 fib_route_path_t r_path = {
2498 .frp_proto = FIB_PROTOCOL_IP4,
2500 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
2502 .frp_sw_if_index = tm->hw[0]->sw_if_index,
2504 .frp_fib_index = ~0,
2506 vec_add1(r_paths, r_path);
2509 fib_table_entry_update(fib_index,
2512 FIB_ENTRY_FLAG_NONE,
2515 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2516 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2517 dpo = fib_entry_contribute_ip_forwarding(fei);
2519 lb = load_balance_get(dpo->dpoi_index);
2520 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
2522 fib_table_entry_delete(fib_index,
2525 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2526 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2527 "4.4.4.4/32 removed");
2531 * add-remove test. no change.
2533 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2534 fib_path_list_db_size());
2535 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2536 fib_path_list_pool_size());
2537 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2538 fib_entry_pool_size());
2541 * A route deag route
2543 fib_table_entry_path_add(fib_index,
2546 FIB_ENTRY_FLAG_NONE,
2553 FIB_ROUTE_PATH_FLAG_NONE);
2555 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2556 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2558 dpo = fib_entry_contribute_ip_forwarding(fei);
2559 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2560 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
2562 FIB_TEST((fib_index == lkd->lkd_fib_index),
2563 "4.4.4.4/32 is deag in %d %U",
2565 format_dpo_id, dpo, 0);
2567 fib_table_entry_delete(fib_index,
2570 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2571 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2572 "4.4.4.4/32 removed");
2576 * add-remove test. no change.
2578 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2579 fib_path_list_db_size());
2580 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2581 fib_path_list_pool_size());
2582 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2583 fib_entry_pool_size());
2587 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
2588 * all of which are via 10.10.10.1, Itf1
2590 fib_table_entry_path_remove(fib_index,
2595 tm->hw[0]->sw_if_index,
2598 FIB_ROUTE_PATH_FLAG_NONE);
2599 fib_table_entry_path_remove(fib_index,
2604 tm->hw[0]->sw_if_index,
2607 FIB_ROUTE_PATH_FLAG_NONE);
2608 fib_table_entry_path_remove(fib_index,
2613 tm->hw[0]->sw_if_index,
2616 FIB_ROUTE_PATH_FLAG_NONE);
2618 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2619 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
2620 "1.1.1.1/32 removed");
2621 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2622 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
2623 "1.1.1.2/32 removed");
2624 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2625 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
2626 "1.1.2.0/24 removed");
2629 * -3 entries and -1 shared path-list
2631 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2632 fib_path_list_db_size());
2633 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2634 fib_path_list_pool_size());
2635 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2636 fib_entry_pool_size());
2639 * An attached-host route. Expect to link to the incomplete adj
2641 fib_prefix_t pfx_4_1_1_1_s_32 = {
2643 .fp_proto = FIB_PROTOCOL_IP4,
2646 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
2649 fib_table_entry_path_add(fib_index,
2652 FIB_ENTRY_FLAG_NONE,
2655 tm->hw[0]->sw_if_index,
2659 FIB_ROUTE_PATH_FLAG_NONE);
2661 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
2662 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
2663 ai = fib_entry_get_adj(fei);
2665 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2667 &pfx_4_1_1_1_s_32.fp_addr,
2668 tm->hw[0]->sw_if_index);
2669 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
2673 * +1 entry and +1 shared path-list
2675 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2676 fib_path_list_db_size());
2677 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2678 fib_path_list_pool_size());
2679 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
2680 fib_entry_pool_size());
2682 fib_table_entry_delete(fib_index,
2686 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2687 fib_path_list_db_size());
2688 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2689 fib_path_list_pool_size());
2690 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2691 fib_entry_pool_size());
2694 * add a v6 prefix via v4 next-hops
2696 fib_prefix_t pfx_2001_s_64 = {
2698 .fp_proto = FIB_PROTOCOL_IP6,
2700 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
2703 fei = fib_table_entry_path_add(0, //default v6 table
2706 FIB_ENTRY_FLAG_NONE,
2709 tm->hw[0]->sw_if_index,
2713 FIB_ROUTE_PATH_FLAG_NONE);
2715 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
2716 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
2717 ai = fib_entry_get_adj(fei);
2719 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
2720 "2001::/64 via ARP-adj");
2721 FIB_TEST((adj->ia_link == FIB_LINK_IP6),
2722 "2001::/64 is link type v6");
2723 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
2724 "2001::/64 ADJ-adj is NH proto v4");
2725 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
2728 * add a uRPF exempt prefix:
2730 * - it's forwarding is drop
2731 * - it's uRPF list is not empty
2732 * - the uRPF list for the default route (it's cover) is empty
2734 fei = fib_table_entry_special_add(fib_index,
2736 FIB_SOURCE_URPF_EXEMPT,
2737 FIB_ENTRY_FLAG_DROP,
2739 dpo = fib_entry_contribute_ip_forwarding(fei);
2740 FIB_TEST(load_balance_is_drop(dpo),
2741 "uRPF exempt 4.1.1.1/32 DROP");
2742 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
2743 "uRPF list for exempt prefix has itf index 0");
2744 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
2745 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2746 "uRPF list for 0.0.0.0/0 empty");
2748 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
2754 fib_table_entry_delete(fib_index,
2755 &pfx_10_10_10_1_s_32,
2757 fib_table_entry_delete(fib_index,
2758 &pfx_10_10_10_2_s_32,
2760 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2761 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
2762 "10.10.10.1/32 adj-fib removed");
2763 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2764 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
2765 "10.10.10.2/32 adj-fib removed");
2768 * -2 entries and -2 non-shared path-list
2770 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2771 fib_path_list_db_size());
2772 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
2773 fib_path_list_pool_size());
2774 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
2775 fib_entry_pool_size());
2778 * unlock the adjacencies for which this test provided a rewrite.
2779 * These are the last locks on these adjs. they should thus go away.
2783 adj_unlock(ai_12_12_12_12);
2785 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2790 * remove the interface prefixes
2792 local_pfx.fp_len = 32;
2793 fib_table_entry_special_remove(fib_index, &local_pfx,
2794 FIB_SOURCE_INTERFACE);
2795 fei = fib_table_lookup(fib_index, &local_pfx);
2797 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2798 fib_table_lookup_exact_match(fib_index, &local_pfx),
2799 "10.10.10.10/32 adj-fib removed");
2801 local_pfx.fp_len = 24;
2802 fib_table_entry_delete(fib_index, &local_pfx,
2803 FIB_SOURCE_INTERFACE);
2805 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2806 fib_table_lookup_exact_match(fib_index, &local_pfx),
2807 "10.10.10.10/24 adj-fib removed");
2810 * -2 entries and -2 non-shared path-list
2812 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2813 fib_path_list_db_size());
2814 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
2815 fib_path_list_pool_size());
2816 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
2817 fib_entry_pool_size());
2820 * Last but not least, remove the VRF
2822 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2825 "NO API Source'd prefixes");
2826 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2829 "NO RR Source'd prefixes");
2830 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2832 FIB_SOURCE_INTERFACE)),
2833 "NO INterface Source'd prefixes");
2835 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
2837 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2838 fib_path_list_db_size());
2839 FIB_TEST((NBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
2840 fib_path_list_pool_size());
2841 FIB_TEST((NBR-5 == fib_entry_pool_size()), "entry pool size is %d",
2842 fib_entry_pool_size());
2843 FIB_TEST((NBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
2844 pool_elts(fib_urpf_list_pool));
2853 * In the default table check for the presence and correct forwarding
2854 * of the special entries
2856 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
2857 const dpo_id_t *dpo, *dpo_drop;
2858 const ip_adjacency_t *adj;
2859 const receive_dpo_t *rd;
2864 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2867 /* via 2001:0:0:1::2 */
2868 ip46_address_t nh_2001_2 = {
2871 [0] = clib_host_to_net_u64(0x2001000000000001),
2872 [1] = clib_host_to_net_u64(0x0000000000000002),
2879 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
2881 /* Find or create FIB table 11 */
2882 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
2884 for (ii = 0; ii < 4; ii++)
2886 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
2889 fib_prefix_t pfx_0_0 = {
2891 .fp_proto = FIB_PROTOCOL_IP6,
2899 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
2900 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
2901 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
2902 "Default route is DROP");
2904 dpo = fib_entry_contribute_ip_forwarding(dfrt);
2905 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2908 &pfx_0_0.fp_addr.ip6)),
2909 "default-route; fwd and non-fwd tables match");
2911 // FIXME - check specials.
2914 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
2915 * each with 6 entries. All entries are special so no path-list sharing.
2918 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
2919 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is %d",
2920 fib_path_list_pool_size());
2921 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
2922 fib_entry_pool_size());
2925 * add interface routes.
2926 * validate presence of /64 attached and /128 recieve.
2927 * test for the presence of the receive address in the glean and local adj
2929 * receive on 2001:0:0:1::1/128
2931 fib_prefix_t local_pfx = {
2933 .fp_proto = FIB_PROTOCOL_IP6,
2937 [0] = clib_host_to_net_u64(0x2001000000000001),
2938 [1] = clib_host_to_net_u64(0x0000000000000001),
2944 fib_table_entry_update_one_path(fib_index, &local_pfx,
2945 FIB_SOURCE_INTERFACE,
2946 (FIB_ENTRY_FLAG_CONNECTED |
2947 FIB_ENTRY_FLAG_ATTACHED),
2950 tm->hw[0]->sw_if_index,
2954 FIB_ROUTE_PATH_FLAG_NONE);
2955 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
2957 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
2959 ai = fib_entry_get_adj(fei);
2960 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
2962 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
2963 "attached interface adj is glean");
2964 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
2965 &adj->sub_type.glean.receive_addr)),
2966 "attached interface adj is receive ok");
2967 dpo = fib_entry_contribute_ip_forwarding(fei);
2968 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2971 &local_pfx.fp_addr.ip6)),
2972 "attached-route; fwd and non-fwd tables match");
2974 local_pfx.fp_len = 128;
2975 fib_table_entry_update_one_path(fib_index, &local_pfx,
2976 FIB_SOURCE_INTERFACE,
2977 (FIB_ENTRY_FLAG_CONNECTED |
2978 FIB_ENTRY_FLAG_LOCAL),
2981 tm->hw[0]->sw_if_index,
2982 ~0, // invalid fib index
2985 FIB_ROUTE_PATH_FLAG_NONE);
2986 fei = fib_table_lookup(fib_index, &local_pfx);
2988 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
2990 dpo = fib_entry_contribute_ip_forwarding(fei);
2991 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2992 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
2993 "local interface adj is local");
2994 rd = receive_dpo_get(dpo->dpoi_index);
2996 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
2998 "local interface adj is receive ok");
3000 dpo = fib_entry_contribute_ip_forwarding(fei);
3001 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3004 &local_pfx.fp_addr.ip6)),
3005 "local-route; fwd and non-fwd tables match");
3008 * +2 entries. +2 unshared path-lists
3010 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3011 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3012 fib_path_list_pool_size());
3013 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3014 fib_entry_pool_size());
3017 * Modify the default route to be via an adj not yet known.
3018 * this sources the defalut route with the API source, which is
3019 * a higher preference to the DEFAULT_ROUTE source
3021 fib_table_entry_path_add(fib_index, &pfx_0_0,
3023 FIB_ENTRY_FLAG_NONE,
3026 tm->hw[0]->sw_if_index,
3030 FIB_ROUTE_PATH_FLAG_NONE);
3031 fei = fib_table_lookup(fib_index, &pfx_0_0);
3033 FIB_TEST((fei == dfrt), "default route same index");
3034 ai = fib_entry_get_adj(fei);
3035 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
3037 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3038 "adj is incomplete");
3039 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
3040 "adj nbr next-hop ok");
3043 * find the adj in the shared db
3045 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3048 tm->hw[0]->sw_if_index);
3049 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
3050 adj_unlock(locked_ai);
3053 * no more entires. +1 shared path-list
3055 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3056 fib_path_list_db_size());
3057 FIB_TEST((NPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
3058 fib_path_list_pool_size());
3059 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3060 fib_entry_pool_size());
3063 * remove the API source from the default route. We expected
3064 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
3066 fib_table_entry_path_remove(fib_index, &pfx_0_0,
3070 tm->hw[0]->sw_if_index,
3073 FIB_ROUTE_PATH_FLAG_NONE);
3074 fei = fib_table_lookup(fib_index, &pfx_0_0);
3076 FIB_TEST((fei == dfrt), "default route same index");
3077 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3078 "Default route is DROP");
3081 * no more entires. -1 shared path-list
3083 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3084 fib_path_list_db_size());
3085 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3086 fib_path_list_pool_size());
3087 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3088 fib_entry_pool_size());
3091 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3093 fib_prefix_t pfx_2001_1_2_s_128 = {
3095 .fp_proto = FIB_PROTOCOL_IP6,
3099 [0] = clib_host_to_net_u64(0x2001000000000001),
3100 [1] = clib_host_to_net_u64(0x0000000000000002),
3105 fib_prefix_t pfx_2001_1_3_s_128 = {
3107 .fp_proto = FIB_PROTOCOL_IP6,
3111 [0] = clib_host_to_net_u64(0x2001000000000001),
3112 [1] = clib_host_to_net_u64(0x0000000000000003),
3118 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
3121 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3123 &pfx_2001_1_2_s_128.fp_addr,
3124 tm->hw[0]->sw_if_index);
3125 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
3126 adj = adj_get(ai_01);
3127 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3128 "adj is incomplete");
3129 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3130 &adj->sub_type.nbr.next_hop)),
3131 "adj nbr next-hop ok");
3133 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
3134 fib_test_build_rewrite(eth_addr));
3135 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3137 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3138 &adj->sub_type.nbr.next_hop)),
3139 "adj nbr next-hop ok");
3141 fib_table_entry_update_one_path(fib_index,
3142 &pfx_2001_1_2_s_128,
3144 FIB_ENTRY_FLAG_NONE,
3146 &pfx_2001_1_2_s_128.fp_addr,
3147 tm->hw[0]->sw_if_index,
3151 FIB_ROUTE_PATH_FLAG_NONE);
3153 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
3154 ai = fib_entry_get_adj(fei);
3155 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3159 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3161 &pfx_2001_1_3_s_128.fp_addr,
3162 tm->hw[0]->sw_if_index);
3163 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
3164 adj = adj_get(ai_02);
3165 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3166 "adj is incomplete");
3167 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3168 &adj->sub_type.nbr.next_hop)),
3169 "adj nbr next-hop ok");
3171 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
3172 fib_test_build_rewrite(eth_addr));
3173 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3175 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3176 &adj->sub_type.nbr.next_hop)),
3177 "adj nbr next-hop ok");
3178 FIB_TEST((ai_01 != ai_02), "ADJs are different");
3180 fib_table_entry_update_one_path(fib_index,
3181 &pfx_2001_1_3_s_128,
3183 FIB_ENTRY_FLAG_NONE,
3185 &pfx_2001_1_3_s_128.fp_addr,
3186 tm->hw[0]->sw_if_index,
3190 FIB_ROUTE_PATH_FLAG_NONE);
3192 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
3193 ai = fib_entry_get_adj(fei);
3194 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3197 * +2 entries, +2 unshread path-lists.
3199 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3200 fib_path_list_db_size());
3201 FIB_TEST((NPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
3202 fib_path_list_pool_size());
3203 FIB_TEST((NPS+4 == fib_entry_pool_size()), "entry pool size is %d",
3204 fib_entry_pool_size());
3207 * Add a 2 routes via the first ADJ. ensure path-list sharing
3209 fib_prefix_t pfx_2001_a_s_64 = {
3211 .fp_proto = FIB_PROTOCOL_IP6,
3215 [0] = clib_host_to_net_u64(0x200100000000000a),
3216 [1] = clib_host_to_net_u64(0x0000000000000000),
3221 fib_prefix_t pfx_2001_b_s_64 = {
3223 .fp_proto = FIB_PROTOCOL_IP6,
3227 [0] = clib_host_to_net_u64(0x200100000000000b),
3228 [1] = clib_host_to_net_u64(0x0000000000000000),
3234 fib_table_entry_path_add(fib_index,
3237 FIB_ENTRY_FLAG_NONE,
3240 tm->hw[0]->sw_if_index,
3244 FIB_ROUTE_PATH_FLAG_NONE);
3245 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
3246 ai = fib_entry_get_adj(fei);
3247 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3248 fib_table_entry_path_add(fib_index,
3251 FIB_ENTRY_FLAG_NONE,
3254 tm->hw[0]->sw_if_index,
3258 FIB_ROUTE_PATH_FLAG_NONE);
3259 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
3260 ai = fib_entry_get_adj(fei);
3261 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3264 * +2 entries, +1 shared path-list.
3266 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3267 fib_path_list_db_size());
3268 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3269 fib_path_list_pool_size());
3270 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3271 fib_entry_pool_size());
3274 * add a v4 prefix via a v6 next-hop
3276 fib_prefix_t pfx_1_1_1_1_s_32 = {
3278 .fp_proto = FIB_PROTOCOL_IP4,
3280 .ip4.as_u32 = 0x01010101,
3283 fei = fib_table_entry_path_add(0, // default table
3286 FIB_ENTRY_FLAG_NONE,
3289 tm->hw[0]->sw_if_index,
3293 FIB_ROUTE_PATH_FLAG_NONE);
3294 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
3295 "1.1.1.1/32 o v6 route present");
3296 ai = fib_entry_get_adj(fei);
3298 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3299 "1.1.1.1/32 via ARP-adj");
3300 FIB_TEST((adj->ia_link == FIB_LINK_IP4),
3301 "1.1.1.1/32 ADJ-adj is link type v4");
3302 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
3303 "1.1.1.1/32 ADJ-adj is NH proto v6");
3304 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
3309 fib_prefix_t pfx_2001_c_s_64 = {
3311 .fp_proto = FIB_PROTOCOL_IP6,
3315 [0] = clib_host_to_net_u64(0x200100000000000c),
3316 [1] = clib_host_to_net_u64(0x0000000000000000),
3321 fib_table_entry_path_add(fib_index,
3324 FIB_ENTRY_FLAG_ATTACHED,
3327 tm->hw[0]->sw_if_index,
3331 FIB_ROUTE_PATH_FLAG_NONE);
3332 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3333 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
3334 ai = fib_entry_get_adj(fei);
3336 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
3337 "2001:0:0:c/64 attached resolves via glean");
3339 fib_table_entry_path_remove(fib_index,
3344 tm->hw[0]->sw_if_index,
3347 FIB_ROUTE_PATH_FLAG_NONE);
3348 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3349 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
3352 * Shutdown the interface on which we have a connected and through
3353 * which the routes are reachable.
3354 * This will result in the connected, adj-fibs, and routes linking to drop
3355 * The local/for-us prefix continues to receive.
3357 clib_error_t * error;
3359 error = vnet_sw_interface_set_flags(vnet_get_main(),
3360 tm->hw[0]->sw_if_index,
3361 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3362 FIB_TEST((NULL == error), "Interface shutdown OK");
3364 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3365 dpo = fib_entry_contribute_ip_forwarding(fei);
3366 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3367 "2001::b/64 resolves via drop");
3369 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3370 dpo = fib_entry_contribute_ip_forwarding(fei);
3371 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3372 "2001::a/64 resolves via drop");
3373 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3374 dpo = fib_entry_contribute_ip_forwarding(fei);
3375 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3376 "2001:0:0:1::3/64 resolves via drop");
3377 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3378 dpo = fib_entry_contribute_ip_forwarding(fei);
3379 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3380 "2001:0:0:1::2/64 resolves via drop");
3381 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3382 dpo = fib_entry_contribute_ip_forwarding(fei);
3383 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3384 "2001:0:0:1::1/128 not drop");
3385 local_pfx.fp_len = 64;
3386 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3387 dpo = fib_entry_contribute_ip_forwarding(fei);
3388 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3389 "2001:0:0:1/64 resolves via drop");
3394 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3395 fib_path_list_db_size());
3396 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3397 fib_path_list_pool_size());
3398 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3399 fib_entry_pool_size());
3402 * shutdown one of the other interfaces, then add a connected.
3403 * and swap one of the routes to it.
3405 error = vnet_sw_interface_set_flags(vnet_get_main(),
3406 tm->hw[1]->sw_if_index,
3407 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3408 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
3410 fib_prefix_t connected_pfx = {
3412 .fp_proto = FIB_PROTOCOL_IP6,
3415 /* 2001:0:0:2::1/64 */
3417 [0] = clib_host_to_net_u64(0x2001000000000002),
3418 [1] = clib_host_to_net_u64(0x0000000000000001),
3423 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3424 FIB_SOURCE_INTERFACE,
3425 (FIB_ENTRY_FLAG_CONNECTED |
3426 FIB_ENTRY_FLAG_ATTACHED),
3429 tm->hw[1]->sw_if_index,
3433 FIB_ROUTE_PATH_FLAG_NONE);
3434 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
3435 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3436 dpo = fib_entry_contribute_ip_forwarding(fei);
3437 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3438 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
3439 "2001:0:0:2/64 not resolves via drop");
3441 connected_pfx.fp_len = 128;
3442 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3443 FIB_SOURCE_INTERFACE,
3444 (FIB_ENTRY_FLAG_CONNECTED |
3445 FIB_ENTRY_FLAG_LOCAL),
3448 tm->hw[0]->sw_if_index,
3449 ~0, // invalid fib index
3452 FIB_ROUTE_PATH_FLAG_NONE);
3453 fei = fib_table_lookup(fib_index, &connected_pfx);
3455 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3456 dpo = fib_entry_contribute_ip_forwarding(fei);
3457 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3458 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3459 "local interface adj is local");
3460 rd = receive_dpo_get(dpo->dpoi_index);
3461 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
3463 "local interface adj is receive ok");
3466 * +2 entries, +2 unshared path-lists
3468 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3469 fib_path_list_db_size());
3470 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3471 fib_path_list_pool_size());
3472 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3473 fib_entry_pool_size());
3477 * bring the interface back up. we expected the routes to return
3478 * to normal forwarding.
3480 error = vnet_sw_interface_set_flags(vnet_get_main(),
3481 tm->hw[0]->sw_if_index,
3482 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3483 FIB_TEST((NULL == error), "Interface bring-up OK");
3484 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3485 ai = fib_entry_get_adj(fei);
3486 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3487 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3488 ai = fib_entry_get_adj(fei);
3489 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3490 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3491 ai = fib_entry_get_adj(fei);
3492 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3493 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3494 ai = fib_entry_get_adj(fei);
3495 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3496 local_pfx.fp_len = 64;
3497 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3498 ai = fib_entry_get_adj(fei);
3500 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3501 "attached interface adj is glean");
3504 * Delete the interface that the routes reolve through.
3505 * Again no routes are removed. They all point to drop.
3507 * This is considered an error case. The control plane should
3508 * not remove interfaces through which routes resolve, but
3509 * such things can happen. ALL affected routes will drop.
3511 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
3513 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3514 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3515 "2001::b/64 resolves via drop");
3516 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3517 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3518 "2001::b/64 resolves via drop");
3519 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3520 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3521 "2001:0:0:1::3/64 resolves via drop");
3522 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3523 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3524 "2001:0:0:1::2/64 resolves via drop");
3525 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3526 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3527 "2001:0:0:1::1/128 is drop");
3528 local_pfx.fp_len = 64;
3529 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3530 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3531 "2001:0:0:1/64 resolves via drop");
3536 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3537 fib_path_list_db_size());
3538 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3539 fib_path_list_pool_size());
3540 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3541 fib_entry_pool_size());
3544 * Add the interface back. routes stay unresolved.
3546 error = ethernet_register_interface(vnet_get_main(),
3547 test_interface_device_class.index,
3550 &tm->hw_if_indicies[0],
3551 /* flag change */ 0);
3553 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3554 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3555 "2001::b/64 resolves via drop");
3556 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3557 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3558 "2001::b/64 resolves via drop");
3559 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3560 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3561 "2001:0:0:1::3/64 resolves via drop");
3562 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3563 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3564 "2001:0:0:1::2/64 resolves via drop");
3565 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3566 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3567 "2001:0:0:1::1/128 is drop");
3568 local_pfx.fp_len = 64;
3569 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3570 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3571 "2001:0:0:1/64 resolves via drop");
3574 * CLEANUP ALL the routes
3576 fib_table_entry_delete(fib_index,
3579 fib_table_entry_delete(fib_index,
3582 fib_table_entry_delete(fib_index,
3585 fib_table_entry_delete(fib_index,
3586 &pfx_2001_1_3_s_128,
3588 fib_table_entry_delete(fib_index,
3589 &pfx_2001_1_2_s_128,
3591 local_pfx.fp_len = 64;
3592 fib_table_entry_delete(fib_index, &local_pfx,
3593 FIB_SOURCE_INTERFACE);
3594 local_pfx.fp_len = 128;
3595 fib_table_entry_special_remove(fib_index, &local_pfx,
3596 FIB_SOURCE_INTERFACE);
3597 connected_pfx.fp_len = 64;
3598 fib_table_entry_delete(fib_index, &connected_pfx,
3599 FIB_SOURCE_INTERFACE);
3600 connected_pfx.fp_len = 128;
3601 fib_table_entry_special_remove(fib_index, &connected_pfx,
3602 FIB_SOURCE_INTERFACE);
3604 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3605 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
3606 "2001::a/64 removed");
3607 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3608 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
3609 "2001::b/64 removed");
3610 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3611 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
3612 "2001:0:0:1::3/128 removed");
3613 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3614 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
3615 "2001:0:0:1::3/128 removed");
3616 local_pfx.fp_len = 64;
3617 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3618 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3619 "2001:0:0:1/64 removed");
3620 local_pfx.fp_len = 128;
3621 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3622 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3623 "2001:0:0:1::1/128 removed");
3624 connected_pfx.fp_len = 64;
3625 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3626 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3627 "2001:0:0:2/64 removed");
3628 connected_pfx.fp_len = 128;
3629 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3630 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3631 "2001:0:0:2::1/128 removed");
3634 * -8 entries. -7 path-lists (1 was shared).
3636 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3637 fib_path_list_db_size());
3638 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is%d",
3639 fib_path_list_pool_size());
3640 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
3641 fib_entry_pool_size());
3644 * now remove the VRF
3646 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
3648 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3649 fib_path_list_db_size());
3650 FIB_TEST((NPS-6 == fib_path_list_pool_size()), "path list pool size is%d",
3651 fib_path_list_pool_size());
3652 FIB_TEST((NPS-6 == fib_entry_pool_size()), "entry pool size is %d",
3653 fib_entry_pool_size());
3659 * return the interfaces to up state
3661 error = vnet_sw_interface_set_flags(vnet_get_main(),
3662 tm->hw[0]->sw_if_index,
3663 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3664 error = vnet_sw_interface_set_flags(vnet_get_main(),
3665 tm->hw[1]->sw_if_index,
3666 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3668 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3673 * Test the recursive route route handling for GRE tunnels
3678 /* fib_node_index_t fei; */
3679 /* u32 fib_index = 0; */
3680 /* test_main_t *tm; */
3683 /* tm = &test_main; */
3685 /* for (ii = 0; ii < 4; ii++) */
3687 /* ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = 0; */
3691 /* * add interface routes. We'll assume this works. It's more rigorously */
3692 /* * tested elsewhere. */
3694 /* fib_prefix_t local_pfx = { */
3696 /* .fp_proto = FIB_PROTOCOL_IP4, */
3699 /* /\* 10.10.10.10 *\/ */
3700 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3705 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3706 /* FIB_SOURCE_INTERFACE, */
3707 /* (FIB_ENTRY_FLAG_CONNECTED | */
3708 /* FIB_ENTRY_FLAG_ATTACHED), */
3710 /* tm->hw[0]->sw_if_index, */
3713 /* FIB_ROUTE_PATH_FLAG_NONE); */
3714 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3715 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3716 /* "attached interface route present"); */
3718 /* local_pfx.fp_len = 32; */
3719 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3720 /* FIB_SOURCE_INTERFACE, */
3721 /* (FIB_ENTRY_FLAG_CONNECTED | */
3722 /* FIB_ENTRY_FLAG_LOCAL), */
3724 /* tm->hw[0]->sw_if_index, */
3725 /* ~0, // invalid fib index */
3727 /* FIB_ROUTE_PATH_FLAG_NONE); */
3728 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3730 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3731 /* "local interface route present"); */
3733 /* fib_prefix_t local2_pfx = { */
3735 /* .fp_proto = FIB_PROTOCOL_IP4, */
3738 /* /\* 10.10.11.11 *\/ */
3739 /* .as_u32 = clib_host_to_net_u32(0x0a0a0b0b), */
3744 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3745 /* FIB_SOURCE_INTERFACE, */
3746 /* (FIB_ENTRY_FLAG_CONNECTED | */
3747 /* FIB_ENTRY_FLAG_ATTACHED), */
3749 /* tm->hw[1]->sw_if_index, */
3752 /* FIB_ROUTE_PATH_FLAG_NONE); */
3753 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3754 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3755 /* "attached interface route present"); */
3757 /* local2_pfx.fp_len = 32; */
3758 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3759 /* FIB_SOURCE_INTERFACE, */
3760 /* (FIB_ENTRY_FLAG_CONNECTED | */
3761 /* FIB_ENTRY_FLAG_LOCAL), */
3763 /* tm->hw[0]->sw_if_index, */
3764 /* ~0, // invalid fib index */
3766 /* FIB_ROUTE_PATH_FLAG_NONE); */
3767 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3769 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3770 /* "local interface route present"); */
3773 /* * Add the route that will be used to resolve the tunnel's destination */
3775 /* fib_prefix_t route_pfx = { */
3777 /* .fp_proto = FIB_PROTOCOL_IP4, */
3780 /* /\* 1.1.1.0/24 *\/ */
3781 /* .as_u32 = clib_host_to_net_u32(0x01010100), */
3785 /* /\* 10.10.10.2 *\/ */
3786 /* ip46_address_t nh_10_10_10_2 = { */
3787 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02), */
3790 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3791 /* FIB_SOURCE_API, */
3792 /* FIB_ENTRY_FLAG_NONE, */
3793 /* &nh_10_10_10_2, */
3794 /* tm->hw[0]->sw_if_index, */
3797 /* FIB_ROUTE_PATH_FLAG_NONE); */
3798 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
3799 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
3800 /* "route present"); */
3803 /* * Add a tunnel */
3805 /* /\* 1.1.1.1 *\/ */
3806 /* fib_prefix_t tun_dst_pfx = { */
3808 /* .fp_proto = FIB_PROTOCOL_IP4, */
3810 /* .ip4.as_u32 = clib_host_to_net_u32(0x01010101), */
3813 /* /\* 10.10.10.10 *\/ */
3814 /* ip4_address_t tun_src = { */
3815 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3817 /* /\* 172.16.0.1 *\/ */
3818 /* ip4_address_t tun_itf = { */
3819 /* .as_u32 = clib_host_to_net_u32(0xac100001), */
3821 /* fib_prefix_t tun_itf_pfx = { */
3823 /* .fp_proto = FIB_PROTOCOL_IP4, */
3825 /* .ip4 = tun_itf, */
3828 /* u32 *encap_labels = NULL; */
3829 /* u32 label = 0xbaba; */
3830 /* u32 encap_index; */
3831 /* u32 tunnel_sw_if_index; */
3836 /* * First we need the MPLS Encap present */
3838 /* * Pretty sure this is broken. the wiki say the 1st aparamter address */
3839 /* * should be the tunnel's interface address, which makes some sense. But */
3840 /* * the code for tunnel creation checks for the tunnel's destination */
3841 /* * address. curious... */
3843 /* vec_add1(encap_labels, label); */
3844 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
3845 /* 0, // inner VRF */
3847 /* ~0, // policy_tunnel_index, */
3848 /* 0, // no_dst_hash, */
3851 /* FIB_TEST((0 == rv), "MPLS encap created"); */
3854 /* * now create the tunnel */
3856 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3857 /* &tun_dst_pfx.fp_addr.ip4, */
3858 /* &tun_itf_pfx.fp_addr.ip4, */
3859 /* tun_itf_pfx.fp_len, */
3860 /* 0, // inner VRF */
3861 /* 0, // outer VRF */
3862 /* &tunnel_sw_if_index, */
3865 /* FIB_TEST((0 == rv), "Tunnel created"); */
3868 /* * add it again. just for giggles. */
3870 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3871 /* &tun_dst_pfx.fp_addr.ip4, */
3872 /* &tun_itf_pfx.fp_addr.ip4, */
3873 /* tun_itf_pfx.fp_len, */
3874 /* 0, // inner VRF */
3875 /* 0, // outer VRF */
3876 /* &tunnel_sw_if_index, */
3879 /* FIB_TEST((0 != rv), "Duplicate Tunnel not created"); */
3882 /* * Find the route added for the tunnel subnet and check that */
3883 /* * it has a midchin adj that is stacked on the adj used to reach the */
3884 /* * tunnel destination */
3886 /* ip_adjacency_t *midchain_adj, *route_adj, *adjfib_adj; */
3887 /* adj_index_t midchain_ai, route_ai, adjfib_ai1, adjfib_ai2; */
3888 /* ip_lookup_main_t *lm; */
3890 /* lm = &ip4_main.lookup_main; */
3892 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
3893 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "tun itf route present"); */
3894 /* midchain_ai = fib_entry_contribute_forwarding(fei); */
3895 /* midchain_adj = adj_get(midchain_ai); */
3897 /* FIB_TEST((IP_LOOKUP_NEXT_MIDCHAIN == midchain_adj->lookup_next_index), */
3898 /* "Tunnel interface links to midchain"); */
3900 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3901 /* route_ai = fib_entry_contribute_forwarding(fei); */
3902 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3903 /* "tunnel midchain it stacked on route adj"); */
3906 /* * update the route to the tunnel's destination to load-balance via */
3907 /* * interface 1. */
3909 /* /\* 10.10.11.2 *\/ */
3910 /* ip46_address_t nh_10_10_11_2 = { */
3911 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02), */
3914 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3915 /* FIB_SOURCE_API, */
3916 /* FIB_ENTRY_FLAG_NONE, */
3917 /* &nh_10_10_11_2, */
3918 /* tm->hw[1]->sw_if_index, */
3921 /* FIB_ROUTE_PATH_FLAG_NONE); */
3924 /* * the tunnels midchain should have re-stacked. This tests that the */
3925 /* * route re-resolution backwalk works to a tunnel interface. */
3927 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3928 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
3929 /* route_ai = fib_entry_contribute_forwarding(fei); */
3931 /* midchain_adj = adj_get(midchain_ai); */
3933 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3934 /* "tunnel midchain has re-stacked on route adj"); */
3936 /* route_adj = adj_get(route_ai); */
3938 /* FIB_TEST((2 == route_adj->n_adj), "Route adj is multipath"); */
3941 /* * At this stage both nieghbour adjs are incomplete, so the same should */
3942 /* * be true of the multipath adj */
3944 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == route_adj->lookup_next_index), */
3945 /* "Adj0 is ARP: %d", route_adj->lookup_next_index); */
3946 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == (route_adj+1)->lookup_next_index), */
3947 /* "Adj1 is ARP"); */
3950 /* * do the equivalent of creating an ARP entry for 10.10.10.2. */
3951 /* * This will complete the adj, and this */
3952 /* * change should be refelct in the multipath too. */
3954 /* u8* rewrite = NULL, byte = 0xd; */
3955 /* vec_add(rewrite, &byte, 6); */
3957 /* adjfib_ai1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
3959 /* &nh_10_10_10_2, */
3960 /* tm->hw[0]->sw_if_index); */
3961 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
3964 /* adjfib_adj = adj_get(adjfib_ai1); */
3965 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
3966 /* "Adj-fib10 adj is rewrite"); */
3968 /* adjfib_ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
3970 /* &nh_10_10_11_2, */
3971 /* tm->hw[1]->sw_if_index); */
3972 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
3976 /* adjfib_adj = adj_get(adjfib_ai2); */
3978 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
3979 /* "Adj-fib11 adj is rewrite"); */
3981 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3982 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
3983 /* route_ai = fib_entry_contribute_forwarding(fei); */
3984 /* route_adj = adj_get(route_ai); */
3985 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == route_adj->lookup_next_index), */
3986 /* "Adj0 is rewrite"); */
3987 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == (route_adj+1)->lookup_next_index), */
3988 /* "Adj1 is rewrite"); */
3993 /* adj_index_t drop_ai = adj_get_special(FIB_PROTOCOL_IP4, */
3994 /* ADJ_SPECIAL_TYPE_DROP); */
3997 /* * remove the route that the tunnel resovles via. expect */
3998 /* * it to now resolve via the default route, which is drop */
4000 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
4001 /* FIB_SOURCE_API, */
4002 /* &nh_10_10_10_2, */
4003 /* tm->hw[0]->sw_if_index, */
4006 /* FIB_ROUTE_PATH_FLAG_NONE); */
4007 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
4008 /* FIB_SOURCE_API, */
4009 /* &nh_10_10_11_2, */
4010 /* tm->hw[1]->sw_if_index, */
4013 /* FIB_ROUTE_PATH_FLAG_NONE); */
4014 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
4015 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
4016 /* "route present"); */
4017 /* midchain_adj = adj_get(midchain_ai); */
4018 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == drop_ai), */
4019 /* "tunnel midchain has re-stacked on drop"); */
4022 /* * remove the tunnel and its MPLS encaps */
4024 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
4025 /* &tun_dst_pfx.fp_addr.ip4, */
4026 /* &tun_itf_pfx.fp_addr.ip4, */
4027 /* tun_itf_pfx.fp_len, */
4028 /* 0, // inner VRF */
4029 /* 0, // outer VRF */
4030 /* &tunnel_sw_if_index, */
4033 /* FIB_TEST((0 == rv), "Tunnel removed"); */
4034 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
4035 /* &tun_dst_pfx.fp_addr.ip4, */
4036 /* &tun_itf_pfx.fp_addr.ip4, */
4037 /* tun_itf_pfx.fp_len, */
4038 /* 0, // inner VRF */
4039 /* 0, // outer VRF */
4040 /* &tunnel_sw_if_index, */
4043 /* FIB_TEST((0 != rv), "No existant Tunnel not removed"); */
4045 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
4046 /* 0, // inner VRF */
4048 /* ~0, // policy_tunnel_index, */
4049 /* 0, // no_dst_hash, */
4052 /* FIB_TEST((0 == rv), "MPLS encap deleted"); */
4054 /* vec_free(encap_labels); */
4057 /* * no more FIB entries expected */
4059 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
4060 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun itf route removed"); */
4061 /* fei = fib_table_lookup_exact_match(fib_index, &tun_dst_pfx); */
4062 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun dst route removed"); */
4065 /* * CLEANUP the connecteds */
4067 /* local2_pfx.fp_len = 24; */
4068 /* fib_table_entry_delete(fib_index, &local2_pfx, */
4069 /* FIB_SOURCE_INTERFACE); */
4070 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
4071 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4072 /* "attached interface route remove"); */
4074 /* local2_pfx.fp_len = 32; */
4075 /* fib_table_entry_special_remove(fib_index, &local2_pfx, */
4076 /* FIB_SOURCE_INTERFACE); */
4077 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
4078 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4079 /* "local interface route removed"); */
4080 /* local_pfx.fp_len = 24; */
4081 /* fib_table_entry_delete(fib_index, &local_pfx, */
4082 /* FIB_SOURCE_INTERFACE); */
4083 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
4084 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4085 /* "attached interface route remove"); */
4087 /* local_pfx.fp_len = 32; */
4088 /* fib_table_entry_special_remove(fib_index, &local_pfx, */
4089 /* FIB_SOURCE_INTERFACE); */
4090 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
4091 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4092 /* "local interface route removed"); */
4096 * Test Attached Exports
4101 const dpo_id_t *dpo, *dpo_drop;
4102 const u32 fib_index = 0;
4103 fib_node_index_t fei;
4110 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4114 * add interface routes. We'll assume this works. It's more rigorously
4117 fib_prefix_t local_pfx = {
4119 .fp_proto = FIB_PROTOCOL_IP4,
4123 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4128 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4129 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4131 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4133 fib_table_entry_update_one_path(fib_index, &local_pfx,
4134 FIB_SOURCE_INTERFACE,
4135 (FIB_ENTRY_FLAG_CONNECTED |
4136 FIB_ENTRY_FLAG_ATTACHED),
4139 tm->hw[0]->sw_if_index,
4143 FIB_ROUTE_PATH_FLAG_NONE);
4144 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4145 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4146 "attached interface route present");
4148 local_pfx.fp_len = 32;
4149 fib_table_entry_update_one_path(fib_index, &local_pfx,
4150 FIB_SOURCE_INTERFACE,
4151 (FIB_ENTRY_FLAG_CONNECTED |
4152 FIB_ENTRY_FLAG_LOCAL),
4155 tm->hw[0]->sw_if_index,
4156 ~0, // invalid fib index
4159 FIB_ROUTE_PATH_FLAG_NONE);
4160 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4162 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4163 "local interface route present");
4166 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4168 fib_prefix_t pfx_10_10_10_1_s_32 = {
4170 .fp_proto = FIB_PROTOCOL_IP4,
4173 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4176 fib_node_index_t ai;
4178 fib_table_entry_update_one_path(fib_index,
4179 &pfx_10_10_10_1_s_32,
4181 FIB_ENTRY_FLAG_NONE,
4183 &pfx_10_10_10_1_s_32.fp_addr,
4184 tm->hw[0]->sw_if_index,
4185 ~0, // invalid fib index
4188 FIB_ROUTE_PATH_FLAG_NONE);
4190 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4191 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4192 ai = fib_entry_get_adj(fei);
4195 * create another FIB table into which routes will be imported
4197 u32 import_fib_index1;
4199 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4202 * Add an attached route in the import FIB
4204 local_pfx.fp_len = 24;
4205 fib_table_entry_update_one_path(import_fib_index1,
4208 FIB_ENTRY_FLAG_NONE,
4211 tm->hw[0]->sw_if_index,
4212 ~0, // invalid fib index
4215 FIB_ROUTE_PATH_FLAG_NONE);
4216 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4217 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4220 * check for the presence of the adj-fibs in the import table
4222 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4223 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4224 FIB_TEST((ai == fib_entry_get_adj(fei)),
4225 "adj-fib1 Import uses same adj as export");
4228 * check for the presence of the local in the import table
4230 local_pfx.fp_len = 32;
4231 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4232 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4235 * Add another adj-fin in the export table. Expect this
4236 * to get magically exported;
4238 fib_prefix_t pfx_10_10_10_2_s_32 = {
4240 .fp_proto = FIB_PROTOCOL_IP4,
4243 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4247 fib_table_entry_update_one_path(fib_index,
4248 &pfx_10_10_10_2_s_32,
4250 FIB_ENTRY_FLAG_NONE,
4252 &pfx_10_10_10_2_s_32.fp_addr,
4253 tm->hw[0]->sw_if_index,
4254 ~0, // invalid fib index
4257 FIB_ROUTE_PATH_FLAG_NONE);
4258 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4259 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4260 ai = fib_entry_get_adj(fei);
4262 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4263 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4264 FIB_TEST((ai == fib_entry_get_adj(fei)),
4265 "Import uses same adj as export");
4268 * create a 2nd FIB table into which routes will be imported
4270 u32 import_fib_index2;
4272 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4275 * Add an attached route in the import FIB
4277 local_pfx.fp_len = 24;
4278 fib_table_entry_update_one_path(import_fib_index2,
4281 FIB_ENTRY_FLAG_NONE,
4284 tm->hw[0]->sw_if_index,
4285 ~0, // invalid fib index
4288 FIB_ROUTE_PATH_FLAG_NONE);
4289 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4290 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4293 * check for the presence of all the adj-fibs and local in the import table
4295 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4296 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4297 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4298 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4299 local_pfx.fp_len = 32;
4300 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4301 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4304 * add a 3rd adj-fib. expect it to be exported to both tables.
4306 fib_prefix_t pfx_10_10_10_3_s_32 = {
4308 .fp_proto = FIB_PROTOCOL_IP4,
4311 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4315 fib_table_entry_update_one_path(fib_index,
4316 &pfx_10_10_10_3_s_32,
4318 FIB_ENTRY_FLAG_NONE,
4320 &pfx_10_10_10_3_s_32.fp_addr,
4321 tm->hw[0]->sw_if_index,
4322 ~0, // invalid fib index
4325 FIB_ROUTE_PATH_FLAG_NONE);
4326 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4327 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4328 ai = fib_entry_get_adj(fei);
4330 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4331 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4332 FIB_TEST((ai == fib_entry_get_adj(fei)),
4333 "Import uses same adj as export");
4334 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4335 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4336 FIB_TEST((ai == fib_entry_get_adj(fei)),
4337 "Import uses same adj as export");
4340 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4342 fib_table_entry_delete(fib_index,
4343 &pfx_10_10_10_3_s_32,
4346 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4347 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4349 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4350 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
4352 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4353 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4356 * remove the attached route from the 2nd FIB. expect the imported
4357 * entires to be removed
4359 local_pfx.fp_len = 24;
4360 fib_table_entry_delete(import_fib_index2,
4363 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4364 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4366 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4367 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4368 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4369 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4370 local_pfx.fp_len = 32;
4371 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4372 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4374 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4375 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4376 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4377 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4378 local_pfx.fp_len = 32;
4379 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4380 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4383 * modify the route in FIB1 so it is no longer attached. expect the imported
4384 * entires to be removed
4386 local_pfx.fp_len = 24;
4387 fib_table_entry_update_one_path(import_fib_index1,
4390 FIB_ENTRY_FLAG_NONE,
4392 &pfx_10_10_10_2_s_32.fp_addr,
4393 tm->hw[0]->sw_if_index,
4394 ~0, // invalid fib index
4397 FIB_ROUTE_PATH_FLAG_NONE);
4398 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4399 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4400 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4401 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4402 local_pfx.fp_len = 32;
4403 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4404 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4407 * modify it back to attached. expect the adj-fibs back
4409 local_pfx.fp_len = 24;
4410 fib_table_entry_update_one_path(import_fib_index1,
4413 FIB_ENTRY_FLAG_NONE,
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(import_fib_index1, &pfx_10_10_10_1_s_32);
4422 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4423 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4424 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4425 local_pfx.fp_len = 32;
4426 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4427 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4430 * add a covering attached next-hop for the interface address, so we have
4431 * a valid adj to find when we check the forwarding tables
4433 fib_prefix_t pfx_10_0_0_0_s_8 = {
4435 .fp_proto = FIB_PROTOCOL_IP4,
4438 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4442 fei = fib_table_entry_update_one_path(fib_index,
4445 FIB_ENTRY_FLAG_NONE,
4447 &pfx_10_10_10_3_s_32.fp_addr,
4448 tm->hw[0]->sw_if_index,
4449 ~0, // invalid fib index
4452 FIB_ROUTE_PATH_FLAG_NONE);
4453 dpo = fib_entry_contribute_ip_forwarding(fei);
4456 * remove the route in the export fib. expect the adj-fibs to be removed
4458 local_pfx.fp_len = 24;
4459 fib_table_entry_delete(fib_index,
4461 FIB_SOURCE_INTERFACE);
4463 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4464 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4465 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4466 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4467 local_pfx.fp_len = 32;
4468 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4469 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4472 * the adj-fibs in the export VRF are present in the FIB table,
4473 * but not installed in forwarding, since they have no attached cover.
4474 * Consequently a lookup in the MTRIE gives the adj for the covering
4477 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4478 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4481 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4482 FIB_TEST(lbi == dpo->dpoi_index,
4483 "10.10.10.1 forwards on \n%U not \n%U",
4484 format_load_balance, lbi, 0,
4485 format_dpo_id, dpo, 0);
4486 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4487 FIB_TEST(lbi == dpo->dpoi_index,
4488 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4489 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
4490 FIB_TEST(lbi == dpo->dpoi_index,
4491 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
4494 * add the export prefix back, but not as attached.
4495 * No adj-fibs in export nor import tables
4497 local_pfx.fp_len = 24;
4498 fei = fib_table_entry_update_one_path(fib_index,
4501 FIB_ENTRY_FLAG_NONE,
4503 &pfx_10_10_10_1_s_32.fp_addr,
4504 tm->hw[0]->sw_if_index,
4505 ~0, // invalid fib index
4508 FIB_ROUTE_PATH_FLAG_NONE);
4509 dpo = fib_entry_contribute_ip_forwarding(fei);
4511 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4512 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
4513 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4514 FIB_TEST(lbi == dpo->dpoi_index,
4515 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
4516 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4517 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4518 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4519 FIB_TEST(lbi == dpo->dpoi_index,
4520 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4522 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4523 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4524 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4525 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4526 local_pfx.fp_len = 32;
4527 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4528 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4531 * modify the export prefix so it is attached. expect all covereds to return
4533 local_pfx.fp_len = 24;
4534 fib_table_entry_update_one_path(fib_index,
4537 FIB_ENTRY_FLAG_NONE,
4540 tm->hw[0]->sw_if_index,
4541 ~0, // invalid fib index
4544 FIB_ROUTE_PATH_FLAG_NONE);
4546 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4547 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4548 dpo = fib_entry_contribute_ip_forwarding(fei);
4549 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4550 "Adj-fib1 is not drop in export");
4551 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4552 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4553 local_pfx.fp_len = 32;
4554 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4555 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4556 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4557 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4558 dpo = fib_entry_contribute_ip_forwarding(fei);
4559 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4560 "Adj-fib1 is not drop in export");
4561 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4562 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4563 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4564 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4565 local_pfx.fp_len = 32;
4566 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4567 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4570 * modify the export prefix so connected. no change.
4572 local_pfx.fp_len = 24;
4573 fib_table_entry_update_one_path(fib_index, &local_pfx,
4574 FIB_SOURCE_INTERFACE,
4575 (FIB_ENTRY_FLAG_CONNECTED |
4576 FIB_ENTRY_FLAG_ATTACHED),
4579 tm->hw[0]->sw_if_index,
4583 FIB_ROUTE_PATH_FLAG_NONE);
4585 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4586 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4587 dpo = fib_entry_contribute_ip_forwarding(fei);
4588 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4589 "Adj-fib1 is not drop in export");
4590 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4591 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4592 local_pfx.fp_len = 32;
4593 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4594 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4595 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4596 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4597 dpo = fib_entry_contribute_ip_forwarding(fei);
4598 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4599 "Adj-fib1 is not drop in export");
4600 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4601 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4602 local_pfx.fp_len = 32;
4603 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4604 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4609 fib_table_entry_delete(fib_index,
4612 fib_table_entry_delete(fib_index,
4613 &pfx_10_10_10_1_s_32,
4615 fib_table_entry_delete(fib_index,
4616 &pfx_10_10_10_2_s_32,
4618 local_pfx.fp_len = 32;
4619 fib_table_entry_delete(fib_index,
4621 FIB_SOURCE_INTERFACE);
4622 local_pfx.fp_len = 24;
4623 fib_table_entry_delete(fib_index,
4626 fib_table_entry_delete(fib_index,
4628 FIB_SOURCE_INTERFACE);
4629 local_pfx.fp_len = 24;
4630 fib_table_entry_delete(import_fib_index1,
4634 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
4635 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
4637 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4641 typedef enum fib_test_lb_bucket_type_t_ {
4647 } fib_test_lb_bucket_type_t;
4649 typedef struct fib_test_lb_bucket_t_ {
4650 fib_test_lb_bucket_type_t type;
4681 } fib_test_lb_bucket_t;
4683 #define FIB_TEST_LB(_cond, _comment, _args...) \
4685 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
4691 fib_test_validate_lb_v (const load_balance_t *lb,
4695 const dpo_id_t *dpo;
4698 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
4700 for (bucket = 0; bucket < n_buckets; bucket++)
4702 const fib_test_lb_bucket_t *exp;
4704 exp = va_arg(ap, fib_test_lb_bucket_t*);
4705 dpo = load_balance_get_bucket_i(lb, bucket);
4709 case FT_LB_LABEL_O_ADJ:
4711 const mpls_label_dpo_t *mld;
4713 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4714 "bucket %d stacks on %U",
4716 format_dpo_type, dpo->dpoi_type);
4718 mld = mpls_label_dpo_get(dpo->dpoi_index);
4719 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4721 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4722 exp->label_o_adj.label),
4723 "bucket %d stacks on label %d",
4725 exp->label_o_adj.label);
4727 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4728 exp->label_o_adj.eos),
4729 "bucket %d stacks on label %d %U",
4731 exp->label_o_adj.label,
4732 format_mpls_eos_bit, exp->label_o_adj.eos);
4734 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
4735 "bucket %d label stacks on %U",
4737 format_dpo_type, mld->mld_dpo.dpoi_type);
4739 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
4740 "bucket %d label stacks on adj %d",
4742 exp->label_o_adj.adj);
4745 case FT_LB_LABEL_O_LB:
4747 const mpls_label_dpo_t *mld;
4750 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4751 "bucket %d stacks on %U",
4753 format_dpo_type, dpo->dpoi_type);
4755 mld = mpls_label_dpo_get(dpo->dpoi_index);
4756 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4758 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4759 exp->label_o_lb.label),
4760 "bucket %d stacks on label %d",
4762 exp->label_o_lb.label);
4764 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4765 exp->label_o_lb.eos),
4766 "bucket %d stacks on label %d %U",
4768 exp->label_o_lb.label,
4769 format_mpls_eos_bit, exp->label_o_lb.eos);
4771 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
4772 "bucket %d label stacks on %U",
4774 format_dpo_type, mld->mld_dpo.dpoi_type);
4776 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
4777 "bucket %d label stacks on LB %d",
4779 exp->label_o_lb.lb);
4783 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
4784 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
4785 "bucket %d stacks on %U",
4787 format_dpo_type, dpo->dpoi_type);
4788 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
4789 "bucket %d stacks on adj %d",
4794 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
4795 "bucket %d stacks on %U",
4797 format_dpo_type, dpo->dpoi_type);
4798 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
4799 "bucket %d stacks on lb %d",
4804 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
4805 "bucket %d stacks on %U",
4807 format_dpo_type, dpo->dpoi_type);
4808 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
4809 "bucket %d stacks on drop %d",
4819 fib_test_validate_entry (fib_node_index_t fei,
4820 fib_forward_chain_type_t fct,
4824 const load_balance_t *lb;
4825 dpo_id_t dpo = DPO_NULL;
4832 va_start(ap, n_buckets);
4834 fib_entry_get_prefix(fei, &pfx);
4835 fib_index = fib_entry_get_fib_index(fei);
4836 fib_entry_contribute_forwarding(fei, fct, &dpo);
4838 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
4839 "Entry links to %U",
4840 format_dpo_type, dpo.dpoi_type);
4841 lb = load_balance_get(dpo.dpoi_index);
4843 res = fib_test_validate_lb_v(lb, n_buckets, ap);
4846 * ensure that the LB contributed by the entry is the
4847 * same as the LB in the forwarding tables
4849 switch (pfx.fp_proto)
4851 case FIB_PROTOCOL_IP4:
4852 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
4854 case FIB_PROTOCOL_IP6:
4855 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
4857 case FIB_PROTOCOL_MPLS:
4859 mpls_unicast_header_t hdr = {
4860 .label_exp_s_ttl = 0,
4863 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
4864 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
4865 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
4867 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
4873 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
4874 "Contributed LB = FW LB: %U\n %U",
4875 format_load_balance, fw_lbi, 0,
4876 format_load_balance, dpo.dpoi_index, 0);
4886 * Test the recursive route route handling for GRE tunnels
4889 fib_test_label (void)
4891 fib_node_index_t fei, ai_mpls_10_10_10_1, ai_v4_10_10_11_1, ai_v4_10_10_11_2, ai_mpls_10_10_11_2, ai_mpls_10_10_11_1;
4892 const u32 fib_index = 0;
4897 lb_count = pool_elts(load_balance_pool);
4902 * add interface routes. We'll assume this works. It's more rigorously
4905 fib_prefix_t local0_pfx = {
4907 .fp_proto = FIB_PROTOCOL_IP4,
4911 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4916 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4919 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4920 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4922 fib_table_entry_update_one_path(fib_index, &local0_pfx,
4923 FIB_SOURCE_INTERFACE,
4924 (FIB_ENTRY_FLAG_CONNECTED |
4925 FIB_ENTRY_FLAG_ATTACHED),
4928 tm->hw[0]->sw_if_index,
4932 FIB_ROUTE_PATH_FLAG_NONE);
4933 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
4934 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4935 "attached interface route present");
4937 local0_pfx.fp_len = 32;
4938 fib_table_entry_update_one_path(fib_index, &local0_pfx,
4939 FIB_SOURCE_INTERFACE,
4940 (FIB_ENTRY_FLAG_CONNECTED |
4941 FIB_ENTRY_FLAG_LOCAL),
4944 tm->hw[0]->sw_if_index,
4945 ~0, // invalid fib index
4948 FIB_ROUTE_PATH_FLAG_NONE);
4949 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
4951 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4952 "local interface route present");
4954 fib_prefix_t local1_pfx = {
4956 .fp_proto = FIB_PROTOCOL_IP4,
4960 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
4965 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
4966 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
4968 fib_table_entry_update_one_path(fib_index, &local1_pfx,
4969 FIB_SOURCE_INTERFACE,
4970 (FIB_ENTRY_FLAG_CONNECTED |
4971 FIB_ENTRY_FLAG_ATTACHED),
4974 tm->hw[1]->sw_if_index,
4978 FIB_ROUTE_PATH_FLAG_NONE);
4979 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
4980 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4981 "attached interface route present");
4983 local1_pfx.fp_len = 32;
4984 fib_table_entry_update_one_path(fib_index, &local1_pfx,
4985 FIB_SOURCE_INTERFACE,
4986 (FIB_ENTRY_FLAG_CONNECTED |
4987 FIB_ENTRY_FLAG_LOCAL),
4990 tm->hw[1]->sw_if_index,
4991 ~0, // invalid fib index
4994 FIB_ROUTE_PATH_FLAG_NONE);
4995 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
4997 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4998 "local interface route present");
5000 ip46_address_t nh_10_10_10_1 = {
5002 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5005 ip46_address_t nh_10_10_11_1 = {
5007 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5010 ip46_address_t nh_10_10_11_2 = {
5012 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5016 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5019 tm->hw[1]->sw_if_index);
5020 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5023 tm->hw[1]->sw_if_index);
5024 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5027 tm->hw[0]->sw_if_index);
5028 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5031 tm->hw[1]->sw_if_index);
5032 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5035 tm->hw[1]->sw_if_index);
5038 * Add an etry with one path with a real out-going label
5040 fib_prefix_t pfx_1_1_1_1_s_32 = {
5042 .fp_proto = FIB_PROTOCOL_IP4,
5044 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5047 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5048 .type = FT_LB_LABEL_O_ADJ,
5050 .adj = ai_mpls_10_10_10_1,
5055 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5056 .type = FT_LB_LABEL_O_ADJ,
5058 .adj = ai_mpls_10_10_10_1,
5060 .eos = MPLS_NON_EOS,
5063 fib_table_entry_update_one_path(fib_index,
5066 FIB_ENTRY_FLAG_NONE,
5069 tm->hw[0]->sw_if_index,
5070 ~0, // invalid fib index
5073 FIB_ROUTE_PATH_FLAG_NONE);
5075 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5076 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5078 FIB_TEST(fib_test_validate_entry(fei,
5079 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5081 &l99_eos_o_10_10_10_1),
5082 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5085 * add a path with an implicit NULL label
5087 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5090 .adj = ai_v4_10_10_11_1,
5093 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5096 .adj = ai_mpls_10_10_11_1,
5100 fei = fib_table_entry_path_add(fib_index,
5103 FIB_ENTRY_FLAG_NONE,
5106 tm->hw[1]->sw_if_index,
5107 ~0, // invalid fib index
5109 MPLS_IETF_IMPLICIT_NULL_LABEL,
5110 FIB_ROUTE_PATH_FLAG_NONE);
5112 FIB_TEST(fib_test_validate_entry(fei,
5113 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5115 &l99_eos_o_10_10_10_1,
5117 "1.1.1.1/32 LB 2 buckets via: "
5118 "label 99 over 10.10.10.1, "
5119 "adj over 10.10.11.1");
5122 * assign the route a local label
5124 fib_table_entry_local_label_add(fib_index,
5128 fib_prefix_t pfx_24001_eos = {
5129 .fp_proto = FIB_PROTOCOL_MPLS,
5133 fib_prefix_t pfx_24001_neos = {
5134 .fp_proto = FIB_PROTOCOL_MPLS,
5136 .fp_eos = MPLS_NON_EOS,
5140 * The EOS entry should link to both the paths,
5141 * and use an ip adj for the imp-null
5142 * The NON-EOS entry should link to both the paths,
5143 * and use an mpls adj for the imp-null
5145 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5147 FIB_TEST(fib_test_validate_entry(fei,
5148 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5150 &l99_eos_o_10_10_10_1,
5152 "24001/eos LB 2 buckets via: "
5153 "label 99 over 10.10.10.1, "
5154 "adj over 10.10.11.1");
5157 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5159 FIB_TEST(fib_test_validate_entry(fei,
5160 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5162 &l99_neos_o_10_10_10_1,
5163 &a_mpls_o_10_10_11_1),
5164 "24001/neos LB 1 bucket via: "
5165 "label 99 over 10.10.10.1 ",
5166 "mpls-adj via 10.10.11.1");
5169 * add an unlabelled path, this is excluded from the neos chains,
5171 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5174 .adj = ai_v4_10_10_11_2,
5178 fei = fib_table_entry_path_add(fib_index,
5181 FIB_ENTRY_FLAG_NONE,
5184 tm->hw[1]->sw_if_index,
5185 ~0, // invalid fib index
5188 FIB_ROUTE_PATH_FLAG_NONE);
5190 FIB_TEST(fib_test_validate_entry(fei,
5191 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5192 16, // 3 choices spread over 16 buckets
5193 &l99_eos_o_10_10_10_1,
5194 &l99_eos_o_10_10_10_1,
5195 &l99_eos_o_10_10_10_1,
5196 &l99_eos_o_10_10_10_1,
5197 &l99_eos_o_10_10_10_1,
5198 &l99_eos_o_10_10_10_1,
5209 "1.1.1.1/32 LB 16 buckets via: "
5210 "label 99 over 10.10.10.1, "
5211 "adj over 10.10.11.1",
5212 "adj over 10.10.11.2");
5215 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5217 dpo_id_t non_eos_1_1_1_1 = DPO_NULL;
5218 fib_entry_contribute_forwarding(fei,
5219 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5223 * n-eos has only the 2 labelled paths
5225 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5228 FIB_TEST(fib_test_validate_entry(fei,
5229 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5231 &l99_neos_o_10_10_10_1,
5232 &a_mpls_o_10_10_11_1),
5233 "24001/neos LB 2 buckets via: "
5234 "label 99 over 10.10.10.1, "
5235 "adj-mpls over 10.10.11.2");
5238 * A labelled recursive
5240 fib_prefix_t pfx_2_2_2_2_s_32 = {
5242 .fp_proto = FIB_PROTOCOL_IP4,
5244 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5247 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5248 .type = FT_LB_LABEL_O_LB,
5250 .lb = non_eos_1_1_1_1.dpoi_index,
5256 fib_table_entry_update_one_path(fib_index,
5259 FIB_ENTRY_FLAG_NONE,
5261 &pfx_1_1_1_1_s_32.fp_addr,
5266 FIB_ROUTE_PATH_FLAG_NONE);
5268 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5269 FIB_TEST(fib_test_validate_entry(fei,
5270 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5272 &l1600_eos_o_1_1_1_1),
5273 "2.2.2.2.2/32 LB 1 buckets via: "
5274 "label 1600 over 1.1.1.1");
5276 dpo_id_t dpo_44 = DPO_NULL;
5279 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5280 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5282 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5283 "uRPF check for 2.2.2.2/32 on %d OK",
5284 tm->hw[0]->sw_if_index);
5285 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5286 "uRPF check for 2.2.2.2/32 on %d OK",
5287 tm->hw[1]->sw_if_index);
5288 FIB_TEST(!fib_urpf_check(urpfi, 99),
5289 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5292 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5293 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5294 "Shared uRPF on IP and non-EOS chain");
5299 * we are holding a lock on the non-eos LB of the via-entry.
5300 * do a PIC-core failover by shutting the link of the via-entry.
5302 * shut down the link with the valid label
5304 vnet_sw_interface_set_flags(vnet_get_main(),
5305 tm->hw[0]->sw_if_index,
5308 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5309 FIB_TEST(fib_test_validate_entry(fei,
5310 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5314 "1.1.1.1/32 LB 2 buckets via: "
5315 "adj over 10.10.11.1, ",
5316 "adj-v4 over 10.10.11.2");
5318 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5320 FIB_TEST(fib_test_validate_entry(fei,
5321 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5325 "24001/eos LB 2 buckets via: "
5326 "adj over 10.10.11.1, ",
5327 "adj-v4 over 10.10.11.2");
5329 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5331 FIB_TEST(fib_test_validate_entry(fei,
5332 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5334 &a_mpls_o_10_10_11_1),
5335 "24001/neos LB 1 buckets via: "
5336 "adj-mpls over 10.10.11.2");
5339 * test that the pre-failover load-balance has been in-place
5342 dpo_id_t current = DPO_NULL;
5343 fib_entry_contribute_forwarding(fei,
5344 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5347 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5349 "PIC-core LB inplace modified %U %U",
5350 format_dpo_id, &non_eos_1_1_1_1, 0,
5351 format_dpo_id, ¤t, 0);
5353 dpo_reset(&non_eos_1_1_1_1);
5354 dpo_reset(¤t);
5357 * no-shut the link with the valid label
5359 vnet_sw_interface_set_flags(vnet_get_main(),
5360 tm->hw[0]->sw_if_index,
5361 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5363 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5364 FIB_TEST(fib_test_validate_entry(fei,
5365 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5366 16, // 3 choices spread over 16 buckets
5367 &l99_eos_o_10_10_10_1,
5368 &l99_eos_o_10_10_10_1,
5369 &l99_eos_o_10_10_10_1,
5370 &l99_eos_o_10_10_10_1,
5371 &l99_eos_o_10_10_10_1,
5372 &l99_eos_o_10_10_10_1,
5383 "1.1.1.1/32 LB 16 buckets via: "
5384 "label 99 over 10.10.10.1, "
5385 "adj over 10.10.11.1",
5386 "adj-v4 over 10.10.11.2");
5389 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5391 FIB_TEST(fib_test_validate_entry(fei,
5392 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5393 16, // 3 choices spread over 16 buckets
5394 &l99_eos_o_10_10_10_1,
5395 &l99_eos_o_10_10_10_1,
5396 &l99_eos_o_10_10_10_1,
5397 &l99_eos_o_10_10_10_1,
5398 &l99_eos_o_10_10_10_1,
5399 &l99_eos_o_10_10_10_1,
5410 "24001/eos LB 16 buckets via: "
5411 "label 99 over 10.10.10.1, "
5412 "adj over 10.10.11.1",
5413 "adj-v4 over 10.10.11.2");
5415 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5417 FIB_TEST(fib_test_validate_entry(fei,
5418 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5420 &l99_neos_o_10_10_10_1,
5421 &a_mpls_o_10_10_11_1),
5422 "24001/neos LB 2 buckets via: "
5423 "label 99 over 10.10.10.1, "
5424 "adj-mpls over 10.10.11.2");
5427 * remove the first path with the valid label
5429 fib_table_entry_path_remove(fib_index,
5434 tm->hw[0]->sw_if_index,
5435 ~0, // invalid fib index
5437 FIB_ROUTE_PATH_FLAG_NONE);
5439 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5440 FIB_TEST(fib_test_validate_entry(fei,
5441 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5445 "1.1.1.1/32 LB 2 buckets via: "
5446 "adj over 10.10.11.1",
5447 "adj-v4 over 10.10.11.2");
5449 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5451 FIB_TEST(fib_test_validate_entry(fei,
5452 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5456 "24001/eos LB 2 buckets via: "
5457 "adj over 10.10.11.1",
5458 "adj-v4 over 10.10.11.2");
5460 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5463 FIB_TEST(fib_test_validate_entry(fei,
5464 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5466 &a_mpls_o_10_10_11_1),
5467 "24001/neos LB 1 buckets via: "
5468 "adj-mpls over 10.10.11.2");
5471 * remove the other path with a valid label
5473 fib_test_lb_bucket_t bucket_drop = {
5474 .type = FT_LB_SPECIAL,
5480 fib_table_entry_path_remove(fib_index,
5485 tm->hw[1]->sw_if_index,
5486 ~0, // invalid fib index
5488 FIB_ROUTE_PATH_FLAG_NONE);
5490 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5491 FIB_TEST(fib_test_validate_entry(fei,
5492 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5495 "1.1.1.1/32 LB 1 buckets via: "
5496 "adj over 10.10.11.2");
5498 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5500 FIB_TEST(fib_test_validate_entry(fei,
5501 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5504 "24001/eos LB 1 buckets via: "
5505 "adj over 10.10.11.2");
5507 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5509 FIB_TEST(fib_test_validate_entry(fei,
5510 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5513 "24001/eos LB 1 buckets via: DROP");
5516 * add back the path with the valid label
5518 fib_table_entry_path_add(fib_index,
5521 FIB_ENTRY_FLAG_NONE,
5524 tm->hw[0]->sw_if_index,
5525 ~0, // invalid fib index
5528 FIB_ROUTE_PATH_FLAG_NONE);
5530 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5531 FIB_TEST(fib_test_validate_entry(fei,
5532 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5534 &l99_eos_o_10_10_10_1,
5536 "1.1.1.1/32 LB 2 buckets via: "
5537 "label 99 over 10.10.10.1, "
5538 "adj over 10.10.11.2");
5540 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5542 FIB_TEST(fib_test_validate_entry(fei,
5543 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5545 &l99_eos_o_10_10_10_1,
5547 "24001/eos LB 2 buckets via: "
5548 "label 99 over 10.10.10.1, "
5549 "adj over 10.10.11.2");
5551 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5553 FIB_TEST(fib_test_validate_entry(fei,
5554 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5556 &l99_neos_o_10_10_10_1),
5557 "24001/neos LB 1 buckets via: "
5558 "label 99 over 10.10.10.1");
5561 * remove the local label
5563 fib_table_entry_local_label_remove(fib_index,
5567 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5568 FIB_TEST(fib_test_validate_entry(fei,
5569 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5571 &l99_eos_o_10_10_10_1,
5573 "24001/eos LB 2 buckets via: "
5574 "label 99 over 10.10.10.1, "
5575 "adj over 10.10.11.2");
5577 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5578 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5579 "No more MPLS FIB entries => table removed");
5582 * add another via-entry for the recursive
5584 fib_prefix_t pfx_1_1_1_2_s_32 = {
5586 .fp_proto = FIB_PROTOCOL_IP4,
5588 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5591 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5592 .type = FT_LB_LABEL_O_ADJ,
5594 .adj = ai_mpls_10_10_10_1,
5600 fei = fib_table_entry_update_one_path(fib_index,
5603 FIB_ENTRY_FLAG_NONE,
5606 tm->hw[0]->sw_if_index,
5607 ~0, // invalid fib index
5610 FIB_ROUTE_PATH_FLAG_NONE);
5612 FIB_TEST(fib_test_validate_entry(fei,
5613 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5615 &l101_eos_o_10_10_10_1),
5616 "1.1.1.2/32 LB 1 buckets via: "
5617 "label 101 over 10.10.10.1");
5619 dpo_id_t non_eos_1_1_1_2 = DPO_NULL;
5620 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5622 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5624 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5626 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5629 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5630 .type = FT_LB_LABEL_O_LB,
5632 .lb = non_eos_1_1_1_2.dpoi_index,
5637 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5639 fei = fib_table_entry_path_add(fib_index,
5642 FIB_ENTRY_FLAG_NONE,
5644 &pfx_1_1_1_2_s_32.fp_addr,
5649 FIB_ROUTE_PATH_FLAG_NONE);
5651 FIB_TEST(fib_test_validate_entry(fei,
5652 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5654 &l1600_eos_o_1_1_1_1,
5655 &l1601_eos_o_1_1_1_2),
5656 "2.2.2.2/32 LB 2 buckets via: "
5657 "label 1600 via 1.1,1.1, "
5658 "label 16001 via 1.1.1.2");
5661 * update the via-entry so it no longer has an imp-null path.
5662 * the LB for the recursive can use an imp-null
5664 fei = fib_table_entry_update_one_path(fib_index,
5667 FIB_ENTRY_FLAG_NONE,
5670 tm->hw[1]->sw_if_index,
5671 ~0, // invalid fib index
5673 MPLS_IETF_IMPLICIT_NULL_LABEL,
5674 FIB_ROUTE_PATH_FLAG_NONE);
5676 FIB_TEST(fib_test_validate_entry(fei,
5677 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5680 "1.1.1.2/32 LB 1 buckets via: "
5683 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5684 FIB_TEST(fib_test_validate_entry(fei,
5685 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5687 &l1600_eos_o_1_1_1_1,
5688 &l1601_eos_o_1_1_1_2),
5689 "2.2.2.2/32 LB 2 buckets via: "
5690 "label 1600 via 1.1,1.1, "
5691 "label 16001 via 1.1.1.2");
5694 * update the via-entry so it no longer has labelled paths.
5695 * the LB for the recursive should exclue this via form its LB
5697 fei = fib_table_entry_update_one_path(fib_index,
5700 FIB_ENTRY_FLAG_NONE,
5703 tm->hw[1]->sw_if_index,
5704 ~0, // invalid fib index
5707 FIB_ROUTE_PATH_FLAG_NONE);
5709 FIB_TEST(fib_test_validate_entry(fei,
5710 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5713 "1.1.1.2/32 LB 1 buckets via: "
5716 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5717 FIB_TEST(fib_test_validate_entry(fei,
5718 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5720 &l1600_eos_o_1_1_1_1),
5721 "2.2.2.2/32 LB 1 buckets via: "
5722 "label 1600 via 1.1,1.1");
5724 dpo_reset(&non_eos_1_1_1_1);
5725 dpo_reset(&non_eos_1_1_1_2);
5728 * Add a recursive with no out-labels. We expect to use the IP of the via
5730 fib_prefix_t pfx_2_2_2_3_s_32 = {
5732 .fp_proto = FIB_PROTOCOL_IP4,
5734 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
5737 dpo_id_t ip_1_1_1_1 = DPO_NULL;
5739 fib_table_entry_update_one_path(fib_index,
5742 FIB_ENTRY_FLAG_NONE,
5744 &pfx_1_1_1_1_s_32.fp_addr,
5749 FIB_ROUTE_PATH_FLAG_NONE);
5751 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5753 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5756 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5759 .lb = ip_1_1_1_1.dpoi_index,
5763 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
5764 FIB_TEST(fib_test_validate_entry(fei,
5765 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5768 "2.2.2.2.3/32 LB 1 buckets via: "
5772 * Add a recursive with an imp-null out-label.
5773 * We expect to use the IP of the via
5775 fib_prefix_t pfx_2_2_2_4_s_32 = {
5777 .fp_proto = FIB_PROTOCOL_IP4,
5779 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
5783 fib_table_entry_update_one_path(fib_index,
5786 FIB_ENTRY_FLAG_NONE,
5788 &pfx_1_1_1_1_s_32.fp_addr,
5793 FIB_ROUTE_PATH_FLAG_NONE);
5795 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
5796 FIB_TEST(fib_test_validate_entry(fei,
5797 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5800 "2.2.2.2.4/32 LB 1 buckets via: "
5803 dpo_reset(&ip_1_1_1_1);
5808 fib_table_entry_delete(fib_index,
5812 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5813 FIB_TEST(fib_test_validate_entry(fei,
5814 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5816 &l1600_eos_o_1_1_1_1),
5817 "2.2.2.2/32 LB 1 buckets via: "
5818 "label 1600 via 1.1,1.1");
5820 fib_table_entry_delete(fib_index,
5824 FIB_TEST(fib_test_validate_entry(fei,
5825 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5828 "2.2.2.2/32 LB 1 buckets via: DROP");
5830 fib_table_entry_delete(fib_index,
5833 fib_table_entry_delete(fib_index,
5836 fib_table_entry_delete(fib_index,
5840 adj_unlock(ai_mpls_10_10_10_1);
5841 adj_unlock(ai_mpls_10_10_11_2);
5842 adj_unlock(ai_v4_10_10_11_1);
5843 adj_unlock(ai_v4_10_10_11_2);
5844 adj_unlock(ai_mpls_10_10_11_1);
5846 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5849 local0_pfx.fp_len = 32;
5850 fib_table_entry_delete(fib_index,
5852 FIB_SOURCE_INTERFACE);
5853 local0_pfx.fp_len = 24;
5854 fib_table_entry_delete(fib_index,
5856 FIB_SOURCE_INTERFACE);
5857 local1_pfx.fp_len = 32;
5858 fib_table_entry_delete(fib_index,
5860 FIB_SOURCE_INTERFACE);
5861 local1_pfx.fp_len = 24;
5862 fib_table_entry_delete(fib_index,
5864 FIB_SOURCE_INTERFACE);
5867 * +1 for the drop LB in the MPLS tables.
5869 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
5870 "Load-balance resources freed %d of %d",
5871 lb_count+1, pool_elts(load_balance_pool));
5874 #define N_TEST_CHILDREN 4
5875 #define PARENT_INDEX 0
5877 typedef struct fib_node_test_t_
5882 fib_node_back_walk_ctx_t *ctxs;
5886 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
5888 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
5890 #define FOR_EACH_TEST_CHILD(_tc) \
5891 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
5892 ii < N_TEST_CHILDREN+1; \
5893 ii++, (_tc) = &fib_test_nodes[ii])
5896 fib_test_child_get_node (fib_node_index_t index)
5898 return (&fib_test_nodes[index].node);
5901 static int fib_test_walk_spawns_walks;
5903 static fib_node_back_walk_rc_t
5904 fib_test_child_back_walk_notify (fib_node_t *node,
5905 fib_node_back_walk_ctx_t *ctx)
5907 fib_node_test_t *tc = (fib_node_test_t*) node;
5909 vec_add1(tc->ctxs, *ctx);
5911 if (1 == fib_test_walk_spawns_walks)
5912 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
5913 if (2 == fib_test_walk_spawns_walks)
5914 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
5915 FIB_WALK_PRIORITY_HIGH, ctx);
5917 return (FIB_NODE_BACK_WALK_CONTINUE);
5921 fib_test_child_last_lock_gone (fib_node_t *node)
5923 fib_node_test_t *tc = (fib_node_test_t *)node;
5929 * The FIB walk's graph node virtual function table
5931 static const fib_node_vft_t fib_test_child_vft = {
5932 .fnv_get = fib_test_child_get_node,
5933 .fnv_last_lock = fib_test_child_last_lock_gone,
5934 .fnv_back_walk = fib_test_child_back_walk_notify,
5938 * the function (that should have been static but isn't so I can do this)
5939 * that processes the walk from the async queue,
5941 f64 fib_walk_process_queues(vlib_main_t * vm,
5943 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
5946 fib_test_walk (void)
5948 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
5949 fib_node_test_t *tc;
5953 vm = vlib_get_main();
5954 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
5957 * init a fake node on which we will add children
5959 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
5960 FIB_NODE_TYPE_TEST);
5962 FOR_EACH_TEST_CHILD(tc)
5964 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
5965 fib_node_lock(&tc->node);
5968 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
5970 FIB_NODE_TYPE_TEST, ii);
5974 * enqueue a walk across the parents children.
5976 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
5978 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5979 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5980 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
5981 "Parent has %d children pre-walk",
5982 fib_node_list_get_size(PARENT()->fn_children));
5985 * give the walk a large amount of time so it gets to the end
5987 fib_walk_process_queues(vm, 1);
5989 FOR_EACH_TEST_CHILD(tc)
5991 FIB_TEST(1 == vec_len(tc->ctxs),
5992 "%d child visitsed %d times",
5993 ii, vec_len(tc->ctxs));
5996 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5997 "Queue is empty post walk");
5998 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5999 "Parent has %d children post walk",
6000 fib_node_list_get_size(PARENT()->fn_children));
6003 * walk again. should be no increase in the number of visits, since
6004 * the walk will have terminated.
6006 fib_walk_process_queues(vm, 1);
6008 FOR_EACH_TEST_CHILD(tc)
6010 FIB_TEST(0 == vec_len(tc->ctxs),
6011 "%d child visitsed %d times",
6012 ii, vec_len(tc->ctxs));
6016 * schedule a low and hig priority walk. expect the high to be performed
6018 * schedule the high prio walk first so that it is further from the head
6019 * of the dependency list. that way it won't merge with the low one.
6021 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6022 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6024 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6025 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6026 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6027 FIB_WALK_PRIORITY_LOW, &low_ctx);
6029 fib_walk_process_queues(vm, 1);
6031 FOR_EACH_TEST_CHILD(tc)
6033 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6034 "%d child visitsed by high prio walk", ii);
6035 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6036 "%d child visitsed by low prio walk", ii);
6039 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6040 "Queue is empty post prio walk");
6041 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6042 "Parent has %d children post prio walk",
6043 fib_node_list_get_size(PARENT()->fn_children));
6046 * schedule 2 walks of the same priority that can be megred.
6047 * expect that each child is thus visited only once.
6049 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6050 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6052 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6053 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6054 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6055 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6057 fib_walk_process_queues(vm, 1);
6059 FOR_EACH_TEST_CHILD(tc)
6061 FIB_TEST(1 == vec_len(tc->ctxs),
6062 "%d child visitsed %d times during merge walk",
6063 ii, vec_len(tc->ctxs));
6066 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6067 "Queue is empty post merge walk");
6068 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6069 "Parent has %d children post merge walk",
6070 fib_node_list_get_size(PARENT()->fn_children));
6073 * schedule 2 walks of the same priority that cannot be megred.
6074 * expect that each child is thus visited twice and in the order
6075 * in which the walks were scheduled.
6077 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6078 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6080 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6081 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6082 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6083 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6085 fib_walk_process_queues(vm, 1);
6087 FOR_EACH_TEST_CHILD(tc)
6089 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6090 "%d child visitsed by high prio walk", ii);
6091 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6092 "%d child visitsed by low prio walk", ii);
6095 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6096 "Queue is empty post no-merge walk");
6097 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6098 "Parent has %d children post no-merge walk",
6099 fib_node_list_get_size(PARENT()->fn_children));
6102 * schedule a walk that makes one one child progress.
6103 * we do this by giving the queue draining process zero
6104 * time quanta. it's a do..while loop, so it does something.
6106 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
6108 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6109 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6110 fib_walk_process_queues(vm, 0);
6112 FOR_EACH_TEST_CHILD(tc)
6114 if (ii == N_TEST_CHILDREN)
6116 FIB_TEST(1 == vec_len(tc->ctxs),
6117 "%d child visitsed %d times in zero quanta walk",
6118 ii, vec_len(tc->ctxs));
6122 FIB_TEST(0 == vec_len(tc->ctxs),
6123 "%d child visitsed %d times in 0 quanta walk",
6124 ii, vec_len(tc->ctxs));
6127 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6128 "Queue is not empty post zero quanta walk");
6129 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6130 "Parent has %d children post zero qunta walk",
6131 fib_node_list_get_size(PARENT()->fn_children));
6136 fib_walk_process_queues(vm, 0);
6138 FOR_EACH_TEST_CHILD(tc)
6140 if (ii >= N_TEST_CHILDREN-1)
6142 FIB_TEST(1 == vec_len(tc->ctxs),
6143 "%d child visitsed %d times in 2nd zero quanta walk",
6144 ii, vec_len(tc->ctxs));
6148 FIB_TEST(0 == vec_len(tc->ctxs),
6149 "%d child visitsed %d times in 2nd 0 quanta walk",
6150 ii, vec_len(tc->ctxs));
6153 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6154 "Queue is not empty post zero quanta walk");
6155 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6156 "Parent has %d children post zero qunta walk",
6157 fib_node_list_get_size(PARENT()->fn_children));
6160 * schedule another walk that will catch-up and merge.
6162 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6163 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6164 fib_walk_process_queues(vm, 1);
6166 FOR_EACH_TEST_CHILD(tc)
6168 if (ii >= N_TEST_CHILDREN-1)
6170 FIB_TEST(2 == vec_len(tc->ctxs),
6171 "%d child visitsed %d times in 2nd zero quanta merge walk",
6172 ii, vec_len(tc->ctxs));
6177 FIB_TEST(1 == vec_len(tc->ctxs),
6178 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6179 ii, vec_len(tc->ctxs));
6183 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6184 "Queue is not empty post 2nd zero quanta merge walk");
6185 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6186 "Parent has %d children post 2nd zero qunta merge walk",
6187 fib_node_list_get_size(PARENT()->fn_children));
6190 * park a async walk in the middle of the list, then have an sync walk catch
6191 * it. same expectations as async catches async.
6193 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
6195 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6196 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6198 fib_walk_process_queues(vm, 0);
6199 fib_walk_process_queues(vm, 0);
6201 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6203 FOR_EACH_TEST_CHILD(tc)
6205 if (ii >= N_TEST_CHILDREN-1)
6207 FIB_TEST(2 == vec_len(tc->ctxs),
6208 "%d child visitsed %d times in sync catches async walk",
6209 ii, vec_len(tc->ctxs));
6214 FIB_TEST(1 == vec_len(tc->ctxs),
6215 "%d child visitsed %d times in sync catches async walk",
6216 ii, vec_len(tc->ctxs));
6220 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6221 "Queue is not empty post 2nd zero quanta merge walk");
6222 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6223 "Parent has %d children post 2nd zero qunta merge walk",
6224 fib_node_list_get_size(PARENT()->fn_children));
6227 * make the parent a child of one of its children, thus inducing a routing loop.
6229 fib_test_nodes[PARENT_INDEX].sibling =
6230 fib_node_child_add(FIB_NODE_TYPE_TEST,
6231 1, // the first child
6236 * execute a sync walk from the parent. each child visited spawns more sync
6237 * walks. we expect the walk to terminate.
6239 fib_test_walk_spawns_walks = 1;
6241 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6243 FOR_EACH_TEST_CHILD(tc)
6246 * child 1 - which is last in the list - has the loop.
6247 * the other children a re thus visitsed first. the we meet
6248 * child 1. we go round the loop again, visting the other children.
6249 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6254 FIB_TEST(1 == vec_len(tc->ctxs),
6255 "child %d visitsed %d times during looped sync walk",
6256 ii, vec_len(tc->ctxs));
6260 FIB_TEST(2 == vec_len(tc->ctxs),
6261 "child %d visitsed %d times during looped sync walk",
6262 ii, vec_len(tc->ctxs));
6266 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6267 "Parent has %d children post sync loop walk",
6268 fib_node_list_get_size(PARENT()->fn_children));
6271 * the walk doesn't reach the max depth because the infra knows that sync
6272 * meets sync implies a loop and bails early.
6274 FIB_TEST(high_ctx.fnbw_depth == 9,
6275 "Walk context depth %d post sync loop walk",
6276 high_ctx.fnbw_depth);
6279 * execute an async walk of the graph loop, with each child spawns sync walks
6281 high_ctx.fnbw_depth = 0;
6282 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6283 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6285 fib_walk_process_queues(vm, 1);
6287 FOR_EACH_TEST_CHILD(tc)
6290 * we don't really care how many times the children are visisted, as long as
6291 * it is more than once.
6293 FIB_TEST(1 <= vec_len(tc->ctxs),
6294 "child %d visitsed %d times during looped aync spawns sync walk",
6295 ii, vec_len(tc->ctxs));
6300 * execute an async walk of the graph loop, with each child spawns async walks
6302 fib_test_walk_spawns_walks = 2;
6303 high_ctx.fnbw_depth = 0;
6304 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6305 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6307 fib_walk_process_queues(vm, 1);
6309 FOR_EACH_TEST_CHILD(tc)
6312 * we don't really care how many times the children are visisted, as long as
6313 * it is more than once.
6315 FIB_TEST(1 <= vec_len(tc->ctxs),
6316 "child %d visitsed %d times during looped async spawns async walk",
6317 ii, vec_len(tc->ctxs));
6322 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6323 1, // the first child
6324 fib_test_nodes[PARENT_INDEX].sibling);
6329 FOR_EACH_TEST_CHILD(tc)
6331 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6333 fib_node_deinit(&tc->node);
6334 fib_node_unlock(&tc->node);
6336 fib_node_deinit(PARENT());
6339 * The parent will be destroyed when the last lock on it goes.
6340 * this test ensures all the walk objects are unlocking it.
6342 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6343 "Parent was destroyed");
6347 lfib_test_deagg (void)
6349 const mpls_label_t deag_label = 50;
6350 const u32 lfib_index = 0;
6351 const u32 fib_index = 0;
6352 dpo_id_t dpo = DPO_NULL;
6353 const dpo_id_t *dpo1;
6354 fib_node_index_t lfe;
6360 lb_count = pool_elts(load_balance_pool);
6362 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6366 * MPLS enable an interface so we get the MPLS table created
6368 mpls_sw_interface_enable_disable(&mpls_main,
6369 tm->hw[0]->sw_if_index,
6373 * Test the specials stack properly.
6375 fib_prefix_t exp_null_v6_pfx = {
6376 .fp_proto = FIB_PROTOCOL_MPLS,
6378 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6379 .fp_payload_proto = DPO_PROTO_IP6,
6381 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
6382 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
6384 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6385 format_mpls_eos_bit, MPLS_EOS);
6386 fib_entry_contribute_forwarding(lfe,
6387 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6389 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6390 lkd = lookup_dpo_get(dpo1->dpoi_index);
6392 FIB_TEST((fib_index == lkd->lkd_fib_index),
6393 "%U/%U is deag in %d %U",
6394 format_mpls_unicast_label, deag_label,
6395 format_mpls_eos_bit, MPLS_EOS,
6397 format_dpo_id, &dpo, 0);
6398 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6399 "%U/%U is dst deag",
6400 format_mpls_unicast_label, deag_label,
6401 format_mpls_eos_bit, MPLS_EOS);
6402 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
6403 "%U/%U is lookup in interface's table",
6404 format_mpls_unicast_label, deag_label,
6405 format_mpls_eos_bit, MPLS_EOS);
6406 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
6407 "%U/%U is %U dst deag",
6408 format_mpls_unicast_label, deag_label,
6409 format_mpls_eos_bit, MPLS_EOS,
6410 format_dpo_proto, lkd->lkd_proto);
6414 * A route deag route for EOS
6416 fib_prefix_t pfx = {
6417 .fp_proto = FIB_PROTOCOL_MPLS,
6419 .fp_label = deag_label,
6420 .fp_payload_proto = DPO_PROTO_IP4,
6422 lfe = fib_table_entry_path_add(lfib_index,
6425 FIB_ENTRY_FLAG_NONE,
6432 FIB_ROUTE_PATH_FLAG_NONE);
6434 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6436 format_mpls_unicast_label, deag_label,
6437 format_mpls_eos_bit, MPLS_EOS);
6439 fib_entry_contribute_forwarding(lfe,
6440 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6442 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6443 lkd = lookup_dpo_get(dpo1->dpoi_index);
6445 FIB_TEST((fib_index == lkd->lkd_fib_index),
6446 "%U/%U is deag in %d %U",
6447 format_mpls_unicast_label, deag_label,
6448 format_mpls_eos_bit, MPLS_EOS,
6450 format_dpo_id, &dpo, 0);
6451 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6452 "%U/%U is dst deag",
6453 format_mpls_unicast_label, deag_label,
6454 format_mpls_eos_bit, MPLS_EOS);
6455 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
6456 "%U/%U is %U dst deag",
6457 format_mpls_unicast_label, deag_label,
6458 format_mpls_eos_bit, MPLS_EOS,
6459 format_dpo_proto, lkd->lkd_proto);
6461 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6463 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6465 "%U/%U not present",
6466 format_mpls_unicast_label, deag_label,
6467 format_mpls_eos_bit, MPLS_EOS);
6470 * A route deag route for non-EOS
6472 pfx.fp_eos = MPLS_NON_EOS;
6473 lfe = fib_table_entry_path_add(lfib_index,
6476 FIB_ENTRY_FLAG_NONE,
6483 FIB_ROUTE_PATH_FLAG_NONE);
6485 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6487 format_mpls_unicast_label, deag_label,
6488 format_mpls_eos_bit, MPLS_NON_EOS);
6490 fib_entry_contribute_forwarding(lfe,
6491 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6493 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6494 lkd = lookup_dpo_get(dpo1->dpoi_index);
6496 FIB_TEST((fib_index == lkd->lkd_fib_index),
6497 "%U/%U is deag in %d %U",
6498 format_mpls_unicast_label, deag_label,
6499 format_mpls_eos_bit, MPLS_NON_EOS,
6501 format_dpo_id, &dpo, 0);
6502 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6503 "%U/%U is dst deag",
6504 format_mpls_unicast_label, deag_label,
6505 format_mpls_eos_bit, MPLS_NON_EOS);
6507 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
6508 "%U/%U is %U dst deag",
6509 format_mpls_unicast_label, deag_label,
6510 format_mpls_eos_bit, MPLS_NON_EOS,
6511 format_dpo_proto, lkd->lkd_proto);
6513 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6515 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6517 "%U/%U not present",
6518 format_mpls_unicast_label, deag_label,
6519 format_mpls_eos_bit, MPLS_EOS);
6522 mpls_sw_interface_enable_disable(&mpls_main,
6523 tm->hw[0]->sw_if_index,
6528 * +1 for the drop LB in the MPLS tables.
6530 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6531 "Load-balance resources freed %d of %d",
6532 lb_count+1, pool_elts(load_balance_pool));
6535 static clib_error_t *
6536 lfib_test (vlib_main_t * vm,
6537 unformat_input_t * input,
6538 vlib_cli_command_t * cmd_arg)
6540 fib_test_mk_intf(4);
6547 static clib_error_t *
6548 fib_test (vlib_main_t * vm,
6549 unformat_input_t * input,
6550 vlib_cli_command_t * cmd_arg)
6552 fib_test_mk_intf(4);
6554 if (unformat (input, "ip"))
6559 else if (unformat (input, "gre"))
6563 else if (unformat (input, "label"))
6567 else if (unformat (input, "ae"))
6571 else if (unformat (input, "walk"))
6578 * These walk UT aren't run as part of the full suite, since the
6579 * fib-walk process must be disabled in order for the tests to work
6593 VLIB_CLI_COMMAND (test_fib_command, static) = {
6595 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6596 .function = fib_test,
6599 VLIB_CLI_COMMAND (test_lfib_command, static) = {
6600 .path = "test lfib",
6601 .short_help = "mpls label fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6602 .function = lfib_test,
6606 fib_test_init (vlib_main_t *vm)
6611 VLIB_INIT_FUNCTION (fib_test_init);