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 6 entries, and 6 non-shared path-lists, in the v6 default
670 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
671 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
672 fib_path_list_pool_size());
673 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
674 fib_entry_pool_size());
677 * add interface routes.
678 * validate presence of /24 attached and /32 recieve.
679 * test for the presence of the receive address in the glean and local adj
681 fib_prefix_t local_pfx = {
683 .fp_proto = FIB_PROTOCOL_IP4,
686 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
691 fib_table_entry_update_one_path(fib_index, &local_pfx,
692 FIB_SOURCE_INTERFACE,
693 (FIB_ENTRY_FLAG_CONNECTED |
694 FIB_ENTRY_FLAG_ATTACHED),
697 tm->hw[0]->sw_if_index,
698 ~0, // invalid fib index
701 FIB_ROUTE_PATH_FLAG_NONE);
702 fei = fib_table_lookup(fib_index, &local_pfx);
703 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
704 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
705 fib_entry_get_flags(fei)),
706 "Flags set on attached interface");
708 ai = fib_entry_get_adj(fei);
709 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
711 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
712 "attached interface adj is glean");
713 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
714 &adj->sub_type.glean.receive_addr)),
715 "attached interface adj is receive ok");
717 local_pfx.fp_len = 32;
718 fib_table_entry_update_one_path(fib_index, &local_pfx,
719 FIB_SOURCE_INTERFACE,
720 (FIB_ENTRY_FLAG_CONNECTED |
721 FIB_ENTRY_FLAG_LOCAL),
724 tm->hw[0]->sw_if_index,
725 ~0, // invalid fib index
728 FIB_ROUTE_PATH_FLAG_NONE);
729 fei = fib_table_lookup(fib_index, &local_pfx);
730 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
731 fib_entry_get_flags(fei)),
732 "Flags set on local interface");
734 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
736 dpo = fib_entry_contribute_ip_forwarding(fei);
737 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
738 "RPF list for local length 0");
739 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
740 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
741 "local interface adj is local");
742 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
744 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
746 "local interface adj is receive ok");
748 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
750 FIB_SOURCE_INTERFACE)),
751 "2 Interface Source'd prefixes");
754 * +2 interface routes +2 non-shared path-lists
756 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
757 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
758 fib_path_list_pool_size());
759 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
760 fib_entry_pool_size());
763 * Modify the default route to be via an adj not yet known.
764 * this sources the defalut route with the API source, which is
765 * a higher preference to the DEFAULT_ROUTE source
767 pfx.fp_addr.ip4.as_u32 = 0;
769 fib_table_entry_path_add(fib_index, &pfx,
774 tm->hw[0]->sw_if_index,
775 ~0, // invalid fib index
778 FIB_ROUTE_PATH_FLAG_NONE);
779 fei = fib_table_lookup(fib_index, &pfx);
780 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
781 "Flags set on API route");
783 FIB_TEST((fei == dfrt), "default route same index");
784 ai = fib_entry_get_adj(fei);
785 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
787 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
788 "adj is incomplete");
789 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
790 "adj nbr next-hop ok");
791 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
794 "1 API Source'd prefixes");
797 * find the adj in the shared db
799 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
802 tm->hw[0]->sw_if_index);
803 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
804 adj_unlock(locked_ai);
807 * +1 shared path-list
809 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
810 fib_path_list_db_size());
811 FIB_TEST((NBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
812 fib_path_list_pool_size());
813 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
814 fib_entry_pool_size());
817 * remove the API source from the default route. We expected
818 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
820 pfx.fp_addr.ip4.as_u32 = 0;
822 fib_table_entry_path_remove(fib_index, &pfx,
826 tm->hw[0]->sw_if_index,
827 ~0, // non-recursive path, so no FIB index
829 FIB_ROUTE_PATH_FLAG_NONE);
831 fei = fib_table_lookup(fib_index, &pfx);
833 FIB_TEST((fei == dfrt), "default route same index");
834 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
835 "Default route is DROP");
838 * -1 shared-path-list
840 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
841 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
842 fib_path_list_pool_size());
843 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
844 fib_entry_pool_size());
847 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
849 fib_prefix_t pfx_10_10_10_1_s_32 = {
851 .fp_proto = FIB_PROTOCOL_IP4,
854 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
857 fib_prefix_t pfx_10_10_10_2_s_32 = {
859 .fp_proto = FIB_PROTOCOL_IP4,
862 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
865 fib_prefix_t pfx_11_11_11_11_s_32 = {
867 .fp_proto = FIB_PROTOCOL_IP4,
870 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
874 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
877 ip46_address_t nh_12_12_12_12 = {
878 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
880 adj_index_t ai_12_12_12_12;
883 * Add a route via an incomplete ADJ. then complete the ADJ
884 * Expect the route LB is updated to use complete adj type.
886 fei = fib_table_entry_update_one_path(fib_index,
887 &pfx_11_11_11_11_s_32,
889 FIB_ENTRY_FLAG_ATTACHED,
891 &pfx_10_10_10_1_s_32.fp_addr,
892 tm->hw[0]->sw_if_index,
893 ~0, // invalid fib index
896 FIB_ROUTE_PATH_FLAG_NONE);
898 dpo = fib_entry_contribute_ip_forwarding(fei);
899 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
900 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
901 "11.11.11.11/32 via incomplete adj");
903 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
905 &pfx_10_10_10_1_s_32.fp_addr,
906 tm->hw[0]->sw_if_index);
907 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
908 adj = adj_get(ai_01);
909 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
910 "adj is incomplete");
911 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
912 &adj->sub_type.nbr.next_hop)),
913 "adj nbr next-hop ok");
915 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
916 fib_test_build_rewrite(eth_addr));
917 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
919 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
920 &adj->sub_type.nbr.next_hop)),
921 "adj nbr next-hop ok");
922 ai = fib_entry_get_adj(fei);
923 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
925 dpo = fib_entry_contribute_ip_forwarding(fei);
926 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
927 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
928 "11.11.11.11/32 via complete adj");
929 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
930 tm->hw[0]->sw_if_index),
931 "RPF list for adj-fib contains adj");
933 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
936 tm->hw[1]->sw_if_index);
937 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
938 adj = adj_get(ai_12_12_12_12);
939 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
940 "adj is incomplete");
941 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
942 &adj->sub_type.nbr.next_hop)),
943 "adj nbr next-hop ok");
944 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
945 fib_test_build_rewrite(eth_addr));
946 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
952 fei = fib_table_entry_update_one_path(fib_index,
953 &pfx_10_10_10_1_s_32,
955 FIB_ENTRY_FLAG_ATTACHED,
957 &pfx_10_10_10_1_s_32.fp_addr,
958 tm->hw[0]->sw_if_index,
959 ~0, // invalid fib index
962 FIB_ROUTE_PATH_FLAG_NONE);
963 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
964 "Flags set on adj-fib");
965 ai = fib_entry_get_adj(fei);
966 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
968 fib_table_entry_path_remove(fib_index,
969 &pfx_11_11_11_11_s_32,
972 &pfx_10_10_10_1_s_32.fp_addr,
973 tm->hw[0]->sw_if_index,
974 ~0, // invalid fib index
976 FIB_ROUTE_PATH_FLAG_NONE);
980 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
982 &pfx_10_10_10_2_s_32.fp_addr,
983 tm->hw[0]->sw_if_index);
984 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
985 adj = adj_get(ai_02);
986 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
987 "adj is incomplete");
988 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
989 &adj->sub_type.nbr.next_hop)),
990 "adj nbr next-hop ok");
992 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
993 fib_test_build_rewrite(eth_addr));
994 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
996 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
997 &adj->sub_type.nbr.next_hop)),
998 "adj nbr next-hop ok");
999 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1001 fib_table_entry_update_one_path(fib_index,
1002 &pfx_10_10_10_2_s_32,
1004 FIB_ENTRY_FLAG_ATTACHED,
1006 &pfx_10_10_10_2_s_32.fp_addr,
1007 tm->hw[0]->sw_if_index,
1008 ~0, // invalid fib index
1011 FIB_ROUTE_PATH_FLAG_NONE);
1013 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1014 ai = fib_entry_get_adj(fei);
1015 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1018 * +2 adj-fibs, and their non-shared path-lists
1020 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1021 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1022 fib_path_list_pool_size());
1023 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1024 fib_entry_pool_size());
1027 * Add 2 routes via the first ADJ. ensure path-list sharing
1029 fib_prefix_t pfx_1_1_1_1_s_32 = {
1031 .fp_proto = FIB_PROTOCOL_IP4,
1034 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1038 fib_table_entry_path_add(fib_index,
1041 FIB_ENTRY_FLAG_NONE,
1044 tm->hw[0]->sw_if_index,
1045 ~0, // invalid fib index
1048 FIB_ROUTE_PATH_FLAG_NONE);
1049 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1050 ai = fib_entry_get_adj(fei);
1051 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1054 * +1 entry and a shared path-list
1056 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1057 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1058 fib_path_list_pool_size());
1059 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1060 fib_entry_pool_size());
1063 fib_prefix_t pfx_1_1_2_0_s_24 = {
1065 .fp_proto = FIB_PROTOCOL_IP4,
1067 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1071 fib_table_entry_path_add(fib_index,
1074 FIB_ENTRY_FLAG_NONE,
1077 tm->hw[0]->sw_if_index,
1078 ~0, // invalid fib index
1081 FIB_ROUTE_PATH_FLAG_NONE);
1082 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1083 ai = fib_entry_get_adj(fei);
1084 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1089 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1090 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1091 fib_path_list_pool_size());
1092 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1093 fib_entry_pool_size());
1096 * modify 1.1.2.0/24 to use multipath.
1098 fib_table_entry_path_add(fib_index,
1101 FIB_ENTRY_FLAG_NONE,
1104 tm->hw[0]->sw_if_index,
1105 ~0, // invalid fib index
1108 FIB_ROUTE_PATH_FLAG_NONE);
1109 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1110 dpo = fib_entry_contribute_ip_forwarding(fei);
1111 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1112 1, tm->hw[0]->sw_if_index),
1113 "RPF list for 1.1.2.0/24 contains both adjs");
1115 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1116 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1117 FIB_TEST((ai_01 == dpo1->dpoi_index),
1118 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1119 ai_01, dpo1->dpoi_index);
1121 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1122 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1123 FIB_TEST((ai_02 == dpo1->dpoi_index),
1124 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1127 * +1 shared-pathlist
1129 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1130 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1131 fib_path_list_pool_size());
1132 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1133 fib_entry_pool_size());
1138 fib_table_entry_path_remove(fib_index,
1143 tm->hw[0]->sw_if_index,
1146 FIB_ROUTE_PATH_FLAG_NONE);
1147 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1148 dpo = fib_entry_contribute_ip_forwarding(fei);
1149 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1150 1, tm->hw[0]->sw_if_index),
1151 "RPF list for 1.1.2.0/24 contains one adj");
1153 ai = fib_entry_get_adj(fei);
1154 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1157 * +1 shared-pathlist
1159 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1160 fib_path_list_db_size());
1161 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1162 fib_path_list_pool_size());
1163 FIB_TEST((NBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1164 fib_entry_pool_size());
1167 * Add 2 recursive routes:
1168 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1169 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1171 fib_prefix_t bgp_100_pfx = {
1173 .fp_proto = FIB_PROTOCOL_IP4,
1175 /* 100.100.100.100/32 */
1176 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1180 ip46_address_t nh_1_1_1_1 = {
1181 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1184 fei = fib_table_entry_path_add(fib_index,
1187 FIB_ENTRY_FLAG_NONE,
1190 ~0, // no index provided.
1191 fib_index, // nexthop in same fib as route
1194 FIB_ROUTE_PATH_FLAG_NONE);
1196 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1197 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1198 tm->hw[0]->sw_if_index),
1199 "RPF list for adj-fib contains adj");
1202 * +1 entry and +1 shared-path-list
1204 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1205 fib_path_list_db_size());
1206 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1207 fib_path_list_pool_size());
1208 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1209 fib_entry_pool_size());
1211 fib_prefix_t bgp_101_pfx = {
1213 .fp_proto = FIB_PROTOCOL_IP4,
1215 /* 100.100.100.101/32 */
1216 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1220 fib_table_entry_path_add(fib_index,
1223 FIB_ENTRY_FLAG_NONE,
1226 ~0, // no index provided.
1227 fib_index, // nexthop in same fib as route
1230 FIB_ROUTE_PATH_FLAG_NONE);
1232 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1233 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1234 tm->hw[0]->sw_if_index),
1235 "RPF list for adj-fib contains adj");
1238 * +1 entry, but the recursive path-list is shared.
1240 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1241 fib_path_list_db_size());
1242 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1243 fib_path_list_pool_size());
1244 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1245 fib_entry_pool_size());
1248 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1249 * adjacency through which the route will resovle
1251 fib_prefix_t ex_pfx = {
1253 .fp_proto = FIB_PROTOCOL_IP4,
1256 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1260 fib_table_entry_special_add(fib_index,
1263 FIB_ENTRY_FLAG_EXCLUSIVE,
1265 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1266 FIB_TEST((ai == fib_entry_get_adj(fei)),
1267 "Exclusive route links to user adj");
1269 fib_table_entry_special_remove(fib_index,
1271 FIB_SOURCE_SPECIAL);
1272 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1273 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1274 "Exclusive reoute removed");
1277 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1278 * adjacency through which the route will resovle
1280 dpo_id_t ex_dpo = DPO_INVALID;
1282 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1284 LOOKUP_INPUT_DST_ADDR,
1285 LOOKUP_TABLE_FROM_CONFIG,
1288 fib_table_entry_special_dpo_add(fib_index,
1291 FIB_ENTRY_FLAG_EXCLUSIVE,
1293 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1294 dpo = fib_entry_contribute_ip_forwarding(fei);
1295 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1296 "exclusive remote uses lookup DPO");
1299 * update the exclusive to use a different DPO
1301 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1302 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1304 fib_table_entry_special_dpo_update(fib_index,
1307 FIB_ENTRY_FLAG_EXCLUSIVE,
1309 dpo = fib_entry_contribute_ip_forwarding(fei);
1310 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1311 "exclusive remote uses now uses NULL DPO");
1313 fib_table_entry_special_remove(fib_index,
1315 FIB_SOURCE_SPECIAL);
1316 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1317 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1318 "Exclusive reoute removed");
1322 * Add a recursive route:
1323 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1325 fib_prefix_t bgp_200_pfx = {
1327 .fp_proto = FIB_PROTOCOL_IP4,
1329 /* 200.200.200.200/32 */
1330 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1334 fib_prefix_t pfx_1_1_1_2_s_32 = {
1336 .fp_proto = FIB_PROTOCOL_IP4,
1338 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1342 fib_table_entry_path_add(fib_index,
1345 FIB_ENTRY_FLAG_NONE,
1347 &pfx_1_1_1_2_s_32.fp_addr,
1348 ~0, // no index provided.
1349 fib_index, // nexthop in same fib as route
1352 FIB_ROUTE_PATH_FLAG_NONE);
1354 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1357 * the adj should be recursive via drop, since the route resolves via
1358 * the default route, which is itself a DROP
1360 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1361 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1362 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1363 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1364 "RPF list for 1.1.1.2/32 contains 0 adjs");
1367 * +2 entry and +1 shared-path-list
1369 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1370 fib_path_list_db_size());
1371 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1372 fib_path_list_pool_size());
1373 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1374 fib_entry_pool_size());
1377 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1378 * The paths are sort by NH first. in this case the the path with greater
1379 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1381 fib_prefix_t pfx_1_2_3_4_s_32 = {
1383 .fp_proto = FIB_PROTOCOL_IP4,
1385 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1388 fib_table_entry_path_add(fib_index,
1391 FIB_ENTRY_FLAG_NONE,
1394 tm->hw[0]->sw_if_index,
1398 FIB_ROUTE_PATH_FLAG_NONE);
1399 fei = fib_table_entry_path_add(fib_index,
1402 FIB_ENTRY_FLAG_NONE,
1405 tm->hw[1]->sw_if_index,
1409 FIB_ROUTE_PATH_FLAG_NONE);
1411 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1412 dpo = fib_entry_contribute_ip_forwarding(fei);
1413 lb = load_balance_get(dpo->dpoi_index);
1414 FIB_TEST((lb->lb_n_buckets == 4),
1415 "1.2.3.4/32 LB has %d bucket",
1418 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1419 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1420 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1421 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1423 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1424 tm->hw[0]->sw_if_index,
1425 tm->hw[1]->sw_if_index),
1426 "RPF list for 1.2.3.4/32 contains both adjs");
1430 * Unequal Cost load-balance. 4:1 ratio.
1431 * fits in a 16 bucket LB with ratio 13:3
1433 fib_prefix_t pfx_1_2_3_5_s_32 = {
1435 .fp_proto = FIB_PROTOCOL_IP4,
1437 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1440 fib_table_entry_path_add(fib_index,
1443 FIB_ENTRY_FLAG_NONE,
1446 tm->hw[1]->sw_if_index,
1450 FIB_ROUTE_PATH_FLAG_NONE);
1451 fei = fib_table_entry_path_add(fib_index,
1454 FIB_ENTRY_FLAG_NONE,
1457 tm->hw[0]->sw_if_index,
1461 FIB_ROUTE_PATH_FLAG_NONE);
1463 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1464 dpo = fib_entry_contribute_ip_forwarding(fei);
1465 lb = load_balance_get(dpo->dpoi_index);
1466 FIB_TEST((lb->lb_n_buckets == 16),
1467 "1.2.3.5/32 LB has %d bucket",
1470 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1471 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1472 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1473 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1474 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1475 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1476 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1477 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1478 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1479 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1480 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1481 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1482 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1483 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1484 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1485 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1487 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1488 tm->hw[0]->sw_if_index,
1489 tm->hw[1]->sw_if_index),
1490 "RPF list for 1.2.3.4/32 contains both adjs");
1493 * Test UCMP with a large weight skew - this produces load-balance objects with large
1494 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1495 * laso testing the LB in placce modify code when number of buckets is large.
1497 fib_prefix_t pfx_6_6_6_6_s_32 = {
1499 .fp_proto = FIB_PROTOCOL_IP4,
1502 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1505 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_1 = {
1511 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_2 = {
1517 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1520 .adj = ai_12_12_12_12,
1523 fib_table_entry_update_one_path(fib_index,
1526 FIB_ENTRY_FLAG_NONE,
1529 tm->hw[0]->sw_if_index,
1530 ~0, // invalid fib index
1533 FIB_ROUTE_PATH_FLAG_NONE);
1535 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1536 FIB_TEST(fib_test_validate_entry(fei,
1537 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1539 &ip_6_6_6_6_o_10_10_10_1),
1540 "6.6.6.6/32 via 10.10.10.1");
1542 fib_table_entry_path_add(fib_index,
1545 FIB_ENTRY_FLAG_NONE,
1548 tm->hw[0]->sw_if_index,
1549 ~0, // invalid fib index
1552 FIB_ROUTE_PATH_FLAG_NONE);
1554 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1555 FIB_TEST(fib_test_validate_entry(fei,
1556 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1558 &ip_6_6_6_6_o_10_10_10_2,
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_1),
1622 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1624 fib_table_entry_path_add(fib_index,
1627 FIB_ENTRY_FLAG_NONE,
1630 tm->hw[1]->sw_if_index,
1631 ~0, // invalid fib index
1634 FIB_ROUTE_PATH_FLAG_NONE);
1636 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1637 FIB_TEST(fib_test_validate_entry(fei,
1638 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1640 &ip_6_6_6_6_o_10_10_10_1,
1641 &ip_6_6_6_6_o_10_10_10_2,
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_12_12_12_12,
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 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1770 fib_table_entry_path_remove(fib_index,
1775 tm->hw[1]->sw_if_index,
1776 ~0, // invalid fib index
1778 FIB_ROUTE_PATH_FLAG_NONE);
1780 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1781 FIB_TEST(fib_test_validate_entry(fei,
1782 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1784 &ip_6_6_6_6_o_10_10_10_2,
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_1),
1848 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1850 fib_table_entry_path_remove(fib_index,
1855 tm->hw[0]->sw_if_index,
1856 ~0, // invalid fib index
1858 FIB_ROUTE_PATH_FLAG_NONE);
1860 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1861 FIB_TEST(fib_test_validate_entry(fei,
1862 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1864 &ip_6_6_6_6_o_10_10_10_1),
1865 "6.6.6.6/32 via 10.10.10.1");
1867 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
1870 * A recursive via the two unequal cost entries
1872 fib_prefix_t bgp_44_s_32 = {
1874 .fp_proto = FIB_PROTOCOL_IP4,
1876 /* 200.200.200.201/32 */
1877 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1880 fei = fib_table_entry_path_add(fib_index,
1883 FIB_ENTRY_FLAG_NONE,
1885 &pfx_1_2_3_4_s_32.fp_addr,
1890 FIB_ROUTE_PATH_FLAG_NONE);
1891 fei = fib_table_entry_path_add(fib_index,
1894 FIB_ENTRY_FLAG_NONE,
1896 &pfx_1_2_3_5_s_32.fp_addr,
1901 FIB_ROUTE_PATH_FLAG_NONE);
1903 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1904 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1905 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1906 tm->hw[0]->sw_if_index,
1907 tm->hw[1]->sw_if_index),
1908 "RPF list for 1.2.3.4/32 contains both adjs");
1911 * test the uRPF check functions
1913 dpo_id_t dpo_44 = DPO_INVALID;
1916 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1917 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
1919 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
1920 "uRPF check for 68.68.68.68/32 on %d OK",
1921 tm->hw[0]->sw_if_index);
1922 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
1923 "uRPF check for 68.68.68.68/32 on %d OK",
1924 tm->hw[1]->sw_if_index);
1925 FIB_TEST(!fib_urpf_check(urpfi, 99),
1926 "uRPF check for 68.68.68.68/32 on 99 not-OK",
1930 fib_table_entry_delete(fib_index,
1933 fib_table_entry_delete(fib_index,
1936 fib_table_entry_delete(fib_index,
1941 * Add a recursive route:
1942 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
1944 fib_prefix_t bgp_201_pfx = {
1946 .fp_proto = FIB_PROTOCOL_IP4,
1948 /* 200.200.200.201/32 */
1949 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1953 fib_prefix_t pfx_1_1_1_200_s_32 = {
1955 .fp_proto = FIB_PROTOCOL_IP4,
1957 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1961 fib_table_entry_path_add(fib_index,
1964 FIB_ENTRY_FLAG_NONE,
1966 &pfx_1_1_1_200_s_32.fp_addr,
1967 ~0, // no index provided.
1968 fib_index, // nexthop in same fib as route
1971 FIB_ROUTE_PATH_FLAG_NONE);
1973 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1975 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1976 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1977 "Flags set on RR via non-attached");
1978 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1979 "RPF list for BGP route empty");
1982 * +2 entry (BGP & RR) and +1 shared-path-list
1984 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1985 fib_path_list_db_size());
1986 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1987 fib_path_list_pool_size());
1988 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1989 fib_entry_pool_size());
1992 * insert a route that covers the missing 1.1.1.2/32. we epxect
1993 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
1995 fib_prefix_t pfx_1_1_1_0_s_24 = {
1997 .fp_proto = FIB_PROTOCOL_IP4,
2000 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2004 fib_table_entry_path_add(fib_index,
2007 FIB_ENTRY_FLAG_NONE,
2010 tm->hw[0]->sw_if_index,
2011 ~0, // invalid fib index
2014 FIB_ROUTE_PATH_FLAG_NONE);
2015 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2016 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2017 ai = fib_entry_get_adj(fei);
2018 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2019 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2020 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2021 ai = fib_entry_get_adj(fei);
2022 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2023 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2024 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2025 ai = fib_entry_get_adj(fei);
2026 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2029 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2031 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2032 fib_path_list_db_size());
2033 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2034 fib_path_list_pool_size());
2035 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2036 fib_entry_pool_size());
2039 * the recursive adj for 200.200.200.200 should be updated.
2041 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2042 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2043 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2044 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2045 tm->hw[0]->sw_if_index),
2046 "RPF list for BGP route has itf index 0");
2049 * insert a more specific route than 1.1.1.0/24 that also covers the
2050 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2051 * 200.200.200.200 to resolve through it.
2053 fib_prefix_t pfx_1_1_1_0_s_28 = {
2055 .fp_proto = FIB_PROTOCOL_IP4,
2058 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2062 fib_table_entry_path_add(fib_index,
2065 FIB_ENTRY_FLAG_NONE,
2068 tm->hw[0]->sw_if_index,
2069 ~0, // invalid fib index
2072 FIB_ROUTE_PATH_FLAG_NONE);
2073 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2074 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2075 ai = fib_entry_get_adj(fei);
2076 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2079 * +1 entry. +1 shared path-list
2081 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2082 fib_path_list_db_size());
2083 FIB_TEST((NBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2084 fib_path_list_pool_size());
2085 FIB_TEST((NBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2086 fib_entry_pool_size());
2089 * the recursive adj for 200.200.200.200 should be updated.
2090 * 200.200.200.201 remains unchanged.
2092 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2093 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2096 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2098 fib_table_entry_path_remove(fib_index,
2103 tm->hw[0]->sw_if_index,
2106 FIB_ROUTE_PATH_FLAG_NONE);
2107 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2108 FIB_NODE_INDEX_INVALID),
2109 "1.1.1.0/28 removed");
2110 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2111 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2112 "1.1.1.0/28 lookup via /24");
2113 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2114 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2117 * -1 entry. -1 shared path-list
2119 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2120 fib_path_list_db_size());
2121 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2122 fib_path_list_pool_size());
2123 FIB_TEST((NBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2124 fib_entry_pool_size());
2127 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2129 fib_table_entry_path_remove(fib_index,
2134 tm->hw[0]->sw_if_index,
2137 FIB_ROUTE_PATH_FLAG_NONE);
2138 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2139 FIB_NODE_INDEX_INVALID),
2140 "1.1.1.0/24 removed");
2142 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2143 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2144 "1.1.1.2/32 route is DROP");
2145 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2146 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2147 "1.1.1.200/32 route is DROP");
2149 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2150 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2155 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2156 fib_path_list_db_size());
2157 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2158 fib_path_list_pool_size());
2159 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2160 fib_entry_pool_size());
2163 * insert the missing 1.1.1.2/32
2165 fei = fib_table_entry_path_add(fib_index,
2168 FIB_ENTRY_FLAG_NONE,
2171 tm->hw[0]->sw_if_index,
2172 ~0, // invalid fib index
2175 FIB_ROUTE_PATH_FLAG_NONE);
2176 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2177 ai = fib_entry_get_adj(fei);
2178 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2180 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2181 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2184 * no change. 1.1.1.2/32 was already there RR sourced.
2186 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2187 fib_path_list_db_size());
2188 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2189 fib_path_list_pool_size());
2190 FIB_TEST((NBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2191 fib_entry_pool_size());
2194 * remove 200.200.200.201/32 which does not have a valid via FIB
2196 fib_table_entry_path_remove(fib_index,
2200 &pfx_1_1_1_200_s_32.fp_addr,
2201 ~0, // no index provided.
2204 FIB_ROUTE_PATH_FLAG_NONE);
2207 * -2 entries (BGP and RR). -1 shared path-list;
2209 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2210 FIB_NODE_INDEX_INVALID),
2211 "200.200.200.201/32 removed");
2212 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2213 FIB_NODE_INDEX_INVALID),
2214 "1.1.1.200/32 removed");
2216 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2217 fib_path_list_db_size());
2218 FIB_TEST((NBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2219 fib_path_list_pool_size());
2220 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2221 fib_entry_pool_size());
2224 * remove 200.200.200.200/32 which does have a valid via FIB
2226 fib_table_entry_path_remove(fib_index,
2230 &pfx_1_1_1_2_s_32.fp_addr,
2231 ~0, // no index provided.
2234 FIB_ROUTE_PATH_FLAG_NONE);
2236 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2237 FIB_NODE_INDEX_INVALID),
2238 "200.200.200.200/32 removed");
2239 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2240 FIB_NODE_INDEX_INVALID),
2241 "1.1.1.2/32 still present");
2244 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2246 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2247 fib_path_list_db_size());
2248 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2249 fib_path_list_pool_size());
2250 FIB_TEST((NBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2251 fib_entry_pool_size());
2254 * A recursive prefix that has a 2 path load-balance.
2255 * It also shares a next-hop with other BGP prefixes and hence
2256 * test the ref counting of RR sourced prefixes and 2 level LB.
2258 const fib_prefix_t bgp_102 = {
2260 .fp_proto = FIB_PROTOCOL_IP4,
2262 /* 100.100.100.101/32 */
2263 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2266 fib_table_entry_path_add(fib_index,
2269 FIB_ENTRY_FLAG_NONE,
2271 &pfx_1_1_1_1_s_32.fp_addr,
2272 ~0, // no index provided.
2273 fib_index, // same as route
2276 FIB_ROUTE_PATH_FLAG_NONE);
2277 fib_table_entry_path_add(fib_index,
2280 FIB_ENTRY_FLAG_NONE,
2282 &pfx_1_1_1_2_s_32.fp_addr,
2283 ~0, // no index provided.
2284 fib_index, // same as route's FIB
2287 FIB_ROUTE_PATH_FLAG_NONE);
2288 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2289 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2290 dpo = fib_entry_contribute_ip_forwarding(fei);
2292 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2293 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2294 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2295 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2297 lb = load_balance_get(dpo->dpoi_index);
2298 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2299 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2300 "First via 10.10.10.1");
2301 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2302 "Second via 10.10.10.1");
2304 fib_table_entry_path_remove(fib_index,
2308 &pfx_1_1_1_1_s_32.fp_addr,
2309 ~0, // no index provided.
2310 fib_index, // same as route's FIB
2312 FIB_ROUTE_PATH_FLAG_NONE);
2313 fib_table_entry_path_remove(fib_index,
2317 &pfx_1_1_1_2_s_32.fp_addr,
2318 ~0, // no index provided.
2319 fib_index, // same as route's FIB
2321 FIB_ROUTE_PATH_FLAG_NONE);
2322 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2323 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2326 * remove the remaining recursives
2328 fib_table_entry_path_remove(fib_index,
2332 &pfx_1_1_1_1_s_32.fp_addr,
2333 ~0, // no index provided.
2334 fib_index, // same as route's FIB
2336 FIB_ROUTE_PATH_FLAG_NONE);
2337 fib_table_entry_path_remove(fib_index,
2341 &pfx_1_1_1_1_s_32.fp_addr,
2342 ~0, // no index provided.
2343 fib_index, // same as route's FIB
2345 FIB_ROUTE_PATH_FLAG_NONE);
2346 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2347 FIB_NODE_INDEX_INVALID),
2348 "100.100.100.100/32 removed");
2349 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2350 FIB_NODE_INDEX_INVALID),
2351 "100.100.100.101/32 removed");
2354 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2356 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2357 fib_path_list_db_size());
2358 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2359 fib_path_list_pool_size());
2360 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2361 fib_entry_pool_size());
2364 * Add a recursive route via a connected cover, using an adj-fib that does exist
2366 fib_table_entry_path_add(fib_index,
2369 FIB_ENTRY_FLAG_NONE,
2372 ~0, // no index provided.
2373 fib_index, // Same as route's FIB
2376 FIB_ROUTE_PATH_FLAG_NONE);
2379 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2381 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2382 fib_path_list_db_size());
2383 FIB_TEST((NBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2384 fib_path_list_pool_size());
2385 FIB_TEST((NBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2386 fib_entry_pool_size());
2388 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2389 dpo = fib_entry_contribute_ip_forwarding(fei);
2391 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2392 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2394 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2395 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2397 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2398 "Flags set on RR via existing attached");
2401 * Add a recursive route via a connected cover, using and adj-fib that does
2404 ip46_address_t nh_10_10_10_3 = {
2405 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2407 fib_prefix_t pfx_10_10_10_3 = {
2409 .fp_proto = FIB_PROTOCOL_IP4,
2410 .fp_addr = nh_10_10_10_3,
2413 fib_table_entry_path_add(fib_index,
2416 FIB_ENTRY_FLAG_NONE,
2419 ~0, // no index provided.
2423 FIB_ROUTE_PATH_FLAG_NONE);
2426 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2427 * one unshared non-recursive via 10.10.10.3
2429 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2430 fib_path_list_db_size());
2431 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2432 fib_path_list_pool_size());
2433 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2434 fib_entry_pool_size());
2436 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2439 tm->hw[0]->sw_if_index);
2441 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2442 dpo = fib_entry_contribute_ip_forwarding(fei);
2443 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2444 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2446 ai = fib_entry_get_adj(fei);
2447 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2448 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2449 fib_entry_get_flags(fei)),
2450 "Flags set on RR via non-existing attached");
2452 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2453 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2458 * remove the recursives
2460 fib_table_entry_path_remove(fib_index,
2465 ~0, // no index provided.
2466 fib_index, // same as route's FIB
2468 FIB_ROUTE_PATH_FLAG_NONE);
2469 fib_table_entry_path_remove(fib_index,
2474 ~0, // no index provided.
2475 fib_index, // same as route's FIB
2477 FIB_ROUTE_PATH_FLAG_NONE);
2479 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2480 FIB_NODE_INDEX_INVALID),
2481 "200.200.200.201/32 removed");
2482 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2483 FIB_NODE_INDEX_INVALID),
2484 "200.200.200.200/32 removed");
2485 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2486 FIB_NODE_INDEX_INVALID),
2487 "10.10.10.3/32 removed");
2490 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2491 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2493 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2494 fib_path_list_db_size());
2495 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2496 fib_path_list_pool_size());
2497 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2498 fib_entry_pool_size());
2503 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2505 fib_prefix_t pfx_5_5_5_5_s_32 = {
2507 .fp_proto = FIB_PROTOCOL_IP4,
2509 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2512 fib_prefix_t pfx_5_5_5_6_s_32 = {
2514 .fp_proto = FIB_PROTOCOL_IP4,
2516 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2519 fib_prefix_t pfx_5_5_5_7_s_32 = {
2521 .fp_proto = FIB_PROTOCOL_IP4,
2523 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2527 fib_table_entry_path_add(fib_index,
2530 FIB_ENTRY_FLAG_NONE,
2532 &pfx_5_5_5_6_s_32.fp_addr,
2533 ~0, // no index provided.
2537 FIB_ROUTE_PATH_FLAG_NONE);
2538 fib_table_entry_path_add(fib_index,
2541 FIB_ENTRY_FLAG_NONE,
2543 &pfx_5_5_5_7_s_32.fp_addr,
2544 ~0, // no index provided.
2548 FIB_ROUTE_PATH_FLAG_NONE);
2549 fib_table_entry_path_add(fib_index,
2552 FIB_ENTRY_FLAG_NONE,
2554 &pfx_5_5_5_5_s_32.fp_addr,
2555 ~0, // no index provided.
2559 FIB_ROUTE_PATH_FLAG_NONE);
2561 * +3 entries, +3 shared path-list
2563 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2564 fib_path_list_db_size());
2565 FIB_TEST((NBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2566 fib_path_list_pool_size());
2567 FIB_TEST((NBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2568 fib_entry_pool_size());
2571 * All the entries have only looped paths, so they are all drop
2573 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2574 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2575 "LB for 5.5.5.7/32 is via adj for DROP");
2576 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2577 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2578 "LB for 5.5.5.5/32 is via adj for DROP");
2579 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2580 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2581 "LB for 5.5.5.6/32 is via adj for DROP");
2584 * provide 5.5.5.6/32 with alternate path.
2585 * this will allow only 5.5.5.6/32 to forward with this path, the others
2586 * are still drop since the loop is still present.
2588 fib_table_entry_path_add(fib_index,
2591 FIB_ENTRY_FLAG_NONE,
2594 tm->hw[0]->sw_if_index,
2598 FIB_ROUTE_PATH_FLAG_NONE);
2601 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2602 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2604 lb = load_balance_get(dpo1->dpoi_index);
2605 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2607 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2608 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2609 FIB_TEST((ai_01 == dpo2->dpoi_index),
2610 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2612 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2613 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2614 "LB for 5.5.5.7/32 is via adj for DROP");
2615 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2616 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2617 "LB for 5.5.5.5/32 is via adj for DROP");
2620 * remove the alternate path for 5.5.5.6/32
2623 fib_table_entry_path_remove(fib_index,
2628 tm->hw[0]->sw_if_index,
2631 FIB_ROUTE_PATH_FLAG_NONE);
2633 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2634 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2635 "LB for 5.5.5.7/32 is via adj for DROP");
2636 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2637 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2638 "LB for 5.5.5.5/32 is via adj for DROP");
2639 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2640 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2641 "LB for 5.5.5.6/32 is via adj for DROP");
2644 * break the loop by giving 5.5.5.5/32 a new set of paths
2645 * expect all to forward via this new path.
2647 fib_table_entry_update_one_path(fib_index,
2650 FIB_ENTRY_FLAG_NONE,
2653 tm->hw[0]->sw_if_index,
2654 ~0, // invalid fib index
2657 FIB_ROUTE_PATH_FLAG_NONE);
2659 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2660 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2661 lb = load_balance_get(dpo1->dpoi_index);
2662 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2664 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2665 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2666 FIB_TEST((ai_01 == dpo2->dpoi_index),
2667 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2669 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2670 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2672 lb = load_balance_get(dpo2->dpoi_index);
2673 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2674 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2675 "5.5.5.5.7 via 5.5.5.5");
2677 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2678 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2680 lb = load_balance_get(dpo1->dpoi_index);
2681 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2682 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2683 "5.5.5.5.6 via 5.5.5.7");
2686 * revert back to the loop. so we can remove the prefixes with
2689 fib_table_entry_update_one_path(fib_index,
2692 FIB_ENTRY_FLAG_NONE,
2694 &pfx_5_5_5_6_s_32.fp_addr,
2695 ~0, // no index provided.
2699 FIB_ROUTE_PATH_FLAG_NONE);
2701 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2702 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2703 "LB for 5.5.5.7/32 is via adj for DROP");
2704 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2705 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2706 "LB for 5.5.5.5/32 is via adj for DROP");
2707 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2708 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2709 "LB for 5.5.5.6/32 is via adj for DROP");
2712 * remove all the 5.5.5.x/32 prefixes
2714 fib_table_entry_path_remove(fib_index,
2718 &pfx_5_5_5_6_s_32.fp_addr,
2719 ~0, // no index provided.
2720 fib_index, // same as route's FIB
2722 FIB_ROUTE_PATH_FLAG_NONE);
2723 fib_table_entry_path_remove(fib_index,
2727 &pfx_5_5_5_7_s_32.fp_addr,
2728 ~0, // no index provided.
2729 fib_index, // same as route's FIB
2731 FIB_ROUTE_PATH_FLAG_NONE);
2732 fib_table_entry_path_remove(fib_index,
2736 &pfx_5_5_5_5_s_32.fp_addr,
2737 ~0, // no index provided.
2738 fib_index, // same as route's FIB
2740 FIB_ROUTE_PATH_FLAG_NONE);
2741 fib_table_entry_path_remove(fib_index,
2746 ~0, // no index provided.
2747 fib_index, // same as route's FIB
2749 FIB_ROUTE_PATH_FLAG_NONE);
2752 * -3 entries, -3 shared path-list
2754 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2755 fib_path_list_db_size());
2756 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2757 fib_path_list_pool_size());
2758 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2759 fib_entry_pool_size());
2762 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2764 fib_table_entry_path_add(fib_index,
2767 FIB_ENTRY_FLAG_NONE,
2769 &pfx_5_5_5_6_s_32.fp_addr,
2770 ~0, // no index provided.
2774 FIB_ROUTE_PATH_FLAG_NONE);
2775 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2776 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2777 "1-level 5.5.5.6/32 loop is via adj for DROP");
2779 fib_table_entry_path_remove(fib_index,
2783 &pfx_5_5_5_6_s_32.fp_addr,
2784 ~0, // no index provided.
2785 fib_index, // same as route's FIB
2787 FIB_ROUTE_PATH_FLAG_NONE);
2788 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2789 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2790 "1-level 5.5.5.6/32 loop is removed");
2793 * A recursive route whose next-hop is covered by the prefix.
2794 * This would mean the via-fib, which inherits forwarding from its
2795 * cover, thus picks up forwarding from the prfix, which is via the
2796 * via-fib, and we have a loop.
2798 fib_prefix_t pfx_23_23_23_0_s_24 = {
2800 .fp_proto = FIB_PROTOCOL_IP4,
2802 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2805 fib_prefix_t pfx_23_23_23_23_s_32 = {
2807 .fp_proto = FIB_PROTOCOL_IP4,
2809 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2812 fei = fib_table_entry_path_add(fib_index,
2813 &pfx_23_23_23_0_s_24,
2815 FIB_ENTRY_FLAG_NONE,
2817 &pfx_23_23_23_23_s_32.fp_addr,
2822 FIB_ROUTE_PATH_FLAG_NONE);
2823 dpo = fib_entry_contribute_ip_forwarding(fei);
2824 FIB_TEST(load_balance_is_drop(dpo),
2825 "23.23.23.0/24 via covered is DROP");
2826 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2829 * add-remove test. no change.
2831 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2832 fib_path_list_db_size());
2833 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2834 fib_path_list_pool_size());
2835 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2836 fib_entry_pool_size());
2839 * A recursive route with recursion constraints.
2840 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2842 fib_table_entry_path_add(fib_index,
2845 FIB_ENTRY_FLAG_NONE,
2852 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2854 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2855 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2857 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2858 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2860 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2861 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2864 * save the load-balance. we expect it to be inplace modified
2866 lb = load_balance_get(dpo1->dpoi_index);
2869 * add a covering prefix for the via fib that would otherwise serve
2870 * as the resolving route when the host is removed
2872 fib_table_entry_path_add(fib_index,
2875 FIB_ENTRY_FLAG_NONE,
2878 tm->hw[0]->sw_if_index,
2879 ~0, // invalid fib index
2882 FIB_ROUTE_PATH_FLAG_NONE);
2883 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
2884 ai = fib_entry_get_adj(fei);
2885 FIB_TEST((ai == ai_01),
2886 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
2889 * remove the host via FIB - expect the BGP prefix to be drop
2891 fib_table_entry_path_remove(fib_index,
2896 tm->hw[0]->sw_if_index,
2897 ~0, // invalid fib index
2899 FIB_ROUTE_PATH_FLAG_NONE);
2901 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2902 "adj for 200.200.200.200/32 is recursive via adj for DROP");
2905 * add the via-entry host reoute back. expect to resolve again
2907 fib_table_entry_path_add(fib_index,
2910 FIB_ENTRY_FLAG_NONE,
2913 tm->hw[0]->sw_if_index,
2914 ~0, // invalid fib index
2917 FIB_ROUTE_PATH_FLAG_NONE);
2918 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2919 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2922 * add another path for the recursive. it will then have 2.
2924 fib_prefix_t pfx_1_1_1_3_s_32 = {
2926 .fp_proto = FIB_PROTOCOL_IP4,
2928 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
2931 fib_table_entry_path_add(fib_index,
2934 FIB_ENTRY_FLAG_NONE,
2937 tm->hw[0]->sw_if_index,
2938 ~0, // invalid fib index
2941 FIB_ROUTE_PATH_FLAG_NONE);
2943 fib_table_entry_path_add(fib_index,
2946 FIB_ENTRY_FLAG_NONE,
2948 &pfx_1_1_1_3_s_32.fp_addr,
2953 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2955 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2956 dpo = fib_entry_contribute_ip_forwarding(fei);
2958 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2959 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2960 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2961 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2962 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2963 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2964 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2965 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2968 * expect the lb-map used by the recursive's load-balance is using both buckets
2970 load_balance_map_t *lbm;
2973 lb = load_balance_get(dpo->dpoi_index);
2975 load_balance_map_lock(lbmi);
2976 lbm = load_balance_map_get(lbmi);
2978 FIB_TEST(lbm->lbm_buckets[0] == 0,
2979 "LB maps's bucket 0 is %d",
2980 lbm->lbm_buckets[0]);
2981 FIB_TEST(lbm->lbm_buckets[1] == 1,
2982 "LB maps's bucket 1 is %d",
2983 lbm->lbm_buckets[1]);
2986 * withdraw one of the /32 via-entrys.
2987 * that ECMP path will be unresolved and forwarding should continue on the
2988 * other available path. this is an iBGP PIC edge failover.
2989 * Test the forwarding changes without re-fetching the adj from the
2990 * recursive entry. this ensures its the same one that is updated; i.e. an
2993 fib_table_entry_path_remove(fib_index,
2998 tm->hw[0]->sw_if_index,
2999 ~0, // invalid fib index
3001 FIB_ROUTE_PATH_FLAG_NONE);
3003 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3004 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3005 "post PIC 200.200.200.200/32 was inplace modified");
3007 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3008 "post PIC adj for 200.200.200.200/32 is recursive"
3009 " via adj for 1.1.1.3");
3012 * the LB maps that was locked above should have been modified to remove
3013 * the path that was down, and thus its bucket points to a path that is
3016 FIB_TEST(lbm->lbm_buckets[0] == 1,
3017 "LB maps's bucket 0 is %d",
3018 lbm->lbm_buckets[0]);
3019 FIB_TEST(lbm->lbm_buckets[1] == 1,
3020 "LB maps's bucket 1 is %d",
3021 lbm->lbm_buckets[1]);
3023 load_balance_map_unlock(lb->lb_map);
3026 * add it back. again
3028 fib_table_entry_path_add(fib_index,
3031 FIB_ENTRY_FLAG_NONE,
3034 tm->hw[0]->sw_if_index,
3035 ~0, // invalid fib index
3038 FIB_ROUTE_PATH_FLAG_NONE);
3040 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3041 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3042 "via adj for 1.1.1.1");
3043 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3044 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3045 "via adj for 1.1.1.3");
3047 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3048 dpo = fib_entry_contribute_ip_forwarding(fei);
3049 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3050 "post PIC 200.200.200.200/32 was inplace modified");
3053 * add a 3rd path. this makes the LB 16 buckets.
3055 fib_table_entry_path_add(fib_index,
3058 FIB_ENTRY_FLAG_NONE,
3060 &pfx_1_1_1_2_s_32.fp_addr,
3065 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3067 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3068 dpo = fib_entry_contribute_ip_forwarding(fei);
3069 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3070 "200.200.200.200/32 was inplace modified for 3rd path");
3071 FIB_TEST(16 == lb->lb_n_buckets,
3072 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3075 load_balance_map_lock(lbmi);
3076 lbm = load_balance_map_get(lbmi);
3078 for (ii = 0; ii < 16; ii++)
3080 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3081 "LB Map for 200.200.200.200/32 at %d is %d",
3082 ii, lbm->lbm_buckets[ii]);
3086 * trigger PIC by removing the first via-entry
3087 * the first 6 buckets of the map should map to the next 6
3089 fib_table_entry_path_remove(fib_index,
3094 tm->hw[0]->sw_if_index,
3097 FIB_ROUTE_PATH_FLAG_NONE);
3099 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3100 dpo = fib_entry_contribute_ip_forwarding(fei);
3101 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3102 "200.200.200.200/32 was inplace modified for 3rd path");
3103 FIB_TEST(2 == lb->lb_n_buckets,
3104 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3106 for (ii = 0; ii < 6; ii++)
3108 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3109 "LB Map for 200.200.200.200/32 at %d is %d",
3110 ii, lbm->lbm_buckets[ii]);
3112 for (ii = 6; ii < 16; ii++)
3114 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3115 "LB Map for 200.200.200.200/32 at %d is %d",
3116 ii, lbm->lbm_buckets[ii]);
3123 fib_table_entry_path_add(fib_index,
3126 FIB_ENTRY_FLAG_NONE,
3129 tm->hw[0]->sw_if_index,
3133 FIB_ROUTE_PATH_FLAG_NONE);
3135 fib_table_entry_path_remove(fib_index,
3139 &pfx_1_1_1_2_s_32.fp_addr,
3143 MPLS_LABEL_INVALID);
3144 fib_table_entry_path_remove(fib_index,
3152 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3153 fib_table_entry_path_remove(fib_index,
3157 &pfx_1_1_1_3_s_32.fp_addr,
3161 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3162 fib_table_entry_delete(fib_index,
3165 fib_table_entry_delete(fib_index,
3168 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3169 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3170 "1.1.1.1/28 removed");
3171 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3172 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3173 "1.1.1.3/32 removed");
3174 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3175 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3176 "200.200.200.200/32 removed");
3179 * add-remove test. no change.
3181 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3182 fib_path_list_db_size());
3183 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3184 fib_path_list_pool_size());
3185 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3186 fib_entry_pool_size());
3189 * A route whose paths are built up iteratively and then removed
3192 fib_prefix_t pfx_4_4_4_4_s_32 = {
3194 .fp_proto = FIB_PROTOCOL_IP4,
3197 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3201 fib_table_entry_path_add(fib_index,
3204 FIB_ENTRY_FLAG_NONE,
3207 tm->hw[0]->sw_if_index,
3211 FIB_ROUTE_PATH_FLAG_NONE);
3212 fib_table_entry_path_add(fib_index,
3215 FIB_ENTRY_FLAG_NONE,
3218 tm->hw[0]->sw_if_index,
3222 FIB_ROUTE_PATH_FLAG_NONE);
3223 fib_table_entry_path_add(fib_index,
3226 FIB_ENTRY_FLAG_NONE,
3229 tm->hw[0]->sw_if_index,
3233 FIB_ROUTE_PATH_FLAG_NONE);
3234 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3235 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3236 "4.4.4.4/32 present");
3238 fib_table_entry_delete(fib_index,
3241 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3242 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3243 "4.4.4.4/32 removed");
3246 * add-remove test. no change.
3248 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3249 fib_path_list_db_size());
3250 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3251 fib_path_list_pool_size());
3252 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3253 fib_entry_pool_size());
3256 * A route with multiple paths at once
3258 fib_route_path_t *r_paths = NULL;
3260 for (ii = 0; ii < 4; ii++)
3262 fib_route_path_t r_path = {
3263 .frp_proto = FIB_PROTOCOL_IP4,
3265 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3267 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3269 .frp_fib_index = ~0,
3271 vec_add1(r_paths, r_path);
3274 fib_table_entry_update(fib_index,
3277 FIB_ENTRY_FLAG_NONE,
3280 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3281 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3282 dpo = fib_entry_contribute_ip_forwarding(fei);
3284 lb = load_balance_get(dpo->dpoi_index);
3285 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3287 fib_table_entry_delete(fib_index,
3290 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3291 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3292 "4.4.4.4/32 removed");
3296 * add-remove test. no change.
3298 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3299 fib_path_list_db_size());
3300 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3301 fib_path_list_pool_size());
3302 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3303 fib_entry_pool_size());
3306 * A route deag route
3308 fib_table_entry_path_add(fib_index,
3311 FIB_ENTRY_FLAG_NONE,
3318 FIB_ROUTE_PATH_FLAG_NONE);
3320 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3321 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3323 dpo = fib_entry_contribute_ip_forwarding(fei);
3324 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3325 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3327 FIB_TEST((fib_index == lkd->lkd_fib_index),
3328 "4.4.4.4/32 is deag in %d %U",
3330 format_dpo_id, dpo, 0);
3332 fib_table_entry_delete(fib_index,
3335 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3336 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3337 "4.4.4.4/32 removed");
3341 * add-remove test. no change.
3343 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3344 fib_path_list_db_size());
3345 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3346 fib_path_list_pool_size());
3347 FIB_TEST((NBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3348 fib_entry_pool_size());
3352 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3354 fib_prefix_t pfx_34_1_1_1_s_32 = {
3356 .fp_proto = FIB_PROTOCOL_IP4,
3358 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3361 fib_prefix_t pfx_34_34_1_1_s_32 = {
3363 .fp_proto = FIB_PROTOCOL_IP4,
3365 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3368 fei = fib_table_entry_path_add(fib_index,
3371 FIB_ENTRY_FLAG_NONE,
3373 &pfx_34_34_1_1_s_32.fp_addr,
3378 FIB_ROUTE_PATH_FLAG_NONE);
3379 fei = fib_table_entry_path_add(fib_index,
3382 FIB_ENTRY_FLAG_NONE,
3384 &pfx_34_34_1_1_s_32.fp_addr,
3389 FIB_ROUTE_PATH_FLAG_NONE);
3390 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3391 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3395 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3396 * all of which are via 10.10.10.1, Itf1
3398 fib_table_entry_path_remove(fib_index,
3403 tm->hw[0]->sw_if_index,
3406 FIB_ROUTE_PATH_FLAG_NONE);
3407 fib_table_entry_path_remove(fib_index,
3412 tm->hw[0]->sw_if_index,
3415 FIB_ROUTE_PATH_FLAG_NONE);
3416 fib_table_entry_path_remove(fib_index,
3421 tm->hw[0]->sw_if_index,
3424 FIB_ROUTE_PATH_FLAG_NONE);
3426 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3427 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3428 "1.1.1.1/32 removed");
3429 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3430 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3431 "1.1.1.2/32 removed");
3432 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3433 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3434 "1.1.2.0/24 removed");
3437 * -3 entries and -1 shared path-list
3439 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3440 fib_path_list_db_size());
3441 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3442 fib_path_list_pool_size());
3443 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3444 fib_entry_pool_size());
3447 * An attached-host route. Expect to link to the incomplete adj
3449 fib_prefix_t pfx_4_1_1_1_s_32 = {
3451 .fp_proto = FIB_PROTOCOL_IP4,
3454 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3457 fib_table_entry_path_add(fib_index,
3460 FIB_ENTRY_FLAG_NONE,
3463 tm->hw[0]->sw_if_index,
3467 FIB_ROUTE_PATH_FLAG_NONE);
3469 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3470 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3471 ai = fib_entry_get_adj(fei);
3473 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3475 &pfx_4_1_1_1_s_32.fp_addr,
3476 tm->hw[0]->sw_if_index);
3477 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3481 * +1 entry and +1 shared path-list
3483 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3484 fib_path_list_db_size());
3485 FIB_TEST((NBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3486 fib_path_list_pool_size());
3487 FIB_TEST((NBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3488 fib_entry_pool_size());
3490 fib_table_entry_delete(fib_index,
3494 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3495 fib_path_list_db_size());
3496 FIB_TEST((NBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3497 fib_path_list_pool_size());
3498 FIB_TEST((NBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3499 fib_entry_pool_size());
3502 * add a v6 prefix via v4 next-hops
3504 fib_prefix_t pfx_2001_s_64 = {
3506 .fp_proto = FIB_PROTOCOL_IP6,
3508 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3511 fei = fib_table_entry_path_add(0, //default v6 table
3514 FIB_ENTRY_FLAG_NONE,
3517 tm->hw[0]->sw_if_index,
3521 FIB_ROUTE_PATH_FLAG_NONE);
3523 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3524 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3525 ai = fib_entry_get_adj(fei);
3527 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3528 "2001::/64 via ARP-adj");
3529 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3530 "2001::/64 is link type v6");
3531 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3532 "2001::/64 ADJ-adj is NH proto v4");
3533 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3536 * add a uRPF exempt prefix:
3538 * - it's forwarding is drop
3539 * - it's uRPF list is not empty
3540 * - the uRPF list for the default route (it's cover) is empty
3542 fei = fib_table_entry_special_add(fib_index,
3544 FIB_SOURCE_URPF_EXEMPT,
3545 FIB_ENTRY_FLAG_DROP,
3547 dpo = fib_entry_contribute_ip_forwarding(fei);
3548 FIB_TEST(load_balance_is_drop(dpo),
3549 "uRPF exempt 4.1.1.1/32 DROP");
3550 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3551 "uRPF list for exempt prefix has itf index 0");
3552 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3553 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3554 "uRPF list for 0.0.0.0/0 empty");
3556 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3562 fib_table_entry_delete(fib_index,
3563 &pfx_10_10_10_1_s_32,
3565 fib_table_entry_delete(fib_index,
3566 &pfx_10_10_10_2_s_32,
3568 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3569 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
3570 "10.10.10.1/32 adj-fib removed");
3571 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3572 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
3573 "10.10.10.2/32 adj-fib removed");
3576 * -2 entries and -2 non-shared path-list
3578 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3579 fib_path_list_db_size());
3580 FIB_TEST((NBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
3581 fib_path_list_pool_size());
3582 FIB_TEST((NBR+2 == fib_entry_pool_size()), "entry pool size is %d",
3583 fib_entry_pool_size());
3586 * unlock the adjacencies for which this test provided a rewrite.
3587 * These are the last locks on these adjs. they should thus go away.
3591 adj_unlock(ai_12_12_12_12);
3593 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3598 * remove the interface prefixes
3600 local_pfx.fp_len = 32;
3601 fib_table_entry_special_remove(fib_index, &local_pfx,
3602 FIB_SOURCE_INTERFACE);
3603 fei = fib_table_lookup(fib_index, &local_pfx);
3605 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3606 fib_table_lookup_exact_match(fib_index, &local_pfx),
3607 "10.10.10.10/32 adj-fib removed");
3609 local_pfx.fp_len = 24;
3610 fib_table_entry_delete(fib_index, &local_pfx,
3611 FIB_SOURCE_INTERFACE);
3613 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3614 fib_table_lookup_exact_match(fib_index, &local_pfx),
3615 "10.10.10.10/24 adj-fib removed");
3618 * -2 entries and -2 non-shared path-list
3620 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3621 fib_path_list_db_size());
3622 FIB_TEST((NBR == fib_path_list_pool_size()), "path list pool size is %d",
3623 fib_path_list_pool_size());
3624 FIB_TEST((NBR == fib_entry_pool_size()), "entry pool size is %d",
3625 fib_entry_pool_size());
3628 * Last but not least, remove the VRF
3630 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3633 "NO API Source'd prefixes");
3634 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3637 "NO RR Source'd prefixes");
3638 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3640 FIB_SOURCE_INTERFACE)),
3641 "NO INterface Source'd prefixes");
3643 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
3645 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3646 fib_path_list_db_size());
3647 FIB_TEST((NBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
3648 fib_path_list_pool_size());
3649 FIB_TEST((NBR-5 == fib_entry_pool_size()), "entry pool size is %d",
3650 fib_entry_pool_size());
3651 FIB_TEST((NBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
3652 pool_elts(fib_urpf_list_pool));
3661 * In the default table check for the presence and correct forwarding
3662 * of the special entries
3664 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
3665 const dpo_id_t *dpo, *dpo_drop;
3666 const ip_adjacency_t *adj;
3667 const receive_dpo_t *rd;
3672 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3675 /* via 2001:0:0:1::2 */
3676 ip46_address_t nh_2001_2 = {
3679 [0] = clib_host_to_net_u64(0x2001000000000001),
3680 [1] = clib_host_to_net_u64(0x0000000000000002),
3687 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
3689 /* Find or create FIB table 11 */
3690 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
3692 for (ii = 0; ii < 4; ii++)
3694 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
3697 fib_prefix_t pfx_0_0 = {
3699 .fp_proto = FIB_PROTOCOL_IP6,
3707 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
3708 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
3709 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3710 "Default route is DROP");
3712 dpo = fib_entry_contribute_ip_forwarding(dfrt);
3713 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3716 &pfx_0_0.fp_addr.ip6)),
3717 "default-route; fwd and non-fwd tables match");
3719 // FIXME - check specials.
3722 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
3723 * each with 6 entries. All entries are special so no path-list sharing.
3726 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3727 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is %d",
3728 fib_path_list_pool_size());
3729 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
3730 fib_entry_pool_size());
3733 * add interface routes.
3734 * validate presence of /64 attached and /128 recieve.
3735 * test for the presence of the receive address in the glean and local adj
3737 * receive on 2001:0:0:1::1/128
3739 fib_prefix_t local_pfx = {
3741 .fp_proto = FIB_PROTOCOL_IP6,
3745 [0] = clib_host_to_net_u64(0x2001000000000001),
3746 [1] = clib_host_to_net_u64(0x0000000000000001),
3752 fib_table_entry_update_one_path(fib_index, &local_pfx,
3753 FIB_SOURCE_INTERFACE,
3754 (FIB_ENTRY_FLAG_CONNECTED |
3755 FIB_ENTRY_FLAG_ATTACHED),
3758 tm->hw[0]->sw_if_index,
3762 FIB_ROUTE_PATH_FLAG_NONE);
3763 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3765 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3767 ai = fib_entry_get_adj(fei);
3768 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
3770 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3771 "attached interface adj is glean");
3772 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3773 &adj->sub_type.glean.receive_addr)),
3774 "attached interface adj is receive ok");
3775 dpo = fib_entry_contribute_ip_forwarding(fei);
3776 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3779 &local_pfx.fp_addr.ip6)),
3780 "attached-route; fwd and non-fwd tables match");
3782 local_pfx.fp_len = 128;
3783 fib_table_entry_update_one_path(fib_index, &local_pfx,
3784 FIB_SOURCE_INTERFACE,
3785 (FIB_ENTRY_FLAG_CONNECTED |
3786 FIB_ENTRY_FLAG_LOCAL),
3789 tm->hw[0]->sw_if_index,
3790 ~0, // invalid fib index
3793 FIB_ROUTE_PATH_FLAG_NONE);
3794 fei = fib_table_lookup(fib_index, &local_pfx);
3796 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3798 dpo = fib_entry_contribute_ip_forwarding(fei);
3799 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3800 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3801 "local interface adj is local");
3802 rd = receive_dpo_get(dpo->dpoi_index);
3804 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3806 "local interface adj is receive ok");
3808 dpo = fib_entry_contribute_ip_forwarding(fei);
3809 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3812 &local_pfx.fp_addr.ip6)),
3813 "local-route; fwd and non-fwd tables match");
3816 * +2 entries. +2 unshared path-lists
3818 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3819 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3820 fib_path_list_pool_size());
3821 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3822 fib_entry_pool_size());
3825 * Modify the default route to be via an adj not yet known.
3826 * this sources the defalut route with the API source, which is
3827 * a higher preference to the DEFAULT_ROUTE source
3829 fib_table_entry_path_add(fib_index, &pfx_0_0,
3831 FIB_ENTRY_FLAG_NONE,
3834 tm->hw[0]->sw_if_index,
3838 FIB_ROUTE_PATH_FLAG_NONE);
3839 fei = fib_table_lookup(fib_index, &pfx_0_0);
3841 FIB_TEST((fei == dfrt), "default route same index");
3842 ai = fib_entry_get_adj(fei);
3843 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
3845 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3846 "adj is incomplete");
3847 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
3848 "adj nbr next-hop ok");
3851 * find the adj in the shared db
3853 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3856 tm->hw[0]->sw_if_index);
3857 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
3858 adj_unlock(locked_ai);
3861 * no more entires. +1 shared path-list
3863 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3864 fib_path_list_db_size());
3865 FIB_TEST((NPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
3866 fib_path_list_pool_size());
3867 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3868 fib_entry_pool_size());
3871 * remove the API source from the default route. We expected
3872 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
3874 fib_table_entry_path_remove(fib_index, &pfx_0_0,
3878 tm->hw[0]->sw_if_index,
3881 FIB_ROUTE_PATH_FLAG_NONE);
3882 fei = fib_table_lookup(fib_index, &pfx_0_0);
3884 FIB_TEST((fei == dfrt), "default route same index");
3885 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3886 "Default route is DROP");
3889 * no more entires. -1 shared path-list
3891 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3892 fib_path_list_db_size());
3893 FIB_TEST((NPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3894 fib_path_list_pool_size());
3895 FIB_TEST((NPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3896 fib_entry_pool_size());
3899 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3901 fib_prefix_t pfx_2001_1_2_s_128 = {
3903 .fp_proto = FIB_PROTOCOL_IP6,
3907 [0] = clib_host_to_net_u64(0x2001000000000001),
3908 [1] = clib_host_to_net_u64(0x0000000000000002),
3913 fib_prefix_t pfx_2001_1_3_s_128 = {
3915 .fp_proto = FIB_PROTOCOL_IP6,
3919 [0] = clib_host_to_net_u64(0x2001000000000001),
3920 [1] = clib_host_to_net_u64(0x0000000000000003),
3926 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
3929 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3931 &pfx_2001_1_2_s_128.fp_addr,
3932 tm->hw[0]->sw_if_index);
3933 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
3934 adj = adj_get(ai_01);
3935 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3936 "adj is incomplete");
3937 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3938 &adj->sub_type.nbr.next_hop)),
3939 "adj nbr next-hop ok");
3941 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
3942 fib_test_build_rewrite(eth_addr));
3943 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3945 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
3946 &adj->sub_type.nbr.next_hop)),
3947 "adj nbr next-hop ok");
3949 fib_table_entry_update_one_path(fib_index,
3950 &pfx_2001_1_2_s_128,
3952 FIB_ENTRY_FLAG_ATTACHED,
3954 &pfx_2001_1_2_s_128.fp_addr,
3955 tm->hw[0]->sw_if_index,
3959 FIB_ROUTE_PATH_FLAG_NONE);
3961 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
3962 ai = fib_entry_get_adj(fei);
3963 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
3967 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3969 &pfx_2001_1_3_s_128.fp_addr,
3970 tm->hw[0]->sw_if_index);
3971 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
3972 adj = adj_get(ai_02);
3973 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3974 "adj is incomplete");
3975 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3976 &adj->sub_type.nbr.next_hop)),
3977 "adj nbr next-hop ok");
3979 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
3980 fib_test_build_rewrite(eth_addr));
3981 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
3983 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
3984 &adj->sub_type.nbr.next_hop)),
3985 "adj nbr next-hop ok");
3986 FIB_TEST((ai_01 != ai_02), "ADJs are different");
3988 fib_table_entry_update_one_path(fib_index,
3989 &pfx_2001_1_3_s_128,
3991 FIB_ENTRY_FLAG_ATTACHED,
3993 &pfx_2001_1_3_s_128.fp_addr,
3994 tm->hw[0]->sw_if_index,
3998 FIB_ROUTE_PATH_FLAG_NONE);
4000 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4001 ai = fib_entry_get_adj(fei);
4002 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4005 * +2 entries, +2 unshread path-lists.
4007 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4008 fib_path_list_db_size());
4009 FIB_TEST((NPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4010 fib_path_list_pool_size());
4011 FIB_TEST((NPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4012 fib_entry_pool_size());
4015 * Add a 2 routes via the first ADJ. ensure path-list sharing
4017 fib_prefix_t pfx_2001_a_s_64 = {
4019 .fp_proto = FIB_PROTOCOL_IP6,
4023 [0] = clib_host_to_net_u64(0x200100000000000a),
4024 [1] = clib_host_to_net_u64(0x0000000000000000),
4029 fib_prefix_t pfx_2001_b_s_64 = {
4031 .fp_proto = FIB_PROTOCOL_IP6,
4035 [0] = clib_host_to_net_u64(0x200100000000000b),
4036 [1] = clib_host_to_net_u64(0x0000000000000000),
4042 fib_table_entry_path_add(fib_index,
4045 FIB_ENTRY_FLAG_NONE,
4048 tm->hw[0]->sw_if_index,
4052 FIB_ROUTE_PATH_FLAG_NONE);
4053 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4054 ai = fib_entry_get_adj(fei);
4055 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4056 fib_table_entry_path_add(fib_index,
4059 FIB_ENTRY_FLAG_NONE,
4062 tm->hw[0]->sw_if_index,
4066 FIB_ROUTE_PATH_FLAG_NONE);
4067 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4068 ai = fib_entry_get_adj(fei);
4069 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4072 * +2 entries, +1 shared path-list.
4074 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4075 fib_path_list_db_size());
4076 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4077 fib_path_list_pool_size());
4078 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4079 fib_entry_pool_size());
4082 * add a v4 prefix via a v6 next-hop
4084 fib_prefix_t pfx_1_1_1_1_s_32 = {
4086 .fp_proto = FIB_PROTOCOL_IP4,
4088 .ip4.as_u32 = 0x01010101,
4091 fei = fib_table_entry_path_add(0, // default table
4094 FIB_ENTRY_FLAG_NONE,
4097 tm->hw[0]->sw_if_index,
4101 FIB_ROUTE_PATH_FLAG_NONE);
4102 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4103 "1.1.1.1/32 o v6 route present");
4104 ai = fib_entry_get_adj(fei);
4106 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4107 "1.1.1.1/32 via ARP-adj");
4108 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4109 "1.1.1.1/32 ADJ-adj is link type v4");
4110 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4111 "1.1.1.1/32 ADJ-adj is NH proto v6");
4112 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4117 fib_prefix_t pfx_2001_c_s_64 = {
4119 .fp_proto = FIB_PROTOCOL_IP6,
4123 [0] = clib_host_to_net_u64(0x200100000000000c),
4124 [1] = clib_host_to_net_u64(0x0000000000000000),
4129 fib_table_entry_path_add(fib_index,
4132 FIB_ENTRY_FLAG_ATTACHED,
4135 tm->hw[0]->sw_if_index,
4139 FIB_ROUTE_PATH_FLAG_NONE);
4140 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4141 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4142 ai = fib_entry_get_adj(fei);
4144 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4145 "2001:0:0:c/64 attached resolves via glean");
4147 fib_table_entry_path_remove(fib_index,
4152 tm->hw[0]->sw_if_index,
4155 FIB_ROUTE_PATH_FLAG_NONE);
4156 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4157 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4160 * Shutdown the interface on which we have a connected and through
4161 * which the routes are reachable.
4162 * This will result in the connected, adj-fibs, and routes linking to drop
4163 * The local/for-us prefix continues to receive.
4165 clib_error_t * error;
4167 error = vnet_sw_interface_set_flags(vnet_get_main(),
4168 tm->hw[0]->sw_if_index,
4169 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4170 FIB_TEST((NULL == error), "Interface shutdown OK");
4172 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4173 dpo = fib_entry_contribute_ip_forwarding(fei);
4174 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4175 "2001::b/64 resolves via drop");
4177 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4178 dpo = fib_entry_contribute_ip_forwarding(fei);
4179 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4180 "2001::a/64 resolves via drop");
4181 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4182 dpo = fib_entry_contribute_ip_forwarding(fei);
4183 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4184 "2001:0:0:1::3/64 resolves via drop");
4185 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4186 dpo = fib_entry_contribute_ip_forwarding(fei);
4187 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4188 "2001:0:0:1::2/64 resolves via drop");
4189 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4190 dpo = fib_entry_contribute_ip_forwarding(fei);
4191 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4192 "2001:0:0:1::1/128 not drop");
4193 local_pfx.fp_len = 64;
4194 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4195 dpo = fib_entry_contribute_ip_forwarding(fei);
4196 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4197 "2001:0:0:1/64 resolves via drop");
4202 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4203 fib_path_list_db_size());
4204 FIB_TEST((NPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4205 fib_path_list_pool_size());
4206 FIB_TEST((NPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4207 fib_entry_pool_size());
4210 * shutdown one of the other interfaces, then add a connected.
4211 * and swap one of the routes to it.
4213 error = vnet_sw_interface_set_flags(vnet_get_main(),
4214 tm->hw[1]->sw_if_index,
4215 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4216 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4218 fib_prefix_t connected_pfx = {
4220 .fp_proto = FIB_PROTOCOL_IP6,
4223 /* 2001:0:0:2::1/64 */
4225 [0] = clib_host_to_net_u64(0x2001000000000002),
4226 [1] = clib_host_to_net_u64(0x0000000000000001),
4231 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4232 FIB_SOURCE_INTERFACE,
4233 (FIB_ENTRY_FLAG_CONNECTED |
4234 FIB_ENTRY_FLAG_ATTACHED),
4237 tm->hw[1]->sw_if_index,
4241 FIB_ROUTE_PATH_FLAG_NONE);
4242 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4243 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4244 dpo = fib_entry_contribute_ip_forwarding(fei);
4245 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4246 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4247 "2001:0:0:2/64 not resolves via drop");
4249 connected_pfx.fp_len = 128;
4250 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4251 FIB_SOURCE_INTERFACE,
4252 (FIB_ENTRY_FLAG_CONNECTED |
4253 FIB_ENTRY_FLAG_LOCAL),
4256 tm->hw[0]->sw_if_index,
4257 ~0, // invalid fib index
4260 FIB_ROUTE_PATH_FLAG_NONE);
4261 fei = fib_table_lookup(fib_index, &connected_pfx);
4263 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4264 dpo = fib_entry_contribute_ip_forwarding(fei);
4265 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4266 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4267 "local interface adj is local");
4268 rd = receive_dpo_get(dpo->dpoi_index);
4269 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4271 "local interface adj is receive ok");
4274 * +2 entries, +2 unshared path-lists
4276 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4277 fib_path_list_db_size());
4278 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4279 fib_path_list_pool_size());
4280 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4281 fib_entry_pool_size());
4285 * bring the interface back up. we expected the routes to return
4286 * to normal forwarding.
4288 error = vnet_sw_interface_set_flags(vnet_get_main(),
4289 tm->hw[0]->sw_if_index,
4290 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4291 FIB_TEST((NULL == error), "Interface bring-up OK");
4292 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4293 ai = fib_entry_get_adj(fei);
4294 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4295 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4296 ai = fib_entry_get_adj(fei);
4297 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4298 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4299 ai = fib_entry_get_adj(fei);
4300 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4301 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4302 ai = fib_entry_get_adj(fei);
4303 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4304 local_pfx.fp_len = 64;
4305 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4306 ai = fib_entry_get_adj(fei);
4308 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4309 "attached interface adj is glean");
4312 * Same test as above, but this time the HW interface goes down
4314 error = vnet_hw_interface_set_flags(vnet_get_main(),
4315 tm->hw_if_indicies[0],
4316 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4317 FIB_TEST((NULL == error), "Interface shutdown OK");
4319 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4320 dpo = fib_entry_contribute_ip_forwarding(fei);
4321 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4322 "2001::b/64 resolves via drop");
4323 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4324 dpo = fib_entry_contribute_ip_forwarding(fei);
4325 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4326 "2001::a/64 resolves via drop");
4327 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4328 dpo = fib_entry_contribute_ip_forwarding(fei);
4329 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4330 "2001:0:0:1::3/128 resolves via drop");
4331 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4332 dpo = fib_entry_contribute_ip_forwarding(fei);
4333 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4334 "2001:0:0:1::2/128 resolves via drop");
4335 local_pfx.fp_len = 128;
4336 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4337 dpo = fib_entry_contribute_ip_forwarding(fei);
4338 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4339 "2001:0:0:1::1/128 not drop");
4340 local_pfx.fp_len = 64;
4341 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4342 dpo = fib_entry_contribute_ip_forwarding(fei);
4343 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4344 "2001:0:0:1/64 resolves via drop");
4346 error = vnet_hw_interface_set_flags(vnet_get_main(),
4347 tm->hw_if_indicies[0],
4348 VNET_HW_INTERFACE_FLAG_LINK_UP);
4349 FIB_TEST((NULL == error), "Interface bring-up OK");
4350 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4351 ai = fib_entry_get_adj(fei);
4352 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4353 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4354 ai = fib_entry_get_adj(fei);
4355 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4356 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4357 ai = fib_entry_get_adj(fei);
4358 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4359 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4360 ai = fib_entry_get_adj(fei);
4361 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4362 local_pfx.fp_len = 64;
4363 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4364 ai = fib_entry_get_adj(fei);
4366 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4367 "attached interface adj is glean");
4370 * Delete the interface that the routes reolve through.
4371 * Again no routes are removed. They all point to drop.
4373 * This is considered an error case. The control plane should
4374 * not remove interfaces through which routes resolve, but
4375 * such things can happen. ALL affected routes will drop.
4377 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4379 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4380 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4381 "2001::b/64 resolves via drop");
4382 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_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_1_3_s_128);
4386 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4387 "2001:0:0:1::3/64 resolves via drop");
4388 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4389 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4390 "2001:0:0:1::2/64 resolves via drop");
4391 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4392 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4393 "2001:0:0:1::1/128 is drop");
4394 local_pfx.fp_len = 64;
4395 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4396 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4397 "2001:0:0:1/64 resolves via drop");
4402 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4403 fib_path_list_db_size());
4404 FIB_TEST((NPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4405 fib_path_list_pool_size());
4406 FIB_TEST((NPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4407 fib_entry_pool_size());
4410 * Add the interface back. routes stay unresolved.
4412 error = ethernet_register_interface(vnet_get_main(),
4413 test_interface_device_class.index,
4416 &tm->hw_if_indicies[0],
4417 /* flag change */ 0);
4419 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4420 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4421 "2001::b/64 resolves via drop");
4422 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_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_1_3_s_128);
4426 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4427 "2001:0:0:1::3/64 resolves via drop");
4428 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4429 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4430 "2001:0:0:1::2/64 resolves via drop");
4431 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4432 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4433 "2001:0:0:1::1/128 is drop");
4434 local_pfx.fp_len = 64;
4435 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4436 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4437 "2001:0:0:1/64 resolves via drop");
4440 * CLEANUP ALL the routes
4442 fib_table_entry_delete(fib_index,
4445 fib_table_entry_delete(fib_index,
4448 fib_table_entry_delete(fib_index,
4451 fib_table_entry_delete(fib_index,
4452 &pfx_2001_1_3_s_128,
4454 fib_table_entry_delete(fib_index,
4455 &pfx_2001_1_2_s_128,
4457 local_pfx.fp_len = 64;
4458 fib_table_entry_delete(fib_index, &local_pfx,
4459 FIB_SOURCE_INTERFACE);
4460 local_pfx.fp_len = 128;
4461 fib_table_entry_special_remove(fib_index, &local_pfx,
4462 FIB_SOURCE_INTERFACE);
4463 connected_pfx.fp_len = 64;
4464 fib_table_entry_delete(fib_index, &connected_pfx,
4465 FIB_SOURCE_INTERFACE);
4466 connected_pfx.fp_len = 128;
4467 fib_table_entry_special_remove(fib_index, &connected_pfx,
4468 FIB_SOURCE_INTERFACE);
4470 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4471 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4472 "2001::a/64 removed");
4473 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4474 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4475 "2001::b/64 removed");
4476 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4477 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4478 "2001:0:0:1::3/128 removed");
4479 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4480 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4481 "2001:0:0:1::3/128 removed");
4482 local_pfx.fp_len = 64;
4483 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4484 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4485 "2001:0:0:1/64 removed");
4486 local_pfx.fp_len = 128;
4487 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4488 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4489 "2001:0:0:1::1/128 removed");
4490 connected_pfx.fp_len = 64;
4491 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4492 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4493 "2001:0:0:2/64 removed");
4494 connected_pfx.fp_len = 128;
4495 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4496 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4497 "2001:0:0:2::1/128 removed");
4500 * -8 entries. -7 path-lists (1 was shared).
4502 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4503 fib_path_list_db_size());
4504 FIB_TEST((NPS == fib_path_list_pool_size()), "path list pool size is%d",
4505 fib_path_list_pool_size());
4506 FIB_TEST((NPS == fib_entry_pool_size()), "entry pool size is %d",
4507 fib_entry_pool_size());
4510 * now remove the VRF
4512 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4514 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4515 fib_path_list_db_size());
4516 FIB_TEST((NPS-6 == fib_path_list_pool_size()), "path list pool size is%d",
4517 fib_path_list_pool_size());
4518 FIB_TEST((NPS-6 == fib_entry_pool_size()), "entry pool size is %d",
4519 fib_entry_pool_size());
4525 * return the interfaces to up state
4527 error = vnet_sw_interface_set_flags(vnet_get_main(),
4528 tm->hw[0]->sw_if_index,
4529 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4530 error = vnet_sw_interface_set_flags(vnet_get_main(),
4531 tm->hw[1]->sw_if_index,
4532 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4534 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4541 * Test Attached Exports
4546 const dpo_id_t *dpo, *dpo_drop;
4547 const u32 fib_index = 0;
4548 fib_node_index_t fei;
4555 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4559 * add interface routes. We'll assume this works. It's more rigorously
4562 fib_prefix_t local_pfx = {
4564 .fp_proto = FIB_PROTOCOL_IP4,
4568 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4573 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4574 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4576 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4578 fib_table_entry_update_one_path(fib_index, &local_pfx,
4579 FIB_SOURCE_INTERFACE,
4580 (FIB_ENTRY_FLAG_CONNECTED |
4581 FIB_ENTRY_FLAG_ATTACHED),
4584 tm->hw[0]->sw_if_index,
4588 FIB_ROUTE_PATH_FLAG_NONE);
4589 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4590 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4591 "attached interface route present");
4593 local_pfx.fp_len = 32;
4594 fib_table_entry_update_one_path(fib_index, &local_pfx,
4595 FIB_SOURCE_INTERFACE,
4596 (FIB_ENTRY_FLAG_CONNECTED |
4597 FIB_ENTRY_FLAG_LOCAL),
4600 tm->hw[0]->sw_if_index,
4601 ~0, // invalid fib index
4604 FIB_ROUTE_PATH_FLAG_NONE);
4605 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4607 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4608 "local interface route present");
4611 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4613 fib_prefix_t pfx_10_10_10_1_s_32 = {
4615 .fp_proto = FIB_PROTOCOL_IP4,
4618 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4621 fib_node_index_t ai;
4623 fib_table_entry_update_one_path(fib_index,
4624 &pfx_10_10_10_1_s_32,
4626 FIB_ENTRY_FLAG_ATTACHED,
4628 &pfx_10_10_10_1_s_32.fp_addr,
4629 tm->hw[0]->sw_if_index,
4630 ~0, // invalid fib index
4633 FIB_ROUTE_PATH_FLAG_NONE);
4635 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4636 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4637 ai = fib_entry_get_adj(fei);
4640 * create another FIB table into which routes will be imported
4642 u32 import_fib_index1;
4644 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4647 * Add an attached route in the import FIB
4649 local_pfx.fp_len = 24;
4650 fib_table_entry_update_one_path(import_fib_index1,
4653 FIB_ENTRY_FLAG_NONE,
4656 tm->hw[0]->sw_if_index,
4657 ~0, // invalid fib index
4660 FIB_ROUTE_PATH_FLAG_NONE);
4661 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4662 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4665 * check for the presence of the adj-fibs in the import table
4667 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4668 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4669 FIB_TEST((ai == fib_entry_get_adj(fei)),
4670 "adj-fib1 Import uses same adj as export");
4673 * check for the presence of the local in the import table
4675 local_pfx.fp_len = 32;
4676 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4677 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4680 * Add another adj-fin in the export table. Expect this
4681 * to get magically exported;
4683 fib_prefix_t pfx_10_10_10_2_s_32 = {
4685 .fp_proto = FIB_PROTOCOL_IP4,
4688 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4692 fib_table_entry_update_one_path(fib_index,
4693 &pfx_10_10_10_2_s_32,
4695 FIB_ENTRY_FLAG_ATTACHED,
4697 &pfx_10_10_10_2_s_32.fp_addr,
4698 tm->hw[0]->sw_if_index,
4699 ~0, // invalid fib index
4702 FIB_ROUTE_PATH_FLAG_NONE);
4703 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4704 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4705 ai = fib_entry_get_adj(fei);
4707 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4708 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4709 FIB_TEST((ai == fib_entry_get_adj(fei)),
4710 "Import uses same adj as export");
4711 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
4712 "ADJ-fib2 imported flags %d",
4713 fib_entry_get_flags(fei));
4716 * create a 2nd FIB table into which routes will be imported
4718 u32 import_fib_index2;
4720 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4723 * Add an attached route in the import FIB
4725 local_pfx.fp_len = 24;
4726 fib_table_entry_update_one_path(import_fib_index2,
4729 FIB_ENTRY_FLAG_NONE,
4732 tm->hw[0]->sw_if_index,
4733 ~0, // invalid fib index
4736 FIB_ROUTE_PATH_FLAG_NONE);
4737 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4738 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4741 * check for the presence of all the adj-fibs and local in the import table
4743 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4744 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4745 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4746 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4747 local_pfx.fp_len = 32;
4748 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4749 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4752 * add a 3rd adj-fib. expect it to be exported to both tables.
4754 fib_prefix_t pfx_10_10_10_3_s_32 = {
4756 .fp_proto = FIB_PROTOCOL_IP4,
4759 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4763 fib_table_entry_update_one_path(fib_index,
4764 &pfx_10_10_10_3_s_32,
4766 FIB_ENTRY_FLAG_ATTACHED,
4768 &pfx_10_10_10_3_s_32.fp_addr,
4769 tm->hw[0]->sw_if_index,
4770 ~0, // invalid fib index
4773 FIB_ROUTE_PATH_FLAG_NONE);
4774 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4775 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4776 ai = fib_entry_get_adj(fei);
4778 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4779 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4780 FIB_TEST((ai == fib_entry_get_adj(fei)),
4781 "Import uses same adj as export");
4782 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4783 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4784 FIB_TEST((ai == fib_entry_get_adj(fei)),
4785 "Import uses same adj as export");
4788 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4790 fib_table_entry_delete(fib_index,
4791 &pfx_10_10_10_3_s_32,
4794 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4795 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4797 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4798 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
4800 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4801 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4804 * remove the attached route from the 2nd FIB. expect the imported
4805 * entires to be removed
4807 local_pfx.fp_len = 24;
4808 fib_table_entry_delete(import_fib_index2,
4811 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4812 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4814 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4815 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4816 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4817 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4818 local_pfx.fp_len = 32;
4819 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4820 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4822 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4823 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4824 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4825 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4826 local_pfx.fp_len = 32;
4827 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4828 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4831 * modify the route in FIB1 so it is no longer attached. expect the imported
4832 * entires to be removed
4834 local_pfx.fp_len = 24;
4835 fib_table_entry_update_one_path(import_fib_index1,
4838 FIB_ENTRY_FLAG_NONE,
4840 &pfx_10_10_10_2_s_32.fp_addr,
4841 tm->hw[0]->sw_if_index,
4842 ~0, // invalid fib index
4845 FIB_ROUTE_PATH_FLAG_NONE);
4846 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4847 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4848 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4849 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4850 local_pfx.fp_len = 32;
4851 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4852 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4855 * modify it back to attached. expect the adj-fibs back
4857 local_pfx.fp_len = 24;
4858 fib_table_entry_update_one_path(import_fib_index1,
4861 FIB_ENTRY_FLAG_NONE,
4864 tm->hw[0]->sw_if_index,
4865 ~0, // invalid fib index
4868 FIB_ROUTE_PATH_FLAG_NONE);
4869 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4870 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4871 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4872 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4873 local_pfx.fp_len = 32;
4874 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4875 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4878 * add a covering attached next-hop for the interface address, so we have
4879 * a valid adj to find when we check the forwarding tables
4881 fib_prefix_t pfx_10_0_0_0_s_8 = {
4883 .fp_proto = FIB_PROTOCOL_IP4,
4886 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4890 fei = fib_table_entry_update_one_path(fib_index,
4893 FIB_ENTRY_FLAG_NONE,
4895 &pfx_10_10_10_3_s_32.fp_addr,
4896 tm->hw[0]->sw_if_index,
4897 ~0, // invalid fib index
4900 FIB_ROUTE_PATH_FLAG_NONE);
4901 dpo = fib_entry_contribute_ip_forwarding(fei);
4904 * remove the route in the export fib. expect the adj-fibs to be removed
4906 local_pfx.fp_len = 24;
4907 fib_table_entry_delete(fib_index,
4909 FIB_SOURCE_INTERFACE);
4911 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4912 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4913 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4914 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4915 local_pfx.fp_len = 32;
4916 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4917 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4920 * the adj-fibs in the export VRF are present in the FIB table,
4921 * but not installed in forwarding, since they have no attached cover.
4922 * Consequently a lookup in the MTRIE gives the adj for the covering
4925 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4926 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4929 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4930 FIB_TEST(lbi == dpo->dpoi_index,
4931 "10.10.10.1 forwards on \n%U not \n%U",
4932 format_load_balance, lbi, 0,
4933 format_dpo_id, dpo, 0);
4934 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4935 FIB_TEST(lbi == dpo->dpoi_index,
4936 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4937 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
4938 FIB_TEST(lbi == dpo->dpoi_index,
4939 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
4942 * add the export prefix back, but not as attached.
4943 * No adj-fibs in export nor import tables
4945 local_pfx.fp_len = 24;
4946 fei = fib_table_entry_update_one_path(fib_index,
4949 FIB_ENTRY_FLAG_NONE,
4951 &pfx_10_10_10_1_s_32.fp_addr,
4952 tm->hw[0]->sw_if_index,
4953 ~0, // invalid fib index
4956 FIB_ROUTE_PATH_FLAG_NONE);
4957 dpo = fib_entry_contribute_ip_forwarding(fei);
4959 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4960 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
4961 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
4962 FIB_TEST(lbi == dpo->dpoi_index,
4963 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
4964 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4965 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
4966 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
4967 FIB_TEST(lbi == dpo->dpoi_index,
4968 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
4970 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4971 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4972 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4973 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4974 local_pfx.fp_len = 32;
4975 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4976 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4979 * modify the export prefix so it is attached. expect all covereds to return
4981 local_pfx.fp_len = 24;
4982 fib_table_entry_update_one_path(fib_index,
4985 FIB_ENTRY_FLAG_NONE,
4988 tm->hw[0]->sw_if_index,
4989 ~0, // invalid fib index
4992 FIB_ROUTE_PATH_FLAG_NONE);
4994 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4995 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
4996 dpo = fib_entry_contribute_ip_forwarding(fei);
4997 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4998 "Adj-fib1 is not drop in export");
4999 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5000 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5001 local_pfx.fp_len = 32;
5002 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5003 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5004 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5005 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5006 dpo = fib_entry_contribute_ip_forwarding(fei);
5007 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5008 "Adj-fib1 is not drop in export");
5009 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5010 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5011 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5012 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5013 local_pfx.fp_len = 32;
5014 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5015 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5018 * modify the export prefix so connected. no change.
5020 local_pfx.fp_len = 24;
5021 fib_table_entry_update_one_path(fib_index, &local_pfx,
5022 FIB_SOURCE_INTERFACE,
5023 (FIB_ENTRY_FLAG_CONNECTED |
5024 FIB_ENTRY_FLAG_ATTACHED),
5027 tm->hw[0]->sw_if_index,
5031 FIB_ROUTE_PATH_FLAG_NONE);
5033 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5034 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5035 dpo = fib_entry_contribute_ip_forwarding(fei);
5036 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5037 "Adj-fib1 is not drop in export");
5038 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5039 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5040 local_pfx.fp_len = 32;
5041 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5042 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5043 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5044 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5045 dpo = fib_entry_contribute_ip_forwarding(fei);
5046 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5047 "Adj-fib1 is not drop in export");
5048 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5049 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5050 local_pfx.fp_len = 32;
5051 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5052 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5057 fib_table_entry_delete(fib_index,
5060 fib_table_entry_delete(fib_index,
5061 &pfx_10_10_10_1_s_32,
5063 fib_table_entry_delete(fib_index,
5064 &pfx_10_10_10_2_s_32,
5066 local_pfx.fp_len = 32;
5067 fib_table_entry_delete(fib_index,
5069 FIB_SOURCE_INTERFACE);
5070 local_pfx.fp_len = 24;
5071 fib_table_entry_delete(fib_index,
5074 fib_table_entry_delete(fib_index,
5076 FIB_SOURCE_INTERFACE);
5077 local_pfx.fp_len = 24;
5078 fib_table_entry_delete(import_fib_index1,
5082 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5083 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5085 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5093 * Test the recursive route route handling for GRE tunnels
5096 fib_test_label (void)
5098 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;
5099 const u32 fib_index = 0;
5104 lb_count = pool_elts(load_balance_pool);
5109 * add interface routes. We'll assume this works. It's more rigorously
5112 fib_prefix_t local0_pfx = {
5114 .fp_proto = FIB_PROTOCOL_IP4,
5118 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5123 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5126 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5127 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5129 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5130 FIB_SOURCE_INTERFACE,
5131 (FIB_ENTRY_FLAG_CONNECTED |
5132 FIB_ENTRY_FLAG_ATTACHED),
5135 tm->hw[0]->sw_if_index,
5139 FIB_ROUTE_PATH_FLAG_NONE);
5140 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5141 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5142 "attached interface route present");
5144 local0_pfx.fp_len = 32;
5145 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5146 FIB_SOURCE_INTERFACE,
5147 (FIB_ENTRY_FLAG_CONNECTED |
5148 FIB_ENTRY_FLAG_LOCAL),
5151 tm->hw[0]->sw_if_index,
5152 ~0, // invalid fib index
5155 FIB_ROUTE_PATH_FLAG_NONE);
5156 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5158 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5159 "local interface route present");
5161 fib_prefix_t local1_pfx = {
5163 .fp_proto = FIB_PROTOCOL_IP4,
5167 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5172 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5173 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5175 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5176 FIB_SOURCE_INTERFACE,
5177 (FIB_ENTRY_FLAG_CONNECTED |
5178 FIB_ENTRY_FLAG_ATTACHED),
5181 tm->hw[1]->sw_if_index,
5185 FIB_ROUTE_PATH_FLAG_NONE);
5186 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5187 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5188 "attached interface route present");
5190 local1_pfx.fp_len = 32;
5191 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5192 FIB_SOURCE_INTERFACE,
5193 (FIB_ENTRY_FLAG_CONNECTED |
5194 FIB_ENTRY_FLAG_LOCAL),
5197 tm->hw[1]->sw_if_index,
5198 ~0, // invalid fib index
5201 FIB_ROUTE_PATH_FLAG_NONE);
5202 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5204 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5205 "local interface route present");
5207 ip46_address_t nh_10_10_10_1 = {
5209 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5212 ip46_address_t nh_10_10_11_1 = {
5214 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5217 ip46_address_t nh_10_10_11_2 = {
5219 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5223 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5226 tm->hw[1]->sw_if_index);
5227 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5230 tm->hw[1]->sw_if_index);
5231 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5234 tm->hw[0]->sw_if_index);
5235 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5238 tm->hw[1]->sw_if_index);
5239 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5242 tm->hw[1]->sw_if_index);
5245 * Add an etry with one path with a real out-going label
5247 fib_prefix_t pfx_1_1_1_1_s_32 = {
5249 .fp_proto = FIB_PROTOCOL_IP4,
5251 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5254 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5255 .type = FT_LB_LABEL_O_ADJ,
5257 .adj = ai_mpls_10_10_10_1,
5262 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5263 .type = FT_LB_LABEL_O_ADJ,
5265 .adj = ai_mpls_10_10_10_1,
5267 .eos = MPLS_NON_EOS,
5270 mpls_label_t *l99 = NULL;
5273 fib_table_entry_update_one_path(fib_index,
5276 FIB_ENTRY_FLAG_NONE,
5279 tm->hw[0]->sw_if_index,
5280 ~0, // invalid fib index
5283 FIB_ROUTE_PATH_FLAG_NONE);
5285 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5286 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5288 FIB_TEST(fib_test_validate_entry(fei,
5289 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5291 &l99_eos_o_10_10_10_1),
5292 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5295 * add a path with an implicit NULL label
5297 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5300 .adj = ai_v4_10_10_11_1,
5303 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5306 .adj = ai_mpls_10_10_11_1,
5309 mpls_label_t *l_imp_null = NULL;
5310 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5312 fei = fib_table_entry_path_add(fib_index,
5315 FIB_ENTRY_FLAG_NONE,
5318 tm->hw[1]->sw_if_index,
5319 ~0, // invalid fib index
5322 FIB_ROUTE_PATH_FLAG_NONE);
5324 FIB_TEST(fib_test_validate_entry(fei,
5325 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5327 &l99_eos_o_10_10_10_1,
5329 "1.1.1.1/32 LB 2 buckets via: "
5330 "label 99 over 10.10.10.1, "
5331 "adj over 10.10.11.1");
5334 * assign the route a local label
5336 fib_table_entry_local_label_add(fib_index,
5340 fib_prefix_t pfx_24001_eos = {
5341 .fp_proto = FIB_PROTOCOL_MPLS,
5345 fib_prefix_t pfx_24001_neos = {
5346 .fp_proto = FIB_PROTOCOL_MPLS,
5348 .fp_eos = MPLS_NON_EOS,
5352 * The EOS entry should link to both the paths,
5353 * and use an ip adj for the imp-null
5354 * The NON-EOS entry should link to both the paths,
5355 * and use an mpls adj for the imp-null
5357 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5359 FIB_TEST(fib_test_validate_entry(fei,
5360 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5362 &l99_eos_o_10_10_10_1,
5364 "24001/eos LB 2 buckets via: "
5365 "label 99 over 10.10.10.1, "
5366 "adj over 10.10.11.1");
5369 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5371 FIB_TEST(fib_test_validate_entry(fei,
5372 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5374 &l99_neos_o_10_10_10_1,
5375 &a_mpls_o_10_10_11_1),
5376 "24001/neos LB 1 bucket via: "
5377 "label 99 over 10.10.10.1 ",
5378 "mpls-adj via 10.10.11.1");
5381 * add an unlabelled path, this is excluded from the neos chains,
5383 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5386 .adj = ai_v4_10_10_11_2,
5390 fei = fib_table_entry_path_add(fib_index,
5393 FIB_ENTRY_FLAG_NONE,
5396 tm->hw[1]->sw_if_index,
5397 ~0, // invalid fib index
5400 FIB_ROUTE_PATH_FLAG_NONE);
5402 FIB_TEST(fib_test_validate_entry(fei,
5403 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5404 16, // 3 choices spread over 16 buckets
5405 &l99_eos_o_10_10_10_1,
5406 &l99_eos_o_10_10_10_1,
5407 &l99_eos_o_10_10_10_1,
5408 &l99_eos_o_10_10_10_1,
5409 &l99_eos_o_10_10_10_1,
5410 &l99_eos_o_10_10_10_1,
5421 "1.1.1.1/32 LB 16 buckets via: "
5422 "label 99 over 10.10.10.1, "
5423 "adj over 10.10.11.1",
5424 "adj over 10.10.11.2");
5427 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5429 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5430 fib_entry_contribute_forwarding(fei,
5431 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5435 * n-eos has only the 2 labelled paths
5437 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5440 FIB_TEST(fib_test_validate_entry(fei,
5441 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5443 &l99_neos_o_10_10_10_1,
5444 &a_mpls_o_10_10_11_1),
5445 "24001/neos LB 2 buckets via: "
5446 "label 99 over 10.10.10.1, "
5447 "adj-mpls over 10.10.11.2");
5450 * A labelled recursive
5452 fib_prefix_t pfx_2_2_2_2_s_32 = {
5454 .fp_proto = FIB_PROTOCOL_IP4,
5456 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5459 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5460 .type = FT_LB_LABEL_O_LB,
5462 .lb = non_eos_1_1_1_1.dpoi_index,
5467 mpls_label_t *l1600 = NULL;
5468 vec_add1(l1600, 1600);
5470 fib_table_entry_update_one_path(fib_index,
5473 FIB_ENTRY_FLAG_NONE,
5475 &pfx_1_1_1_1_s_32.fp_addr,
5480 FIB_ROUTE_PATH_FLAG_NONE);
5482 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5483 FIB_TEST(fib_test_validate_entry(fei,
5484 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5486 &l1600_eos_o_1_1_1_1),
5487 "2.2.2.2.2/32 LB 1 buckets via: "
5488 "label 1600 over 1.1.1.1");
5490 dpo_id_t dpo_44 = DPO_INVALID;
5493 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5494 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5496 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5497 "uRPF check for 2.2.2.2/32 on %d OK",
5498 tm->hw[0]->sw_if_index);
5499 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5500 "uRPF check for 2.2.2.2/32 on %d OK",
5501 tm->hw[1]->sw_if_index);
5502 FIB_TEST(!fib_urpf_check(urpfi, 99),
5503 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5506 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5507 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5508 "Shared uRPF on IP and non-EOS chain");
5513 * we are holding a lock on the non-eos LB of the via-entry.
5514 * do a PIC-core failover by shutting the link of the via-entry.
5516 * shut down the link with the valid label
5518 vnet_sw_interface_set_flags(vnet_get_main(),
5519 tm->hw[0]->sw_if_index,
5522 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5523 FIB_TEST(fib_test_validate_entry(fei,
5524 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5528 "1.1.1.1/32 LB 2 buckets via: "
5529 "adj over 10.10.11.1, ",
5530 "adj-v4 over 10.10.11.2");
5532 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5534 FIB_TEST(fib_test_validate_entry(fei,
5535 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5539 "24001/eos LB 2 buckets via: "
5540 "adj over 10.10.11.1, ",
5541 "adj-v4 over 10.10.11.2");
5543 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5545 FIB_TEST(fib_test_validate_entry(fei,
5546 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5548 &a_mpls_o_10_10_11_1),
5549 "24001/neos LB 1 buckets via: "
5550 "adj-mpls over 10.10.11.2");
5553 * test that the pre-failover load-balance has been in-place
5556 dpo_id_t current = DPO_INVALID;
5557 fib_entry_contribute_forwarding(fei,
5558 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5561 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5563 "PIC-core LB inplace modified %U %U",
5564 format_dpo_id, &non_eos_1_1_1_1, 0,
5565 format_dpo_id, ¤t, 0);
5567 dpo_reset(&non_eos_1_1_1_1);
5568 dpo_reset(¤t);
5571 * no-shut the link with the valid label
5573 vnet_sw_interface_set_flags(vnet_get_main(),
5574 tm->hw[0]->sw_if_index,
5575 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5577 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5578 FIB_TEST(fib_test_validate_entry(fei,
5579 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5580 16, // 3 choices spread over 16 buckets
5581 &l99_eos_o_10_10_10_1,
5582 &l99_eos_o_10_10_10_1,
5583 &l99_eos_o_10_10_10_1,
5584 &l99_eos_o_10_10_10_1,
5585 &l99_eos_o_10_10_10_1,
5586 &l99_eos_o_10_10_10_1,
5597 "1.1.1.1/32 LB 16 buckets via: "
5598 "label 99 over 10.10.10.1, "
5599 "adj over 10.10.11.1",
5600 "adj-v4 over 10.10.11.2");
5603 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5605 FIB_TEST(fib_test_validate_entry(fei,
5606 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5607 16, // 3 choices spread over 16 buckets
5608 &l99_eos_o_10_10_10_1,
5609 &l99_eos_o_10_10_10_1,
5610 &l99_eos_o_10_10_10_1,
5611 &l99_eos_o_10_10_10_1,
5612 &l99_eos_o_10_10_10_1,
5613 &l99_eos_o_10_10_10_1,
5624 "24001/eos LB 16 buckets via: "
5625 "label 99 over 10.10.10.1, "
5626 "adj over 10.10.11.1",
5627 "adj-v4 over 10.10.11.2");
5629 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5631 FIB_TEST(fib_test_validate_entry(fei,
5632 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5634 &l99_neos_o_10_10_10_1,
5635 &a_mpls_o_10_10_11_1),
5636 "24001/neos LB 2 buckets via: "
5637 "label 99 over 10.10.10.1, "
5638 "adj-mpls over 10.10.11.2");
5641 * remove the first path with the valid label
5643 fib_table_entry_path_remove(fib_index,
5648 tm->hw[0]->sw_if_index,
5649 ~0, // invalid fib index
5651 FIB_ROUTE_PATH_FLAG_NONE);
5653 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5654 FIB_TEST(fib_test_validate_entry(fei,
5655 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5659 "1.1.1.1/32 LB 2 buckets via: "
5660 "adj over 10.10.11.1",
5661 "adj-v4 over 10.10.11.2");
5663 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5665 FIB_TEST(fib_test_validate_entry(fei,
5666 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5670 "24001/eos LB 2 buckets via: "
5671 "adj over 10.10.11.1",
5672 "adj-v4 over 10.10.11.2");
5674 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5677 FIB_TEST(fib_test_validate_entry(fei,
5678 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5680 &a_mpls_o_10_10_11_1),
5681 "24001/neos LB 1 buckets via: "
5682 "adj-mpls over 10.10.11.2");
5685 * remove the other path with a valid label
5687 fib_test_lb_bucket_t bucket_drop = {
5688 .type = FT_LB_SPECIAL,
5690 .adj = DPO_PROTO_IP4,
5694 fib_table_entry_path_remove(fib_index,
5699 tm->hw[1]->sw_if_index,
5700 ~0, // invalid fib index
5702 FIB_ROUTE_PATH_FLAG_NONE);
5704 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5705 FIB_TEST(fib_test_validate_entry(fei,
5706 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5709 "1.1.1.1/32 LB 1 buckets via: "
5710 "adj over 10.10.11.2");
5712 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5714 FIB_TEST(fib_test_validate_entry(fei,
5715 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5718 "24001/eos LB 1 buckets via: "
5719 "adj over 10.10.11.2");
5721 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5723 FIB_TEST(fib_test_validate_entry(fei,
5724 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5727 "24001/eos LB 1 buckets via: DROP");
5730 * add back the path with the valid label
5735 fib_table_entry_path_add(fib_index,
5738 FIB_ENTRY_FLAG_NONE,
5741 tm->hw[0]->sw_if_index,
5742 ~0, // invalid fib index
5745 FIB_ROUTE_PATH_FLAG_NONE);
5747 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5748 FIB_TEST(fib_test_validate_entry(fei,
5749 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5751 &l99_eos_o_10_10_10_1,
5753 "1.1.1.1/32 LB 2 buckets via: "
5754 "label 99 over 10.10.10.1, "
5755 "adj over 10.10.11.2");
5757 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5759 FIB_TEST(fib_test_validate_entry(fei,
5760 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5762 &l99_eos_o_10_10_10_1,
5764 "24001/eos LB 2 buckets via: "
5765 "label 99 over 10.10.10.1, "
5766 "adj over 10.10.11.2");
5768 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5770 FIB_TEST(fib_test_validate_entry(fei,
5771 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5773 &l99_neos_o_10_10_10_1),
5774 "24001/neos LB 1 buckets via: "
5775 "label 99 over 10.10.10.1");
5778 * change the local label
5780 fib_table_entry_local_label_add(fib_index,
5784 fib_prefix_t pfx_25005_eos = {
5785 .fp_proto = FIB_PROTOCOL_MPLS,
5789 fib_prefix_t pfx_25005_neos = {
5790 .fp_proto = FIB_PROTOCOL_MPLS,
5792 .fp_eos = MPLS_NON_EOS,
5795 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5796 fib_table_lookup(fib_index, &pfx_24001_eos)),
5797 "24001/eos removed after label change");
5798 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5799 fib_table_lookup(fib_index, &pfx_24001_neos)),
5800 "24001/eos removed after label change");
5802 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5804 FIB_TEST(fib_test_validate_entry(fei,
5805 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5807 &l99_eos_o_10_10_10_1,
5809 "25005/eos LB 2 buckets via: "
5810 "label 99 over 10.10.10.1, "
5811 "adj over 10.10.11.2");
5813 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5815 FIB_TEST(fib_test_validate_entry(fei,
5816 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5818 &l99_neos_o_10_10_10_1),
5819 "25005/neos LB 1 buckets via: "
5820 "label 99 over 10.10.10.1");
5823 * remove the local label.
5824 * the check that the MPLS entries are gone is done by the fact the
5825 * MPLS table is no longer present.
5827 fib_table_entry_local_label_remove(fib_index,
5831 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5832 FIB_TEST(fib_test_validate_entry(fei,
5833 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5835 &l99_eos_o_10_10_10_1,
5837 "24001/eos LB 2 buckets via: "
5838 "label 99 over 10.10.10.1, "
5839 "adj over 10.10.11.2");
5841 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5842 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5843 "No more MPLS FIB entries => table removed");
5846 * add another via-entry for the recursive
5848 fib_prefix_t pfx_1_1_1_2_s_32 = {
5850 .fp_proto = FIB_PROTOCOL_IP4,
5852 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5855 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5856 .type = FT_LB_LABEL_O_ADJ,
5858 .adj = ai_mpls_10_10_10_1,
5863 mpls_label_t *l101 = NULL;
5864 vec_add1(l101, 101);
5866 fei = fib_table_entry_update_one_path(fib_index,
5869 FIB_ENTRY_FLAG_NONE,
5872 tm->hw[0]->sw_if_index,
5873 ~0, // invalid fib index
5876 FIB_ROUTE_PATH_FLAG_NONE);
5878 FIB_TEST(fib_test_validate_entry(fei,
5879 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5881 &l101_eos_o_10_10_10_1),
5882 "1.1.1.2/32 LB 1 buckets via: "
5883 "label 101 over 10.10.10.1");
5885 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
5886 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5888 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5890 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5892 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5895 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5896 .type = FT_LB_LABEL_O_LB,
5898 .lb = non_eos_1_1_1_2.dpoi_index,
5903 mpls_label_t *l1601 = NULL;
5904 vec_add1(l1601, 1601);
5906 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5908 fei = fib_table_entry_path_add(fib_index,
5911 FIB_ENTRY_FLAG_NONE,
5913 &pfx_1_1_1_2_s_32.fp_addr,
5918 FIB_ROUTE_PATH_FLAG_NONE);
5920 FIB_TEST(fib_test_validate_entry(fei,
5921 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5923 &l1600_eos_o_1_1_1_1,
5924 &l1601_eos_o_1_1_1_2),
5925 "2.2.2.2/32 LB 2 buckets via: "
5926 "label 1600 via 1.1,1.1, "
5927 "label 16001 via 1.1.1.2");
5930 * update the via-entry so it no longer has an imp-null path.
5931 * the LB for the recursive can use an imp-null
5934 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5936 fei = fib_table_entry_update_one_path(fib_index,
5939 FIB_ENTRY_FLAG_NONE,
5942 tm->hw[1]->sw_if_index,
5943 ~0, // invalid fib index
5946 FIB_ROUTE_PATH_FLAG_NONE);
5948 FIB_TEST(fib_test_validate_entry(fei,
5949 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5952 "1.1.1.2/32 LB 1 buckets via: "
5955 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5956 FIB_TEST(fib_test_validate_entry(fei,
5957 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5959 &l1600_eos_o_1_1_1_1,
5960 &l1601_eos_o_1_1_1_2),
5961 "2.2.2.2/32 LB 2 buckets via: "
5962 "label 1600 via 1.1,1.1, "
5963 "label 16001 via 1.1.1.2");
5966 * update the via-entry so it no longer has labelled paths.
5967 * the LB for the recursive should exclue this via form its LB
5969 fei = fib_table_entry_update_one_path(fib_index,
5972 FIB_ENTRY_FLAG_NONE,
5975 tm->hw[1]->sw_if_index,
5976 ~0, // invalid fib index
5979 FIB_ROUTE_PATH_FLAG_NONE);
5981 FIB_TEST(fib_test_validate_entry(fei,
5982 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5985 "1.1.1.2/32 LB 1 buckets via: "
5988 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5989 FIB_TEST(fib_test_validate_entry(fei,
5990 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5992 &l1600_eos_o_1_1_1_1),
5993 "2.2.2.2/32 LB 1 buckets via: "
5994 "label 1600 via 1.1,1.1");
5996 dpo_reset(&non_eos_1_1_1_1);
5997 dpo_reset(&non_eos_1_1_1_2);
6000 * Add a recursive with no out-labels. We expect to use the IP of the via
6002 fib_prefix_t pfx_2_2_2_3_s_32 = {
6004 .fp_proto = FIB_PROTOCOL_IP4,
6006 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6009 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6011 fib_table_entry_update_one_path(fib_index,
6014 FIB_ENTRY_FLAG_NONE,
6016 &pfx_1_1_1_1_s_32.fp_addr,
6021 FIB_ROUTE_PATH_FLAG_NONE);
6023 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6025 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6028 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6031 .lb = ip_1_1_1_1.dpoi_index,
6035 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6036 FIB_TEST(fib_test_validate_entry(fei,
6037 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6040 "2.2.2.2.3/32 LB 1 buckets via: "
6044 * Add a recursive with an imp-null out-label.
6045 * We expect to use the IP of the via
6047 fib_prefix_t pfx_2_2_2_4_s_32 = {
6049 .fp_proto = FIB_PROTOCOL_IP4,
6051 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6055 fib_table_entry_update_one_path(fib_index,
6058 FIB_ENTRY_FLAG_NONE,
6060 &pfx_1_1_1_1_s_32.fp_addr,
6065 FIB_ROUTE_PATH_FLAG_NONE);
6067 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6068 FIB_TEST(fib_test_validate_entry(fei,
6069 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6072 "2.2.2.2.4/32 LB 1 buckets via: "
6075 dpo_reset(&ip_1_1_1_1);
6078 * Create an entry with a deep label stack
6080 fib_prefix_t pfx_2_2_5_5_s_32 = {
6082 .fp_proto = FIB_PROTOCOL_IP4,
6084 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6087 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6088 .type = FT_LB_LABEL_STACK_O_ADJ,
6089 .label_stack_o_adj = {
6090 .adj = ai_mpls_10_10_11_1,
6091 .label_stack_size = 8,
6093 200, 201, 202, 203, 204, 205, 206, 207
6098 mpls_label_t *label_stack = NULL;
6099 vec_validate(label_stack, 7);
6100 for (ii = 0; ii < 8; ii++)
6102 label_stack[ii] = ii + 200;
6105 fei = fib_table_entry_update_one_path(fib_index,
6108 FIB_ENTRY_FLAG_NONE,
6111 tm->hw[1]->sw_if_index,
6112 ~0, // invalid fib index
6115 FIB_ROUTE_PATH_FLAG_NONE);
6117 FIB_TEST(fib_test_validate_entry(fei,
6118 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6120 &ls_eos_o_10_10_10_1),
6121 "2.2.5.5/32 LB 1 buckets via: "
6123 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6128 fib_table_entry_delete(fib_index,
6132 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6133 FIB_TEST(fib_test_validate_entry(fei,
6134 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6136 &l1600_eos_o_1_1_1_1),
6137 "2.2.2.2/32 LB 1 buckets via: "
6138 "label 1600 via 1.1,1.1");
6140 fib_table_entry_delete(fib_index,
6144 FIB_TEST(fib_test_validate_entry(fei,
6145 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6148 "2.2.2.2/32 LB 1 buckets via: DROP");
6150 fib_table_entry_delete(fib_index,
6153 fib_table_entry_delete(fib_index,
6156 fib_table_entry_delete(fib_index,
6160 adj_unlock(ai_mpls_10_10_10_1);
6161 adj_unlock(ai_mpls_10_10_11_2);
6162 adj_unlock(ai_v4_10_10_11_1);
6163 adj_unlock(ai_v4_10_10_11_2);
6164 adj_unlock(ai_mpls_10_10_11_1);
6166 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6169 local0_pfx.fp_len = 32;
6170 fib_table_entry_delete(fib_index,
6172 FIB_SOURCE_INTERFACE);
6173 local0_pfx.fp_len = 24;
6174 fib_table_entry_delete(fib_index,
6176 FIB_SOURCE_INTERFACE);
6177 local1_pfx.fp_len = 32;
6178 fib_table_entry_delete(fib_index,
6180 FIB_SOURCE_INTERFACE);
6181 local1_pfx.fp_len = 24;
6182 fib_table_entry_delete(fib_index,
6184 FIB_SOURCE_INTERFACE);
6187 * +1 for the drop LB in the MPLS tables.
6189 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6190 "Load-balance resources freed %d of %d",
6191 lb_count+1, pool_elts(load_balance_pool));
6196 #define N_TEST_CHILDREN 4
6197 #define PARENT_INDEX 0
6199 typedef struct fib_node_test_t_
6204 fib_node_back_walk_ctx_t *ctxs;
6208 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6210 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6212 #define FOR_EACH_TEST_CHILD(_tc) \
6213 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
6214 ii < N_TEST_CHILDREN+1; \
6215 ii++, (_tc) = &fib_test_nodes[ii])
6218 fib_test_child_get_node (fib_node_index_t index)
6220 return (&fib_test_nodes[index].node);
6223 static int fib_test_walk_spawns_walks;
6225 static fib_node_back_walk_rc_t
6226 fib_test_child_back_walk_notify (fib_node_t *node,
6227 fib_node_back_walk_ctx_t *ctx)
6229 fib_node_test_t *tc = (fib_node_test_t*) node;
6231 vec_add1(tc->ctxs, *ctx);
6233 if (1 == fib_test_walk_spawns_walks)
6234 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6235 if (2 == fib_test_walk_spawns_walks)
6236 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6237 FIB_WALK_PRIORITY_HIGH, ctx);
6239 return (FIB_NODE_BACK_WALK_CONTINUE);
6243 fib_test_child_last_lock_gone (fib_node_t *node)
6245 fib_node_test_t *tc = (fib_node_test_t *)node;
6251 * The FIB walk's graph node virtual function table
6253 static const fib_node_vft_t fib_test_child_vft = {
6254 .fnv_get = fib_test_child_get_node,
6255 .fnv_last_lock = fib_test_child_last_lock_gone,
6256 .fnv_back_walk = fib_test_child_back_walk_notify,
6260 * the function (that should have been static but isn't so I can do this)
6261 * that processes the walk from the async queue,
6263 f64 fib_walk_process_queues(vlib_main_t * vm,
6265 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6268 fib_test_walk (void)
6270 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6271 fib_node_test_t *tc;
6275 vm = vlib_get_main();
6276 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6279 * init a fake node on which we will add children
6281 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6282 FIB_NODE_TYPE_TEST);
6284 FOR_EACH_TEST_CHILD(tc)
6286 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6287 fib_node_lock(&tc->node);
6290 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6292 FIB_NODE_TYPE_TEST, ii);
6296 * enqueue a walk across the parents children.
6298 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6300 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6301 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6302 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6303 "Parent has %d children pre-walk",
6304 fib_node_list_get_size(PARENT()->fn_children));
6307 * give the walk a large amount of time so it gets to the end
6309 fib_walk_process_queues(vm, 1);
6311 FOR_EACH_TEST_CHILD(tc)
6313 FIB_TEST(1 == vec_len(tc->ctxs),
6314 "%d child visitsed %d times",
6315 ii, vec_len(tc->ctxs));
6318 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6319 "Queue is empty post walk");
6320 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6321 "Parent has %d children post walk",
6322 fib_node_list_get_size(PARENT()->fn_children));
6325 * walk again. should be no increase in the number of visits, since
6326 * the walk will have terminated.
6328 fib_walk_process_queues(vm, 1);
6330 FOR_EACH_TEST_CHILD(tc)
6332 FIB_TEST(0 == vec_len(tc->ctxs),
6333 "%d child visitsed %d times",
6334 ii, vec_len(tc->ctxs));
6338 * schedule a low and hig priority walk. expect the high to be performed
6340 * schedule the high prio walk first so that it is further from the head
6341 * of the dependency list. that way it won't merge with the low one.
6343 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6344 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6346 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6347 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6348 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6349 FIB_WALK_PRIORITY_LOW, &low_ctx);
6351 fib_walk_process_queues(vm, 1);
6353 FOR_EACH_TEST_CHILD(tc)
6355 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6356 "%d child visitsed by high prio walk", ii);
6357 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6358 "%d child visitsed by low prio walk", ii);
6361 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6362 "Queue is empty post prio walk");
6363 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6364 "Parent has %d children post prio walk",
6365 fib_node_list_get_size(PARENT()->fn_children));
6368 * schedule 2 walks of the same priority that can be megred.
6369 * expect that each child is thus visited only once.
6371 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6372 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6374 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6375 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6376 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6377 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6379 fib_walk_process_queues(vm, 1);
6381 FOR_EACH_TEST_CHILD(tc)
6383 FIB_TEST(1 == vec_len(tc->ctxs),
6384 "%d child visitsed %d times during merge walk",
6385 ii, vec_len(tc->ctxs));
6388 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6389 "Queue is empty post merge walk");
6390 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6391 "Parent has %d children post merge walk",
6392 fib_node_list_get_size(PARENT()->fn_children));
6395 * schedule 2 walks of the same priority that cannot be megred.
6396 * expect that each child is thus visited twice and in the order
6397 * in which the walks were scheduled.
6399 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6400 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6402 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6403 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6404 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6405 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6407 fib_walk_process_queues(vm, 1);
6409 FOR_EACH_TEST_CHILD(tc)
6411 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6412 "%d child visitsed by high prio walk", ii);
6413 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6414 "%d child visitsed by low prio walk", ii);
6417 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6418 "Queue is empty post no-merge walk");
6419 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6420 "Parent has %d children post no-merge walk",
6421 fib_node_list_get_size(PARENT()->fn_children));
6424 * schedule a walk that makes one one child progress.
6425 * we do this by giving the queue draining process zero
6426 * time quanta. it's a do..while loop, so it does something.
6428 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6430 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6431 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6432 fib_walk_process_queues(vm, 0);
6434 FOR_EACH_TEST_CHILD(tc)
6436 if (ii == N_TEST_CHILDREN)
6438 FIB_TEST(1 == vec_len(tc->ctxs),
6439 "%d child visitsed %d times in zero quanta walk",
6440 ii, vec_len(tc->ctxs));
6444 FIB_TEST(0 == vec_len(tc->ctxs),
6445 "%d child visitsed %d times in 0 quanta walk",
6446 ii, vec_len(tc->ctxs));
6449 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6450 "Queue is not empty post zero quanta walk");
6451 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6452 "Parent has %d children post zero qunta walk",
6453 fib_node_list_get_size(PARENT()->fn_children));
6458 fib_walk_process_queues(vm, 0);
6460 FOR_EACH_TEST_CHILD(tc)
6462 if (ii >= N_TEST_CHILDREN-1)
6464 FIB_TEST(1 == vec_len(tc->ctxs),
6465 "%d child visitsed %d times in 2nd zero quanta walk",
6466 ii, vec_len(tc->ctxs));
6470 FIB_TEST(0 == vec_len(tc->ctxs),
6471 "%d child visitsed %d times in 2nd 0 quanta walk",
6472 ii, vec_len(tc->ctxs));
6475 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6476 "Queue is not empty post zero quanta walk");
6477 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6478 "Parent has %d children post zero qunta walk",
6479 fib_node_list_get_size(PARENT()->fn_children));
6482 * schedule another walk that will catch-up and merge.
6484 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6485 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6486 fib_walk_process_queues(vm, 1);
6488 FOR_EACH_TEST_CHILD(tc)
6490 if (ii >= N_TEST_CHILDREN-1)
6492 FIB_TEST(2 == vec_len(tc->ctxs),
6493 "%d child visitsed %d times in 2nd zero quanta merge walk",
6494 ii, vec_len(tc->ctxs));
6499 FIB_TEST(1 == vec_len(tc->ctxs),
6500 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6501 ii, vec_len(tc->ctxs));
6505 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6506 "Queue is not empty post 2nd zero quanta merge walk");
6507 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6508 "Parent has %d children post 2nd zero qunta merge walk",
6509 fib_node_list_get_size(PARENT()->fn_children));
6512 * park a async walk in the middle of the list, then have an sync walk catch
6513 * it. same expectations as async catches async.
6515 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6517 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6518 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6520 fib_walk_process_queues(vm, 0);
6521 fib_walk_process_queues(vm, 0);
6523 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6525 FOR_EACH_TEST_CHILD(tc)
6527 if (ii >= N_TEST_CHILDREN-1)
6529 FIB_TEST(2 == vec_len(tc->ctxs),
6530 "%d child visitsed %d times in sync catches async walk",
6531 ii, vec_len(tc->ctxs));
6536 FIB_TEST(1 == vec_len(tc->ctxs),
6537 "%d child visitsed %d times in sync catches async walk",
6538 ii, vec_len(tc->ctxs));
6542 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6543 "Queue is not empty post 2nd zero quanta merge walk");
6544 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6545 "Parent has %d children post 2nd zero qunta merge walk",
6546 fib_node_list_get_size(PARENT()->fn_children));
6549 * make the parent a child of one of its children, thus inducing a routing loop.
6551 fib_test_nodes[PARENT_INDEX].sibling =
6552 fib_node_child_add(FIB_NODE_TYPE_TEST,
6553 1, // the first child
6558 * execute a sync walk from the parent. each child visited spawns more sync
6559 * walks. we expect the walk to terminate.
6561 fib_test_walk_spawns_walks = 1;
6563 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6565 FOR_EACH_TEST_CHILD(tc)
6568 * child 1 - which is last in the list - has the loop.
6569 * the other children a re thus visitsed first. the we meet
6570 * child 1. we go round the loop again, visting the other children.
6571 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6576 FIB_TEST(1 == vec_len(tc->ctxs),
6577 "child %d visitsed %d times during looped sync walk",
6578 ii, vec_len(tc->ctxs));
6582 FIB_TEST(2 == vec_len(tc->ctxs),
6583 "child %d visitsed %d times during looped sync walk",
6584 ii, vec_len(tc->ctxs));
6588 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6589 "Parent has %d children post sync loop walk",
6590 fib_node_list_get_size(PARENT()->fn_children));
6593 * the walk doesn't reach the max depth because the infra knows that sync
6594 * meets sync implies a loop and bails early.
6596 FIB_TEST(high_ctx.fnbw_depth == 9,
6597 "Walk context depth %d post sync loop walk",
6598 high_ctx.fnbw_depth);
6601 * execute an async walk of the graph loop, with each child spawns sync walks
6603 high_ctx.fnbw_depth = 0;
6604 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6605 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6607 fib_walk_process_queues(vm, 1);
6609 FOR_EACH_TEST_CHILD(tc)
6612 * we don't really care how many times the children are visisted, as long as
6613 * it is more than once.
6615 FIB_TEST(1 <= vec_len(tc->ctxs),
6616 "child %d visitsed %d times during looped aync spawns sync walk",
6617 ii, vec_len(tc->ctxs));
6622 * execute an async walk of the graph loop, with each child spawns async walks
6624 fib_test_walk_spawns_walks = 2;
6625 high_ctx.fnbw_depth = 0;
6626 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6627 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6629 fib_walk_process_queues(vm, 1);
6631 FOR_EACH_TEST_CHILD(tc)
6634 * we don't really care how many times the children are visisted, as long as
6635 * it is more than once.
6637 FIB_TEST(1 <= vec_len(tc->ctxs),
6638 "child %d visitsed %d times during looped async spawns async walk",
6639 ii, vec_len(tc->ctxs));
6644 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6645 1, // the first child
6646 fib_test_nodes[PARENT_INDEX].sibling);
6651 FOR_EACH_TEST_CHILD(tc)
6653 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6655 fib_node_deinit(&tc->node);
6656 fib_node_unlock(&tc->node);
6658 fib_node_deinit(PARENT());
6661 * The parent will be destroyed when the last lock on it goes.
6662 * this test ensures all the walk objects are unlocking it.
6664 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6665 "Parent was destroyed");
6673 const mpls_label_t deag_label = 50;
6674 const u32 lfib_index = 0;
6675 const u32 fib_index = 0;
6676 dpo_id_t dpo = DPO_INVALID;
6677 const dpo_id_t *dpo1;
6678 fib_node_index_t lfe;
6682 adj_index_t ai_mpls_10_10_10_1;
6685 lb_count = pool_elts(load_balance_pool);
6687 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6691 * MPLS enable an interface so we get the MPLS table created
6693 mpls_sw_interface_enable_disable(&mpls_main,
6694 tm->hw[0]->sw_if_index,
6697 ip46_address_t nh_10_10_10_1 = {
6698 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6700 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6703 tm->hw[0]->sw_if_index);
6706 * Test the specials stack properly.
6708 fib_prefix_t exp_null_v6_pfx = {
6709 .fp_proto = FIB_PROTOCOL_MPLS,
6711 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6712 .fp_payload_proto = DPO_PROTO_IP6,
6714 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
6715 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
6717 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
6718 format_mpls_eos_bit, MPLS_EOS);
6719 fib_entry_contribute_forwarding(lfe,
6720 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6722 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6723 lkd = lookup_dpo_get(dpo1->dpoi_index);
6725 FIB_TEST((fib_index == lkd->lkd_fib_index),
6726 "%U/%U is deag in %d %U",
6727 format_mpls_unicast_label, deag_label,
6728 format_mpls_eos_bit, MPLS_EOS,
6730 format_dpo_id, &dpo, 0);
6731 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6732 "%U/%U is dst deag",
6733 format_mpls_unicast_label, deag_label,
6734 format_mpls_eos_bit, MPLS_EOS);
6735 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
6736 "%U/%U is lookup in interface's table",
6737 format_mpls_unicast_label, deag_label,
6738 format_mpls_eos_bit, MPLS_EOS);
6739 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
6740 "%U/%U is %U dst deag",
6741 format_mpls_unicast_label, deag_label,
6742 format_mpls_eos_bit, MPLS_EOS,
6743 format_dpo_proto, lkd->lkd_proto);
6747 * A route deag route for EOS
6749 fib_prefix_t pfx = {
6750 .fp_proto = FIB_PROTOCOL_MPLS,
6752 .fp_label = deag_label,
6753 .fp_payload_proto = DPO_PROTO_IP4,
6755 lfe = fib_table_entry_path_add(lfib_index,
6758 FIB_ENTRY_FLAG_NONE,
6765 FIB_ROUTE_PATH_FLAG_NONE);
6767 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6769 format_mpls_unicast_label, deag_label,
6770 format_mpls_eos_bit, MPLS_EOS);
6772 fib_entry_contribute_forwarding(lfe,
6773 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6775 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6776 lkd = lookup_dpo_get(dpo1->dpoi_index);
6778 FIB_TEST((fib_index == lkd->lkd_fib_index),
6779 "%U/%U is deag in %d %U",
6780 format_mpls_unicast_label, deag_label,
6781 format_mpls_eos_bit, MPLS_EOS,
6783 format_dpo_id, &dpo, 0);
6784 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6785 "%U/%U is dst deag",
6786 format_mpls_unicast_label, deag_label,
6787 format_mpls_eos_bit, MPLS_EOS);
6788 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
6789 "%U/%U is %U dst deag",
6790 format_mpls_unicast_label, deag_label,
6791 format_mpls_eos_bit, MPLS_EOS,
6792 format_dpo_proto, lkd->lkd_proto);
6794 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6796 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6798 "%U/%U not present",
6799 format_mpls_unicast_label, deag_label,
6800 format_mpls_eos_bit, MPLS_EOS);
6803 * A route deag route for non-EOS
6805 pfx.fp_eos = MPLS_NON_EOS;
6806 lfe = fib_table_entry_path_add(lfib_index,
6809 FIB_ENTRY_FLAG_NONE,
6816 FIB_ROUTE_PATH_FLAG_NONE);
6818 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
6820 format_mpls_unicast_label, deag_label,
6821 format_mpls_eos_bit, MPLS_NON_EOS);
6823 fib_entry_contribute_forwarding(lfe,
6824 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6826 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
6827 lkd = lookup_dpo_get(dpo1->dpoi_index);
6829 FIB_TEST((fib_index == lkd->lkd_fib_index),
6830 "%U/%U is deag in %d %U",
6831 format_mpls_unicast_label, deag_label,
6832 format_mpls_eos_bit, MPLS_NON_EOS,
6834 format_dpo_id, &dpo, 0);
6835 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
6836 "%U/%U is dst deag",
6837 format_mpls_unicast_label, deag_label,
6838 format_mpls_eos_bit, MPLS_NON_EOS);
6840 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
6841 "%U/%U is %U dst deag",
6842 format_mpls_unicast_label, deag_label,
6843 format_mpls_eos_bit, MPLS_NON_EOS,
6844 format_dpo_proto, lkd->lkd_proto);
6846 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
6848 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
6850 "%U/%U not present",
6851 format_mpls_unicast_label, deag_label,
6852 format_mpls_eos_bit, MPLS_EOS);
6859 fib_prefix_t pfx_1200 = {
6861 .fp_proto = FIB_PROTOCOL_MPLS,
6863 .fp_eos = MPLS_NON_EOS,
6865 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
6866 .type = FT_LB_LABEL_STACK_O_ADJ,
6867 .label_stack_o_adj = {
6868 .adj = ai_mpls_10_10_10_1,
6869 .label_stack_size = 4,
6873 .eos = MPLS_NON_EOS,
6876 dpo_id_t neos_1200 = DPO_INVALID;
6877 dpo_id_t ip_1200 = DPO_INVALID;
6878 mpls_label_t *l200 = NULL;
6879 vec_add1(l200, 200);
6880 vec_add1(l200, 300);
6881 vec_add1(l200, 400);
6882 vec_add1(l200, 500);
6884 lfe = fib_table_entry_update_one_path(fib_index,
6887 FIB_ENTRY_FLAG_NONE,
6890 tm->hw[0]->sw_if_index,
6891 ~0, // invalid fib index
6894 FIB_ROUTE_PATH_FLAG_NONE);
6896 FIB_TEST(fib_test_validate_entry(lfe,
6897 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6899 &neos_o_10_10_10_1),
6900 "1200/0 LB 1 buckets via: "
6904 * A recursive route via the MPLS x-connect
6906 fib_prefix_t pfx_2_2_2_3_s_32 = {
6908 .fp_proto = FIB_PROTOCOL_IP4,
6910 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6913 fib_route_path_t *rpaths = NULL, rpath = {
6914 .frp_proto = FIB_PROTOCOL_MPLS,
6915 .frp_local_label = 1200,
6916 .frp_sw_if_index = ~0, // recurive
6917 .frp_fib_index = 0, // Default MPLS fib
6919 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6920 .frp_label_stack = NULL,
6922 vec_add1(rpaths, rpath);
6924 fib_table_entry_path_add2(fib_index,
6927 FIB_ENTRY_FLAG_NONE,
6931 * A labelled recursive route via the MPLS x-connect
6933 fib_prefix_t pfx_2_2_2_4_s_32 = {
6935 .fp_proto = FIB_PROTOCOL_IP4,
6937 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6940 mpls_label_t *l999 = NULL;
6941 vec_add1(l999, 999);
6942 rpaths[0].frp_label_stack = l999,
6944 fib_table_entry_path_add2(fib_index,
6947 FIB_ENTRY_FLAG_NONE,
6950 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
6951 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6953 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
6954 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6957 fib_test_lb_bucket_t ip_o_1200 = {
6960 .lb = ip_1200.dpoi_index,
6963 fib_test_lb_bucket_t mpls_o_1200 = {
6964 .type = FT_LB_LABEL_O_LB,
6966 .lb = neos_1200.dpoi_index,
6972 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6973 FIB_TEST(fib_test_validate_entry(lfe,
6974 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6977 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
6978 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6979 FIB_TEST(fib_test_validate_entry(lfe,
6980 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6983 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
6985 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
6986 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
6987 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
6989 dpo_reset(&neos_1200);
6990 dpo_reset(&ip_1200);
6993 * A recursive via a label that does not exist
6995 fib_test_lb_bucket_t bucket_drop = {
6996 .type = FT_LB_SPECIAL,
6998 .adj = DPO_PROTO_MPLS,
7002 rpaths[0].frp_label_stack = NULL;
7003 lfe = fib_table_entry_path_add2(fib_index,
7006 FIB_ENTRY_FLAG_NONE,
7009 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7010 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7012 ip_o_1200.lb.lb = ip_1200.dpoi_index;
7014 FIB_TEST(fib_test_validate_entry(lfe,
7015 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7018 "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
7019 lfe = fib_table_lookup(fib_index, &pfx_1200);
7020 FIB_TEST(fib_test_validate_entry(lfe,
7021 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7024 "2.2.2.4/32 LB 1 buckets via: ip4-DROP");
7026 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7028 dpo_reset(&ip_1200);
7033 mpls_sw_interface_enable_disable(&mpls_main,
7034 tm->hw[0]->sw_if_index,
7037 FIB_TEST(lb_count == pool_elts(load_balance_pool),
7038 "Load-balance resources freed %d of %d",
7039 lb_count, pool_elts(load_balance_pool));
7044 static clib_error_t *
7045 fib_test (vlib_main_t * vm,
7046 unformat_input_t * input,
7047 vlib_cli_command_t * cmd_arg)
7052 fib_test_mk_intf(4);
7054 if (unformat (input, "ip"))
7056 res += fib_test_v4();
7057 res += fib_test_v6();
7059 else if (unformat (input, "label"))
7061 res += fib_test_label();
7063 else if (unformat (input, "ae"))
7065 res += fib_test_ae();
7067 else if (unformat (input, "lfib"))
7071 else if (unformat (input, "walk"))
7073 res += fib_test_walk();
7078 * These walk UT aren't run as part of the full suite, since the
7079 * fib-walk process must be disabled in order for the tests to work
7083 res += fib_test_v4();
7084 res += fib_test_v6();
7085 res += fib_test_ae();
7086 res += fib_test_label();
7092 return clib_error_return(0, "FIB Unit Test Failed");
7100 VLIB_CLI_COMMAND (test_fib_command, static) = {
7102 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
7103 .function = fib_test,
7107 fib_test_init (vlib_main_t *vm)
7112 VLIB_INIT_FUNCTION (fib_test_init);