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),
229 * In the default table check for the presence and correct forwarding
230 * of the special entries
232 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
233 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
234 const ip_adjacency_t *adj;
235 const load_balance_t *lb;
241 ip46_address_t nh_10_10_10_1 = {
242 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
245 ip46_address_t nh_10_10_10_2 = {
246 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
251 /* Find or create FIB table 11 */
252 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
254 for (ii = 0; ii < 4; ii++)
256 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
259 fib_prefix_t pfx_0_0_0_0_s_0 = {
261 .fp_proto = FIB_PROTOCOL_IP4,
271 .fp_proto = FIB_PROTOCOL_IP4,
279 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
281 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
282 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
283 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
284 "Default route is DROP");
287 fei = fib_table_lookup(fib_index, &pfx);
288 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
289 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
290 "all 0s route is DROP");
292 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
294 fei = fib_table_lookup(fib_index, &pfx);
295 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
296 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
297 "all 1s route is DROP");
299 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
301 fei = fib_table_lookup(fib_index, &pfx);
302 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
303 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
304 "all-mcast route is DROP");
306 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
308 fei = fib_table_lookup(fib_index, &pfx);
309 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
310 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
311 "class-e route is DROP");
314 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
315 * all of which are special sourced and so none of which share path-lists.
316 * There are also 6 entries, and 6 non-shared path-lists, in the v6 default
320 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
321 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
322 fib_path_list_pool_size());
323 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
324 fib_entry_pool_size());
327 * add interface routes.
328 * validate presence of /24 attached and /32 recieve.
329 * test for the presence of the receive address in the glean and local adj
331 fib_prefix_t local_pfx = {
333 .fp_proto = FIB_PROTOCOL_IP4,
336 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
341 fib_table_entry_update_one_path(fib_index, &local_pfx,
342 FIB_SOURCE_INTERFACE,
343 (FIB_ENTRY_FLAG_CONNECTED |
344 FIB_ENTRY_FLAG_ATTACHED),
347 tm->hw[0]->sw_if_index,
348 ~0, // invalid fib index
351 FIB_ROUTE_PATH_FLAG_NONE);
352 fei = fib_table_lookup(fib_index, &local_pfx);
353 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
354 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
355 fib_entry_get_flags(fei)),
356 "Flags set on attached interface");
358 ai = fib_entry_get_adj(fei);
359 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
361 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
362 "attached interface adj is glean");
363 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
364 &adj->sub_type.glean.receive_addr)),
365 "attached interface adj is receive ok");
367 local_pfx.fp_len = 32;
368 fib_table_entry_update_one_path(fib_index, &local_pfx,
369 FIB_SOURCE_INTERFACE,
370 (FIB_ENTRY_FLAG_CONNECTED |
371 FIB_ENTRY_FLAG_LOCAL),
374 tm->hw[0]->sw_if_index,
375 ~0, // invalid fib index
378 FIB_ROUTE_PATH_FLAG_NONE);
379 fei = fib_table_lookup(fib_index, &local_pfx);
380 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
381 fib_entry_get_flags(fei)),
382 "Flags set on local interface");
384 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
386 dpo = fib_entry_contribute_ip_forwarding(fei);
387 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
388 "RPF list for local length 0");
389 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
390 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
391 "local interface adj is local");
392 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
394 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
396 "local interface adj is receive ok");
398 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
400 FIB_SOURCE_INTERFACE)),
401 "2 Interface Source'd prefixes");
404 * +2 interface routes +2 non-shared path-lists
406 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
407 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
408 fib_path_list_pool_size());
409 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
410 fib_entry_pool_size());
413 * Modify the default route to be via an adj not yet known.
414 * this sources the defalut route with the API source, which is
415 * a higher preference to the DEFAULT_ROUTE source
417 pfx.fp_addr.ip4.as_u32 = 0;
419 fib_table_entry_path_add(fib_index, &pfx,
424 tm->hw[0]->sw_if_index,
425 ~0, // invalid fib index
428 FIB_ROUTE_PATH_FLAG_NONE);
429 fei = fib_table_lookup(fib_index, &pfx);
430 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
431 "Flags set on API route");
433 FIB_TEST((fei == dfrt), "default route same index");
434 ai = fib_entry_get_adj(fei);
435 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
437 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
438 "adj is incomplete");
439 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
440 "adj nbr next-hop ok");
441 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
444 "1 API Source'd prefixes");
447 * find the adj in the shared db
449 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
452 tm->hw[0]->sw_if_index);
453 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
454 adj_unlock(locked_ai);
457 * +1 shared path-list
459 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
460 fib_path_list_db_size());
461 FIB_TEST((NBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
462 fib_path_list_pool_size());
463 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
464 fib_entry_pool_size());
467 * remove the API source from the default route. We expected
468 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
470 pfx.fp_addr.ip4.as_u32 = 0;
472 fib_table_entry_path_remove(fib_index, &pfx,
476 tm->hw[0]->sw_if_index,
477 ~0, // non-recursive path, so no FIB index
479 FIB_ROUTE_PATH_FLAG_NONE);
481 fei = fib_table_lookup(fib_index, &pfx);
483 FIB_TEST((fei == dfrt), "default route same index");
484 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
485 "Default route is DROP");
488 * -1 shared-path-list
490 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
491 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
492 fib_path_list_pool_size());
493 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
494 fib_entry_pool_size());
497 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
499 fib_prefix_t pfx_10_10_10_1_s_32 = {
501 .fp_proto = FIB_PROTOCOL_IP4,
504 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
507 fib_prefix_t pfx_10_10_10_2_s_32 = {
509 .fp_proto = FIB_PROTOCOL_IP4,
512 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
515 fib_prefix_t pfx_11_11_11_11_s_32 = {
517 .fp_proto = FIB_PROTOCOL_IP4,
520 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
524 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
526 ip46_address_t nh_12_12_12_12 = {
527 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
529 adj_index_t ai_12_12_12_12;
532 * Add a route via an incomplete ADJ. then complete the ADJ
533 * Expect the route LB is updated to use complete adj type.
535 fei = fib_table_entry_update_one_path(fib_index,
536 &pfx_11_11_11_11_s_32,
538 FIB_ENTRY_FLAG_ATTACHED,
540 &pfx_10_10_10_1_s_32.fp_addr,
541 tm->hw[0]->sw_if_index,
542 ~0, // invalid fib index
545 FIB_ROUTE_PATH_FLAG_NONE);
547 dpo = fib_entry_contribute_ip_forwarding(fei);
548 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
549 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
550 "11.11.11.11/32 via incomplete adj");
552 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
554 &pfx_10_10_10_1_s_32.fp_addr,
555 tm->hw[0]->sw_if_index);
556 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
557 adj = adj_get(ai_01);
558 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
559 "adj is incomplete");
560 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
561 &adj->sub_type.nbr.next_hop)),
562 "adj nbr next-hop ok");
564 adj_nbr_update_rewrite(ai_01, eth_addr);
565 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
567 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
568 &adj->sub_type.nbr.next_hop)),
569 "adj nbr next-hop ok");
570 ai = fib_entry_get_adj(fei);
571 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
573 dpo = fib_entry_contribute_ip_forwarding(fei);
574 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
575 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
576 "11.11.11.11/32 via complete adj");
577 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
578 tm->hw[0]->sw_if_index),
579 "RPF list for adj-fib contains adj");
581 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
584 tm->hw[1]->sw_if_index);
585 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
586 adj = adj_get(ai_12_12_12_12);
587 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
588 "adj is incomplete");
589 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
590 &adj->sub_type.nbr.next_hop)),
591 "adj nbr next-hop ok");
592 adj_nbr_update_rewrite(ai_12_12_12_12, eth_addr);
593 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
599 fei = fib_table_entry_update_one_path(fib_index,
600 &pfx_10_10_10_1_s_32,
602 FIB_ENTRY_FLAG_ATTACHED,
604 &pfx_10_10_10_1_s_32.fp_addr,
605 tm->hw[0]->sw_if_index,
606 ~0, // invalid fib index
609 FIB_ROUTE_PATH_FLAG_NONE);
610 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
611 "Flags set on adj-fib");
612 ai = fib_entry_get_adj(fei);
613 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
615 fib_table_entry_path_remove(fib_index,
616 &pfx_11_11_11_11_s_32,
619 &pfx_10_10_10_1_s_32.fp_addr,
620 tm->hw[0]->sw_if_index,
621 ~0, // invalid fib index
623 FIB_ROUTE_PATH_FLAG_NONE);
627 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
629 &pfx_10_10_10_2_s_32.fp_addr,
630 tm->hw[0]->sw_if_index);
631 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
632 adj = adj_get(ai_02);
633 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
634 "adj is incomplete");
635 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
636 &adj->sub_type.nbr.next_hop)),
637 "adj nbr next-hop ok");
639 adj_nbr_update_rewrite(ai_02, eth_addr);
640 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
642 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
643 &adj->sub_type.nbr.next_hop)),
644 "adj nbr next-hop ok");
645 FIB_TEST((ai_01 != ai_02), "ADJs are different");
647 fib_table_entry_update_one_path(fib_index,
648 &pfx_10_10_10_2_s_32,
652 &pfx_10_10_10_2_s_32.fp_addr,
653 tm->hw[0]->sw_if_index,
654 ~0, // invalid fib index
657 FIB_ROUTE_PATH_FLAG_NONE);
659 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
660 ai = fib_entry_get_adj(fei);
661 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
664 * +2 adj-fibs, and their non-shared path-lists
666 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
667 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
668 fib_path_list_pool_size());
669 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
670 fib_entry_pool_size());
673 * Add 2 routes via the first ADJ. ensure path-list sharing
675 fib_prefix_t pfx_1_1_1_1_s_32 = {
677 .fp_proto = FIB_PROTOCOL_IP4,
680 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
684 fib_table_entry_path_add(fib_index,
690 tm->hw[0]->sw_if_index,
691 ~0, // invalid fib index
694 FIB_ROUTE_PATH_FLAG_NONE);
695 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
696 ai = fib_entry_get_adj(fei);
697 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
700 * +1 entry and a shared path-list
702 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
703 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
704 fib_path_list_pool_size());
705 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
706 fib_entry_pool_size());
709 fib_prefix_t pfx_1_1_2_0_s_24 = {
711 .fp_proto = FIB_PROTOCOL_IP4,
713 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
717 fib_table_entry_path_add(fib_index,
723 tm->hw[0]->sw_if_index,
724 ~0, // invalid fib index
727 FIB_ROUTE_PATH_FLAG_NONE);
728 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
729 ai = fib_entry_get_adj(fei);
730 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
735 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
736 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
737 fib_path_list_pool_size());
738 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
739 fib_entry_pool_size());
742 * modify 1.1.2.0/24 to use multipath.
744 fib_table_entry_path_add(fib_index,
750 tm->hw[0]->sw_if_index,
751 ~0, // invalid fib index
754 FIB_ROUTE_PATH_FLAG_NONE);
755 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
756 dpo = fib_entry_contribute_ip_forwarding(fei);
757 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
758 1, tm->hw[0]->sw_if_index),
759 "RPF list for 1.1.2.0/24 contains both adjs");
761 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
762 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
763 FIB_TEST((ai_01 == dpo1->dpoi_index),
764 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
765 ai_01, dpo1->dpoi_index);
767 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
768 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
769 FIB_TEST((ai_02 == dpo1->dpoi_index),
770 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
775 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
776 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
777 fib_path_list_pool_size());
778 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
779 fib_entry_pool_size());
784 fib_table_entry_path_remove(fib_index,
789 tm->hw[0]->sw_if_index,
792 FIB_ROUTE_PATH_FLAG_NONE);
793 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
794 dpo = fib_entry_contribute_ip_forwarding(fei);
795 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
796 1, tm->hw[0]->sw_if_index),
797 "RPF list for 1.1.2.0/24 contains one adj");
799 ai = fib_entry_get_adj(fei);
800 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
805 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
806 fib_path_list_db_size());
807 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
808 fib_path_list_pool_size());
809 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
810 fib_entry_pool_size());
813 * Add 2 recursive routes:
814 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
815 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
817 fib_prefix_t bgp_100_pfx = {
819 .fp_proto = FIB_PROTOCOL_IP4,
821 /* 100.100.100.100/32 */
822 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
826 ip46_address_t nh_1_1_1_1 = {
827 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
830 fei = fib_table_entry_path_add(fib_index,
836 ~0, // no index provided.
837 fib_index, // nexthop in same fib as route
840 FIB_ROUTE_PATH_FLAG_NONE);
842 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
843 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
844 tm->hw[0]->sw_if_index),
845 "RPF list for adj-fib contains adj");
848 * +1 entry and +1 shared-path-list
850 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
851 fib_path_list_db_size());
852 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
853 fib_path_list_pool_size());
854 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
855 fib_entry_pool_size());
857 fib_prefix_t bgp_101_pfx = {
859 .fp_proto = FIB_PROTOCOL_IP4,
861 /* 100.100.100.101/32 */
862 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
866 fib_table_entry_path_add(fib_index,
872 ~0, // no index provided.
873 fib_index, // nexthop in same fib as route
876 FIB_ROUTE_PATH_FLAG_NONE);
878 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
879 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
880 tm->hw[0]->sw_if_index),
881 "RPF list for adj-fib contains adj");
884 * +1 entry, but the recursive path-list is shared.
886 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
887 fib_path_list_db_size());
888 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
889 fib_path_list_pool_size());
890 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
891 fib_entry_pool_size());
894 * An EXCLUSIVE route; one where the user (me) provides the exclusive
895 * adjacency through which the route will resovle
897 fib_prefix_t ex_pfx = {
899 .fp_proto = FIB_PROTOCOL_IP4,
902 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
906 fib_table_entry_special_add(fib_index,
909 FIB_ENTRY_FLAG_EXCLUSIVE,
911 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
912 FIB_TEST((ai == fib_entry_get_adj(fei)),
913 "Exclusive route links to user adj");
915 fib_table_entry_special_remove(fib_index,
918 FIB_TEST(FIB_NODE_INDEX_INVALID ==
919 fib_table_lookup_exact_match(fib_index, &ex_pfx),
920 "Exclusive reoute removed");
923 * An EXCLUSIVE route; one where the user (me) provides the exclusive
924 * adjacency through which the route will resovle
926 dpo_id_t ex_dpo = DPO_NULL;
928 lookup_dpo_add_or_lock_w_fib_index(fib_index,
930 LOOKUP_INPUT_DST_ADDR,
931 LOOKUP_TABLE_FROM_CONFIG,
934 fib_table_entry_special_dpo_add(fib_index,
937 FIB_ENTRY_FLAG_EXCLUSIVE,
939 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
940 dpo = fib_entry_contribute_ip_forwarding(fei);
941 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
942 "exclusive remote uses lookup DPO");
944 fib_table_entry_special_remove(fib_index,
947 FIB_TEST(FIB_NODE_INDEX_INVALID ==
948 fib_table_lookup_exact_match(fib_index, &ex_pfx),
949 "Exclusive reoute removed");
953 * Add a recursive route:
954 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
956 fib_prefix_t bgp_200_pfx = {
958 .fp_proto = FIB_PROTOCOL_IP4,
960 /* 200.200.200.200/32 */
961 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
965 fib_prefix_t pfx_1_1_1_2_s_32 = {
967 .fp_proto = FIB_PROTOCOL_IP4,
969 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
973 fib_table_entry_path_add(fib_index,
978 &pfx_1_1_1_2_s_32.fp_addr,
979 ~0, // no index provided.
980 fib_index, // nexthop in same fib as route
983 FIB_ROUTE_PATH_FLAG_NONE);
985 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
988 * the adj should be recursive via drop, since the route resolves via
989 * the default route, which is itself a DROP
991 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
992 dpo1 = fib_entry_contribute_ip_forwarding(fei);
993 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
994 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
995 "RPF list for 1.1.1.2/32 contains 0 adjs");
998 * +2 entry and +1 shared-path-list
1000 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1001 fib_path_list_db_size());
1002 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1003 fib_path_list_pool_size());
1004 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1005 fib_entry_pool_size());
1008 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1009 * The paths are sort by NH first. in this case the the path with greater
1010 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1012 fib_prefix_t pfx_1_2_3_4_s_32 = {
1014 .fp_proto = FIB_PROTOCOL_IP4,
1016 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1019 fib_table_entry_path_add(fib_index,
1022 FIB_ENTRY_FLAG_NONE,
1025 tm->hw[0]->sw_if_index,
1029 FIB_ROUTE_PATH_FLAG_NONE);
1030 fei = fib_table_entry_path_add(fib_index,
1033 FIB_ENTRY_FLAG_NONE,
1036 tm->hw[1]->sw_if_index,
1040 FIB_ROUTE_PATH_FLAG_NONE);
1042 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1043 dpo = fib_entry_contribute_ip_forwarding(fei);
1044 lb = load_balance_get(dpo->dpoi_index);
1045 FIB_TEST((lb->lb_n_buckets == 4),
1046 "1.2.3.4/32 LB has %d bucket",
1049 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1050 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1051 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1052 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1054 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1055 tm->hw[0]->sw_if_index,
1056 tm->hw[1]->sw_if_index),
1057 "RPF list for 1.2.3.4/32 contains both adjs");
1061 * Unequal Cost load-balance. 4:1 ratio.
1062 * fits in a 16 bucket LB with ratio 13:3
1064 fib_prefix_t pfx_1_2_3_5_s_32 = {
1066 .fp_proto = FIB_PROTOCOL_IP4,
1068 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1071 fib_table_entry_path_add(fib_index,
1074 FIB_ENTRY_FLAG_NONE,
1077 tm->hw[1]->sw_if_index,
1081 FIB_ROUTE_PATH_FLAG_NONE);
1082 fei = fib_table_entry_path_add(fib_index,
1085 FIB_ENTRY_FLAG_NONE,
1088 tm->hw[0]->sw_if_index,
1092 FIB_ROUTE_PATH_FLAG_NONE);
1094 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1095 dpo = fib_entry_contribute_ip_forwarding(fei);
1096 lb = load_balance_get(dpo->dpoi_index);
1097 FIB_TEST((lb->lb_n_buckets == 16),
1098 "1.2.3.5/32 LB has %d bucket",
1101 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1102 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1103 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1104 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1105 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1106 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1107 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1108 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1109 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1110 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1111 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1112 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1113 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1114 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1115 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1116 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1118 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1119 tm->hw[0]->sw_if_index,
1120 tm->hw[1]->sw_if_index),
1121 "RPF list for 1.2.3.4/32 contains both adjs");
1124 * A recursive via the two unequal cost entries
1126 fib_prefix_t bgp_44_s_32 = {
1128 .fp_proto = FIB_PROTOCOL_IP4,
1130 /* 200.200.200.201/32 */
1131 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1134 fei = fib_table_entry_path_add(fib_index,
1137 FIB_ENTRY_FLAG_NONE,
1139 &pfx_1_2_3_4_s_32.fp_addr,
1144 FIB_ROUTE_PATH_FLAG_NONE);
1145 fei = fib_table_entry_path_add(fib_index,
1148 FIB_ENTRY_FLAG_NONE,
1150 &pfx_1_2_3_5_s_32.fp_addr,
1155 FIB_ROUTE_PATH_FLAG_NONE);
1157 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1158 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1159 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1160 tm->hw[0]->sw_if_index,
1161 tm->hw[1]->sw_if_index),
1162 "RPF list for 1.2.3.4/32 contains both adjs");
1165 * test the uRPF check functions
1167 dpo_id_t dpo_44 = DPO_NULL;
1170 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1171 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
1173 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
1174 "uRPF check for 68.68.68.68/32 on %d OK",
1175 tm->hw[0]->sw_if_index);
1176 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
1177 "uRPF check for 68.68.68.68/32 on %d OK",
1178 tm->hw[1]->sw_if_index);
1179 FIB_TEST(!fib_urpf_check(urpfi, 99),
1180 "uRPF check for 68.68.68.68/32 on 99 not-OK",
1184 fib_table_entry_delete(fib_index,
1187 fib_table_entry_delete(fib_index,
1190 fib_table_entry_delete(fib_index,
1195 * Add a recursive route:
1196 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
1198 fib_prefix_t bgp_201_pfx = {
1200 .fp_proto = FIB_PROTOCOL_IP4,
1202 /* 200.200.200.201/32 */
1203 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1207 fib_prefix_t pfx_1_1_1_200_s_32 = {
1209 .fp_proto = FIB_PROTOCOL_IP4,
1211 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1215 fib_table_entry_path_add(fib_index,
1218 FIB_ENTRY_FLAG_NONE,
1220 &pfx_1_1_1_200_s_32.fp_addr,
1221 ~0, // no index provided.
1222 fib_index, // nexthop in same fib as route
1225 FIB_ROUTE_PATH_FLAG_NONE);
1227 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1229 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1230 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1231 "Flags set on RR via non-attached");
1232 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1233 "RPF list for BGP route empty");
1236 * +2 entry (BGP & RR) and +1 shared-path-list
1238 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1239 fib_path_list_db_size());
1240 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1241 fib_path_list_pool_size());
1242 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1243 fib_entry_pool_size());
1246 * insert a route that covers the missing 1.1.1.2/32. we epxect
1247 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
1249 fib_prefix_t pfx_1_1_1_0_s_24 = {
1251 .fp_proto = FIB_PROTOCOL_IP4,
1254 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1258 fib_table_entry_path_add(fib_index,
1261 FIB_ENTRY_FLAG_NONE,
1264 tm->hw[0]->sw_if_index,
1265 ~0, // invalid fib index
1268 FIB_ROUTE_PATH_FLAG_NONE);
1269 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
1270 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1271 ai = fib_entry_get_adj(fei);
1272 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
1273 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1274 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1275 ai = fib_entry_get_adj(fei);
1276 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
1277 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1278 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1279 ai = fib_entry_get_adj(fei);
1280 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
1283 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
1285 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1286 fib_path_list_db_size());
1287 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1288 fib_path_list_pool_size());
1289 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1290 fib_entry_pool_size());
1293 * the recursive adj for 200.200.200.200 should be updated.
1295 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1296 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1297 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
1298 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1299 tm->hw[0]->sw_if_index),
1300 "RPF list for BGP route has itf index 0");
1303 * insert a more specific route than 1.1.1.0/24 that also covers the
1304 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
1305 * 200.200.200.200 to resolve through it.
1307 fib_prefix_t pfx_1_1_1_0_s_28 = {
1309 .fp_proto = FIB_PROTOCOL_IP4,
1312 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
1316 fib_table_entry_path_add(fib_index,
1319 FIB_ENTRY_FLAG_NONE,
1322 tm->hw[0]->sw_if_index,
1323 ~0, // invalid fib index
1326 FIB_ROUTE_PATH_FLAG_NONE);
1327 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
1328 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1329 ai = fib_entry_get_adj(fei);
1330 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
1333 * +1 entry. +1 shared path-list
1335 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
1336 fib_path_list_db_size());
1337 FIB_TEST((NBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
1338 fib_path_list_pool_size());
1339 FIB_TEST((NBR+14 == fib_entry_pool_size()), "entry pool size is %d",
1340 fib_entry_pool_size());
1343 * the recursive adj for 200.200.200.200 should be updated.
1344 * 200.200.200.201 remains unchanged.
1346 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1347 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1350 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
1352 fib_table_entry_path_remove(fib_index,
1357 tm->hw[0]->sw_if_index,
1360 FIB_ROUTE_PATH_FLAG_NONE);
1361 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
1362 FIB_NODE_INDEX_INVALID),
1363 "1.1.1.0/28 removed");
1364 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
1365 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
1366 "1.1.1.0/28 lookup via /24");
1367 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1368 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1371 * -1 entry. -1 shared path-list
1373 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1374 fib_path_list_db_size());
1375 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1376 fib_path_list_pool_size());
1377 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
1378 fib_entry_pool_size());
1381 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
1383 fib_table_entry_path_remove(fib_index,
1388 tm->hw[0]->sw_if_index,
1391 FIB_ROUTE_PATH_FLAG_NONE);
1392 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
1393 FIB_NODE_INDEX_INVALID),
1394 "1.1.1.0/24 removed");
1396 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1397 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1398 "1.1.1.2/32 route is DROP");
1399 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
1400 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1401 "1.1.1.200/32 route is DROP");
1403 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1404 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1409 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1410 fib_path_list_db_size());
1411 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1412 fib_path_list_pool_size());
1413 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1414 fib_entry_pool_size());
1417 * insert the missing 1.1.1.2/32
1419 fei = fib_table_entry_path_add(fib_index,
1422 FIB_ENTRY_FLAG_NONE,
1425 tm->hw[0]->sw_if_index,
1426 ~0, // invalid fib index
1429 FIB_ROUTE_PATH_FLAG_NONE);
1430 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1431 ai = fib_entry_get_adj(fei);
1432 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
1434 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1435 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1438 * no change. 1.1.1.2/32 was already there RR sourced.
1440 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1441 fib_path_list_db_size());
1442 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1443 fib_path_list_pool_size());
1444 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1445 fib_entry_pool_size());
1448 * remove 200.200.200.201/32 which does not have a valid via FIB
1450 fib_table_entry_path_remove(fib_index,
1454 &pfx_1_1_1_200_s_32.fp_addr,
1455 ~0, // no index provided.
1458 FIB_ROUTE_PATH_FLAG_NONE);
1461 * -2 entries (BGP and RR). -1 shared path-list;
1463 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1464 FIB_NODE_INDEX_INVALID),
1465 "200.200.200.201/32 removed");
1466 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
1467 FIB_NODE_INDEX_INVALID),
1468 "1.1.1.200/32 removed");
1470 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1471 fib_path_list_db_size());
1472 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1473 fib_path_list_pool_size());
1474 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1475 fib_entry_pool_size());
1478 * remove 200.200.200.200/32 which does have a valid via FIB
1480 fib_table_entry_path_remove(fib_index,
1484 &pfx_1_1_1_2_s_32.fp_addr,
1485 ~0, // no index provided.
1488 FIB_ROUTE_PATH_FLAG_NONE);
1490 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1491 FIB_NODE_INDEX_INVALID),
1492 "200.200.200.200/32 removed");
1493 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
1494 FIB_NODE_INDEX_INVALID),
1495 "1.1.1.2/32 still present");
1498 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
1500 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1501 fib_path_list_db_size());
1502 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1503 fib_path_list_pool_size());
1504 FIB_TEST((NBR+9 == fib_entry_pool_size()), "entry pool size is %d",
1505 fib_entry_pool_size());
1508 * A recursive prefix that has a 2 path load-balance.
1509 * It also shares a next-hop with other BGP prefixes and hence
1510 * test the ref counting of RR sourced prefixes and 2 level LB.
1512 const fib_prefix_t bgp_102 = {
1514 .fp_proto = FIB_PROTOCOL_IP4,
1516 /* 100.100.100.101/32 */
1517 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
1520 fib_table_entry_path_add(fib_index,
1523 FIB_ENTRY_FLAG_NONE,
1525 &pfx_1_1_1_1_s_32.fp_addr,
1526 ~0, // no index provided.
1527 fib_index, // same as route
1530 FIB_ROUTE_PATH_FLAG_NONE);
1531 fib_table_entry_path_add(fib_index,
1534 FIB_ENTRY_FLAG_NONE,
1536 &pfx_1_1_1_2_s_32.fp_addr,
1537 ~0, // no index provided.
1538 fib_index, // same as route's FIB
1541 FIB_ROUTE_PATH_FLAG_NONE);
1542 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1543 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
1544 dpo = fib_entry_contribute_ip_forwarding(fei);
1546 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
1547 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1548 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
1549 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1551 lb = load_balance_get(dpo->dpoi_index);
1552 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
1553 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1554 "First via 10.10.10.1");
1555 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
1556 "Second via 10.10.10.1");
1558 fib_table_entry_path_remove(fib_index,
1562 &pfx_1_1_1_1_s_32.fp_addr,
1563 ~0, // no index provided.
1564 fib_index, // same as route's FIB
1566 FIB_ROUTE_PATH_FLAG_NONE);
1567 fib_table_entry_path_remove(fib_index,
1571 &pfx_1_1_1_2_s_32.fp_addr,
1572 ~0, // no index provided.
1573 fib_index, // same as route's FIB
1575 FIB_ROUTE_PATH_FLAG_NONE);
1576 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
1577 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
1580 * remove the remaining recursives
1582 fib_table_entry_path_remove(fib_index,
1586 &pfx_1_1_1_1_s_32.fp_addr,
1587 ~0, // no index provided.
1588 fib_index, // same as route's FIB
1590 FIB_ROUTE_PATH_FLAG_NONE);
1591 fib_table_entry_path_remove(fib_index,
1595 &pfx_1_1_1_1_s_32.fp_addr,
1596 ~0, // no index provided.
1597 fib_index, // same as route's FIB
1599 FIB_ROUTE_PATH_FLAG_NONE);
1600 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
1601 FIB_NODE_INDEX_INVALID),
1602 "100.100.100.100/32 removed");
1603 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
1604 FIB_NODE_INDEX_INVALID),
1605 "100.100.100.101/32 removed");
1608 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
1610 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1611 fib_path_list_db_size());
1612 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1613 fib_path_list_pool_size());
1614 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1615 fib_entry_pool_size());
1618 * Add a recursive route via a connected cover, using an adj-fib that does exist
1620 fib_table_entry_path_add(fib_index,
1623 FIB_ENTRY_FLAG_NONE,
1626 ~0, // no index provided.
1627 fib_index, // Same as route's FIB
1630 FIB_ROUTE_PATH_FLAG_NONE);
1633 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
1635 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1636 fib_path_list_db_size());
1637 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1638 fib_path_list_pool_size());
1639 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1640 fib_entry_pool_size());
1642 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
1643 dpo = fib_entry_contribute_ip_forwarding(fei);
1645 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
1646 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1648 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1649 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
1651 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1652 "Flags set on RR via existing attached");
1655 * Add a recursive route via a connected cover, using and adj-fib that does
1658 ip46_address_t nh_10_10_10_3 = {
1659 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
1661 fib_prefix_t pfx_10_10_10_3 = {
1663 .fp_proto = FIB_PROTOCOL_IP4,
1664 .fp_addr = nh_10_10_10_3,
1667 fib_table_entry_path_add(fib_index,
1670 FIB_ENTRY_FLAG_NONE,
1673 ~0, // no index provided.
1677 FIB_ROUTE_PATH_FLAG_NONE);
1680 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
1681 * one unshared non-recursive via 10.10.10.3
1683 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1684 fib_path_list_db_size());
1685 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1686 fib_path_list_pool_size());
1687 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1688 fib_entry_pool_size());
1690 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1693 tm->hw[0]->sw_if_index);
1695 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
1696 dpo = fib_entry_contribute_ip_forwarding(fei);
1697 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
1698 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1700 ai = fib_entry_get_adj(fei);
1701 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
1702 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
1703 fib_entry_get_flags(fei)),
1704 "Flags set on RR via non-existing attached");
1706 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
1707 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
1712 * remove the recursives
1714 fib_table_entry_path_remove(fib_index,
1719 ~0, // no index provided.
1720 fib_index, // same as route's FIB
1722 FIB_ROUTE_PATH_FLAG_NONE);
1723 fib_table_entry_path_remove(fib_index,
1728 ~0, // no index provided.
1729 fib_index, // same as route's FIB
1731 FIB_ROUTE_PATH_FLAG_NONE);
1733 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
1734 FIB_NODE_INDEX_INVALID),
1735 "200.200.200.201/32 removed");
1736 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
1737 FIB_NODE_INDEX_INVALID),
1738 "200.200.200.200/32 removed");
1739 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
1740 FIB_NODE_INDEX_INVALID),
1741 "10.10.10.3/32 removed");
1744 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
1745 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
1747 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1748 fib_path_list_db_size());
1749 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1750 fib_path_list_pool_size());
1751 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1752 fib_entry_pool_size());
1757 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
1759 fib_prefix_t pfx_5_5_5_5_s_32 = {
1761 .fp_proto = FIB_PROTOCOL_IP4,
1763 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
1766 fib_prefix_t pfx_5_5_5_6_s_32 = {
1768 .fp_proto = FIB_PROTOCOL_IP4,
1770 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
1773 fib_prefix_t pfx_5_5_5_7_s_32 = {
1775 .fp_proto = FIB_PROTOCOL_IP4,
1777 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
1781 fib_table_entry_path_add(fib_index,
1784 FIB_ENTRY_FLAG_NONE,
1786 &pfx_5_5_5_6_s_32.fp_addr,
1787 ~0, // no index provided.
1791 FIB_ROUTE_PATH_FLAG_NONE);
1792 fib_table_entry_path_add(fib_index,
1795 FIB_ENTRY_FLAG_NONE,
1797 &pfx_5_5_5_7_s_32.fp_addr,
1798 ~0, // no index provided.
1802 FIB_ROUTE_PATH_FLAG_NONE);
1803 fib_table_entry_path_add(fib_index,
1806 FIB_ENTRY_FLAG_NONE,
1808 &pfx_5_5_5_5_s_32.fp_addr,
1809 ~0, // no index provided.
1813 FIB_ROUTE_PATH_FLAG_NONE);
1815 * +3 entries, +3 shared path-list
1817 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1818 fib_path_list_db_size());
1819 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1820 fib_path_list_pool_size());
1821 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1822 fib_entry_pool_size());
1825 * All the entries have only looped paths, so they are all drop
1827 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1828 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1829 "LB for 5.5.5.7/32 is via adj for DROP");
1830 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1831 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1832 "LB for 5.5.5.5/32 is via adj for DROP");
1833 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1834 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1835 "LB for 5.5.5.6/32 is via adj for DROP");
1838 * provide 5.5.5.6/32 with alternate path.
1839 * this will allow only 5.5.5.6/32 to forward with this path, the others
1840 * are still drop since the loop is still present.
1842 fib_table_entry_path_add(fib_index,
1845 FIB_ENTRY_FLAG_NONE,
1848 tm->hw[0]->sw_if_index,
1852 FIB_ROUTE_PATH_FLAG_NONE);
1855 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1856 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1858 lb = load_balance_get(dpo1->dpoi_index);
1859 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
1861 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1862 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1863 FIB_TEST((ai_01 == dpo2->dpoi_index),
1864 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
1866 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1867 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1868 "LB for 5.5.5.7/32 is via adj for DROP");
1869 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1870 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1871 "LB for 5.5.5.5/32 is via adj for DROP");
1874 * remove the alternate path for 5.5.5.6/32
1877 fib_table_entry_path_remove(fib_index,
1882 tm->hw[0]->sw_if_index,
1885 FIB_ROUTE_PATH_FLAG_NONE);
1887 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1888 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1889 "LB for 5.5.5.7/32 is via adj for DROP");
1890 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1891 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1892 "LB for 5.5.5.5/32 is via adj for DROP");
1893 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1894 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1895 "LB for 5.5.5.6/32 is via adj for DROP");
1898 * break the loop by giving 5.5.5.5/32 a new set of paths
1899 * expect all to forward via this new path.
1901 fib_table_entry_update_one_path(fib_index,
1904 FIB_ENTRY_FLAG_NONE,
1907 tm->hw[0]->sw_if_index,
1908 ~0, // invalid fib index
1911 FIB_ROUTE_PATH_FLAG_NONE);
1913 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1914 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1915 lb = load_balance_get(dpo1->dpoi_index);
1916 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
1918 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
1919 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
1920 FIB_TEST((ai_01 == dpo2->dpoi_index),
1921 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
1923 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
1924 dpo2 = fib_entry_contribute_ip_forwarding(fei);
1926 lb = load_balance_get(dpo2->dpoi_index);
1927 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1928 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
1929 "5.5.5.5.7 via 5.5.5.5");
1931 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
1932 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1934 lb = load_balance_get(dpo1->dpoi_index);
1935 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
1936 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
1937 "5.5.5.5.6 via 5.5.5.7");
1940 * revert back to the loop. so we can remove the prefixes with
1943 fib_table_entry_update_one_path(fib_index,
1946 FIB_ENTRY_FLAG_NONE,
1948 &pfx_5_5_5_6_s_32.fp_addr,
1949 ~0, // no index provided.
1953 FIB_ROUTE_PATH_FLAG_NONE);
1955 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
1956 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1957 "LB for 5.5.5.7/32 is via adj for DROP");
1958 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
1959 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1960 "LB for 5.5.5.5/32 is via adj for DROP");
1961 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
1962 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1963 "LB for 5.5.5.6/32 is via adj for DROP");
1966 * remove all the 5.5.5.x/32 prefixes
1968 fib_table_entry_path_remove(fib_index,
1972 &pfx_5_5_5_6_s_32.fp_addr,
1973 ~0, // no index provided.
1974 fib_index, // same as route's FIB
1976 FIB_ROUTE_PATH_FLAG_NONE);
1977 fib_table_entry_path_remove(fib_index,
1981 &pfx_5_5_5_7_s_32.fp_addr,
1982 ~0, // no index provided.
1983 fib_index, // same as route's FIB
1985 FIB_ROUTE_PATH_FLAG_NONE);
1986 fib_table_entry_path_remove(fib_index,
1990 &pfx_5_5_5_5_s_32.fp_addr,
1991 ~0, // no index provided.
1992 fib_index, // same as route's FIB
1994 FIB_ROUTE_PATH_FLAG_NONE);
1995 fib_table_entry_path_remove(fib_index,
2000 ~0, // no index provided.
2001 fib_index, // same as route's FIB
2003 FIB_ROUTE_PATH_FLAG_NONE);
2006 * -3 entries, -3 shared path-list
2008 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2009 fib_path_list_db_size());
2010 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2011 fib_path_list_pool_size());
2012 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2013 fib_entry_pool_size());
2016 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2018 fib_table_entry_path_add(fib_index,
2021 FIB_ENTRY_FLAG_NONE,
2023 &pfx_5_5_5_6_s_32.fp_addr,
2024 ~0, // no index provided.
2028 FIB_ROUTE_PATH_FLAG_NONE);
2029 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2030 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2031 "1-level 5.5.5.6/32 loop is via adj for DROP");
2033 fib_table_entry_path_remove(fib_index,
2037 &pfx_5_5_5_6_s_32.fp_addr,
2038 ~0, // no index provided.
2039 fib_index, // same as route's FIB
2041 FIB_ROUTE_PATH_FLAG_NONE);
2042 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2043 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2044 "1-level 5.5.5.6/32 loop is removed");
2047 * add-remove test. no change.
2049 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2050 fib_path_list_db_size());
2051 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2052 fib_path_list_pool_size());
2053 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2054 fib_entry_pool_size());
2057 * A recursive route with recursion constraints.
2058 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2060 fib_table_entry_path_add(fib_index,
2063 FIB_ENTRY_FLAG_NONE,
2070 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2072 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2073 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2075 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2076 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2078 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2079 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2082 * save the load-balance. we expect it to be inplace modified
2084 lb = load_balance_get(dpo1->dpoi_index);
2087 * add a covering prefix for the via fib that would otherwise serve
2088 * as the resolving route when the host is removed
2090 fib_table_entry_path_add(fib_index,
2093 FIB_ENTRY_FLAG_NONE,
2096 tm->hw[0]->sw_if_index,
2097 ~0, // invalid fib index
2100 FIB_ROUTE_PATH_FLAG_NONE);
2101 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
2102 ai = fib_entry_get_adj(fei);
2103 FIB_TEST((ai == ai_01),
2104 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
2107 * remove the host via FIB - expect the BGP prefix to be drop
2109 fib_table_entry_path_remove(fib_index,
2114 tm->hw[0]->sw_if_index,
2115 ~0, // invalid fib index
2117 FIB_ROUTE_PATH_FLAG_NONE);
2119 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2120 "adj for 200.200.200.200/32 is recursive via adj for DROP");
2123 * add the via-entry host reoute back. expect to resolve again
2125 fib_table_entry_path_add(fib_index,
2128 FIB_ENTRY_FLAG_NONE,
2131 tm->hw[0]->sw_if_index,
2132 ~0, // invalid fib index
2135 FIB_ROUTE_PATH_FLAG_NONE);
2136 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2137 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2140 * add another path for the recursive. it will then have 2.
2142 fib_prefix_t pfx_1_1_1_3_s_32 = {
2144 .fp_proto = FIB_PROTOCOL_IP4,
2146 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
2149 fib_table_entry_path_add(fib_index,
2152 FIB_ENTRY_FLAG_NONE,
2155 tm->hw[0]->sw_if_index,
2156 ~0, // invalid fib index
2159 FIB_ROUTE_PATH_FLAG_NONE);
2161 fib_table_entry_path_add(fib_index,
2164 FIB_ENTRY_FLAG_NONE,
2166 &pfx_1_1_1_3_s_32.fp_addr,
2171 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2173 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2174 dpo = fib_entry_contribute_ip_forwarding(fei);
2176 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2177 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2178 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2179 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2180 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2181 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2182 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2183 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2186 * expect the lb-map used by the recursive's load-balance is using both buckets
2188 load_balance_map_t *lbm;
2191 lb = load_balance_get(dpo->dpoi_index);
2193 load_balance_map_lock(lbmi);
2194 lbm = load_balance_map_get(lbmi);
2196 FIB_TEST(lbm->lbm_buckets[0] == 0,
2197 "LB maps's bucket 0 is %d",
2198 lbm->lbm_buckets[0]);
2199 FIB_TEST(lbm->lbm_buckets[1] == 1,
2200 "LB maps's bucket 1 is %d",
2201 lbm->lbm_buckets[1]);
2204 * withdraw one of the /32 via-entrys.
2205 * that ECMP path will be unresolved and forwarding should continue on the
2206 * other available path. this is an iBGP PIC edge failover.
2207 * Test the forwarding changes without re-fetching the adj from the
2208 * recursive entry. this ensures its the same one that is updated; i.e. an
2211 fib_table_entry_path_remove(fib_index,
2216 tm->hw[0]->sw_if_index,
2217 ~0, // invalid fib index
2219 FIB_ROUTE_PATH_FLAG_NONE);
2221 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2222 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
2223 "post PIC 200.200.200.200/32 was inplace modified");
2225 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
2226 "post PIC adj for 200.200.200.200/32 is recursive"
2227 " via adj for 1.1.1.3");
2230 * the LB maps that was locked above should have been modified to remove
2231 * the path that was down, and thus its bucket points to a path that is
2234 FIB_TEST(lbm->lbm_buckets[0] == 1,
2235 "LB maps's bucket 0 is %d",
2236 lbm->lbm_buckets[0]);
2237 FIB_TEST(lbm->lbm_buckets[1] == 1,
2238 "LB maps's bucket 1 is %d",
2239 lbm->lbm_buckets[1]);
2241 load_balance_map_unlock(lb->lb_map);
2244 * add it back. again
2246 fib_table_entry_path_add(fib_index,
2249 FIB_ENTRY_FLAG_NONE,
2252 tm->hw[0]->sw_if_index,
2253 ~0, // invalid fib index
2256 FIB_ROUTE_PATH_FLAG_NONE);
2258 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
2259 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2260 "via adj for 1.1.1.1");
2261 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
2262 "post PIC recovery adj for 200.200.200.200/32 is recursive "
2263 "via adj for 1.1.1.3");
2265 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2266 dpo = fib_entry_contribute_ip_forwarding(fei);
2267 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2268 "post PIC 200.200.200.200/32 was inplace modified");
2271 * add a 3rd path. this makes the LB 16 buckets.
2273 fib_table_entry_path_add(fib_index,
2276 FIB_ENTRY_FLAG_NONE,
2278 &pfx_1_1_1_2_s_32.fp_addr,
2283 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2285 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2286 dpo = fib_entry_contribute_ip_forwarding(fei);
2287 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2288 "200.200.200.200/32 was inplace modified for 3rd path");
2289 FIB_TEST(16 == lb->lb_n_buckets,
2290 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
2293 load_balance_map_lock(lbmi);
2294 lbm = load_balance_map_get(lbmi);
2296 for (ii = 0; ii < 16; ii++)
2298 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2299 "LB Map for 200.200.200.200/32 at %d is %d",
2300 ii, lbm->lbm_buckets[ii]);
2304 * trigger PIC by removing the first via-entry
2305 * the first 6 buckets of the map should map to the next 6
2307 fib_table_entry_path_remove(fib_index,
2312 tm->hw[0]->sw_if_index,
2315 FIB_ROUTE_PATH_FLAG_NONE);
2317 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2318 dpo = fib_entry_contribute_ip_forwarding(fei);
2319 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
2320 "200.200.200.200/32 was inplace modified for 3rd path");
2321 FIB_TEST(2 == lb->lb_n_buckets,
2322 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
2324 for (ii = 0; ii < 6; ii++)
2326 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
2327 "LB Map for 200.200.200.200/32 at %d is %d",
2328 ii, lbm->lbm_buckets[ii]);
2330 for (ii = 6; ii < 16; ii++)
2332 FIB_TEST(lbm->lbm_buckets[ii] == ii,
2333 "LB Map for 200.200.200.200/32 at %d is %d",
2334 ii, lbm->lbm_buckets[ii]);
2341 fib_table_entry_path_add(fib_index,
2344 FIB_ENTRY_FLAG_NONE,
2347 tm->hw[0]->sw_if_index,
2351 FIB_ROUTE_PATH_FLAG_NONE);
2353 fib_table_entry_path_remove(fib_index,
2357 &pfx_1_1_1_2_s_32.fp_addr,
2361 MPLS_LABEL_INVALID);
2362 fib_table_entry_path_remove(fib_index,
2370 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2371 fib_table_entry_path_remove(fib_index,
2375 &pfx_1_1_1_3_s_32.fp_addr,
2379 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2380 fib_table_entry_delete(fib_index,
2383 fib_table_entry_delete(fib_index,
2386 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2387 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
2388 "1.1.1.1/28 removed");
2389 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2390 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
2391 "1.1.1.3/32 removed");
2392 FIB_TEST((FIB_NODE_INDEX_INVALID ==
2393 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
2394 "200.200.200.200/32 removed");
2397 * add-remove test. no change.
2399 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2400 fib_path_list_db_size());
2401 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2402 fib_path_list_pool_size());
2403 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2404 fib_entry_pool_size());
2407 * A route whose paths are built up iteratively and then removed
2410 fib_prefix_t pfx_4_4_4_4_s_32 = {
2412 .fp_proto = FIB_PROTOCOL_IP4,
2415 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
2419 fib_table_entry_path_add(fib_index,
2422 FIB_ENTRY_FLAG_NONE,
2425 tm->hw[0]->sw_if_index,
2429 FIB_ROUTE_PATH_FLAG_NONE);
2430 fib_table_entry_path_add(fib_index,
2433 FIB_ENTRY_FLAG_NONE,
2436 tm->hw[0]->sw_if_index,
2440 FIB_ROUTE_PATH_FLAG_NONE);
2441 fib_table_entry_path_add(fib_index,
2444 FIB_ENTRY_FLAG_NONE,
2447 tm->hw[0]->sw_if_index,
2451 FIB_ROUTE_PATH_FLAG_NONE);
2452 FIB_TEST(FIB_NODE_INDEX_INVALID !=
2453 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2454 "4.4.4.4/32 present");
2456 fib_table_entry_delete(fib_index,
2459 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2460 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2461 "4.4.4.4/32 removed");
2464 * add-remove test. no change.
2466 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2467 fib_path_list_db_size());
2468 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2469 fib_path_list_pool_size());
2470 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2471 fib_entry_pool_size());
2474 * A route with multiple paths at once
2476 fib_route_path_t *r_paths = NULL;
2478 for (ii = 0; ii < 4; ii++)
2480 fib_route_path_t r_path = {
2481 .frp_proto = FIB_PROTOCOL_IP4,
2483 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
2485 .frp_sw_if_index = tm->hw[0]->sw_if_index,
2487 .frp_fib_index = ~0,
2489 vec_add1(r_paths, r_path);
2492 fib_table_entry_update(fib_index,
2495 FIB_ENTRY_FLAG_NONE,
2498 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2499 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2500 dpo = fib_entry_contribute_ip_forwarding(fei);
2502 lb = load_balance_get(dpo->dpoi_index);
2503 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
2505 fib_table_entry_delete(fib_index,
2508 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2509 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2510 "4.4.4.4/32 removed");
2514 * add-remove test. no change.
2516 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2517 fib_path_list_db_size());
2518 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2519 fib_path_list_pool_size());
2520 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2521 fib_entry_pool_size());
2524 * A route deag route
2526 fib_table_entry_path_add(fib_index,
2529 FIB_ENTRY_FLAG_NONE,
2536 FIB_ROUTE_PATH_FLAG_NONE);
2538 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
2539 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
2541 dpo = fib_entry_contribute_ip_forwarding(fei);
2542 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2543 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
2545 FIB_TEST((fib_index == lkd->lkd_fib_index),
2546 "4.4.4.4/32 is deag in %d %U",
2548 format_dpo_id, dpo, 0);
2550 fib_table_entry_delete(fib_index,
2553 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2554 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
2555 "4.4.4.4/32 removed");
2559 * add-remove test. no change.
2561 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2562 fib_path_list_db_size());
2563 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2564 fib_path_list_pool_size());
2565 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2566 fib_entry_pool_size());
2570 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
2571 * all of which are via 10.10.10.1, Itf1
2573 fib_table_entry_path_remove(fib_index,
2578 tm->hw[0]->sw_if_index,
2581 FIB_ROUTE_PATH_FLAG_NONE);
2582 fib_table_entry_path_remove(fib_index,
2587 tm->hw[0]->sw_if_index,
2590 FIB_ROUTE_PATH_FLAG_NONE);
2591 fib_table_entry_path_remove(fib_index,
2596 tm->hw[0]->sw_if_index,
2599 FIB_ROUTE_PATH_FLAG_NONE);
2601 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2602 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
2603 "1.1.1.1/32 removed");
2604 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2605 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
2606 "1.1.1.2/32 removed");
2607 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2608 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
2609 "1.1.2.0/24 removed");
2612 * -3 entries and -1 shared path-list
2614 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2615 fib_path_list_db_size());
2616 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2617 fib_path_list_pool_size());
2618 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2619 fib_entry_pool_size());
2622 * An attached-host route. Expect to link to the incomplete adj
2624 fib_prefix_t pfx_4_1_1_1_s_32 = {
2626 .fp_proto = FIB_PROTOCOL_IP4,
2629 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
2632 fib_table_entry_path_add(fib_index,
2635 FIB_ENTRY_FLAG_NONE,
2638 tm->hw[0]->sw_if_index,
2642 FIB_ROUTE_PATH_FLAG_NONE);
2644 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
2645 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
2646 ai = fib_entry_get_adj(fei);
2648 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2650 &pfx_4_1_1_1_s_32.fp_addr,
2651 tm->hw[0]->sw_if_index);
2652 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
2656 * +1 entry and +1 shared path-list
2658 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2659 fib_path_list_db_size());
2660 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2661 fib_path_list_pool_size());
2662 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
2663 fib_entry_pool_size());
2665 fib_table_entry_delete(fib_index,
2669 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2670 fib_path_list_db_size());
2671 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
2672 fib_path_list_pool_size());
2673 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
2674 fib_entry_pool_size());
2677 * add a v6 prefix via v4 next-hops
2679 fib_prefix_t pfx_2001_s_64 = {
2681 .fp_proto = FIB_PROTOCOL_IP6,
2683 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
2686 fei = fib_table_entry_path_add(0, //default v6 table
2689 FIB_ENTRY_FLAG_NONE,
2692 tm->hw[0]->sw_if_index,
2696 FIB_ROUTE_PATH_FLAG_NONE);
2698 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
2699 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
2700 ai = fib_entry_get_adj(fei);
2702 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
2703 "2001::/64 via ARP-adj");
2704 FIB_TEST((adj->ia_link == FIB_LINK_IP6),
2705 "2001::/64 is link type v6");
2706 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
2707 "2001::/64 ADJ-adj is NH proto v4");
2708 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
2711 * add a uRPF exempt prefix:
2713 * - it's forwarding is drop
2714 * - it's uRPF list is not empty
2715 * - the uRPF list for the default route (it's cover) is empty
2717 fei = fib_table_entry_special_add(fib_index,
2719 FIB_SOURCE_URPF_EXEMPT,
2720 FIB_ENTRY_FLAG_DROP,
2722 dpo = fib_entry_contribute_ip_forwarding(fei);
2723 FIB_TEST(load_balance_is_drop(dpo),
2724 "uRPF exempt 4.1.1.1/32 DROP");
2725 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
2726 "uRPF list for exempt prefix has itf index 0");
2727 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
2728 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2729 "uRPF list for 0.0.0.0/0 empty");
2731 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
2737 fib_table_entry_delete(fib_index,
2738 &pfx_10_10_10_1_s_32,
2740 fib_table_entry_delete(fib_index,
2741 &pfx_10_10_10_2_s_32,
2743 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2744 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
2745 "10.10.10.1/32 adj-fib removed");
2746 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2747 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
2748 "10.10.10.2/32 adj-fib removed");
2751 * -2 entries and -2 non-shared path-list
2753 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2754 fib_path_list_db_size());
2755 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
2756 fib_path_list_pool_size());
2757 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
2758 fib_entry_pool_size());
2761 * unlock the adjacencies for which this test provided a rewrite.
2762 * These are the last locks on these adjs. they should thus go away.
2766 adj_unlock(ai_12_12_12_12);
2768 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2773 * remove the interface prefixes
2775 local_pfx.fp_len = 32;
2776 fib_table_entry_special_remove(fib_index, &local_pfx,
2777 FIB_SOURCE_INTERFACE);
2778 fei = fib_table_lookup(fib_index, &local_pfx);
2780 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2781 fib_table_lookup_exact_match(fib_index, &local_pfx),
2782 "10.10.10.10/32 adj-fib removed");
2784 local_pfx.fp_len = 24;
2785 fib_table_entry_delete(fib_index, &local_pfx,
2786 FIB_SOURCE_INTERFACE);
2788 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2789 fib_table_lookup_exact_match(fib_index, &local_pfx),
2790 "10.10.10.10/24 adj-fib removed");
2793 * -2 entries and -2 non-shared path-list
2795 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2796 fib_path_list_db_size());
2797 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
2798 fib_path_list_pool_size());
2799 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
2800 fib_entry_pool_size());
2803 * Last but not least, remove the VRF
2805 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2808 "NO API Source'd prefixes");
2809 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2812 "NO RR Source'd prefixes");
2813 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
2815 FIB_SOURCE_INTERFACE)),
2816 "NO INterface Source'd prefixes");
2818 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
2820 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
2821 fib_path_list_db_size());
2822 FIB_TEST((NBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
2823 fib_path_list_pool_size());
2824 FIB_TEST((NBR-5 == fib_entry_pool_size()), "entry pool size is %d",
2825 fib_entry_pool_size());
2826 FIB_TEST((NBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
2827 pool_elts(fib_urpf_list_pool));
2836 * In the default table check for the presence and correct forwarding
2837 * of the special entries
2839 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
2840 const dpo_id_t *dpo, *dpo_drop;
2841 const ip_adjacency_t *adj;
2842 const receive_dpo_t *rd;
2847 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
2850 /* via 2001:0:0:1::2 */
2851 ip46_address_t nh_2001_2 = {
2854 [0] = clib_host_to_net_u64(0x2001000000000001),
2855 [1] = clib_host_to_net_u64(0x0000000000000002),
2862 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
2864 /* Find or create FIB table 11 */
2865 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
2867 for (ii = 0; ii < 4; ii++)
2869 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
2872 fib_prefix_t pfx_0_0 = {
2874 .fp_proto = FIB_PROTOCOL_IP6,
2882 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
2883 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
2884 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
2885 "Default route is DROP");
2887 dpo = fib_entry_contribute_ip_forwarding(dfrt);
2888 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2891 &pfx_0_0.fp_addr.ip6)),
2892 "default-route; fwd and non-fwd tables match");
2894 // FIXME - check specials.
2897 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
2898 * each with 6 entries. All entries are special so no path-list sharing.
2901 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
2902 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is %d",
2903 fib_path_list_pool_size());
2904 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
2905 fib_entry_pool_size());
2908 * add interface routes.
2909 * validate presence of /64 attached and /128 recieve.
2910 * test for the presence of the receive address in the glean and local adj
2912 * receive on 2001:0:0:1::1/128
2914 fib_prefix_t local_pfx = {
2916 .fp_proto = FIB_PROTOCOL_IP6,
2920 [0] = clib_host_to_net_u64(0x2001000000000001),
2921 [1] = clib_host_to_net_u64(0x0000000000000001),
2927 fib_table_entry_update_one_path(fib_index, &local_pfx,
2928 FIB_SOURCE_INTERFACE,
2929 (FIB_ENTRY_FLAG_CONNECTED |
2930 FIB_ENTRY_FLAG_ATTACHED),
2933 tm->hw[0]->sw_if_index,
2937 FIB_ROUTE_PATH_FLAG_NONE);
2938 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
2940 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
2942 ai = fib_entry_get_adj(fei);
2943 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
2945 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
2946 "attached interface adj is glean");
2947 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
2948 &adj->sub_type.glean.receive_addr)),
2949 "attached interface adj is receive ok");
2950 dpo = fib_entry_contribute_ip_forwarding(fei);
2951 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2954 &local_pfx.fp_addr.ip6)),
2955 "attached-route; fwd and non-fwd tables match");
2957 local_pfx.fp_len = 128;
2958 fib_table_entry_update_one_path(fib_index, &local_pfx,
2959 FIB_SOURCE_INTERFACE,
2960 (FIB_ENTRY_FLAG_CONNECTED |
2961 FIB_ENTRY_FLAG_LOCAL),
2964 tm->hw[0]->sw_if_index,
2965 ~0, // invalid fib index
2968 FIB_ROUTE_PATH_FLAG_NONE);
2969 fei = fib_table_lookup(fib_index, &local_pfx);
2971 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
2973 dpo = fib_entry_contribute_ip_forwarding(fei);
2974 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
2975 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
2976 "local interface adj is local");
2977 rd = receive_dpo_get(dpo->dpoi_index);
2979 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
2981 "local interface adj is receive ok");
2983 dpo = fib_entry_contribute_ip_forwarding(fei);
2984 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
2987 &local_pfx.fp_addr.ip6)),
2988 "local-route; fwd and non-fwd tables match");
2991 * +2 entries. +2 unshared path-lists
2993 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
2994 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
2995 fib_path_list_pool_size());
2996 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
2997 fib_entry_pool_size());
3000 * Modify the default route to be via an adj not yet known.
3001 * this sources the defalut route with the API source, which is
3002 * a higher preference to the DEFAULT_ROUTE source
3004 fib_table_entry_path_add(fib_index, &pfx_0_0,
3006 FIB_ENTRY_FLAG_NONE,
3009 tm->hw[0]->sw_if_index,
3013 FIB_ROUTE_PATH_FLAG_NONE);
3014 fei = fib_table_lookup(fib_index, &pfx_0_0);
3016 FIB_TEST((fei == dfrt), "default route same index");
3017 ai = fib_entry_get_adj(fei);
3018 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
3020 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3021 "adj is incomplete");
3022 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
3023 "adj nbr next-hop ok");
3026 * find the adj in the shared db
3028 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3031 tm->hw[0]->sw_if_index);
3032 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
3033 adj_unlock(locked_ai);
3036 * no more entires. +1 shared path-list
3038 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3039 fib_path_list_db_size());
3040 FIB_TEST((NPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
3041 fib_path_list_pool_size());
3042 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3043 fib_entry_pool_size());
3046 * remove the API source from the default route. We expected
3047 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
3049 fib_table_entry_path_remove(fib_index, &pfx_0_0,
3053 tm->hw[0]->sw_if_index,
3056 FIB_ROUTE_PATH_FLAG_NONE);
3057 fei = fib_table_lookup(fib_index, &pfx_0_0);
3059 FIB_TEST((fei == dfrt), "default route same index");
3060 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3061 "Default route is DROP");
3064 * no more entires. -1 shared path-list
3066 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3067 fib_path_list_db_size());
3068 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3069 fib_path_list_pool_size());
3070 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3071 fib_entry_pool_size());
3074 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3076 fib_prefix_t pfx_2001_1_2_s_128 = {
3078 .fp_proto = FIB_PROTOCOL_IP6,
3082 [0] = clib_host_to_net_u64(0x2001000000000001),
3083 [1] = clib_host_to_net_u64(0x0000000000000002),
3088 fib_prefix_t pfx_2001_1_3_s_128 = {
3090 .fp_proto = FIB_PROTOCOL_IP6,
3094 [0] = clib_host_to_net_u64(0x2001000000000001),
3095 [1] = clib_host_to_net_u64(0x0000000000000003),
3101 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
3104 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3106 &pfx_2001_1_2_s_128.fp_addr,
3107 tm->hw[0]->sw_if_index);
3108 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
3109 adj = adj_get(ai_01);
3110 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3111 "adj is incomplete");
3112 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3113 &adj->sub_type.nbr.next_hop)),
3114 "adj nbr next-hop ok");
3116 adj_nbr_update_rewrite(ai_01, eth_addr);
3117 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3119 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3120 &adj->sub_type.nbr.next_hop)),
3121 "adj nbr next-hop ok");
3123 fib_table_entry_update_one_path(fib_index,
3124 &pfx_2001_1_2_s_128,
3126 FIB_ENTRY_FLAG_NONE,
3128 &pfx_2001_1_2_s_128.fp_addr,
3129 tm->hw[0]->sw_if_index,
3133 FIB_ROUTE_PATH_FLAG_NONE);
3135 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
3136 ai = fib_entry_get_adj(fei);
3137 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3141 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3143 &pfx_2001_1_3_s_128.fp_addr,
3144 tm->hw[0]->sw_if_index);
3145 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
3146 adj = adj_get(ai_02);
3147 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3148 "adj is incomplete");
3149 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3150 &adj->sub_type.nbr.next_hop)),
3151 "adj nbr next-hop ok");
3153 adj_nbr_update_rewrite(ai_02, eth_addr);
3154 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3156 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3157 &adj->sub_type.nbr.next_hop)),
3158 "adj nbr next-hop ok");
3159 FIB_TEST((ai_01 != ai_02), "ADJs are different");
3161 fib_table_entry_update_one_path(fib_index,
3162 &pfx_2001_1_3_s_128,
3164 FIB_ENTRY_FLAG_NONE,
3166 &pfx_2001_1_3_s_128.fp_addr,
3167 tm->hw[0]->sw_if_index,
3171 FIB_ROUTE_PATH_FLAG_NONE);
3173 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
3174 ai = fib_entry_get_adj(fei);
3175 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3178 * +2 entries, +2 unshread path-lists.
3180 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3181 fib_path_list_db_size());
3182 FIB_TEST((NPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
3183 fib_path_list_pool_size());
3184 FIB_TEST((NPS+4 == fib_entry_pool_size()), "entry pool size is %d",
3185 fib_entry_pool_size());
3188 * Add a 2 routes via the first ADJ. ensure path-list sharing
3190 fib_prefix_t pfx_2001_a_s_64 = {
3192 .fp_proto = FIB_PROTOCOL_IP6,
3196 [0] = clib_host_to_net_u64(0x200100000000000a),
3197 [1] = clib_host_to_net_u64(0x0000000000000000),
3202 fib_prefix_t pfx_2001_b_s_64 = {
3204 .fp_proto = FIB_PROTOCOL_IP6,
3208 [0] = clib_host_to_net_u64(0x200100000000000b),
3209 [1] = clib_host_to_net_u64(0x0000000000000000),
3215 fib_table_entry_path_add(fib_index,
3218 FIB_ENTRY_FLAG_NONE,
3221 tm->hw[0]->sw_if_index,
3225 FIB_ROUTE_PATH_FLAG_NONE);
3226 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
3227 ai = fib_entry_get_adj(fei);
3228 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3229 fib_table_entry_path_add(fib_index,
3232 FIB_ENTRY_FLAG_NONE,
3235 tm->hw[0]->sw_if_index,
3239 FIB_ROUTE_PATH_FLAG_NONE);
3240 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
3241 ai = fib_entry_get_adj(fei);
3242 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3245 * +2 entries, +1 shared path-list.
3247 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3248 fib_path_list_db_size());
3249 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3250 fib_path_list_pool_size());
3251 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3252 fib_entry_pool_size());
3255 * add a v4 prefix via a v6 next-hop
3257 fib_prefix_t pfx_1_1_1_1_s_32 = {
3259 .fp_proto = FIB_PROTOCOL_IP4,
3261 .ip4.as_u32 = 0x01010101,
3264 fei = fib_table_entry_path_add(0, // default table
3267 FIB_ENTRY_FLAG_NONE,
3270 tm->hw[0]->sw_if_index,
3274 FIB_ROUTE_PATH_FLAG_NONE);
3275 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
3276 "1.1.1.1/32 o v6 route present");
3277 ai = fib_entry_get_adj(fei);
3279 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3280 "1.1.1.1/32 via ARP-adj");
3281 FIB_TEST((adj->ia_link == FIB_LINK_IP4),
3282 "1.1.1.1/32 ADJ-adj is link type v4");
3283 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
3284 "1.1.1.1/32 ADJ-adj is NH proto v6");
3285 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
3290 fib_prefix_t pfx_2001_c_s_64 = {
3292 .fp_proto = FIB_PROTOCOL_IP6,
3296 [0] = clib_host_to_net_u64(0x200100000000000c),
3297 [1] = clib_host_to_net_u64(0x0000000000000000),
3302 fib_table_entry_path_add(fib_index,
3305 FIB_ENTRY_FLAG_ATTACHED,
3308 tm->hw[0]->sw_if_index,
3312 FIB_ROUTE_PATH_FLAG_NONE);
3313 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3314 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
3315 ai = fib_entry_get_adj(fei);
3317 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
3318 "2001:0:0:c/64 attached resolves via glean");
3320 fib_table_entry_path_remove(fib_index,
3325 tm->hw[0]->sw_if_index,
3328 FIB_ROUTE_PATH_FLAG_NONE);
3329 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
3330 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
3333 * Shutdown the interface on which we have a connected and through
3334 * which the routes are reachable.
3335 * This will result in the connected, adj-fibs, and routes linking to drop
3336 * The local/for-us prefix continues to receive.
3338 clib_error_t * error;
3340 error = vnet_sw_interface_set_flags(vnet_get_main(),
3341 tm->hw[0]->sw_if_index,
3342 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3343 FIB_TEST((NULL == error), "Interface shutdown OK");
3345 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3346 dpo = fib_entry_contribute_ip_forwarding(fei);
3347 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3348 "2001::b/64 resolves via drop");
3350 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3351 dpo = fib_entry_contribute_ip_forwarding(fei);
3352 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3353 "2001::a/64 resolves via drop");
3354 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3355 dpo = fib_entry_contribute_ip_forwarding(fei);
3356 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3357 "2001:0:0:1::3/64 resolves via drop");
3358 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3359 dpo = fib_entry_contribute_ip_forwarding(fei);
3360 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3361 "2001:0:0:1::2/64 resolves via drop");
3362 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3363 dpo = fib_entry_contribute_ip_forwarding(fei);
3364 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3365 "2001:0:0:1::1/128 not drop");
3366 local_pfx.fp_len = 64;
3367 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3368 dpo = fib_entry_contribute_ip_forwarding(fei);
3369 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
3370 "2001:0:0:1/64 resolves via drop");
3375 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3376 fib_path_list_db_size());
3377 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
3378 fib_path_list_pool_size());
3379 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
3380 fib_entry_pool_size());
3383 * shutdown one of the other interfaces, then add a connected.
3384 * and swap one of the routes to it.
3386 error = vnet_sw_interface_set_flags(vnet_get_main(),
3387 tm->hw[1]->sw_if_index,
3388 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3389 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
3391 fib_prefix_t connected_pfx = {
3393 .fp_proto = FIB_PROTOCOL_IP6,
3396 /* 2001:0:0:2::1/64 */
3398 [0] = clib_host_to_net_u64(0x2001000000000002),
3399 [1] = clib_host_to_net_u64(0x0000000000000001),
3404 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3405 FIB_SOURCE_INTERFACE,
3406 (FIB_ENTRY_FLAG_CONNECTED |
3407 FIB_ENTRY_FLAG_ATTACHED),
3410 tm->hw[1]->sw_if_index,
3414 FIB_ROUTE_PATH_FLAG_NONE);
3415 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
3416 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3417 dpo = fib_entry_contribute_ip_forwarding(fei);
3418 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3419 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
3420 "2001:0:0:2/64 not resolves via drop");
3422 connected_pfx.fp_len = 128;
3423 fib_table_entry_update_one_path(fib_index, &connected_pfx,
3424 FIB_SOURCE_INTERFACE,
3425 (FIB_ENTRY_FLAG_CONNECTED |
3426 FIB_ENTRY_FLAG_LOCAL),
3429 tm->hw[0]->sw_if_index,
3430 ~0, // invalid fib index
3433 FIB_ROUTE_PATH_FLAG_NONE);
3434 fei = fib_table_lookup(fib_index, &connected_pfx);
3436 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3437 dpo = fib_entry_contribute_ip_forwarding(fei);
3438 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3439 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3440 "local interface adj is local");
3441 rd = receive_dpo_get(dpo->dpoi_index);
3442 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
3444 "local interface adj is receive ok");
3447 * +2 entries, +2 unshared path-lists
3449 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3450 fib_path_list_db_size());
3451 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3452 fib_path_list_pool_size());
3453 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3454 fib_entry_pool_size());
3458 * bring the interface back up. we expected the routes to return
3459 * to normal forwarding.
3461 error = vnet_sw_interface_set_flags(vnet_get_main(),
3462 tm->hw[0]->sw_if_index,
3463 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3464 FIB_TEST((NULL == error), "Interface bring-up OK");
3465 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3466 ai = fib_entry_get_adj(fei);
3467 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
3468 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3469 ai = fib_entry_get_adj(fei);
3470 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
3471 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3472 ai = fib_entry_get_adj(fei);
3473 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
3474 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3475 ai = fib_entry_get_adj(fei);
3476 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3477 local_pfx.fp_len = 64;
3478 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3479 ai = fib_entry_get_adj(fei);
3481 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3482 "attached interface adj is glean");
3485 * Delete the interface that the routes reolve through.
3486 * Again no routes are removed. They all point to drop.
3488 * This is considered an error case. The control plane should
3489 * not remove interfaces through which routes resolve, but
3490 * such things can happen. ALL affected routes will drop.
3492 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
3494 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3495 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3496 "2001::b/64 resolves via drop");
3497 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3498 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3499 "2001::b/64 resolves via drop");
3500 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3501 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3502 "2001:0:0:1::3/64 resolves via drop");
3503 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3504 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3505 "2001:0:0:1::2/64 resolves via drop");
3506 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3507 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3508 "2001:0:0:1::1/128 is drop");
3509 local_pfx.fp_len = 64;
3510 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3511 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3512 "2001:0:0:1/64 resolves via drop");
3517 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3518 fib_path_list_db_size());
3519 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
3520 fib_path_list_pool_size());
3521 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
3522 fib_entry_pool_size());
3525 * Add the interface back. routes stay unresolved.
3527 error = ethernet_register_interface(vnet_get_main(),
3528 test_interface_device_class.index,
3531 &tm->hw_if_indicies[0],
3532 /* flag change */ 0);
3534 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
3535 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3536 "2001::b/64 resolves via drop");
3537 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
3538 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3539 "2001::b/64 resolves via drop");
3540 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
3541 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3542 "2001:0:0:1::3/64 resolves via drop");
3543 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
3544 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3545 "2001:0:0:1::2/64 resolves via drop");
3546 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3547 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3548 "2001:0:0:1::1/128 is drop");
3549 local_pfx.fp_len = 64;
3550 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3551 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3552 "2001:0:0:1/64 resolves via drop");
3555 * CLEANUP ALL the routes
3557 fib_table_entry_delete(fib_index,
3560 fib_table_entry_delete(fib_index,
3563 fib_table_entry_delete(fib_index,
3566 fib_table_entry_delete(fib_index,
3567 &pfx_2001_1_3_s_128,
3569 fib_table_entry_delete(fib_index,
3570 &pfx_2001_1_2_s_128,
3572 local_pfx.fp_len = 64;
3573 fib_table_entry_delete(fib_index, &local_pfx,
3574 FIB_SOURCE_INTERFACE);
3575 local_pfx.fp_len = 128;
3576 fib_table_entry_special_remove(fib_index, &local_pfx,
3577 FIB_SOURCE_INTERFACE);
3578 connected_pfx.fp_len = 64;
3579 fib_table_entry_delete(fib_index, &connected_pfx,
3580 FIB_SOURCE_INTERFACE);
3581 connected_pfx.fp_len = 128;
3582 fib_table_entry_special_remove(fib_index, &connected_pfx,
3583 FIB_SOURCE_INTERFACE);
3585 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3586 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
3587 "2001::a/64 removed");
3588 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3589 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
3590 "2001::b/64 removed");
3591 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3592 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
3593 "2001:0:0:1::3/128 removed");
3594 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3595 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
3596 "2001:0:0:1::3/128 removed");
3597 local_pfx.fp_len = 64;
3598 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3599 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3600 "2001:0:0:1/64 removed");
3601 local_pfx.fp_len = 128;
3602 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3603 fib_table_lookup_exact_match(fib_index, &local_pfx)),
3604 "2001:0:0:1::1/128 removed");
3605 connected_pfx.fp_len = 64;
3606 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3607 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3608 "2001:0:0:2/64 removed");
3609 connected_pfx.fp_len = 128;
3610 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3611 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
3612 "2001:0:0:2::1/128 removed");
3615 * -8 entries. -7 path-lists (1 was shared).
3617 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3618 fib_path_list_db_size());
3619 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is%d",
3620 fib_path_list_pool_size());
3621 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
3622 fib_entry_pool_size());
3625 * now remove the VRF
3627 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
3629 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3630 fib_path_list_db_size());
3631 FIB_TEST((NPS-6 == fib_path_list_pool_size()), "path list pool size is%d",
3632 fib_path_list_pool_size());
3633 FIB_TEST((NPS-6 == fib_entry_pool_size()), "entry pool size is %d",
3634 fib_entry_pool_size());
3640 * return the interfaces to up state
3642 error = vnet_sw_interface_set_flags(vnet_get_main(),
3643 tm->hw[0]->sw_if_index,
3644 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3645 error = vnet_sw_interface_set_flags(vnet_get_main(),
3646 tm->hw[1]->sw_if_index,
3647 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3649 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3654 * Test the recursive route route handling for GRE tunnels
3659 /* fib_node_index_t fei; */
3660 /* u32 fib_index = 0; */
3661 /* test_main_t *tm; */
3664 /* tm = &test_main; */
3666 /* for (ii = 0; ii < 4; ii++) */
3668 /* ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = 0; */
3672 /* * add interface routes. We'll assume this works. It's more rigorously */
3673 /* * tested elsewhere. */
3675 /* fib_prefix_t local_pfx = { */
3677 /* .fp_proto = FIB_PROTOCOL_IP4, */
3680 /* /\* 10.10.10.10 *\/ */
3681 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3686 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3687 /* FIB_SOURCE_INTERFACE, */
3688 /* (FIB_ENTRY_FLAG_CONNECTED | */
3689 /* FIB_ENTRY_FLAG_ATTACHED), */
3691 /* tm->hw[0]->sw_if_index, */
3694 /* FIB_ROUTE_PATH_FLAG_NONE); */
3695 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3696 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3697 /* "attached interface route present"); */
3699 /* local_pfx.fp_len = 32; */
3700 /* fib_table_entry_update_one_path(fib_index, &local_pfx, */
3701 /* FIB_SOURCE_INTERFACE, */
3702 /* (FIB_ENTRY_FLAG_CONNECTED | */
3703 /* FIB_ENTRY_FLAG_LOCAL), */
3705 /* tm->hw[0]->sw_if_index, */
3706 /* ~0, // invalid fib index */
3708 /* FIB_ROUTE_PATH_FLAG_NONE); */
3709 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
3711 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3712 /* "local interface route present"); */
3714 /* fib_prefix_t local2_pfx = { */
3716 /* .fp_proto = FIB_PROTOCOL_IP4, */
3719 /* /\* 10.10.11.11 *\/ */
3720 /* .as_u32 = clib_host_to_net_u32(0x0a0a0b0b), */
3725 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3726 /* FIB_SOURCE_INTERFACE, */
3727 /* (FIB_ENTRY_FLAG_CONNECTED | */
3728 /* FIB_ENTRY_FLAG_ATTACHED), */
3730 /* tm->hw[1]->sw_if_index, */
3733 /* FIB_ROUTE_PATH_FLAG_NONE); */
3734 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3735 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3736 /* "attached interface route present"); */
3738 /* local2_pfx.fp_len = 32; */
3739 /* fib_table_entry_update_one_path(fib_index, &local2_pfx, */
3740 /* FIB_SOURCE_INTERFACE, */
3741 /* (FIB_ENTRY_FLAG_CONNECTED | */
3742 /* FIB_ENTRY_FLAG_LOCAL), */
3744 /* tm->hw[0]->sw_if_index, */
3745 /* ~0, // invalid fib index */
3747 /* FIB_ROUTE_PATH_FLAG_NONE); */
3748 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
3750 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), */
3751 /* "local interface route present"); */
3754 /* * Add the route that will be used to resolve the tunnel's destination */
3756 /* fib_prefix_t route_pfx = { */
3758 /* .fp_proto = FIB_PROTOCOL_IP4, */
3761 /* /\* 1.1.1.0/24 *\/ */
3762 /* .as_u32 = clib_host_to_net_u32(0x01010100), */
3766 /* /\* 10.10.10.2 *\/ */
3767 /* ip46_address_t nh_10_10_10_2 = { */
3768 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02), */
3771 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3772 /* FIB_SOURCE_API, */
3773 /* FIB_ENTRY_FLAG_NONE, */
3774 /* &nh_10_10_10_2, */
3775 /* tm->hw[0]->sw_if_index, */
3778 /* FIB_ROUTE_PATH_FLAG_NONE); */
3779 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
3780 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
3781 /* "route present"); */
3784 /* * Add a tunnel */
3786 /* /\* 1.1.1.1 *\/ */
3787 /* fib_prefix_t tun_dst_pfx = { */
3789 /* .fp_proto = FIB_PROTOCOL_IP4, */
3791 /* .ip4.as_u32 = clib_host_to_net_u32(0x01010101), */
3794 /* /\* 10.10.10.10 *\/ */
3795 /* ip4_address_t tun_src = { */
3796 /* .as_u32 = clib_host_to_net_u32(0x0a0a0a0a), */
3798 /* /\* 172.16.0.1 *\/ */
3799 /* ip4_address_t tun_itf = { */
3800 /* .as_u32 = clib_host_to_net_u32(0xac100001), */
3802 /* fib_prefix_t tun_itf_pfx = { */
3804 /* .fp_proto = FIB_PROTOCOL_IP4, */
3806 /* .ip4 = tun_itf, */
3809 /* u32 *encap_labels = NULL; */
3810 /* u32 label = 0xbaba; */
3811 /* u32 encap_index; */
3812 /* u32 tunnel_sw_if_index; */
3817 /* * First we need the MPLS Encap present */
3819 /* * Pretty sure this is broken. the wiki say the 1st aparamter address */
3820 /* * should be the tunnel's interface address, which makes some sense. But */
3821 /* * the code for tunnel creation checks for the tunnel's destination */
3822 /* * address. curious... */
3824 /* vec_add1(encap_labels, label); */
3825 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
3826 /* 0, // inner VRF */
3828 /* ~0, // policy_tunnel_index, */
3829 /* 0, // no_dst_hash, */
3832 /* FIB_TEST((0 == rv), "MPLS encap created"); */
3835 /* * now create the tunnel */
3837 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3838 /* &tun_dst_pfx.fp_addr.ip4, */
3839 /* &tun_itf_pfx.fp_addr.ip4, */
3840 /* tun_itf_pfx.fp_len, */
3841 /* 0, // inner VRF */
3842 /* 0, // outer VRF */
3843 /* &tunnel_sw_if_index, */
3846 /* FIB_TEST((0 == rv), "Tunnel created"); */
3849 /* * add it again. just for giggles. */
3851 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
3852 /* &tun_dst_pfx.fp_addr.ip4, */
3853 /* &tun_itf_pfx.fp_addr.ip4, */
3854 /* tun_itf_pfx.fp_len, */
3855 /* 0, // inner VRF */
3856 /* 0, // outer VRF */
3857 /* &tunnel_sw_if_index, */
3860 /* FIB_TEST((0 != rv), "Duplicate Tunnel not created"); */
3863 /* * Find the route added for the tunnel subnet and check that */
3864 /* * it has a midchin adj that is stacked on the adj used to reach the */
3865 /* * tunnel destination */
3867 /* ip_adjacency_t *midchain_adj, *route_adj, *adjfib_adj; */
3868 /* adj_index_t midchain_ai, route_ai, adjfib_ai1, adjfib_ai2; */
3869 /* ip_lookup_main_t *lm; */
3871 /* lm = &ip4_main.lookup_main; */
3873 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
3874 /* FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "tun itf route present"); */
3875 /* midchain_ai = fib_entry_contribute_forwarding(fei); */
3876 /* midchain_adj = adj_get(midchain_ai); */
3878 /* FIB_TEST((IP_LOOKUP_NEXT_MIDCHAIN == midchain_adj->lookup_next_index), */
3879 /* "Tunnel interface links to midchain"); */
3881 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3882 /* route_ai = fib_entry_contribute_forwarding(fei); */
3883 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3884 /* "tunnel midchain it stacked on route adj"); */
3887 /* * update the route to the tunnel's destination to load-balance via */
3888 /* * interface 1. */
3890 /* /\* 10.10.11.2 *\/ */
3891 /* ip46_address_t nh_10_10_11_2 = { */
3892 /* .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02), */
3895 /* fib_table_entry_path_add(fib_index, &route_pfx, */
3896 /* FIB_SOURCE_API, */
3897 /* FIB_ENTRY_FLAG_NONE, */
3898 /* &nh_10_10_11_2, */
3899 /* tm->hw[1]->sw_if_index, */
3902 /* FIB_ROUTE_PATH_FLAG_NONE); */
3905 /* * the tunnels midchain should have re-stacked. This tests that the */
3906 /* * route re-resolution backwalk works to a tunnel interface. */
3908 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3909 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
3910 /* route_ai = fib_entry_contribute_forwarding(fei); */
3912 /* midchain_adj = adj_get(midchain_ai); */
3914 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == route_ai), */
3915 /* "tunnel midchain has re-stacked on route adj"); */
3917 /* route_adj = adj_get(route_ai); */
3919 /* FIB_TEST((2 == route_adj->n_adj), "Route adj is multipath"); */
3922 /* * At this stage both nieghbour adjs are incomplete, so the same should */
3923 /* * be true of the multipath adj */
3925 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == route_adj->lookup_next_index), */
3926 /* "Adj0 is ARP: %d", route_adj->lookup_next_index); */
3927 /* FIB_TEST((IP_LOOKUP_NEXT_ARP == (route_adj+1)->lookup_next_index), */
3928 /* "Adj1 is ARP"); */
3931 /* * do the equivalent of creating an ARP entry for 10.10.10.2. */
3932 /* * This will complete the adj, and this */
3933 /* * change should be refelct in the multipath too. */
3935 /* u8* rewrite = NULL, byte = 0xd; */
3936 /* vec_add(rewrite, &byte, 6); */
3938 /* adjfib_ai1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
3940 /* &nh_10_10_10_2, */
3941 /* tm->hw[0]->sw_if_index); */
3942 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
3945 /* adjfib_adj = adj_get(adjfib_ai1); */
3946 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
3947 /* "Adj-fib10 adj is rewrite"); */
3949 /* adjfib_ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, */
3951 /* &nh_10_10_11_2, */
3952 /* tm->hw[1]->sw_if_index); */
3953 /* adj_nbr_update_rewrite(FIB_PROTOCOL_IP4, */
3957 /* adjfib_adj = adj_get(adjfib_ai2); */
3959 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adjfib_adj->lookup_next_index), */
3960 /* "Adj-fib11 adj is rewrite"); */
3962 /* fei = fib_table_lookup_exact_match(fib_index, &route_pfx); */
3963 /* FIB_TEST((route_ai != fib_entry_contribute_forwarding(fei)), "route changed"); */
3964 /* route_ai = fib_entry_contribute_forwarding(fei); */
3965 /* route_adj = adj_get(route_ai); */
3966 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == route_adj->lookup_next_index), */
3967 /* "Adj0 is rewrite"); */
3968 /* FIB_TEST((IP_LOOKUP_NEXT_REWRITE == (route_adj+1)->lookup_next_index), */
3969 /* "Adj1 is rewrite"); */
3974 /* adj_index_t drop_ai = adj_get_special(FIB_PROTOCOL_IP4, */
3975 /* ADJ_SPECIAL_TYPE_DROP); */
3978 /* * remove the route that the tunnel resovles via. expect */
3979 /* * it to now resolve via the default route, which is drop */
3981 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
3982 /* FIB_SOURCE_API, */
3983 /* &nh_10_10_10_2, */
3984 /* tm->hw[0]->sw_if_index, */
3987 /* FIB_ROUTE_PATH_FLAG_NONE); */
3988 /* fib_table_entry_path_remove(fib_index, &route_pfx, */
3989 /* FIB_SOURCE_API, */
3990 /* &nh_10_10_11_2, */
3991 /* tm->hw[1]->sw_if_index, */
3994 /* FIB_ROUTE_PATH_FLAG_NONE); */
3995 /* FIB_TEST((FIB_NODE_INDEX_INVALID != */
3996 /* fib_table_lookup_exact_match(fib_index, &local_pfx)), */
3997 /* "route present"); */
3998 /* midchain_adj = adj_get(midchain_ai); */
3999 /* FIB_TEST((midchain_adj->sub_type.midchain.adj_index == drop_ai), */
4000 /* "tunnel midchain has re-stacked on drop"); */
4003 /* * remove the tunnel and its MPLS encaps */
4005 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
4006 /* &tun_dst_pfx.fp_addr.ip4, */
4007 /* &tun_itf_pfx.fp_addr.ip4, */
4008 /* tun_itf_pfx.fp_len, */
4009 /* 0, // inner VRF */
4010 /* 0, // outer VRF */
4011 /* &tunnel_sw_if_index, */
4014 /* FIB_TEST((0 == rv), "Tunnel removed"); */
4015 /* rv = vnet_mpls_gre_add_del_tunnel(&tun_src, */
4016 /* &tun_dst_pfx.fp_addr.ip4, */
4017 /* &tun_itf_pfx.fp_addr.ip4, */
4018 /* tun_itf_pfx.fp_len, */
4019 /* 0, // inner VRF */
4020 /* 0, // outer VRF */
4021 /* &tunnel_sw_if_index, */
4024 /* FIB_TEST((0 != rv), "No existant Tunnel not removed"); */
4026 /* rv = vnet_mpls_add_del_encap(&tun_dst_pfx.fp_addr.ip4, */
4027 /* 0, // inner VRF */
4029 /* ~0, // policy_tunnel_index, */
4030 /* 0, // no_dst_hash, */
4033 /* FIB_TEST((0 == rv), "MPLS encap deleted"); */
4035 /* vec_free(encap_labels); */
4038 /* * no more FIB entries expected */
4040 /* fei = fib_table_lookup_exact_match(fib_index, &tun_itf_pfx); */
4041 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun itf route removed"); */
4042 /* fei = fib_table_lookup_exact_match(fib_index, &tun_dst_pfx); */
4043 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "tun dst route removed"); */
4046 /* * CLEANUP the connecteds */
4048 /* local2_pfx.fp_len = 24; */
4049 /* fib_table_entry_delete(fib_index, &local2_pfx, */
4050 /* FIB_SOURCE_INTERFACE); */
4051 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
4052 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4053 /* "attached interface route remove"); */
4055 /* local2_pfx.fp_len = 32; */
4056 /* fib_table_entry_special_remove(fib_index, &local2_pfx, */
4057 /* FIB_SOURCE_INTERFACE); */
4058 /* fei = fib_table_lookup_exact_match(fib_index, &local2_pfx); */
4059 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4060 /* "local interface route removed"); */
4061 /* local_pfx.fp_len = 24; */
4062 /* fib_table_entry_delete(fib_index, &local_pfx, */
4063 /* FIB_SOURCE_INTERFACE); */
4064 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
4065 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4066 /* "attached interface route remove"); */
4068 /* local_pfx.fp_len = 32; */
4069 /* fib_table_entry_special_remove(fib_index, &local_pfx, */
4070 /* FIB_SOURCE_INTERFACE); */
4071 /* fei = fib_table_lookup_exact_match(fib_index, &local_pfx); */
4072 /* FIB_TEST((FIB_NODE_INDEX_INVALID == fei), */
4073 /* "local interface route removed"); */
4077 * Test Attached Exports
4082 const dpo_id_t *dpo, *dpo_drop;
4083 const u32 fib_index = 0;
4084 fib_node_index_t fei;
4091 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4095 * add interface routes. We'll assume this works. It's more rigorously
4098 fib_prefix_t local_pfx = {
4100 .fp_proto = FIB_PROTOCOL_IP4,
4104 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4109 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4110 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4112 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4114 fib_table_entry_update_one_path(fib_index, &local_pfx,
4115 FIB_SOURCE_INTERFACE,
4116 (FIB_ENTRY_FLAG_CONNECTED |
4117 FIB_ENTRY_FLAG_ATTACHED),
4120 tm->hw[0]->sw_if_index,
4124 FIB_ROUTE_PATH_FLAG_NONE);
4125 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4126 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4127 "attached interface route present");
4129 local_pfx.fp_len = 32;
4130 fib_table_entry_update_one_path(fib_index, &local_pfx,
4131 FIB_SOURCE_INTERFACE,
4132 (FIB_ENTRY_FLAG_CONNECTED |
4133 FIB_ENTRY_FLAG_LOCAL),
4136 tm->hw[0]->sw_if_index,
4137 ~0, // invalid fib index
4140 FIB_ROUTE_PATH_FLAG_NONE);
4141 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4143 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4144 "local interface route present");
4147 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4149 fib_prefix_t pfx_10_10_10_1_s_32 = {
4151 .fp_proto = FIB_PROTOCOL_IP4,
4154 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4157 fib_node_index_t ai;
4159 fib_table_entry_update_one_path(fib_index,
4160 &pfx_10_10_10_1_s_32,
4162 FIB_ENTRY_FLAG_NONE,
4164 &pfx_10_10_10_1_s_32.fp_addr,
4165 tm->hw[0]->sw_if_index,
4166 ~0, // invalid fib index
4169 FIB_ROUTE_PATH_FLAG_NONE);
4171 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4172 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4173 ai = fib_entry_get_adj(fei);
4176 * create another FIB table into which routes will be imported
4178 u32 import_fib_index1;
4180 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4183 * Add an attached route in the import FIB
4185 local_pfx.fp_len = 24;
4186 fib_table_entry_update_one_path(import_fib_index1,
4189 FIB_ENTRY_FLAG_NONE,
4192 tm->hw[0]->sw_if_index,
4193 ~0, // invalid fib index
4196 FIB_ROUTE_PATH_FLAG_NONE);
4197 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4198 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4201 * check for the presence of the adj-fibs in the import table
4203 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4204 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4205 FIB_TEST((ai == fib_entry_get_adj(fei)),
4206 "adj-fib1 Import uses same adj as export");
4209 * check for the presence of the local in the import table
4211 local_pfx.fp_len = 32;
4212 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4213 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4216 * Add another adj-fin in the export table. Expect this
4217 * to get magically exported;
4219 fib_prefix_t pfx_10_10_10_2_s_32 = {
4221 .fp_proto = FIB_PROTOCOL_IP4,
4224 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4228 fib_table_entry_update_one_path(fib_index,
4229 &pfx_10_10_10_2_s_32,
4231 FIB_ENTRY_FLAG_NONE,
4233 &pfx_10_10_10_2_s_32.fp_addr,
4234 tm->hw[0]->sw_if_index,
4235 ~0, // invalid fib index
4238 FIB_ROUTE_PATH_FLAG_NONE);
4239 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4240 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4241 ai = fib_entry_get_adj(fei);
4243 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4244 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4245 FIB_TEST((ai == fib_entry_get_adj(fei)),
4246 "Import uses same adj as export");
4249 * create a 2nd FIB table into which routes will be imported
4251 u32 import_fib_index2;
4253 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4256 * Add an attached route in the import FIB
4258 local_pfx.fp_len = 24;
4259 fib_table_entry_update_one_path(import_fib_index2,
4262 FIB_ENTRY_FLAG_NONE,
4265 tm->hw[0]->sw_if_index,
4266 ~0, // invalid fib index
4269 FIB_ROUTE_PATH_FLAG_NONE);
4270 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4271 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4274 * check for the presence of all the adj-fibs and local in the import table
4276 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4277 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4278 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4279 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4280 local_pfx.fp_len = 32;
4281 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4282 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4285 * add a 3rd adj-fib. expect it to be exported to both tables.
4287 fib_prefix_t pfx_10_10_10_3_s_32 = {
4289 .fp_proto = FIB_PROTOCOL_IP4,
4292 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4296 fib_table_entry_update_one_path(fib_index,
4297 &pfx_10_10_10_3_s_32,
4299 FIB_ENTRY_FLAG_NONE,
4301 &pfx_10_10_10_3_s_32.fp_addr,
4302 tm->hw[0]->sw_if_index,
4303 ~0, // invalid fib index
4306 FIB_ROUTE_PATH_FLAG_NONE);
4307 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4308 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4309 ai = fib_entry_get_adj(fei);
4311 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4312 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4313 FIB_TEST((ai == fib_entry_get_adj(fei)),
4314 "Import uses same adj as export");
4315 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4316 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4317 FIB_TEST((ai == fib_entry_get_adj(fei)),
4318 "Import uses same adj as export");
4321 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4323 fib_table_entry_delete(fib_index,
4324 &pfx_10_10_10_3_s_32,
4327 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4328 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
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 removed from FIB1");
4333 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4334 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4337 * remove the attached route from the 2nd FIB. expect the imported
4338 * entires to be removed
4340 local_pfx.fp_len = 24;
4341 fib_table_entry_delete(import_fib_index2,
4344 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4345 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4347 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4348 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4349 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4350 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4351 local_pfx.fp_len = 32;
4352 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4353 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4355 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4356 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4357 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4358 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4359 local_pfx.fp_len = 32;
4360 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4361 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4364 * modify the route in FIB1 so it is no longer attached. expect the imported
4365 * entires to be removed
4367 local_pfx.fp_len = 24;
4368 fib_table_entry_update_one_path(import_fib_index1,
4371 FIB_ENTRY_FLAG_NONE,
4373 &pfx_10_10_10_2_s_32.fp_addr,
4374 tm->hw[0]->sw_if_index,
4375 ~0, // invalid fib index
4378 FIB_ROUTE_PATH_FLAG_NONE);
4379 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4380 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4381 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4382 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4383 local_pfx.fp_len = 32;
4384 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4385 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4388 * modify it back to attached. expect the adj-fibs back
4390 local_pfx.fp_len = 24;
4391 fib_table_entry_update_one_path(import_fib_index1,
4394 FIB_ENTRY_FLAG_NONE,
4397 tm->hw[0]->sw_if_index,
4398 ~0, // invalid fib index
4401 FIB_ROUTE_PATH_FLAG_NONE);
4402 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4403 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4404 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4405 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4406 local_pfx.fp_len = 32;
4407 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4408 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4411 * add a covering attached next-hop for the interface address, so we have
4412 * a valid adj to find when we check the forwarding tables
4414 fib_prefix_t pfx_10_0_0_0_s_8 = {
4416 .fp_proto = FIB_PROTOCOL_IP4,
4419 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4423 fei = fib_table_entry_update_one_path(fib_index,
4426 FIB_ENTRY_FLAG_NONE,
4428 &pfx_10_10_10_3_s_32.fp_addr,
4429 tm->hw[0]->sw_if_index,
4430 ~0, // invalid fib index
4433 FIB_ROUTE_PATH_FLAG_NONE);
4434 dpo = fib_entry_contribute_ip_forwarding(fei);
4437 * remove the route in the export fib. expect the adj-fibs to be removed
4439 local_pfx.fp_len = 24;
4440 fib_table_entry_delete(fib_index,
4442 FIB_SOURCE_INTERFACE);
4444 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4445 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4446 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4447 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4448 local_pfx.fp_len = 32;
4449 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4450 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4453 * the adj-fibs in the export VRF are present in the FIB table,
4454 * but not installed in forwarding, since they have no attached cover.
4455 * Consequently a lookup in the MTRIE gives the adj for the covering
4458 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4459 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4462 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4463 FIB_TEST(lbi == dpo->dpoi_index,
4464 "10.10.10.1 forwards on \n%U not \n%U",
4465 format_load_balance, lbi, 0,
4466 format_dpo_id, dpo, 0);
4467 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4468 FIB_TEST(lbi == dpo->dpoi_index,
4469 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4470 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
4471 FIB_TEST(lbi == dpo->dpoi_index,
4472 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
4475 * add the export prefix back, but not as attached.
4476 * No adj-fibs in export nor import tables
4478 local_pfx.fp_len = 24;
4479 fei = fib_table_entry_update_one_path(fib_index,
4482 FIB_ENTRY_FLAG_NONE,
4484 &pfx_10_10_10_1_s_32.fp_addr,
4485 tm->hw[0]->sw_if_index,
4486 ~0, // invalid fib index
4489 FIB_ROUTE_PATH_FLAG_NONE);
4490 dpo = fib_entry_contribute_ip_forwarding(fei);
4492 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4493 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
4494 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4495 FIB_TEST(lbi == dpo->dpoi_index,
4496 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
4497 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4498 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4499 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4500 FIB_TEST(lbi == dpo->dpoi_index,
4501 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4503 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4504 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4505 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4506 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4507 local_pfx.fp_len = 32;
4508 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4509 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4512 * modify the export prefix so it is attached. expect all covereds to return
4514 local_pfx.fp_len = 24;
4515 fib_table_entry_update_one_path(fib_index,
4518 FIB_ENTRY_FLAG_NONE,
4521 tm->hw[0]->sw_if_index,
4522 ~0, // invalid fib index
4525 FIB_ROUTE_PATH_FLAG_NONE);
4527 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4528 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4529 dpo = fib_entry_contribute_ip_forwarding(fei);
4530 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4531 "Adj-fib1 is not drop in export");
4532 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4533 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4534 local_pfx.fp_len = 32;
4535 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4536 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4537 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4538 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4539 dpo = fib_entry_contribute_ip_forwarding(fei);
4540 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4541 "Adj-fib1 is not drop in export");
4542 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4543 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4544 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4545 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4546 local_pfx.fp_len = 32;
4547 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4548 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4551 * modify the export prefix so connected. no change.
4553 local_pfx.fp_len = 24;
4554 fib_table_entry_update_one_path(fib_index, &local_pfx,
4555 FIB_SOURCE_INTERFACE,
4556 (FIB_ENTRY_FLAG_CONNECTED |
4557 FIB_ENTRY_FLAG_ATTACHED),
4560 tm->hw[0]->sw_if_index,
4564 FIB_ROUTE_PATH_FLAG_NONE);
4566 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4567 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4568 dpo = fib_entry_contribute_ip_forwarding(fei);
4569 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4570 "Adj-fib1 is not drop in export");
4571 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4572 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
4573 local_pfx.fp_len = 32;
4574 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4575 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
4576 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4577 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
4578 dpo = fib_entry_contribute_ip_forwarding(fei);
4579 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4580 "Adj-fib1 is not drop in export");
4581 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4582 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4583 local_pfx.fp_len = 32;
4584 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4585 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4590 fib_table_entry_delete(fib_index,
4593 fib_table_entry_delete(fib_index,
4594 &pfx_10_10_10_1_s_32,
4596 fib_table_entry_delete(fib_index,
4597 &pfx_10_10_10_2_s_32,
4599 local_pfx.fp_len = 32;
4600 fib_table_entry_delete(fib_index,
4602 FIB_SOURCE_INTERFACE);
4603 local_pfx.fp_len = 24;
4604 fib_table_entry_delete(fib_index,
4607 fib_table_entry_delete(fib_index,
4609 FIB_SOURCE_INTERFACE);
4610 local_pfx.fp_len = 24;
4611 fib_table_entry_delete(import_fib_index1,
4615 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
4616 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
4618 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4622 typedef enum fib_test_lb_bucket_type_t_ {
4628 } fib_test_lb_bucket_type_t;
4630 typedef struct fib_test_lb_bucket_t_ {
4631 fib_test_lb_bucket_type_t type;
4662 } fib_test_lb_bucket_t;
4664 #define FIB_TEST_LB(_cond, _comment, _args...) \
4666 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
4672 fib_test_validate_lb_v (const load_balance_t *lb,
4676 const dpo_id_t *dpo;
4679 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
4681 for (bucket = 0; bucket < n_buckets; bucket++)
4683 const fib_test_lb_bucket_t *exp;
4685 exp = va_arg(ap, fib_test_lb_bucket_t*);
4686 dpo = load_balance_get_bucket_i(lb, bucket);
4690 case FT_LB_LABEL_O_ADJ:
4692 const mpls_label_dpo_t *mld;
4694 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4695 "bucket %d stacks on %U",
4697 format_dpo_type, dpo->dpoi_type);
4699 mld = mpls_label_dpo_get(dpo->dpoi_index);
4700 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4702 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4703 exp->label_o_adj.label),
4704 "bucket %d stacks on label %d",
4706 exp->label_o_adj.label);
4708 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4709 exp->label_o_adj.eos),
4710 "bucket %d stacks on label %d %U",
4712 exp->label_o_adj.label,
4713 format_mpls_eos_bit, exp->label_o_adj.eos);
4715 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
4716 "bucket %d label stacks on %U",
4718 format_dpo_type, mld->mld_dpo.dpoi_type);
4720 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
4721 "bucket %d label stacks on adj %d",
4723 exp->label_o_adj.adj);
4726 case FT_LB_LABEL_O_LB:
4728 const mpls_label_dpo_t *mld;
4731 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
4732 "bucket %d stacks on %U",
4734 format_dpo_type, dpo->dpoi_type);
4736 mld = mpls_label_dpo_get(dpo->dpoi_index);
4737 hdr = clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
4739 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
4740 exp->label_o_lb.label),
4741 "bucket %d stacks on label %d",
4743 exp->label_o_lb.label);
4745 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
4746 exp->label_o_lb.eos),
4747 "bucket %d stacks on label %d %U",
4749 exp->label_o_lb.label,
4750 format_mpls_eos_bit, exp->label_o_lb.eos);
4752 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
4753 "bucket %d label stacks on %U",
4755 format_dpo_type, mld->mld_dpo.dpoi_type);
4757 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
4758 "bucket %d label stacks on LB %d",
4760 exp->label_o_lb.lb);
4764 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
4765 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
4766 "bucket %d stacks on %U",
4768 format_dpo_type, dpo->dpoi_type);
4769 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
4770 "bucket %d stacks on adj %d",
4775 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
4776 "bucket %d stacks on %U",
4778 format_dpo_type, dpo->dpoi_type);
4779 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
4780 "bucket %d stacks on lb %d",
4785 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
4786 "bucket %d stacks on %U",
4788 format_dpo_type, dpo->dpoi_type);
4789 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
4790 "bucket %d stacks on drop %d",
4800 fib_test_validate_entry (fib_node_index_t fei,
4801 fib_forward_chain_type_t fct,
4805 const load_balance_t *lb;
4806 dpo_id_t dpo = DPO_NULL;
4813 va_start(ap, n_buckets);
4815 fib_entry_get_prefix(fei, &pfx);
4816 fib_index = fib_entry_get_fib_index(fei);
4817 fib_entry_contribute_forwarding(fei, fct, &dpo);
4819 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
4820 "Entry links to %U",
4821 format_dpo_type, dpo.dpoi_type);
4822 lb = load_balance_get(dpo.dpoi_index);
4824 res = fib_test_validate_lb_v(lb, n_buckets, ap);
4827 * ensure that the LB contributed by the entry is the
4828 * same as the LB in the forwarding tables
4830 switch (pfx.fp_proto)
4832 case FIB_PROTOCOL_IP4:
4833 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
4835 case FIB_PROTOCOL_IP6:
4836 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
4838 case FIB_PROTOCOL_MPLS:
4840 mpls_unicast_header_t hdr = {
4841 .label_exp_s_ttl = 0,
4844 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
4845 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
4846 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
4848 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
4854 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
4855 "Contributed LB = FW LB: %U\n %U",
4856 format_load_balance, fw_lbi, 0,
4857 format_load_balance, dpo.dpoi_index, 0);
4867 * Test the recursive route route handling for GRE tunnels
4870 fib_test_label (void)
4872 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;
4873 const u32 fib_index = 0;
4878 lb_count = pool_elts(load_balance_pool);
4883 * add interface routes. We'll assume this works. It's more rigorously
4886 fib_prefix_t local0_pfx = {
4888 .fp_proto = FIB_PROTOCOL_IP4,
4892 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4897 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4900 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4901 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4903 fib_table_entry_update_one_path(fib_index, &local0_pfx,
4904 FIB_SOURCE_INTERFACE,
4905 (FIB_ENTRY_FLAG_CONNECTED |
4906 FIB_ENTRY_FLAG_ATTACHED),
4909 tm->hw[0]->sw_if_index,
4913 FIB_ROUTE_PATH_FLAG_NONE);
4914 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
4915 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4916 "attached interface route present");
4918 local0_pfx.fp_len = 32;
4919 fib_table_entry_update_one_path(fib_index, &local0_pfx,
4920 FIB_SOURCE_INTERFACE,
4921 (FIB_ENTRY_FLAG_CONNECTED |
4922 FIB_ENTRY_FLAG_LOCAL),
4925 tm->hw[0]->sw_if_index,
4926 ~0, // invalid fib index
4929 FIB_ROUTE_PATH_FLAG_NONE);
4930 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
4932 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4933 "local interface route present");
4935 fib_prefix_t local1_pfx = {
4937 .fp_proto = FIB_PROTOCOL_IP4,
4941 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
4946 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
4947 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
4949 fib_table_entry_update_one_path(fib_index, &local1_pfx,
4950 FIB_SOURCE_INTERFACE,
4951 (FIB_ENTRY_FLAG_CONNECTED |
4952 FIB_ENTRY_FLAG_ATTACHED),
4955 tm->hw[1]->sw_if_index,
4959 FIB_ROUTE_PATH_FLAG_NONE);
4960 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
4961 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4962 "attached interface route present");
4964 local1_pfx.fp_len = 32;
4965 fib_table_entry_update_one_path(fib_index, &local1_pfx,
4966 FIB_SOURCE_INTERFACE,
4967 (FIB_ENTRY_FLAG_CONNECTED |
4968 FIB_ENTRY_FLAG_LOCAL),
4971 tm->hw[1]->sw_if_index,
4972 ~0, // invalid fib index
4975 FIB_ROUTE_PATH_FLAG_NONE);
4976 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
4978 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4979 "local interface route present");
4981 ip46_address_t nh_10_10_10_1 = {
4983 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4986 ip46_address_t nh_10_10_11_1 = {
4988 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
4991 ip46_address_t nh_10_10_11_2 = {
4993 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
4997 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5000 tm->hw[1]->sw_if_index);
5001 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5004 tm->hw[1]->sw_if_index);
5005 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5008 tm->hw[0]->sw_if_index);
5009 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5012 tm->hw[1]->sw_if_index);
5013 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5016 tm->hw[1]->sw_if_index);
5019 * Add an etry with one path with a real out-going label
5021 fib_prefix_t pfx_1_1_1_1_s_32 = {
5023 .fp_proto = FIB_PROTOCOL_IP4,
5025 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5028 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5029 .type = FT_LB_LABEL_O_ADJ,
5031 .adj = ai_mpls_10_10_10_1,
5036 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5037 .type = FT_LB_LABEL_O_ADJ,
5039 .adj = ai_mpls_10_10_10_1,
5041 .eos = MPLS_NON_EOS,
5044 fib_table_entry_update_one_path(fib_index,
5047 FIB_ENTRY_FLAG_NONE,
5050 tm->hw[0]->sw_if_index,
5051 ~0, // invalid fib index
5054 FIB_ROUTE_PATH_FLAG_NONE);
5056 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5057 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5059 FIB_TEST(fib_test_validate_entry(fei,
5060 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5062 &l99_eos_o_10_10_10_1),
5063 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5066 * add a path with an implicit NULL label
5068 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5071 .adj = ai_v4_10_10_11_1,
5074 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5077 .adj = ai_mpls_10_10_11_1,
5081 fei = fib_table_entry_path_add(fib_index,
5084 FIB_ENTRY_FLAG_NONE,
5087 tm->hw[1]->sw_if_index,
5088 ~0, // invalid fib index
5090 MPLS_IETF_IMPLICIT_NULL_LABEL,
5091 FIB_ROUTE_PATH_FLAG_NONE);
5093 FIB_TEST(fib_test_validate_entry(fei,
5094 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5096 &l99_eos_o_10_10_10_1,
5098 "1.1.1.1/32 LB 2 buckets via: "
5099 "label 99 over 10.10.10.1, "
5100 "adj over 10.10.11.1");
5103 * assign the route a local label
5105 fib_table_entry_local_label_add(fib_index,
5109 fib_prefix_t pfx_24001_eos = {
5110 .fp_proto = FIB_PROTOCOL_MPLS,
5114 fib_prefix_t pfx_24001_neos = {
5115 .fp_proto = FIB_PROTOCOL_MPLS,
5117 .fp_eos = MPLS_NON_EOS,
5121 * The EOS entry should link to both the paths,
5122 * and use an ip adj for the imp-null
5123 * The NON-EOS entry should link to both the paths,
5124 * and use an mpls adj for the imp-null
5126 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5128 FIB_TEST(fib_test_validate_entry(fei,
5129 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5131 &l99_eos_o_10_10_10_1,
5133 "24001/eos LB 2 buckets via: "
5134 "label 99 over 10.10.10.1, "
5135 "adj over 10.10.11.1");
5138 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5140 FIB_TEST(fib_test_validate_entry(fei,
5141 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5143 &l99_neos_o_10_10_10_1,
5144 &a_mpls_o_10_10_11_1),
5145 "24001/neos LB 1 bucket via: "
5146 "label 99 over 10.10.10.1 ",
5147 "mpls-adj via 10.10.11.1");
5150 * add an unlabelled path, this is excluded from the neos chains,
5152 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5155 .adj = ai_v4_10_10_11_2,
5159 fei = fib_table_entry_path_add(fib_index,
5162 FIB_ENTRY_FLAG_NONE,
5165 tm->hw[1]->sw_if_index,
5166 ~0, // invalid fib index
5169 FIB_ROUTE_PATH_FLAG_NONE);
5171 FIB_TEST(fib_test_validate_entry(fei,
5172 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5173 16, // 3 choices spread over 16 buckets
5174 &l99_eos_o_10_10_10_1,
5175 &l99_eos_o_10_10_10_1,
5176 &l99_eos_o_10_10_10_1,
5177 &l99_eos_o_10_10_10_1,
5178 &l99_eos_o_10_10_10_1,
5179 &l99_eos_o_10_10_10_1,
5190 "1.1.1.1/32 LB 16 buckets via: "
5191 "label 99 over 10.10.10.1, "
5192 "adj over 10.10.11.1",
5193 "adj over 10.10.11.2");
5196 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5198 dpo_id_t non_eos_1_1_1_1 = DPO_NULL;
5199 fib_entry_contribute_forwarding(fei,
5200 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5204 * n-eos has only the 2 labelled paths
5206 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5209 FIB_TEST(fib_test_validate_entry(fei,
5210 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5212 &l99_neos_o_10_10_10_1,
5213 &a_mpls_o_10_10_11_1),
5214 "24001/neos LB 2 buckets via: "
5215 "label 99 over 10.10.10.1, "
5216 "adj-mpls over 10.10.11.2");
5219 * A labelled recursive
5221 fib_prefix_t pfx_2_2_2_2_s_32 = {
5223 .fp_proto = FIB_PROTOCOL_IP4,
5225 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5228 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5229 .type = FT_LB_LABEL_O_LB,
5231 .lb = non_eos_1_1_1_1.dpoi_index,
5237 fib_table_entry_update_one_path(fib_index,
5240 FIB_ENTRY_FLAG_NONE,
5242 &pfx_1_1_1_1_s_32.fp_addr,
5247 FIB_ROUTE_PATH_FLAG_NONE);
5249 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5250 FIB_TEST(fib_test_validate_entry(fei,
5251 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5253 &l1600_eos_o_1_1_1_1),
5254 "2.2.2.2.2/32 LB 1 buckets via: "
5255 "label 1600 over 1.1.1.1");
5257 dpo_id_t dpo_44 = DPO_NULL;
5260 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5261 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5263 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5264 "uRPF check for 2.2.2.2/32 on %d OK",
5265 tm->hw[0]->sw_if_index);
5266 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5267 "uRPF check for 2.2.2.2/32 on %d OK",
5268 tm->hw[1]->sw_if_index);
5269 FIB_TEST(!fib_urpf_check(urpfi, 99),
5270 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5273 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5274 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5275 "Shared uRPF on IP and non-EOS chain");
5280 * we are holding a lock on the non-eos LB of the via-entry.
5281 * do a PIC-core failover by shutting the link of the via-entry.
5283 * shut down the link with the valid label
5285 vnet_sw_interface_set_flags(vnet_get_main(),
5286 tm->hw[0]->sw_if_index,
5289 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5290 FIB_TEST(fib_test_validate_entry(fei,
5291 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5295 "1.1.1.1/32 LB 2 buckets via: "
5296 "adj over 10.10.11.1, ",
5297 "adj-v4 over 10.10.11.2");
5299 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5301 FIB_TEST(fib_test_validate_entry(fei,
5302 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5306 "24001/eos LB 2 buckets via: "
5307 "adj over 10.10.11.1, ",
5308 "adj-v4 over 10.10.11.2");
5310 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5312 FIB_TEST(fib_test_validate_entry(fei,
5313 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5315 &a_mpls_o_10_10_11_1),
5316 "24001/neos LB 1 buckets via: "
5317 "adj-mpls over 10.10.11.2");
5320 * test that the pre-failover load-balance has been in-place
5323 dpo_id_t current = DPO_NULL;
5324 fib_entry_contribute_forwarding(fei,
5325 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5328 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5330 "PIC-core LB inplace modified %U %U",
5331 format_dpo_id, &non_eos_1_1_1_1, 0,
5332 format_dpo_id, ¤t, 0);
5334 dpo_reset(&non_eos_1_1_1_1);
5335 dpo_reset(¤t);
5338 * no-shut the link with the valid label
5340 vnet_sw_interface_set_flags(vnet_get_main(),
5341 tm->hw[0]->sw_if_index,
5342 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5344 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5345 FIB_TEST(fib_test_validate_entry(fei,
5346 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5347 16, // 3 choices spread over 16 buckets
5348 &l99_eos_o_10_10_10_1,
5349 &l99_eos_o_10_10_10_1,
5350 &l99_eos_o_10_10_10_1,
5351 &l99_eos_o_10_10_10_1,
5352 &l99_eos_o_10_10_10_1,
5353 &l99_eos_o_10_10_10_1,
5364 "1.1.1.1/32 LB 16 buckets via: "
5365 "label 99 over 10.10.10.1, "
5366 "adj over 10.10.11.1",
5367 "adj-v4 over 10.10.11.2");
5370 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5372 FIB_TEST(fib_test_validate_entry(fei,
5373 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5374 16, // 3 choices spread over 16 buckets
5375 &l99_eos_o_10_10_10_1,
5376 &l99_eos_o_10_10_10_1,
5377 &l99_eos_o_10_10_10_1,
5378 &l99_eos_o_10_10_10_1,
5379 &l99_eos_o_10_10_10_1,
5380 &l99_eos_o_10_10_10_1,
5391 "24001/eos LB 16 buckets via: "
5392 "label 99 over 10.10.10.1, "
5393 "adj over 10.10.11.1",
5394 "adj-v4 over 10.10.11.2");
5396 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5398 FIB_TEST(fib_test_validate_entry(fei,
5399 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5401 &l99_neos_o_10_10_10_1,
5402 &a_mpls_o_10_10_11_1),
5403 "24001/neos LB 2 buckets via: "
5404 "label 99 over 10.10.10.1, "
5405 "adj-mpls over 10.10.11.2");
5408 * remove the first path with the valid label
5410 fib_table_entry_path_remove(fib_index,
5415 tm->hw[0]->sw_if_index,
5416 ~0, // invalid fib index
5418 FIB_ROUTE_PATH_FLAG_NONE);
5420 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5421 FIB_TEST(fib_test_validate_entry(fei,
5422 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5426 "1.1.1.1/32 LB 2 buckets via: "
5427 "adj over 10.10.11.1",
5428 "adj-v4 over 10.10.11.2");
5430 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5432 FIB_TEST(fib_test_validate_entry(fei,
5433 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5437 "24001/eos LB 2 buckets via: "
5438 "adj over 10.10.11.1",
5439 "adj-v4 over 10.10.11.2");
5441 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5444 FIB_TEST(fib_test_validate_entry(fei,
5445 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5447 &a_mpls_o_10_10_11_1),
5448 "24001/neos LB 1 buckets via: "
5449 "adj-mpls over 10.10.11.2");
5452 * remove the other path with a valid label
5454 fib_test_lb_bucket_t bucket_drop = {
5455 .type = FT_LB_SPECIAL,
5461 fib_table_entry_path_remove(fib_index,
5466 tm->hw[1]->sw_if_index,
5467 ~0, // invalid fib index
5469 FIB_ROUTE_PATH_FLAG_NONE);
5471 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5472 FIB_TEST(fib_test_validate_entry(fei,
5473 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5476 "1.1.1.1/32 LB 1 buckets via: "
5477 "adj over 10.10.11.2");
5479 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5481 FIB_TEST(fib_test_validate_entry(fei,
5482 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5485 "24001/eos LB 1 buckets via: "
5486 "adj over 10.10.11.2");
5488 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5490 FIB_TEST(fib_test_validate_entry(fei,
5491 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5494 "24001/eos LB 1 buckets via: DROP");
5497 * add back the path with the valid label
5499 fib_table_entry_path_add(fib_index,
5502 FIB_ENTRY_FLAG_NONE,
5505 tm->hw[0]->sw_if_index,
5506 ~0, // invalid fib index
5509 FIB_ROUTE_PATH_FLAG_NONE);
5511 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5512 FIB_TEST(fib_test_validate_entry(fei,
5513 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5515 &l99_eos_o_10_10_10_1,
5517 "1.1.1.1/32 LB 2 buckets via: "
5518 "label 99 over 10.10.10.1, "
5519 "adj over 10.10.11.2");
5521 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5523 FIB_TEST(fib_test_validate_entry(fei,
5524 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5526 &l99_eos_o_10_10_10_1,
5528 "24001/eos LB 2 buckets via: "
5529 "label 99 over 10.10.10.1, "
5530 "adj over 10.10.11.2");
5532 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5534 FIB_TEST(fib_test_validate_entry(fei,
5535 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5537 &l99_neos_o_10_10_10_1),
5538 "24001/neos LB 1 buckets via: "
5539 "label 99 over 10.10.10.1");
5542 * remove the local label
5544 fib_table_entry_local_label_remove(fib_index,
5548 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5549 FIB_TEST(fib_test_validate_entry(fei,
5550 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5552 &l99_eos_o_10_10_10_1,
5554 "24001/eos LB 2 buckets via: "
5555 "label 99 over 10.10.10.1, "
5556 "adj over 10.10.11.2");
5558 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5559 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5560 "No more MPLS FIB entries => table removed");
5563 * add another via-entry for the recursive
5565 fib_prefix_t pfx_1_1_1_2_s_32 = {
5567 .fp_proto = FIB_PROTOCOL_IP4,
5569 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5572 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5573 .type = FT_LB_LABEL_O_ADJ,
5575 .adj = ai_mpls_10_10_10_1,
5581 fei = fib_table_entry_update_one_path(fib_index,
5584 FIB_ENTRY_FLAG_NONE,
5587 tm->hw[0]->sw_if_index,
5588 ~0, // invalid fib index
5591 FIB_ROUTE_PATH_FLAG_NONE);
5593 FIB_TEST(fib_test_validate_entry(fei,
5594 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5596 &l101_eos_o_10_10_10_1),
5597 "1.1.1.2/32 LB 1 buckets via: "
5598 "label 101 over 10.10.10.1");
5600 dpo_id_t non_eos_1_1_1_2 = DPO_NULL;
5601 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5603 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5605 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5607 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5610 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5611 .type = FT_LB_LABEL_O_LB,
5613 .lb = non_eos_1_1_1_2.dpoi_index,
5618 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5620 fei = fib_table_entry_path_add(fib_index,
5623 FIB_ENTRY_FLAG_NONE,
5625 &pfx_1_1_1_2_s_32.fp_addr,
5630 FIB_ROUTE_PATH_FLAG_NONE);
5632 FIB_TEST(fib_test_validate_entry(fei,
5633 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5635 &l1600_eos_o_1_1_1_1,
5636 &l1601_eos_o_1_1_1_2),
5637 "2.2.2.2/32 LB 2 buckets via: "
5638 "label 1600 via 1.1,1.1, "
5639 "label 16001 via 1.1.1.2");
5642 * update the via-entry so it no longer has an imp-null path.
5643 * the LB for the recursive can use an imp-null
5645 fei = fib_table_entry_update_one_path(fib_index,
5648 FIB_ENTRY_FLAG_NONE,
5651 tm->hw[1]->sw_if_index,
5652 ~0, // invalid fib index
5654 MPLS_IETF_IMPLICIT_NULL_LABEL,
5655 FIB_ROUTE_PATH_FLAG_NONE);
5657 FIB_TEST(fib_test_validate_entry(fei,
5658 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5661 "1.1.1.2/32 LB 1 buckets via: "
5664 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5665 FIB_TEST(fib_test_validate_entry(fei,
5666 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5668 &l1600_eos_o_1_1_1_1,
5669 &l1601_eos_o_1_1_1_2),
5670 "2.2.2.2/32 LB 2 buckets via: "
5671 "label 1600 via 1.1,1.1, "
5672 "label 16001 via 1.1.1.2");
5675 * update the via-entry so it no longer has labelled paths.
5676 * the LB for the recursive should exclue this via form its LB
5678 fei = fib_table_entry_update_one_path(fib_index,
5681 FIB_ENTRY_FLAG_NONE,
5684 tm->hw[1]->sw_if_index,
5685 ~0, // invalid fib index
5688 FIB_ROUTE_PATH_FLAG_NONE);
5690 FIB_TEST(fib_test_validate_entry(fei,
5691 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5694 "1.1.1.2/32 LB 1 buckets via: "
5697 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5698 FIB_TEST(fib_test_validate_entry(fei,
5699 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5701 &l1600_eos_o_1_1_1_1),
5702 "2.2.2.2/32 LB 1 buckets via: "
5703 "label 1600 via 1.1,1.1");
5705 dpo_reset(&non_eos_1_1_1_1);
5706 dpo_reset(&non_eos_1_1_1_2);
5709 * Add a recursive with no out-labels. We expect to use the IP of the via
5711 fib_prefix_t pfx_2_2_2_3_s_32 = {
5713 .fp_proto = FIB_PROTOCOL_IP4,
5715 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
5718 dpo_id_t ip_1_1_1_1 = DPO_NULL;
5720 fib_table_entry_update_one_path(fib_index,
5723 FIB_ENTRY_FLAG_NONE,
5725 &pfx_1_1_1_1_s_32.fp_addr,
5730 FIB_ROUTE_PATH_FLAG_NONE);
5732 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5734 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5737 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5740 .lb = ip_1_1_1_1.dpoi_index,
5744 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
5745 FIB_TEST(fib_test_validate_entry(fei,
5746 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5749 "2.2.2.2.3/32 LB 1 buckets via: "
5753 * Add a recursive with an imp-null out-label.
5754 * We expect to use the IP of the via
5756 fib_prefix_t pfx_2_2_2_4_s_32 = {
5758 .fp_proto = FIB_PROTOCOL_IP4,
5760 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
5764 fib_table_entry_update_one_path(fib_index,
5767 FIB_ENTRY_FLAG_NONE,
5769 &pfx_1_1_1_1_s_32.fp_addr,
5774 FIB_ROUTE_PATH_FLAG_NONE);
5776 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
5777 FIB_TEST(fib_test_validate_entry(fei,
5778 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5781 "2.2.2.2.4/32 LB 1 buckets via: "
5784 dpo_reset(&ip_1_1_1_1);
5789 fib_table_entry_delete(fib_index,
5793 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5794 FIB_TEST(fib_test_validate_entry(fei,
5795 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5797 &l1600_eos_o_1_1_1_1),
5798 "2.2.2.2/32 LB 1 buckets via: "
5799 "label 1600 via 1.1,1.1");
5801 fib_table_entry_delete(fib_index,
5805 FIB_TEST(fib_test_validate_entry(fei,
5806 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5809 "2.2.2.2/32 LB 1 buckets via: DROP");
5811 fib_table_entry_delete(fib_index,
5814 fib_table_entry_delete(fib_index,
5817 fib_table_entry_delete(fib_index,
5821 adj_unlock(ai_mpls_10_10_10_1);
5822 adj_unlock(ai_mpls_10_10_11_2);
5823 adj_unlock(ai_v4_10_10_11_1);
5824 adj_unlock(ai_v4_10_10_11_2);
5825 adj_unlock(ai_mpls_10_10_11_1);
5827 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5830 local0_pfx.fp_len = 32;
5831 fib_table_entry_delete(fib_index,
5833 FIB_SOURCE_INTERFACE);
5834 local0_pfx.fp_len = 24;
5835 fib_table_entry_delete(fib_index,
5837 FIB_SOURCE_INTERFACE);
5838 local1_pfx.fp_len = 32;
5839 fib_table_entry_delete(fib_index,
5841 FIB_SOURCE_INTERFACE);
5842 local1_pfx.fp_len = 24;
5843 fib_table_entry_delete(fib_index,
5845 FIB_SOURCE_INTERFACE);
5848 * +1 for the drop LB in the MPLS tables.
5850 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
5851 "Load-balance resources freed %d of %d",
5852 lb_count+1, pool_elts(load_balance_pool));
5855 #define N_TEST_CHILDREN 4
5856 #define PARENT_INDEX 0
5858 typedef struct fib_node_test_t_
5863 fib_node_back_walk_ctx_t *ctxs;
5867 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
5869 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
5871 #define FOR_EACH_TEST_CHILD(_tc) \
5872 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
5873 ii < N_TEST_CHILDREN+1; \
5874 ii++, (_tc) = &fib_test_nodes[ii])
5877 fib_test_child_get_node (fib_node_index_t index)
5879 return (&fib_test_nodes[index].node);
5882 static int fib_test_walk_spawns_walks;
5884 static fib_node_back_walk_rc_t
5885 fib_test_child_back_walk_notify (fib_node_t *node,
5886 fib_node_back_walk_ctx_t *ctx)
5888 fib_node_test_t *tc = (fib_node_test_t*) node;
5890 vec_add1(tc->ctxs, *ctx);
5892 if (1 == fib_test_walk_spawns_walks)
5893 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
5894 if (2 == fib_test_walk_spawns_walks)
5895 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
5896 FIB_WALK_PRIORITY_HIGH, ctx);
5898 return (FIB_NODE_BACK_WALK_CONTINUE);
5902 fib_test_child_last_lock_gone (fib_node_t *node)
5904 fib_node_test_t *tc = (fib_node_test_t *)node;
5910 * The FIB walk's graph node virtual function table
5912 static const fib_node_vft_t fib_test_child_vft = {
5913 .fnv_get = fib_test_child_get_node,
5914 .fnv_last_lock = fib_test_child_last_lock_gone,
5915 .fnv_back_walk = fib_test_child_back_walk_notify,
5919 * the function (that should have been static but isn't so I can do this)
5920 * that processes the walk from the async queue,
5922 f64 fib_walk_process_queues(vlib_main_t * vm,
5924 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
5927 fib_test_walk (void)
5929 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
5930 fib_node_test_t *tc;
5934 vm = vlib_get_main();
5935 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
5938 * init a fake node on which we will add children
5940 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
5941 FIB_NODE_TYPE_TEST);
5943 FOR_EACH_TEST_CHILD(tc)
5945 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
5946 fib_node_lock(&tc->node);
5949 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
5951 FIB_NODE_TYPE_TEST, ii);
5955 * enqueue a walk across the parents children.
5957 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
5959 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
5960 FIB_WALK_PRIORITY_HIGH, &high_ctx);
5961 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
5962 "Parent has %d children pre-walk",
5963 fib_node_list_get_size(PARENT()->fn_children));
5966 * give the walk a large amount of time so it gets to the end
5968 fib_walk_process_queues(vm, 1);
5970 FOR_EACH_TEST_CHILD(tc)
5972 FIB_TEST(1 == vec_len(tc->ctxs),
5973 "%d child visitsed %d times",
5974 ii, vec_len(tc->ctxs));
5977 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
5978 "Queue is empty post walk");
5979 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
5980 "Parent has %d children post walk",
5981 fib_node_list_get_size(PARENT()->fn_children));
5984 * walk again. should be no increase in the number of visits, since
5985 * the walk will have terminated.
5987 fib_walk_process_queues(vm, 1);
5989 FOR_EACH_TEST_CHILD(tc)
5991 FIB_TEST(0 == vec_len(tc->ctxs),
5992 "%d child visitsed %d times",
5993 ii, vec_len(tc->ctxs));
5997 * schedule a low and hig priority walk. expect the high to be performed
5999 * schedule the high prio walk first so that it is further from the head
6000 * of the dependency list. that way it won't merge with the low one.
6002 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6003 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6005 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6006 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6007 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6008 FIB_WALK_PRIORITY_LOW, &low_ctx);
6010 fib_walk_process_queues(vm, 1);
6012 FOR_EACH_TEST_CHILD(tc)
6014 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6015 "%d child visitsed by high prio walk", ii);
6016 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6017 "%d child visitsed by low prio walk", ii);
6020 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6021 "Queue is empty post prio walk");
6022 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6023 "Parent has %d children post prio walk",
6024 fib_node_list_get_size(PARENT()->fn_children));
6027 * schedule 2 walks of the same priority that can be megred.
6028 * expect that each child is thus visited only once.
6030 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6031 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6033 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6034 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6035 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6036 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6038 fib_walk_process_queues(vm, 1);
6040 FOR_EACH_TEST_CHILD(tc)
6042 FIB_TEST(1 == vec_len(tc->ctxs),
6043 "%d child visitsed %d times during merge walk",
6044 ii, vec_len(tc->ctxs));
6047 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6048 "Queue is empty post merge walk");
6049 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6050 "Parent has %d children post merge walk",
6051 fib_node_list_get_size(PARENT()->fn_children));
6054 * schedule 2 walks of the same priority that cannot be megred.
6055 * expect that each child is thus visited twice and in the order
6056 * in which the walks were scheduled.
6058 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6059 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6061 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6062 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6063 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6064 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6066 fib_walk_process_queues(vm, 1);
6068 FOR_EACH_TEST_CHILD(tc)
6070 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6071 "%d child visitsed by high prio walk", ii);
6072 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6073 "%d child visitsed by low prio walk", ii);
6076 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6077 "Queue is empty post no-merge walk");
6078 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6079 "Parent has %d children post no-merge walk",
6080 fib_node_list_get_size(PARENT()->fn_children));
6083 * schedule a walk that makes one one child progress.
6084 * we do this by giving the queue draining process zero
6085 * time quanta. it's a do..while loop, so it does something.
6087 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
6089 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6090 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6091 fib_walk_process_queues(vm, 0);
6093 FOR_EACH_TEST_CHILD(tc)
6095 if (ii == N_TEST_CHILDREN)
6097 FIB_TEST(1 == vec_len(tc->ctxs),
6098 "%d child visitsed %d times in zero quanta walk",
6099 ii, vec_len(tc->ctxs));
6103 FIB_TEST(0 == vec_len(tc->ctxs),
6104 "%d child visitsed %d times in 0 quanta walk",
6105 ii, vec_len(tc->ctxs));
6108 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6109 "Queue is not empty post zero quanta walk");
6110 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6111 "Parent has %d children post zero qunta walk",
6112 fib_node_list_get_size(PARENT()->fn_children));
6117 fib_walk_process_queues(vm, 0);
6119 FOR_EACH_TEST_CHILD(tc)
6121 if (ii >= N_TEST_CHILDREN-1)
6123 FIB_TEST(1 == vec_len(tc->ctxs),
6124 "%d child visitsed %d times in 2nd zero quanta walk",
6125 ii, vec_len(tc->ctxs));
6129 FIB_TEST(0 == vec_len(tc->ctxs),
6130 "%d child visitsed %d times in 2nd 0 quanta walk",
6131 ii, vec_len(tc->ctxs));
6134 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6135 "Queue is not empty post zero quanta walk");
6136 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6137 "Parent has %d children post zero qunta walk",
6138 fib_node_list_get_size(PARENT()->fn_children));
6141 * schedule another walk that will catch-up and merge.
6143 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6144 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6145 fib_walk_process_queues(vm, 1);
6147 FOR_EACH_TEST_CHILD(tc)
6149 if (ii >= N_TEST_CHILDREN-1)
6151 FIB_TEST(2 == vec_len(tc->ctxs),
6152 "%d child visitsed %d times in 2nd zero quanta merge walk",
6153 ii, vec_len(tc->ctxs));
6158 FIB_TEST(1 == vec_len(tc->ctxs),
6159 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6160 ii, vec_len(tc->ctxs));
6164 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6165 "Queue is not empty post 2nd zero quanta merge walk");
6166 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6167 "Parent has %d children post 2nd zero qunta merge walk",
6168 fib_node_list_get_size(PARENT()->fn_children));
6171 * park a async walk in the middle of the list, then have an sync walk catch
6172 * it. same expectations as async catches async.
6174 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_RESOLVE;
6176 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6177 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6179 fib_walk_process_queues(vm, 0);
6180 fib_walk_process_queues(vm, 0);
6182 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6184 FOR_EACH_TEST_CHILD(tc)
6186 if (ii >= N_TEST_CHILDREN-1)
6188 FIB_TEST(2 == vec_len(tc->ctxs),
6189 "%d child visitsed %d times in sync catches async walk",
6190 ii, vec_len(tc->ctxs));
6195 FIB_TEST(1 == vec_len(tc->ctxs),
6196 "%d child visitsed %d times in sync catches async walk",
6197 ii, vec_len(tc->ctxs));
6201 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6202 "Queue is not empty post 2nd zero quanta merge walk");
6203 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6204 "Parent has %d children post 2nd zero qunta merge walk",
6205 fib_node_list_get_size(PARENT()->fn_children));
6208 * make the parent a child of one of its children, thus inducing a routing loop.
6210 fib_test_nodes[PARENT_INDEX].sibling =
6211 fib_node_child_add(FIB_NODE_TYPE_TEST,
6212 1, // the first child
6217 * execute a sync walk from the parent. each child visited spawns more sync
6218 * walks. we expect the walk to terminate.
6220 fib_test_walk_spawns_walks = 1;
6222 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6224 FOR_EACH_TEST_CHILD(tc)
6227 * child 1 - which is last in the list - has the loop.
6228 * the other children a re thus visitsed first. the we meet
6229 * child 1. we go round the loop again, visting the other children.
6230 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6235 FIB_TEST(1 == vec_len(tc->ctxs),
6236 "child %d visitsed %d times during looped sync walk",
6237 ii, vec_len(tc->ctxs));
6241 FIB_TEST(2 == vec_len(tc->ctxs),
6242 "child %d visitsed %d times during looped sync walk",
6243 ii, vec_len(tc->ctxs));
6247 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6248 "Parent has %d children post sync loop walk",
6249 fib_node_list_get_size(PARENT()->fn_children));
6252 * the walk doesn't reach the max depth because the infra knows that sync
6253 * meets sync implies a loop and bails early.
6255 FIB_TEST(high_ctx.fnbw_depth == 9,
6256 "Walk context depth %d post sync loop walk",
6257 high_ctx.fnbw_depth);
6260 * execute an async walk of the graph loop, with each child spawns sync walks
6262 high_ctx.fnbw_depth = 0;
6263 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6264 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6266 fib_walk_process_queues(vm, 1);
6268 FOR_EACH_TEST_CHILD(tc)
6271 * we don't really care how many times the children are visisted, as long as
6272 * it is more than once.
6274 FIB_TEST(1 <= vec_len(tc->ctxs),
6275 "child %d visitsed %d times during looped aync spawns sync walk",
6276 ii, vec_len(tc->ctxs));
6281 * execute an async walk of the graph loop, with each child spawns async walks
6283 fib_test_walk_spawns_walks = 2;
6284 high_ctx.fnbw_depth = 0;
6285 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6286 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6288 fib_walk_process_queues(vm, 1);
6290 FOR_EACH_TEST_CHILD(tc)
6293 * we don't really care how many times the children are visisted, as long as
6294 * it is more than once.
6296 FIB_TEST(1 <= vec_len(tc->ctxs),
6297 "child %d visitsed %d times during looped async spawns async walk",
6298 ii, vec_len(tc->ctxs));
6303 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6304 1, // the first child
6305 fib_test_nodes[PARENT_INDEX].sibling);
6310 FOR_EACH_TEST_CHILD(tc)
6312 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6314 fib_node_deinit(&tc->node);
6315 fib_node_unlock(&tc->node);
6317 fib_node_deinit(PARENT());
6320 * The parent will be destroyed when the last lock on it goes.
6321 * this test ensures all the walk objects are unlocking it.
6323 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6324 "Parent was destroyed");
6328 lfib_test_deagg (void)
6330 const mpls_label_t deag_label = 50;
6331 const u32 lfib_index = 0;
6332 const u32 fib_index = 0;
6333 dpo_id_t dpo = DPO_NULL;
6334 const dpo_id_t *dpo1;
6335 fib_node_index_t lfe;
6341 lb_count = pool_elts(load_balance_pool);
6343 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6347 * MPLS enable an interface so we get the MPLS table created
6349 mpls_sw_interface_enable_disable(&mpls_main,
6350 tm->hw[0]->sw_if_index,
6354 * Test the specials stack properly.
6356 fib_prefix_t exp_null_v6_pfx = {
6357 .fp_proto = FIB_PROTOCOL_MPLS,
6359 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6360 .fp_payload_proto = DPO_PROTO_IP6,
6362 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
6363 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
6365 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6366 format_mpls_eos_bit, MPLS_EOS);
6367 fib_entry_contribute_forwarding(lfe,
6368 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6370 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6371 lkd = lookup_dpo_get(dpo1->dpoi_index);
6373 FIB_TEST((fib_index == lkd->lkd_fib_index),
6374 "%U/%U is deag in %d %U",
6375 format_mpls_unicast_label, deag_label,
6376 format_mpls_eos_bit, MPLS_EOS,
6378 format_dpo_id, &dpo, 0);
6379 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6380 "%U/%U is dst deag",
6381 format_mpls_unicast_label, deag_label,
6382 format_mpls_eos_bit, MPLS_EOS);
6383 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
6384 "%U/%U is lookup in interface's table",
6385 format_mpls_unicast_label, deag_label,
6386 format_mpls_eos_bit, MPLS_EOS);
6387 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
6388 "%U/%U is %U dst deag",
6389 format_mpls_unicast_label, deag_label,
6390 format_mpls_eos_bit, MPLS_EOS,
6391 format_dpo_proto, lkd->lkd_proto);
6395 * A route deag route for EOS
6397 fib_prefix_t pfx = {
6398 .fp_proto = FIB_PROTOCOL_MPLS,
6400 .fp_label = deag_label,
6401 .fp_payload_proto = DPO_PROTO_IP4,
6403 lfe = fib_table_entry_path_add(lfib_index,
6406 FIB_ENTRY_FLAG_NONE,
6413 FIB_ROUTE_PATH_FLAG_NONE);
6415 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6417 format_mpls_unicast_label, deag_label,
6418 format_mpls_eos_bit, MPLS_EOS);
6420 fib_entry_contribute_forwarding(lfe,
6421 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6423 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6424 lkd = lookup_dpo_get(dpo1->dpoi_index);
6426 FIB_TEST((fib_index == lkd->lkd_fib_index),
6427 "%U/%U is deag in %d %U",
6428 format_mpls_unicast_label, deag_label,
6429 format_mpls_eos_bit, MPLS_EOS,
6431 format_dpo_id, &dpo, 0);
6432 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6433 "%U/%U is dst deag",
6434 format_mpls_unicast_label, deag_label,
6435 format_mpls_eos_bit, MPLS_EOS);
6436 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
6437 "%U/%U is %U dst deag",
6438 format_mpls_unicast_label, deag_label,
6439 format_mpls_eos_bit, MPLS_EOS,
6440 format_dpo_proto, lkd->lkd_proto);
6442 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6444 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6446 "%U/%U not present",
6447 format_mpls_unicast_label, deag_label,
6448 format_mpls_eos_bit, MPLS_EOS);
6451 * A route deag route for non-EOS
6453 pfx.fp_eos = MPLS_NON_EOS;
6454 lfe = fib_table_entry_path_add(lfib_index,
6457 FIB_ENTRY_FLAG_NONE,
6464 FIB_ROUTE_PATH_FLAG_NONE);
6466 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6468 format_mpls_unicast_label, deag_label,
6469 format_mpls_eos_bit, MPLS_NON_EOS);
6471 fib_entry_contribute_forwarding(lfe,
6472 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6474 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6475 lkd = lookup_dpo_get(dpo1->dpoi_index);
6477 FIB_TEST((fib_index == lkd->lkd_fib_index),
6478 "%U/%U is deag in %d %U",
6479 format_mpls_unicast_label, deag_label,
6480 format_mpls_eos_bit, MPLS_NON_EOS,
6482 format_dpo_id, &dpo, 0);
6483 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6484 "%U/%U is dst deag",
6485 format_mpls_unicast_label, deag_label,
6486 format_mpls_eos_bit, MPLS_NON_EOS);
6488 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
6489 "%U/%U is %U dst deag",
6490 format_mpls_unicast_label, deag_label,
6491 format_mpls_eos_bit, MPLS_NON_EOS,
6492 format_dpo_proto, lkd->lkd_proto);
6494 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6496 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6498 "%U/%U not present",
6499 format_mpls_unicast_label, deag_label,
6500 format_mpls_eos_bit, MPLS_EOS);
6503 mpls_sw_interface_enable_disable(&mpls_main,
6504 tm->hw[0]->sw_if_index,
6509 * +1 for the drop LB in the MPLS tables.
6511 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6512 "Load-balance resources freed %d of %d",
6513 lb_count+1, pool_elts(load_balance_pool));
6516 static clib_error_t *
6517 lfib_test (vlib_main_t * vm,
6518 unformat_input_t * input,
6519 vlib_cli_command_t * cmd_arg)
6521 fib_test_mk_intf(4);
6528 static clib_error_t *
6529 fib_test (vlib_main_t * vm,
6530 unformat_input_t * input,
6531 vlib_cli_command_t * cmd_arg)
6533 fib_test_mk_intf(4);
6535 if (unformat (input, "ip"))
6540 else if (unformat (input, "gre"))
6544 else if (unformat (input, "label"))
6548 else if (unformat (input, "ae"))
6552 else if (unformat (input, "walk"))
6559 * These walk UT aren't run as part of the full suite, since the
6560 * fib-walk process must be disabled in order for the tests to work
6574 VLIB_CLI_COMMAND (test_fib_command, static) = {
6576 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6577 .function = fib_test,
6580 VLIB_CLI_COMMAND (test_lfib_command, static) = {
6581 .path = "test lfib",
6582 .short_help = "mpls label fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
6583 .function = lfib_test,
6587 fib_test_init (vlib_main_t *vm)
6592 VLIB_INIT_FUNCTION (fib_test_init);