2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/fib/ip6_fib.h>
17 #include <vnet/fib/ip4_fib.h>
18 #include <vnet/fib/mpls_fib.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/dpo/load_balance_map.h>
22 #include <vnet/dpo/mpls_label_dpo.h>
23 #include <vnet/dpo/lookup_dpo.h>
24 #include <vnet/dpo/drop_dpo.h>
25 #include <vnet/dpo/receive_dpo.h>
26 #include <vnet/dpo/ip_null_dpo.h>
28 #include <vnet/mpls/mpls.h>
30 #include <vnet/fib/fib_path_list.h>
31 #include <vnet/fib/fib_entry_src.h>
32 #include <vnet/fib/fib_walk.h>
33 #include <vnet/fib/fib_node_list.h>
34 #include <vnet/fib/fib_urpf_list.h>
36 #define FIB_TEST_I(_cond, _comment, _args...) \
38 int _evald = (_cond); \
40 fformat(stderr, "FAIL:%d: " _comment "\n", \
43 fformat(stderr, "PASS:%d: " _comment "\n", \
48 #define FIB_TEST(_cond, _comment, _args...) \
50 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
52 ASSERT(!("FAIL: " _comment)); \
57 * A 'i'm not fussed is this is not efficient' store of test data
59 typedef struct test_main_t_ {
63 u32 hw_if_indicies[4];
67 vnet_hw_interface_t * hw[4];
70 static test_main_t test_main;
72 /* fake ethernet device class, distinct from "fake-ethX" */
73 static u8 * format_test_interface_name (u8 * s, va_list * args)
75 u32 dev_instance = va_arg (*args, u32);
76 return format (s, "test-eth%d", dev_instance);
79 static uword dummy_interface_tx (vlib_main_t * vm,
80 vlib_node_runtime_t * node,
83 clib_warning ("you shouldn't be here, leaking buffers...");
84 return frame->n_vectors;
88 test_interface_admin_up_down (vnet_main_t * vnm,
92 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
93 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
94 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
98 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
99 .name = "Test interface",
100 .format_device_name = format_test_interface_name,
101 .tx_function = dummy_interface_tx,
102 .admin_up_down_function = test_interface_admin_up_down,
105 static u8 *hw_address;
108 fib_test_mk_intf (u32 ninterfaces)
110 clib_error_t * error = NULL;
111 test_main_t *tm = &test_main;
115 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
120 vec_add1(hw_address, byte);
123 for (i = 0; i < ninterfaces; i++)
127 error = ethernet_register_interface(vnet_get_main(),
128 test_interface_device_class.index,
131 &tm->hw_if_indicies[i],
132 /* flag change */ 0);
134 FIB_TEST((NULL == error), "ADD interface %d", i);
136 error = vnet_hw_interface_set_flags(vnet_get_main(),
137 tm->hw_if_indicies[i],
138 VNET_HW_INTERFACE_FLAG_LINK_UP);
139 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
140 tm->hw_if_indicies[i]);
141 vec_validate (ip4_main.fib_index_by_sw_if_index,
142 tm->hw[i]->sw_if_index);
143 vec_validate (ip6_main.fib_index_by_sw_if_index,
144 tm->hw[i]->sw_if_index);
145 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
146 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
148 error = vnet_sw_interface_set_flags(vnet_get_main(),
149 tm->hw[i]->sw_if_index,
150 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
151 FIB_TEST((NULL == error), "UP interface %d", i);
154 * re-eval after the inevitable realloc
156 for (i = 0; i < ninterfaces; i++)
158 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
159 tm->hw_if_indicies[i]);
165 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
167 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
168 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
169 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
170 fib_table_lookup(fib_index, (_via_prefix))); \
171 FIB_TEST(!dpo_cmp(_via_dpo, \
172 load_balance_get_bucket(_rec_dpo->dpoi_index, \
174 "%U is recursive via %U", \
175 format_fib_prefix, (_rec_prefix), \
176 format_fib_prefix, _via_prefix); \
179 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
181 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
182 fib_table_lookup_exact_match(fib_index, (_prefix))); \
183 const dpo_id_t *_dpo1 = \
184 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
185 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
186 format_dpo_type, _dpo1->dpoi_type); \
187 FIB_TEST((_ai == _dpo1->dpoi_index), \
188 "%U bucket %d resolves via %U", \
189 format_fib_prefix, (_prefix), \
191 format_dpo_id, _dpo1, 0); \
194 #define FIB_TEST_RPF(_cond, _comment, _args...) \
196 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
202 fib_test_urpf_is_equal (fib_node_index_t fei,
203 fib_forward_chain_type_t fct,
206 dpo_id_t dpo = DPO_INVALID;
207 fib_urpf_list_t *urpf;
214 fib_entry_contribute_forwarding(fei, fct, &dpo);
215 ui = load_balance_get_urpf(dpo.dpoi_index);
217 urpf = fib_urpf_list_get(ui);
219 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
220 "RPF:%U len %d == %d",
221 format_fib_urpf_list, ui,
222 num, vec_len(urpf->furpf_itfs));
223 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
224 "RPF:%U check-size %d == %d",
225 format_fib_urpf_list, ui,
226 num, vec_len(urpf->furpf_itfs));
228 for (ii = 0; ii < num; ii++)
230 adj_index_t ai = va_arg(ap, adj_index_t);
232 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
233 "RPF:%d item:%d - %d == %d",
234 ui, ii, ai, urpf->furpf_itfs[ii]);
235 FIB_TEST_RPF(fib_urpf_check(ui, ai),
248 fib_test_build_rewrite (u8 *eth_addr)
252 vec_validate(rewrite, 13);
254 memcpy(rewrite, eth_addr, 6);
255 memcpy(rewrite+6, eth_addr, 6);
260 typedef enum fib_test_lb_bucket_type_t_ {
262 FT_LB_LABEL_STACK_O_ADJ,
267 } fib_test_lb_bucket_type_t;
269 typedef struct fib_test_lb_bucket_t_ {
270 fib_test_lb_bucket_type_t type;
284 mpls_label_t label_stack[8];
309 } fib_test_lb_bucket_t;
311 #define FIB_TEST_LB(_cond, _comment, _args...) \
313 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
319 fib_test_validate_lb_v (const load_balance_t *lb,
326 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
328 for (bucket = 0; bucket < n_buckets; bucket++)
330 const fib_test_lb_bucket_t *exp;
332 exp = va_arg(ap, fib_test_lb_bucket_t*);
333 dpo = load_balance_get_bucket_i(lb, bucket);
337 case FT_LB_LABEL_STACK_O_ADJ:
339 const mpls_label_dpo_t *mld;
343 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
344 "bucket %d stacks on %U",
346 format_dpo_type, dpo->dpoi_type);
348 mld = mpls_label_dpo_get(dpo->dpoi_index);
350 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
354 for (ii = 0; ii < mld->mld_n_labels; ii++)
356 hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
357 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
358 exp->label_stack_o_adj.label_stack[ii]),
359 "bucket %d stacks on label %d",
361 exp->label_stack_o_adj.label_stack[ii]);
363 if (ii == mld->mld_n_labels-1)
365 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
366 exp->label_o_adj.eos),
367 "bucket %d stacks on label %d %U!=%U",
369 exp->label_stack_o_adj.label_stack[ii],
370 format_mpls_eos_bit, exp->label_o_adj.eos,
371 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
375 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
376 "bucket %d stacks on label %d %U",
378 exp->label_stack_o_adj.label_stack[ii],
379 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
383 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
384 "bucket %d label stacks on %U",
386 format_dpo_type, mld->mld_dpo.dpoi_type);
388 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
389 "bucket %d label stacks on adj %d",
391 exp->label_stack_o_adj.adj);
394 case FT_LB_LABEL_O_ADJ:
396 const mpls_label_dpo_t *mld;
398 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
399 "bucket %d stacks on %U",
401 format_dpo_type, dpo->dpoi_type);
403 mld = mpls_label_dpo_get(dpo->dpoi_index);
404 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
406 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
407 exp->label_o_adj.label),
408 "bucket %d stacks on label %d",
410 exp->label_o_adj.label);
412 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
413 exp->label_o_adj.eos),
414 "bucket %d stacks on label %d %U",
416 exp->label_o_adj.label,
417 format_mpls_eos_bit, exp->label_o_adj.eos);
419 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
420 "bucket %d label stacks on %U",
422 format_dpo_type, mld->mld_dpo.dpoi_type);
424 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
425 "bucket %d label stacks on adj %d",
427 exp->label_o_adj.adj);
430 case FT_LB_LABEL_O_LB:
432 const mpls_label_dpo_t *mld;
435 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
436 "bucket %d stacks on %U",
438 format_dpo_type, dpo->dpoi_type);
440 mld = mpls_label_dpo_get(dpo->dpoi_index);
441 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
443 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
445 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
446 exp->label_o_lb.label),
447 "bucket %d stacks on label %d",
449 exp->label_o_lb.label);
451 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
452 exp->label_o_lb.eos),
453 "bucket %d stacks on label %d %U",
455 exp->label_o_lb.label,
456 format_mpls_eos_bit, exp->label_o_lb.eos);
458 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
459 "bucket %d label stacks on %U",
461 format_dpo_type, mld->mld_dpo.dpoi_type);
463 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
464 "bucket %d label stacks on LB %d",
470 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
471 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
472 "bucket %d stacks on %U",
474 format_dpo_type, dpo->dpoi_type);
475 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
476 "bucket %d stacks on adj %d",
481 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
482 "bucket %d stacks on %U",
484 format_dpo_type, dpo->dpoi_type);
485 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
486 "bucket %d stacks on lb %d",
491 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
492 "bucket %d stacks on %U",
494 format_dpo_type, dpo->dpoi_type);
495 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
496 "bucket %d stacks on drop %d",
506 fib_test_validate_entry (fib_node_index_t fei,
507 fib_forward_chain_type_t fct,
511 dpo_id_t dpo = DPO_INVALID;
512 const load_balance_t *lb;
519 va_start(ap, n_buckets);
521 fib_entry_get_prefix(fei, &pfx);
522 fib_index = fib_entry_get_fib_index(fei);
523 fib_entry_contribute_forwarding(fei, fct, &dpo);
525 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
527 format_dpo_type, dpo.dpoi_type);
528 lb = load_balance_get(dpo.dpoi_index);
530 res = fib_test_validate_lb_v(lb, n_buckets, ap);
533 * ensure that the LB contributed by the entry is the
534 * same as the LB in the forwarding tables
536 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
538 switch (pfx.fp_proto)
540 case FIB_PROTOCOL_IP4:
541 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
543 case FIB_PROTOCOL_IP6:
544 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
546 case FIB_PROTOCOL_MPLS:
548 mpls_unicast_header_t hdr = {
549 .label_exp_s_ttl = 0,
552 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
553 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
554 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
556 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
562 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
563 "Contributed LB = FW LB: %U\n %U",
564 format_load_balance, fw_lbi, 0,
565 format_load_balance, dpo.dpoi_index, 0);
579 * In the default table check for the presence and correct forwarding
580 * of the special entries
582 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
583 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
584 const ip_adjacency_t *adj;
585 const load_balance_t *lb;
591 ip46_address_t nh_10_10_10_1 = {
592 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
595 ip46_address_t nh_10_10_10_2 = {
596 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
601 /* Find or create FIB table 11 */
602 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
604 for (ii = 0; ii < 4; ii++)
606 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
609 fib_prefix_t pfx_0_0_0_0_s_0 = {
611 .fp_proto = FIB_PROTOCOL_IP4,
621 .fp_proto = FIB_PROTOCOL_IP4,
629 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
631 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
632 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
633 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
634 "Default route is DROP");
637 fei = fib_table_lookup(fib_index, &pfx);
638 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
639 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
640 "all 0s route is DROP");
642 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
644 fei = fib_table_lookup(fib_index, &pfx);
645 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
646 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
647 "all 1s route is DROP");
649 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
651 fei = fib_table_lookup(fib_index, &pfx);
652 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
653 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
654 "all-mcast route is DROP");
656 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
658 fei = fib_table_lookup(fib_index, &pfx);
659 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
660 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
661 "class-e route is DROP");
664 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
665 * all of which are special sourced and so none of which share path-lists.
666 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
667 * table, and 4 path-lists in the v6 MFIB table
671 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
672 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
673 fib_path_list_pool_size());
674 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
675 fib_entry_pool_size());
678 * add interface routes.
679 * validate presence of /24 attached and /32 recieve.
680 * test for the presence of the receive address in the glean and local adj
682 fib_prefix_t local_pfx = {
684 .fp_proto = FIB_PROTOCOL_IP4,
687 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
692 fib_table_entry_update_one_path(fib_index, &local_pfx,
693 FIB_SOURCE_INTERFACE,
694 (FIB_ENTRY_FLAG_CONNECTED |
695 FIB_ENTRY_FLAG_ATTACHED),
698 tm->hw[0]->sw_if_index,
699 ~0, // invalid fib index
702 FIB_ROUTE_PATH_FLAG_NONE);
703 fei = fib_table_lookup(fib_index, &local_pfx);
704 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
705 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
706 fib_entry_get_flags(fei)),
707 "Flags set on attached interface");
709 ai = fib_entry_get_adj(fei);
710 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
712 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
713 "attached interface adj is glean");
714 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
715 &adj->sub_type.glean.receive_addr)),
716 "attached interface adj is receive ok");
718 local_pfx.fp_len = 32;
719 fib_table_entry_update_one_path(fib_index, &local_pfx,
720 FIB_SOURCE_INTERFACE,
721 (FIB_ENTRY_FLAG_CONNECTED |
722 FIB_ENTRY_FLAG_LOCAL),
725 tm->hw[0]->sw_if_index,
726 ~0, // invalid fib index
729 FIB_ROUTE_PATH_FLAG_NONE);
730 fei = fib_table_lookup(fib_index, &local_pfx);
731 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
732 fib_entry_get_flags(fei)),
733 "Flags set on local interface");
735 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
737 dpo = fib_entry_contribute_ip_forwarding(fei);
738 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
739 "RPF list for local length 0");
740 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
741 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
742 "local interface adj is local");
743 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
745 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
747 "local interface adj is receive ok");
749 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
751 FIB_SOURCE_INTERFACE)),
752 "2 Interface Source'd prefixes");
755 * +2 interface routes +2 non-shared path-lists
757 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
758 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
759 fib_path_list_pool_size());
760 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
761 fib_entry_pool_size());
764 * Modify the default route to be via an adj not yet known.
765 * this sources the defalut route with the API source, which is
766 * a higher preference to the DEFAULT_ROUTE source
768 pfx.fp_addr.ip4.as_u32 = 0;
770 fib_table_entry_path_add(fib_index, &pfx,
775 tm->hw[0]->sw_if_index,
776 ~0, // invalid fib index
779 FIB_ROUTE_PATH_FLAG_NONE);
780 fei = fib_table_lookup(fib_index, &pfx);
781 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
782 "Flags set on API route");
784 FIB_TEST((fei == dfrt), "default route same index");
785 ai = fib_entry_get_adj(fei);
786 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
788 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
789 "adj is incomplete");
790 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
791 "adj nbr next-hop ok");
792 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
795 "1 API Source'd prefixes");
798 * find the adj in the shared db
800 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
803 tm->hw[0]->sw_if_index);
804 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
805 adj_unlock(locked_ai);
808 * +1 shared path-list
810 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
811 fib_path_list_db_size());
812 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
813 fib_path_list_pool_size());
814 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
815 fib_entry_pool_size());
818 * remove the API source from the default route. We expected
819 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
821 pfx.fp_addr.ip4.as_u32 = 0;
823 fib_table_entry_path_remove(fib_index, &pfx,
827 tm->hw[0]->sw_if_index,
828 ~0, // non-recursive path, so no FIB index
830 FIB_ROUTE_PATH_FLAG_NONE);
832 fei = fib_table_lookup(fib_index, &pfx);
834 FIB_TEST((fei == dfrt), "default route same index");
835 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
836 "Default route is DROP");
839 * -1 shared-path-list
841 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
842 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
843 fib_path_list_pool_size());
844 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
845 fib_entry_pool_size());
848 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
850 fib_prefix_t pfx_10_10_10_1_s_32 = {
852 .fp_proto = FIB_PROTOCOL_IP4,
855 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
858 fib_prefix_t pfx_10_10_10_2_s_32 = {
860 .fp_proto = FIB_PROTOCOL_IP4,
863 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
866 fib_prefix_t pfx_11_11_11_11_s_32 = {
868 .fp_proto = FIB_PROTOCOL_IP4,
871 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
875 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
878 ip46_address_t nh_12_12_12_12 = {
879 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
881 adj_index_t ai_12_12_12_12;
884 * Add a route via an incomplete ADJ. then complete the ADJ
885 * Expect the route LB is updated to use complete adj type.
887 fei = fib_table_entry_update_one_path(fib_index,
888 &pfx_11_11_11_11_s_32,
890 FIB_ENTRY_FLAG_ATTACHED,
892 &pfx_10_10_10_1_s_32.fp_addr,
893 tm->hw[0]->sw_if_index,
894 ~0, // invalid fib index
897 FIB_ROUTE_PATH_FLAG_NONE);
899 dpo = fib_entry_contribute_ip_forwarding(fei);
900 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
901 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
902 "11.11.11.11/32 via incomplete adj");
904 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
906 &pfx_10_10_10_1_s_32.fp_addr,
907 tm->hw[0]->sw_if_index);
908 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
909 adj = adj_get(ai_01);
910 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
911 "adj is incomplete");
912 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
913 &adj->sub_type.nbr.next_hop)),
914 "adj nbr next-hop ok");
916 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
917 fib_test_build_rewrite(eth_addr));
918 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
920 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
921 &adj->sub_type.nbr.next_hop)),
922 "adj nbr next-hop ok");
923 ai = fib_entry_get_adj(fei);
924 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
926 dpo = fib_entry_contribute_ip_forwarding(fei);
927 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
928 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
929 "11.11.11.11/32 via complete adj");
930 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
931 tm->hw[0]->sw_if_index),
932 "RPF list for adj-fib contains adj");
934 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
937 tm->hw[1]->sw_if_index);
938 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
939 adj = adj_get(ai_12_12_12_12);
940 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
941 "adj is incomplete");
942 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
943 &adj->sub_type.nbr.next_hop)),
944 "adj nbr next-hop ok");
945 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
946 fib_test_build_rewrite(eth_addr));
947 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
953 fei = fib_table_entry_update_one_path(fib_index,
954 &pfx_10_10_10_1_s_32,
956 FIB_ENTRY_FLAG_ATTACHED,
958 &pfx_10_10_10_1_s_32.fp_addr,
959 tm->hw[0]->sw_if_index,
960 ~0, // invalid fib index
963 FIB_ROUTE_PATH_FLAG_NONE);
964 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
965 "Flags set on adj-fib");
966 ai = fib_entry_get_adj(fei);
967 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
969 fib_table_entry_path_remove(fib_index,
970 &pfx_11_11_11_11_s_32,
973 &pfx_10_10_10_1_s_32.fp_addr,
974 tm->hw[0]->sw_if_index,
975 ~0, // invalid fib index
977 FIB_ROUTE_PATH_FLAG_NONE);
981 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
983 &pfx_10_10_10_2_s_32.fp_addr,
984 tm->hw[0]->sw_if_index);
985 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
986 adj = adj_get(ai_02);
987 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
988 "adj is incomplete");
989 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
990 &adj->sub_type.nbr.next_hop)),
991 "adj nbr next-hop ok");
993 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
994 fib_test_build_rewrite(eth_addr));
995 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
997 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
998 &adj->sub_type.nbr.next_hop)),
999 "adj nbr next-hop ok");
1000 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1002 fib_table_entry_update_one_path(fib_index,
1003 &pfx_10_10_10_2_s_32,
1005 FIB_ENTRY_FLAG_ATTACHED,
1007 &pfx_10_10_10_2_s_32.fp_addr,
1008 tm->hw[0]->sw_if_index,
1009 ~0, // invalid fib index
1012 FIB_ROUTE_PATH_FLAG_NONE);
1014 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1015 ai = fib_entry_get_adj(fei);
1016 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1019 * +2 adj-fibs, and their non-shared path-lists
1021 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1022 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1023 fib_path_list_pool_size());
1024 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1025 fib_entry_pool_size());
1028 * Add 2 routes via the first ADJ. ensure path-list sharing
1030 fib_prefix_t pfx_1_1_1_1_s_32 = {
1032 .fp_proto = FIB_PROTOCOL_IP4,
1035 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1039 fib_table_entry_path_add(fib_index,
1042 FIB_ENTRY_FLAG_NONE,
1045 tm->hw[0]->sw_if_index,
1046 ~0, // invalid fib index
1049 FIB_ROUTE_PATH_FLAG_NONE);
1050 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1051 ai = fib_entry_get_adj(fei);
1052 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1055 * +1 entry and a shared path-list
1057 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1058 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1059 fib_path_list_pool_size());
1060 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1061 fib_entry_pool_size());
1064 fib_prefix_t pfx_1_1_2_0_s_24 = {
1066 .fp_proto = FIB_PROTOCOL_IP4,
1068 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1072 fib_table_entry_path_add(fib_index,
1075 FIB_ENTRY_FLAG_NONE,
1078 tm->hw[0]->sw_if_index,
1079 ~0, // invalid fib index
1082 FIB_ROUTE_PATH_FLAG_NONE);
1083 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1084 ai = fib_entry_get_adj(fei);
1085 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1090 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1091 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1092 fib_path_list_pool_size());
1093 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1094 fib_entry_pool_size());
1097 * modify 1.1.2.0/24 to use multipath.
1099 fib_table_entry_path_add(fib_index,
1102 FIB_ENTRY_FLAG_NONE,
1105 tm->hw[0]->sw_if_index,
1106 ~0, // invalid fib index
1109 FIB_ROUTE_PATH_FLAG_NONE);
1110 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1111 dpo = fib_entry_contribute_ip_forwarding(fei);
1112 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1113 1, tm->hw[0]->sw_if_index),
1114 "RPF list for 1.1.2.0/24 contains both adjs");
1116 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1117 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1118 FIB_TEST((ai_01 == dpo1->dpoi_index),
1119 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1120 ai_01, dpo1->dpoi_index);
1122 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1123 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1124 FIB_TEST((ai_02 == dpo1->dpoi_index),
1125 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1128 * +1 shared-pathlist
1130 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1131 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1132 fib_path_list_pool_size());
1133 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1134 fib_entry_pool_size());
1139 fib_table_entry_path_remove(fib_index,
1144 tm->hw[0]->sw_if_index,
1147 FIB_ROUTE_PATH_FLAG_NONE);
1148 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1149 dpo = fib_entry_contribute_ip_forwarding(fei);
1150 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1151 1, tm->hw[0]->sw_if_index),
1152 "RPF list for 1.1.2.0/24 contains one adj");
1154 ai = fib_entry_get_adj(fei);
1155 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1158 * +1 shared-pathlist
1160 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1161 fib_path_list_db_size());
1162 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1163 fib_path_list_pool_size());
1164 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1165 fib_entry_pool_size());
1168 * Add 2 recursive routes:
1169 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1170 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1172 fib_prefix_t bgp_100_pfx = {
1174 .fp_proto = FIB_PROTOCOL_IP4,
1176 /* 100.100.100.100/32 */
1177 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1181 ip46_address_t nh_1_1_1_1 = {
1182 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1185 fei = fib_table_entry_path_add(fib_index,
1188 FIB_ENTRY_FLAG_NONE,
1191 ~0, // no index provided.
1192 fib_index, // nexthop in same fib as route
1195 FIB_ROUTE_PATH_FLAG_NONE);
1197 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1198 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1199 tm->hw[0]->sw_if_index),
1200 "RPF list for adj-fib contains adj");
1203 * +1 entry and +1 shared-path-list
1205 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1206 fib_path_list_db_size());
1207 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1208 fib_path_list_pool_size());
1209 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1210 fib_entry_pool_size());
1212 fib_prefix_t bgp_101_pfx = {
1214 .fp_proto = FIB_PROTOCOL_IP4,
1216 /* 100.100.100.101/32 */
1217 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1221 fib_table_entry_path_add(fib_index,
1224 FIB_ENTRY_FLAG_NONE,
1227 ~0, // no index provided.
1228 fib_index, // nexthop in same fib as route
1231 FIB_ROUTE_PATH_FLAG_NONE);
1233 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1234 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1235 tm->hw[0]->sw_if_index),
1236 "RPF list for adj-fib contains adj");
1239 * +1 entry, but the recursive path-list is shared.
1241 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1242 fib_path_list_db_size());
1243 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1244 fib_path_list_pool_size());
1245 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1246 fib_entry_pool_size());
1249 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1250 * adjacency through which the route will resovle
1252 fib_prefix_t ex_pfx = {
1254 .fp_proto = FIB_PROTOCOL_IP4,
1257 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1261 fib_table_entry_special_add(fib_index,
1264 FIB_ENTRY_FLAG_EXCLUSIVE,
1266 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1267 FIB_TEST((ai == fib_entry_get_adj(fei)),
1268 "Exclusive route links to user adj");
1270 fib_table_entry_special_remove(fib_index,
1272 FIB_SOURCE_SPECIAL);
1273 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1274 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1275 "Exclusive reoute removed");
1278 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1279 * adjacency through which the route will resovle
1281 dpo_id_t ex_dpo = DPO_INVALID;
1283 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1285 LOOKUP_INPUT_DST_ADDR,
1286 LOOKUP_TABLE_FROM_CONFIG,
1289 fib_table_entry_special_dpo_add(fib_index,
1292 FIB_ENTRY_FLAG_EXCLUSIVE,
1294 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1295 dpo = fib_entry_contribute_ip_forwarding(fei);
1296 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1297 "exclusive remote uses lookup DPO");
1300 * update the exclusive to use a different DPO
1302 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1303 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1305 fib_table_entry_special_dpo_update(fib_index,
1308 FIB_ENTRY_FLAG_EXCLUSIVE,
1310 dpo = fib_entry_contribute_ip_forwarding(fei);
1311 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1312 "exclusive remote uses now uses NULL DPO");
1314 fib_table_entry_special_remove(fib_index,
1316 FIB_SOURCE_SPECIAL);
1317 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1318 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1319 "Exclusive reoute removed");
1323 * Add a recursive route:
1324 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1326 fib_prefix_t bgp_200_pfx = {
1328 .fp_proto = FIB_PROTOCOL_IP4,
1330 /* 200.200.200.200/32 */
1331 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1335 fib_prefix_t pfx_1_1_1_2_s_32 = {
1337 .fp_proto = FIB_PROTOCOL_IP4,
1339 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1343 fib_table_entry_path_add(fib_index,
1346 FIB_ENTRY_FLAG_NONE,
1348 &pfx_1_1_1_2_s_32.fp_addr,
1349 ~0, // no index provided.
1350 fib_index, // nexthop in same fib as route
1353 FIB_ROUTE_PATH_FLAG_NONE);
1355 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1358 * the adj should be recursive via drop, since the route resolves via
1359 * the default route, which is itself a DROP
1361 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1362 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1363 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1364 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1365 "RPF list for 1.1.1.2/32 contains 0 adjs");
1368 * +2 entry and +1 shared-path-list
1370 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1371 fib_path_list_db_size());
1372 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1373 fib_path_list_pool_size());
1374 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1375 fib_entry_pool_size());
1378 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1379 * The paths are sort by NH first. in this case the the path with greater
1380 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1382 fib_prefix_t pfx_1_2_3_4_s_32 = {
1384 .fp_proto = FIB_PROTOCOL_IP4,
1386 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1389 fib_table_entry_path_add(fib_index,
1392 FIB_ENTRY_FLAG_NONE,
1395 tm->hw[0]->sw_if_index,
1399 FIB_ROUTE_PATH_FLAG_NONE);
1400 fei = fib_table_entry_path_add(fib_index,
1403 FIB_ENTRY_FLAG_NONE,
1406 tm->hw[1]->sw_if_index,
1410 FIB_ROUTE_PATH_FLAG_NONE);
1412 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1413 dpo = fib_entry_contribute_ip_forwarding(fei);
1414 lb = load_balance_get(dpo->dpoi_index);
1415 FIB_TEST((lb->lb_n_buckets == 4),
1416 "1.2.3.4/32 LB has %d bucket",
1419 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1420 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1421 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1422 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1424 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1425 tm->hw[0]->sw_if_index,
1426 tm->hw[1]->sw_if_index),
1427 "RPF list for 1.2.3.4/32 contains both adjs");
1431 * Unequal Cost load-balance. 4:1 ratio.
1432 * fits in a 16 bucket LB with ratio 13:3
1434 fib_prefix_t pfx_1_2_3_5_s_32 = {
1436 .fp_proto = FIB_PROTOCOL_IP4,
1438 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1441 fib_table_entry_path_add(fib_index,
1444 FIB_ENTRY_FLAG_NONE,
1447 tm->hw[1]->sw_if_index,
1451 FIB_ROUTE_PATH_FLAG_NONE);
1452 fei = fib_table_entry_path_add(fib_index,
1455 FIB_ENTRY_FLAG_NONE,
1458 tm->hw[0]->sw_if_index,
1462 FIB_ROUTE_PATH_FLAG_NONE);
1464 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1465 dpo = fib_entry_contribute_ip_forwarding(fei);
1466 lb = load_balance_get(dpo->dpoi_index);
1467 FIB_TEST((lb->lb_n_buckets == 16),
1468 "1.2.3.5/32 LB has %d bucket",
1471 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1472 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1473 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1474 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1475 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1476 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1477 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1478 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1479 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1480 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1481 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1482 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1483 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1484 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1485 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1486 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1488 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1489 tm->hw[0]->sw_if_index,
1490 tm->hw[1]->sw_if_index),
1491 "RPF list for 1.2.3.4/32 contains both adjs");
1494 * Test UCMP with a large weight skew - this produces load-balance objects with large
1495 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1496 * laso testing the LB in placce modify code when number of buckets is large.
1498 fib_prefix_t pfx_6_6_6_6_s_32 = {
1500 .fp_proto = FIB_PROTOCOL_IP4,
1503 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1506 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_1 = {
1512 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_2 = {
1518 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1521 .adj = ai_12_12_12_12,
1524 fib_table_entry_update_one_path(fib_index,
1527 FIB_ENTRY_FLAG_NONE,
1530 tm->hw[0]->sw_if_index,
1531 ~0, // invalid fib index
1534 FIB_ROUTE_PATH_FLAG_NONE);
1536 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1537 FIB_TEST(fib_test_validate_entry(fei,
1538 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1540 &ip_6_6_6_6_o_10_10_10_1),
1541 "6.6.6.6/32 via 10.10.10.1");
1543 fib_table_entry_path_add(fib_index,
1546 FIB_ENTRY_FLAG_NONE,
1549 tm->hw[0]->sw_if_index,
1550 ~0, // invalid fib index
1553 FIB_ROUTE_PATH_FLAG_NONE);
1555 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1556 FIB_TEST(fib_test_validate_entry(fei,
1557 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1559 &ip_6_6_6_6_o_10_10_10_2,
1560 &ip_6_6_6_6_o_10_10_10_2,
1561 &ip_6_6_6_6_o_10_10_10_2,
1562 &ip_6_6_6_6_o_10_10_10_2,
1563 &ip_6_6_6_6_o_10_10_10_2,
1564 &ip_6_6_6_6_o_10_10_10_2,
1565 &ip_6_6_6_6_o_10_10_10_2,
1566 &ip_6_6_6_6_o_10_10_10_2,
1567 &ip_6_6_6_6_o_10_10_10_2,
1568 &ip_6_6_6_6_o_10_10_10_2,
1569 &ip_6_6_6_6_o_10_10_10_2,
1570 &ip_6_6_6_6_o_10_10_10_2,
1571 &ip_6_6_6_6_o_10_10_10_2,
1572 &ip_6_6_6_6_o_10_10_10_2,
1573 &ip_6_6_6_6_o_10_10_10_2,
1574 &ip_6_6_6_6_o_10_10_10_2,
1575 &ip_6_6_6_6_o_10_10_10_2,
1576 &ip_6_6_6_6_o_10_10_10_2,
1577 &ip_6_6_6_6_o_10_10_10_2,
1578 &ip_6_6_6_6_o_10_10_10_2,
1579 &ip_6_6_6_6_o_10_10_10_2,
1580 &ip_6_6_6_6_o_10_10_10_2,
1581 &ip_6_6_6_6_o_10_10_10_2,
1582 &ip_6_6_6_6_o_10_10_10_2,
1583 &ip_6_6_6_6_o_10_10_10_2,
1584 &ip_6_6_6_6_o_10_10_10_2,
1585 &ip_6_6_6_6_o_10_10_10_2,
1586 &ip_6_6_6_6_o_10_10_10_2,
1587 &ip_6_6_6_6_o_10_10_10_2,
1588 &ip_6_6_6_6_o_10_10_10_2,
1589 &ip_6_6_6_6_o_10_10_10_2,
1590 &ip_6_6_6_6_o_10_10_10_2,
1591 &ip_6_6_6_6_o_10_10_10_2,
1592 &ip_6_6_6_6_o_10_10_10_2,
1593 &ip_6_6_6_6_o_10_10_10_2,
1594 &ip_6_6_6_6_o_10_10_10_2,
1595 &ip_6_6_6_6_o_10_10_10_2,
1596 &ip_6_6_6_6_o_10_10_10_2,
1597 &ip_6_6_6_6_o_10_10_10_2,
1598 &ip_6_6_6_6_o_10_10_10_2,
1599 &ip_6_6_6_6_o_10_10_10_2,
1600 &ip_6_6_6_6_o_10_10_10_2,
1601 &ip_6_6_6_6_o_10_10_10_2,
1602 &ip_6_6_6_6_o_10_10_10_2,
1603 &ip_6_6_6_6_o_10_10_10_2,
1604 &ip_6_6_6_6_o_10_10_10_2,
1605 &ip_6_6_6_6_o_10_10_10_2,
1606 &ip_6_6_6_6_o_10_10_10_2,
1607 &ip_6_6_6_6_o_10_10_10_2,
1608 &ip_6_6_6_6_o_10_10_10_2,
1609 &ip_6_6_6_6_o_10_10_10_2,
1610 &ip_6_6_6_6_o_10_10_10_2,
1611 &ip_6_6_6_6_o_10_10_10_2,
1612 &ip_6_6_6_6_o_10_10_10_2,
1613 &ip_6_6_6_6_o_10_10_10_2,
1614 &ip_6_6_6_6_o_10_10_10_2,
1615 &ip_6_6_6_6_o_10_10_10_2,
1616 &ip_6_6_6_6_o_10_10_10_2,
1617 &ip_6_6_6_6_o_10_10_10_2,
1618 &ip_6_6_6_6_o_10_10_10_2,
1619 &ip_6_6_6_6_o_10_10_10_2,
1620 &ip_6_6_6_6_o_10_10_10_2,
1621 &ip_6_6_6_6_o_10_10_10_2,
1622 &ip_6_6_6_6_o_10_10_10_1),
1623 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1625 fib_table_entry_path_add(fib_index,
1628 FIB_ENTRY_FLAG_NONE,
1631 tm->hw[1]->sw_if_index,
1632 ~0, // invalid fib index
1635 FIB_ROUTE_PATH_FLAG_NONE);
1637 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1638 FIB_TEST(fib_test_validate_entry(fei,
1639 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1641 &ip_6_6_6_6_o_10_10_10_1,
1642 &ip_6_6_6_6_o_10_10_10_2,
1643 &ip_6_6_6_6_o_10_10_10_2,
1644 &ip_6_6_6_6_o_10_10_10_2,
1645 &ip_6_6_6_6_o_10_10_10_2,
1646 &ip_6_6_6_6_o_10_10_10_2,
1647 &ip_6_6_6_6_o_10_10_10_2,
1648 &ip_6_6_6_6_o_10_10_10_2,
1649 &ip_6_6_6_6_o_10_10_10_2,
1650 &ip_6_6_6_6_o_10_10_10_2,
1651 &ip_6_6_6_6_o_10_10_10_2,
1652 &ip_6_6_6_6_o_10_10_10_2,
1653 &ip_6_6_6_6_o_10_10_10_2,
1654 &ip_6_6_6_6_o_10_10_10_2,
1655 &ip_6_6_6_6_o_10_10_10_2,
1656 &ip_6_6_6_6_o_10_10_10_2,
1657 &ip_6_6_6_6_o_10_10_10_2,
1658 &ip_6_6_6_6_o_10_10_10_2,
1659 &ip_6_6_6_6_o_10_10_10_2,
1660 &ip_6_6_6_6_o_10_10_10_2,
1661 &ip_6_6_6_6_o_10_10_10_2,
1662 &ip_6_6_6_6_o_10_10_10_2,
1663 &ip_6_6_6_6_o_10_10_10_2,
1664 &ip_6_6_6_6_o_10_10_10_2,
1665 &ip_6_6_6_6_o_10_10_10_2,
1666 &ip_6_6_6_6_o_10_10_10_2,
1667 &ip_6_6_6_6_o_10_10_10_2,
1668 &ip_6_6_6_6_o_10_10_10_2,
1669 &ip_6_6_6_6_o_10_10_10_2,
1670 &ip_6_6_6_6_o_10_10_10_2,
1671 &ip_6_6_6_6_o_10_10_10_2,
1672 &ip_6_6_6_6_o_10_10_10_2,
1673 &ip_6_6_6_6_o_10_10_10_2,
1674 &ip_6_6_6_6_o_10_10_10_2,
1675 &ip_6_6_6_6_o_10_10_10_2,
1676 &ip_6_6_6_6_o_10_10_10_2,
1677 &ip_6_6_6_6_o_10_10_10_2,
1678 &ip_6_6_6_6_o_10_10_10_2,
1679 &ip_6_6_6_6_o_10_10_10_2,
1680 &ip_6_6_6_6_o_10_10_10_2,
1681 &ip_6_6_6_6_o_10_10_10_2,
1682 &ip_6_6_6_6_o_10_10_10_2,
1683 &ip_6_6_6_6_o_10_10_10_2,
1684 &ip_6_6_6_6_o_10_10_10_2,
1685 &ip_6_6_6_6_o_10_10_10_2,
1686 &ip_6_6_6_6_o_10_10_10_2,
1687 &ip_6_6_6_6_o_10_10_10_2,
1688 &ip_6_6_6_6_o_10_10_10_2,
1689 &ip_6_6_6_6_o_10_10_10_2,
1690 &ip_6_6_6_6_o_10_10_10_2,
1691 &ip_6_6_6_6_o_10_10_10_2,
1692 &ip_6_6_6_6_o_10_10_10_2,
1693 &ip_6_6_6_6_o_10_10_10_2,
1694 &ip_6_6_6_6_o_10_10_10_2,
1695 &ip_6_6_6_6_o_10_10_10_2,
1696 &ip_6_6_6_6_o_10_10_10_2,
1697 &ip_6_6_6_6_o_10_10_10_2,
1698 &ip_6_6_6_6_o_10_10_10_2,
1699 &ip_6_6_6_6_o_10_10_10_2,
1700 &ip_6_6_6_6_o_10_10_10_2,
1701 &ip_6_6_6_6_o_10_10_10_2,
1702 &ip_6_6_6_6_o_10_10_10_2,
1703 &ip_6_6_6_6_o_10_10_10_2,
1704 &ip_6_6_6_6_o_10_10_10_2,
1705 &ip_6_6_6_6_o_10_10_10_2,
1706 &ip_6_6_6_6_o_12_12_12_12,
1707 &ip_6_6_6_6_o_12_12_12_12,
1708 &ip_6_6_6_6_o_12_12_12_12,
1709 &ip_6_6_6_6_o_12_12_12_12,
1710 &ip_6_6_6_6_o_12_12_12_12,
1711 &ip_6_6_6_6_o_12_12_12_12,
1712 &ip_6_6_6_6_o_12_12_12_12,
1713 &ip_6_6_6_6_o_12_12_12_12,
1714 &ip_6_6_6_6_o_12_12_12_12,
1715 &ip_6_6_6_6_o_12_12_12_12,
1716 &ip_6_6_6_6_o_12_12_12_12,
1717 &ip_6_6_6_6_o_12_12_12_12,
1718 &ip_6_6_6_6_o_12_12_12_12,
1719 &ip_6_6_6_6_o_12_12_12_12,
1720 &ip_6_6_6_6_o_12_12_12_12,
1721 &ip_6_6_6_6_o_12_12_12_12,
1722 &ip_6_6_6_6_o_12_12_12_12,
1723 &ip_6_6_6_6_o_12_12_12_12,
1724 &ip_6_6_6_6_o_12_12_12_12,
1725 &ip_6_6_6_6_o_12_12_12_12,
1726 &ip_6_6_6_6_o_12_12_12_12,
1727 &ip_6_6_6_6_o_12_12_12_12,
1728 &ip_6_6_6_6_o_12_12_12_12,
1729 &ip_6_6_6_6_o_12_12_12_12,
1730 &ip_6_6_6_6_o_12_12_12_12,
1731 &ip_6_6_6_6_o_12_12_12_12,
1732 &ip_6_6_6_6_o_12_12_12_12,
1733 &ip_6_6_6_6_o_12_12_12_12,
1734 &ip_6_6_6_6_o_12_12_12_12,
1735 &ip_6_6_6_6_o_12_12_12_12,
1736 &ip_6_6_6_6_o_12_12_12_12,
1737 &ip_6_6_6_6_o_12_12_12_12,
1738 &ip_6_6_6_6_o_12_12_12_12,
1739 &ip_6_6_6_6_o_12_12_12_12,
1740 &ip_6_6_6_6_o_12_12_12_12,
1741 &ip_6_6_6_6_o_12_12_12_12,
1742 &ip_6_6_6_6_o_12_12_12_12,
1743 &ip_6_6_6_6_o_12_12_12_12,
1744 &ip_6_6_6_6_o_12_12_12_12,
1745 &ip_6_6_6_6_o_12_12_12_12,
1746 &ip_6_6_6_6_o_12_12_12_12,
1747 &ip_6_6_6_6_o_12_12_12_12,
1748 &ip_6_6_6_6_o_12_12_12_12,
1749 &ip_6_6_6_6_o_12_12_12_12,
1750 &ip_6_6_6_6_o_12_12_12_12,
1751 &ip_6_6_6_6_o_12_12_12_12,
1752 &ip_6_6_6_6_o_12_12_12_12,
1753 &ip_6_6_6_6_o_12_12_12_12,
1754 &ip_6_6_6_6_o_12_12_12_12,
1755 &ip_6_6_6_6_o_12_12_12_12,
1756 &ip_6_6_6_6_o_12_12_12_12,
1757 &ip_6_6_6_6_o_12_12_12_12,
1758 &ip_6_6_6_6_o_12_12_12_12,
1759 &ip_6_6_6_6_o_12_12_12_12,
1760 &ip_6_6_6_6_o_12_12_12_12,
1761 &ip_6_6_6_6_o_12_12_12_12,
1762 &ip_6_6_6_6_o_12_12_12_12,
1763 &ip_6_6_6_6_o_12_12_12_12,
1764 &ip_6_6_6_6_o_12_12_12_12,
1765 &ip_6_6_6_6_o_12_12_12_12,
1766 &ip_6_6_6_6_o_12_12_12_12,
1767 &ip_6_6_6_6_o_12_12_12_12,
1768 &ip_6_6_6_6_o_12_12_12_12),
1769 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1771 fib_table_entry_path_remove(fib_index,
1776 tm->hw[1]->sw_if_index,
1777 ~0, // invalid fib index
1779 FIB_ROUTE_PATH_FLAG_NONE);
1781 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1782 FIB_TEST(fib_test_validate_entry(fei,
1783 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1785 &ip_6_6_6_6_o_10_10_10_2,
1786 &ip_6_6_6_6_o_10_10_10_2,
1787 &ip_6_6_6_6_o_10_10_10_2,
1788 &ip_6_6_6_6_o_10_10_10_2,
1789 &ip_6_6_6_6_o_10_10_10_2,
1790 &ip_6_6_6_6_o_10_10_10_2,
1791 &ip_6_6_6_6_o_10_10_10_2,
1792 &ip_6_6_6_6_o_10_10_10_2,
1793 &ip_6_6_6_6_o_10_10_10_2,
1794 &ip_6_6_6_6_o_10_10_10_2,
1795 &ip_6_6_6_6_o_10_10_10_2,
1796 &ip_6_6_6_6_o_10_10_10_2,
1797 &ip_6_6_6_6_o_10_10_10_2,
1798 &ip_6_6_6_6_o_10_10_10_2,
1799 &ip_6_6_6_6_o_10_10_10_2,
1800 &ip_6_6_6_6_o_10_10_10_2,
1801 &ip_6_6_6_6_o_10_10_10_2,
1802 &ip_6_6_6_6_o_10_10_10_2,
1803 &ip_6_6_6_6_o_10_10_10_2,
1804 &ip_6_6_6_6_o_10_10_10_2,
1805 &ip_6_6_6_6_o_10_10_10_2,
1806 &ip_6_6_6_6_o_10_10_10_2,
1807 &ip_6_6_6_6_o_10_10_10_2,
1808 &ip_6_6_6_6_o_10_10_10_2,
1809 &ip_6_6_6_6_o_10_10_10_2,
1810 &ip_6_6_6_6_o_10_10_10_2,
1811 &ip_6_6_6_6_o_10_10_10_2,
1812 &ip_6_6_6_6_o_10_10_10_2,
1813 &ip_6_6_6_6_o_10_10_10_2,
1814 &ip_6_6_6_6_o_10_10_10_2,
1815 &ip_6_6_6_6_o_10_10_10_2,
1816 &ip_6_6_6_6_o_10_10_10_2,
1817 &ip_6_6_6_6_o_10_10_10_2,
1818 &ip_6_6_6_6_o_10_10_10_2,
1819 &ip_6_6_6_6_o_10_10_10_2,
1820 &ip_6_6_6_6_o_10_10_10_2,
1821 &ip_6_6_6_6_o_10_10_10_2,
1822 &ip_6_6_6_6_o_10_10_10_2,
1823 &ip_6_6_6_6_o_10_10_10_2,
1824 &ip_6_6_6_6_o_10_10_10_2,
1825 &ip_6_6_6_6_o_10_10_10_2,
1826 &ip_6_6_6_6_o_10_10_10_2,
1827 &ip_6_6_6_6_o_10_10_10_2,
1828 &ip_6_6_6_6_o_10_10_10_2,
1829 &ip_6_6_6_6_o_10_10_10_2,
1830 &ip_6_6_6_6_o_10_10_10_2,
1831 &ip_6_6_6_6_o_10_10_10_2,
1832 &ip_6_6_6_6_o_10_10_10_2,
1833 &ip_6_6_6_6_o_10_10_10_2,
1834 &ip_6_6_6_6_o_10_10_10_2,
1835 &ip_6_6_6_6_o_10_10_10_2,
1836 &ip_6_6_6_6_o_10_10_10_2,
1837 &ip_6_6_6_6_o_10_10_10_2,
1838 &ip_6_6_6_6_o_10_10_10_2,
1839 &ip_6_6_6_6_o_10_10_10_2,
1840 &ip_6_6_6_6_o_10_10_10_2,
1841 &ip_6_6_6_6_o_10_10_10_2,
1842 &ip_6_6_6_6_o_10_10_10_2,
1843 &ip_6_6_6_6_o_10_10_10_2,
1844 &ip_6_6_6_6_o_10_10_10_2,
1845 &ip_6_6_6_6_o_10_10_10_2,
1846 &ip_6_6_6_6_o_10_10_10_2,
1847 &ip_6_6_6_6_o_10_10_10_2,
1848 &ip_6_6_6_6_o_10_10_10_1),
1849 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1851 fib_table_entry_path_remove(fib_index,
1856 tm->hw[0]->sw_if_index,
1857 ~0, // invalid fib index
1859 FIB_ROUTE_PATH_FLAG_NONE);
1861 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1862 FIB_TEST(fib_test_validate_entry(fei,
1863 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1865 &ip_6_6_6_6_o_10_10_10_1),
1866 "6.6.6.6/32 via 10.10.10.1");
1868 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
1871 * A recursive via the two unequal cost entries
1873 fib_prefix_t bgp_44_s_32 = {
1875 .fp_proto = FIB_PROTOCOL_IP4,
1877 /* 200.200.200.201/32 */
1878 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1881 fei = fib_table_entry_path_add(fib_index,
1884 FIB_ENTRY_FLAG_NONE,
1886 &pfx_1_2_3_4_s_32.fp_addr,
1891 FIB_ROUTE_PATH_FLAG_NONE);
1892 fei = fib_table_entry_path_add(fib_index,
1895 FIB_ENTRY_FLAG_NONE,
1897 &pfx_1_2_3_5_s_32.fp_addr,
1902 FIB_ROUTE_PATH_FLAG_NONE);
1904 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1905 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1906 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1907 tm->hw[0]->sw_if_index,
1908 tm->hw[1]->sw_if_index),
1909 "RPF list for 1.2.3.4/32 contains both adjs");
1912 * test the uRPF check functions
1914 dpo_id_t dpo_44 = DPO_INVALID;
1917 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1918 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
1920 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
1921 "uRPF check for 68.68.68.68/32 on %d OK",
1922 tm->hw[0]->sw_if_index);
1923 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
1924 "uRPF check for 68.68.68.68/32 on %d OK",
1925 tm->hw[1]->sw_if_index);
1926 FIB_TEST(!fib_urpf_check(urpfi, 99),
1927 "uRPF check for 68.68.68.68/32 on 99 not-OK",
1931 fib_table_entry_delete(fib_index,
1934 fib_table_entry_delete(fib_index,
1937 fib_table_entry_delete(fib_index,
1942 * Add a recursive route:
1943 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
1945 fib_prefix_t bgp_201_pfx = {
1947 .fp_proto = FIB_PROTOCOL_IP4,
1949 /* 200.200.200.201/32 */
1950 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1954 fib_prefix_t pfx_1_1_1_200_s_32 = {
1956 .fp_proto = FIB_PROTOCOL_IP4,
1958 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1962 fib_table_entry_path_add(fib_index,
1965 FIB_ENTRY_FLAG_NONE,
1967 &pfx_1_1_1_200_s_32.fp_addr,
1968 ~0, // no index provided.
1969 fib_index, // nexthop in same fib as route
1972 FIB_ROUTE_PATH_FLAG_NONE);
1974 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1976 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1977 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1978 "Flags set on RR via non-attached");
1979 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1980 "RPF list for BGP route empty");
1983 * +2 entry (BGP & RR) and +1 shared-path-list
1985 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1986 fib_path_list_db_size());
1987 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1988 fib_path_list_pool_size());
1989 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1990 fib_entry_pool_size());
1993 * insert a route that covers the missing 1.1.1.2/32. we epxect
1994 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
1996 fib_prefix_t pfx_1_1_1_0_s_24 = {
1998 .fp_proto = FIB_PROTOCOL_IP4,
2001 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2005 fib_table_entry_path_add(fib_index,
2008 FIB_ENTRY_FLAG_NONE,
2011 tm->hw[0]->sw_if_index,
2012 ~0, // invalid fib index
2015 FIB_ROUTE_PATH_FLAG_NONE);
2016 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2017 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2018 ai = fib_entry_get_adj(fei);
2019 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2020 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2021 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2022 ai = fib_entry_get_adj(fei);
2023 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2024 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2025 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2026 ai = fib_entry_get_adj(fei);
2027 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2030 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2032 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2033 fib_path_list_db_size());
2034 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2035 fib_path_list_pool_size());
2036 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2037 fib_entry_pool_size());
2040 * the recursive adj for 200.200.200.200 should be updated.
2042 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2043 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2044 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2045 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2046 tm->hw[0]->sw_if_index),
2047 "RPF list for BGP route has itf index 0");
2050 * insert a more specific route than 1.1.1.0/24 that also covers the
2051 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2052 * 200.200.200.200 to resolve through it.
2054 fib_prefix_t pfx_1_1_1_0_s_28 = {
2056 .fp_proto = FIB_PROTOCOL_IP4,
2059 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2063 fib_table_entry_path_add(fib_index,
2066 FIB_ENTRY_FLAG_NONE,
2069 tm->hw[0]->sw_if_index,
2070 ~0, // invalid fib index
2073 FIB_ROUTE_PATH_FLAG_NONE);
2074 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2075 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2076 ai = fib_entry_get_adj(fei);
2077 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2080 * +1 entry. +1 shared path-list
2082 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2083 fib_path_list_db_size());
2084 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2085 fib_path_list_pool_size());
2086 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2087 fib_entry_pool_size());
2090 * the recursive adj for 200.200.200.200 should be updated.
2091 * 200.200.200.201 remains unchanged.
2093 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2094 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2097 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2099 fib_table_entry_path_remove(fib_index,
2104 tm->hw[0]->sw_if_index,
2107 FIB_ROUTE_PATH_FLAG_NONE);
2108 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2109 FIB_NODE_INDEX_INVALID),
2110 "1.1.1.0/28 removed");
2111 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2112 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2113 "1.1.1.0/28 lookup via /24");
2114 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2115 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2118 * -1 entry. -1 shared path-list
2120 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2121 fib_path_list_db_size());
2122 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2123 fib_path_list_pool_size());
2124 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2125 fib_entry_pool_size());
2128 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2130 fib_table_entry_path_remove(fib_index,
2135 tm->hw[0]->sw_if_index,
2138 FIB_ROUTE_PATH_FLAG_NONE);
2139 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2140 FIB_NODE_INDEX_INVALID),
2141 "1.1.1.0/24 removed");
2143 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2144 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2145 "1.1.1.2/32 route is DROP");
2146 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2147 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2148 "1.1.1.200/32 route is DROP");
2150 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2151 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2156 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2157 fib_path_list_db_size());
2158 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2159 fib_path_list_pool_size());
2160 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2161 fib_entry_pool_size());
2164 * insert the missing 1.1.1.2/32
2166 fei = fib_table_entry_path_add(fib_index,
2169 FIB_ENTRY_FLAG_NONE,
2172 tm->hw[0]->sw_if_index,
2173 ~0, // invalid fib index
2176 FIB_ROUTE_PATH_FLAG_NONE);
2177 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2178 ai = fib_entry_get_adj(fei);
2179 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2181 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2182 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2185 * no change. 1.1.1.2/32 was already there RR sourced.
2187 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2188 fib_path_list_db_size());
2189 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2190 fib_path_list_pool_size());
2191 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2192 fib_entry_pool_size());
2195 * remove 200.200.200.201/32 which does not have a valid via FIB
2197 fib_table_entry_path_remove(fib_index,
2201 &pfx_1_1_1_200_s_32.fp_addr,
2202 ~0, // no index provided.
2205 FIB_ROUTE_PATH_FLAG_NONE);
2208 * -2 entries (BGP and RR). -1 shared path-list;
2210 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2211 FIB_NODE_INDEX_INVALID),
2212 "200.200.200.201/32 removed");
2213 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2214 FIB_NODE_INDEX_INVALID),
2215 "1.1.1.200/32 removed");
2217 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2218 fib_path_list_db_size());
2219 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2220 fib_path_list_pool_size());
2221 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2222 fib_entry_pool_size());
2225 * remove 200.200.200.200/32 which does have a valid via FIB
2227 fib_table_entry_path_remove(fib_index,
2231 &pfx_1_1_1_2_s_32.fp_addr,
2232 ~0, // no index provided.
2235 FIB_ROUTE_PATH_FLAG_NONE);
2237 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2238 FIB_NODE_INDEX_INVALID),
2239 "200.200.200.200/32 removed");
2240 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2241 FIB_NODE_INDEX_INVALID),
2242 "1.1.1.2/32 still present");
2245 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2247 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2248 fib_path_list_db_size());
2249 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2250 fib_path_list_pool_size());
2251 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2252 fib_entry_pool_size());
2255 * A recursive prefix that has a 2 path load-balance.
2256 * It also shares a next-hop with other BGP prefixes and hence
2257 * test the ref counting of RR sourced prefixes and 2 level LB.
2259 const fib_prefix_t bgp_102 = {
2261 .fp_proto = FIB_PROTOCOL_IP4,
2263 /* 100.100.100.101/32 */
2264 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2267 fib_table_entry_path_add(fib_index,
2270 FIB_ENTRY_FLAG_NONE,
2272 &pfx_1_1_1_1_s_32.fp_addr,
2273 ~0, // no index provided.
2274 fib_index, // same as route
2277 FIB_ROUTE_PATH_FLAG_NONE);
2278 fib_table_entry_path_add(fib_index,
2281 FIB_ENTRY_FLAG_NONE,
2283 &pfx_1_1_1_2_s_32.fp_addr,
2284 ~0, // no index provided.
2285 fib_index, // same as route's FIB
2288 FIB_ROUTE_PATH_FLAG_NONE);
2289 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2290 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2291 dpo = fib_entry_contribute_ip_forwarding(fei);
2293 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2294 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2295 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2296 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2298 lb = load_balance_get(dpo->dpoi_index);
2299 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2300 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2301 "First via 10.10.10.1");
2302 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2303 "Second via 10.10.10.1");
2305 fib_table_entry_path_remove(fib_index,
2309 &pfx_1_1_1_1_s_32.fp_addr,
2310 ~0, // no index provided.
2311 fib_index, // same as route's FIB
2313 FIB_ROUTE_PATH_FLAG_NONE);
2314 fib_table_entry_path_remove(fib_index,
2318 &pfx_1_1_1_2_s_32.fp_addr,
2319 ~0, // no index provided.
2320 fib_index, // same as route's FIB
2322 FIB_ROUTE_PATH_FLAG_NONE);
2323 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2324 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2327 * remove the remaining recursives
2329 fib_table_entry_path_remove(fib_index,
2333 &pfx_1_1_1_1_s_32.fp_addr,
2334 ~0, // no index provided.
2335 fib_index, // same as route's FIB
2337 FIB_ROUTE_PATH_FLAG_NONE);
2338 fib_table_entry_path_remove(fib_index,
2342 &pfx_1_1_1_1_s_32.fp_addr,
2343 ~0, // no index provided.
2344 fib_index, // same as route's FIB
2346 FIB_ROUTE_PATH_FLAG_NONE);
2347 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2348 FIB_NODE_INDEX_INVALID),
2349 "100.100.100.100/32 removed");
2350 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2351 FIB_NODE_INDEX_INVALID),
2352 "100.100.100.101/32 removed");
2355 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2357 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2358 fib_path_list_db_size());
2359 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2360 fib_path_list_pool_size());
2361 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2362 fib_entry_pool_size());
2365 * Add a recursive route via a connected cover, using an adj-fib that does exist
2367 fib_table_entry_path_add(fib_index,
2370 FIB_ENTRY_FLAG_NONE,
2373 ~0, // no index provided.
2374 fib_index, // Same as route's FIB
2377 FIB_ROUTE_PATH_FLAG_NONE);
2380 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2382 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2383 fib_path_list_db_size());
2384 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2385 fib_path_list_pool_size());
2386 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2387 fib_entry_pool_size());
2389 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2390 dpo = fib_entry_contribute_ip_forwarding(fei);
2392 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2393 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2395 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2396 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2398 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2399 "Flags set on RR via existing attached");
2402 * Add a recursive route via a connected cover, using and adj-fib that does
2405 ip46_address_t nh_10_10_10_3 = {
2406 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2408 fib_prefix_t pfx_10_10_10_3 = {
2410 .fp_proto = FIB_PROTOCOL_IP4,
2411 .fp_addr = nh_10_10_10_3,
2414 fib_table_entry_path_add(fib_index,
2417 FIB_ENTRY_FLAG_NONE,
2420 ~0, // no index provided.
2424 FIB_ROUTE_PATH_FLAG_NONE);
2427 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2428 * one unshared non-recursive via 10.10.10.3
2430 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2431 fib_path_list_db_size());
2432 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2433 fib_path_list_pool_size());
2434 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2435 fib_entry_pool_size());
2437 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2440 tm->hw[0]->sw_if_index);
2442 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2443 dpo = fib_entry_contribute_ip_forwarding(fei);
2444 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2445 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2447 ai = fib_entry_get_adj(fei);
2448 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2449 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2450 fib_entry_get_flags(fei)),
2451 "Flags set on RR via non-existing attached");
2453 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2454 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2459 * remove the recursives
2461 fib_table_entry_path_remove(fib_index,
2466 ~0, // no index provided.
2467 fib_index, // same as route's FIB
2469 FIB_ROUTE_PATH_FLAG_NONE);
2470 fib_table_entry_path_remove(fib_index,
2475 ~0, // no index provided.
2476 fib_index, // same as route's FIB
2478 FIB_ROUTE_PATH_FLAG_NONE);
2480 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2481 FIB_NODE_INDEX_INVALID),
2482 "200.200.200.201/32 removed");
2483 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2484 FIB_NODE_INDEX_INVALID),
2485 "200.200.200.200/32 removed");
2486 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2487 FIB_NODE_INDEX_INVALID),
2488 "10.10.10.3/32 removed");
2491 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2492 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2494 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2495 fib_path_list_db_size());
2496 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2497 fib_path_list_pool_size());
2498 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2499 fib_entry_pool_size());
2504 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2506 fib_prefix_t pfx_5_5_5_5_s_32 = {
2508 .fp_proto = FIB_PROTOCOL_IP4,
2510 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2513 fib_prefix_t pfx_5_5_5_6_s_32 = {
2515 .fp_proto = FIB_PROTOCOL_IP4,
2517 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2520 fib_prefix_t pfx_5_5_5_7_s_32 = {
2522 .fp_proto = FIB_PROTOCOL_IP4,
2524 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2528 fib_table_entry_path_add(fib_index,
2531 FIB_ENTRY_FLAG_NONE,
2533 &pfx_5_5_5_6_s_32.fp_addr,
2534 ~0, // no index provided.
2538 FIB_ROUTE_PATH_FLAG_NONE);
2539 fib_table_entry_path_add(fib_index,
2542 FIB_ENTRY_FLAG_NONE,
2544 &pfx_5_5_5_7_s_32.fp_addr,
2545 ~0, // no index provided.
2549 FIB_ROUTE_PATH_FLAG_NONE);
2550 fib_table_entry_path_add(fib_index,
2553 FIB_ENTRY_FLAG_NONE,
2555 &pfx_5_5_5_5_s_32.fp_addr,
2556 ~0, // no index provided.
2560 FIB_ROUTE_PATH_FLAG_NONE);
2562 * +3 entries, +3 shared path-list
2564 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2565 fib_path_list_db_size());
2566 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2567 fib_path_list_pool_size());
2568 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2569 fib_entry_pool_size());
2572 * All the entries have only looped paths, so they are all drop
2574 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2575 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2576 "LB for 5.5.5.7/32 is via adj for DROP");
2577 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2578 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2579 "LB for 5.5.5.5/32 is via adj for DROP");
2580 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2581 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2582 "LB for 5.5.5.6/32 is via adj for DROP");
2585 * provide 5.5.5.6/32 with alternate path.
2586 * this will allow only 5.5.5.6/32 to forward with this path, the others
2587 * are still drop since the loop is still present.
2589 fib_table_entry_path_add(fib_index,
2592 FIB_ENTRY_FLAG_NONE,
2595 tm->hw[0]->sw_if_index,
2599 FIB_ROUTE_PATH_FLAG_NONE);
2602 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2603 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2605 lb = load_balance_get(dpo1->dpoi_index);
2606 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2608 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2609 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2610 FIB_TEST((ai_01 == dpo2->dpoi_index),
2611 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2613 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2614 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2615 "LB for 5.5.5.7/32 is via adj for DROP");
2616 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2617 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2618 "LB for 5.5.5.5/32 is via adj for DROP");
2621 * remove the alternate path for 5.5.5.6/32
2624 fib_table_entry_path_remove(fib_index,
2629 tm->hw[0]->sw_if_index,
2632 FIB_ROUTE_PATH_FLAG_NONE);
2634 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2635 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2636 "LB for 5.5.5.7/32 is via adj for DROP");
2637 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2638 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2639 "LB for 5.5.5.5/32 is via adj for DROP");
2640 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2641 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2642 "LB for 5.5.5.6/32 is via adj for DROP");
2645 * break the loop by giving 5.5.5.5/32 a new set of paths
2646 * expect all to forward via this new path.
2648 fib_table_entry_update_one_path(fib_index,
2651 FIB_ENTRY_FLAG_NONE,
2654 tm->hw[0]->sw_if_index,
2655 ~0, // invalid fib index
2658 FIB_ROUTE_PATH_FLAG_NONE);
2660 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2661 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2662 lb = load_balance_get(dpo1->dpoi_index);
2663 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2665 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2666 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2667 FIB_TEST((ai_01 == dpo2->dpoi_index),
2668 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2670 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2671 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2673 lb = load_balance_get(dpo2->dpoi_index);
2674 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2675 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2676 "5.5.5.5.7 via 5.5.5.5");
2678 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2679 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2681 lb = load_balance_get(dpo1->dpoi_index);
2682 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2683 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2684 "5.5.5.5.6 via 5.5.5.7");
2687 * revert back to the loop. so we can remove the prefixes with
2690 fib_table_entry_update_one_path(fib_index,
2693 FIB_ENTRY_FLAG_NONE,
2695 &pfx_5_5_5_6_s_32.fp_addr,
2696 ~0, // no index provided.
2700 FIB_ROUTE_PATH_FLAG_NONE);
2702 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2703 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2704 "LB for 5.5.5.7/32 is via adj for DROP");
2705 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2706 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2707 "LB for 5.5.5.5/32 is via adj for DROP");
2708 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2709 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2710 "LB for 5.5.5.6/32 is via adj for DROP");
2713 * remove all the 5.5.5.x/32 prefixes
2715 fib_table_entry_path_remove(fib_index,
2719 &pfx_5_5_5_6_s_32.fp_addr,
2720 ~0, // no index provided.
2721 fib_index, // same as route's FIB
2723 FIB_ROUTE_PATH_FLAG_NONE);
2724 fib_table_entry_path_remove(fib_index,
2728 &pfx_5_5_5_7_s_32.fp_addr,
2729 ~0, // no index provided.
2730 fib_index, // same as route's FIB
2732 FIB_ROUTE_PATH_FLAG_NONE);
2733 fib_table_entry_path_remove(fib_index,
2737 &pfx_5_5_5_5_s_32.fp_addr,
2738 ~0, // no index provided.
2739 fib_index, // same as route's FIB
2741 FIB_ROUTE_PATH_FLAG_NONE);
2742 fib_table_entry_path_remove(fib_index,
2747 ~0, // no index provided.
2748 fib_index, // same as route's FIB
2750 FIB_ROUTE_PATH_FLAG_NONE);
2753 * -3 entries, -3 shared path-list
2755 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2756 fib_path_list_db_size());
2757 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2758 fib_path_list_pool_size());
2759 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2760 fib_entry_pool_size());
2763 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2765 fib_table_entry_path_add(fib_index,
2768 FIB_ENTRY_FLAG_NONE,
2770 &pfx_5_5_5_6_s_32.fp_addr,
2771 ~0, // no index provided.
2775 FIB_ROUTE_PATH_FLAG_NONE);
2776 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2777 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2778 "1-level 5.5.5.6/32 loop is via adj for DROP");
2780 fib_table_entry_path_remove(fib_index,
2784 &pfx_5_5_5_6_s_32.fp_addr,
2785 ~0, // no index provided.
2786 fib_index, // same as route's FIB
2788 FIB_ROUTE_PATH_FLAG_NONE);
2789 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2790 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2791 "1-level 5.5.5.6/32 loop is removed");
2794 * A recursive route whose next-hop is covered by the prefix.
2795 * This would mean the via-fib, which inherits forwarding from its
2796 * cover, thus picks up forwarding from the prfix, which is via the
2797 * via-fib, and we have a loop.
2799 fib_prefix_t pfx_23_23_23_0_s_24 = {
2801 .fp_proto = FIB_PROTOCOL_IP4,
2803 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2806 fib_prefix_t pfx_23_23_23_23_s_32 = {
2808 .fp_proto = FIB_PROTOCOL_IP4,
2810 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2813 fei = fib_table_entry_path_add(fib_index,
2814 &pfx_23_23_23_0_s_24,
2816 FIB_ENTRY_FLAG_NONE,
2818 &pfx_23_23_23_23_s_32.fp_addr,
2823 FIB_ROUTE_PATH_FLAG_NONE);
2824 dpo = fib_entry_contribute_ip_forwarding(fei);
2825 FIB_TEST(load_balance_is_drop(dpo),
2826 "23.23.23.0/24 via covered is DROP");
2827 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2830 * add-remove test. no change.
2832 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2833 fib_path_list_db_size());
2834 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2835 fib_path_list_pool_size());
2836 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2837 fib_entry_pool_size());
2840 * A recursive route with recursion constraints.
2841 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2843 fib_table_entry_path_add(fib_index,
2846 FIB_ENTRY_FLAG_NONE,
2853 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2855 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2856 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2858 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2859 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2861 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2862 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2865 * save the load-balance. we expect it to be inplace modified
2867 lb = load_balance_get(dpo1->dpoi_index);
2870 * add a covering prefix for the via fib that would otherwise serve
2871 * as the resolving route when the host is removed
2873 fib_table_entry_path_add(fib_index,
2876 FIB_ENTRY_FLAG_NONE,
2879 tm->hw[0]->sw_if_index,
2880 ~0, // invalid fib index
2883 FIB_ROUTE_PATH_FLAG_NONE);
2884 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
2885 ai = fib_entry_get_adj(fei);
2886 FIB_TEST((ai == ai_01),
2887 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
2890 * remove the host via FIB - expect the BGP prefix to be drop
2892 fib_table_entry_path_remove(fib_index,
2897 tm->hw[0]->sw_if_index,
2898 ~0, // invalid fib index
2900 FIB_ROUTE_PATH_FLAG_NONE);
2902 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2903 "adj for 200.200.200.200/32 is recursive via adj for DROP");
2906 * add the via-entry host reoute back. expect to resolve again
2908 fib_table_entry_path_add(fib_index,
2911 FIB_ENTRY_FLAG_NONE,
2914 tm->hw[0]->sw_if_index,
2915 ~0, // invalid fib index
2918 FIB_ROUTE_PATH_FLAG_NONE);
2919 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2920 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2923 * add another path for the recursive. it will then have 2.
2925 fib_prefix_t pfx_1_1_1_3_s_32 = {
2927 .fp_proto = FIB_PROTOCOL_IP4,
2929 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
2932 fib_table_entry_path_add(fib_index,
2935 FIB_ENTRY_FLAG_NONE,
2938 tm->hw[0]->sw_if_index,
2939 ~0, // invalid fib index
2942 FIB_ROUTE_PATH_FLAG_NONE);
2944 fib_table_entry_path_add(fib_index,
2947 FIB_ENTRY_FLAG_NONE,
2949 &pfx_1_1_1_3_s_32.fp_addr,
2954 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2956 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2957 dpo = fib_entry_contribute_ip_forwarding(fei);
2959 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2960 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2961 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2962 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2963 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2964 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2965 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2966 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2969 * expect the lb-map used by the recursive's load-balance is using both buckets
2971 load_balance_map_t *lbm;
2974 lb = load_balance_get(dpo->dpoi_index);
2976 load_balance_map_lock(lbmi);
2977 lbm = load_balance_map_get(lbmi);
2979 FIB_TEST(lbm->lbm_buckets[0] == 0,
2980 "LB maps's bucket 0 is %d",
2981 lbm->lbm_buckets[0]);
2982 FIB_TEST(lbm->lbm_buckets[1] == 1,
2983 "LB maps's bucket 1 is %d",
2984 lbm->lbm_buckets[1]);
2987 * withdraw one of the /32 via-entrys.
2988 * that ECMP path will be unresolved and forwarding should continue on the
2989 * other available path. this is an iBGP PIC edge failover.
2990 * Test the forwarding changes without re-fetching the adj from the
2991 * recursive entry. this ensures its the same one that is updated; i.e. an
2994 fib_table_entry_path_remove(fib_index,
2999 tm->hw[0]->sw_if_index,
3000 ~0, // invalid fib index
3002 FIB_ROUTE_PATH_FLAG_NONE);
3004 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3005 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3006 "post PIC 200.200.200.200/32 was inplace modified");
3008 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3009 "post PIC adj for 200.200.200.200/32 is recursive"
3010 " via adj for 1.1.1.3");
3013 * the LB maps that was locked above should have been modified to remove
3014 * the path that was down, and thus its bucket points to a path that is
3017 FIB_TEST(lbm->lbm_buckets[0] == 1,
3018 "LB maps's bucket 0 is %d",
3019 lbm->lbm_buckets[0]);
3020 FIB_TEST(lbm->lbm_buckets[1] == 1,
3021 "LB maps's bucket 1 is %d",
3022 lbm->lbm_buckets[1]);
3024 load_balance_map_unlock(lb->lb_map);
3027 * add it back. again
3029 fib_table_entry_path_add(fib_index,
3032 FIB_ENTRY_FLAG_NONE,
3035 tm->hw[0]->sw_if_index,
3036 ~0, // invalid fib index
3039 FIB_ROUTE_PATH_FLAG_NONE);
3041 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3042 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3043 "via adj for 1.1.1.1");
3044 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3045 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3046 "via adj for 1.1.1.3");
3048 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3049 dpo = fib_entry_contribute_ip_forwarding(fei);
3050 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3051 "post PIC 200.200.200.200/32 was inplace modified");
3054 * add a 3rd path. this makes the LB 16 buckets.
3056 fib_table_entry_path_add(fib_index,
3059 FIB_ENTRY_FLAG_NONE,
3061 &pfx_1_1_1_2_s_32.fp_addr,
3066 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3068 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3069 dpo = fib_entry_contribute_ip_forwarding(fei);
3070 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3071 "200.200.200.200/32 was inplace modified for 3rd path");
3072 FIB_TEST(16 == lb->lb_n_buckets,
3073 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3076 load_balance_map_lock(lbmi);
3077 lbm = load_balance_map_get(lbmi);
3079 for (ii = 0; ii < 16; ii++)
3081 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3082 "LB Map for 200.200.200.200/32 at %d is %d",
3083 ii, lbm->lbm_buckets[ii]);
3087 * trigger PIC by removing the first via-entry
3088 * the first 6 buckets of the map should map to the next 6
3090 fib_table_entry_path_remove(fib_index,
3095 tm->hw[0]->sw_if_index,
3098 FIB_ROUTE_PATH_FLAG_NONE);
3100 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3101 dpo = fib_entry_contribute_ip_forwarding(fei);
3102 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3103 "200.200.200.200/32 was inplace modified for 3rd path");
3104 FIB_TEST(2 == lb->lb_n_buckets,
3105 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3107 for (ii = 0; ii < 6; ii++)
3109 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3110 "LB Map for 200.200.200.200/32 at %d is %d",
3111 ii, lbm->lbm_buckets[ii]);
3113 for (ii = 6; ii < 16; ii++)
3115 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3116 "LB Map for 200.200.200.200/32 at %d is %d",
3117 ii, lbm->lbm_buckets[ii]);
3124 fib_table_entry_path_add(fib_index,
3127 FIB_ENTRY_FLAG_NONE,
3130 tm->hw[0]->sw_if_index,
3134 FIB_ROUTE_PATH_FLAG_NONE);
3136 fib_table_entry_path_remove(fib_index,
3140 &pfx_1_1_1_2_s_32.fp_addr,
3144 MPLS_LABEL_INVALID);
3145 fib_table_entry_path_remove(fib_index,
3153 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3154 fib_table_entry_path_remove(fib_index,
3158 &pfx_1_1_1_3_s_32.fp_addr,
3162 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3163 fib_table_entry_delete(fib_index,
3166 fib_table_entry_delete(fib_index,
3169 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3170 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3171 "1.1.1.1/28 removed");
3172 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3173 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3174 "1.1.1.3/32 removed");
3175 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3176 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3177 "200.200.200.200/32 removed");
3180 * add-remove test. no change.
3182 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3183 fib_path_list_db_size());
3184 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3185 fib_path_list_pool_size());
3186 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3187 fib_entry_pool_size());
3190 * A route whose paths are built up iteratively and then removed
3193 fib_prefix_t pfx_4_4_4_4_s_32 = {
3195 .fp_proto = FIB_PROTOCOL_IP4,
3198 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3202 fib_table_entry_path_add(fib_index,
3205 FIB_ENTRY_FLAG_NONE,
3208 tm->hw[0]->sw_if_index,
3212 FIB_ROUTE_PATH_FLAG_NONE);
3213 fib_table_entry_path_add(fib_index,
3216 FIB_ENTRY_FLAG_NONE,
3219 tm->hw[0]->sw_if_index,
3223 FIB_ROUTE_PATH_FLAG_NONE);
3224 fib_table_entry_path_add(fib_index,
3227 FIB_ENTRY_FLAG_NONE,
3230 tm->hw[0]->sw_if_index,
3234 FIB_ROUTE_PATH_FLAG_NONE);
3235 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3236 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3237 "4.4.4.4/32 present");
3239 fib_table_entry_delete(fib_index,
3242 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3243 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3244 "4.4.4.4/32 removed");
3247 * add-remove test. no change.
3249 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3250 fib_path_list_db_size());
3251 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3252 fib_path_list_pool_size());
3253 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3254 fib_entry_pool_size());
3257 * A route with multiple paths at once
3259 fib_route_path_t *r_paths = NULL;
3261 for (ii = 0; ii < 4; ii++)
3263 fib_route_path_t r_path = {
3264 .frp_proto = FIB_PROTOCOL_IP4,
3266 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3268 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3270 .frp_fib_index = ~0,
3272 vec_add1(r_paths, r_path);
3275 fib_table_entry_update(fib_index,
3278 FIB_ENTRY_FLAG_NONE,
3281 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3282 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3283 dpo = fib_entry_contribute_ip_forwarding(fei);
3285 lb = load_balance_get(dpo->dpoi_index);
3286 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3288 fib_table_entry_delete(fib_index,
3291 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3292 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3293 "4.4.4.4/32 removed");
3297 * add-remove test. no change.
3299 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3300 fib_path_list_db_size());
3301 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3302 fib_path_list_pool_size());
3303 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3304 fib_entry_pool_size());
3307 * A route deag route
3309 fib_table_entry_path_add(fib_index,
3312 FIB_ENTRY_FLAG_NONE,
3319 FIB_ROUTE_PATH_FLAG_NONE);
3321 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3322 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3324 dpo = fib_entry_contribute_ip_forwarding(fei);
3325 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3326 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3328 FIB_TEST((fib_index == lkd->lkd_fib_index),
3329 "4.4.4.4/32 is deag in %d %U",
3331 format_dpo_id, dpo, 0);
3333 fib_table_entry_delete(fib_index,
3336 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3337 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3338 "4.4.4.4/32 removed");
3342 * add-remove test. no change.
3344 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3345 fib_path_list_db_size());
3346 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3347 fib_path_list_pool_size());
3348 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3349 fib_entry_pool_size());
3353 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3355 fib_prefix_t pfx_34_1_1_1_s_32 = {
3357 .fp_proto = FIB_PROTOCOL_IP4,
3359 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3362 fib_prefix_t pfx_34_34_1_1_s_32 = {
3364 .fp_proto = FIB_PROTOCOL_IP4,
3366 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3369 fei = fib_table_entry_path_add(fib_index,
3372 FIB_ENTRY_FLAG_NONE,
3374 &pfx_34_34_1_1_s_32.fp_addr,
3379 FIB_ROUTE_PATH_FLAG_NONE);
3380 fei = fib_table_entry_path_add(fib_index,
3383 FIB_ENTRY_FLAG_NONE,
3385 &pfx_34_34_1_1_s_32.fp_addr,
3390 FIB_ROUTE_PATH_FLAG_NONE);
3391 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3392 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3396 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3397 * all of which are via 10.10.10.1, Itf1
3399 fib_table_entry_path_remove(fib_index,
3404 tm->hw[0]->sw_if_index,
3407 FIB_ROUTE_PATH_FLAG_NONE);
3408 fib_table_entry_path_remove(fib_index,
3413 tm->hw[0]->sw_if_index,
3416 FIB_ROUTE_PATH_FLAG_NONE);
3417 fib_table_entry_path_remove(fib_index,
3422 tm->hw[0]->sw_if_index,
3425 FIB_ROUTE_PATH_FLAG_NONE);
3427 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3428 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3429 "1.1.1.1/32 removed");
3430 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3431 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3432 "1.1.1.2/32 removed");
3433 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3434 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3435 "1.1.2.0/24 removed");
3438 * -3 entries and -1 shared path-list
3440 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3441 fib_path_list_db_size());
3442 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3443 fib_path_list_pool_size());
3444 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3445 fib_entry_pool_size());
3448 * An attached-host route. Expect to link to the incomplete adj
3450 fib_prefix_t pfx_4_1_1_1_s_32 = {
3452 .fp_proto = FIB_PROTOCOL_IP4,
3455 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3458 fib_table_entry_path_add(fib_index,
3461 FIB_ENTRY_FLAG_NONE,
3464 tm->hw[0]->sw_if_index,
3468 FIB_ROUTE_PATH_FLAG_NONE);
3470 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3471 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3472 ai = fib_entry_get_adj(fei);
3474 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3476 &pfx_4_1_1_1_s_32.fp_addr,
3477 tm->hw[0]->sw_if_index);
3478 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3482 * +1 entry and +1 shared path-list
3484 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3485 fib_path_list_db_size());
3486 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3487 fib_path_list_pool_size());
3488 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3489 fib_entry_pool_size());
3491 fib_table_entry_delete(fib_index,
3495 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3496 fib_path_list_db_size());
3497 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3498 fib_path_list_pool_size());
3499 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3500 fib_entry_pool_size());
3503 * add a v6 prefix via v4 next-hops
3505 fib_prefix_t pfx_2001_s_64 = {
3507 .fp_proto = FIB_PROTOCOL_IP6,
3509 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3512 fei = fib_table_entry_path_add(0, //default v6 table
3515 FIB_ENTRY_FLAG_NONE,
3518 tm->hw[0]->sw_if_index,
3522 FIB_ROUTE_PATH_FLAG_NONE);
3524 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3525 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3526 ai = fib_entry_get_adj(fei);
3528 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3529 "2001::/64 via ARP-adj");
3530 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3531 "2001::/64 is link type v6");
3532 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3533 "2001::/64 ADJ-adj is NH proto v4");
3534 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3537 * add a uRPF exempt prefix:
3539 * - it's forwarding is drop
3540 * - it's uRPF list is not empty
3541 * - the uRPF list for the default route (it's cover) is empty
3543 fei = fib_table_entry_special_add(fib_index,
3545 FIB_SOURCE_URPF_EXEMPT,
3546 FIB_ENTRY_FLAG_DROP,
3548 dpo = fib_entry_contribute_ip_forwarding(fei);
3549 FIB_TEST(load_balance_is_drop(dpo),
3550 "uRPF exempt 4.1.1.1/32 DROP");
3551 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3552 "uRPF list for exempt prefix has itf index 0");
3553 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3554 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3555 "uRPF list for 0.0.0.0/0 empty");
3557 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3563 fib_table_entry_delete(fib_index,
3564 &pfx_10_10_10_1_s_32,
3566 fib_table_entry_delete(fib_index,
3567 &pfx_10_10_10_2_s_32,
3569 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3570 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
3571 "10.10.10.1/32 adj-fib removed");
3572 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3573 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
3574 "10.10.10.2/32 adj-fib removed");
3577 * -2 entries and -2 non-shared path-list
3579 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3580 fib_path_list_db_size());
3581 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
3582 fib_path_list_pool_size());
3583 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
3584 fib_entry_pool_size());
3587 * unlock the adjacencies for which this test provided a rewrite.
3588 * These are the last locks on these adjs. they should thus go away.
3592 adj_unlock(ai_12_12_12_12);
3594 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3599 * remove the interface prefixes
3601 local_pfx.fp_len = 32;
3602 fib_table_entry_special_remove(fib_index, &local_pfx,
3603 FIB_SOURCE_INTERFACE);
3604 fei = fib_table_lookup(fib_index, &local_pfx);
3606 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3607 fib_table_lookup_exact_match(fib_index, &local_pfx),
3608 "10.10.10.10/32 adj-fib removed");
3610 local_pfx.fp_len = 24;
3611 fib_table_entry_delete(fib_index, &local_pfx,
3612 FIB_SOURCE_INTERFACE);
3614 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3615 fib_table_lookup_exact_match(fib_index, &local_pfx),
3616 "10.10.10.10/24 adj-fib removed");
3619 * -2 entries and -2 non-shared path-list
3621 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3622 fib_path_list_db_size());
3623 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
3624 fib_path_list_pool_size());
3625 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
3626 fib_entry_pool_size());
3629 * Last but not least, remove the VRF
3631 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3634 "NO API Source'd prefixes");
3635 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3638 "NO RR Source'd prefixes");
3639 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3641 FIB_SOURCE_INTERFACE)),
3642 "NO INterface Source'd prefixes");
3644 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
3646 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3647 fib_path_list_db_size());
3648 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
3649 fib_path_list_pool_size());
3650 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
3651 fib_entry_pool_size());
3652 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
3653 pool_elts(fib_urpf_list_pool));
3662 * In the default table check for the presence and correct forwarding
3663 * of the special entries
3665 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
3666 const dpo_id_t *dpo, *dpo_drop;
3667 const ip_adjacency_t *adj;
3668 const receive_dpo_t *rd;
3673 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3676 /* via 2001:0:0:1::2 */
3677 ip46_address_t nh_2001_2 = {
3680 [0] = clib_host_to_net_u64(0x2001000000000001),
3681 [1] = clib_host_to_net_u64(0x0000000000000002),
3688 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
3690 /* Find or create FIB table 11 */
3691 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
3693 for (ii = 0; ii < 4; ii++)
3695 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
3698 fib_prefix_t pfx_0_0 = {
3700 .fp_proto = FIB_PROTOCOL_IP6,
3708 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
3709 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
3710 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3711 "Default route is DROP");
3713 dpo = fib_entry_contribute_ip_forwarding(dfrt);
3714 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3717 &pfx_0_0.fp_addr.ip6)),
3718 "default-route; fwd and non-fwd tables match");
3720 // FIXME - check specials.
3723 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
3724 * each with 2 entries and a v6 mfib with 4 path-lists.
3725 * All entries are special so no path-list sharing.
3728 #define PNPS (5+4+4)
3729 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3730 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
3731 fib_path_list_pool_size());
3732 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
3733 fib_entry_pool_size());
3736 * add interface routes.
3737 * validate presence of /64 attached and /128 recieve.
3738 * test for the presence of the receive address in the glean and local adj
3740 * receive on 2001:0:0:1::1/128
3742 fib_prefix_t local_pfx = {
3744 .fp_proto = FIB_PROTOCOL_IP6,
3748 [0] = clib_host_to_net_u64(0x2001000000000001),
3749 [1] = clib_host_to_net_u64(0x0000000000000001),
3755 fib_table_entry_update_one_path(fib_index, &local_pfx,
3756 FIB_SOURCE_INTERFACE,
3757 (FIB_ENTRY_FLAG_CONNECTED |
3758 FIB_ENTRY_FLAG_ATTACHED),
3761 tm->hw[0]->sw_if_index,
3765 FIB_ROUTE_PATH_FLAG_NONE);
3766 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3768 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3770 ai = fib_entry_get_adj(fei);
3771 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
3773 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3774 "attached interface adj is glean");
3775 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3776 &adj->sub_type.glean.receive_addr)),
3777 "attached interface adj is receive ok");
3778 dpo = fib_entry_contribute_ip_forwarding(fei);
3779 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3782 &local_pfx.fp_addr.ip6)),
3783 "attached-route; fwd and non-fwd tables match");
3785 local_pfx.fp_len = 128;
3786 fib_table_entry_update_one_path(fib_index, &local_pfx,
3787 FIB_SOURCE_INTERFACE,
3788 (FIB_ENTRY_FLAG_CONNECTED |
3789 FIB_ENTRY_FLAG_LOCAL),
3792 tm->hw[0]->sw_if_index,
3793 ~0, // invalid fib index
3796 FIB_ROUTE_PATH_FLAG_NONE);
3797 fei = fib_table_lookup(fib_index, &local_pfx);
3799 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3801 dpo = fib_entry_contribute_ip_forwarding(fei);
3802 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3803 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3804 "local interface adj is local");
3805 rd = receive_dpo_get(dpo->dpoi_index);
3807 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3809 "local interface adj is receive ok");
3811 dpo = fib_entry_contribute_ip_forwarding(fei);
3812 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3815 &local_pfx.fp_addr.ip6)),
3816 "local-route; fwd and non-fwd tables match");
3819 * +2 entries. +2 unshared path-lists
3821 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3822 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3823 fib_path_list_pool_size());
3824 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3825 fib_entry_pool_size());
3828 * Modify the default route to be via an adj not yet known.
3829 * this sources the defalut route with the API source, which is
3830 * a higher preference to the DEFAULT_ROUTE source
3832 fib_table_entry_path_add(fib_index, &pfx_0_0,
3834 FIB_ENTRY_FLAG_NONE,
3837 tm->hw[0]->sw_if_index,
3841 FIB_ROUTE_PATH_FLAG_NONE);
3842 fei = fib_table_lookup(fib_index, &pfx_0_0);
3844 FIB_TEST((fei == dfrt), "default route same index");
3845 ai = fib_entry_get_adj(fei);
3846 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
3848 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3849 "adj is incomplete");
3850 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
3851 "adj nbr next-hop ok");
3854 * find the adj in the shared db
3856 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3859 tm->hw[0]->sw_if_index);
3860 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
3861 adj_unlock(locked_ai);
3864 * no more entires. +1 shared path-list
3866 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3867 fib_path_list_db_size());
3868 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
3869 fib_path_list_pool_size());
3870 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3871 fib_entry_pool_size());
3874 * remove the API source from the default route. We expected
3875 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
3877 fib_table_entry_path_remove(fib_index, &pfx_0_0,
3881 tm->hw[0]->sw_if_index,
3884 FIB_ROUTE_PATH_FLAG_NONE);
3885 fei = fib_table_lookup(fib_index, &pfx_0_0);
3887 FIB_TEST((fei == dfrt), "default route same index");
3888 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3889 "Default route is DROP");
3892 * no more entires. -1 shared path-list
3894 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3895 fib_path_list_db_size());
3896 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3897 fib_path_list_pool_size());
3898 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3899 fib_entry_pool_size());
3902 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3904 fib_prefix_t pfx_2001_1_2_s_128 = {
3906 .fp_proto = FIB_PROTOCOL_IP6,
3910 [0] = clib_host_to_net_u64(0x2001000000000001),
3911 [1] = clib_host_to_net_u64(0x0000000000000002),
3916 fib_prefix_t pfx_2001_1_3_s_128 = {
3918 .fp_proto = FIB_PROTOCOL_IP6,
3922 [0] = clib_host_to_net_u64(0x2001000000000001),
3923 [1] = clib_host_to_net_u64(0x0000000000000003),
3929 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
3932 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3934 &pfx_2001_1_2_s_128.fp_addr,
3935 tm->hw[0]->sw_if_index);
3936 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
3937 adj = adj_get(ai_01);
3938 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3939 "adj is incomplete");
3940 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3941 &adj->sub_type.nbr.next_hop)),
3942 "adj nbr next-hop ok");
3944 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
3945 fib_test_build_rewrite(eth_addr));
3946 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3948 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3949 &adj->sub_type.nbr.next_hop)),
3950 "adj nbr next-hop ok");
3952 fib_table_entry_update_one_path(fib_index,
3953 &pfx_2001_1_2_s_128,
3955 FIB_ENTRY_FLAG_ATTACHED,
3957 &pfx_2001_1_2_s_128.fp_addr,
3958 tm->hw[0]->sw_if_index,
3962 FIB_ROUTE_PATH_FLAG_NONE);
3964 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
3965 ai = fib_entry_get_adj(fei);
3966 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3970 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3972 &pfx_2001_1_3_s_128.fp_addr,
3973 tm->hw[0]->sw_if_index);
3974 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
3975 adj = adj_get(ai_02);
3976 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3977 "adj is incomplete");
3978 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3979 &adj->sub_type.nbr.next_hop)),
3980 "adj nbr next-hop ok");
3982 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
3983 fib_test_build_rewrite(eth_addr));
3984 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3986 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3987 &adj->sub_type.nbr.next_hop)),
3988 "adj nbr next-hop ok");
3989 FIB_TEST((ai_01 != ai_02), "ADJs are different");
3991 fib_table_entry_update_one_path(fib_index,
3992 &pfx_2001_1_3_s_128,
3994 FIB_ENTRY_FLAG_ATTACHED,
3996 &pfx_2001_1_3_s_128.fp_addr,
3997 tm->hw[0]->sw_if_index,
4001 FIB_ROUTE_PATH_FLAG_NONE);
4003 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4004 ai = fib_entry_get_adj(fei);
4005 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4008 * +2 entries, +2 unshread path-lists.
4010 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4011 fib_path_list_db_size());
4012 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4013 fib_path_list_pool_size());
4014 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4015 fib_entry_pool_size());
4018 * Add a 2 routes via the first ADJ. ensure path-list sharing
4020 fib_prefix_t pfx_2001_a_s_64 = {
4022 .fp_proto = FIB_PROTOCOL_IP6,
4026 [0] = clib_host_to_net_u64(0x200100000000000a),
4027 [1] = clib_host_to_net_u64(0x0000000000000000),
4032 fib_prefix_t pfx_2001_b_s_64 = {
4034 .fp_proto = FIB_PROTOCOL_IP6,
4038 [0] = clib_host_to_net_u64(0x200100000000000b),
4039 [1] = clib_host_to_net_u64(0x0000000000000000),
4045 fib_table_entry_path_add(fib_index,
4048 FIB_ENTRY_FLAG_NONE,
4051 tm->hw[0]->sw_if_index,
4055 FIB_ROUTE_PATH_FLAG_NONE);
4056 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4057 ai = fib_entry_get_adj(fei);
4058 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4059 fib_table_entry_path_add(fib_index,
4062 FIB_ENTRY_FLAG_NONE,
4065 tm->hw[0]->sw_if_index,
4069 FIB_ROUTE_PATH_FLAG_NONE);
4070 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4071 ai = fib_entry_get_adj(fei);
4072 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4075 * +2 entries, +1 shared path-list.
4077 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4078 fib_path_list_db_size());
4079 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4080 fib_path_list_pool_size());
4081 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4082 fib_entry_pool_size());
4085 * add a v4 prefix via a v6 next-hop
4087 fib_prefix_t pfx_1_1_1_1_s_32 = {
4089 .fp_proto = FIB_PROTOCOL_IP4,
4091 .ip4.as_u32 = 0x01010101,
4094 fei = fib_table_entry_path_add(0, // default table
4097 FIB_ENTRY_FLAG_NONE,
4100 tm->hw[0]->sw_if_index,
4104 FIB_ROUTE_PATH_FLAG_NONE);
4105 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4106 "1.1.1.1/32 o v6 route present");
4107 ai = fib_entry_get_adj(fei);
4109 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4110 "1.1.1.1/32 via ARP-adj");
4111 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4112 "1.1.1.1/32 ADJ-adj is link type v4");
4113 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4114 "1.1.1.1/32 ADJ-adj is NH proto v6");
4115 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4120 fib_prefix_t pfx_2001_c_s_64 = {
4122 .fp_proto = FIB_PROTOCOL_IP6,
4126 [0] = clib_host_to_net_u64(0x200100000000000c),
4127 [1] = clib_host_to_net_u64(0x0000000000000000),
4132 fib_table_entry_path_add(fib_index,
4135 FIB_ENTRY_FLAG_ATTACHED,
4138 tm->hw[0]->sw_if_index,
4142 FIB_ROUTE_PATH_FLAG_NONE);
4143 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4144 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4145 ai = fib_entry_get_adj(fei);
4147 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4148 "2001:0:0:c/64 attached resolves via glean");
4150 fib_table_entry_path_remove(fib_index,
4155 tm->hw[0]->sw_if_index,
4158 FIB_ROUTE_PATH_FLAG_NONE);
4159 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4160 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4163 * Shutdown the interface on which we have a connected and through
4164 * which the routes are reachable.
4165 * This will result in the connected, adj-fibs, and routes linking to drop
4166 * The local/for-us prefix continues to receive.
4168 clib_error_t * error;
4170 error = vnet_sw_interface_set_flags(vnet_get_main(),
4171 tm->hw[0]->sw_if_index,
4172 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4173 FIB_TEST((NULL == error), "Interface shutdown OK");
4175 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4176 dpo = fib_entry_contribute_ip_forwarding(fei);
4177 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4178 "2001::b/64 resolves via drop");
4180 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4181 dpo = fib_entry_contribute_ip_forwarding(fei);
4182 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4183 "2001::a/64 resolves via drop");
4184 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4185 dpo = fib_entry_contribute_ip_forwarding(fei);
4186 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4187 "2001:0:0:1::3/64 resolves via drop");
4188 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4189 dpo = fib_entry_contribute_ip_forwarding(fei);
4190 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4191 "2001:0:0:1::2/64 resolves via drop");
4192 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4193 dpo = fib_entry_contribute_ip_forwarding(fei);
4194 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4195 "2001:0:0:1::1/128 not drop");
4196 local_pfx.fp_len = 64;
4197 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4198 dpo = fib_entry_contribute_ip_forwarding(fei);
4199 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4200 "2001:0:0:1/64 resolves via drop");
4205 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4206 fib_path_list_db_size());
4207 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4208 fib_path_list_pool_size());
4209 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4210 fib_entry_pool_size());
4213 * shutdown one of the other interfaces, then add a connected.
4214 * and swap one of the routes to it.
4216 error = vnet_sw_interface_set_flags(vnet_get_main(),
4217 tm->hw[1]->sw_if_index,
4218 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4219 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4221 fib_prefix_t connected_pfx = {
4223 .fp_proto = FIB_PROTOCOL_IP6,
4226 /* 2001:0:0:2::1/64 */
4228 [0] = clib_host_to_net_u64(0x2001000000000002),
4229 [1] = clib_host_to_net_u64(0x0000000000000001),
4234 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4235 FIB_SOURCE_INTERFACE,
4236 (FIB_ENTRY_FLAG_CONNECTED |
4237 FIB_ENTRY_FLAG_ATTACHED),
4240 tm->hw[1]->sw_if_index,
4244 FIB_ROUTE_PATH_FLAG_NONE);
4245 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4246 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4247 dpo = fib_entry_contribute_ip_forwarding(fei);
4248 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4249 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4250 "2001:0:0:2/64 not resolves via drop");
4252 connected_pfx.fp_len = 128;
4253 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4254 FIB_SOURCE_INTERFACE,
4255 (FIB_ENTRY_FLAG_CONNECTED |
4256 FIB_ENTRY_FLAG_LOCAL),
4259 tm->hw[0]->sw_if_index,
4260 ~0, // invalid fib index
4263 FIB_ROUTE_PATH_FLAG_NONE);
4264 fei = fib_table_lookup(fib_index, &connected_pfx);
4266 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4267 dpo = fib_entry_contribute_ip_forwarding(fei);
4268 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4269 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4270 "local interface adj is local");
4271 rd = receive_dpo_get(dpo->dpoi_index);
4272 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4274 "local interface adj is receive ok");
4277 * +2 entries, +2 unshared path-lists
4279 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4280 fib_path_list_db_size());
4281 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4282 fib_path_list_pool_size());
4283 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4284 fib_entry_pool_size());
4288 * bring the interface back up. we expected the routes to return
4289 * to normal forwarding.
4291 error = vnet_sw_interface_set_flags(vnet_get_main(),
4292 tm->hw[0]->sw_if_index,
4293 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4294 FIB_TEST((NULL == error), "Interface bring-up OK");
4295 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4296 ai = fib_entry_get_adj(fei);
4297 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4298 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4299 ai = fib_entry_get_adj(fei);
4300 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4301 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4302 ai = fib_entry_get_adj(fei);
4303 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4304 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4305 ai = fib_entry_get_adj(fei);
4306 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4307 local_pfx.fp_len = 64;
4308 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4309 ai = fib_entry_get_adj(fei);
4311 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4312 "attached interface adj is glean");
4315 * Same test as above, but this time the HW interface goes down
4317 error = vnet_hw_interface_set_flags(vnet_get_main(),
4318 tm->hw_if_indicies[0],
4319 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4320 FIB_TEST((NULL == error), "Interface shutdown OK");
4322 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4323 dpo = fib_entry_contribute_ip_forwarding(fei);
4324 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4325 "2001::b/64 resolves via drop");
4326 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4327 dpo = fib_entry_contribute_ip_forwarding(fei);
4328 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4329 "2001::a/64 resolves via drop");
4330 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4331 dpo = fib_entry_contribute_ip_forwarding(fei);
4332 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4333 "2001:0:0:1::3/128 resolves via drop");
4334 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4335 dpo = fib_entry_contribute_ip_forwarding(fei);
4336 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4337 "2001:0:0:1::2/128 resolves via drop");
4338 local_pfx.fp_len = 128;
4339 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4340 dpo = fib_entry_contribute_ip_forwarding(fei);
4341 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4342 "2001:0:0:1::1/128 not drop");
4343 local_pfx.fp_len = 64;
4344 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4345 dpo = fib_entry_contribute_ip_forwarding(fei);
4346 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4347 "2001:0:0:1/64 resolves via drop");
4349 error = vnet_hw_interface_set_flags(vnet_get_main(),
4350 tm->hw_if_indicies[0],
4351 VNET_HW_INTERFACE_FLAG_LINK_UP);
4352 FIB_TEST((NULL == error), "Interface bring-up OK");
4353 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4354 ai = fib_entry_get_adj(fei);
4355 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4356 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4357 ai = fib_entry_get_adj(fei);
4358 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4359 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4360 ai = fib_entry_get_adj(fei);
4361 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4362 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4363 ai = fib_entry_get_adj(fei);
4364 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4365 local_pfx.fp_len = 64;
4366 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4367 ai = fib_entry_get_adj(fei);
4369 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4370 "attached interface adj is glean");
4373 * Delete the interface that the routes reolve through.
4374 * Again no routes are removed. They all point to drop.
4376 * This is considered an error case. The control plane should
4377 * not remove interfaces through which routes resolve, but
4378 * such things can happen. ALL affected routes will drop.
4380 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4382 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4383 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4384 "2001::b/64 resolves via drop");
4385 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4386 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4387 "2001::b/64 resolves via drop");
4388 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4389 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4390 "2001:0:0:1::3/64 resolves via drop");
4391 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4392 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4393 "2001:0:0:1::2/64 resolves via drop");
4394 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4395 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4396 "2001:0:0:1::1/128 is drop");
4397 local_pfx.fp_len = 64;
4398 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4399 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4400 "2001:0:0:1/64 resolves via drop");
4405 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4406 fib_path_list_db_size());
4407 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4408 fib_path_list_pool_size());
4409 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4410 fib_entry_pool_size());
4413 * Add the interface back. routes stay unresolved.
4415 error = ethernet_register_interface(vnet_get_main(),
4416 test_interface_device_class.index,
4419 &tm->hw_if_indicies[0],
4420 /* flag change */ 0);
4422 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4423 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4424 "2001::b/64 resolves via drop");
4425 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4426 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4427 "2001::b/64 resolves via drop");
4428 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4429 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4430 "2001:0:0:1::3/64 resolves via drop");
4431 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4432 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4433 "2001:0:0:1::2/64 resolves via drop");
4434 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4435 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4436 "2001:0:0:1::1/128 is drop");
4437 local_pfx.fp_len = 64;
4438 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4439 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4440 "2001:0:0:1/64 resolves via drop");
4443 * CLEANUP ALL the routes
4445 fib_table_entry_delete(fib_index,
4448 fib_table_entry_delete(fib_index,
4451 fib_table_entry_delete(fib_index,
4454 fib_table_entry_delete(fib_index,
4455 &pfx_2001_1_3_s_128,
4457 fib_table_entry_delete(fib_index,
4458 &pfx_2001_1_2_s_128,
4460 local_pfx.fp_len = 64;
4461 fib_table_entry_delete(fib_index, &local_pfx,
4462 FIB_SOURCE_INTERFACE);
4463 local_pfx.fp_len = 128;
4464 fib_table_entry_special_remove(fib_index, &local_pfx,
4465 FIB_SOURCE_INTERFACE);
4466 connected_pfx.fp_len = 64;
4467 fib_table_entry_delete(fib_index, &connected_pfx,
4468 FIB_SOURCE_INTERFACE);
4469 connected_pfx.fp_len = 128;
4470 fib_table_entry_special_remove(fib_index, &connected_pfx,
4471 FIB_SOURCE_INTERFACE);
4473 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4474 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4475 "2001::a/64 removed");
4476 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4477 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4478 "2001::b/64 removed");
4479 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4480 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4481 "2001:0:0:1::3/128 removed");
4482 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4483 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4484 "2001:0:0:1::3/128 removed");
4485 local_pfx.fp_len = 64;
4486 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4487 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4488 "2001:0:0:1/64 removed");
4489 local_pfx.fp_len = 128;
4490 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4491 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4492 "2001:0:0:1::1/128 removed");
4493 connected_pfx.fp_len = 64;
4494 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4495 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4496 "2001:0:0:2/64 removed");
4497 connected_pfx.fp_len = 128;
4498 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4499 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4500 "2001:0:0:2::1/128 removed");
4503 * -8 entries. -7 path-lists (1 was shared).
4505 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4506 fib_path_list_db_size());
4507 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
4508 fib_path_list_pool_size());
4509 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4510 fib_entry_pool_size());
4513 * now remove the VRF
4515 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4517 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4518 fib_path_list_db_size());
4519 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
4520 fib_path_list_pool_size());
4521 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
4522 fib_entry_pool_size());
4528 * return the interfaces to up state
4530 error = vnet_sw_interface_set_flags(vnet_get_main(),
4531 tm->hw[0]->sw_if_index,
4532 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4533 error = vnet_sw_interface_set_flags(vnet_get_main(),
4534 tm->hw[1]->sw_if_index,
4535 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4537 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4544 * Test Attached Exports
4549 const dpo_id_t *dpo, *dpo_drop;
4550 const u32 fib_index = 0;
4551 fib_node_index_t fei;
4558 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4562 * add interface routes. We'll assume this works. It's more rigorously
4565 fib_prefix_t local_pfx = {
4567 .fp_proto = FIB_PROTOCOL_IP4,
4571 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4576 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4577 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4579 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4581 fib_table_entry_update_one_path(fib_index, &local_pfx,
4582 FIB_SOURCE_INTERFACE,
4583 (FIB_ENTRY_FLAG_CONNECTED |
4584 FIB_ENTRY_FLAG_ATTACHED),
4587 tm->hw[0]->sw_if_index,
4591 FIB_ROUTE_PATH_FLAG_NONE);
4592 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4593 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4594 "attached interface route present");
4596 local_pfx.fp_len = 32;
4597 fib_table_entry_update_one_path(fib_index, &local_pfx,
4598 FIB_SOURCE_INTERFACE,
4599 (FIB_ENTRY_FLAG_CONNECTED |
4600 FIB_ENTRY_FLAG_LOCAL),
4603 tm->hw[0]->sw_if_index,
4604 ~0, // invalid fib index
4607 FIB_ROUTE_PATH_FLAG_NONE);
4608 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4610 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4611 "local interface route present");
4614 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4616 fib_prefix_t pfx_10_10_10_1_s_32 = {
4618 .fp_proto = FIB_PROTOCOL_IP4,
4621 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4624 fib_node_index_t ai;
4626 fib_table_entry_update_one_path(fib_index,
4627 &pfx_10_10_10_1_s_32,
4629 FIB_ENTRY_FLAG_ATTACHED,
4631 &pfx_10_10_10_1_s_32.fp_addr,
4632 tm->hw[0]->sw_if_index,
4633 ~0, // invalid fib index
4636 FIB_ROUTE_PATH_FLAG_NONE);
4638 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4639 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4640 ai = fib_entry_get_adj(fei);
4643 * create another FIB table into which routes will be imported
4645 u32 import_fib_index1;
4647 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4650 * Add an attached route in the import FIB
4652 local_pfx.fp_len = 24;
4653 fib_table_entry_update_one_path(import_fib_index1,
4656 FIB_ENTRY_FLAG_NONE,
4659 tm->hw[0]->sw_if_index,
4660 ~0, // invalid fib index
4663 FIB_ROUTE_PATH_FLAG_NONE);
4664 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4665 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4668 * check for the presence of the adj-fibs in the import table
4670 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4671 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4672 FIB_TEST((ai == fib_entry_get_adj(fei)),
4673 "adj-fib1 Import uses same adj as export");
4676 * check for the presence of the local in the import table
4678 local_pfx.fp_len = 32;
4679 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4680 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4683 * Add another adj-fin in the export table. Expect this
4684 * to get magically exported;
4686 fib_prefix_t pfx_10_10_10_2_s_32 = {
4688 .fp_proto = FIB_PROTOCOL_IP4,
4691 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4695 fib_table_entry_update_one_path(fib_index,
4696 &pfx_10_10_10_2_s_32,
4698 FIB_ENTRY_FLAG_ATTACHED,
4700 &pfx_10_10_10_2_s_32.fp_addr,
4701 tm->hw[0]->sw_if_index,
4702 ~0, // invalid fib index
4705 FIB_ROUTE_PATH_FLAG_NONE);
4706 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4707 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4708 ai = fib_entry_get_adj(fei);
4710 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4711 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4712 FIB_TEST((ai == fib_entry_get_adj(fei)),
4713 "Import uses same adj as export");
4714 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
4715 "ADJ-fib2 imported flags %d",
4716 fib_entry_get_flags(fei));
4719 * create a 2nd FIB table into which routes will be imported
4721 u32 import_fib_index2;
4723 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4726 * Add an attached route in the import FIB
4728 local_pfx.fp_len = 24;
4729 fib_table_entry_update_one_path(import_fib_index2,
4732 FIB_ENTRY_FLAG_NONE,
4735 tm->hw[0]->sw_if_index,
4736 ~0, // invalid fib index
4739 FIB_ROUTE_PATH_FLAG_NONE);
4740 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4741 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4744 * check for the presence of all the adj-fibs and local in the import table
4746 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4747 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4748 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4749 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4750 local_pfx.fp_len = 32;
4751 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4752 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4755 * add a 3rd adj-fib. expect it to be exported to both tables.
4757 fib_prefix_t pfx_10_10_10_3_s_32 = {
4759 .fp_proto = FIB_PROTOCOL_IP4,
4762 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4766 fib_table_entry_update_one_path(fib_index,
4767 &pfx_10_10_10_3_s_32,
4769 FIB_ENTRY_FLAG_ATTACHED,
4771 &pfx_10_10_10_3_s_32.fp_addr,
4772 tm->hw[0]->sw_if_index,
4773 ~0, // invalid fib index
4776 FIB_ROUTE_PATH_FLAG_NONE);
4777 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4778 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4779 ai = fib_entry_get_adj(fei);
4781 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4782 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4783 FIB_TEST((ai == fib_entry_get_adj(fei)),
4784 "Import uses same adj as export");
4785 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4786 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4787 FIB_TEST((ai == fib_entry_get_adj(fei)),
4788 "Import uses same adj as export");
4791 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4793 fib_table_entry_delete(fib_index,
4794 &pfx_10_10_10_3_s_32,
4797 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4798 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4800 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4801 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
4803 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4804 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4807 * remove the attached route from the 2nd FIB. expect the imported
4808 * entires to be removed
4810 local_pfx.fp_len = 24;
4811 fib_table_entry_delete(import_fib_index2,
4814 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4815 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4817 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4818 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4819 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4820 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4821 local_pfx.fp_len = 32;
4822 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4823 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4825 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4826 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4827 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4828 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4829 local_pfx.fp_len = 32;
4830 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4831 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4834 * modify the route in FIB1 so it is no longer attached. expect the imported
4835 * entires to be removed
4837 local_pfx.fp_len = 24;
4838 fib_table_entry_update_one_path(import_fib_index1,
4841 FIB_ENTRY_FLAG_NONE,
4843 &pfx_10_10_10_2_s_32.fp_addr,
4844 tm->hw[0]->sw_if_index,
4845 ~0, // invalid fib index
4848 FIB_ROUTE_PATH_FLAG_NONE);
4849 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4850 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4851 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4852 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4853 local_pfx.fp_len = 32;
4854 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4855 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4858 * modify it back to attached. expect the adj-fibs back
4860 local_pfx.fp_len = 24;
4861 fib_table_entry_update_one_path(import_fib_index1,
4864 FIB_ENTRY_FLAG_NONE,
4867 tm->hw[0]->sw_if_index,
4868 ~0, // invalid fib index
4871 FIB_ROUTE_PATH_FLAG_NONE);
4872 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4873 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4874 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4875 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4876 local_pfx.fp_len = 32;
4877 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4878 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4881 * add a covering attached next-hop for the interface address, so we have
4882 * a valid adj to find when we check the forwarding tables
4884 fib_prefix_t pfx_10_0_0_0_s_8 = {
4886 .fp_proto = FIB_PROTOCOL_IP4,
4889 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4893 fei = fib_table_entry_update_one_path(fib_index,
4896 FIB_ENTRY_FLAG_NONE,
4898 &pfx_10_10_10_3_s_32.fp_addr,
4899 tm->hw[0]->sw_if_index,
4900 ~0, // invalid fib index
4903 FIB_ROUTE_PATH_FLAG_NONE);
4904 dpo = fib_entry_contribute_ip_forwarding(fei);
4907 * remove the route in the export fib. expect the adj-fibs to be removed
4909 local_pfx.fp_len = 24;
4910 fib_table_entry_delete(fib_index,
4912 FIB_SOURCE_INTERFACE);
4914 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4915 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4916 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4917 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4918 local_pfx.fp_len = 32;
4919 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4920 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4923 * the adj-fibs in the export VRF are present in the FIB table,
4924 * but not installed in forwarding, since they have no attached cover.
4925 * Consequently a lookup in the MTRIE gives the adj for the covering
4928 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4929 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4932 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4933 FIB_TEST(lbi == dpo->dpoi_index,
4934 "10.10.10.1 forwards on \n%U not \n%U",
4935 format_load_balance, lbi, 0,
4936 format_dpo_id, dpo, 0);
4937 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4938 FIB_TEST(lbi == dpo->dpoi_index,
4939 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4940 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
4941 FIB_TEST(lbi == dpo->dpoi_index,
4942 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
4945 * add the export prefix back, but not as attached.
4946 * No adj-fibs in export nor import tables
4948 local_pfx.fp_len = 24;
4949 fei = fib_table_entry_update_one_path(fib_index,
4952 FIB_ENTRY_FLAG_NONE,
4954 &pfx_10_10_10_1_s_32.fp_addr,
4955 tm->hw[0]->sw_if_index,
4956 ~0, // invalid fib index
4959 FIB_ROUTE_PATH_FLAG_NONE);
4960 dpo = fib_entry_contribute_ip_forwarding(fei);
4962 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4963 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
4964 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4965 FIB_TEST(lbi == dpo->dpoi_index,
4966 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
4967 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4968 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4969 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4970 FIB_TEST(lbi == dpo->dpoi_index,
4971 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4973 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4974 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4975 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4976 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4977 local_pfx.fp_len = 32;
4978 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4979 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4982 * modify the export prefix so it is attached. expect all covereds to return
4984 local_pfx.fp_len = 24;
4985 fib_table_entry_update_one_path(fib_index,
4988 FIB_ENTRY_FLAG_NONE,
4991 tm->hw[0]->sw_if_index,
4992 ~0, // invalid fib index
4995 FIB_ROUTE_PATH_FLAG_NONE);
4997 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4998 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4999 dpo = fib_entry_contribute_ip_forwarding(fei);
5000 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5001 "Adj-fib1 is not drop in export");
5002 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5003 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5004 local_pfx.fp_len = 32;
5005 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5006 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5007 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5008 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5009 dpo = fib_entry_contribute_ip_forwarding(fei);
5010 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5011 "Adj-fib1 is not drop in export");
5012 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5013 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5014 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5015 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5016 local_pfx.fp_len = 32;
5017 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5018 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5021 * modify the export prefix so connected. no change.
5023 local_pfx.fp_len = 24;
5024 fib_table_entry_update_one_path(fib_index, &local_pfx,
5025 FIB_SOURCE_INTERFACE,
5026 (FIB_ENTRY_FLAG_CONNECTED |
5027 FIB_ENTRY_FLAG_ATTACHED),
5030 tm->hw[0]->sw_if_index,
5034 FIB_ROUTE_PATH_FLAG_NONE);
5036 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5037 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5038 dpo = fib_entry_contribute_ip_forwarding(fei);
5039 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5040 "Adj-fib1 is not drop in export");
5041 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5042 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5043 local_pfx.fp_len = 32;
5044 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5045 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5046 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5047 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5048 dpo = fib_entry_contribute_ip_forwarding(fei);
5049 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5050 "Adj-fib1 is not drop in export");
5051 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5052 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5053 local_pfx.fp_len = 32;
5054 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5055 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5060 fib_table_entry_delete(fib_index,
5063 fib_table_entry_delete(fib_index,
5064 &pfx_10_10_10_1_s_32,
5066 fib_table_entry_delete(fib_index,
5067 &pfx_10_10_10_2_s_32,
5069 local_pfx.fp_len = 32;
5070 fib_table_entry_delete(fib_index,
5072 FIB_SOURCE_INTERFACE);
5073 local_pfx.fp_len = 24;
5074 fib_table_entry_delete(fib_index,
5077 fib_table_entry_delete(fib_index,
5079 FIB_SOURCE_INTERFACE);
5080 local_pfx.fp_len = 24;
5081 fib_table_entry_delete(import_fib_index1,
5085 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5086 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5088 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5096 * Test the recursive route route handling for GRE tunnels
5099 fib_test_label (void)
5101 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;
5102 const u32 fib_index = 0;
5107 lb_count = pool_elts(load_balance_pool);
5112 * add interface routes. We'll assume this works. It's more rigorously
5115 fib_prefix_t local0_pfx = {
5117 .fp_proto = FIB_PROTOCOL_IP4,
5121 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5126 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5129 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5130 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5132 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5133 FIB_SOURCE_INTERFACE,
5134 (FIB_ENTRY_FLAG_CONNECTED |
5135 FIB_ENTRY_FLAG_ATTACHED),
5138 tm->hw[0]->sw_if_index,
5142 FIB_ROUTE_PATH_FLAG_NONE);
5143 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5144 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5145 "attached interface route present");
5147 local0_pfx.fp_len = 32;
5148 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5149 FIB_SOURCE_INTERFACE,
5150 (FIB_ENTRY_FLAG_CONNECTED |
5151 FIB_ENTRY_FLAG_LOCAL),
5154 tm->hw[0]->sw_if_index,
5155 ~0, // invalid fib index
5158 FIB_ROUTE_PATH_FLAG_NONE);
5159 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5161 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5162 "local interface route present");
5164 fib_prefix_t local1_pfx = {
5166 .fp_proto = FIB_PROTOCOL_IP4,
5170 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5175 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5176 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5178 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5179 FIB_SOURCE_INTERFACE,
5180 (FIB_ENTRY_FLAG_CONNECTED |
5181 FIB_ENTRY_FLAG_ATTACHED),
5184 tm->hw[1]->sw_if_index,
5188 FIB_ROUTE_PATH_FLAG_NONE);
5189 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5190 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5191 "attached interface route present");
5193 local1_pfx.fp_len = 32;
5194 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5195 FIB_SOURCE_INTERFACE,
5196 (FIB_ENTRY_FLAG_CONNECTED |
5197 FIB_ENTRY_FLAG_LOCAL),
5200 tm->hw[1]->sw_if_index,
5201 ~0, // invalid fib index
5204 FIB_ROUTE_PATH_FLAG_NONE);
5205 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5207 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5208 "local interface route present");
5210 ip46_address_t nh_10_10_10_1 = {
5212 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5215 ip46_address_t nh_10_10_11_1 = {
5217 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5220 ip46_address_t nh_10_10_11_2 = {
5222 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5226 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5229 tm->hw[1]->sw_if_index);
5230 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5233 tm->hw[1]->sw_if_index);
5234 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5237 tm->hw[0]->sw_if_index);
5238 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5241 tm->hw[1]->sw_if_index);
5242 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5245 tm->hw[1]->sw_if_index);
5248 * Add an etry with one path with a real out-going label
5250 fib_prefix_t pfx_1_1_1_1_s_32 = {
5252 .fp_proto = FIB_PROTOCOL_IP4,
5254 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5257 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5258 .type = FT_LB_LABEL_O_ADJ,
5260 .adj = ai_mpls_10_10_10_1,
5265 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5266 .type = FT_LB_LABEL_O_ADJ,
5268 .adj = ai_mpls_10_10_10_1,
5270 .eos = MPLS_NON_EOS,
5273 mpls_label_t *l99 = NULL;
5276 fib_table_entry_update_one_path(fib_index,
5279 FIB_ENTRY_FLAG_NONE,
5282 tm->hw[0]->sw_if_index,
5283 ~0, // invalid fib index
5286 FIB_ROUTE_PATH_FLAG_NONE);
5288 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5289 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5291 FIB_TEST(fib_test_validate_entry(fei,
5292 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5294 &l99_eos_o_10_10_10_1),
5295 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5298 * add a path with an implicit NULL label
5300 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5303 .adj = ai_v4_10_10_11_1,
5306 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5309 .adj = ai_mpls_10_10_11_1,
5312 mpls_label_t *l_imp_null = NULL;
5313 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5315 fei = fib_table_entry_path_add(fib_index,
5318 FIB_ENTRY_FLAG_NONE,
5321 tm->hw[1]->sw_if_index,
5322 ~0, // invalid fib index
5325 FIB_ROUTE_PATH_FLAG_NONE);
5327 FIB_TEST(fib_test_validate_entry(fei,
5328 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5330 &l99_eos_o_10_10_10_1,
5332 "1.1.1.1/32 LB 2 buckets via: "
5333 "label 99 over 10.10.10.1, "
5334 "adj over 10.10.11.1");
5337 * assign the route a local label
5339 fib_table_entry_local_label_add(fib_index,
5343 fib_prefix_t pfx_24001_eos = {
5344 .fp_proto = FIB_PROTOCOL_MPLS,
5348 fib_prefix_t pfx_24001_neos = {
5349 .fp_proto = FIB_PROTOCOL_MPLS,
5351 .fp_eos = MPLS_NON_EOS,
5355 * The EOS entry should link to both the paths,
5356 * and use an ip adj for the imp-null
5357 * The NON-EOS entry should link to both the paths,
5358 * and use an mpls adj for the imp-null
5360 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5362 FIB_TEST(fib_test_validate_entry(fei,
5363 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5365 &l99_eos_o_10_10_10_1,
5367 "24001/eos LB 2 buckets via: "
5368 "label 99 over 10.10.10.1, "
5369 "adj over 10.10.11.1");
5372 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5374 FIB_TEST(fib_test_validate_entry(fei,
5375 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5377 &l99_neos_o_10_10_10_1,
5378 &a_mpls_o_10_10_11_1),
5379 "24001/neos LB 1 bucket via: "
5380 "label 99 over 10.10.10.1 ",
5381 "mpls-adj via 10.10.11.1");
5384 * add an unlabelled path, this is excluded from the neos chains,
5386 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5389 .adj = ai_v4_10_10_11_2,
5393 fei = fib_table_entry_path_add(fib_index,
5396 FIB_ENTRY_FLAG_NONE,
5399 tm->hw[1]->sw_if_index,
5400 ~0, // invalid fib index
5403 FIB_ROUTE_PATH_FLAG_NONE);
5405 FIB_TEST(fib_test_validate_entry(fei,
5406 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5407 16, // 3 choices spread over 16 buckets
5408 &l99_eos_o_10_10_10_1,
5409 &l99_eos_o_10_10_10_1,
5410 &l99_eos_o_10_10_10_1,
5411 &l99_eos_o_10_10_10_1,
5412 &l99_eos_o_10_10_10_1,
5413 &l99_eos_o_10_10_10_1,
5424 "1.1.1.1/32 LB 16 buckets via: "
5425 "label 99 over 10.10.10.1, "
5426 "adj over 10.10.11.1",
5427 "adj over 10.10.11.2");
5430 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5432 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5433 fib_entry_contribute_forwarding(fei,
5434 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5438 * n-eos has only the 2 labelled paths
5440 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5443 FIB_TEST(fib_test_validate_entry(fei,
5444 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5446 &l99_neos_o_10_10_10_1,
5447 &a_mpls_o_10_10_11_1),
5448 "24001/neos LB 2 buckets via: "
5449 "label 99 over 10.10.10.1, "
5450 "adj-mpls over 10.10.11.2");
5453 * A labelled recursive
5455 fib_prefix_t pfx_2_2_2_2_s_32 = {
5457 .fp_proto = FIB_PROTOCOL_IP4,
5459 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5462 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5463 .type = FT_LB_LABEL_O_LB,
5465 .lb = non_eos_1_1_1_1.dpoi_index,
5470 mpls_label_t *l1600 = NULL;
5471 vec_add1(l1600, 1600);
5473 fib_table_entry_update_one_path(fib_index,
5476 FIB_ENTRY_FLAG_NONE,
5478 &pfx_1_1_1_1_s_32.fp_addr,
5483 FIB_ROUTE_PATH_FLAG_NONE);
5485 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5486 FIB_TEST(fib_test_validate_entry(fei,
5487 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5489 &l1600_eos_o_1_1_1_1),
5490 "2.2.2.2.2/32 LB 1 buckets via: "
5491 "label 1600 over 1.1.1.1");
5493 dpo_id_t dpo_44 = DPO_INVALID;
5496 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5497 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5499 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5500 "uRPF check for 2.2.2.2/32 on %d OK",
5501 tm->hw[0]->sw_if_index);
5502 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5503 "uRPF check for 2.2.2.2/32 on %d OK",
5504 tm->hw[1]->sw_if_index);
5505 FIB_TEST(!fib_urpf_check(urpfi, 99),
5506 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5509 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5510 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5511 "Shared uRPF on IP and non-EOS chain");
5516 * we are holding a lock on the non-eos LB of the via-entry.
5517 * do a PIC-core failover by shutting the link of the via-entry.
5519 * shut down the link with the valid label
5521 vnet_sw_interface_set_flags(vnet_get_main(),
5522 tm->hw[0]->sw_if_index,
5525 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5526 FIB_TEST(fib_test_validate_entry(fei,
5527 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5531 "1.1.1.1/32 LB 2 buckets via: "
5532 "adj over 10.10.11.1, ",
5533 "adj-v4 over 10.10.11.2");
5535 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5537 FIB_TEST(fib_test_validate_entry(fei,
5538 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5542 "24001/eos LB 2 buckets via: "
5543 "adj over 10.10.11.1, ",
5544 "adj-v4 over 10.10.11.2");
5546 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5548 FIB_TEST(fib_test_validate_entry(fei,
5549 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5551 &a_mpls_o_10_10_11_1),
5552 "24001/neos LB 1 buckets via: "
5553 "adj-mpls over 10.10.11.2");
5556 * test that the pre-failover load-balance has been in-place
5559 dpo_id_t current = DPO_INVALID;
5560 fib_entry_contribute_forwarding(fei,
5561 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5564 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5566 "PIC-core LB inplace modified %U %U",
5567 format_dpo_id, &non_eos_1_1_1_1, 0,
5568 format_dpo_id, ¤t, 0);
5570 dpo_reset(&non_eos_1_1_1_1);
5571 dpo_reset(¤t);
5574 * no-shut the link with the valid label
5576 vnet_sw_interface_set_flags(vnet_get_main(),
5577 tm->hw[0]->sw_if_index,
5578 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5580 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5581 FIB_TEST(fib_test_validate_entry(fei,
5582 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5583 16, // 3 choices spread over 16 buckets
5584 &l99_eos_o_10_10_10_1,
5585 &l99_eos_o_10_10_10_1,
5586 &l99_eos_o_10_10_10_1,
5587 &l99_eos_o_10_10_10_1,
5588 &l99_eos_o_10_10_10_1,
5589 &l99_eos_o_10_10_10_1,
5600 "1.1.1.1/32 LB 16 buckets via: "
5601 "label 99 over 10.10.10.1, "
5602 "adj over 10.10.11.1",
5603 "adj-v4 over 10.10.11.2");
5606 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5608 FIB_TEST(fib_test_validate_entry(fei,
5609 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5610 16, // 3 choices spread over 16 buckets
5611 &l99_eos_o_10_10_10_1,
5612 &l99_eos_o_10_10_10_1,
5613 &l99_eos_o_10_10_10_1,
5614 &l99_eos_o_10_10_10_1,
5615 &l99_eos_o_10_10_10_1,
5616 &l99_eos_o_10_10_10_1,
5627 "24001/eos LB 16 buckets via: "
5628 "label 99 over 10.10.10.1, "
5629 "adj over 10.10.11.1",
5630 "adj-v4 over 10.10.11.2");
5632 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5634 FIB_TEST(fib_test_validate_entry(fei,
5635 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5637 &l99_neos_o_10_10_10_1,
5638 &a_mpls_o_10_10_11_1),
5639 "24001/neos LB 2 buckets via: "
5640 "label 99 over 10.10.10.1, "
5641 "adj-mpls over 10.10.11.2");
5644 * remove the first path with the valid label
5646 fib_table_entry_path_remove(fib_index,
5651 tm->hw[0]->sw_if_index,
5652 ~0, // invalid fib index
5654 FIB_ROUTE_PATH_FLAG_NONE);
5656 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5657 FIB_TEST(fib_test_validate_entry(fei,
5658 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5662 "1.1.1.1/32 LB 2 buckets via: "
5663 "adj over 10.10.11.1",
5664 "adj-v4 over 10.10.11.2");
5666 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5668 FIB_TEST(fib_test_validate_entry(fei,
5669 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5673 "24001/eos LB 2 buckets via: "
5674 "adj over 10.10.11.1",
5675 "adj-v4 over 10.10.11.2");
5677 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5680 FIB_TEST(fib_test_validate_entry(fei,
5681 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5683 &a_mpls_o_10_10_11_1),
5684 "24001/neos LB 1 buckets via: "
5685 "adj-mpls over 10.10.11.2");
5688 * remove the other path with a valid label
5690 fib_test_lb_bucket_t bucket_drop = {
5691 .type = FT_LB_SPECIAL,
5693 .adj = DPO_PROTO_IP4,
5697 fib_table_entry_path_remove(fib_index,
5702 tm->hw[1]->sw_if_index,
5703 ~0, // invalid fib index
5705 FIB_ROUTE_PATH_FLAG_NONE);
5707 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5708 FIB_TEST(fib_test_validate_entry(fei,
5709 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5712 "1.1.1.1/32 LB 1 buckets via: "
5713 "adj over 10.10.11.2");
5715 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5717 FIB_TEST(fib_test_validate_entry(fei,
5718 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5721 "24001/eos LB 1 buckets via: "
5722 "adj over 10.10.11.2");
5724 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5726 FIB_TEST(fib_test_validate_entry(fei,
5727 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5730 "24001/eos LB 1 buckets via: DROP");
5733 * add back the path with the valid label
5738 fib_table_entry_path_add(fib_index,
5741 FIB_ENTRY_FLAG_NONE,
5744 tm->hw[0]->sw_if_index,
5745 ~0, // invalid fib index
5748 FIB_ROUTE_PATH_FLAG_NONE);
5750 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5751 FIB_TEST(fib_test_validate_entry(fei,
5752 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5754 &l99_eos_o_10_10_10_1,
5756 "1.1.1.1/32 LB 2 buckets via: "
5757 "label 99 over 10.10.10.1, "
5758 "adj over 10.10.11.2");
5760 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5762 FIB_TEST(fib_test_validate_entry(fei,
5763 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5765 &l99_eos_o_10_10_10_1,
5767 "24001/eos LB 2 buckets via: "
5768 "label 99 over 10.10.10.1, "
5769 "adj over 10.10.11.2");
5771 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5773 FIB_TEST(fib_test_validate_entry(fei,
5774 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5776 &l99_neos_o_10_10_10_1),
5777 "24001/neos LB 1 buckets via: "
5778 "label 99 over 10.10.10.1");
5781 * change the local label
5783 fib_table_entry_local_label_add(fib_index,
5787 fib_prefix_t pfx_25005_eos = {
5788 .fp_proto = FIB_PROTOCOL_MPLS,
5792 fib_prefix_t pfx_25005_neos = {
5793 .fp_proto = FIB_PROTOCOL_MPLS,
5795 .fp_eos = MPLS_NON_EOS,
5798 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5799 fib_table_lookup(fib_index, &pfx_24001_eos)),
5800 "24001/eos removed after label change");
5801 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5802 fib_table_lookup(fib_index, &pfx_24001_neos)),
5803 "24001/eos removed after label change");
5805 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5807 FIB_TEST(fib_test_validate_entry(fei,
5808 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5810 &l99_eos_o_10_10_10_1,
5812 "25005/eos LB 2 buckets via: "
5813 "label 99 over 10.10.10.1, "
5814 "adj over 10.10.11.2");
5816 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5818 FIB_TEST(fib_test_validate_entry(fei,
5819 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5821 &l99_neos_o_10_10_10_1),
5822 "25005/neos LB 1 buckets via: "
5823 "label 99 over 10.10.10.1");
5826 * remove the local label.
5827 * the check that the MPLS entries are gone is done by the fact the
5828 * MPLS table is no longer present.
5830 fib_table_entry_local_label_remove(fib_index,
5834 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5835 FIB_TEST(fib_test_validate_entry(fei,
5836 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5838 &l99_eos_o_10_10_10_1,
5840 "24001/eos LB 2 buckets via: "
5841 "label 99 over 10.10.10.1, "
5842 "adj over 10.10.11.2");
5844 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5845 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5846 "No more MPLS FIB entries => table removed");
5849 * add another via-entry for the recursive
5851 fib_prefix_t pfx_1_1_1_2_s_32 = {
5853 .fp_proto = FIB_PROTOCOL_IP4,
5855 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5858 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5859 .type = FT_LB_LABEL_O_ADJ,
5861 .adj = ai_mpls_10_10_10_1,
5866 mpls_label_t *l101 = NULL;
5867 vec_add1(l101, 101);
5869 fei = fib_table_entry_update_one_path(fib_index,
5872 FIB_ENTRY_FLAG_NONE,
5875 tm->hw[0]->sw_if_index,
5876 ~0, // invalid fib index
5879 FIB_ROUTE_PATH_FLAG_NONE);
5881 FIB_TEST(fib_test_validate_entry(fei,
5882 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5884 &l101_eos_o_10_10_10_1),
5885 "1.1.1.2/32 LB 1 buckets via: "
5886 "label 101 over 10.10.10.1");
5888 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
5889 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5891 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5893 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5895 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5898 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5899 .type = FT_LB_LABEL_O_LB,
5901 .lb = non_eos_1_1_1_2.dpoi_index,
5906 mpls_label_t *l1601 = NULL;
5907 vec_add1(l1601, 1601);
5909 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5911 fei = fib_table_entry_path_add(fib_index,
5914 FIB_ENTRY_FLAG_NONE,
5916 &pfx_1_1_1_2_s_32.fp_addr,
5921 FIB_ROUTE_PATH_FLAG_NONE);
5923 FIB_TEST(fib_test_validate_entry(fei,
5924 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5926 &l1600_eos_o_1_1_1_1,
5927 &l1601_eos_o_1_1_1_2),
5928 "2.2.2.2/32 LB 2 buckets via: "
5929 "label 1600 via 1.1,1.1, "
5930 "label 16001 via 1.1.1.2");
5933 * update the via-entry so it no longer has an imp-null path.
5934 * the LB for the recursive can use an imp-null
5937 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5939 fei = fib_table_entry_update_one_path(fib_index,
5942 FIB_ENTRY_FLAG_NONE,
5945 tm->hw[1]->sw_if_index,
5946 ~0, // invalid fib index
5949 FIB_ROUTE_PATH_FLAG_NONE);
5951 FIB_TEST(fib_test_validate_entry(fei,
5952 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5955 "1.1.1.2/32 LB 1 buckets via: "
5958 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5959 FIB_TEST(fib_test_validate_entry(fei,
5960 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5962 &l1600_eos_o_1_1_1_1,
5963 &l1601_eos_o_1_1_1_2),
5964 "2.2.2.2/32 LB 2 buckets via: "
5965 "label 1600 via 1.1,1.1, "
5966 "label 16001 via 1.1.1.2");
5969 * update the via-entry so it no longer has labelled paths.
5970 * the LB for the recursive should exclue this via form its LB
5972 fei = fib_table_entry_update_one_path(fib_index,
5975 FIB_ENTRY_FLAG_NONE,
5978 tm->hw[1]->sw_if_index,
5979 ~0, // invalid fib index
5982 FIB_ROUTE_PATH_FLAG_NONE);
5984 FIB_TEST(fib_test_validate_entry(fei,
5985 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5988 "1.1.1.2/32 LB 1 buckets via: "
5991 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5992 FIB_TEST(fib_test_validate_entry(fei,
5993 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5995 &l1600_eos_o_1_1_1_1),
5996 "2.2.2.2/32 LB 1 buckets via: "
5997 "label 1600 via 1.1,1.1");
5999 dpo_reset(&non_eos_1_1_1_1);
6000 dpo_reset(&non_eos_1_1_1_2);
6003 * Add a recursive with no out-labels. We expect to use the IP of the via
6005 fib_prefix_t pfx_2_2_2_3_s_32 = {
6007 .fp_proto = FIB_PROTOCOL_IP4,
6009 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6012 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6014 fib_table_entry_update_one_path(fib_index,
6017 FIB_ENTRY_FLAG_NONE,
6019 &pfx_1_1_1_1_s_32.fp_addr,
6024 FIB_ROUTE_PATH_FLAG_NONE);
6026 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6028 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6031 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6034 .lb = ip_1_1_1_1.dpoi_index,
6038 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6039 FIB_TEST(fib_test_validate_entry(fei,
6040 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6043 "2.2.2.2.3/32 LB 1 buckets via: "
6047 * Add a recursive with an imp-null out-label.
6048 * We expect to use the IP of the via
6050 fib_prefix_t pfx_2_2_2_4_s_32 = {
6052 .fp_proto = FIB_PROTOCOL_IP4,
6054 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6058 fib_table_entry_update_one_path(fib_index,
6061 FIB_ENTRY_FLAG_NONE,
6063 &pfx_1_1_1_1_s_32.fp_addr,
6068 FIB_ROUTE_PATH_FLAG_NONE);
6070 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6071 FIB_TEST(fib_test_validate_entry(fei,
6072 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6075 "2.2.2.2.4/32 LB 1 buckets via: "
6078 dpo_reset(&ip_1_1_1_1);
6081 * Create an entry with a deep label stack
6083 fib_prefix_t pfx_2_2_5_5_s_32 = {
6085 .fp_proto = FIB_PROTOCOL_IP4,
6087 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6090 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6091 .type = FT_LB_LABEL_STACK_O_ADJ,
6092 .label_stack_o_adj = {
6093 .adj = ai_mpls_10_10_11_1,
6094 .label_stack_size = 8,
6096 200, 201, 202, 203, 204, 205, 206, 207
6101 mpls_label_t *label_stack = NULL;
6102 vec_validate(label_stack, 7);
6103 for (ii = 0; ii < 8; ii++)
6105 label_stack[ii] = ii + 200;
6108 fei = fib_table_entry_update_one_path(fib_index,
6111 FIB_ENTRY_FLAG_NONE,
6114 tm->hw[1]->sw_if_index,
6115 ~0, // invalid fib index
6118 FIB_ROUTE_PATH_FLAG_NONE);
6120 FIB_TEST(fib_test_validate_entry(fei,
6121 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6123 &ls_eos_o_10_10_10_1),
6124 "2.2.5.5/32 LB 1 buckets via: "
6126 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6131 fib_table_entry_delete(fib_index,
6135 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6136 FIB_TEST(fib_test_validate_entry(fei,
6137 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6139 &l1600_eos_o_1_1_1_1),
6140 "2.2.2.2/32 LB 1 buckets via: "
6141 "label 1600 via 1.1,1.1");
6143 fib_table_entry_delete(fib_index,
6147 FIB_TEST(fib_test_validate_entry(fei,
6148 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6151 "2.2.2.2/32 LB 1 buckets via: DROP");
6153 fib_table_entry_delete(fib_index,
6156 fib_table_entry_delete(fib_index,
6159 fib_table_entry_delete(fib_index,
6163 adj_unlock(ai_mpls_10_10_10_1);
6164 adj_unlock(ai_mpls_10_10_11_2);
6165 adj_unlock(ai_v4_10_10_11_1);
6166 adj_unlock(ai_v4_10_10_11_2);
6167 adj_unlock(ai_mpls_10_10_11_1);
6169 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6172 local0_pfx.fp_len = 32;
6173 fib_table_entry_delete(fib_index,
6175 FIB_SOURCE_INTERFACE);
6176 local0_pfx.fp_len = 24;
6177 fib_table_entry_delete(fib_index,
6179 FIB_SOURCE_INTERFACE);
6180 local1_pfx.fp_len = 32;
6181 fib_table_entry_delete(fib_index,
6183 FIB_SOURCE_INTERFACE);
6184 local1_pfx.fp_len = 24;
6185 fib_table_entry_delete(fib_index,
6187 FIB_SOURCE_INTERFACE);
6190 * +1 for the drop LB in the MPLS tables.
6192 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6193 "Load-balance resources freed %d of %d",
6194 lb_count+1, pool_elts(load_balance_pool));
6199 #define N_TEST_CHILDREN 4
6200 #define PARENT_INDEX 0
6202 typedef struct fib_node_test_t_
6207 fib_node_back_walk_ctx_t *ctxs;
6211 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6213 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6215 #define FOR_EACH_TEST_CHILD(_tc) \
6216 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
6217 ii < N_TEST_CHILDREN+1; \
6218 ii++, (_tc) = &fib_test_nodes[ii])
6221 fib_test_child_get_node (fib_node_index_t index)
6223 return (&fib_test_nodes[index].node);
6226 static int fib_test_walk_spawns_walks;
6228 static fib_node_back_walk_rc_t
6229 fib_test_child_back_walk_notify (fib_node_t *node,
6230 fib_node_back_walk_ctx_t *ctx)
6232 fib_node_test_t *tc = (fib_node_test_t*) node;
6234 vec_add1(tc->ctxs, *ctx);
6236 if (1 == fib_test_walk_spawns_walks)
6237 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6238 if (2 == fib_test_walk_spawns_walks)
6239 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6240 FIB_WALK_PRIORITY_HIGH, ctx);
6242 return (FIB_NODE_BACK_WALK_CONTINUE);
6246 fib_test_child_last_lock_gone (fib_node_t *node)
6248 fib_node_test_t *tc = (fib_node_test_t *)node;
6254 * The FIB walk's graph node virtual function table
6256 static const fib_node_vft_t fib_test_child_vft = {
6257 .fnv_get = fib_test_child_get_node,
6258 .fnv_last_lock = fib_test_child_last_lock_gone,
6259 .fnv_back_walk = fib_test_child_back_walk_notify,
6263 * the function (that should have been static but isn't so I can do this)
6264 * that processes the walk from the async queue,
6266 f64 fib_walk_process_queues(vlib_main_t * vm,
6268 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6271 fib_test_walk (void)
6273 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6274 fib_node_test_t *tc;
6278 vm = vlib_get_main();
6279 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6282 * init a fake node on which we will add children
6284 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6285 FIB_NODE_TYPE_TEST);
6287 FOR_EACH_TEST_CHILD(tc)
6289 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6290 fib_node_lock(&tc->node);
6293 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6295 FIB_NODE_TYPE_TEST, ii);
6299 * enqueue a walk across the parents children.
6301 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6303 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6304 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6305 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6306 "Parent has %d children pre-walk",
6307 fib_node_list_get_size(PARENT()->fn_children));
6310 * give the walk a large amount of time so it gets to the end
6312 fib_walk_process_queues(vm, 1);
6314 FOR_EACH_TEST_CHILD(tc)
6316 FIB_TEST(1 == vec_len(tc->ctxs),
6317 "%d child visitsed %d times",
6318 ii, vec_len(tc->ctxs));
6321 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6322 "Queue is empty post walk");
6323 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6324 "Parent has %d children post walk",
6325 fib_node_list_get_size(PARENT()->fn_children));
6328 * walk again. should be no increase in the number of visits, since
6329 * the walk will have terminated.
6331 fib_walk_process_queues(vm, 1);
6333 FOR_EACH_TEST_CHILD(tc)
6335 FIB_TEST(0 == vec_len(tc->ctxs),
6336 "%d child visitsed %d times",
6337 ii, vec_len(tc->ctxs));
6341 * schedule a low and hig priority walk. expect the high to be performed
6343 * schedule the high prio walk first so that it is further from the head
6344 * of the dependency list. that way it won't merge with the low one.
6346 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6347 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6349 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6350 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6351 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6352 FIB_WALK_PRIORITY_LOW, &low_ctx);
6354 fib_walk_process_queues(vm, 1);
6356 FOR_EACH_TEST_CHILD(tc)
6358 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6359 "%d child visitsed by high prio walk", ii);
6360 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6361 "%d child visitsed by low prio walk", ii);
6364 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6365 "Queue is empty post prio walk");
6366 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6367 "Parent has %d children post prio walk",
6368 fib_node_list_get_size(PARENT()->fn_children));
6371 * schedule 2 walks of the same priority that can be megred.
6372 * expect that each child is thus visited only once.
6374 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6375 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6377 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6378 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6379 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6380 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6382 fib_walk_process_queues(vm, 1);
6384 FOR_EACH_TEST_CHILD(tc)
6386 FIB_TEST(1 == vec_len(tc->ctxs),
6387 "%d child visitsed %d times during merge walk",
6388 ii, vec_len(tc->ctxs));
6391 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6392 "Queue is empty post merge walk");
6393 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6394 "Parent has %d children post merge walk",
6395 fib_node_list_get_size(PARENT()->fn_children));
6398 * schedule 2 walks of the same priority that cannot be megred.
6399 * expect that each child is thus visited twice and in the order
6400 * in which the walks were scheduled.
6402 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6403 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6405 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6406 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6407 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6408 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6410 fib_walk_process_queues(vm, 1);
6412 FOR_EACH_TEST_CHILD(tc)
6414 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6415 "%d child visitsed by high prio walk", ii);
6416 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6417 "%d child visitsed by low prio walk", ii);
6420 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6421 "Queue is empty post no-merge walk");
6422 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6423 "Parent has %d children post no-merge walk",
6424 fib_node_list_get_size(PARENT()->fn_children));
6427 * schedule a walk that makes one one child progress.
6428 * we do this by giving the queue draining process zero
6429 * time quanta. it's a do..while loop, so it does something.
6431 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6433 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6434 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6435 fib_walk_process_queues(vm, 0);
6437 FOR_EACH_TEST_CHILD(tc)
6439 if (ii == N_TEST_CHILDREN)
6441 FIB_TEST(1 == vec_len(tc->ctxs),
6442 "%d child visitsed %d times in zero quanta walk",
6443 ii, vec_len(tc->ctxs));
6447 FIB_TEST(0 == vec_len(tc->ctxs),
6448 "%d child visitsed %d times in 0 quanta walk",
6449 ii, vec_len(tc->ctxs));
6452 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6453 "Queue is not empty post zero quanta walk");
6454 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6455 "Parent has %d children post zero qunta walk",
6456 fib_node_list_get_size(PARENT()->fn_children));
6461 fib_walk_process_queues(vm, 0);
6463 FOR_EACH_TEST_CHILD(tc)
6465 if (ii >= N_TEST_CHILDREN-1)
6467 FIB_TEST(1 == vec_len(tc->ctxs),
6468 "%d child visitsed %d times in 2nd zero quanta walk",
6469 ii, vec_len(tc->ctxs));
6473 FIB_TEST(0 == vec_len(tc->ctxs),
6474 "%d child visitsed %d times in 2nd 0 quanta walk",
6475 ii, vec_len(tc->ctxs));
6478 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6479 "Queue is not empty post zero quanta walk");
6480 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6481 "Parent has %d children post zero qunta walk",
6482 fib_node_list_get_size(PARENT()->fn_children));
6485 * schedule another walk that will catch-up and merge.
6487 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6488 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6489 fib_walk_process_queues(vm, 1);
6491 FOR_EACH_TEST_CHILD(tc)
6493 if (ii >= N_TEST_CHILDREN-1)
6495 FIB_TEST(2 == vec_len(tc->ctxs),
6496 "%d child visitsed %d times in 2nd zero quanta merge walk",
6497 ii, vec_len(tc->ctxs));
6502 FIB_TEST(1 == vec_len(tc->ctxs),
6503 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6504 ii, vec_len(tc->ctxs));
6508 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6509 "Queue is not empty post 2nd zero quanta merge walk");
6510 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6511 "Parent has %d children post 2nd zero qunta merge walk",
6512 fib_node_list_get_size(PARENT()->fn_children));
6515 * park a async walk in the middle of the list, then have an sync walk catch
6516 * it. same expectations as async catches async.
6518 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6520 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6521 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6523 fib_walk_process_queues(vm, 0);
6524 fib_walk_process_queues(vm, 0);
6526 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6528 FOR_EACH_TEST_CHILD(tc)
6530 if (ii >= N_TEST_CHILDREN-1)
6532 FIB_TEST(2 == vec_len(tc->ctxs),
6533 "%d child visitsed %d times in sync catches async walk",
6534 ii, vec_len(tc->ctxs));
6539 FIB_TEST(1 == vec_len(tc->ctxs),
6540 "%d child visitsed %d times in sync catches async walk",
6541 ii, vec_len(tc->ctxs));
6545 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6546 "Queue is not empty post 2nd zero quanta merge walk");
6547 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6548 "Parent has %d children post 2nd zero qunta merge walk",
6549 fib_node_list_get_size(PARENT()->fn_children));
6552 * make the parent a child of one of its children, thus inducing a routing loop.
6554 fib_test_nodes[PARENT_INDEX].sibling =
6555 fib_node_child_add(FIB_NODE_TYPE_TEST,
6556 1, // the first child
6561 * execute a sync walk from the parent. each child visited spawns more sync
6562 * walks. we expect the walk to terminate.
6564 fib_test_walk_spawns_walks = 1;
6566 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6568 FOR_EACH_TEST_CHILD(tc)
6571 * child 1 - which is last in the list - has the loop.
6572 * the other children a re thus visitsed first. the we meet
6573 * child 1. we go round the loop again, visting the other children.
6574 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6579 FIB_TEST(1 == vec_len(tc->ctxs),
6580 "child %d visitsed %d times during looped sync walk",
6581 ii, vec_len(tc->ctxs));
6585 FIB_TEST(2 == vec_len(tc->ctxs),
6586 "child %d visitsed %d times during looped sync walk",
6587 ii, vec_len(tc->ctxs));
6591 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6592 "Parent has %d children post sync loop walk",
6593 fib_node_list_get_size(PARENT()->fn_children));
6596 * the walk doesn't reach the max depth because the infra knows that sync
6597 * meets sync implies a loop and bails early.
6599 FIB_TEST(high_ctx.fnbw_depth == 9,
6600 "Walk context depth %d post sync loop walk",
6601 high_ctx.fnbw_depth);
6604 * execute an async walk of the graph loop, with each child spawns sync walks
6606 high_ctx.fnbw_depth = 0;
6607 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6608 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6610 fib_walk_process_queues(vm, 1);
6612 FOR_EACH_TEST_CHILD(tc)
6615 * we don't really care how many times the children are visisted, as long as
6616 * it is more than once.
6618 FIB_TEST(1 <= vec_len(tc->ctxs),
6619 "child %d visitsed %d times during looped aync spawns sync walk",
6620 ii, vec_len(tc->ctxs));
6625 * execute an async walk of the graph loop, with each child spawns async walks
6627 fib_test_walk_spawns_walks = 2;
6628 high_ctx.fnbw_depth = 0;
6629 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6630 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6632 fib_walk_process_queues(vm, 1);
6634 FOR_EACH_TEST_CHILD(tc)
6637 * we don't really care how many times the children are visisted, as long as
6638 * it is more than once.
6640 FIB_TEST(1 <= vec_len(tc->ctxs),
6641 "child %d visitsed %d times during looped async spawns async walk",
6642 ii, vec_len(tc->ctxs));
6647 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6648 1, // the first child
6649 fib_test_nodes[PARENT_INDEX].sibling);
6654 FOR_EACH_TEST_CHILD(tc)
6656 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6658 fib_node_deinit(&tc->node);
6659 fib_node_unlock(&tc->node);
6661 fib_node_deinit(PARENT());
6664 * The parent will be destroyed when the last lock on it goes.
6665 * this test ensures all the walk objects are unlocking it.
6667 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6668 "Parent was destroyed");
6676 const mpls_label_t deag_label = 50;
6677 const u32 lfib_index = 0;
6678 const u32 fib_index = 0;
6679 dpo_id_t dpo = DPO_INVALID;
6680 const dpo_id_t *dpo1;
6681 fib_node_index_t lfe;
6685 adj_index_t ai_mpls_10_10_10_1;
6688 lb_count = pool_elts(load_balance_pool);
6690 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6694 * MPLS enable an interface so we get the MPLS table created
6696 mpls_sw_interface_enable_disable(&mpls_main,
6697 tm->hw[0]->sw_if_index,
6700 ip46_address_t nh_10_10_10_1 = {
6701 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6703 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6706 tm->hw[0]->sw_if_index);
6709 * Test the specials stack properly.
6711 fib_prefix_t exp_null_v6_pfx = {
6712 .fp_proto = FIB_PROTOCOL_MPLS,
6714 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6715 .fp_payload_proto = DPO_PROTO_IP6,
6717 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
6718 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
6720 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6721 format_mpls_eos_bit, MPLS_EOS);
6722 fib_entry_contribute_forwarding(lfe,
6723 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6725 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6726 lkd = lookup_dpo_get(dpo1->dpoi_index);
6728 FIB_TEST((fib_index == lkd->lkd_fib_index),
6729 "%U/%U is deag in %d %U",
6730 format_mpls_unicast_label, deag_label,
6731 format_mpls_eos_bit, MPLS_EOS,
6733 format_dpo_id, &dpo, 0);
6734 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6735 "%U/%U is dst deag",
6736 format_mpls_unicast_label, deag_label,
6737 format_mpls_eos_bit, MPLS_EOS);
6738 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
6739 "%U/%U is lookup in interface's table",
6740 format_mpls_unicast_label, deag_label,
6741 format_mpls_eos_bit, MPLS_EOS);
6742 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
6743 "%U/%U is %U dst deag",
6744 format_mpls_unicast_label, deag_label,
6745 format_mpls_eos_bit, MPLS_EOS,
6746 format_dpo_proto, lkd->lkd_proto);
6750 * A route deag route for EOS
6752 fib_prefix_t pfx = {
6753 .fp_proto = FIB_PROTOCOL_MPLS,
6755 .fp_label = deag_label,
6756 .fp_payload_proto = DPO_PROTO_IP4,
6758 lfe = fib_table_entry_path_add(lfib_index,
6761 FIB_ENTRY_FLAG_NONE,
6768 FIB_ROUTE_PATH_FLAG_NONE);
6770 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6772 format_mpls_unicast_label, deag_label,
6773 format_mpls_eos_bit, MPLS_EOS);
6775 fib_entry_contribute_forwarding(lfe,
6776 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6778 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6779 lkd = lookup_dpo_get(dpo1->dpoi_index);
6781 FIB_TEST((fib_index == lkd->lkd_fib_index),
6782 "%U/%U is deag in %d %U",
6783 format_mpls_unicast_label, deag_label,
6784 format_mpls_eos_bit, MPLS_EOS,
6786 format_dpo_id, &dpo, 0);
6787 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6788 "%U/%U is dst deag",
6789 format_mpls_unicast_label, deag_label,
6790 format_mpls_eos_bit, MPLS_EOS);
6791 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
6792 "%U/%U is %U dst deag",
6793 format_mpls_unicast_label, deag_label,
6794 format_mpls_eos_bit, MPLS_EOS,
6795 format_dpo_proto, lkd->lkd_proto);
6797 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6799 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6801 "%U/%U not present",
6802 format_mpls_unicast_label, deag_label,
6803 format_mpls_eos_bit, MPLS_EOS);
6806 * A route deag route for non-EOS
6808 pfx.fp_eos = MPLS_NON_EOS;
6809 lfe = fib_table_entry_path_add(lfib_index,
6812 FIB_ENTRY_FLAG_NONE,
6819 FIB_ROUTE_PATH_FLAG_NONE);
6821 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6823 format_mpls_unicast_label, deag_label,
6824 format_mpls_eos_bit, MPLS_NON_EOS);
6826 fib_entry_contribute_forwarding(lfe,
6827 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6829 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6830 lkd = lookup_dpo_get(dpo1->dpoi_index);
6832 FIB_TEST((fib_index == lkd->lkd_fib_index),
6833 "%U/%U is deag in %d %U",
6834 format_mpls_unicast_label, deag_label,
6835 format_mpls_eos_bit, MPLS_NON_EOS,
6837 format_dpo_id, &dpo, 0);
6838 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6839 "%U/%U is dst deag",
6840 format_mpls_unicast_label, deag_label,
6841 format_mpls_eos_bit, MPLS_NON_EOS);
6843 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
6844 "%U/%U is %U dst deag",
6845 format_mpls_unicast_label, deag_label,
6846 format_mpls_eos_bit, MPLS_NON_EOS,
6847 format_dpo_proto, lkd->lkd_proto);
6849 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6851 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6853 "%U/%U not present",
6854 format_mpls_unicast_label, deag_label,
6855 format_mpls_eos_bit, MPLS_EOS);
6862 fib_prefix_t pfx_1200 = {
6864 .fp_proto = FIB_PROTOCOL_MPLS,
6866 .fp_eos = MPLS_NON_EOS,
6868 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
6869 .type = FT_LB_LABEL_STACK_O_ADJ,
6870 .label_stack_o_adj = {
6871 .adj = ai_mpls_10_10_10_1,
6872 .label_stack_size = 4,
6876 .eos = MPLS_NON_EOS,
6879 dpo_id_t neos_1200 = DPO_INVALID;
6880 dpo_id_t ip_1200 = DPO_INVALID;
6881 mpls_label_t *l200 = NULL;
6882 vec_add1(l200, 200);
6883 vec_add1(l200, 300);
6884 vec_add1(l200, 400);
6885 vec_add1(l200, 500);
6887 lfe = fib_table_entry_update_one_path(fib_index,
6890 FIB_ENTRY_FLAG_NONE,
6893 tm->hw[0]->sw_if_index,
6894 ~0, // invalid fib index
6897 FIB_ROUTE_PATH_FLAG_NONE);
6899 FIB_TEST(fib_test_validate_entry(lfe,
6900 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6902 &neos_o_10_10_10_1),
6903 "1200/0 LB 1 buckets via: "
6907 * A recursive route via the MPLS x-connect
6909 fib_prefix_t pfx_2_2_2_3_s_32 = {
6911 .fp_proto = FIB_PROTOCOL_IP4,
6913 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6916 fib_route_path_t *rpaths = NULL, rpath = {
6917 .frp_proto = FIB_PROTOCOL_MPLS,
6918 .frp_local_label = 1200,
6919 .frp_sw_if_index = ~0, // recurive
6920 .frp_fib_index = 0, // Default MPLS fib
6922 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6923 .frp_label_stack = NULL,
6925 vec_add1(rpaths, rpath);
6927 fib_table_entry_path_add2(fib_index,
6930 FIB_ENTRY_FLAG_NONE,
6934 * A labelled recursive route via the MPLS x-connect
6936 fib_prefix_t pfx_2_2_2_4_s_32 = {
6938 .fp_proto = FIB_PROTOCOL_IP4,
6940 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6943 mpls_label_t *l999 = NULL;
6944 vec_add1(l999, 999);
6945 rpaths[0].frp_label_stack = l999,
6947 fib_table_entry_path_add2(fib_index,
6950 FIB_ENTRY_FLAG_NONE,
6953 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
6954 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6956 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
6957 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6960 fib_test_lb_bucket_t ip_o_1200 = {
6963 .lb = ip_1200.dpoi_index,
6966 fib_test_lb_bucket_t mpls_o_1200 = {
6967 .type = FT_LB_LABEL_O_LB,
6969 .lb = neos_1200.dpoi_index,
6975 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6976 FIB_TEST(fib_test_validate_entry(lfe,
6977 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6980 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
6981 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6982 FIB_TEST(fib_test_validate_entry(lfe,
6983 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6986 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
6988 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
6989 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
6990 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
6992 dpo_reset(&neos_1200);
6993 dpo_reset(&ip_1200);
6996 * A recursive via a label that does not exist
6998 fib_test_lb_bucket_t bucket_drop = {
6999 .type = FT_LB_SPECIAL,
7001 .adj = DPO_PROTO_MPLS,
7005 rpaths[0].frp_label_stack = NULL;
7006 lfe = fib_table_entry_path_add2(fib_index,
7009 FIB_ENTRY_FLAG_NONE,
7012 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7013 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7015 ip_o_1200.lb.lb = ip_1200.dpoi_index;
7017 FIB_TEST(fib_test_validate_entry(lfe,
7018 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7021 "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
7022 lfe = fib_table_lookup(fib_index, &pfx_1200);
7023 FIB_TEST(fib_test_validate_entry(lfe,
7024 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7027 "2.2.2.4/32 LB 1 buckets via: ip4-DROP");
7029 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7031 dpo_reset(&ip_1200);
7036 mpls_sw_interface_enable_disable(&mpls_main,
7037 tm->hw[0]->sw_if_index,
7040 FIB_TEST(lb_count == pool_elts(load_balance_pool),
7041 "Load-balance resources freed %d of %d",
7042 lb_count, pool_elts(load_balance_pool));
7047 static clib_error_t *
7048 fib_test (vlib_main_t * vm,
7049 unformat_input_t * input,
7050 vlib_cli_command_t * cmd_arg)
7055 fib_test_mk_intf(4);
7057 if (unformat (input, "ip"))
7059 res += fib_test_v4();
7060 res += fib_test_v6();
7062 else if (unformat (input, "label"))
7064 res += fib_test_label();
7066 else if (unformat (input, "ae"))
7068 res += fib_test_ae();
7070 else if (unformat (input, "lfib"))
7074 else if (unformat (input, "walk"))
7076 res += fib_test_walk();
7081 * These walk UT aren't run as part of the full suite, since the
7082 * fib-walk process must be disabled in order for the tests to work
7086 res += fib_test_v4();
7087 res += fib_test_v6();
7088 res += fib_test_ae();
7089 res += fib_test_label();
7095 return clib_error_return(0, "FIB Unit Test Failed");
7103 VLIB_CLI_COMMAND (test_fib_command, static) = {
7105 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
7106 .function = fib_test,
7110 fib_test_init (vlib_main_t *vm)
7115 VLIB_INIT_FUNCTION (fib_test_init);