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>
27 #include <vnet/bfd/bfd_main.h>
29 #include <vnet/mpls/mpls.h>
31 #include <vnet/fib/fib_path_list.h>
32 #include <vnet/fib/fib_entry_src.h>
33 #include <vnet/fib/fib_walk.h>
34 #include <vnet/fib/fib_node_list.h>
35 #include <vnet/fib/fib_urpf_list.h>
38 * Add debugs for passing tests
40 static int fib_test_do_debug;
42 #define FIB_TEST_I(_cond, _comment, _args...) \
44 int _evald = (_cond); \
46 fformat(stderr, "FAIL:%d: " _comment "\n", \
49 if (fib_test_do_debug) \
50 fformat(stderr, "PASS:%d: " _comment "\n", \
55 #define FIB_TEST(_cond, _comment, _args...) \
57 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
59 ASSERT(!("FAIL: " _comment)); \
64 * A 'i'm not fussed is this is not efficient' store of test data
66 typedef struct test_main_t_ {
70 u32 hw_if_indicies[4];
74 vnet_hw_interface_t * hw[4];
77 static test_main_t test_main;
79 /* fake ethernet device class, distinct from "fake-ethX" */
80 static u8 * format_test_interface_name (u8 * s, va_list * args)
82 u32 dev_instance = va_arg (*args, u32);
83 return format (s, "test-eth%d", dev_instance);
86 static uword dummy_interface_tx (vlib_main_t * vm,
87 vlib_node_runtime_t * node,
90 clib_warning ("you shouldn't be here, leaking buffers...");
91 return frame->n_vectors;
95 test_interface_admin_up_down (vnet_main_t * vnm,
99 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
100 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
101 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
105 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
106 .name = "Test interface",
107 .format_device_name = format_test_interface_name,
108 .tx_function = dummy_interface_tx,
109 .admin_up_down_function = test_interface_admin_up_down,
112 static u8 *hw_address;
115 fib_test_mk_intf (u32 ninterfaces)
117 clib_error_t * error = NULL;
118 test_main_t *tm = &test_main;
122 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
127 vec_add1(hw_address, byte);
130 for (i = 0; i < ninterfaces; i++)
134 error = ethernet_register_interface(vnet_get_main(),
135 test_interface_device_class.index,
138 &tm->hw_if_indicies[i],
139 /* flag change */ 0);
141 FIB_TEST((NULL == error), "ADD interface %d", i);
143 error = vnet_hw_interface_set_flags(vnet_get_main(),
144 tm->hw_if_indicies[i],
145 VNET_HW_INTERFACE_FLAG_LINK_UP);
146 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
147 tm->hw_if_indicies[i]);
148 vec_validate (ip4_main.fib_index_by_sw_if_index,
149 tm->hw[i]->sw_if_index);
150 vec_validate (ip6_main.fib_index_by_sw_if_index,
151 tm->hw[i]->sw_if_index);
152 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
153 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
155 error = vnet_sw_interface_set_flags(vnet_get_main(),
156 tm->hw[i]->sw_if_index,
157 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
158 FIB_TEST((NULL == error), "UP interface %d", i);
161 * re-eval after the inevitable realloc
163 for (i = 0; i < ninterfaces; i++)
165 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
166 tm->hw_if_indicies[i]);
172 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
174 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
175 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
176 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
177 fib_table_lookup(fib_index, (_via_prefix))); \
178 FIB_TEST(!dpo_cmp(_via_dpo, \
179 load_balance_get_bucket(_rec_dpo->dpoi_index, \
181 "%U is recursive via %U", \
182 format_fib_prefix, (_rec_prefix), \
183 format_fib_prefix, _via_prefix); \
186 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
188 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
189 fib_table_lookup_exact_match(fib_index, (_prefix))); \
190 const dpo_id_t *_dpo1 = \
191 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
192 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
193 format_dpo_type, _dpo1->dpoi_type); \
194 FIB_TEST((_ai == _dpo1->dpoi_index), \
195 "%U bucket %d resolves via %U", \
196 format_fib_prefix, (_prefix), \
198 format_dpo_id, _dpo1, 0); \
201 #define FIB_TEST_RPF(_cond, _comment, _args...) \
203 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
209 fib_test_urpf_is_equal (fib_node_index_t fei,
210 fib_forward_chain_type_t fct,
213 dpo_id_t dpo = DPO_INVALID;
214 fib_urpf_list_t *urpf;
221 fib_entry_contribute_forwarding(fei, fct, &dpo);
222 ui = load_balance_get_urpf(dpo.dpoi_index);
224 urpf = fib_urpf_list_get(ui);
226 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
227 "RPF:%U len %d == %d",
228 format_fib_urpf_list, ui,
229 num, vec_len(urpf->furpf_itfs));
230 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
231 "RPF:%U check-size %d == %d",
232 format_fib_urpf_list, ui,
233 num, vec_len(urpf->furpf_itfs));
235 for (ii = 0; ii < num; ii++)
237 adj_index_t ai = va_arg(ap, adj_index_t);
239 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
240 "RPF:%d item:%d - %d == %d",
241 ui, ii, ai, urpf->furpf_itfs[ii]);
242 FIB_TEST_RPF(fib_urpf_check(ui, ai),
255 fib_test_build_rewrite (u8 *eth_addr)
259 vec_validate(rewrite, 13);
261 memcpy(rewrite, eth_addr, 6);
262 memcpy(rewrite+6, eth_addr, 6);
267 typedef enum fib_test_lb_bucket_type_t_ {
269 FT_LB_LABEL_STACK_O_ADJ,
274 } fib_test_lb_bucket_type_t;
276 typedef struct fib_test_lb_bucket_t_ {
277 fib_test_lb_bucket_type_t type;
291 mpls_label_t label_stack[8];
316 } fib_test_lb_bucket_t;
318 #define FIB_TEST_LB(_cond, _comment, _args...) \
320 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
326 fib_test_validate_lb_v (const load_balance_t *lb,
333 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
335 for (bucket = 0; bucket < n_buckets; bucket++)
337 const fib_test_lb_bucket_t *exp;
339 exp = va_arg(ap, fib_test_lb_bucket_t*);
340 dpo = load_balance_get_bucket_i(lb, bucket);
344 case FT_LB_LABEL_STACK_O_ADJ:
346 const mpls_label_dpo_t *mld;
350 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
351 "bucket %d stacks on %U",
353 format_dpo_type, dpo->dpoi_type);
355 mld = mpls_label_dpo_get(dpo->dpoi_index);
357 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
361 for (ii = 0; ii < mld->mld_n_labels; ii++)
363 hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
364 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
365 exp->label_stack_o_adj.label_stack[ii]),
366 "bucket %d stacks on label %d",
368 exp->label_stack_o_adj.label_stack[ii]);
370 if (ii == mld->mld_n_labels-1)
372 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
373 exp->label_o_adj.eos),
374 "bucket %d stacks on label %d %U!=%U",
376 exp->label_stack_o_adj.label_stack[ii],
377 format_mpls_eos_bit, exp->label_o_adj.eos,
378 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
382 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
383 "bucket %d stacks on label %d %U",
385 exp->label_stack_o_adj.label_stack[ii],
386 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
390 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
391 "bucket %d label stacks on %U",
393 format_dpo_type, mld->mld_dpo.dpoi_type);
395 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
396 "bucket %d label stacks on adj %d",
398 exp->label_stack_o_adj.adj);
401 case FT_LB_LABEL_O_ADJ:
403 const mpls_label_dpo_t *mld;
405 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
406 "bucket %d stacks on %U",
408 format_dpo_type, dpo->dpoi_type);
410 mld = mpls_label_dpo_get(dpo->dpoi_index);
411 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
413 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
414 exp->label_o_adj.label),
415 "bucket %d stacks on label %d",
417 exp->label_o_adj.label);
419 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
420 exp->label_o_adj.eos),
421 "bucket %d stacks on label %d %U",
423 exp->label_o_adj.label,
424 format_mpls_eos_bit, exp->label_o_adj.eos);
426 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
427 "bucket %d label stacks on %U",
429 format_dpo_type, mld->mld_dpo.dpoi_type);
431 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
432 "bucket %d label stacks on adj %d",
434 exp->label_o_adj.adj);
437 case FT_LB_LABEL_O_LB:
439 const mpls_label_dpo_t *mld;
442 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
443 "bucket %d stacks on %U",
445 format_dpo_type, dpo->dpoi_type);
447 mld = mpls_label_dpo_get(dpo->dpoi_index);
448 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
450 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
452 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
453 exp->label_o_lb.label),
454 "bucket %d stacks on label %d",
456 exp->label_o_lb.label);
458 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
459 exp->label_o_lb.eos),
460 "bucket %d stacks on label %d %U",
462 exp->label_o_lb.label,
463 format_mpls_eos_bit, exp->label_o_lb.eos);
465 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
466 "bucket %d label stacks on %U",
468 format_dpo_type, mld->mld_dpo.dpoi_type);
470 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
471 "bucket %d label stacks on LB %d",
477 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
478 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
479 "bucket %d stacks on %U",
481 format_dpo_type, dpo->dpoi_type);
482 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
483 "bucket %d stacks on adj %d",
488 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
489 "bucket %d stacks on %U",
491 format_dpo_type, dpo->dpoi_type);
492 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
493 "bucket %d stacks on lb %d",
498 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
499 "bucket %d stacks on %U",
501 format_dpo_type, dpo->dpoi_type);
502 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
503 "bucket %d stacks on drop %d",
513 fib_test_validate_entry (fib_node_index_t fei,
514 fib_forward_chain_type_t fct,
518 dpo_id_t dpo = DPO_INVALID;
519 const load_balance_t *lb;
526 va_start(ap, n_buckets);
528 fib_entry_get_prefix(fei, &pfx);
529 fib_index = fib_entry_get_fib_index(fei);
530 fib_entry_contribute_forwarding(fei, fct, &dpo);
532 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
534 format_dpo_type, dpo.dpoi_type);
535 lb = load_balance_get(dpo.dpoi_index);
537 res = fib_test_validate_lb_v(lb, n_buckets, ap);
540 * ensure that the LB contributed by the entry is the
541 * same as the LB in the forwarding tables
543 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
545 switch (pfx.fp_proto)
547 case FIB_PROTOCOL_IP4:
548 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
550 case FIB_PROTOCOL_IP6:
551 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
553 case FIB_PROTOCOL_MPLS:
555 mpls_unicast_header_t hdr = {
556 .label_exp_s_ttl = 0,
559 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
560 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
561 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
563 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
569 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
570 "Contributed LB = FW LB: %U\n %U",
571 format_load_balance, fw_lbi, 0,
572 format_load_balance, dpo.dpoi_index, 0);
586 * In the default table check for the presence and correct forwarding
587 * of the special entries
589 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
590 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
591 const ip_adjacency_t *adj;
592 const load_balance_t *lb;
598 ip46_address_t nh_10_10_10_1 = {
599 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
602 ip46_address_t nh_10_10_10_2 = {
603 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
608 /* Find or create FIB table 11 */
609 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
611 for (ii = 0; ii < 4; ii++)
613 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
616 fib_prefix_t pfx_0_0_0_0_s_0 = {
618 .fp_proto = FIB_PROTOCOL_IP4,
628 .fp_proto = FIB_PROTOCOL_IP4,
636 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
638 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
639 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
640 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
641 "Default route is DROP");
644 fei = fib_table_lookup(fib_index, &pfx);
645 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
646 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
647 "all 0s route is DROP");
649 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
651 fei = fib_table_lookup(fib_index, &pfx);
652 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
653 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
654 "all 1s route is DROP");
656 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
658 fei = fib_table_lookup(fib_index, &pfx);
659 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
660 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
661 "all-mcast route is DROP");
663 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
665 fei = fib_table_lookup(fib_index, &pfx);
666 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
667 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
668 "class-e route is DROP");
671 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
672 * all of which are special sourced and so none of which share path-lists.
673 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
674 * table, and 4 path-lists in the v6 MFIB table
678 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
679 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
680 fib_path_list_pool_size());
681 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
682 fib_entry_pool_size());
685 * add interface routes.
686 * validate presence of /24 attached and /32 recieve.
687 * test for the presence of the receive address in the glean and local adj
689 fib_prefix_t local_pfx = {
691 .fp_proto = FIB_PROTOCOL_IP4,
694 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
699 fib_table_entry_update_one_path(fib_index, &local_pfx,
700 FIB_SOURCE_INTERFACE,
701 (FIB_ENTRY_FLAG_CONNECTED |
702 FIB_ENTRY_FLAG_ATTACHED),
705 tm->hw[0]->sw_if_index,
706 ~0, // invalid fib index
709 FIB_ROUTE_PATH_FLAG_NONE);
710 fei = fib_table_lookup(fib_index, &local_pfx);
711 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
712 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
713 fib_entry_get_flags(fei)),
714 "Flags set on attached interface");
716 ai = fib_entry_get_adj(fei);
717 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
719 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
720 "attached interface adj is glean");
721 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
722 &adj->sub_type.glean.receive_addr)),
723 "attached interface adj is receive ok");
725 local_pfx.fp_len = 32;
726 fib_table_entry_update_one_path(fib_index, &local_pfx,
727 FIB_SOURCE_INTERFACE,
728 (FIB_ENTRY_FLAG_CONNECTED |
729 FIB_ENTRY_FLAG_LOCAL),
732 tm->hw[0]->sw_if_index,
733 ~0, // invalid fib index
736 FIB_ROUTE_PATH_FLAG_NONE);
737 fei = fib_table_lookup(fib_index, &local_pfx);
738 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
739 fib_entry_get_flags(fei)),
740 "Flags set on local interface");
742 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
744 dpo = fib_entry_contribute_ip_forwarding(fei);
745 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
746 "RPF list for local length 0");
747 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
748 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
749 "local interface adj is local");
750 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
752 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
754 "local interface adj is receive ok");
756 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
758 FIB_SOURCE_INTERFACE)),
759 "2 Interface Source'd prefixes");
762 * +2 interface routes +2 non-shared path-lists
764 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
765 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
766 fib_path_list_pool_size());
767 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
768 fib_entry_pool_size());
771 * Modify the default route to be via an adj not yet known.
772 * this sources the defalut route with the API source, which is
773 * a higher preference to the DEFAULT_ROUTE source
775 pfx.fp_addr.ip4.as_u32 = 0;
777 fib_table_entry_path_add(fib_index, &pfx,
782 tm->hw[0]->sw_if_index,
783 ~0, // invalid fib index
786 FIB_ROUTE_PATH_FLAG_NONE);
787 fei = fib_table_lookup(fib_index, &pfx);
788 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
789 "Flags set on API route");
791 FIB_TEST((fei == dfrt), "default route same index");
792 ai = fib_entry_get_adj(fei);
793 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
795 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
796 "adj is incomplete");
797 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
798 "adj nbr next-hop ok");
799 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
802 "1 API Source'd prefixes");
805 * find the adj in the shared db
807 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
810 tm->hw[0]->sw_if_index);
811 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
812 adj_unlock(locked_ai);
815 * +1 shared path-list
817 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
818 fib_path_list_db_size());
819 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
820 fib_path_list_pool_size());
821 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
822 fib_entry_pool_size());
825 * remove the API source from the default route. We expected
826 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
828 pfx.fp_addr.ip4.as_u32 = 0;
830 fib_table_entry_path_remove(fib_index, &pfx,
834 tm->hw[0]->sw_if_index,
835 ~0, // non-recursive path, so no FIB index
837 FIB_ROUTE_PATH_FLAG_NONE);
839 fei = fib_table_lookup(fib_index, &pfx);
841 FIB_TEST((fei == dfrt), "default route same index");
842 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
843 "Default route is DROP");
846 * -1 shared-path-list
848 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
849 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
850 fib_path_list_pool_size());
851 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
852 fib_entry_pool_size());
855 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
857 fib_prefix_t pfx_10_10_10_1_s_32 = {
859 .fp_proto = FIB_PROTOCOL_IP4,
862 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
865 fib_prefix_t pfx_10_10_10_2_s_32 = {
867 .fp_proto = FIB_PROTOCOL_IP4,
870 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
873 fib_prefix_t pfx_11_11_11_11_s_32 = {
875 .fp_proto = FIB_PROTOCOL_IP4,
878 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
882 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
885 ip46_address_t nh_12_12_12_12 = {
886 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
888 adj_index_t ai_12_12_12_12;
891 * Add a route via an incomplete ADJ. then complete the ADJ
892 * Expect the route LB is updated to use complete adj type.
894 fei = fib_table_entry_update_one_path(fib_index,
895 &pfx_11_11_11_11_s_32,
897 FIB_ENTRY_FLAG_ATTACHED,
899 &pfx_10_10_10_1_s_32.fp_addr,
900 tm->hw[0]->sw_if_index,
901 ~0, // invalid fib index
904 FIB_ROUTE_PATH_FLAG_NONE);
906 dpo = fib_entry_contribute_ip_forwarding(fei);
907 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
908 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
909 "11.11.11.11/32 via incomplete adj");
911 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
913 &pfx_10_10_10_1_s_32.fp_addr,
914 tm->hw[0]->sw_if_index);
915 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
916 adj = adj_get(ai_01);
917 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
918 "adj is incomplete");
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");
923 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
924 fib_test_build_rewrite(eth_addr));
925 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
927 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
928 &adj->sub_type.nbr.next_hop)),
929 "adj nbr next-hop ok");
930 ai = fib_entry_get_adj(fei);
931 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
933 dpo = fib_entry_contribute_ip_forwarding(fei);
934 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
935 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
936 "11.11.11.11/32 via complete adj");
937 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
938 tm->hw[0]->sw_if_index),
939 "RPF list for adj-fib contains adj");
941 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
944 tm->hw[1]->sw_if_index);
945 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
946 adj = adj_get(ai_12_12_12_12);
947 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
948 "adj is incomplete");
949 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
950 &adj->sub_type.nbr.next_hop)),
951 "adj nbr next-hop ok");
952 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
953 fib_test_build_rewrite(eth_addr));
954 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
960 fei = fib_table_entry_update_one_path(fib_index,
961 &pfx_10_10_10_1_s_32,
963 FIB_ENTRY_FLAG_ATTACHED,
965 &pfx_10_10_10_1_s_32.fp_addr,
966 tm->hw[0]->sw_if_index,
967 ~0, // invalid fib index
970 FIB_ROUTE_PATH_FLAG_NONE);
971 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
972 "Flags set on adj-fib");
973 ai = fib_entry_get_adj(fei);
974 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
976 fib_table_entry_path_remove(fib_index,
977 &pfx_11_11_11_11_s_32,
980 &pfx_10_10_10_1_s_32.fp_addr,
981 tm->hw[0]->sw_if_index,
982 ~0, // invalid fib index
984 FIB_ROUTE_PATH_FLAG_NONE);
988 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
990 &pfx_10_10_10_2_s_32.fp_addr,
991 tm->hw[0]->sw_if_index);
992 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
993 adj = adj_get(ai_02);
994 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
995 "adj is incomplete");
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");
1000 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1001 fib_test_build_rewrite(eth_addr));
1002 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1004 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1005 &adj->sub_type.nbr.next_hop)),
1006 "adj nbr next-hop ok");
1007 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1009 fib_table_entry_update_one_path(fib_index,
1010 &pfx_10_10_10_2_s_32,
1012 FIB_ENTRY_FLAG_ATTACHED,
1014 &pfx_10_10_10_2_s_32.fp_addr,
1015 tm->hw[0]->sw_if_index,
1016 ~0, // invalid fib index
1019 FIB_ROUTE_PATH_FLAG_NONE);
1021 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1022 ai = fib_entry_get_adj(fei);
1023 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1026 * +2 adj-fibs, and their non-shared path-lists
1028 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1029 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1030 fib_path_list_pool_size());
1031 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1032 fib_entry_pool_size());
1035 * Add 2 routes via the first ADJ. ensure path-list sharing
1037 fib_prefix_t pfx_1_1_1_1_s_32 = {
1039 .fp_proto = FIB_PROTOCOL_IP4,
1042 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1046 fib_table_entry_path_add(fib_index,
1049 FIB_ENTRY_FLAG_NONE,
1052 tm->hw[0]->sw_if_index,
1053 ~0, // invalid fib index
1056 FIB_ROUTE_PATH_FLAG_NONE);
1057 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1058 ai = fib_entry_get_adj(fei);
1059 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1062 * +1 entry and a shared path-list
1064 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1065 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1066 fib_path_list_pool_size());
1067 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1068 fib_entry_pool_size());
1071 fib_prefix_t pfx_1_1_2_0_s_24 = {
1073 .fp_proto = FIB_PROTOCOL_IP4,
1075 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1079 fib_table_entry_path_add(fib_index,
1082 FIB_ENTRY_FLAG_NONE,
1085 tm->hw[0]->sw_if_index,
1086 ~0, // invalid fib index
1089 FIB_ROUTE_PATH_FLAG_NONE);
1090 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1091 ai = fib_entry_get_adj(fei);
1092 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1097 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1098 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1099 fib_path_list_pool_size());
1100 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1101 fib_entry_pool_size());
1104 * modify 1.1.2.0/24 to use multipath.
1106 fib_table_entry_path_add(fib_index,
1109 FIB_ENTRY_FLAG_NONE,
1112 tm->hw[0]->sw_if_index,
1113 ~0, // invalid fib index
1116 FIB_ROUTE_PATH_FLAG_NONE);
1117 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1118 dpo = fib_entry_contribute_ip_forwarding(fei);
1119 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1120 1, tm->hw[0]->sw_if_index),
1121 "RPF list for 1.1.2.0/24 contains both adjs");
1123 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1124 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1125 FIB_TEST((ai_01 == dpo1->dpoi_index),
1126 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1127 ai_01, dpo1->dpoi_index);
1129 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1130 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1131 FIB_TEST((ai_02 == dpo1->dpoi_index),
1132 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1135 * +1 shared-pathlist
1137 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1138 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1139 fib_path_list_pool_size());
1140 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1141 fib_entry_pool_size());
1146 fib_table_entry_path_remove(fib_index,
1151 tm->hw[0]->sw_if_index,
1154 FIB_ROUTE_PATH_FLAG_NONE);
1155 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1156 dpo = fib_entry_contribute_ip_forwarding(fei);
1157 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1158 1, tm->hw[0]->sw_if_index),
1159 "RPF list for 1.1.2.0/24 contains one adj");
1161 ai = fib_entry_get_adj(fei);
1162 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1165 * +1 shared-pathlist
1167 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1168 fib_path_list_db_size());
1169 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1170 fib_path_list_pool_size());
1171 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1172 fib_entry_pool_size());
1175 * Add 2 recursive routes:
1176 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1177 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1179 fib_prefix_t bgp_100_pfx = {
1181 .fp_proto = FIB_PROTOCOL_IP4,
1183 /* 100.100.100.100/32 */
1184 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1188 ip46_address_t nh_1_1_1_1 = {
1189 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1192 fei = fib_table_entry_path_add(fib_index,
1195 FIB_ENTRY_FLAG_NONE,
1198 ~0, // no index provided.
1199 fib_index, // nexthop in same fib as route
1202 FIB_ROUTE_PATH_FLAG_NONE);
1204 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1205 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1206 tm->hw[0]->sw_if_index),
1207 "RPF list for adj-fib contains adj");
1210 * +1 entry and +1 shared-path-list
1212 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1213 fib_path_list_db_size());
1214 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1215 fib_path_list_pool_size());
1216 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1217 fib_entry_pool_size());
1219 fib_prefix_t bgp_101_pfx = {
1221 .fp_proto = FIB_PROTOCOL_IP4,
1223 /* 100.100.100.101/32 */
1224 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1228 fib_table_entry_path_add(fib_index,
1231 FIB_ENTRY_FLAG_NONE,
1234 ~0, // no index provided.
1235 fib_index, // nexthop in same fib as route
1238 FIB_ROUTE_PATH_FLAG_NONE);
1240 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1241 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1242 tm->hw[0]->sw_if_index),
1243 "RPF list for adj-fib contains adj");
1246 * +1 entry, but the recursive path-list is shared.
1248 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1249 fib_path_list_db_size());
1250 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1251 fib_path_list_pool_size());
1252 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1253 fib_entry_pool_size());
1256 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1257 * adjacency through which the route will resovle
1259 fib_prefix_t ex_pfx = {
1261 .fp_proto = FIB_PROTOCOL_IP4,
1264 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1268 fib_table_entry_special_add(fib_index,
1271 FIB_ENTRY_FLAG_EXCLUSIVE,
1273 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1274 FIB_TEST((ai == fib_entry_get_adj(fei)),
1275 "Exclusive route links to user adj");
1277 fib_table_entry_special_remove(fib_index,
1279 FIB_SOURCE_SPECIAL);
1280 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1281 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1282 "Exclusive reoute removed");
1285 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1286 * adjacency through which the route will resovle
1288 dpo_id_t ex_dpo = DPO_INVALID;
1290 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1292 LOOKUP_INPUT_DST_ADDR,
1293 LOOKUP_TABLE_FROM_CONFIG,
1296 fib_table_entry_special_dpo_add(fib_index,
1299 FIB_ENTRY_FLAG_EXCLUSIVE,
1301 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1302 dpo = fib_entry_contribute_ip_forwarding(fei);
1303 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1304 "exclusive remote uses lookup DPO");
1307 * update the exclusive to use a different DPO
1309 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1310 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1312 fib_table_entry_special_dpo_update(fib_index,
1315 FIB_ENTRY_FLAG_EXCLUSIVE,
1317 dpo = fib_entry_contribute_ip_forwarding(fei);
1318 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1319 "exclusive remote uses now uses NULL DPO");
1321 fib_table_entry_special_remove(fib_index,
1323 FIB_SOURCE_SPECIAL);
1324 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1325 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1326 "Exclusive reoute removed");
1330 * Add a recursive route:
1331 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1333 fib_prefix_t bgp_200_pfx = {
1335 .fp_proto = FIB_PROTOCOL_IP4,
1337 /* 200.200.200.200/32 */
1338 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1342 fib_prefix_t pfx_1_1_1_2_s_32 = {
1344 .fp_proto = FIB_PROTOCOL_IP4,
1346 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1350 fib_table_entry_path_add(fib_index,
1353 FIB_ENTRY_FLAG_NONE,
1355 &pfx_1_1_1_2_s_32.fp_addr,
1356 ~0, // no index provided.
1357 fib_index, // nexthop in same fib as route
1360 FIB_ROUTE_PATH_FLAG_NONE);
1362 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1365 * the adj should be recursive via drop, since the route resolves via
1366 * the default route, which is itself a DROP
1368 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1369 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1370 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1371 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1372 "RPF list for 1.1.1.2/32 contains 0 adjs");
1375 * +2 entry and +1 shared-path-list
1377 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1378 fib_path_list_db_size());
1379 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1380 fib_path_list_pool_size());
1381 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1382 fib_entry_pool_size());
1385 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1386 * The paths are sort by NH first. in this case the the path with greater
1387 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1389 fib_prefix_t pfx_1_2_3_4_s_32 = {
1391 .fp_proto = FIB_PROTOCOL_IP4,
1393 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1396 fib_table_entry_path_add(fib_index,
1399 FIB_ENTRY_FLAG_NONE,
1402 tm->hw[0]->sw_if_index,
1406 FIB_ROUTE_PATH_FLAG_NONE);
1407 fei = fib_table_entry_path_add(fib_index,
1410 FIB_ENTRY_FLAG_NONE,
1413 tm->hw[1]->sw_if_index,
1417 FIB_ROUTE_PATH_FLAG_NONE);
1419 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1420 dpo = fib_entry_contribute_ip_forwarding(fei);
1421 lb = load_balance_get(dpo->dpoi_index);
1422 FIB_TEST((lb->lb_n_buckets == 4),
1423 "1.2.3.4/32 LB has %d bucket",
1426 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1427 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1428 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1429 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1431 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1432 tm->hw[0]->sw_if_index,
1433 tm->hw[1]->sw_if_index),
1434 "RPF list for 1.2.3.4/32 contains both adjs");
1438 * Unequal Cost load-balance. 4:1 ratio.
1439 * fits in a 16 bucket LB with ratio 13:3
1441 fib_prefix_t pfx_1_2_3_5_s_32 = {
1443 .fp_proto = FIB_PROTOCOL_IP4,
1445 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1448 fib_table_entry_path_add(fib_index,
1451 FIB_ENTRY_FLAG_NONE,
1454 tm->hw[1]->sw_if_index,
1458 FIB_ROUTE_PATH_FLAG_NONE);
1459 fei = fib_table_entry_path_add(fib_index,
1462 FIB_ENTRY_FLAG_NONE,
1465 tm->hw[0]->sw_if_index,
1469 FIB_ROUTE_PATH_FLAG_NONE);
1471 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1472 dpo = fib_entry_contribute_ip_forwarding(fei);
1473 lb = load_balance_get(dpo->dpoi_index);
1474 FIB_TEST((lb->lb_n_buckets == 16),
1475 "1.2.3.5/32 LB has %d bucket",
1478 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1479 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1480 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1481 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1482 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1483 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1484 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1485 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1486 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1487 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1488 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1489 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1490 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1491 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1492 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1493 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1495 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1496 tm->hw[0]->sw_if_index,
1497 tm->hw[1]->sw_if_index),
1498 "RPF list for 1.2.3.4/32 contains both adjs");
1501 * Test UCMP with a large weight skew - this produces load-balance objects with large
1502 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1503 * laso testing the LB in placce modify code when number of buckets is large.
1505 fib_prefix_t pfx_6_6_6_6_s_32 = {
1507 .fp_proto = FIB_PROTOCOL_IP4,
1510 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1513 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_1 = {
1519 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_2 = {
1525 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1528 .adj = ai_12_12_12_12,
1531 fib_table_entry_update_one_path(fib_index,
1534 FIB_ENTRY_FLAG_NONE,
1537 tm->hw[0]->sw_if_index,
1538 ~0, // invalid fib index
1541 FIB_ROUTE_PATH_FLAG_NONE);
1543 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1544 FIB_TEST(fib_test_validate_entry(fei,
1545 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1547 &ip_6_6_6_6_o_10_10_10_1),
1548 "6.6.6.6/32 via 10.10.10.1");
1550 fib_table_entry_path_add(fib_index,
1553 FIB_ENTRY_FLAG_NONE,
1556 tm->hw[0]->sw_if_index,
1557 ~0, // invalid fib index
1560 FIB_ROUTE_PATH_FLAG_NONE);
1562 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1563 FIB_TEST(fib_test_validate_entry(fei,
1564 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1566 &ip_6_6_6_6_o_10_10_10_2,
1567 &ip_6_6_6_6_o_10_10_10_2,
1568 &ip_6_6_6_6_o_10_10_10_2,
1569 &ip_6_6_6_6_o_10_10_10_2,
1570 &ip_6_6_6_6_o_10_10_10_2,
1571 &ip_6_6_6_6_o_10_10_10_2,
1572 &ip_6_6_6_6_o_10_10_10_2,
1573 &ip_6_6_6_6_o_10_10_10_2,
1574 &ip_6_6_6_6_o_10_10_10_2,
1575 &ip_6_6_6_6_o_10_10_10_2,
1576 &ip_6_6_6_6_o_10_10_10_2,
1577 &ip_6_6_6_6_o_10_10_10_2,
1578 &ip_6_6_6_6_o_10_10_10_2,
1579 &ip_6_6_6_6_o_10_10_10_2,
1580 &ip_6_6_6_6_o_10_10_10_2,
1581 &ip_6_6_6_6_o_10_10_10_2,
1582 &ip_6_6_6_6_o_10_10_10_2,
1583 &ip_6_6_6_6_o_10_10_10_2,
1584 &ip_6_6_6_6_o_10_10_10_2,
1585 &ip_6_6_6_6_o_10_10_10_2,
1586 &ip_6_6_6_6_o_10_10_10_2,
1587 &ip_6_6_6_6_o_10_10_10_2,
1588 &ip_6_6_6_6_o_10_10_10_2,
1589 &ip_6_6_6_6_o_10_10_10_2,
1590 &ip_6_6_6_6_o_10_10_10_2,
1591 &ip_6_6_6_6_o_10_10_10_2,
1592 &ip_6_6_6_6_o_10_10_10_2,
1593 &ip_6_6_6_6_o_10_10_10_2,
1594 &ip_6_6_6_6_o_10_10_10_2,
1595 &ip_6_6_6_6_o_10_10_10_2,
1596 &ip_6_6_6_6_o_10_10_10_2,
1597 &ip_6_6_6_6_o_10_10_10_2,
1598 &ip_6_6_6_6_o_10_10_10_2,
1599 &ip_6_6_6_6_o_10_10_10_2,
1600 &ip_6_6_6_6_o_10_10_10_2,
1601 &ip_6_6_6_6_o_10_10_10_2,
1602 &ip_6_6_6_6_o_10_10_10_2,
1603 &ip_6_6_6_6_o_10_10_10_2,
1604 &ip_6_6_6_6_o_10_10_10_2,
1605 &ip_6_6_6_6_o_10_10_10_2,
1606 &ip_6_6_6_6_o_10_10_10_2,
1607 &ip_6_6_6_6_o_10_10_10_2,
1608 &ip_6_6_6_6_o_10_10_10_2,
1609 &ip_6_6_6_6_o_10_10_10_2,
1610 &ip_6_6_6_6_o_10_10_10_2,
1611 &ip_6_6_6_6_o_10_10_10_2,
1612 &ip_6_6_6_6_o_10_10_10_2,
1613 &ip_6_6_6_6_o_10_10_10_2,
1614 &ip_6_6_6_6_o_10_10_10_2,
1615 &ip_6_6_6_6_o_10_10_10_2,
1616 &ip_6_6_6_6_o_10_10_10_2,
1617 &ip_6_6_6_6_o_10_10_10_2,
1618 &ip_6_6_6_6_o_10_10_10_2,
1619 &ip_6_6_6_6_o_10_10_10_2,
1620 &ip_6_6_6_6_o_10_10_10_2,
1621 &ip_6_6_6_6_o_10_10_10_2,
1622 &ip_6_6_6_6_o_10_10_10_2,
1623 &ip_6_6_6_6_o_10_10_10_2,
1624 &ip_6_6_6_6_o_10_10_10_2,
1625 &ip_6_6_6_6_o_10_10_10_2,
1626 &ip_6_6_6_6_o_10_10_10_2,
1627 &ip_6_6_6_6_o_10_10_10_2,
1628 &ip_6_6_6_6_o_10_10_10_2,
1629 &ip_6_6_6_6_o_10_10_10_1),
1630 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1632 fib_table_entry_path_add(fib_index,
1635 FIB_ENTRY_FLAG_NONE,
1638 tm->hw[1]->sw_if_index,
1639 ~0, // invalid fib index
1642 FIB_ROUTE_PATH_FLAG_NONE);
1644 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1645 FIB_TEST(fib_test_validate_entry(fei,
1646 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1648 &ip_6_6_6_6_o_10_10_10_1,
1649 &ip_6_6_6_6_o_10_10_10_2,
1650 &ip_6_6_6_6_o_10_10_10_2,
1651 &ip_6_6_6_6_o_10_10_10_2,
1652 &ip_6_6_6_6_o_10_10_10_2,
1653 &ip_6_6_6_6_o_10_10_10_2,
1654 &ip_6_6_6_6_o_10_10_10_2,
1655 &ip_6_6_6_6_o_10_10_10_2,
1656 &ip_6_6_6_6_o_10_10_10_2,
1657 &ip_6_6_6_6_o_10_10_10_2,
1658 &ip_6_6_6_6_o_10_10_10_2,
1659 &ip_6_6_6_6_o_10_10_10_2,
1660 &ip_6_6_6_6_o_10_10_10_2,
1661 &ip_6_6_6_6_o_10_10_10_2,
1662 &ip_6_6_6_6_o_10_10_10_2,
1663 &ip_6_6_6_6_o_10_10_10_2,
1664 &ip_6_6_6_6_o_10_10_10_2,
1665 &ip_6_6_6_6_o_10_10_10_2,
1666 &ip_6_6_6_6_o_10_10_10_2,
1667 &ip_6_6_6_6_o_10_10_10_2,
1668 &ip_6_6_6_6_o_10_10_10_2,
1669 &ip_6_6_6_6_o_10_10_10_2,
1670 &ip_6_6_6_6_o_10_10_10_2,
1671 &ip_6_6_6_6_o_10_10_10_2,
1672 &ip_6_6_6_6_o_10_10_10_2,
1673 &ip_6_6_6_6_o_10_10_10_2,
1674 &ip_6_6_6_6_o_10_10_10_2,
1675 &ip_6_6_6_6_o_10_10_10_2,
1676 &ip_6_6_6_6_o_10_10_10_2,
1677 &ip_6_6_6_6_o_10_10_10_2,
1678 &ip_6_6_6_6_o_10_10_10_2,
1679 &ip_6_6_6_6_o_10_10_10_2,
1680 &ip_6_6_6_6_o_10_10_10_2,
1681 &ip_6_6_6_6_o_10_10_10_2,
1682 &ip_6_6_6_6_o_10_10_10_2,
1683 &ip_6_6_6_6_o_10_10_10_2,
1684 &ip_6_6_6_6_o_10_10_10_2,
1685 &ip_6_6_6_6_o_10_10_10_2,
1686 &ip_6_6_6_6_o_10_10_10_2,
1687 &ip_6_6_6_6_o_10_10_10_2,
1688 &ip_6_6_6_6_o_10_10_10_2,
1689 &ip_6_6_6_6_o_10_10_10_2,
1690 &ip_6_6_6_6_o_10_10_10_2,
1691 &ip_6_6_6_6_o_10_10_10_2,
1692 &ip_6_6_6_6_o_10_10_10_2,
1693 &ip_6_6_6_6_o_10_10_10_2,
1694 &ip_6_6_6_6_o_10_10_10_2,
1695 &ip_6_6_6_6_o_10_10_10_2,
1696 &ip_6_6_6_6_o_10_10_10_2,
1697 &ip_6_6_6_6_o_10_10_10_2,
1698 &ip_6_6_6_6_o_10_10_10_2,
1699 &ip_6_6_6_6_o_10_10_10_2,
1700 &ip_6_6_6_6_o_10_10_10_2,
1701 &ip_6_6_6_6_o_10_10_10_2,
1702 &ip_6_6_6_6_o_10_10_10_2,
1703 &ip_6_6_6_6_o_10_10_10_2,
1704 &ip_6_6_6_6_o_10_10_10_2,
1705 &ip_6_6_6_6_o_10_10_10_2,
1706 &ip_6_6_6_6_o_10_10_10_2,
1707 &ip_6_6_6_6_o_10_10_10_2,
1708 &ip_6_6_6_6_o_10_10_10_2,
1709 &ip_6_6_6_6_o_10_10_10_2,
1710 &ip_6_6_6_6_o_10_10_10_2,
1711 &ip_6_6_6_6_o_10_10_10_2,
1712 &ip_6_6_6_6_o_10_10_10_2,
1713 &ip_6_6_6_6_o_12_12_12_12,
1714 &ip_6_6_6_6_o_12_12_12_12,
1715 &ip_6_6_6_6_o_12_12_12_12,
1716 &ip_6_6_6_6_o_12_12_12_12,
1717 &ip_6_6_6_6_o_12_12_12_12,
1718 &ip_6_6_6_6_o_12_12_12_12,
1719 &ip_6_6_6_6_o_12_12_12_12,
1720 &ip_6_6_6_6_o_12_12_12_12,
1721 &ip_6_6_6_6_o_12_12_12_12,
1722 &ip_6_6_6_6_o_12_12_12_12,
1723 &ip_6_6_6_6_o_12_12_12_12,
1724 &ip_6_6_6_6_o_12_12_12_12,
1725 &ip_6_6_6_6_o_12_12_12_12,
1726 &ip_6_6_6_6_o_12_12_12_12,
1727 &ip_6_6_6_6_o_12_12_12_12,
1728 &ip_6_6_6_6_o_12_12_12_12,
1729 &ip_6_6_6_6_o_12_12_12_12,
1730 &ip_6_6_6_6_o_12_12_12_12,
1731 &ip_6_6_6_6_o_12_12_12_12,
1732 &ip_6_6_6_6_o_12_12_12_12,
1733 &ip_6_6_6_6_o_12_12_12_12,
1734 &ip_6_6_6_6_o_12_12_12_12,
1735 &ip_6_6_6_6_o_12_12_12_12,
1736 &ip_6_6_6_6_o_12_12_12_12,
1737 &ip_6_6_6_6_o_12_12_12_12,
1738 &ip_6_6_6_6_o_12_12_12_12,
1739 &ip_6_6_6_6_o_12_12_12_12,
1740 &ip_6_6_6_6_o_12_12_12_12,
1741 &ip_6_6_6_6_o_12_12_12_12,
1742 &ip_6_6_6_6_o_12_12_12_12,
1743 &ip_6_6_6_6_o_12_12_12_12,
1744 &ip_6_6_6_6_o_12_12_12_12,
1745 &ip_6_6_6_6_o_12_12_12_12,
1746 &ip_6_6_6_6_o_12_12_12_12,
1747 &ip_6_6_6_6_o_12_12_12_12,
1748 &ip_6_6_6_6_o_12_12_12_12,
1749 &ip_6_6_6_6_o_12_12_12_12,
1750 &ip_6_6_6_6_o_12_12_12_12,
1751 &ip_6_6_6_6_o_12_12_12_12,
1752 &ip_6_6_6_6_o_12_12_12_12,
1753 &ip_6_6_6_6_o_12_12_12_12,
1754 &ip_6_6_6_6_o_12_12_12_12,
1755 &ip_6_6_6_6_o_12_12_12_12,
1756 &ip_6_6_6_6_o_12_12_12_12,
1757 &ip_6_6_6_6_o_12_12_12_12,
1758 &ip_6_6_6_6_o_12_12_12_12,
1759 &ip_6_6_6_6_o_12_12_12_12,
1760 &ip_6_6_6_6_o_12_12_12_12,
1761 &ip_6_6_6_6_o_12_12_12_12,
1762 &ip_6_6_6_6_o_12_12_12_12,
1763 &ip_6_6_6_6_o_12_12_12_12,
1764 &ip_6_6_6_6_o_12_12_12_12,
1765 &ip_6_6_6_6_o_12_12_12_12,
1766 &ip_6_6_6_6_o_12_12_12_12,
1767 &ip_6_6_6_6_o_12_12_12_12,
1768 &ip_6_6_6_6_o_12_12_12_12,
1769 &ip_6_6_6_6_o_12_12_12_12,
1770 &ip_6_6_6_6_o_12_12_12_12,
1771 &ip_6_6_6_6_o_12_12_12_12,
1772 &ip_6_6_6_6_o_12_12_12_12,
1773 &ip_6_6_6_6_o_12_12_12_12,
1774 &ip_6_6_6_6_o_12_12_12_12,
1775 &ip_6_6_6_6_o_12_12_12_12),
1776 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1778 fib_table_entry_path_remove(fib_index,
1783 tm->hw[1]->sw_if_index,
1784 ~0, // invalid fib index
1786 FIB_ROUTE_PATH_FLAG_NONE);
1788 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1789 FIB_TEST(fib_test_validate_entry(fei,
1790 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1792 &ip_6_6_6_6_o_10_10_10_2,
1793 &ip_6_6_6_6_o_10_10_10_2,
1794 &ip_6_6_6_6_o_10_10_10_2,
1795 &ip_6_6_6_6_o_10_10_10_2,
1796 &ip_6_6_6_6_o_10_10_10_2,
1797 &ip_6_6_6_6_o_10_10_10_2,
1798 &ip_6_6_6_6_o_10_10_10_2,
1799 &ip_6_6_6_6_o_10_10_10_2,
1800 &ip_6_6_6_6_o_10_10_10_2,
1801 &ip_6_6_6_6_o_10_10_10_2,
1802 &ip_6_6_6_6_o_10_10_10_2,
1803 &ip_6_6_6_6_o_10_10_10_2,
1804 &ip_6_6_6_6_o_10_10_10_2,
1805 &ip_6_6_6_6_o_10_10_10_2,
1806 &ip_6_6_6_6_o_10_10_10_2,
1807 &ip_6_6_6_6_o_10_10_10_2,
1808 &ip_6_6_6_6_o_10_10_10_2,
1809 &ip_6_6_6_6_o_10_10_10_2,
1810 &ip_6_6_6_6_o_10_10_10_2,
1811 &ip_6_6_6_6_o_10_10_10_2,
1812 &ip_6_6_6_6_o_10_10_10_2,
1813 &ip_6_6_6_6_o_10_10_10_2,
1814 &ip_6_6_6_6_o_10_10_10_2,
1815 &ip_6_6_6_6_o_10_10_10_2,
1816 &ip_6_6_6_6_o_10_10_10_2,
1817 &ip_6_6_6_6_o_10_10_10_2,
1818 &ip_6_6_6_6_o_10_10_10_2,
1819 &ip_6_6_6_6_o_10_10_10_2,
1820 &ip_6_6_6_6_o_10_10_10_2,
1821 &ip_6_6_6_6_o_10_10_10_2,
1822 &ip_6_6_6_6_o_10_10_10_2,
1823 &ip_6_6_6_6_o_10_10_10_2,
1824 &ip_6_6_6_6_o_10_10_10_2,
1825 &ip_6_6_6_6_o_10_10_10_2,
1826 &ip_6_6_6_6_o_10_10_10_2,
1827 &ip_6_6_6_6_o_10_10_10_2,
1828 &ip_6_6_6_6_o_10_10_10_2,
1829 &ip_6_6_6_6_o_10_10_10_2,
1830 &ip_6_6_6_6_o_10_10_10_2,
1831 &ip_6_6_6_6_o_10_10_10_2,
1832 &ip_6_6_6_6_o_10_10_10_2,
1833 &ip_6_6_6_6_o_10_10_10_2,
1834 &ip_6_6_6_6_o_10_10_10_2,
1835 &ip_6_6_6_6_o_10_10_10_2,
1836 &ip_6_6_6_6_o_10_10_10_2,
1837 &ip_6_6_6_6_o_10_10_10_2,
1838 &ip_6_6_6_6_o_10_10_10_2,
1839 &ip_6_6_6_6_o_10_10_10_2,
1840 &ip_6_6_6_6_o_10_10_10_2,
1841 &ip_6_6_6_6_o_10_10_10_2,
1842 &ip_6_6_6_6_o_10_10_10_2,
1843 &ip_6_6_6_6_o_10_10_10_2,
1844 &ip_6_6_6_6_o_10_10_10_2,
1845 &ip_6_6_6_6_o_10_10_10_2,
1846 &ip_6_6_6_6_o_10_10_10_2,
1847 &ip_6_6_6_6_o_10_10_10_2,
1848 &ip_6_6_6_6_o_10_10_10_2,
1849 &ip_6_6_6_6_o_10_10_10_2,
1850 &ip_6_6_6_6_o_10_10_10_2,
1851 &ip_6_6_6_6_o_10_10_10_2,
1852 &ip_6_6_6_6_o_10_10_10_2,
1853 &ip_6_6_6_6_o_10_10_10_2,
1854 &ip_6_6_6_6_o_10_10_10_2,
1855 &ip_6_6_6_6_o_10_10_10_1),
1856 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1858 fib_table_entry_path_remove(fib_index,
1863 tm->hw[0]->sw_if_index,
1864 ~0, // invalid fib index
1866 FIB_ROUTE_PATH_FLAG_NONE);
1868 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1869 FIB_TEST(fib_test_validate_entry(fei,
1870 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1872 &ip_6_6_6_6_o_10_10_10_1),
1873 "6.6.6.6/32 via 10.10.10.1");
1875 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
1878 * A recursive via the two unequal cost entries
1880 fib_prefix_t bgp_44_s_32 = {
1882 .fp_proto = FIB_PROTOCOL_IP4,
1884 /* 200.200.200.201/32 */
1885 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1888 fei = fib_table_entry_path_add(fib_index,
1891 FIB_ENTRY_FLAG_NONE,
1893 &pfx_1_2_3_4_s_32.fp_addr,
1898 FIB_ROUTE_PATH_FLAG_NONE);
1899 fei = fib_table_entry_path_add(fib_index,
1902 FIB_ENTRY_FLAG_NONE,
1904 &pfx_1_2_3_5_s_32.fp_addr,
1909 FIB_ROUTE_PATH_FLAG_NONE);
1911 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1912 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1913 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1914 tm->hw[0]->sw_if_index,
1915 tm->hw[1]->sw_if_index),
1916 "RPF list for 1.2.3.4/32 contains both adjs");
1919 * test the uRPF check functions
1921 dpo_id_t dpo_44 = DPO_INVALID;
1924 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1925 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
1927 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
1928 "uRPF check for 68.68.68.68/32 on %d OK",
1929 tm->hw[0]->sw_if_index);
1930 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
1931 "uRPF check for 68.68.68.68/32 on %d OK",
1932 tm->hw[1]->sw_if_index);
1933 FIB_TEST(!fib_urpf_check(urpfi, 99),
1934 "uRPF check for 68.68.68.68/32 on 99 not-OK",
1938 fib_table_entry_delete(fib_index,
1941 fib_table_entry_delete(fib_index,
1944 fib_table_entry_delete(fib_index,
1949 * Add a recursive route:
1950 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
1952 fib_prefix_t bgp_201_pfx = {
1954 .fp_proto = FIB_PROTOCOL_IP4,
1956 /* 200.200.200.201/32 */
1957 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
1961 fib_prefix_t pfx_1_1_1_200_s_32 = {
1963 .fp_proto = FIB_PROTOCOL_IP4,
1965 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
1969 fib_table_entry_path_add(fib_index,
1972 FIB_ENTRY_FLAG_NONE,
1974 &pfx_1_1_1_200_s_32.fp_addr,
1975 ~0, // no index provided.
1976 fib_index, // nexthop in same fib as route
1979 FIB_ROUTE_PATH_FLAG_NONE);
1981 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
1983 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
1984 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1985 "Flags set on RR via non-attached");
1986 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1987 "RPF list for BGP route empty");
1990 * +2 entry (BGP & RR) and +1 shared-path-list
1992 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
1993 fib_path_list_db_size());
1994 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
1995 fib_path_list_pool_size());
1996 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
1997 fib_entry_pool_size());
2000 * insert a route that covers the missing 1.1.1.2/32. we epxect
2001 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2003 fib_prefix_t pfx_1_1_1_0_s_24 = {
2005 .fp_proto = FIB_PROTOCOL_IP4,
2008 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2012 fib_table_entry_path_add(fib_index,
2015 FIB_ENTRY_FLAG_NONE,
2018 tm->hw[0]->sw_if_index,
2019 ~0, // invalid fib index
2022 FIB_ROUTE_PATH_FLAG_NONE);
2023 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2024 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2025 ai = fib_entry_get_adj(fei);
2026 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2027 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2028 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2029 ai = fib_entry_get_adj(fei);
2030 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2031 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2032 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2033 ai = fib_entry_get_adj(fei);
2034 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2037 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2039 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2040 fib_path_list_db_size());
2041 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2042 fib_path_list_pool_size());
2043 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2044 fib_entry_pool_size());
2047 * the recursive adj for 200.200.200.200 should be updated.
2049 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2050 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2051 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2052 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2053 tm->hw[0]->sw_if_index),
2054 "RPF list for BGP route has itf index 0");
2057 * insert a more specific route than 1.1.1.0/24 that also covers the
2058 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2059 * 200.200.200.200 to resolve through it.
2061 fib_prefix_t pfx_1_1_1_0_s_28 = {
2063 .fp_proto = FIB_PROTOCOL_IP4,
2066 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2070 fib_table_entry_path_add(fib_index,
2073 FIB_ENTRY_FLAG_NONE,
2076 tm->hw[0]->sw_if_index,
2077 ~0, // invalid fib index
2080 FIB_ROUTE_PATH_FLAG_NONE);
2081 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2082 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2083 ai = fib_entry_get_adj(fei);
2084 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2087 * +1 entry. +1 shared path-list
2089 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2090 fib_path_list_db_size());
2091 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2092 fib_path_list_pool_size());
2093 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2094 fib_entry_pool_size());
2097 * the recursive adj for 200.200.200.200 should be updated.
2098 * 200.200.200.201 remains unchanged.
2100 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2101 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2104 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2106 fib_table_entry_path_remove(fib_index,
2111 tm->hw[0]->sw_if_index,
2114 FIB_ROUTE_PATH_FLAG_NONE);
2115 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2116 FIB_NODE_INDEX_INVALID),
2117 "1.1.1.0/28 removed");
2118 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2119 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2120 "1.1.1.0/28 lookup via /24");
2121 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2122 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2125 * -1 entry. -1 shared path-list
2127 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2128 fib_path_list_db_size());
2129 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2130 fib_path_list_pool_size());
2131 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2132 fib_entry_pool_size());
2135 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2137 fib_table_entry_path_remove(fib_index,
2142 tm->hw[0]->sw_if_index,
2145 FIB_ROUTE_PATH_FLAG_NONE);
2146 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2147 FIB_NODE_INDEX_INVALID),
2148 "1.1.1.0/24 removed");
2150 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2151 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2152 "1.1.1.2/32 route is DROP");
2153 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2154 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2155 "1.1.1.200/32 route is DROP");
2157 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2158 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2163 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2164 fib_path_list_db_size());
2165 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2166 fib_path_list_pool_size());
2167 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2168 fib_entry_pool_size());
2171 * insert the missing 1.1.1.2/32
2173 fei = fib_table_entry_path_add(fib_index,
2176 FIB_ENTRY_FLAG_NONE,
2179 tm->hw[0]->sw_if_index,
2180 ~0, // invalid fib index
2183 FIB_ROUTE_PATH_FLAG_NONE);
2184 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2185 ai = fib_entry_get_adj(fei);
2186 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2188 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2189 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2192 * no change. 1.1.1.2/32 was already there RR sourced.
2194 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2195 fib_path_list_db_size());
2196 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2197 fib_path_list_pool_size());
2198 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2199 fib_entry_pool_size());
2202 * remove 200.200.200.201/32 which does not have a valid via FIB
2204 fib_table_entry_path_remove(fib_index,
2208 &pfx_1_1_1_200_s_32.fp_addr,
2209 ~0, // no index provided.
2212 FIB_ROUTE_PATH_FLAG_NONE);
2215 * -2 entries (BGP and RR). -1 shared path-list;
2217 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2218 FIB_NODE_INDEX_INVALID),
2219 "200.200.200.201/32 removed");
2220 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2221 FIB_NODE_INDEX_INVALID),
2222 "1.1.1.200/32 removed");
2224 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2225 fib_path_list_db_size());
2226 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2227 fib_path_list_pool_size());
2228 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2229 fib_entry_pool_size());
2232 * remove 200.200.200.200/32 which does have a valid via FIB
2234 fib_table_entry_path_remove(fib_index,
2238 &pfx_1_1_1_2_s_32.fp_addr,
2239 ~0, // no index provided.
2242 FIB_ROUTE_PATH_FLAG_NONE);
2244 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2245 FIB_NODE_INDEX_INVALID),
2246 "200.200.200.200/32 removed");
2247 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2248 FIB_NODE_INDEX_INVALID),
2249 "1.1.1.2/32 still present");
2252 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2254 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2255 fib_path_list_db_size());
2256 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2257 fib_path_list_pool_size());
2258 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2259 fib_entry_pool_size());
2262 * A recursive prefix that has a 2 path load-balance.
2263 * It also shares a next-hop with other BGP prefixes and hence
2264 * test the ref counting of RR sourced prefixes and 2 level LB.
2266 const fib_prefix_t bgp_102 = {
2268 .fp_proto = FIB_PROTOCOL_IP4,
2270 /* 100.100.100.101/32 */
2271 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2274 fib_table_entry_path_add(fib_index,
2277 FIB_ENTRY_FLAG_NONE,
2279 &pfx_1_1_1_1_s_32.fp_addr,
2280 ~0, // no index provided.
2281 fib_index, // same as route
2284 FIB_ROUTE_PATH_FLAG_NONE);
2285 fib_table_entry_path_add(fib_index,
2288 FIB_ENTRY_FLAG_NONE,
2290 &pfx_1_1_1_2_s_32.fp_addr,
2291 ~0, // no index provided.
2292 fib_index, // same as route's FIB
2295 FIB_ROUTE_PATH_FLAG_NONE);
2296 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2297 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2298 dpo = fib_entry_contribute_ip_forwarding(fei);
2300 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2301 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2302 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2303 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2305 lb = load_balance_get(dpo->dpoi_index);
2306 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2307 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2308 "First via 10.10.10.1");
2309 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2310 "Second via 10.10.10.1");
2312 fib_table_entry_path_remove(fib_index,
2316 &pfx_1_1_1_1_s_32.fp_addr,
2317 ~0, // no index provided.
2318 fib_index, // same as route's FIB
2320 FIB_ROUTE_PATH_FLAG_NONE);
2321 fib_table_entry_path_remove(fib_index,
2325 &pfx_1_1_1_2_s_32.fp_addr,
2326 ~0, // no index provided.
2327 fib_index, // same as route's FIB
2329 FIB_ROUTE_PATH_FLAG_NONE);
2330 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2331 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2334 * remove the remaining recursives
2336 fib_table_entry_path_remove(fib_index,
2340 &pfx_1_1_1_1_s_32.fp_addr,
2341 ~0, // no index provided.
2342 fib_index, // same as route's FIB
2344 FIB_ROUTE_PATH_FLAG_NONE);
2345 fib_table_entry_path_remove(fib_index,
2349 &pfx_1_1_1_1_s_32.fp_addr,
2350 ~0, // no index provided.
2351 fib_index, // same as route's FIB
2353 FIB_ROUTE_PATH_FLAG_NONE);
2354 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2355 FIB_NODE_INDEX_INVALID),
2356 "100.100.100.100/32 removed");
2357 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2358 FIB_NODE_INDEX_INVALID),
2359 "100.100.100.101/32 removed");
2362 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2364 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2365 fib_path_list_db_size());
2366 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2367 fib_path_list_pool_size());
2368 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2369 fib_entry_pool_size());
2372 * Add a recursive route via a connected cover, using an adj-fib that does exist
2374 fib_table_entry_path_add(fib_index,
2377 FIB_ENTRY_FLAG_NONE,
2380 ~0, // no index provided.
2381 fib_index, // Same as route's FIB
2384 FIB_ROUTE_PATH_FLAG_NONE);
2387 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2389 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2390 fib_path_list_db_size());
2391 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2392 fib_path_list_pool_size());
2393 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2394 fib_entry_pool_size());
2396 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2397 dpo = fib_entry_contribute_ip_forwarding(fei);
2399 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2400 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2402 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2403 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2405 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2406 "Flags set on RR via existing attached");
2409 * Add a recursive route via a connected cover, using and adj-fib that does
2412 ip46_address_t nh_10_10_10_3 = {
2413 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2415 fib_prefix_t pfx_10_10_10_3 = {
2417 .fp_proto = FIB_PROTOCOL_IP4,
2418 .fp_addr = nh_10_10_10_3,
2421 fib_table_entry_path_add(fib_index,
2424 FIB_ENTRY_FLAG_NONE,
2427 ~0, // no index provided.
2431 FIB_ROUTE_PATH_FLAG_NONE);
2434 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2435 * one unshared non-recursive via 10.10.10.3
2437 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2438 fib_path_list_db_size());
2439 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2440 fib_path_list_pool_size());
2441 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2442 fib_entry_pool_size());
2444 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2447 tm->hw[0]->sw_if_index);
2449 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2450 dpo = fib_entry_contribute_ip_forwarding(fei);
2451 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2452 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2454 ai = fib_entry_get_adj(fei);
2455 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2456 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2457 fib_entry_get_flags(fei)),
2458 "Flags set on RR via non-existing attached");
2460 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2461 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2466 * remove the recursives
2468 fib_table_entry_path_remove(fib_index,
2473 ~0, // no index provided.
2474 fib_index, // same as route's FIB
2476 FIB_ROUTE_PATH_FLAG_NONE);
2477 fib_table_entry_path_remove(fib_index,
2482 ~0, // no index provided.
2483 fib_index, // same as route's FIB
2485 FIB_ROUTE_PATH_FLAG_NONE);
2487 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2488 FIB_NODE_INDEX_INVALID),
2489 "200.200.200.201/32 removed");
2490 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2491 FIB_NODE_INDEX_INVALID),
2492 "200.200.200.200/32 removed");
2493 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2494 FIB_NODE_INDEX_INVALID),
2495 "10.10.10.3/32 removed");
2498 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2499 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2501 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2502 fib_path_list_db_size());
2503 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2504 fib_path_list_pool_size());
2505 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2506 fib_entry_pool_size());
2511 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2513 fib_prefix_t pfx_5_5_5_5_s_32 = {
2515 .fp_proto = FIB_PROTOCOL_IP4,
2517 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2520 fib_prefix_t pfx_5_5_5_6_s_32 = {
2522 .fp_proto = FIB_PROTOCOL_IP4,
2524 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2527 fib_prefix_t pfx_5_5_5_7_s_32 = {
2529 .fp_proto = FIB_PROTOCOL_IP4,
2531 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2535 fib_table_entry_path_add(fib_index,
2538 FIB_ENTRY_FLAG_NONE,
2540 &pfx_5_5_5_6_s_32.fp_addr,
2541 ~0, // no index provided.
2545 FIB_ROUTE_PATH_FLAG_NONE);
2546 fib_table_entry_path_add(fib_index,
2549 FIB_ENTRY_FLAG_NONE,
2551 &pfx_5_5_5_7_s_32.fp_addr,
2552 ~0, // no index provided.
2556 FIB_ROUTE_PATH_FLAG_NONE);
2557 fib_table_entry_path_add(fib_index,
2560 FIB_ENTRY_FLAG_NONE,
2562 &pfx_5_5_5_5_s_32.fp_addr,
2563 ~0, // no index provided.
2567 FIB_ROUTE_PATH_FLAG_NONE);
2569 * +3 entries, +3 shared path-list
2571 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2572 fib_path_list_db_size());
2573 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2574 fib_path_list_pool_size());
2575 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2576 fib_entry_pool_size());
2579 * All the entries have only looped paths, so they are all drop
2581 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2582 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2583 "LB for 5.5.5.7/32 is via adj for DROP");
2584 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2585 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2586 "LB for 5.5.5.5/32 is via adj for DROP");
2587 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2588 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2589 "LB for 5.5.5.6/32 is via adj for DROP");
2592 * provide 5.5.5.6/32 with alternate path.
2593 * this will allow only 5.5.5.6/32 to forward with this path, the others
2594 * are still drop since the loop is still present.
2596 fib_table_entry_path_add(fib_index,
2599 FIB_ENTRY_FLAG_NONE,
2602 tm->hw[0]->sw_if_index,
2606 FIB_ROUTE_PATH_FLAG_NONE);
2609 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2610 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2612 lb = load_balance_get(dpo1->dpoi_index);
2613 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2615 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2616 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2617 FIB_TEST((ai_01 == dpo2->dpoi_index),
2618 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2620 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2621 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2622 "LB for 5.5.5.7/32 is via adj for DROP");
2623 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2624 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2625 "LB for 5.5.5.5/32 is via adj for DROP");
2628 * remove the alternate path for 5.5.5.6/32
2631 fib_table_entry_path_remove(fib_index,
2636 tm->hw[0]->sw_if_index,
2639 FIB_ROUTE_PATH_FLAG_NONE);
2641 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2642 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2643 "LB for 5.5.5.7/32 is via adj for DROP");
2644 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2645 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2646 "LB for 5.5.5.5/32 is via adj for DROP");
2647 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2648 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2649 "LB for 5.5.5.6/32 is via adj for DROP");
2652 * break the loop by giving 5.5.5.5/32 a new set of paths
2653 * expect all to forward via this new path.
2655 fib_table_entry_update_one_path(fib_index,
2658 FIB_ENTRY_FLAG_NONE,
2661 tm->hw[0]->sw_if_index,
2662 ~0, // invalid fib index
2665 FIB_ROUTE_PATH_FLAG_NONE);
2667 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2668 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2669 lb = load_balance_get(dpo1->dpoi_index);
2670 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2672 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2673 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2674 FIB_TEST((ai_01 == dpo2->dpoi_index),
2675 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2677 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2678 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2680 lb = load_balance_get(dpo2->dpoi_index);
2681 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2682 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2683 "5.5.5.5.7 via 5.5.5.5");
2685 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2686 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2688 lb = load_balance_get(dpo1->dpoi_index);
2689 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2690 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2691 "5.5.5.5.6 via 5.5.5.7");
2694 * revert back to the loop. so we can remove the prefixes with
2697 fib_table_entry_update_one_path(fib_index,
2700 FIB_ENTRY_FLAG_NONE,
2702 &pfx_5_5_5_6_s_32.fp_addr,
2703 ~0, // no index provided.
2707 FIB_ROUTE_PATH_FLAG_NONE);
2709 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2710 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2711 "LB for 5.5.5.7/32 is via adj for DROP");
2712 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2713 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2714 "LB for 5.5.5.5/32 is via adj for DROP");
2715 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2716 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2717 "LB for 5.5.5.6/32 is via adj for DROP");
2720 * remove all the 5.5.5.x/32 prefixes
2722 fib_table_entry_path_remove(fib_index,
2726 &pfx_5_5_5_6_s_32.fp_addr,
2727 ~0, // no index provided.
2728 fib_index, // same as route's FIB
2730 FIB_ROUTE_PATH_FLAG_NONE);
2731 fib_table_entry_path_remove(fib_index,
2735 &pfx_5_5_5_7_s_32.fp_addr,
2736 ~0, // no index provided.
2737 fib_index, // same as route's FIB
2739 FIB_ROUTE_PATH_FLAG_NONE);
2740 fib_table_entry_path_remove(fib_index,
2744 &pfx_5_5_5_5_s_32.fp_addr,
2745 ~0, // no index provided.
2746 fib_index, // same as route's FIB
2748 FIB_ROUTE_PATH_FLAG_NONE);
2749 fib_table_entry_path_remove(fib_index,
2754 ~0, // no index provided.
2755 fib_index, // same as route's FIB
2757 FIB_ROUTE_PATH_FLAG_NONE);
2760 * -3 entries, -3 shared path-list
2762 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2763 fib_path_list_db_size());
2764 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2765 fib_path_list_pool_size());
2766 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2767 fib_entry_pool_size());
2770 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2772 fib_table_entry_path_add(fib_index,
2775 FIB_ENTRY_FLAG_NONE,
2777 &pfx_5_5_5_6_s_32.fp_addr,
2778 ~0, // no index provided.
2782 FIB_ROUTE_PATH_FLAG_NONE);
2783 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2784 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2785 "1-level 5.5.5.6/32 loop is via adj for DROP");
2787 fib_table_entry_path_remove(fib_index,
2791 &pfx_5_5_5_6_s_32.fp_addr,
2792 ~0, // no index provided.
2793 fib_index, // same as route's FIB
2795 FIB_ROUTE_PATH_FLAG_NONE);
2796 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2797 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2798 "1-level 5.5.5.6/32 loop is removed");
2801 * A recursive route whose next-hop is covered by the prefix.
2802 * This would mean the via-fib, which inherits forwarding from its
2803 * cover, thus picks up forwarding from the prfix, which is via the
2804 * via-fib, and we have a loop.
2806 fib_prefix_t pfx_23_23_23_0_s_24 = {
2808 .fp_proto = FIB_PROTOCOL_IP4,
2810 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2813 fib_prefix_t pfx_23_23_23_23_s_32 = {
2815 .fp_proto = FIB_PROTOCOL_IP4,
2817 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2820 fei = fib_table_entry_path_add(fib_index,
2821 &pfx_23_23_23_0_s_24,
2823 FIB_ENTRY_FLAG_NONE,
2825 &pfx_23_23_23_23_s_32.fp_addr,
2830 FIB_ROUTE_PATH_FLAG_NONE);
2831 dpo = fib_entry_contribute_ip_forwarding(fei);
2832 FIB_TEST(load_balance_is_drop(dpo),
2833 "23.23.23.0/24 via covered is DROP");
2834 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2837 * add-remove test. no change.
2839 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2840 fib_path_list_db_size());
2841 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2842 fib_path_list_pool_size());
2843 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2844 fib_entry_pool_size());
2847 * A recursive route with recursion constraints.
2848 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2850 fib_table_entry_path_add(fib_index,
2853 FIB_ENTRY_FLAG_NONE,
2860 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2862 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2863 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2865 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2866 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2868 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2869 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2872 * save the load-balance. we expect it to be inplace modified
2874 lb = load_balance_get(dpo1->dpoi_index);
2877 * add a covering prefix for the via fib that would otherwise serve
2878 * as the resolving route when the host is removed
2880 fib_table_entry_path_add(fib_index,
2883 FIB_ENTRY_FLAG_NONE,
2886 tm->hw[0]->sw_if_index,
2887 ~0, // invalid fib index
2890 FIB_ROUTE_PATH_FLAG_NONE);
2891 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
2892 ai = fib_entry_get_adj(fei);
2893 FIB_TEST((ai == ai_01),
2894 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
2897 * remove the host via FIB - expect the BGP prefix to be drop
2899 fib_table_entry_path_remove(fib_index,
2904 tm->hw[0]->sw_if_index,
2905 ~0, // invalid fib index
2907 FIB_ROUTE_PATH_FLAG_NONE);
2909 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2910 "adj for 200.200.200.200/32 is recursive via adj for DROP");
2913 * add the via-entry host reoute back. expect to resolve again
2915 fib_table_entry_path_add(fib_index,
2918 FIB_ENTRY_FLAG_NONE,
2921 tm->hw[0]->sw_if_index,
2922 ~0, // invalid fib index
2925 FIB_ROUTE_PATH_FLAG_NONE);
2926 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2927 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2930 * add another path for the recursive. it will then have 2.
2932 fib_prefix_t pfx_1_1_1_3_s_32 = {
2934 .fp_proto = FIB_PROTOCOL_IP4,
2936 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
2939 fib_table_entry_path_add(fib_index,
2942 FIB_ENTRY_FLAG_NONE,
2945 tm->hw[0]->sw_if_index,
2946 ~0, // invalid fib index
2949 FIB_ROUTE_PATH_FLAG_NONE);
2951 fib_table_entry_path_add(fib_index,
2954 FIB_ENTRY_FLAG_NONE,
2956 &pfx_1_1_1_3_s_32.fp_addr,
2961 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2963 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2964 dpo = fib_entry_contribute_ip_forwarding(fei);
2966 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2967 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2968 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
2969 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2970 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
2971 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2972 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
2973 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
2976 * expect the lb-map used by the recursive's load-balance is using both buckets
2978 load_balance_map_t *lbm;
2981 lb = load_balance_get(dpo->dpoi_index);
2983 load_balance_map_lock(lbmi);
2984 lbm = load_balance_map_get(lbmi);
2986 FIB_TEST(lbm->lbm_buckets[0] == 0,
2987 "LB maps's bucket 0 is %d",
2988 lbm->lbm_buckets[0]);
2989 FIB_TEST(lbm->lbm_buckets[1] == 1,
2990 "LB maps's bucket 1 is %d",
2991 lbm->lbm_buckets[1]);
2994 * withdraw one of the /32 via-entrys.
2995 * that ECMP path will be unresolved and forwarding should continue on the
2996 * other available path. this is an iBGP PIC edge failover.
2997 * Test the forwarding changes without re-fetching the adj from the
2998 * recursive entry. this ensures its the same one that is updated; i.e. an
3001 fib_table_entry_path_remove(fib_index,
3006 tm->hw[0]->sw_if_index,
3007 ~0, // invalid fib index
3009 FIB_ROUTE_PATH_FLAG_NONE);
3011 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3012 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3013 "post PIC 200.200.200.200/32 was inplace modified");
3015 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3016 "post PIC adj for 200.200.200.200/32 is recursive"
3017 " via adj for 1.1.1.3");
3020 * the LB maps that was locked above should have been modified to remove
3021 * the path that was down, and thus its bucket points to a path that is
3024 FIB_TEST(lbm->lbm_buckets[0] == 1,
3025 "LB maps's bucket 0 is %d",
3026 lbm->lbm_buckets[0]);
3027 FIB_TEST(lbm->lbm_buckets[1] == 1,
3028 "LB maps's bucket 1 is %d",
3029 lbm->lbm_buckets[1]);
3031 load_balance_map_unlock(lb->lb_map);
3034 * add it back. again
3036 fib_table_entry_path_add(fib_index,
3039 FIB_ENTRY_FLAG_NONE,
3042 tm->hw[0]->sw_if_index,
3043 ~0, // invalid fib index
3046 FIB_ROUTE_PATH_FLAG_NONE);
3048 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3049 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3050 "via adj for 1.1.1.1");
3051 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3052 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3053 "via adj for 1.1.1.3");
3055 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3056 dpo = fib_entry_contribute_ip_forwarding(fei);
3057 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3058 "post PIC 200.200.200.200/32 was inplace modified");
3061 * add a 3rd path. this makes the LB 16 buckets.
3063 fib_table_entry_path_add(fib_index,
3066 FIB_ENTRY_FLAG_NONE,
3068 &pfx_1_1_1_2_s_32.fp_addr,
3073 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3075 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3076 dpo = fib_entry_contribute_ip_forwarding(fei);
3077 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3078 "200.200.200.200/32 was inplace modified for 3rd path");
3079 FIB_TEST(16 == lb->lb_n_buckets,
3080 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3083 load_balance_map_lock(lbmi);
3084 lbm = load_balance_map_get(lbmi);
3086 for (ii = 0; ii < 16; ii++)
3088 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3089 "LB Map for 200.200.200.200/32 at %d is %d",
3090 ii, lbm->lbm_buckets[ii]);
3094 * trigger PIC by removing the first via-entry
3095 * the first 6 buckets of the map should map to the next 6
3097 fib_table_entry_path_remove(fib_index,
3102 tm->hw[0]->sw_if_index,
3105 FIB_ROUTE_PATH_FLAG_NONE);
3107 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3108 dpo = fib_entry_contribute_ip_forwarding(fei);
3109 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3110 "200.200.200.200/32 was inplace modified for 3rd path");
3111 FIB_TEST(2 == lb->lb_n_buckets,
3112 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3114 for (ii = 0; ii < 6; ii++)
3116 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3117 "LB Map for 200.200.200.200/32 at %d is %d",
3118 ii, lbm->lbm_buckets[ii]);
3120 for (ii = 6; ii < 16; ii++)
3122 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3123 "LB Map for 200.200.200.200/32 at %d is %d",
3124 ii, lbm->lbm_buckets[ii]);
3131 fib_table_entry_path_add(fib_index,
3134 FIB_ENTRY_FLAG_NONE,
3137 tm->hw[0]->sw_if_index,
3141 FIB_ROUTE_PATH_FLAG_NONE);
3143 fib_table_entry_path_remove(fib_index,
3147 &pfx_1_1_1_2_s_32.fp_addr,
3151 MPLS_LABEL_INVALID);
3152 fib_table_entry_path_remove(fib_index,
3160 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3161 fib_table_entry_path_remove(fib_index,
3165 &pfx_1_1_1_3_s_32.fp_addr,
3169 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3170 fib_table_entry_delete(fib_index,
3173 fib_table_entry_delete(fib_index,
3176 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3177 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3178 "1.1.1.1/28 removed");
3179 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3180 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3181 "1.1.1.3/32 removed");
3182 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3183 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3184 "200.200.200.200/32 removed");
3187 * add-remove test. no change.
3189 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3190 fib_path_list_db_size());
3191 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3192 fib_path_list_pool_size());
3193 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3194 fib_entry_pool_size());
3197 * A route whose paths are built up iteratively and then removed
3200 fib_prefix_t pfx_4_4_4_4_s_32 = {
3202 .fp_proto = FIB_PROTOCOL_IP4,
3205 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3209 fib_table_entry_path_add(fib_index,
3212 FIB_ENTRY_FLAG_NONE,
3215 tm->hw[0]->sw_if_index,
3219 FIB_ROUTE_PATH_FLAG_NONE);
3220 fib_table_entry_path_add(fib_index,
3223 FIB_ENTRY_FLAG_NONE,
3226 tm->hw[0]->sw_if_index,
3230 FIB_ROUTE_PATH_FLAG_NONE);
3231 fib_table_entry_path_add(fib_index,
3234 FIB_ENTRY_FLAG_NONE,
3237 tm->hw[0]->sw_if_index,
3241 FIB_ROUTE_PATH_FLAG_NONE);
3242 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3243 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3244 "4.4.4.4/32 present");
3246 fib_table_entry_delete(fib_index,
3249 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3250 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3251 "4.4.4.4/32 removed");
3254 * add-remove test. no change.
3256 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3257 fib_path_list_db_size());
3258 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3259 fib_path_list_pool_size());
3260 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3261 fib_entry_pool_size());
3264 * A route with multiple paths at once
3266 fib_route_path_t *r_paths = NULL;
3268 for (ii = 0; ii < 4; ii++)
3270 fib_route_path_t r_path = {
3271 .frp_proto = FIB_PROTOCOL_IP4,
3273 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3275 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3277 .frp_fib_index = ~0,
3279 vec_add1(r_paths, r_path);
3282 fib_table_entry_update(fib_index,
3285 FIB_ENTRY_FLAG_NONE,
3288 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3289 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3290 dpo = fib_entry_contribute_ip_forwarding(fei);
3292 lb = load_balance_get(dpo->dpoi_index);
3293 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3295 fib_table_entry_delete(fib_index,
3298 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3299 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3300 "4.4.4.4/32 removed");
3304 * add-remove test. no change.
3306 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3307 fib_path_list_db_size());
3308 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3309 fib_path_list_pool_size());
3310 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3311 fib_entry_pool_size());
3314 * A route deag route
3316 fib_table_entry_path_add(fib_index,
3319 FIB_ENTRY_FLAG_NONE,
3326 FIB_ROUTE_PATH_FLAG_NONE);
3328 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3329 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3331 dpo = fib_entry_contribute_ip_forwarding(fei);
3332 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3333 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3335 FIB_TEST((fib_index == lkd->lkd_fib_index),
3336 "4.4.4.4/32 is deag in %d %U",
3338 format_dpo_id, dpo, 0);
3340 fib_table_entry_delete(fib_index,
3343 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3344 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3345 "4.4.4.4/32 removed");
3349 * add-remove test. no change.
3351 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3352 fib_path_list_db_size());
3353 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3354 fib_path_list_pool_size());
3355 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3356 fib_entry_pool_size());
3360 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3362 fib_prefix_t pfx_34_1_1_1_s_32 = {
3364 .fp_proto = FIB_PROTOCOL_IP4,
3366 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3369 fib_prefix_t pfx_34_34_1_1_s_32 = {
3371 .fp_proto = FIB_PROTOCOL_IP4,
3373 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3376 fei = fib_table_entry_path_add(fib_index,
3379 FIB_ENTRY_FLAG_NONE,
3381 &pfx_34_34_1_1_s_32.fp_addr,
3386 FIB_ROUTE_PATH_FLAG_NONE);
3387 fei = fib_table_entry_path_add(fib_index,
3390 FIB_ENTRY_FLAG_NONE,
3392 &pfx_34_34_1_1_s_32.fp_addr,
3397 FIB_ROUTE_PATH_FLAG_NONE);
3398 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3399 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3403 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3404 * all of which are via 10.10.10.1, Itf1
3406 fib_table_entry_path_remove(fib_index,
3411 tm->hw[0]->sw_if_index,
3414 FIB_ROUTE_PATH_FLAG_NONE);
3415 fib_table_entry_path_remove(fib_index,
3420 tm->hw[0]->sw_if_index,
3423 FIB_ROUTE_PATH_FLAG_NONE);
3424 fib_table_entry_path_remove(fib_index,
3429 tm->hw[0]->sw_if_index,
3432 FIB_ROUTE_PATH_FLAG_NONE);
3434 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3435 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3436 "1.1.1.1/32 removed");
3437 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3438 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3439 "1.1.1.2/32 removed");
3440 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3441 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3442 "1.1.2.0/24 removed");
3445 * -3 entries and -1 shared path-list
3447 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3448 fib_path_list_db_size());
3449 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3450 fib_path_list_pool_size());
3451 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3452 fib_entry_pool_size());
3455 * An attached-host route. Expect to link to the incomplete adj
3457 fib_prefix_t pfx_4_1_1_1_s_32 = {
3459 .fp_proto = FIB_PROTOCOL_IP4,
3462 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3465 fib_table_entry_path_add(fib_index,
3468 FIB_ENTRY_FLAG_NONE,
3471 tm->hw[0]->sw_if_index,
3475 FIB_ROUTE_PATH_FLAG_NONE);
3477 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3478 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3479 ai = fib_entry_get_adj(fei);
3481 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3483 &pfx_4_1_1_1_s_32.fp_addr,
3484 tm->hw[0]->sw_if_index);
3485 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3489 * +1 entry and +1 shared path-list
3491 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3492 fib_path_list_db_size());
3493 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3494 fib_path_list_pool_size());
3495 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3496 fib_entry_pool_size());
3498 fib_table_entry_delete(fib_index,
3502 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3503 fib_path_list_db_size());
3504 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3505 fib_path_list_pool_size());
3506 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3507 fib_entry_pool_size());
3510 * add a v6 prefix via v4 next-hops
3512 fib_prefix_t pfx_2001_s_64 = {
3514 .fp_proto = FIB_PROTOCOL_IP6,
3516 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3519 fei = fib_table_entry_path_add(0, //default v6 table
3522 FIB_ENTRY_FLAG_NONE,
3525 tm->hw[0]->sw_if_index,
3529 FIB_ROUTE_PATH_FLAG_NONE);
3531 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3532 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3533 ai = fib_entry_get_adj(fei);
3535 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3536 "2001::/64 via ARP-adj");
3537 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3538 "2001::/64 is link type v6");
3539 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3540 "2001::/64 ADJ-adj is NH proto v4");
3541 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3544 * add a uRPF exempt prefix:
3546 * - it's forwarding is drop
3547 * - it's uRPF list is not empty
3548 * - the uRPF list for the default route (it's cover) is empty
3550 fei = fib_table_entry_special_add(fib_index,
3552 FIB_SOURCE_URPF_EXEMPT,
3553 FIB_ENTRY_FLAG_DROP,
3555 dpo = fib_entry_contribute_ip_forwarding(fei);
3556 FIB_TEST(load_balance_is_drop(dpo),
3557 "uRPF exempt 4.1.1.1/32 DROP");
3558 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3559 "uRPF list for exempt prefix has itf index 0");
3560 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3561 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3562 "uRPF list for 0.0.0.0/0 empty");
3564 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3567 * An adj-fib that fails the refinement criteria - no connected cover
3569 fib_prefix_t pfx_12_10_10_2_s_32 = {
3571 .fp_proto = FIB_PROTOCOL_IP4,
3574 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3578 fib_table_entry_update_one_path(fib_index,
3579 &pfx_12_10_10_2_s_32,
3581 FIB_ENTRY_FLAG_ATTACHED,
3583 &pfx_12_10_10_2_s_32.fp_addr,
3584 tm->hw[0]->sw_if_index,
3585 ~0, // invalid fib index
3588 FIB_ROUTE_PATH_FLAG_NONE);
3590 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3591 dpo = fib_entry_contribute_ip_forwarding(fei);
3592 FIB_TEST(!dpo_id_is_valid(dpo),
3593 "no connected cover adj-fib fails refinement");
3595 fib_table_entry_delete(fib_index,
3596 &pfx_12_10_10_2_s_32,
3600 * An adj-fib that fails the refinement criteria - cover is connected
3601 * but on a different interface
3603 fib_prefix_t pfx_10_10_10_127_s_32 = {
3605 .fp_proto = FIB_PROTOCOL_IP4,
3608 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3612 fib_table_entry_update_one_path(fib_index,
3613 &pfx_10_10_10_127_s_32,
3615 FIB_ENTRY_FLAG_ATTACHED,
3617 &pfx_10_10_10_127_s_32.fp_addr,
3618 tm->hw[1]->sw_if_index,
3619 ~0, // invalid fib index
3622 FIB_ROUTE_PATH_FLAG_NONE);
3624 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3625 dpo = fib_entry_contribute_ip_forwarding(fei);
3626 FIB_TEST(!dpo_id_is_valid(dpo),
3627 "wrong interface adj-fib fails refinement");
3629 fib_table_entry_delete(fib_index,
3630 &pfx_10_10_10_127_s_32,
3637 fib_table_entry_delete(fib_index,
3638 &pfx_10_10_10_1_s_32,
3640 fib_table_entry_delete(fib_index,
3641 &pfx_10_10_10_2_s_32,
3643 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3644 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
3645 "10.10.10.1/32 adj-fib removed");
3646 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3647 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
3648 "10.10.10.2/32 adj-fib removed");
3651 * -2 entries and -2 non-shared path-list
3653 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3654 fib_path_list_db_size());
3655 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
3656 fib_path_list_pool_size());
3657 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
3658 fib_entry_pool_size());
3661 * unlock the adjacencies for which this test provided a rewrite.
3662 * These are the last locks on these adjs. they should thus go away.
3666 adj_unlock(ai_12_12_12_12);
3668 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3673 * remove the interface prefixes
3675 local_pfx.fp_len = 32;
3676 fib_table_entry_special_remove(fib_index, &local_pfx,
3677 FIB_SOURCE_INTERFACE);
3678 fei = fib_table_lookup(fib_index, &local_pfx);
3680 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3681 fib_table_lookup_exact_match(fib_index, &local_pfx),
3682 "10.10.10.10/32 adj-fib removed");
3684 local_pfx.fp_len = 24;
3685 fib_table_entry_delete(fib_index, &local_pfx,
3686 FIB_SOURCE_INTERFACE);
3688 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3689 fib_table_lookup_exact_match(fib_index, &local_pfx),
3690 "10.10.10.10/24 adj-fib removed");
3693 * -2 entries and -2 non-shared path-list
3695 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3696 fib_path_list_db_size());
3697 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
3698 fib_path_list_pool_size());
3699 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
3700 fib_entry_pool_size());
3703 * Last but not least, remove the VRF
3705 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3708 "NO API Source'd prefixes");
3709 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3712 "NO RR Source'd prefixes");
3713 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3715 FIB_SOURCE_INTERFACE)),
3716 "NO INterface Source'd prefixes");
3718 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
3720 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3721 fib_path_list_db_size());
3722 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
3723 fib_path_list_pool_size());
3724 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
3725 fib_entry_pool_size());
3726 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
3727 pool_elts(fib_urpf_list_pool));
3736 * In the default table check for the presence and correct forwarding
3737 * of the special entries
3739 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
3740 const dpo_id_t *dpo, *dpo_drop;
3741 const ip_adjacency_t *adj;
3742 const receive_dpo_t *rd;
3747 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3750 /* via 2001:0:0:1::2 */
3751 ip46_address_t nh_2001_2 = {
3754 [0] = clib_host_to_net_u64(0x2001000000000001),
3755 [1] = clib_host_to_net_u64(0x0000000000000002),
3762 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
3764 /* Find or create FIB table 11 */
3765 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
3767 for (ii = 0; ii < 4; ii++)
3769 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
3772 fib_prefix_t pfx_0_0 = {
3774 .fp_proto = FIB_PROTOCOL_IP6,
3782 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
3783 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
3784 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3785 "Default route is DROP");
3787 dpo = fib_entry_contribute_ip_forwarding(dfrt);
3788 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3791 &pfx_0_0.fp_addr.ip6)),
3792 "default-route; fwd and non-fwd tables match");
3794 // FIXME - check specials.
3797 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
3798 * each with 2 entries and a v6 mfib with 4 path-lists.
3799 * All entries are special so no path-list sharing.
3802 #define PNPS (5+4+4)
3803 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3804 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
3805 fib_path_list_pool_size());
3806 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
3807 fib_entry_pool_size());
3810 * add interface routes.
3811 * validate presence of /64 attached and /128 recieve.
3812 * test for the presence of the receive address in the glean and local adj
3814 * receive on 2001:0:0:1::1/128
3816 fib_prefix_t local_pfx = {
3818 .fp_proto = FIB_PROTOCOL_IP6,
3822 [0] = clib_host_to_net_u64(0x2001000000000001),
3823 [1] = clib_host_to_net_u64(0x0000000000000001),
3829 fib_table_entry_update_one_path(fib_index, &local_pfx,
3830 FIB_SOURCE_INTERFACE,
3831 (FIB_ENTRY_FLAG_CONNECTED |
3832 FIB_ENTRY_FLAG_ATTACHED),
3835 tm->hw[0]->sw_if_index,
3839 FIB_ROUTE_PATH_FLAG_NONE);
3840 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3842 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3844 ai = fib_entry_get_adj(fei);
3845 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
3847 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3848 "attached interface adj is glean");
3849 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3850 &adj->sub_type.glean.receive_addr)),
3851 "attached interface adj is receive ok");
3852 dpo = fib_entry_contribute_ip_forwarding(fei);
3853 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3856 &local_pfx.fp_addr.ip6)),
3857 "attached-route; fwd and non-fwd tables match");
3859 local_pfx.fp_len = 128;
3860 fib_table_entry_update_one_path(fib_index, &local_pfx,
3861 FIB_SOURCE_INTERFACE,
3862 (FIB_ENTRY_FLAG_CONNECTED |
3863 FIB_ENTRY_FLAG_LOCAL),
3866 tm->hw[0]->sw_if_index,
3867 ~0, // invalid fib index
3870 FIB_ROUTE_PATH_FLAG_NONE);
3871 fei = fib_table_lookup(fib_index, &local_pfx);
3873 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
3875 dpo = fib_entry_contribute_ip_forwarding(fei);
3876 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3877 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
3878 "local interface adj is local");
3879 rd = receive_dpo_get(dpo->dpoi_index);
3881 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3883 "local interface adj is receive ok");
3885 dpo = fib_entry_contribute_ip_forwarding(fei);
3886 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3889 &local_pfx.fp_addr.ip6)),
3890 "local-route; fwd and non-fwd tables match");
3893 * +2 entries. +2 unshared path-lists
3895 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3896 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3897 fib_path_list_pool_size());
3898 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3899 fib_entry_pool_size());
3902 * Modify the default route to be via an adj not yet known.
3903 * this sources the defalut route with the API source, which is
3904 * a higher preference to the DEFAULT_ROUTE source
3906 fib_table_entry_path_add(fib_index, &pfx_0_0,
3908 FIB_ENTRY_FLAG_NONE,
3911 tm->hw[0]->sw_if_index,
3915 FIB_ROUTE_PATH_FLAG_NONE);
3916 fei = fib_table_lookup(fib_index, &pfx_0_0);
3918 FIB_TEST((fei == dfrt), "default route same index");
3919 ai = fib_entry_get_adj(fei);
3920 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
3922 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
3923 "adj is incomplete");
3924 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
3925 "adj nbr next-hop ok");
3928 * find the adj in the shared db
3930 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
3933 tm->hw[0]->sw_if_index);
3934 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
3935 adj_unlock(locked_ai);
3938 * no more entires. +1 shared path-list
3940 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3941 fib_path_list_db_size());
3942 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
3943 fib_path_list_pool_size());
3944 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3945 fib_entry_pool_size());
3948 * remove the API source from the default route. We expected
3949 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
3951 fib_table_entry_path_remove(fib_index, &pfx_0_0,
3955 tm->hw[0]->sw_if_index,
3958 FIB_ROUTE_PATH_FLAG_NONE);
3959 fei = fib_table_lookup(fib_index, &pfx_0_0);
3961 FIB_TEST((fei == dfrt), "default route same index");
3962 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3963 "Default route is DROP");
3966 * no more entires. -1 shared path-list
3968 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3969 fib_path_list_db_size());
3970 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
3971 fib_path_list_pool_size());
3972 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
3973 fib_entry_pool_size());
3976 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
3978 fib_prefix_t pfx_2001_1_2_s_128 = {
3980 .fp_proto = FIB_PROTOCOL_IP6,
3984 [0] = clib_host_to_net_u64(0x2001000000000001),
3985 [1] = clib_host_to_net_u64(0x0000000000000002),
3990 fib_prefix_t pfx_2001_1_3_s_128 = {
3992 .fp_proto = FIB_PROTOCOL_IP6,
3996 [0] = clib_host_to_net_u64(0x2001000000000001),
3997 [1] = clib_host_to_net_u64(0x0000000000000003),
4003 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4006 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4008 &pfx_2001_1_2_s_128.fp_addr,
4009 tm->hw[0]->sw_if_index);
4010 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4011 adj = adj_get(ai_01);
4012 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4013 "adj is incomplete");
4014 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4015 &adj->sub_type.nbr.next_hop)),
4016 "adj nbr next-hop ok");
4018 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4019 fib_test_build_rewrite(eth_addr));
4020 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4022 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4023 &adj->sub_type.nbr.next_hop)),
4024 "adj nbr next-hop ok");
4026 fib_table_entry_update_one_path(fib_index,
4027 &pfx_2001_1_2_s_128,
4029 FIB_ENTRY_FLAG_ATTACHED,
4031 &pfx_2001_1_2_s_128.fp_addr,
4032 tm->hw[0]->sw_if_index,
4036 FIB_ROUTE_PATH_FLAG_NONE);
4038 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4039 ai = fib_entry_get_adj(fei);
4040 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4044 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4046 &pfx_2001_1_3_s_128.fp_addr,
4047 tm->hw[0]->sw_if_index);
4048 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4049 adj = adj_get(ai_02);
4050 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4051 "adj is incomplete");
4052 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4053 &adj->sub_type.nbr.next_hop)),
4054 "adj nbr next-hop ok");
4056 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4057 fib_test_build_rewrite(eth_addr));
4058 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4060 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4061 &adj->sub_type.nbr.next_hop)),
4062 "adj nbr next-hop ok");
4063 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4065 fib_table_entry_update_one_path(fib_index,
4066 &pfx_2001_1_3_s_128,
4068 FIB_ENTRY_FLAG_ATTACHED,
4070 &pfx_2001_1_3_s_128.fp_addr,
4071 tm->hw[0]->sw_if_index,
4075 FIB_ROUTE_PATH_FLAG_NONE);
4077 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4078 ai = fib_entry_get_adj(fei);
4079 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4082 * +2 entries, +2 unshread path-lists.
4084 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4085 fib_path_list_db_size());
4086 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4087 fib_path_list_pool_size());
4088 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4089 fib_entry_pool_size());
4092 * Add a 2 routes via the first ADJ. ensure path-list sharing
4094 fib_prefix_t pfx_2001_a_s_64 = {
4096 .fp_proto = FIB_PROTOCOL_IP6,
4100 [0] = clib_host_to_net_u64(0x200100000000000a),
4101 [1] = clib_host_to_net_u64(0x0000000000000000),
4106 fib_prefix_t pfx_2001_b_s_64 = {
4108 .fp_proto = FIB_PROTOCOL_IP6,
4112 [0] = clib_host_to_net_u64(0x200100000000000b),
4113 [1] = clib_host_to_net_u64(0x0000000000000000),
4119 fib_table_entry_path_add(fib_index,
4122 FIB_ENTRY_FLAG_NONE,
4125 tm->hw[0]->sw_if_index,
4129 FIB_ROUTE_PATH_FLAG_NONE);
4130 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4131 ai = fib_entry_get_adj(fei);
4132 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4133 fib_table_entry_path_add(fib_index,
4136 FIB_ENTRY_FLAG_NONE,
4139 tm->hw[0]->sw_if_index,
4143 FIB_ROUTE_PATH_FLAG_NONE);
4144 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4145 ai = fib_entry_get_adj(fei);
4146 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4149 * +2 entries, +1 shared path-list.
4151 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4152 fib_path_list_db_size());
4153 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4154 fib_path_list_pool_size());
4155 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4156 fib_entry_pool_size());
4159 * add a v4 prefix via a v6 next-hop
4161 fib_prefix_t pfx_1_1_1_1_s_32 = {
4163 .fp_proto = FIB_PROTOCOL_IP4,
4165 .ip4.as_u32 = 0x01010101,
4168 fei = fib_table_entry_path_add(0, // default table
4171 FIB_ENTRY_FLAG_NONE,
4174 tm->hw[0]->sw_if_index,
4178 FIB_ROUTE_PATH_FLAG_NONE);
4179 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4180 "1.1.1.1/32 o v6 route present");
4181 ai = fib_entry_get_adj(fei);
4183 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4184 "1.1.1.1/32 via ARP-adj");
4185 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4186 "1.1.1.1/32 ADJ-adj is link type v4");
4187 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4188 "1.1.1.1/32 ADJ-adj is NH proto v6");
4189 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4194 fib_prefix_t pfx_2001_c_s_64 = {
4196 .fp_proto = FIB_PROTOCOL_IP6,
4200 [0] = clib_host_to_net_u64(0x200100000000000c),
4201 [1] = clib_host_to_net_u64(0x0000000000000000),
4206 fib_table_entry_path_add(fib_index,
4209 FIB_ENTRY_FLAG_ATTACHED,
4212 tm->hw[0]->sw_if_index,
4216 FIB_ROUTE_PATH_FLAG_NONE);
4217 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4218 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4219 ai = fib_entry_get_adj(fei);
4221 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4222 "2001:0:0:c/64 attached resolves via glean");
4224 fib_table_entry_path_remove(fib_index,
4229 tm->hw[0]->sw_if_index,
4232 FIB_ROUTE_PATH_FLAG_NONE);
4233 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4234 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4237 * Shutdown the interface on which we have a connected and through
4238 * which the routes are reachable.
4239 * This will result in the connected, adj-fibs, and routes linking to drop
4240 * The local/for-us prefix continues to receive.
4242 clib_error_t * error;
4244 error = vnet_sw_interface_set_flags(vnet_get_main(),
4245 tm->hw[0]->sw_if_index,
4246 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4247 FIB_TEST((NULL == error), "Interface shutdown OK");
4249 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4250 dpo = fib_entry_contribute_ip_forwarding(fei);
4251 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4252 "2001::b/64 resolves via drop");
4254 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4255 dpo = fib_entry_contribute_ip_forwarding(fei);
4256 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4257 "2001::a/64 resolves via drop");
4258 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4259 dpo = fib_entry_contribute_ip_forwarding(fei);
4260 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4261 "2001:0:0:1::3/64 resolves via drop");
4262 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4263 dpo = fib_entry_contribute_ip_forwarding(fei);
4264 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4265 "2001:0:0:1::2/64 resolves via drop");
4266 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4267 dpo = fib_entry_contribute_ip_forwarding(fei);
4268 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4269 "2001:0:0:1::1/128 not drop");
4270 local_pfx.fp_len = 64;
4271 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4272 dpo = fib_entry_contribute_ip_forwarding(fei);
4273 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4274 "2001:0:0:1/64 resolves via drop");
4279 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4280 fib_path_list_db_size());
4281 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4282 fib_path_list_pool_size());
4283 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4284 fib_entry_pool_size());
4287 * shutdown one of the other interfaces, then add a connected.
4288 * and swap one of the routes to it.
4290 error = vnet_sw_interface_set_flags(vnet_get_main(),
4291 tm->hw[1]->sw_if_index,
4292 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4293 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4295 fib_prefix_t connected_pfx = {
4297 .fp_proto = FIB_PROTOCOL_IP6,
4300 /* 2001:0:0:2::1/64 */
4302 [0] = clib_host_to_net_u64(0x2001000000000002),
4303 [1] = clib_host_to_net_u64(0x0000000000000001),
4308 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4309 FIB_SOURCE_INTERFACE,
4310 (FIB_ENTRY_FLAG_CONNECTED |
4311 FIB_ENTRY_FLAG_ATTACHED),
4314 tm->hw[1]->sw_if_index,
4318 FIB_ROUTE_PATH_FLAG_NONE);
4319 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4320 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4321 dpo = fib_entry_contribute_ip_forwarding(fei);
4322 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4323 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4324 "2001:0:0:2/64 not resolves via drop");
4326 connected_pfx.fp_len = 128;
4327 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4328 FIB_SOURCE_INTERFACE,
4329 (FIB_ENTRY_FLAG_CONNECTED |
4330 FIB_ENTRY_FLAG_LOCAL),
4333 tm->hw[0]->sw_if_index,
4334 ~0, // invalid fib index
4337 FIB_ROUTE_PATH_FLAG_NONE);
4338 fei = fib_table_lookup(fib_index, &connected_pfx);
4340 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4341 dpo = fib_entry_contribute_ip_forwarding(fei);
4342 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4343 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4344 "local interface adj is local");
4345 rd = receive_dpo_get(dpo->dpoi_index);
4346 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4348 "local interface adj is receive ok");
4351 * +2 entries, +2 unshared path-lists
4353 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4354 fib_path_list_db_size());
4355 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4356 fib_path_list_pool_size());
4357 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4358 fib_entry_pool_size());
4362 * bring the interface back up. we expected the routes to return
4363 * to normal forwarding.
4365 error = vnet_sw_interface_set_flags(vnet_get_main(),
4366 tm->hw[0]->sw_if_index,
4367 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4368 FIB_TEST((NULL == error), "Interface bring-up OK");
4369 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4370 ai = fib_entry_get_adj(fei);
4371 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4372 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4373 ai = fib_entry_get_adj(fei);
4374 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4375 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4376 ai = fib_entry_get_adj(fei);
4377 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4378 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4379 ai = fib_entry_get_adj(fei);
4380 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4381 local_pfx.fp_len = 64;
4382 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4383 ai = fib_entry_get_adj(fei);
4385 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4386 "attached interface adj is glean");
4389 * Same test as above, but this time the HW interface goes down
4391 error = vnet_hw_interface_set_flags(vnet_get_main(),
4392 tm->hw_if_indicies[0],
4393 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4394 FIB_TEST((NULL == error), "Interface shutdown OK");
4396 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4397 dpo = fib_entry_contribute_ip_forwarding(fei);
4398 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4399 "2001::b/64 resolves via drop");
4400 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4401 dpo = fib_entry_contribute_ip_forwarding(fei);
4402 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4403 "2001::a/64 resolves via drop");
4404 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4405 dpo = fib_entry_contribute_ip_forwarding(fei);
4406 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4407 "2001:0:0:1::3/128 resolves via drop");
4408 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4409 dpo = fib_entry_contribute_ip_forwarding(fei);
4410 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4411 "2001:0:0:1::2/128 resolves via drop");
4412 local_pfx.fp_len = 128;
4413 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4414 dpo = fib_entry_contribute_ip_forwarding(fei);
4415 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4416 "2001:0:0:1::1/128 not drop");
4417 local_pfx.fp_len = 64;
4418 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4419 dpo = fib_entry_contribute_ip_forwarding(fei);
4420 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4421 "2001:0:0:1/64 resolves via drop");
4423 error = vnet_hw_interface_set_flags(vnet_get_main(),
4424 tm->hw_if_indicies[0],
4425 VNET_HW_INTERFACE_FLAG_LINK_UP);
4426 FIB_TEST((NULL == error), "Interface bring-up OK");
4427 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4428 ai = fib_entry_get_adj(fei);
4429 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4430 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4431 ai = fib_entry_get_adj(fei);
4432 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4433 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4434 ai = fib_entry_get_adj(fei);
4435 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4436 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4437 ai = fib_entry_get_adj(fei);
4438 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4439 local_pfx.fp_len = 64;
4440 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4441 ai = fib_entry_get_adj(fei);
4443 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4444 "attached interface adj is glean");
4447 * Delete the interface that the routes reolve through.
4448 * Again no routes are removed. They all point to drop.
4450 * This is considered an error case. The control plane should
4451 * not remove interfaces through which routes resolve, but
4452 * such things can happen. ALL affected routes will drop.
4454 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4456 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4457 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4458 "2001::b/64 resolves via drop");
4459 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4460 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4461 "2001::b/64 resolves via drop");
4462 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4463 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4464 "2001:0:0:1::3/64 resolves via drop");
4465 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4466 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4467 "2001:0:0:1::2/64 resolves via drop");
4468 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4469 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4470 "2001:0:0:1::1/128 is drop");
4471 local_pfx.fp_len = 64;
4472 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4473 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4474 "2001:0:0:1/64 resolves via drop");
4479 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4480 fib_path_list_db_size());
4481 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4482 fib_path_list_pool_size());
4483 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4484 fib_entry_pool_size());
4487 * Add the interface back. routes stay unresolved.
4489 error = ethernet_register_interface(vnet_get_main(),
4490 test_interface_device_class.index,
4493 &tm->hw_if_indicies[0],
4494 /* flag change */ 0);
4496 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4497 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4498 "2001::b/64 resolves via drop");
4499 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4500 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4501 "2001::b/64 resolves via drop");
4502 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4503 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4504 "2001:0:0:1::3/64 resolves via drop");
4505 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4506 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4507 "2001:0:0:1::2/64 resolves via drop");
4508 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4509 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4510 "2001:0:0:1::1/128 is drop");
4511 local_pfx.fp_len = 64;
4512 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4513 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4514 "2001:0:0:1/64 resolves via drop");
4517 * CLEANUP ALL the routes
4519 fib_table_entry_delete(fib_index,
4522 fib_table_entry_delete(fib_index,
4525 fib_table_entry_delete(fib_index,
4528 fib_table_entry_delete(fib_index,
4529 &pfx_2001_1_3_s_128,
4531 fib_table_entry_delete(fib_index,
4532 &pfx_2001_1_2_s_128,
4534 local_pfx.fp_len = 64;
4535 fib_table_entry_delete(fib_index, &local_pfx,
4536 FIB_SOURCE_INTERFACE);
4537 local_pfx.fp_len = 128;
4538 fib_table_entry_special_remove(fib_index, &local_pfx,
4539 FIB_SOURCE_INTERFACE);
4540 connected_pfx.fp_len = 64;
4541 fib_table_entry_delete(fib_index, &connected_pfx,
4542 FIB_SOURCE_INTERFACE);
4543 connected_pfx.fp_len = 128;
4544 fib_table_entry_special_remove(fib_index, &connected_pfx,
4545 FIB_SOURCE_INTERFACE);
4547 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4548 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4549 "2001::a/64 removed");
4550 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4551 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4552 "2001::b/64 removed");
4553 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4554 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4555 "2001:0:0:1::3/128 removed");
4556 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4557 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4558 "2001:0:0:1::3/128 removed");
4559 local_pfx.fp_len = 64;
4560 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4561 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4562 "2001:0:0:1/64 removed");
4563 local_pfx.fp_len = 128;
4564 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4565 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4566 "2001:0:0:1::1/128 removed");
4567 connected_pfx.fp_len = 64;
4568 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4569 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4570 "2001:0:0:2/64 removed");
4571 connected_pfx.fp_len = 128;
4572 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4573 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4574 "2001:0:0:2::1/128 removed");
4577 * -8 entries. -7 path-lists (1 was shared).
4579 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4580 fib_path_list_db_size());
4581 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
4582 fib_path_list_pool_size());
4583 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4584 fib_entry_pool_size());
4587 * now remove the VRF
4589 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4591 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4592 fib_path_list_db_size());
4593 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
4594 fib_path_list_pool_size());
4595 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
4596 fib_entry_pool_size());
4602 * return the interfaces to up state
4604 error = vnet_sw_interface_set_flags(vnet_get_main(),
4605 tm->hw[0]->sw_if_index,
4606 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4607 error = vnet_sw_interface_set_flags(vnet_get_main(),
4608 tm->hw[1]->sw_if_index,
4609 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4611 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4618 * Test Attached Exports
4623 const dpo_id_t *dpo, *dpo_drop;
4624 const u32 fib_index = 0;
4625 fib_node_index_t fei;
4632 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4636 * add interface routes. We'll assume this works. It's more rigorously
4639 fib_prefix_t local_pfx = {
4641 .fp_proto = FIB_PROTOCOL_IP4,
4645 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4650 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4651 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4653 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4655 fib_table_entry_update_one_path(fib_index, &local_pfx,
4656 FIB_SOURCE_INTERFACE,
4657 (FIB_ENTRY_FLAG_CONNECTED |
4658 FIB_ENTRY_FLAG_ATTACHED),
4661 tm->hw[0]->sw_if_index,
4665 FIB_ROUTE_PATH_FLAG_NONE);
4666 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4667 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4668 "attached interface route present");
4670 local_pfx.fp_len = 32;
4671 fib_table_entry_update_one_path(fib_index, &local_pfx,
4672 FIB_SOURCE_INTERFACE,
4673 (FIB_ENTRY_FLAG_CONNECTED |
4674 FIB_ENTRY_FLAG_LOCAL),
4677 tm->hw[0]->sw_if_index,
4678 ~0, // invalid fib index
4681 FIB_ROUTE_PATH_FLAG_NONE);
4682 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4684 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4685 "local interface route present");
4688 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4690 fib_prefix_t pfx_10_10_10_1_s_32 = {
4692 .fp_proto = FIB_PROTOCOL_IP4,
4695 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4698 fib_node_index_t ai;
4700 fib_table_entry_update_one_path(fib_index,
4701 &pfx_10_10_10_1_s_32,
4703 FIB_ENTRY_FLAG_ATTACHED,
4705 &pfx_10_10_10_1_s_32.fp_addr,
4706 tm->hw[0]->sw_if_index,
4707 ~0, // invalid fib index
4710 FIB_ROUTE_PATH_FLAG_NONE);
4712 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4713 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4714 ai = fib_entry_get_adj(fei);
4717 * create another FIB table into which routes will be imported
4719 u32 import_fib_index1;
4721 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4724 * Add an attached route in the import FIB
4726 local_pfx.fp_len = 24;
4727 fib_table_entry_update_one_path(import_fib_index1,
4730 FIB_ENTRY_FLAG_NONE,
4733 tm->hw[0]->sw_if_index,
4734 ~0, // invalid fib index
4737 FIB_ROUTE_PATH_FLAG_NONE);
4738 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4739 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4742 * check for the presence of the adj-fibs in the import table
4744 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4745 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4746 FIB_TEST((ai == fib_entry_get_adj(fei)),
4747 "adj-fib1 Import uses same adj as export");
4750 * check for the presence of the local in the import table
4752 local_pfx.fp_len = 32;
4753 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4754 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4757 * Add another adj-fin in the export table. Expect this
4758 * to get magically exported;
4760 fib_prefix_t pfx_10_10_10_2_s_32 = {
4762 .fp_proto = FIB_PROTOCOL_IP4,
4765 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4769 fib_table_entry_update_one_path(fib_index,
4770 &pfx_10_10_10_2_s_32,
4772 FIB_ENTRY_FLAG_ATTACHED,
4774 &pfx_10_10_10_2_s_32.fp_addr,
4775 tm->hw[0]->sw_if_index,
4776 ~0, // invalid fib index
4779 FIB_ROUTE_PATH_FLAG_NONE);
4780 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4781 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4782 ai = fib_entry_get_adj(fei);
4784 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4785 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4786 FIB_TEST((ai == fib_entry_get_adj(fei)),
4787 "Import uses same adj as export");
4788 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
4789 "ADJ-fib2 imported flags %d",
4790 fib_entry_get_flags(fei));
4793 * create a 2nd FIB table into which routes will be imported
4795 u32 import_fib_index2;
4797 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4800 * Add an attached route in the import FIB
4802 local_pfx.fp_len = 24;
4803 fib_table_entry_update_one_path(import_fib_index2,
4806 FIB_ENTRY_FLAG_NONE,
4809 tm->hw[0]->sw_if_index,
4810 ~0, // invalid fib index
4813 FIB_ROUTE_PATH_FLAG_NONE);
4814 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4815 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4818 * check for the presence of all the adj-fibs and local in the import table
4820 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4821 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4822 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4823 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4824 local_pfx.fp_len = 32;
4825 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4826 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4829 * add a 3rd adj-fib. expect it to be exported to both tables.
4831 fib_prefix_t pfx_10_10_10_3_s_32 = {
4833 .fp_proto = FIB_PROTOCOL_IP4,
4836 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4840 fib_table_entry_update_one_path(fib_index,
4841 &pfx_10_10_10_3_s_32,
4843 FIB_ENTRY_FLAG_ATTACHED,
4845 &pfx_10_10_10_3_s_32.fp_addr,
4846 tm->hw[0]->sw_if_index,
4847 ~0, // invalid fib index
4850 FIB_ROUTE_PATH_FLAG_NONE);
4851 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4852 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4853 ai = fib_entry_get_adj(fei);
4855 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4856 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4857 FIB_TEST((ai == fib_entry_get_adj(fei)),
4858 "Import uses same adj as export");
4859 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4860 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4861 FIB_TEST((ai == fib_entry_get_adj(fei)),
4862 "Import uses same adj as export");
4865 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4867 fib_table_entry_delete(fib_index,
4868 &pfx_10_10_10_3_s_32,
4871 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4872 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4874 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4875 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
4877 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4878 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
4881 * remove the attached route from the 2nd FIB. expect the imported
4882 * entires to be removed
4884 local_pfx.fp_len = 24;
4885 fib_table_entry_delete(import_fib_index2,
4888 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4889 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
4891 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4892 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
4893 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4894 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
4895 local_pfx.fp_len = 32;
4896 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4897 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
4899 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4900 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
4901 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4902 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
4903 local_pfx.fp_len = 32;
4904 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4905 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
4908 * modify the route in FIB1 so it is no longer attached. expect the imported
4909 * entires to be removed
4911 local_pfx.fp_len = 24;
4912 fib_table_entry_update_one_path(import_fib_index1,
4915 FIB_ENTRY_FLAG_NONE,
4917 &pfx_10_10_10_2_s_32.fp_addr,
4918 tm->hw[0]->sw_if_index,
4919 ~0, // invalid fib index
4922 FIB_ROUTE_PATH_FLAG_NONE);
4923 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4924 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
4925 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4926 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4927 local_pfx.fp_len = 32;
4928 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4929 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4932 * modify it back to attached. expect the adj-fibs back
4934 local_pfx.fp_len = 24;
4935 fib_table_entry_update_one_path(import_fib_index1,
4938 FIB_ENTRY_FLAG_NONE,
4941 tm->hw[0]->sw_if_index,
4942 ~0, // invalid fib index
4945 FIB_ROUTE_PATH_FLAG_NONE);
4946 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4947 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
4948 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4949 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
4950 local_pfx.fp_len = 32;
4951 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4952 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
4955 * add a covering attached next-hop for the interface address, so we have
4956 * a valid adj to find when we check the forwarding tables
4958 fib_prefix_t pfx_10_0_0_0_s_8 = {
4960 .fp_proto = FIB_PROTOCOL_IP4,
4963 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
4967 fei = fib_table_entry_update_one_path(fib_index,
4970 FIB_ENTRY_FLAG_NONE,
4972 &pfx_10_10_10_3_s_32.fp_addr,
4973 tm->hw[0]->sw_if_index,
4974 ~0, // invalid fib index
4977 FIB_ROUTE_PATH_FLAG_NONE);
4978 dpo = fib_entry_contribute_ip_forwarding(fei);
4981 * remove the route in the export fib. expect the adj-fibs to be removed
4983 local_pfx.fp_len = 24;
4984 fib_table_entry_delete(fib_index,
4986 FIB_SOURCE_INTERFACE);
4988 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4989 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
4990 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4991 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
4992 local_pfx.fp_len = 32;
4993 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4994 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
4997 * the adj-fibs in the export VRF are present in the FIB table,
4998 * but not installed in forwarding, since they have no attached cover.
4999 * Consequently a lookup in the MTRIE gives the adj for the covering
5002 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5003 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5006 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5007 FIB_TEST(lbi == dpo->dpoi_index,
5008 "10.10.10.1 forwards on \n%U not \n%U",
5009 format_load_balance, lbi, 0,
5010 format_dpo_id, dpo, 0);
5011 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5012 FIB_TEST(lbi == dpo->dpoi_index,
5013 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5014 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5015 FIB_TEST(lbi == dpo->dpoi_index,
5016 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5019 * add the export prefix back, but not as attached.
5020 * No adj-fibs in export nor import tables
5022 local_pfx.fp_len = 24;
5023 fei = fib_table_entry_update_one_path(fib_index,
5026 FIB_ENTRY_FLAG_NONE,
5028 &pfx_10_10_10_1_s_32.fp_addr,
5029 tm->hw[0]->sw_if_index,
5030 ~0, // invalid fib index
5033 FIB_ROUTE_PATH_FLAG_NONE);
5034 dpo = fib_entry_contribute_ip_forwarding(fei);
5036 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5037 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5038 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5039 FIB_TEST(lbi == dpo->dpoi_index,
5040 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5041 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5042 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5043 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5044 FIB_TEST(lbi == dpo->dpoi_index,
5045 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5047 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5048 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5049 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5050 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5051 local_pfx.fp_len = 32;
5052 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5053 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5056 * modify the export prefix so it is attached. expect all covereds to return
5058 local_pfx.fp_len = 24;
5059 fib_table_entry_update_one_path(fib_index,
5062 FIB_ENTRY_FLAG_NONE,
5065 tm->hw[0]->sw_if_index,
5066 ~0, // invalid fib index
5069 FIB_ROUTE_PATH_FLAG_NONE);
5071 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5072 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5073 dpo = fib_entry_contribute_ip_forwarding(fei);
5074 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5075 "Adj-fib1 is not drop in export");
5076 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5077 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5078 local_pfx.fp_len = 32;
5079 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5080 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5081 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5082 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5083 dpo = fib_entry_contribute_ip_forwarding(fei);
5084 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5085 "Adj-fib1 is not drop in export");
5086 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5087 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5088 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5089 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5090 local_pfx.fp_len = 32;
5091 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5092 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5095 * modify the export prefix so connected. no change.
5097 local_pfx.fp_len = 24;
5098 fib_table_entry_update_one_path(fib_index, &local_pfx,
5099 FIB_SOURCE_INTERFACE,
5100 (FIB_ENTRY_FLAG_CONNECTED |
5101 FIB_ENTRY_FLAG_ATTACHED),
5104 tm->hw[0]->sw_if_index,
5108 FIB_ROUTE_PATH_FLAG_NONE);
5110 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5111 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5112 dpo = fib_entry_contribute_ip_forwarding(fei);
5113 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5114 "Adj-fib1 is not drop in export");
5115 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5116 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5117 local_pfx.fp_len = 32;
5118 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5119 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5120 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5121 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5122 dpo = fib_entry_contribute_ip_forwarding(fei);
5123 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5124 "Adj-fib1 is not drop in export");
5125 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5126 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5127 local_pfx.fp_len = 32;
5128 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5129 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5134 fib_table_entry_delete(fib_index,
5137 fib_table_entry_delete(fib_index,
5138 &pfx_10_10_10_1_s_32,
5140 fib_table_entry_delete(fib_index,
5141 &pfx_10_10_10_2_s_32,
5143 local_pfx.fp_len = 32;
5144 fib_table_entry_delete(fib_index,
5146 FIB_SOURCE_INTERFACE);
5147 local_pfx.fp_len = 24;
5148 fib_table_entry_delete(fib_index,
5151 fib_table_entry_delete(fib_index,
5153 FIB_SOURCE_INTERFACE);
5154 local_pfx.fp_len = 24;
5155 fib_table_entry_delete(import_fib_index1,
5159 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5160 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5162 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5170 * Test the recursive route route handling for GRE tunnels
5173 fib_test_label (void)
5175 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;
5176 const u32 fib_index = 0;
5181 lb_count = pool_elts(load_balance_pool);
5186 * add interface routes. We'll assume this works. It's more rigorously
5189 fib_prefix_t local0_pfx = {
5191 .fp_proto = FIB_PROTOCOL_IP4,
5195 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5200 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5203 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5204 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5206 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5207 FIB_SOURCE_INTERFACE,
5208 (FIB_ENTRY_FLAG_CONNECTED |
5209 FIB_ENTRY_FLAG_ATTACHED),
5212 tm->hw[0]->sw_if_index,
5216 FIB_ROUTE_PATH_FLAG_NONE);
5217 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5218 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5219 "attached interface route present");
5221 local0_pfx.fp_len = 32;
5222 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5223 FIB_SOURCE_INTERFACE,
5224 (FIB_ENTRY_FLAG_CONNECTED |
5225 FIB_ENTRY_FLAG_LOCAL),
5228 tm->hw[0]->sw_if_index,
5229 ~0, // invalid fib index
5232 FIB_ROUTE_PATH_FLAG_NONE);
5233 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5235 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5236 "local interface route present");
5238 fib_prefix_t local1_pfx = {
5240 .fp_proto = FIB_PROTOCOL_IP4,
5244 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5249 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5250 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5252 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5253 FIB_SOURCE_INTERFACE,
5254 (FIB_ENTRY_FLAG_CONNECTED |
5255 FIB_ENTRY_FLAG_ATTACHED),
5258 tm->hw[1]->sw_if_index,
5262 FIB_ROUTE_PATH_FLAG_NONE);
5263 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5264 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5265 "attached interface route present");
5267 local1_pfx.fp_len = 32;
5268 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5269 FIB_SOURCE_INTERFACE,
5270 (FIB_ENTRY_FLAG_CONNECTED |
5271 FIB_ENTRY_FLAG_LOCAL),
5274 tm->hw[1]->sw_if_index,
5275 ~0, // invalid fib index
5278 FIB_ROUTE_PATH_FLAG_NONE);
5279 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5281 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5282 "local interface route present");
5284 ip46_address_t nh_10_10_10_1 = {
5286 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5289 ip46_address_t nh_10_10_11_1 = {
5291 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5294 ip46_address_t nh_10_10_11_2 = {
5296 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5300 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5303 tm->hw[1]->sw_if_index);
5304 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5307 tm->hw[1]->sw_if_index);
5308 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5311 tm->hw[0]->sw_if_index);
5312 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5315 tm->hw[1]->sw_if_index);
5316 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5319 tm->hw[1]->sw_if_index);
5322 * Add an etry with one path with a real out-going label
5324 fib_prefix_t pfx_1_1_1_1_s_32 = {
5326 .fp_proto = FIB_PROTOCOL_IP4,
5328 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5331 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5332 .type = FT_LB_LABEL_O_ADJ,
5334 .adj = ai_mpls_10_10_10_1,
5339 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5340 .type = FT_LB_LABEL_O_ADJ,
5342 .adj = ai_mpls_10_10_10_1,
5344 .eos = MPLS_NON_EOS,
5347 mpls_label_t *l99 = NULL;
5350 fib_table_entry_update_one_path(fib_index,
5353 FIB_ENTRY_FLAG_NONE,
5356 tm->hw[0]->sw_if_index,
5357 ~0, // invalid fib index
5360 FIB_ROUTE_PATH_FLAG_NONE);
5362 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5363 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5365 FIB_TEST(fib_test_validate_entry(fei,
5366 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5368 &l99_eos_o_10_10_10_1),
5369 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5372 * add a path with an implicit NULL label
5374 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5377 .adj = ai_v4_10_10_11_1,
5380 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5383 .adj = ai_mpls_10_10_11_1,
5386 mpls_label_t *l_imp_null = NULL;
5387 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5389 fei = fib_table_entry_path_add(fib_index,
5392 FIB_ENTRY_FLAG_NONE,
5395 tm->hw[1]->sw_if_index,
5396 ~0, // invalid fib index
5399 FIB_ROUTE_PATH_FLAG_NONE);
5401 FIB_TEST(fib_test_validate_entry(fei,
5402 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5404 &l99_eos_o_10_10_10_1,
5406 "1.1.1.1/32 LB 2 buckets via: "
5407 "label 99 over 10.10.10.1, "
5408 "adj over 10.10.11.1");
5411 * assign the route a local label
5413 fib_table_entry_local_label_add(fib_index,
5417 fib_prefix_t pfx_24001_eos = {
5418 .fp_proto = FIB_PROTOCOL_MPLS,
5422 fib_prefix_t pfx_24001_neos = {
5423 .fp_proto = FIB_PROTOCOL_MPLS,
5425 .fp_eos = MPLS_NON_EOS,
5429 * The EOS entry should link to both the paths,
5430 * and use an ip adj for the imp-null
5431 * The NON-EOS entry should link to both the paths,
5432 * and use an mpls adj for the imp-null
5434 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5436 FIB_TEST(fib_test_validate_entry(fei,
5437 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5439 &l99_eos_o_10_10_10_1,
5441 "24001/eos LB 2 buckets via: "
5442 "label 99 over 10.10.10.1, "
5443 "adj over 10.10.11.1");
5446 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5448 FIB_TEST(fib_test_validate_entry(fei,
5449 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5451 &l99_neos_o_10_10_10_1,
5452 &a_mpls_o_10_10_11_1),
5453 "24001/neos LB 1 bucket via: "
5454 "label 99 over 10.10.10.1 ",
5455 "mpls-adj via 10.10.11.1");
5458 * add an unlabelled path, this is excluded from the neos chains,
5460 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5463 .adj = ai_v4_10_10_11_2,
5467 fei = fib_table_entry_path_add(fib_index,
5470 FIB_ENTRY_FLAG_NONE,
5473 tm->hw[1]->sw_if_index,
5474 ~0, // invalid fib index
5477 FIB_ROUTE_PATH_FLAG_NONE);
5479 FIB_TEST(fib_test_validate_entry(fei,
5480 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5481 16, // 3 choices spread over 16 buckets
5482 &l99_eos_o_10_10_10_1,
5483 &l99_eos_o_10_10_10_1,
5484 &l99_eos_o_10_10_10_1,
5485 &l99_eos_o_10_10_10_1,
5486 &l99_eos_o_10_10_10_1,
5487 &l99_eos_o_10_10_10_1,
5498 "1.1.1.1/32 LB 16 buckets via: "
5499 "label 99 over 10.10.10.1, "
5500 "adj over 10.10.11.1",
5501 "adj over 10.10.11.2");
5504 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5506 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5507 fib_entry_contribute_forwarding(fei,
5508 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5512 * n-eos has only the 2 labelled paths
5514 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5517 FIB_TEST(fib_test_validate_entry(fei,
5518 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5520 &l99_neos_o_10_10_10_1,
5521 &a_mpls_o_10_10_11_1),
5522 "24001/neos LB 2 buckets via: "
5523 "label 99 over 10.10.10.1, "
5524 "adj-mpls over 10.10.11.2");
5527 * A labelled recursive
5529 fib_prefix_t pfx_2_2_2_2_s_32 = {
5531 .fp_proto = FIB_PROTOCOL_IP4,
5533 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5536 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5537 .type = FT_LB_LABEL_O_LB,
5539 .lb = non_eos_1_1_1_1.dpoi_index,
5544 mpls_label_t *l1600 = NULL;
5545 vec_add1(l1600, 1600);
5547 fib_table_entry_update_one_path(fib_index,
5550 FIB_ENTRY_FLAG_NONE,
5552 &pfx_1_1_1_1_s_32.fp_addr,
5557 FIB_ROUTE_PATH_FLAG_NONE);
5559 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5560 FIB_TEST(fib_test_validate_entry(fei,
5561 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5563 &l1600_eos_o_1_1_1_1),
5564 "2.2.2.2.2/32 LB 1 buckets via: "
5565 "label 1600 over 1.1.1.1");
5567 dpo_id_t dpo_44 = DPO_INVALID;
5570 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5571 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5573 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5574 "uRPF check for 2.2.2.2/32 on %d OK",
5575 tm->hw[0]->sw_if_index);
5576 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5577 "uRPF check for 2.2.2.2/32 on %d OK",
5578 tm->hw[1]->sw_if_index);
5579 FIB_TEST(!fib_urpf_check(urpfi, 99),
5580 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5583 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5584 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5585 "Shared uRPF on IP and non-EOS chain");
5590 * we are holding a lock on the non-eos LB of the via-entry.
5591 * do a PIC-core failover by shutting the link of the via-entry.
5593 * shut down the link with the valid label
5595 vnet_sw_interface_set_flags(vnet_get_main(),
5596 tm->hw[0]->sw_if_index,
5599 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5600 FIB_TEST(fib_test_validate_entry(fei,
5601 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5605 "1.1.1.1/32 LB 2 buckets via: "
5606 "adj over 10.10.11.1, ",
5607 "adj-v4 over 10.10.11.2");
5609 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5611 FIB_TEST(fib_test_validate_entry(fei,
5612 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5616 "24001/eos LB 2 buckets via: "
5617 "adj over 10.10.11.1, ",
5618 "adj-v4 over 10.10.11.2");
5620 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5622 FIB_TEST(fib_test_validate_entry(fei,
5623 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5625 &a_mpls_o_10_10_11_1),
5626 "24001/neos LB 1 buckets via: "
5627 "adj-mpls over 10.10.11.2");
5630 * test that the pre-failover load-balance has been in-place
5633 dpo_id_t current = DPO_INVALID;
5634 fib_entry_contribute_forwarding(fei,
5635 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5638 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5640 "PIC-core LB inplace modified %U %U",
5641 format_dpo_id, &non_eos_1_1_1_1, 0,
5642 format_dpo_id, ¤t, 0);
5644 dpo_reset(&non_eos_1_1_1_1);
5645 dpo_reset(¤t);
5648 * no-shut the link with the valid label
5650 vnet_sw_interface_set_flags(vnet_get_main(),
5651 tm->hw[0]->sw_if_index,
5652 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5654 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5655 FIB_TEST(fib_test_validate_entry(fei,
5656 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5657 16, // 3 choices spread over 16 buckets
5658 &l99_eos_o_10_10_10_1,
5659 &l99_eos_o_10_10_10_1,
5660 &l99_eos_o_10_10_10_1,
5661 &l99_eos_o_10_10_10_1,
5662 &l99_eos_o_10_10_10_1,
5663 &l99_eos_o_10_10_10_1,
5674 "1.1.1.1/32 LB 16 buckets via: "
5675 "label 99 over 10.10.10.1, "
5676 "adj over 10.10.11.1",
5677 "adj-v4 over 10.10.11.2");
5680 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5682 FIB_TEST(fib_test_validate_entry(fei,
5683 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5684 16, // 3 choices spread over 16 buckets
5685 &l99_eos_o_10_10_10_1,
5686 &l99_eos_o_10_10_10_1,
5687 &l99_eos_o_10_10_10_1,
5688 &l99_eos_o_10_10_10_1,
5689 &l99_eos_o_10_10_10_1,
5690 &l99_eos_o_10_10_10_1,
5701 "24001/eos LB 16 buckets via: "
5702 "label 99 over 10.10.10.1, "
5703 "adj over 10.10.11.1",
5704 "adj-v4 over 10.10.11.2");
5706 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5708 FIB_TEST(fib_test_validate_entry(fei,
5709 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5711 &l99_neos_o_10_10_10_1,
5712 &a_mpls_o_10_10_11_1),
5713 "24001/neos LB 2 buckets via: "
5714 "label 99 over 10.10.10.1, "
5715 "adj-mpls over 10.10.11.2");
5718 * remove the first path with the valid label
5720 fib_table_entry_path_remove(fib_index,
5725 tm->hw[0]->sw_if_index,
5726 ~0, // invalid fib index
5728 FIB_ROUTE_PATH_FLAG_NONE);
5730 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5731 FIB_TEST(fib_test_validate_entry(fei,
5732 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5736 "1.1.1.1/32 LB 2 buckets via: "
5737 "adj over 10.10.11.1, "
5738 "adj-v4 over 10.10.11.2");
5740 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5742 FIB_TEST(fib_test_validate_entry(fei,
5743 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5747 "24001/eos LB 2 buckets via: "
5748 "adj over 10.10.11.1, "
5749 "adj-v4 over 10.10.11.2");
5751 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5754 FIB_TEST(fib_test_validate_entry(fei,
5755 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5757 &a_mpls_o_10_10_11_1),
5758 "24001/neos LB 1 buckets via: "
5759 "adj-mpls over 10.10.11.2");
5762 * remove the other path with a valid label
5764 fib_test_lb_bucket_t bucket_drop = {
5765 .type = FT_LB_SPECIAL,
5767 .adj = DPO_PROTO_IP4,
5771 fib_table_entry_path_remove(fib_index,
5776 tm->hw[1]->sw_if_index,
5777 ~0, // invalid fib index
5779 FIB_ROUTE_PATH_FLAG_NONE);
5781 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5782 FIB_TEST(fib_test_validate_entry(fei,
5783 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5786 "1.1.1.1/32 LB 1 buckets via: "
5787 "adj over 10.10.11.2");
5789 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5791 FIB_TEST(fib_test_validate_entry(fei,
5792 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5795 "24001/eos LB 1 buckets via: "
5796 "adj over 10.10.11.2");
5798 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5800 FIB_TEST(fib_test_validate_entry(fei,
5801 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5804 "24001/eos LB 1 buckets via: DROP");
5807 * add back the path with the valid label
5812 fib_table_entry_path_add(fib_index,
5815 FIB_ENTRY_FLAG_NONE,
5818 tm->hw[0]->sw_if_index,
5819 ~0, // invalid fib index
5822 FIB_ROUTE_PATH_FLAG_NONE);
5824 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5825 FIB_TEST(fib_test_validate_entry(fei,
5826 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5828 &l99_eos_o_10_10_10_1,
5830 "1.1.1.1/32 LB 2 buckets via: "
5831 "label 99 over 10.10.10.1, "
5832 "adj over 10.10.11.2");
5834 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5836 FIB_TEST(fib_test_validate_entry(fei,
5837 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5839 &l99_eos_o_10_10_10_1,
5841 "24001/eos LB 2 buckets via: "
5842 "label 99 over 10.10.10.1, "
5843 "adj over 10.10.11.2");
5845 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5847 FIB_TEST(fib_test_validate_entry(fei,
5848 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5850 &l99_neos_o_10_10_10_1),
5851 "24001/neos LB 1 buckets via: "
5852 "label 99 over 10.10.10.1");
5855 * change the local label
5857 fib_table_entry_local_label_add(fib_index,
5861 fib_prefix_t pfx_25005_eos = {
5862 .fp_proto = FIB_PROTOCOL_MPLS,
5866 fib_prefix_t pfx_25005_neos = {
5867 .fp_proto = FIB_PROTOCOL_MPLS,
5869 .fp_eos = MPLS_NON_EOS,
5872 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5873 fib_table_lookup(fib_index, &pfx_24001_eos)),
5874 "24001/eos removed after label change");
5875 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5876 fib_table_lookup(fib_index, &pfx_24001_neos)),
5877 "24001/eos removed after label change");
5879 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5881 FIB_TEST(fib_test_validate_entry(fei,
5882 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5884 &l99_eos_o_10_10_10_1,
5886 "25005/eos LB 2 buckets via: "
5887 "label 99 over 10.10.10.1, "
5888 "adj over 10.10.11.2");
5890 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5892 FIB_TEST(fib_test_validate_entry(fei,
5893 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5895 &l99_neos_o_10_10_10_1),
5896 "25005/neos LB 1 buckets via: "
5897 "label 99 over 10.10.10.1");
5900 * remove the local label.
5901 * the check that the MPLS entries are gone is done by the fact the
5902 * MPLS table is no longer present.
5904 fib_table_entry_local_label_remove(fib_index,
5908 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5909 FIB_TEST(fib_test_validate_entry(fei,
5910 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5912 &l99_eos_o_10_10_10_1,
5914 "24001/eos LB 2 buckets via: "
5915 "label 99 over 10.10.10.1, "
5916 "adj over 10.10.11.2");
5918 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5919 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
5920 "No more MPLS FIB entries => table removed");
5923 * add another via-entry for the recursive
5925 fib_prefix_t pfx_1_1_1_2_s_32 = {
5927 .fp_proto = FIB_PROTOCOL_IP4,
5929 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
5932 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
5933 .type = FT_LB_LABEL_O_ADJ,
5935 .adj = ai_mpls_10_10_10_1,
5940 mpls_label_t *l101 = NULL;
5941 vec_add1(l101, 101);
5943 fei = fib_table_entry_update_one_path(fib_index,
5946 FIB_ENTRY_FLAG_NONE,
5949 tm->hw[0]->sw_if_index,
5950 ~0, // invalid fib index
5953 FIB_ROUTE_PATH_FLAG_NONE);
5955 FIB_TEST(fib_test_validate_entry(fei,
5956 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5958 &l101_eos_o_10_10_10_1),
5959 "1.1.1.2/32 LB 1 buckets via: "
5960 "label 101 over 10.10.10.1");
5962 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
5963 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5965 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5967 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
5969 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5972 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
5973 .type = FT_LB_LABEL_O_LB,
5975 .lb = non_eos_1_1_1_2.dpoi_index,
5980 mpls_label_t *l1601 = NULL;
5981 vec_add1(l1601, 1601);
5983 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
5985 fei = fib_table_entry_path_add(fib_index,
5988 FIB_ENTRY_FLAG_NONE,
5990 &pfx_1_1_1_2_s_32.fp_addr,
5995 FIB_ROUTE_PATH_FLAG_NONE);
5997 FIB_TEST(fib_test_validate_entry(fei,
5998 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6000 &l1600_eos_o_1_1_1_1,
6001 &l1601_eos_o_1_1_1_2),
6002 "2.2.2.2/32 LB 2 buckets via: "
6003 "label 1600 via 1.1,1.1, "
6004 "label 16001 via 1.1.1.2");
6007 * update the via-entry so it no longer has an imp-null path.
6008 * the LB for the recursive can use an imp-null
6011 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6013 fei = fib_table_entry_update_one_path(fib_index,
6016 FIB_ENTRY_FLAG_NONE,
6019 tm->hw[1]->sw_if_index,
6020 ~0, // invalid fib index
6023 FIB_ROUTE_PATH_FLAG_NONE);
6025 FIB_TEST(fib_test_validate_entry(fei,
6026 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6029 "1.1.1.2/32 LB 1 buckets via: "
6032 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6033 FIB_TEST(fib_test_validate_entry(fei,
6034 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6036 &l1600_eos_o_1_1_1_1,
6037 &l1601_eos_o_1_1_1_2),
6038 "2.2.2.2/32 LB 2 buckets via: "
6039 "label 1600 via 1.1,1.1, "
6040 "label 16001 via 1.1.1.2");
6043 * update the via-entry so it no longer has labelled paths.
6044 * the LB for the recursive should exclue this via form its LB
6046 fei = fib_table_entry_update_one_path(fib_index,
6049 FIB_ENTRY_FLAG_NONE,
6052 tm->hw[1]->sw_if_index,
6053 ~0, // invalid fib index
6056 FIB_ROUTE_PATH_FLAG_NONE);
6058 FIB_TEST(fib_test_validate_entry(fei,
6059 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6062 "1.1.1.2/32 LB 1 buckets via: "
6065 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6066 FIB_TEST(fib_test_validate_entry(fei,
6067 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6069 &l1600_eos_o_1_1_1_1),
6070 "2.2.2.2/32 LB 1 buckets via: "
6071 "label 1600 via 1.1,1.1");
6073 dpo_reset(&non_eos_1_1_1_1);
6074 dpo_reset(&non_eos_1_1_1_2);
6077 * Add a recursive with no out-labels. We expect to use the IP of the via
6079 fib_prefix_t pfx_2_2_2_3_s_32 = {
6081 .fp_proto = FIB_PROTOCOL_IP4,
6083 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6086 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6088 fib_table_entry_update_one_path(fib_index,
6091 FIB_ENTRY_FLAG_NONE,
6093 &pfx_1_1_1_1_s_32.fp_addr,
6098 FIB_ROUTE_PATH_FLAG_NONE);
6100 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6102 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6105 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6108 .lb = ip_1_1_1_1.dpoi_index,
6112 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6113 FIB_TEST(fib_test_validate_entry(fei,
6114 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6117 "2.2.2.2.3/32 LB 1 buckets via: "
6121 * Add a recursive with an imp-null out-label.
6122 * We expect to use the IP of the via
6124 fib_prefix_t pfx_2_2_2_4_s_32 = {
6126 .fp_proto = FIB_PROTOCOL_IP4,
6128 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6132 fib_table_entry_update_one_path(fib_index,
6135 FIB_ENTRY_FLAG_NONE,
6137 &pfx_1_1_1_1_s_32.fp_addr,
6142 FIB_ROUTE_PATH_FLAG_NONE);
6144 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6145 FIB_TEST(fib_test_validate_entry(fei,
6146 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6149 "2.2.2.2.4/32 LB 1 buckets via: "
6152 dpo_reset(&ip_1_1_1_1);
6155 * Create an entry with a deep label stack
6157 fib_prefix_t pfx_2_2_5_5_s_32 = {
6159 .fp_proto = FIB_PROTOCOL_IP4,
6161 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6164 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6165 .type = FT_LB_LABEL_STACK_O_ADJ,
6166 .label_stack_o_adj = {
6167 .adj = ai_mpls_10_10_11_1,
6168 .label_stack_size = 8,
6170 200, 201, 202, 203, 204, 205, 206, 207
6175 mpls_label_t *label_stack = NULL;
6176 vec_validate(label_stack, 7);
6177 for (ii = 0; ii < 8; ii++)
6179 label_stack[ii] = ii + 200;
6182 fei = fib_table_entry_update_one_path(fib_index,
6185 FIB_ENTRY_FLAG_NONE,
6188 tm->hw[1]->sw_if_index,
6189 ~0, // invalid fib index
6192 FIB_ROUTE_PATH_FLAG_NONE);
6194 FIB_TEST(fib_test_validate_entry(fei,
6195 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6197 &ls_eos_o_10_10_10_1),
6198 "2.2.5.5/32 LB 1 buckets via: "
6200 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6205 fib_table_entry_delete(fib_index,
6209 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6210 FIB_TEST(fib_test_validate_entry(fei,
6211 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6213 &l1600_eos_o_1_1_1_1),
6214 "2.2.2.2/32 LB 1 buckets via: "
6215 "label 1600 via 1.1,1.1");
6217 fib_table_entry_delete(fib_index,
6221 FIB_TEST(fib_test_validate_entry(fei,
6222 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6225 "2.2.2.2/32 LB 1 buckets via: DROP");
6227 fib_table_entry_delete(fib_index,
6230 fib_table_entry_delete(fib_index,
6233 fib_table_entry_delete(fib_index,
6237 adj_unlock(ai_mpls_10_10_10_1);
6238 adj_unlock(ai_mpls_10_10_11_2);
6239 adj_unlock(ai_v4_10_10_11_1);
6240 adj_unlock(ai_v4_10_10_11_2);
6241 adj_unlock(ai_mpls_10_10_11_1);
6243 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6246 local0_pfx.fp_len = 32;
6247 fib_table_entry_delete(fib_index,
6249 FIB_SOURCE_INTERFACE);
6250 local0_pfx.fp_len = 24;
6251 fib_table_entry_delete(fib_index,
6253 FIB_SOURCE_INTERFACE);
6254 local1_pfx.fp_len = 32;
6255 fib_table_entry_delete(fib_index,
6257 FIB_SOURCE_INTERFACE);
6258 local1_pfx.fp_len = 24;
6259 fib_table_entry_delete(fib_index,
6261 FIB_SOURCE_INTERFACE);
6264 * +1 for the drop LB in the MPLS tables.
6266 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6267 "Load-balance resources freed %d of %d",
6268 lb_count+1, pool_elts(load_balance_pool));
6273 #define N_TEST_CHILDREN 4
6274 #define PARENT_INDEX 0
6276 typedef struct fib_node_test_t_
6281 fib_node_back_walk_ctx_t *ctxs;
6285 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6287 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6289 #define FOR_EACH_TEST_CHILD(_tc) \
6290 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
6291 ii < N_TEST_CHILDREN+1; \
6292 ii++, (_tc) = &fib_test_nodes[ii])
6295 fib_test_child_get_node (fib_node_index_t index)
6297 return (&fib_test_nodes[index].node);
6300 static int fib_test_walk_spawns_walks;
6302 static fib_node_back_walk_rc_t
6303 fib_test_child_back_walk_notify (fib_node_t *node,
6304 fib_node_back_walk_ctx_t *ctx)
6306 fib_node_test_t *tc = (fib_node_test_t*) node;
6308 vec_add1(tc->ctxs, *ctx);
6310 if (1 == fib_test_walk_spawns_walks)
6311 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6312 if (2 == fib_test_walk_spawns_walks)
6313 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6314 FIB_WALK_PRIORITY_HIGH, ctx);
6316 return (FIB_NODE_BACK_WALK_CONTINUE);
6320 fib_test_child_last_lock_gone (fib_node_t *node)
6322 fib_node_test_t *tc = (fib_node_test_t *)node;
6328 * The FIB walk's graph node virtual function table
6330 static const fib_node_vft_t fib_test_child_vft = {
6331 .fnv_get = fib_test_child_get_node,
6332 .fnv_last_lock = fib_test_child_last_lock_gone,
6333 .fnv_back_walk = fib_test_child_back_walk_notify,
6337 * the function (that should have been static but isn't so I can do this)
6338 * that processes the walk from the async queue,
6340 f64 fib_walk_process_queues(vlib_main_t * vm,
6342 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6345 fib_test_walk (void)
6347 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6348 fib_node_test_t *tc;
6352 vm = vlib_get_main();
6353 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6356 * init a fake node on which we will add children
6358 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6359 FIB_NODE_TYPE_TEST);
6361 FOR_EACH_TEST_CHILD(tc)
6363 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6364 fib_node_lock(&tc->node);
6367 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6369 FIB_NODE_TYPE_TEST, ii);
6373 * enqueue a walk across the parents children.
6375 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6377 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6378 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6379 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6380 "Parent has %d children pre-walk",
6381 fib_node_list_get_size(PARENT()->fn_children));
6384 * give the walk a large amount of time so it gets to the end
6386 fib_walk_process_queues(vm, 1);
6388 FOR_EACH_TEST_CHILD(tc)
6390 FIB_TEST(1 == vec_len(tc->ctxs),
6391 "%d child visitsed %d times",
6392 ii, vec_len(tc->ctxs));
6395 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6396 "Queue is empty post walk");
6397 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6398 "Parent has %d children post walk",
6399 fib_node_list_get_size(PARENT()->fn_children));
6402 * walk again. should be no increase in the number of visits, since
6403 * the walk will have terminated.
6405 fib_walk_process_queues(vm, 1);
6407 FOR_EACH_TEST_CHILD(tc)
6409 FIB_TEST(0 == vec_len(tc->ctxs),
6410 "%d child visitsed %d times",
6411 ii, vec_len(tc->ctxs));
6415 * schedule a low and hig priority walk. expect the high to be performed
6417 * schedule the high prio walk first so that it is further from the head
6418 * of the dependency list. that way it won't merge with the low one.
6420 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6421 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6423 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6424 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6425 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6426 FIB_WALK_PRIORITY_LOW, &low_ctx);
6428 fib_walk_process_queues(vm, 1);
6430 FOR_EACH_TEST_CHILD(tc)
6432 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6433 "%d child visitsed by high prio walk", ii);
6434 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6435 "%d child visitsed by low prio walk", ii);
6438 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6439 "Queue is empty post prio walk");
6440 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6441 "Parent has %d children post prio walk",
6442 fib_node_list_get_size(PARENT()->fn_children));
6445 * schedule 2 walks of the same priority that can be megred.
6446 * expect that each child is thus visited only once.
6448 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6449 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6451 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6452 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6453 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6454 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6456 fib_walk_process_queues(vm, 1);
6458 FOR_EACH_TEST_CHILD(tc)
6460 FIB_TEST(1 == vec_len(tc->ctxs),
6461 "%d child visitsed %d times during merge walk",
6462 ii, vec_len(tc->ctxs));
6465 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6466 "Queue is empty post merge walk");
6467 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6468 "Parent has %d children post merge walk",
6469 fib_node_list_get_size(PARENT()->fn_children));
6472 * schedule 2 walks of the same priority that cannot be megred.
6473 * expect that each child is thus visited twice and in the order
6474 * in which the walks were scheduled.
6476 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6477 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6479 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6480 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6481 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6482 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6484 fib_walk_process_queues(vm, 1);
6486 FOR_EACH_TEST_CHILD(tc)
6488 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6489 "%d child visitsed by high prio walk", ii);
6490 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6491 "%d child visitsed by low prio walk", ii);
6494 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6495 "Queue is empty post no-merge walk");
6496 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6497 "Parent has %d children post no-merge walk",
6498 fib_node_list_get_size(PARENT()->fn_children));
6501 * schedule a walk that makes one one child progress.
6502 * we do this by giving the queue draining process zero
6503 * time quanta. it's a do..while loop, so it does something.
6505 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6507 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6508 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6509 fib_walk_process_queues(vm, 0);
6511 FOR_EACH_TEST_CHILD(tc)
6513 if (ii == N_TEST_CHILDREN)
6515 FIB_TEST(1 == vec_len(tc->ctxs),
6516 "%d child visitsed %d times in zero quanta walk",
6517 ii, vec_len(tc->ctxs));
6521 FIB_TEST(0 == vec_len(tc->ctxs),
6522 "%d child visitsed %d times in 0 quanta walk",
6523 ii, vec_len(tc->ctxs));
6526 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6527 "Queue is not empty post zero quanta walk");
6528 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6529 "Parent has %d children post zero qunta walk",
6530 fib_node_list_get_size(PARENT()->fn_children));
6535 fib_walk_process_queues(vm, 0);
6537 FOR_EACH_TEST_CHILD(tc)
6539 if (ii >= N_TEST_CHILDREN-1)
6541 FIB_TEST(1 == vec_len(tc->ctxs),
6542 "%d child visitsed %d times in 2nd zero quanta walk",
6543 ii, vec_len(tc->ctxs));
6547 FIB_TEST(0 == vec_len(tc->ctxs),
6548 "%d child visitsed %d times in 2nd 0 quanta walk",
6549 ii, vec_len(tc->ctxs));
6552 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6553 "Queue is not empty post zero quanta walk");
6554 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6555 "Parent has %d children post zero qunta walk",
6556 fib_node_list_get_size(PARENT()->fn_children));
6559 * schedule another walk that will catch-up and merge.
6561 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6562 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6563 fib_walk_process_queues(vm, 1);
6565 FOR_EACH_TEST_CHILD(tc)
6567 if (ii >= N_TEST_CHILDREN-1)
6569 FIB_TEST(2 == vec_len(tc->ctxs),
6570 "%d child visitsed %d times in 2nd zero quanta merge walk",
6571 ii, vec_len(tc->ctxs));
6576 FIB_TEST(1 == vec_len(tc->ctxs),
6577 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6578 ii, vec_len(tc->ctxs));
6582 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6583 "Queue is not empty post 2nd zero quanta merge walk");
6584 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6585 "Parent has %d children post 2nd zero qunta merge walk",
6586 fib_node_list_get_size(PARENT()->fn_children));
6589 * park a async walk in the middle of the list, then have an sync walk catch
6590 * it. same expectations as async catches async.
6592 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6594 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6595 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6597 fib_walk_process_queues(vm, 0);
6598 fib_walk_process_queues(vm, 0);
6600 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6602 FOR_EACH_TEST_CHILD(tc)
6604 if (ii >= N_TEST_CHILDREN-1)
6606 FIB_TEST(2 == vec_len(tc->ctxs),
6607 "%d child visitsed %d times in sync catches async walk",
6608 ii, vec_len(tc->ctxs));
6613 FIB_TEST(1 == vec_len(tc->ctxs),
6614 "%d child visitsed %d times in sync catches async walk",
6615 ii, vec_len(tc->ctxs));
6619 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6620 "Queue is not empty post 2nd zero quanta merge walk");
6621 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6622 "Parent has %d children post 2nd zero qunta merge walk",
6623 fib_node_list_get_size(PARENT()->fn_children));
6626 * make the parent a child of one of its children, thus inducing a routing loop.
6628 fib_test_nodes[PARENT_INDEX].sibling =
6629 fib_node_child_add(FIB_NODE_TYPE_TEST,
6630 1, // the first child
6635 * execute a sync walk from the parent. each child visited spawns more sync
6636 * walks. we expect the walk to terminate.
6638 fib_test_walk_spawns_walks = 1;
6640 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6642 FOR_EACH_TEST_CHILD(tc)
6645 * child 1 - which is last in the list - has the loop.
6646 * the other children a re thus visitsed first. the we meet
6647 * child 1. we go round the loop again, visting the other children.
6648 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6653 FIB_TEST(1 == vec_len(tc->ctxs),
6654 "child %d visitsed %d times during looped sync walk",
6655 ii, vec_len(tc->ctxs));
6659 FIB_TEST(2 == vec_len(tc->ctxs),
6660 "child %d visitsed %d times during looped sync walk",
6661 ii, vec_len(tc->ctxs));
6665 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6666 "Parent has %d children post sync loop walk",
6667 fib_node_list_get_size(PARENT()->fn_children));
6670 * the walk doesn't reach the max depth because the infra knows that sync
6671 * meets sync implies a loop and bails early.
6673 FIB_TEST(high_ctx.fnbw_depth == 9,
6674 "Walk context depth %d post sync loop walk",
6675 high_ctx.fnbw_depth);
6678 * execute an async walk of the graph loop, with each child spawns sync walks
6680 high_ctx.fnbw_depth = 0;
6681 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6682 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6684 fib_walk_process_queues(vm, 1);
6686 FOR_EACH_TEST_CHILD(tc)
6689 * we don't really care how many times the children are visisted, as long as
6690 * it is more than once.
6692 FIB_TEST(1 <= vec_len(tc->ctxs),
6693 "child %d visitsed %d times during looped aync spawns sync walk",
6694 ii, vec_len(tc->ctxs));
6699 * execute an async walk of the graph loop, with each child spawns async walks
6701 fib_test_walk_spawns_walks = 2;
6702 high_ctx.fnbw_depth = 0;
6703 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6704 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6706 fib_walk_process_queues(vm, 1);
6708 FOR_EACH_TEST_CHILD(tc)
6711 * we don't really care how many times the children are visisted, as long as
6712 * it is more than once.
6714 FIB_TEST(1 <= vec_len(tc->ctxs),
6715 "child %d visitsed %d times during looped async spawns async walk",
6716 ii, vec_len(tc->ctxs));
6721 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6722 1, // the first child
6723 fib_test_nodes[PARENT_INDEX].sibling);
6728 FOR_EACH_TEST_CHILD(tc)
6730 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6732 fib_node_deinit(&tc->node);
6733 fib_node_unlock(&tc->node);
6735 fib_node_deinit(PARENT());
6738 * The parent will be destroyed when the last lock on it goes.
6739 * this test ensures all the walk objects are unlocking it.
6741 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6742 "Parent was destroyed");
6748 * declaration of the otherwise static callback functions
6750 void fib_bfd_notify (bfd_listen_event_e event,
6751 const bfd_session_t *session);
6752 void adj_bfd_notify (bfd_listen_event_e event,
6753 const bfd_session_t *session);
6756 * Test BFD session interaction with FIB
6761 fib_node_index_t fei;
6765 /* via 10.10.10.1 */
6766 ip46_address_t nh_10_10_10_1 = {
6767 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6769 /* via 10.10.10.2 */
6770 ip46_address_t nh_10_10_10_2 = {
6771 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
6773 /* via 10.10.10.10 */
6774 ip46_address_t nh_10_10_10_10 = {
6775 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6777 n_feis = fib_entry_pool_size();
6782 * add interface routes. we'll assume this works. it's tested elsewhere
6784 fib_prefix_t pfx_10_10_10_10_s_24 = {
6786 .fp_proto = FIB_PROTOCOL_IP4,
6787 .fp_addr = nh_10_10_10_10,
6790 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
6791 FIB_SOURCE_INTERFACE,
6792 (FIB_ENTRY_FLAG_CONNECTED |
6793 FIB_ENTRY_FLAG_ATTACHED),
6796 tm->hw[0]->sw_if_index,
6797 ~0, // invalid fib index
6800 FIB_ROUTE_PATH_FLAG_NONE);
6802 fib_prefix_t pfx_10_10_10_10_s_32 = {
6804 .fp_proto = FIB_PROTOCOL_IP4,
6805 .fp_addr = nh_10_10_10_10,
6807 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
6808 FIB_SOURCE_INTERFACE,
6809 (FIB_ENTRY_FLAG_CONNECTED |
6810 FIB_ENTRY_FLAG_LOCAL),
6813 tm->hw[0]->sw_if_index,
6814 ~0, // invalid fib index
6817 FIB_ROUTE_PATH_FLAG_NONE);
6820 * A BFD session via a neighbour we do not yet know
6822 bfd_session_t bfd_10_10_10_1 = {
6826 .peer_addr = nh_10_10_10_1,
6829 .hop_type = BFD_HOP_TYPE_MULTI,
6830 .local_state = BFD_STATE_init,
6833 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
6836 * A new entry will be created that forwards via the adj
6838 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6841 tm->hw[0]->sw_if_index);
6842 fib_prefix_t pfx_10_10_10_1_s_32 = {
6843 .fp_addr = nh_10_10_10_1,
6845 .fp_proto = FIB_PROTOCOL_IP4,
6847 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
6850 .adj = ai_10_10_10_1,
6854 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
6855 FIB_TEST(fib_test_validate_entry(fei,
6856 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6859 "BFD sourced %U via %U",
6860 format_fib_prefix, &pfx_10_10_10_1_s_32,
6861 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
6864 * Delete the BFD session. Expect the fib_entry to be removed
6866 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
6868 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
6869 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
6870 "BFD sourced %U removed",
6871 format_fib_prefix, &pfx_10_10_10_1_s_32);
6874 * Add the BFD source back
6876 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
6879 * source the entry via the ADJ fib
6881 fei = fib_table_entry_update_one_path(0,
6882 &pfx_10_10_10_1_s_32,
6884 FIB_ENTRY_FLAG_ATTACHED,
6887 tm->hw[0]->sw_if_index,
6888 ~0, // invalid fib index
6891 FIB_ROUTE_PATH_FLAG_NONE);
6894 * Delete the BFD session. Expect the fib_entry to remain
6896 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
6898 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
6899 FIB_TEST(fib_test_validate_entry(fei,
6900 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6903 "BFD sourced %U remains via %U",
6904 format_fib_prefix, &pfx_10_10_10_1_s_32,
6905 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
6908 * Add the BFD source back
6910 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
6913 * Create another ADJ FIB
6915 fib_prefix_t pfx_10_10_10_2_s_32 = {
6916 .fp_addr = nh_10_10_10_2,
6918 .fp_proto = FIB_PROTOCOL_IP4,
6920 fib_table_entry_update_one_path(0,
6921 &pfx_10_10_10_2_s_32,
6923 FIB_ENTRY_FLAG_ATTACHED,
6926 tm->hw[0]->sw_if_index,
6927 ~0, // invalid fib index
6930 FIB_ROUTE_PATH_FLAG_NONE);
6932 * A BFD session for the new ADJ FIB
6934 bfd_session_t bfd_10_10_10_2 = {
6938 .peer_addr = nh_10_10_10_2,
6941 .hop_type = BFD_HOP_TYPE_MULTI,
6942 .local_state = BFD_STATE_init,
6945 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
6948 * remove the adj-fib source whilst the session is present
6951 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
6952 fib_table_entry_update_one_path(0,
6953 &pfx_10_10_10_2_s_32,
6955 FIB_ENTRY_FLAG_ATTACHED,
6958 tm->hw[0]->sw_if_index,
6959 ~0, // invalid fib index
6962 FIB_ROUTE_PATH_FLAG_NONE);
6965 * Before adding a recursive via the BFD tracked ADJ-FIBs,
6966 * bring one of the sessions UP, leave the other down
6968 bfd_10_10_10_1.local_state = BFD_STATE_up;
6969 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
6970 bfd_10_10_10_2.local_state = BFD_STATE_down;
6971 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
6974 * A recursive prefix via both of the ADJ FIBs
6976 fib_prefix_t pfx_200_0_0_0_s_24 = {
6977 .fp_proto = FIB_PROTOCOL_IP4,
6980 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
6983 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
6986 fib_entry_contribute_ip_forwarding(
6987 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
6989 fib_entry_contribute_ip_forwarding(
6990 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
6992 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
6995 .lb = dpo_10_10_10_1->dpoi_index,
6998 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7001 .lb = dpo_10_10_10_2->dpoi_index,
7006 * A prefix via the adj-fib that is BFD down => DROP
7008 fei = fib_table_entry_path_add(0,
7009 &pfx_200_0_0_0_s_24,
7011 FIB_ENTRY_FLAG_NONE,
7015 0, // default fib index
7018 FIB_ROUTE_PATH_FLAG_NONE);
7019 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7020 "%U resolves via drop",
7021 format_fib_prefix, &pfx_200_0_0_0_s_24);
7024 * add a path via the UP BFD adj-fib.
7025 * we expect that the DOWN BFD ADJ FIB is not used.
7027 fei = fib_table_entry_path_add(0,
7028 &pfx_200_0_0_0_s_24,
7030 FIB_ENTRY_FLAG_NONE,
7034 0, // default fib index
7037 FIB_ROUTE_PATH_FLAG_NONE);
7039 FIB_TEST(fib_test_validate_entry(fei,
7040 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7043 "Recursive %U only UP BFD adj-fibs",
7044 format_fib_prefix, &pfx_200_0_0_0_s_24);
7047 * Send a BFD state change to UP - both sessions are now up
7048 * the recursive prefix should LB over both
7050 bfd_10_10_10_2.local_state = BFD_STATE_up;
7051 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7054 FIB_TEST(fib_test_validate_entry(fei,
7055 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7059 "Recursive %U via both UP BFD adj-fibs",
7060 format_fib_prefix, &pfx_200_0_0_0_s_24);
7063 * Send a BFD state change to DOWN
7064 * the recursive prefix should exclude the down
7066 bfd_10_10_10_2.local_state = BFD_STATE_down;
7067 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7070 FIB_TEST(fib_test_validate_entry(fei,
7071 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7074 "Recursive %U via only UP",
7075 format_fib_prefix, &pfx_200_0_0_0_s_24);
7078 * Delete the BFD session while it is in the DOWN state.
7079 * FIB should consider the entry's state as back up
7081 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
7083 FIB_TEST(fib_test_validate_entry(fei,
7084 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7088 "Recursive %U via both UP BFD adj-fibs post down session delete",
7089 format_fib_prefix, &pfx_200_0_0_0_s_24);
7092 * Delete the BFD other session while it is in the UP state.
7094 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7096 FIB_TEST(fib_test_validate_entry(fei,
7097 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7101 "Recursive %U via both UP BFD adj-fibs post up session delete",
7102 format_fib_prefix, &pfx_200_0_0_0_s_24);
7107 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
7108 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
7109 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7111 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
7112 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
7114 adj_unlock(ai_10_10_10_1);
7116 * test no-one left behind
7118 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7119 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7122 * Single-hop BFD tests
7124 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
7125 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
7127 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7129 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7132 tm->hw[0]->sw_if_index);
7134 * whilst the BFD session is not signalled, the adj is up
7136 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
7139 * bring the BFD session up
7141 bfd_10_10_10_1.local_state = BFD_STATE_up;
7142 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7143 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
7146 * bring the BFD session down
7148 bfd_10_10_10_1.local_state = BFD_STATE_down;
7149 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7150 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
7154 * add an attached next hop FIB entry via the down adj
7156 fib_prefix_t pfx_5_5_5_5_s_32 = {
7159 .as_u32 = clib_host_to_net_u32(0x05050505),
7163 .fp_proto = FIB_PROTOCOL_IP4,
7166 fei = fib_table_entry_path_add(0,
7169 FIB_ENTRY_FLAG_NONE,
7172 tm->hw[0]->sw_if_index,
7173 ~0, // invalid fib index
7176 FIB_ROUTE_PATH_FLAG_NONE);
7177 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7178 "%U resolves via drop",
7179 format_fib_prefix, &pfx_5_5_5_5_s_32);
7182 * Add a path via an ADJ that is up
7184 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7187 tm->hw[0]->sw_if_index);
7189 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
7192 .adj = ai_10_10_10_2,
7195 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
7197 fei = fib_table_entry_path_add(0,
7200 FIB_ENTRY_FLAG_NONE,
7203 tm->hw[0]->sw_if_index,
7204 ~0, // invalid fib index
7207 FIB_ROUTE_PATH_FLAG_NONE);
7209 FIB_TEST(fib_test_validate_entry(fei,
7210 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7213 "BFD sourced %U via %U",
7214 format_fib_prefix, &pfx_5_5_5_5_s_32,
7215 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
7218 * Bring up the down session - should now LB
7220 bfd_10_10_10_1.local_state = BFD_STATE_up;
7221 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7222 FIB_TEST(fib_test_validate_entry(fei,
7223 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7227 "BFD sourced %U via noth adjs",
7228 format_fib_prefix, &pfx_5_5_5_5_s_32);
7231 * remove the BFD session state from the adj
7233 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7238 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
7239 adj_unlock(ai_10_10_10_1);
7240 adj_unlock(ai_10_10_10_2);
7243 * test no-one left behind
7245 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7246 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7253 const mpls_label_t deag_label = 50;
7254 const u32 lfib_index = 0;
7255 const u32 fib_index = 0;
7256 dpo_id_t dpo = DPO_INVALID;
7257 const dpo_id_t *dpo1;
7258 fib_node_index_t lfe;
7262 adj_index_t ai_mpls_10_10_10_1;
7265 lb_count = pool_elts(load_balance_pool);
7267 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7271 * MPLS enable an interface so we get the MPLS table created
7273 mpls_sw_interface_enable_disable(&mpls_main,
7274 tm->hw[0]->sw_if_index,
7277 ip46_address_t nh_10_10_10_1 = {
7278 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7280 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7283 tm->hw[0]->sw_if_index);
7286 * Test the specials stack properly.
7288 fib_prefix_t exp_null_v6_pfx = {
7289 .fp_proto = FIB_PROTOCOL_MPLS,
7291 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7292 .fp_payload_proto = DPO_PROTO_IP6,
7294 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
7295 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
7297 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7298 format_mpls_eos_bit, MPLS_EOS);
7299 fib_entry_contribute_forwarding(lfe,
7300 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7302 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7303 lkd = lookup_dpo_get(dpo1->dpoi_index);
7305 FIB_TEST((fib_index == lkd->lkd_fib_index),
7306 "%U/%U is deag in %d %U",
7307 format_mpls_unicast_label, deag_label,
7308 format_mpls_eos_bit, MPLS_EOS,
7310 format_dpo_id, &dpo, 0);
7311 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7312 "%U/%U is dst deag",
7313 format_mpls_unicast_label, deag_label,
7314 format_mpls_eos_bit, MPLS_EOS);
7315 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
7316 "%U/%U is lookup in interface's table",
7317 format_mpls_unicast_label, deag_label,
7318 format_mpls_eos_bit, MPLS_EOS);
7319 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
7320 "%U/%U is %U dst deag",
7321 format_mpls_unicast_label, deag_label,
7322 format_mpls_eos_bit, MPLS_EOS,
7323 format_dpo_proto, lkd->lkd_proto);
7327 * A route deag route for EOS
7329 fib_prefix_t pfx = {
7330 .fp_proto = FIB_PROTOCOL_MPLS,
7332 .fp_label = deag_label,
7333 .fp_payload_proto = DPO_PROTO_IP4,
7335 lfe = fib_table_entry_path_add(lfib_index,
7338 FIB_ENTRY_FLAG_NONE,
7345 FIB_ROUTE_PATH_FLAG_NONE);
7347 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7349 format_mpls_unicast_label, deag_label,
7350 format_mpls_eos_bit, MPLS_EOS);
7352 fib_entry_contribute_forwarding(lfe,
7353 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7355 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7356 lkd = lookup_dpo_get(dpo1->dpoi_index);
7358 FIB_TEST((fib_index == lkd->lkd_fib_index),
7359 "%U/%U is deag in %d %U",
7360 format_mpls_unicast_label, deag_label,
7361 format_mpls_eos_bit, MPLS_EOS,
7363 format_dpo_id, &dpo, 0);
7364 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7365 "%U/%U is dst deag",
7366 format_mpls_unicast_label, deag_label,
7367 format_mpls_eos_bit, MPLS_EOS);
7368 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
7369 "%U/%U is %U dst deag",
7370 format_mpls_unicast_label, deag_label,
7371 format_mpls_eos_bit, MPLS_EOS,
7372 format_dpo_proto, lkd->lkd_proto);
7374 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7376 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7378 "%U/%U not present",
7379 format_mpls_unicast_label, deag_label,
7380 format_mpls_eos_bit, MPLS_EOS);
7383 * A route deag route for non-EOS
7385 pfx.fp_eos = MPLS_NON_EOS;
7386 lfe = fib_table_entry_path_add(lfib_index,
7389 FIB_ENTRY_FLAG_NONE,
7396 FIB_ROUTE_PATH_FLAG_NONE);
7398 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7400 format_mpls_unicast_label, deag_label,
7401 format_mpls_eos_bit, MPLS_NON_EOS);
7403 fib_entry_contribute_forwarding(lfe,
7404 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7406 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7407 lkd = lookup_dpo_get(dpo1->dpoi_index);
7409 FIB_TEST((fib_index == lkd->lkd_fib_index),
7410 "%U/%U is deag in %d %U",
7411 format_mpls_unicast_label, deag_label,
7412 format_mpls_eos_bit, MPLS_NON_EOS,
7414 format_dpo_id, &dpo, 0);
7415 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7416 "%U/%U is dst deag",
7417 format_mpls_unicast_label, deag_label,
7418 format_mpls_eos_bit, MPLS_NON_EOS);
7420 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
7421 "%U/%U is %U dst deag",
7422 format_mpls_unicast_label, deag_label,
7423 format_mpls_eos_bit, MPLS_NON_EOS,
7424 format_dpo_proto, lkd->lkd_proto);
7426 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7428 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7430 "%U/%U not present",
7431 format_mpls_unicast_label, deag_label,
7432 format_mpls_eos_bit, MPLS_EOS);
7439 fib_prefix_t pfx_1200 = {
7441 .fp_proto = FIB_PROTOCOL_MPLS,
7443 .fp_eos = MPLS_NON_EOS,
7445 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
7446 .type = FT_LB_LABEL_STACK_O_ADJ,
7447 .label_stack_o_adj = {
7448 .adj = ai_mpls_10_10_10_1,
7449 .label_stack_size = 4,
7453 .eos = MPLS_NON_EOS,
7456 dpo_id_t neos_1200 = DPO_INVALID;
7457 dpo_id_t ip_1200 = DPO_INVALID;
7458 mpls_label_t *l200 = NULL;
7459 vec_add1(l200, 200);
7460 vec_add1(l200, 300);
7461 vec_add1(l200, 400);
7462 vec_add1(l200, 500);
7464 lfe = fib_table_entry_update_one_path(fib_index,
7467 FIB_ENTRY_FLAG_NONE,
7470 tm->hw[0]->sw_if_index,
7471 ~0, // invalid fib index
7474 FIB_ROUTE_PATH_FLAG_NONE);
7476 FIB_TEST(fib_test_validate_entry(lfe,
7477 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7479 &neos_o_10_10_10_1),
7480 "1200/0 LB 1 buckets via: "
7484 * A recursive route via the MPLS x-connect
7486 fib_prefix_t pfx_2_2_2_3_s_32 = {
7488 .fp_proto = FIB_PROTOCOL_IP4,
7490 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7493 fib_route_path_t *rpaths = NULL, rpath = {
7494 .frp_proto = FIB_PROTOCOL_MPLS,
7495 .frp_local_label = 1200,
7496 .frp_sw_if_index = ~0, // recurive
7497 .frp_fib_index = 0, // Default MPLS fib
7499 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
7500 .frp_label_stack = NULL,
7502 vec_add1(rpaths, rpath);
7504 fib_table_entry_path_add2(fib_index,
7507 FIB_ENTRY_FLAG_NONE,
7511 * A labelled recursive route via the MPLS x-connect
7513 fib_prefix_t pfx_2_2_2_4_s_32 = {
7515 .fp_proto = FIB_PROTOCOL_IP4,
7517 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7520 mpls_label_t *l999 = NULL;
7521 vec_add1(l999, 999);
7522 rpaths[0].frp_label_stack = l999,
7524 fib_table_entry_path_add2(fib_index,
7527 FIB_ENTRY_FLAG_NONE,
7530 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7531 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7533 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7534 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7537 fib_test_lb_bucket_t ip_o_1200 = {
7540 .lb = ip_1200.dpoi_index,
7543 fib_test_lb_bucket_t mpls_o_1200 = {
7544 .type = FT_LB_LABEL_O_LB,
7546 .lb = neos_1200.dpoi_index,
7552 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7553 FIB_TEST(fib_test_validate_entry(lfe,
7554 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7557 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
7558 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7559 FIB_TEST(fib_test_validate_entry(lfe,
7560 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7563 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
7565 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
7566 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
7567 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7569 dpo_reset(&neos_1200);
7570 dpo_reset(&ip_1200);
7573 * A recursive via a label that does not exist
7575 fib_test_lb_bucket_t bucket_drop = {
7576 .type = FT_LB_SPECIAL,
7578 .adj = DPO_PROTO_MPLS,
7582 rpaths[0].frp_label_stack = NULL;
7583 lfe = fib_table_entry_path_add2(fib_index,
7586 FIB_ENTRY_FLAG_NONE,
7589 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7590 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7592 ip_o_1200.lb.lb = ip_1200.dpoi_index;
7594 FIB_TEST(fib_test_validate_entry(lfe,
7595 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7598 "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
7599 lfe = fib_table_lookup(fib_index, &pfx_1200);
7600 FIB_TEST(fib_test_validate_entry(lfe,
7601 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7604 "2.2.2.4/32 LB 1 buckets via: ip4-DROP");
7606 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7608 dpo_reset(&ip_1200);
7613 mpls_sw_interface_enable_disable(&mpls_main,
7614 tm->hw[0]->sw_if_index,
7617 FIB_TEST(lb_count == pool_elts(load_balance_pool),
7618 "Load-balance resources freed %d of %d",
7619 lb_count, pool_elts(load_balance_pool));
7624 static clib_error_t *
7625 fib_test (vlib_main_t * vm,
7626 unformat_input_t * input,
7627 vlib_cli_command_t * cmd_arg)
7632 fib_test_mk_intf(4);
7634 if (unformat (input, "debug"))
7636 fib_test_do_debug = 1;
7639 if (unformat (input, "ip"))
7641 res += fib_test_v4();
7642 res += fib_test_v6();
7644 else if (unformat (input, "label"))
7646 res += fib_test_label();
7648 else if (unformat (input, "ae"))
7650 res += fib_test_ae();
7652 else if (unformat (input, "lfib"))
7656 else if (unformat (input, "walk"))
7658 res += fib_test_walk();
7660 else if (unformat (input, "bfd"))
7662 res += fib_test_bfd();
7667 * These walk UT aren't run as part of the full suite, since the
7668 * fib-walk process must be disabled in order for the tests to work
7672 res += fib_test_v4();
7673 res += fib_test_v6();
7674 res += fib_test_ae();
7675 res += fib_test_bfd();
7676 res += fib_test_label();
7682 return clib_error_return(0, "FIB Unit Test Failed");
7690 VLIB_CLI_COMMAND (test_fib_command, static) = {
7692 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
7693 .function = fib_test,
7697 fib_test_init (vlib_main_t *vm)
7702 VLIB_INIT_FUNCTION (fib_test_init);