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>
28 #include <vnet/dpo/interface_dpo.h>
29 #include <vnet/dpo/replicate_dpo.h>
31 #include <vnet/mpls/mpls.h>
33 #include <vnet/fib/fib_path_list.h>
34 #include <vnet/fib/fib_entry_src.h>
35 #include <vnet/fib/fib_walk.h>
36 #include <vnet/fib/fib_node_list.h>
37 #include <vnet/fib/fib_urpf_list.h>
40 * Add debugs for passing tests
42 static int fib_test_do_debug;
44 #define FIB_TEST_I(_cond, _comment, _args...) \
46 int _evald = (_cond); \
48 fformat(stderr, "FAIL:%d: " _comment "\n", \
51 if (fib_test_do_debug) \
52 fformat(stderr, "PASS:%d: " _comment "\n", \
57 #define FIB_TEST(_cond, _comment, _args...) \
59 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
61 ASSERT(!("FAIL: " _comment)); \
66 * A 'i'm not fussed is this is not efficient' store of test data
68 typedef struct test_main_t_ {
72 u32 hw_if_indicies[4];
76 vnet_hw_interface_t * hw[4];
79 static test_main_t test_main;
81 /* fake ethernet device class, distinct from "fake-ethX" */
82 static u8 * format_test_interface_name (u8 * s, va_list * args)
84 u32 dev_instance = va_arg (*args, u32);
85 return format (s, "test-eth%d", dev_instance);
88 static uword dummy_interface_tx (vlib_main_t * vm,
89 vlib_node_runtime_t * node,
92 clib_warning ("you shouldn't be here, leaking buffers...");
93 return frame->n_vectors;
97 test_interface_admin_up_down (vnet_main_t * vnm,
101 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
102 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
103 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
107 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
108 .name = "Test interface",
109 .format_device_name = format_test_interface_name,
110 .tx_function = dummy_interface_tx,
111 .admin_up_down_function = test_interface_admin_up_down,
114 static u8 *hw_address;
117 fib_test_mk_intf (u32 ninterfaces)
119 clib_error_t * error = NULL;
120 test_main_t *tm = &test_main;
124 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
129 vec_add1(hw_address, byte);
132 for (i = 0; i < ninterfaces; i++)
136 error = ethernet_register_interface(vnet_get_main(),
137 test_interface_device_class.index,
140 &tm->hw_if_indicies[i],
141 /* flag change */ 0);
143 FIB_TEST((NULL == error), "ADD interface %d", i);
145 error = vnet_hw_interface_set_flags(vnet_get_main(),
146 tm->hw_if_indicies[i],
147 VNET_HW_INTERFACE_FLAG_LINK_UP);
148 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
149 tm->hw_if_indicies[i]);
150 vec_validate (ip4_main.fib_index_by_sw_if_index,
151 tm->hw[i]->sw_if_index);
152 vec_validate (ip6_main.fib_index_by_sw_if_index,
153 tm->hw[i]->sw_if_index);
154 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
155 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
157 error = vnet_sw_interface_set_flags(vnet_get_main(),
158 tm->hw[i]->sw_if_index,
159 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
160 FIB_TEST((NULL == error), "UP interface %d", i);
163 * re-eval after the inevitable realloc
165 for (i = 0; i < ninterfaces; i++)
167 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
168 tm->hw_if_indicies[i]);
174 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
176 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
177 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
178 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
179 fib_table_lookup(fib_index, (_via_prefix))); \
180 FIB_TEST(!dpo_cmp(_via_dpo, \
181 load_balance_get_bucket(_rec_dpo->dpoi_index, \
183 "%U is recursive via %U", \
184 format_fib_prefix, (_rec_prefix), \
185 format_fib_prefix, _via_prefix); \
188 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
190 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
191 fib_table_lookup_exact_match(fib_index, (_prefix))); \
192 const dpo_id_t *_dpo1 = \
193 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
194 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
195 format_dpo_type, _dpo1->dpoi_type); \
196 FIB_TEST((_ai == _dpo1->dpoi_index), \
197 "%U bucket %d resolves via %U", \
198 format_fib_prefix, (_prefix), \
200 format_dpo_id, _dpo1, 0); \
203 #define FIB_TEST_RPF(_cond, _comment, _args...) \
205 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
211 fib_test_urpf_is_equal (fib_node_index_t fei,
212 fib_forward_chain_type_t fct,
215 dpo_id_t dpo = DPO_INVALID;
216 fib_urpf_list_t *urpf;
223 fib_entry_contribute_forwarding(fei, fct, &dpo);
224 ui = load_balance_get_urpf(dpo.dpoi_index);
226 urpf = fib_urpf_list_get(ui);
228 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
229 "RPF:%U len %d == %d",
230 format_fib_urpf_list, ui,
231 num, vec_len(urpf->furpf_itfs));
232 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
233 "RPF:%U check-size %d == %d",
234 format_fib_urpf_list, ui,
235 num, vec_len(urpf->furpf_itfs));
237 for (ii = 0; ii < num; ii++)
239 adj_index_t ai = va_arg(ap, adj_index_t);
241 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
242 "RPF:%d item:%d - %d == %d",
243 ui, ii, ai, urpf->furpf_itfs[ii]);
244 FIB_TEST_RPF(fib_urpf_check(ui, ai),
257 fib_test_build_rewrite (u8 *eth_addr)
261 vec_validate(rewrite, 13);
263 memcpy(rewrite, eth_addr, 6);
264 memcpy(rewrite+6, eth_addr, 6);
269 typedef enum fib_test_lb_bucket_type_t_ {
271 FT_LB_LABEL_STACK_O_ADJ,
277 } fib_test_lb_bucket_type_t;
279 typedef struct fib_test_lb_bucket_t_ {
280 fib_test_lb_bucket_type_t type;
294 mpls_label_t label_stack[8];
319 } fib_test_lb_bucket_t;
321 typedef enum fib_test_rep_bucket_type_t_ {
323 FT_REP_DISP_MFIB_LOOKUP,
325 } fib_test_rep_bucket_type_t;
327 typedef struct fib_test_rep_bucket_t_ {
328 fib_test_rep_bucket_type_t type;
344 } fib_test_rep_bucket_t;
346 #define FIB_TEST_LB(_cond, _comment, _args...) \
348 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
354 fib_test_validate_rep_v (const replicate_t *rep,
358 const fib_test_rep_bucket_t *exp;
362 FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
363 "n_buckets = %d", rep->rep_n_buckets);
365 for (bucket = 0; bucket < n_buckets; bucket++)
367 exp = va_arg(ap, fib_test_rep_bucket_t*);
369 dpo = replicate_get_bucket_i(rep, bucket);
373 case FT_REP_LABEL_O_ADJ:
375 const mpls_label_dpo_t *mld;
377 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
378 "bucket %d stacks on %U",
380 format_dpo_type, dpo->dpoi_type);
382 mld = mpls_label_dpo_get(dpo->dpoi_index);
383 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
385 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
386 exp->label_o_adj.label),
387 "bucket %d stacks on label %d",
389 exp->label_o_adj.label);
391 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
392 exp->label_o_adj.eos),
393 "bucket %d stacks on label %d %U",
395 exp->label_o_adj.label,
396 format_mpls_eos_bit, exp->label_o_adj.eos);
398 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
399 "bucket %d label stacks on %U",
401 format_dpo_type, mld->mld_dpo.dpoi_type);
403 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
404 "bucket %d label stacks on adj %d",
406 exp->label_o_adj.adj);
410 FIB_TEST_LB((DPO_INTERFACE == dpo->dpoi_type),
411 "bucket %d stacks on %U",
413 format_dpo_type, dpo->dpoi_type);
415 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
416 "bucket %d stacks on adj %d",
420 case FT_REP_DISP_MFIB_LOOKUP:
430 fib_test_validate_lb_v (const load_balance_t *lb,
437 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
439 for (bucket = 0; bucket < n_buckets; bucket++)
441 const fib_test_lb_bucket_t *exp;
443 exp = va_arg(ap, fib_test_lb_bucket_t*);
444 dpo = load_balance_get_bucket_i(lb, bucket);
448 case FT_LB_LABEL_STACK_O_ADJ:
450 const mpls_label_dpo_t *mld;
454 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
455 "bucket %d stacks on %U",
457 format_dpo_type, dpo->dpoi_type);
459 mld = mpls_label_dpo_get(dpo->dpoi_index);
461 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
465 for (ii = 0; ii < mld->mld_n_labels; ii++)
467 hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
468 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
469 exp->label_stack_o_adj.label_stack[ii]),
470 "bucket %d stacks on label %d",
472 exp->label_stack_o_adj.label_stack[ii]);
474 if (ii == mld->mld_n_labels-1)
476 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
477 exp->label_o_adj.eos),
478 "bucket %d stacks on label %d %U!=%U",
480 exp->label_stack_o_adj.label_stack[ii],
481 format_mpls_eos_bit, exp->label_o_adj.eos,
482 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
486 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
487 "bucket %d stacks on label %d %U",
489 exp->label_stack_o_adj.label_stack[ii],
490 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
494 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
495 "bucket %d label stacks on %U",
497 format_dpo_type, mld->mld_dpo.dpoi_type);
499 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
500 "bucket %d label stacks on adj %d",
502 exp->label_stack_o_adj.adj);
505 case FT_LB_LABEL_O_ADJ:
507 const mpls_label_dpo_t *mld;
509 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
510 "bucket %d stacks on %U",
512 format_dpo_type, dpo->dpoi_type);
514 mld = mpls_label_dpo_get(dpo->dpoi_index);
515 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
517 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
518 exp->label_o_adj.label),
519 "bucket %d stacks on label %d",
521 exp->label_o_adj.label);
523 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
524 exp->label_o_adj.eos),
525 "bucket %d stacks on label %d %U",
527 exp->label_o_adj.label,
528 format_mpls_eos_bit, exp->label_o_adj.eos);
530 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
531 "bucket %d label stacks on %U",
533 format_dpo_type, mld->mld_dpo.dpoi_type);
535 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
536 "bucket %d label stacks on adj %d",
538 exp->label_o_adj.adj);
541 case FT_LB_LABEL_O_LB:
543 const mpls_label_dpo_t *mld;
546 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
547 "bucket %d stacks on %U",
549 format_dpo_type, dpo->dpoi_type);
551 mld = mpls_label_dpo_get(dpo->dpoi_index);
552 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
554 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
556 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
557 exp->label_o_lb.label),
558 "bucket %d stacks on label %d",
560 exp->label_o_lb.label);
562 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
563 exp->label_o_lb.eos),
564 "bucket %d stacks on label %d %U",
566 exp->label_o_lb.label,
567 format_mpls_eos_bit, exp->label_o_lb.eos);
569 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
570 "bucket %d label stacks on %U",
572 format_dpo_type, mld->mld_dpo.dpoi_type);
574 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
575 "bucket %d label stacks on LB %d",
581 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
582 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
583 "bucket %d stacks on %U",
585 format_dpo_type, dpo->dpoi_type);
586 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
587 "bucket %d stacks on adj %d",
592 FIB_TEST_I((DPO_INTERFACE == dpo->dpoi_type),
593 "bucket %d stacks on %U",
595 format_dpo_type, dpo->dpoi_type);
596 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
597 "bucket %d stacks on adj %d",
602 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
603 "bucket %d stacks on %U",
605 format_dpo_type, dpo->dpoi_type);
606 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
607 "bucket %d stacks on lb %d",
612 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
613 "bucket %d stacks on %U",
615 format_dpo_type, dpo->dpoi_type);
616 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
617 "bucket %d stacks on drop %d",
627 fib_test_validate_entry (fib_node_index_t fei,
628 fib_forward_chain_type_t fct,
632 dpo_id_t dpo = DPO_INVALID;
639 va_start(ap, n_buckets);
641 fib_entry_get_prefix(fei, &pfx);
642 fib_index = fib_entry_get_fib_index(fei);
643 fib_entry_contribute_forwarding(fei, fct, &dpo);
645 if (DPO_REPLICATE == dpo.dpoi_type)
647 const replicate_t *rep;
649 rep = replicate_get(dpo.dpoi_index);
650 res = fib_test_validate_rep_v(rep, n_buckets, ap);
654 const load_balance_t *lb;
656 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
658 format_dpo_type, dpo.dpoi_type);
660 lb = load_balance_get(dpo.dpoi_index);
661 res = fib_test_validate_lb_v(lb, n_buckets, ap);
664 * ensure that the LB contributed by the entry is the
665 * same as the LB in the forwarding tables
667 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
669 switch (pfx.fp_proto)
671 case FIB_PROTOCOL_IP4:
672 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
674 case FIB_PROTOCOL_IP6:
675 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
677 case FIB_PROTOCOL_MPLS:
679 mpls_unicast_header_t hdr = {
680 .label_exp_s_ttl = 0,
683 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
684 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
685 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
687 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
693 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
694 "Contributed LB = FW LB: %U\n %U",
695 format_load_balance, fw_lbi, 0,
696 format_load_balance, dpo.dpoi_index, 0);
711 * In the default table check for the presence and correct forwarding
712 * of the special entries
714 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
715 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
716 const ip_adjacency_t *adj;
717 const load_balance_t *lb;
724 ip46_address_t nh_10_10_10_1 = {
725 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
728 ip46_address_t nh_10_10_10_2 = {
729 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
734 /* record the nubmer of load-balances in use before we start */
735 lb_count = pool_elts(load_balance_pool);
737 /* Find or create FIB table 11 */
738 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
740 for (ii = 0; ii < 4; ii++)
742 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
745 fib_prefix_t pfx_0_0_0_0_s_0 = {
747 .fp_proto = FIB_PROTOCOL_IP4,
757 .fp_proto = FIB_PROTOCOL_IP4,
765 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
767 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
768 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
769 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
770 "Default route is DROP");
773 fei = fib_table_lookup(fib_index, &pfx);
774 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
775 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
776 "all 0s route is DROP");
778 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
780 fei = fib_table_lookup(fib_index, &pfx);
781 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
782 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
783 "all 1s route is DROP");
785 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
787 fei = fib_table_lookup(fib_index, &pfx);
788 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
789 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
790 "all-mcast route is DROP");
792 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
794 fei = fib_table_lookup(fib_index, &pfx);
795 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
796 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
797 "class-e route is DROP");
800 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
801 * all of which are special sourced and so none of which share path-lists.
802 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
803 * table, and 4 path-lists in the v6 MFIB table
807 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
808 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
809 fib_path_list_pool_size());
810 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
811 fib_entry_pool_size());
814 * add interface routes.
815 * validate presence of /24 attached and /32 recieve.
816 * test for the presence of the receive address in the glean and local adj
818 fib_prefix_t local_pfx = {
820 .fp_proto = FIB_PROTOCOL_IP4,
823 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
828 fib_table_entry_update_one_path(fib_index, &local_pfx,
829 FIB_SOURCE_INTERFACE,
830 (FIB_ENTRY_FLAG_CONNECTED |
831 FIB_ENTRY_FLAG_ATTACHED),
834 tm->hw[0]->sw_if_index,
835 ~0, // invalid fib index
838 FIB_ROUTE_PATH_FLAG_NONE);
839 fei = fib_table_lookup(fib_index, &local_pfx);
840 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
841 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
842 fib_entry_get_flags(fei)),
843 "Flags set on attached interface");
845 ai = fib_entry_get_adj(fei);
846 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
848 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
849 "attached interface adj is glean");
850 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
851 &adj->sub_type.glean.receive_addr)),
852 "attached interface adj is receive ok");
854 local_pfx.fp_len = 32;
855 fib_table_entry_update_one_path(fib_index, &local_pfx,
856 FIB_SOURCE_INTERFACE,
857 (FIB_ENTRY_FLAG_CONNECTED |
858 FIB_ENTRY_FLAG_LOCAL),
861 tm->hw[0]->sw_if_index,
862 ~0, // invalid fib index
865 FIB_ROUTE_PATH_FLAG_NONE);
866 fei = fib_table_lookup(fib_index, &local_pfx);
867 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
868 fib_entry_get_flags(fei)),
869 "Flags set on local interface");
871 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
873 dpo = fib_entry_contribute_ip_forwarding(fei);
874 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
875 "RPF list for local length 0");
876 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
877 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
878 "local interface adj is local");
879 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
881 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
883 "local interface adj is receive ok");
885 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
887 FIB_SOURCE_INTERFACE)),
888 "2 Interface Source'd prefixes");
891 * +2 interface routes +2 non-shared path-lists
893 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
894 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
895 fib_path_list_pool_size());
896 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
897 fib_entry_pool_size());
900 * Modify the default route to be via an adj not yet known.
901 * this sources the defalut route with the API source, which is
902 * a higher preference to the DEFAULT_ROUTE source
904 pfx.fp_addr.ip4.as_u32 = 0;
906 fib_table_entry_path_add(fib_index, &pfx,
911 tm->hw[0]->sw_if_index,
912 ~0, // invalid fib index
915 FIB_ROUTE_PATH_FLAG_NONE);
916 fei = fib_table_lookup(fib_index, &pfx);
917 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
918 "Flags set on API route");
920 FIB_TEST((fei == dfrt), "default route same index");
921 ai = fib_entry_get_adj(fei);
922 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
924 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
925 "adj is incomplete");
926 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
927 "adj nbr next-hop ok");
928 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
931 "1 API Source'd prefixes");
934 * find the adj in the shared db
936 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
939 tm->hw[0]->sw_if_index);
940 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
941 adj_unlock(locked_ai);
944 * +1 shared path-list
946 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
947 fib_path_list_db_size());
948 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
949 fib_path_list_pool_size());
950 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
951 fib_entry_pool_size());
954 * remove the API source from the default route. We expected
955 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
957 pfx.fp_addr.ip4.as_u32 = 0;
959 fib_table_entry_path_remove(fib_index, &pfx,
963 tm->hw[0]->sw_if_index,
964 ~0, // non-recursive path, so no FIB index
966 FIB_ROUTE_PATH_FLAG_NONE);
968 fei = fib_table_lookup(fib_index, &pfx);
970 FIB_TEST((fei == dfrt), "default route same index");
971 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
972 "Default route is DROP");
975 * -1 shared-path-list
977 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
978 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
979 fib_path_list_pool_size());
980 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
981 fib_entry_pool_size());
984 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
986 fib_prefix_t pfx_10_10_10_1_s_32 = {
988 .fp_proto = FIB_PROTOCOL_IP4,
991 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
994 fib_prefix_t pfx_10_10_10_2_s_32 = {
996 .fp_proto = FIB_PROTOCOL_IP4,
999 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1002 fib_prefix_t pfx_11_11_11_11_s_32 = {
1004 .fp_proto = FIB_PROTOCOL_IP4,
1007 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1011 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1014 ip46_address_t nh_12_12_12_12 = {
1015 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1017 adj_index_t ai_12_12_12_12;
1020 * Add a route via an incomplete ADJ. then complete the ADJ
1021 * Expect the route LB is updated to use complete adj type.
1023 fei = fib_table_entry_update_one_path(fib_index,
1024 &pfx_11_11_11_11_s_32,
1026 FIB_ENTRY_FLAG_ATTACHED,
1028 &pfx_10_10_10_1_s_32.fp_addr,
1029 tm->hw[0]->sw_if_index,
1030 ~0, // invalid fib index
1033 FIB_ROUTE_PATH_FLAG_NONE);
1035 dpo = fib_entry_contribute_ip_forwarding(fei);
1036 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1037 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1038 "11.11.11.11/32 via incomplete adj");
1040 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1042 &pfx_10_10_10_1_s_32.fp_addr,
1043 tm->hw[0]->sw_if_index);
1044 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1045 adj = adj_get(ai_01);
1046 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1047 "adj is incomplete");
1048 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1049 &adj->sub_type.nbr.next_hop)),
1050 "adj nbr next-hop ok");
1052 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1053 fib_test_build_rewrite(eth_addr));
1054 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1056 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1057 &adj->sub_type.nbr.next_hop)),
1058 "adj nbr next-hop ok");
1059 ai = fib_entry_get_adj(fei);
1060 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1062 dpo = fib_entry_contribute_ip_forwarding(fei);
1063 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1064 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1065 "11.11.11.11/32 via complete adj");
1066 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1067 tm->hw[0]->sw_if_index),
1068 "RPF list for adj-fib contains adj");
1070 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1073 tm->hw[1]->sw_if_index);
1074 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1075 adj = adj_get(ai_12_12_12_12);
1076 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1077 "adj is incomplete");
1078 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1079 &adj->sub_type.nbr.next_hop)),
1080 "adj nbr next-hop ok");
1081 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1082 fib_test_build_rewrite(eth_addr));
1083 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1089 fei = fib_table_entry_update_one_path(fib_index,
1090 &pfx_10_10_10_1_s_32,
1092 FIB_ENTRY_FLAG_ATTACHED,
1094 &pfx_10_10_10_1_s_32.fp_addr,
1095 tm->hw[0]->sw_if_index,
1096 ~0, // invalid fib index
1099 FIB_ROUTE_PATH_FLAG_NONE);
1100 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1101 "Flags set on adj-fib");
1102 ai = fib_entry_get_adj(fei);
1103 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1105 fib_table_entry_path_remove(fib_index,
1106 &pfx_11_11_11_11_s_32,
1109 &pfx_10_10_10_1_s_32.fp_addr,
1110 tm->hw[0]->sw_if_index,
1111 ~0, // invalid fib index
1113 FIB_ROUTE_PATH_FLAG_NONE);
1117 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1119 &pfx_10_10_10_2_s_32.fp_addr,
1120 tm->hw[0]->sw_if_index);
1121 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1122 adj = adj_get(ai_02);
1123 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1124 "adj is incomplete");
1125 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1126 &adj->sub_type.nbr.next_hop)),
1127 "adj nbr next-hop ok");
1129 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1130 fib_test_build_rewrite(eth_addr));
1131 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1133 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1134 &adj->sub_type.nbr.next_hop)),
1135 "adj nbr next-hop ok");
1136 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1138 fib_table_entry_update_one_path(fib_index,
1139 &pfx_10_10_10_2_s_32,
1141 FIB_ENTRY_FLAG_ATTACHED,
1143 &pfx_10_10_10_2_s_32.fp_addr,
1144 tm->hw[0]->sw_if_index,
1145 ~0, // invalid fib index
1148 FIB_ROUTE_PATH_FLAG_NONE);
1150 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1151 ai = fib_entry_get_adj(fei);
1152 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1155 * +2 adj-fibs, and their non-shared path-lists
1157 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1158 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1159 fib_path_list_pool_size());
1160 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1161 fib_entry_pool_size());
1164 * Add 2 routes via the first ADJ. ensure path-list sharing
1166 fib_prefix_t pfx_1_1_1_1_s_32 = {
1168 .fp_proto = FIB_PROTOCOL_IP4,
1171 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1175 fib_table_entry_path_add(fib_index,
1178 FIB_ENTRY_FLAG_NONE,
1181 tm->hw[0]->sw_if_index,
1182 ~0, // invalid fib index
1185 FIB_ROUTE_PATH_FLAG_NONE);
1186 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1187 ai = fib_entry_get_adj(fei);
1188 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1191 * +1 entry and a shared path-list
1193 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1194 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1195 fib_path_list_pool_size());
1196 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1197 fib_entry_pool_size());
1200 fib_prefix_t pfx_1_1_2_0_s_24 = {
1202 .fp_proto = FIB_PROTOCOL_IP4,
1204 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1208 fib_table_entry_path_add(fib_index,
1211 FIB_ENTRY_FLAG_NONE,
1214 tm->hw[0]->sw_if_index,
1215 ~0, // invalid fib index
1218 FIB_ROUTE_PATH_FLAG_NONE);
1219 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1220 ai = fib_entry_get_adj(fei);
1221 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1226 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1227 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1228 fib_path_list_pool_size());
1229 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1230 fib_entry_pool_size());
1233 * modify 1.1.2.0/24 to use multipath.
1235 fib_table_entry_path_add(fib_index,
1238 FIB_ENTRY_FLAG_NONE,
1241 tm->hw[0]->sw_if_index,
1242 ~0, // invalid fib index
1245 FIB_ROUTE_PATH_FLAG_NONE);
1246 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1247 dpo = fib_entry_contribute_ip_forwarding(fei);
1248 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1249 1, tm->hw[0]->sw_if_index),
1250 "RPF list for 1.1.2.0/24 contains both adjs");
1252 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1253 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1254 FIB_TEST((ai_01 == dpo1->dpoi_index),
1255 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1256 ai_01, dpo1->dpoi_index);
1258 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1259 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1260 FIB_TEST((ai_02 == dpo1->dpoi_index),
1261 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1264 * +1 shared-pathlist
1266 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1267 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1268 fib_path_list_pool_size());
1269 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1270 fib_entry_pool_size());
1275 fib_table_entry_path_remove(fib_index,
1280 tm->hw[0]->sw_if_index,
1283 FIB_ROUTE_PATH_FLAG_NONE);
1284 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1285 dpo = fib_entry_contribute_ip_forwarding(fei);
1286 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1287 1, tm->hw[0]->sw_if_index),
1288 "RPF list for 1.1.2.0/24 contains one adj");
1290 ai = fib_entry_get_adj(fei);
1291 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1294 * +1 shared-pathlist
1296 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1297 fib_path_list_db_size());
1298 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1299 fib_path_list_pool_size());
1300 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1301 fib_entry_pool_size());
1304 * Add 2 recursive routes:
1305 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1306 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1308 fib_prefix_t bgp_100_pfx = {
1310 .fp_proto = FIB_PROTOCOL_IP4,
1312 /* 100.100.100.100/32 */
1313 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1317 ip46_address_t nh_1_1_1_1 = {
1318 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1321 fei = fib_table_entry_path_add(fib_index,
1324 FIB_ENTRY_FLAG_NONE,
1327 ~0, // no index provided.
1328 fib_index, // nexthop in same fib as route
1331 FIB_ROUTE_PATH_FLAG_NONE);
1333 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1334 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1335 tm->hw[0]->sw_if_index),
1336 "RPF list for adj-fib contains adj");
1339 * +1 entry and +1 shared-path-list
1341 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1342 fib_path_list_db_size());
1343 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1344 fib_path_list_pool_size());
1345 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1346 fib_entry_pool_size());
1348 fib_prefix_t bgp_101_pfx = {
1350 .fp_proto = FIB_PROTOCOL_IP4,
1352 /* 100.100.100.101/32 */
1353 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1357 fib_table_entry_path_add(fib_index,
1360 FIB_ENTRY_FLAG_NONE,
1363 ~0, // no index provided.
1364 fib_index, // nexthop in same fib as route
1367 FIB_ROUTE_PATH_FLAG_NONE);
1369 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1370 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1371 tm->hw[0]->sw_if_index),
1372 "RPF list for adj-fib contains adj");
1375 * +1 entry, but the recursive path-list is shared.
1377 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1378 fib_path_list_db_size());
1379 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1380 fib_path_list_pool_size());
1381 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1382 fib_entry_pool_size());
1385 * An special route; one where the user (me) provides the
1386 * adjacency through which the route will resovle by setting the flags
1388 fib_prefix_t ex_pfx = {
1390 .fp_proto = FIB_PROTOCOL_IP4,
1393 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1397 fib_table_entry_special_add(fib_index,
1400 FIB_ENTRY_FLAG_LOCAL);
1401 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1402 dpo = fib_entry_contribute_ip_forwarding(fei);
1403 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1404 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1405 "local interface adj is local");
1407 fib_table_entry_special_remove(fib_index,
1409 FIB_SOURCE_SPECIAL);
1410 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1411 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1412 "Exclusive reoute removed");
1415 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1416 * adjacency through which the route will resovle
1418 dpo_id_t ex_dpo = DPO_INVALID;
1420 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1423 LOOKUP_INPUT_DST_ADDR,
1424 LOOKUP_TABLE_FROM_CONFIG,
1427 fib_table_entry_special_dpo_add(fib_index,
1430 FIB_ENTRY_FLAG_EXCLUSIVE,
1432 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1433 dpo = fib_entry_contribute_ip_forwarding(fei);
1434 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1435 "exclusive remote uses lookup DPO");
1438 * update the exclusive to use a different DPO
1440 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1441 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1443 fib_table_entry_special_dpo_update(fib_index,
1446 FIB_ENTRY_FLAG_EXCLUSIVE,
1448 dpo = fib_entry_contribute_ip_forwarding(fei);
1449 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1450 "exclusive remote uses now uses NULL DPO");
1452 fib_table_entry_special_remove(fib_index,
1454 FIB_SOURCE_SPECIAL);
1455 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1456 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1457 "Exclusive reoute removed");
1461 * Add a recursive route:
1462 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1464 fib_prefix_t bgp_200_pfx = {
1466 .fp_proto = FIB_PROTOCOL_IP4,
1468 /* 200.200.200.200/32 */
1469 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1473 fib_prefix_t pfx_1_1_1_2_s_32 = {
1475 .fp_proto = FIB_PROTOCOL_IP4,
1477 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1481 fib_table_entry_path_add(fib_index,
1484 FIB_ENTRY_FLAG_NONE,
1486 &pfx_1_1_1_2_s_32.fp_addr,
1487 ~0, // no index provided.
1488 fib_index, // nexthop in same fib as route
1491 FIB_ROUTE_PATH_FLAG_NONE);
1493 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1496 * the adj should be recursive via drop, since the route resolves via
1497 * the default route, which is itself a DROP
1499 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1500 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1501 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1502 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1503 "RPF list for 1.1.1.2/32 contains 0 adjs");
1506 * +2 entry and +1 shared-path-list
1508 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1509 fib_path_list_db_size());
1510 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1511 fib_path_list_pool_size());
1512 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1513 fib_entry_pool_size());
1516 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1517 * The paths are sort by NH first. in this case the the path with greater
1518 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1520 fib_prefix_t pfx_1_2_3_4_s_32 = {
1522 .fp_proto = FIB_PROTOCOL_IP4,
1524 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1527 fib_table_entry_path_add(fib_index,
1530 FIB_ENTRY_FLAG_NONE,
1533 tm->hw[0]->sw_if_index,
1537 FIB_ROUTE_PATH_FLAG_NONE);
1538 fei = fib_table_entry_path_add(fib_index,
1541 FIB_ENTRY_FLAG_NONE,
1544 tm->hw[1]->sw_if_index,
1548 FIB_ROUTE_PATH_FLAG_NONE);
1550 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1551 dpo = fib_entry_contribute_ip_forwarding(fei);
1552 lb = load_balance_get(dpo->dpoi_index);
1553 FIB_TEST((lb->lb_n_buckets == 4),
1554 "1.2.3.4/32 LB has %d bucket",
1557 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1558 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1559 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1560 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1562 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1563 tm->hw[0]->sw_if_index,
1564 tm->hw[1]->sw_if_index),
1565 "RPF list for 1.2.3.4/32 contains both adjs");
1569 * Unequal Cost load-balance. 4:1 ratio.
1570 * fits in a 16 bucket LB with ratio 13:3
1572 fib_prefix_t pfx_1_2_3_5_s_32 = {
1574 .fp_proto = FIB_PROTOCOL_IP4,
1576 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1579 fib_table_entry_path_add(fib_index,
1582 FIB_ENTRY_FLAG_NONE,
1585 tm->hw[1]->sw_if_index,
1589 FIB_ROUTE_PATH_FLAG_NONE);
1590 fei = fib_table_entry_path_add(fib_index,
1593 FIB_ENTRY_FLAG_NONE,
1596 tm->hw[0]->sw_if_index,
1600 FIB_ROUTE_PATH_FLAG_NONE);
1602 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1603 dpo = fib_entry_contribute_ip_forwarding(fei);
1604 lb = load_balance_get(dpo->dpoi_index);
1605 FIB_TEST((lb->lb_n_buckets == 16),
1606 "1.2.3.5/32 LB has %d bucket",
1609 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1610 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1611 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1612 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1613 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1614 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1615 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1616 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1617 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1618 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1619 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1620 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1621 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1622 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1623 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1624 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1626 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1627 tm->hw[0]->sw_if_index,
1628 tm->hw[1]->sw_if_index),
1629 "RPF list for 1.2.3.4/32 contains both adjs");
1632 * Test UCMP with a large weight skew - this produces load-balance objects with large
1633 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1634 * laso testing the LB in placce modify code when number of buckets is large.
1636 fib_prefix_t pfx_6_6_6_6_s_32 = {
1638 .fp_proto = FIB_PROTOCOL_IP4,
1641 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1644 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_1 = {
1650 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_2 = {
1656 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1659 .adj = ai_12_12_12_12,
1662 fib_table_entry_update_one_path(fib_index,
1665 FIB_ENTRY_FLAG_NONE,
1668 tm->hw[0]->sw_if_index,
1669 ~0, // invalid fib index
1672 FIB_ROUTE_PATH_FLAG_NONE);
1674 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1675 FIB_TEST(fib_test_validate_entry(fei,
1676 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1678 &ip_6_6_6_6_o_10_10_10_1),
1679 "6.6.6.6/32 via 10.10.10.1");
1681 fib_table_entry_path_add(fib_index,
1684 FIB_ENTRY_FLAG_NONE,
1687 tm->hw[0]->sw_if_index,
1688 ~0, // invalid fib index
1691 FIB_ROUTE_PATH_FLAG_NONE);
1693 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1694 FIB_TEST(fib_test_validate_entry(fei,
1695 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
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_10_10_10_2,
1714 &ip_6_6_6_6_o_10_10_10_2,
1715 &ip_6_6_6_6_o_10_10_10_2,
1716 &ip_6_6_6_6_o_10_10_10_2,
1717 &ip_6_6_6_6_o_10_10_10_2,
1718 &ip_6_6_6_6_o_10_10_10_2,
1719 &ip_6_6_6_6_o_10_10_10_2,
1720 &ip_6_6_6_6_o_10_10_10_2,
1721 &ip_6_6_6_6_o_10_10_10_2,
1722 &ip_6_6_6_6_o_10_10_10_2,
1723 &ip_6_6_6_6_o_10_10_10_2,
1724 &ip_6_6_6_6_o_10_10_10_2,
1725 &ip_6_6_6_6_o_10_10_10_2,
1726 &ip_6_6_6_6_o_10_10_10_2,
1727 &ip_6_6_6_6_o_10_10_10_2,
1728 &ip_6_6_6_6_o_10_10_10_2,
1729 &ip_6_6_6_6_o_10_10_10_2,
1730 &ip_6_6_6_6_o_10_10_10_2,
1731 &ip_6_6_6_6_o_10_10_10_2,
1732 &ip_6_6_6_6_o_10_10_10_2,
1733 &ip_6_6_6_6_o_10_10_10_2,
1734 &ip_6_6_6_6_o_10_10_10_2,
1735 &ip_6_6_6_6_o_10_10_10_2,
1736 &ip_6_6_6_6_o_10_10_10_2,
1737 &ip_6_6_6_6_o_10_10_10_2,
1738 &ip_6_6_6_6_o_10_10_10_2,
1739 &ip_6_6_6_6_o_10_10_10_2,
1740 &ip_6_6_6_6_o_10_10_10_2,
1741 &ip_6_6_6_6_o_10_10_10_2,
1742 &ip_6_6_6_6_o_10_10_10_2,
1743 &ip_6_6_6_6_o_10_10_10_2,
1744 &ip_6_6_6_6_o_10_10_10_2,
1745 &ip_6_6_6_6_o_10_10_10_2,
1746 &ip_6_6_6_6_o_10_10_10_2,
1747 &ip_6_6_6_6_o_10_10_10_2,
1748 &ip_6_6_6_6_o_10_10_10_2,
1749 &ip_6_6_6_6_o_10_10_10_2,
1750 &ip_6_6_6_6_o_10_10_10_2,
1751 &ip_6_6_6_6_o_10_10_10_2,
1752 &ip_6_6_6_6_o_10_10_10_2,
1753 &ip_6_6_6_6_o_10_10_10_2,
1754 &ip_6_6_6_6_o_10_10_10_2,
1755 &ip_6_6_6_6_o_10_10_10_2,
1756 &ip_6_6_6_6_o_10_10_10_2,
1757 &ip_6_6_6_6_o_10_10_10_2,
1758 &ip_6_6_6_6_o_10_10_10_2,
1759 &ip_6_6_6_6_o_10_10_10_2,
1760 &ip_6_6_6_6_o_10_10_10_1),
1761 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1763 fib_table_entry_path_add(fib_index,
1766 FIB_ENTRY_FLAG_NONE,
1769 tm->hw[1]->sw_if_index,
1770 ~0, // invalid fib index
1773 FIB_ROUTE_PATH_FLAG_NONE);
1775 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1776 FIB_TEST(fib_test_validate_entry(fei,
1777 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1779 &ip_6_6_6_6_o_10_10_10_1,
1780 &ip_6_6_6_6_o_10_10_10_2,
1781 &ip_6_6_6_6_o_10_10_10_2,
1782 &ip_6_6_6_6_o_10_10_10_2,
1783 &ip_6_6_6_6_o_10_10_10_2,
1784 &ip_6_6_6_6_o_10_10_10_2,
1785 &ip_6_6_6_6_o_10_10_10_2,
1786 &ip_6_6_6_6_o_10_10_10_2,
1787 &ip_6_6_6_6_o_10_10_10_2,
1788 &ip_6_6_6_6_o_10_10_10_2,
1789 &ip_6_6_6_6_o_10_10_10_2,
1790 &ip_6_6_6_6_o_10_10_10_2,
1791 &ip_6_6_6_6_o_10_10_10_2,
1792 &ip_6_6_6_6_o_10_10_10_2,
1793 &ip_6_6_6_6_o_10_10_10_2,
1794 &ip_6_6_6_6_o_10_10_10_2,
1795 &ip_6_6_6_6_o_10_10_10_2,
1796 &ip_6_6_6_6_o_10_10_10_2,
1797 &ip_6_6_6_6_o_10_10_10_2,
1798 &ip_6_6_6_6_o_10_10_10_2,
1799 &ip_6_6_6_6_o_10_10_10_2,
1800 &ip_6_6_6_6_o_10_10_10_2,
1801 &ip_6_6_6_6_o_10_10_10_2,
1802 &ip_6_6_6_6_o_10_10_10_2,
1803 &ip_6_6_6_6_o_10_10_10_2,
1804 &ip_6_6_6_6_o_10_10_10_2,
1805 &ip_6_6_6_6_o_10_10_10_2,
1806 &ip_6_6_6_6_o_10_10_10_2,
1807 &ip_6_6_6_6_o_10_10_10_2,
1808 &ip_6_6_6_6_o_10_10_10_2,
1809 &ip_6_6_6_6_o_10_10_10_2,
1810 &ip_6_6_6_6_o_10_10_10_2,
1811 &ip_6_6_6_6_o_10_10_10_2,
1812 &ip_6_6_6_6_o_10_10_10_2,
1813 &ip_6_6_6_6_o_10_10_10_2,
1814 &ip_6_6_6_6_o_10_10_10_2,
1815 &ip_6_6_6_6_o_10_10_10_2,
1816 &ip_6_6_6_6_o_10_10_10_2,
1817 &ip_6_6_6_6_o_10_10_10_2,
1818 &ip_6_6_6_6_o_10_10_10_2,
1819 &ip_6_6_6_6_o_10_10_10_2,
1820 &ip_6_6_6_6_o_10_10_10_2,
1821 &ip_6_6_6_6_o_10_10_10_2,
1822 &ip_6_6_6_6_o_10_10_10_2,
1823 &ip_6_6_6_6_o_10_10_10_2,
1824 &ip_6_6_6_6_o_10_10_10_2,
1825 &ip_6_6_6_6_o_10_10_10_2,
1826 &ip_6_6_6_6_o_10_10_10_2,
1827 &ip_6_6_6_6_o_10_10_10_2,
1828 &ip_6_6_6_6_o_10_10_10_2,
1829 &ip_6_6_6_6_o_10_10_10_2,
1830 &ip_6_6_6_6_o_10_10_10_2,
1831 &ip_6_6_6_6_o_10_10_10_2,
1832 &ip_6_6_6_6_o_10_10_10_2,
1833 &ip_6_6_6_6_o_10_10_10_2,
1834 &ip_6_6_6_6_o_10_10_10_2,
1835 &ip_6_6_6_6_o_10_10_10_2,
1836 &ip_6_6_6_6_o_10_10_10_2,
1837 &ip_6_6_6_6_o_10_10_10_2,
1838 &ip_6_6_6_6_o_10_10_10_2,
1839 &ip_6_6_6_6_o_10_10_10_2,
1840 &ip_6_6_6_6_o_10_10_10_2,
1841 &ip_6_6_6_6_o_10_10_10_2,
1842 &ip_6_6_6_6_o_10_10_10_2,
1843 &ip_6_6_6_6_o_10_10_10_2,
1844 &ip_6_6_6_6_o_12_12_12_12,
1845 &ip_6_6_6_6_o_12_12_12_12,
1846 &ip_6_6_6_6_o_12_12_12_12,
1847 &ip_6_6_6_6_o_12_12_12_12,
1848 &ip_6_6_6_6_o_12_12_12_12,
1849 &ip_6_6_6_6_o_12_12_12_12,
1850 &ip_6_6_6_6_o_12_12_12_12,
1851 &ip_6_6_6_6_o_12_12_12_12,
1852 &ip_6_6_6_6_o_12_12_12_12,
1853 &ip_6_6_6_6_o_12_12_12_12,
1854 &ip_6_6_6_6_o_12_12_12_12,
1855 &ip_6_6_6_6_o_12_12_12_12,
1856 &ip_6_6_6_6_o_12_12_12_12,
1857 &ip_6_6_6_6_o_12_12_12_12,
1858 &ip_6_6_6_6_o_12_12_12_12,
1859 &ip_6_6_6_6_o_12_12_12_12,
1860 &ip_6_6_6_6_o_12_12_12_12,
1861 &ip_6_6_6_6_o_12_12_12_12,
1862 &ip_6_6_6_6_o_12_12_12_12,
1863 &ip_6_6_6_6_o_12_12_12_12,
1864 &ip_6_6_6_6_o_12_12_12_12,
1865 &ip_6_6_6_6_o_12_12_12_12,
1866 &ip_6_6_6_6_o_12_12_12_12,
1867 &ip_6_6_6_6_o_12_12_12_12,
1868 &ip_6_6_6_6_o_12_12_12_12,
1869 &ip_6_6_6_6_o_12_12_12_12,
1870 &ip_6_6_6_6_o_12_12_12_12,
1871 &ip_6_6_6_6_o_12_12_12_12,
1872 &ip_6_6_6_6_o_12_12_12_12,
1873 &ip_6_6_6_6_o_12_12_12_12,
1874 &ip_6_6_6_6_o_12_12_12_12,
1875 &ip_6_6_6_6_o_12_12_12_12,
1876 &ip_6_6_6_6_o_12_12_12_12,
1877 &ip_6_6_6_6_o_12_12_12_12,
1878 &ip_6_6_6_6_o_12_12_12_12,
1879 &ip_6_6_6_6_o_12_12_12_12,
1880 &ip_6_6_6_6_o_12_12_12_12,
1881 &ip_6_6_6_6_o_12_12_12_12,
1882 &ip_6_6_6_6_o_12_12_12_12,
1883 &ip_6_6_6_6_o_12_12_12_12,
1884 &ip_6_6_6_6_o_12_12_12_12,
1885 &ip_6_6_6_6_o_12_12_12_12,
1886 &ip_6_6_6_6_o_12_12_12_12,
1887 &ip_6_6_6_6_o_12_12_12_12,
1888 &ip_6_6_6_6_o_12_12_12_12,
1889 &ip_6_6_6_6_o_12_12_12_12,
1890 &ip_6_6_6_6_o_12_12_12_12,
1891 &ip_6_6_6_6_o_12_12_12_12,
1892 &ip_6_6_6_6_o_12_12_12_12,
1893 &ip_6_6_6_6_o_12_12_12_12,
1894 &ip_6_6_6_6_o_12_12_12_12,
1895 &ip_6_6_6_6_o_12_12_12_12,
1896 &ip_6_6_6_6_o_12_12_12_12,
1897 &ip_6_6_6_6_o_12_12_12_12,
1898 &ip_6_6_6_6_o_12_12_12_12,
1899 &ip_6_6_6_6_o_12_12_12_12,
1900 &ip_6_6_6_6_o_12_12_12_12,
1901 &ip_6_6_6_6_o_12_12_12_12,
1902 &ip_6_6_6_6_o_12_12_12_12,
1903 &ip_6_6_6_6_o_12_12_12_12,
1904 &ip_6_6_6_6_o_12_12_12_12,
1905 &ip_6_6_6_6_o_12_12_12_12,
1906 &ip_6_6_6_6_o_12_12_12_12),
1907 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1909 fib_table_entry_path_remove(fib_index,
1914 tm->hw[1]->sw_if_index,
1915 ~0, // invalid fib index
1917 FIB_ROUTE_PATH_FLAG_NONE);
1919 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1920 FIB_TEST(fib_test_validate_entry(fei,
1921 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1923 &ip_6_6_6_6_o_10_10_10_2,
1924 &ip_6_6_6_6_o_10_10_10_2,
1925 &ip_6_6_6_6_o_10_10_10_2,
1926 &ip_6_6_6_6_o_10_10_10_2,
1927 &ip_6_6_6_6_o_10_10_10_2,
1928 &ip_6_6_6_6_o_10_10_10_2,
1929 &ip_6_6_6_6_o_10_10_10_2,
1930 &ip_6_6_6_6_o_10_10_10_2,
1931 &ip_6_6_6_6_o_10_10_10_2,
1932 &ip_6_6_6_6_o_10_10_10_2,
1933 &ip_6_6_6_6_o_10_10_10_2,
1934 &ip_6_6_6_6_o_10_10_10_2,
1935 &ip_6_6_6_6_o_10_10_10_2,
1936 &ip_6_6_6_6_o_10_10_10_2,
1937 &ip_6_6_6_6_o_10_10_10_2,
1938 &ip_6_6_6_6_o_10_10_10_2,
1939 &ip_6_6_6_6_o_10_10_10_2,
1940 &ip_6_6_6_6_o_10_10_10_2,
1941 &ip_6_6_6_6_o_10_10_10_2,
1942 &ip_6_6_6_6_o_10_10_10_2,
1943 &ip_6_6_6_6_o_10_10_10_2,
1944 &ip_6_6_6_6_o_10_10_10_2,
1945 &ip_6_6_6_6_o_10_10_10_2,
1946 &ip_6_6_6_6_o_10_10_10_2,
1947 &ip_6_6_6_6_o_10_10_10_2,
1948 &ip_6_6_6_6_o_10_10_10_2,
1949 &ip_6_6_6_6_o_10_10_10_2,
1950 &ip_6_6_6_6_o_10_10_10_2,
1951 &ip_6_6_6_6_o_10_10_10_2,
1952 &ip_6_6_6_6_o_10_10_10_2,
1953 &ip_6_6_6_6_o_10_10_10_2,
1954 &ip_6_6_6_6_o_10_10_10_2,
1955 &ip_6_6_6_6_o_10_10_10_2,
1956 &ip_6_6_6_6_o_10_10_10_2,
1957 &ip_6_6_6_6_o_10_10_10_2,
1958 &ip_6_6_6_6_o_10_10_10_2,
1959 &ip_6_6_6_6_o_10_10_10_2,
1960 &ip_6_6_6_6_o_10_10_10_2,
1961 &ip_6_6_6_6_o_10_10_10_2,
1962 &ip_6_6_6_6_o_10_10_10_2,
1963 &ip_6_6_6_6_o_10_10_10_2,
1964 &ip_6_6_6_6_o_10_10_10_2,
1965 &ip_6_6_6_6_o_10_10_10_2,
1966 &ip_6_6_6_6_o_10_10_10_2,
1967 &ip_6_6_6_6_o_10_10_10_2,
1968 &ip_6_6_6_6_o_10_10_10_2,
1969 &ip_6_6_6_6_o_10_10_10_2,
1970 &ip_6_6_6_6_o_10_10_10_2,
1971 &ip_6_6_6_6_o_10_10_10_2,
1972 &ip_6_6_6_6_o_10_10_10_2,
1973 &ip_6_6_6_6_o_10_10_10_2,
1974 &ip_6_6_6_6_o_10_10_10_2,
1975 &ip_6_6_6_6_o_10_10_10_2,
1976 &ip_6_6_6_6_o_10_10_10_2,
1977 &ip_6_6_6_6_o_10_10_10_2,
1978 &ip_6_6_6_6_o_10_10_10_2,
1979 &ip_6_6_6_6_o_10_10_10_2,
1980 &ip_6_6_6_6_o_10_10_10_2,
1981 &ip_6_6_6_6_o_10_10_10_2,
1982 &ip_6_6_6_6_o_10_10_10_2,
1983 &ip_6_6_6_6_o_10_10_10_2,
1984 &ip_6_6_6_6_o_10_10_10_2,
1985 &ip_6_6_6_6_o_10_10_10_2,
1986 &ip_6_6_6_6_o_10_10_10_1),
1987 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1989 fib_table_entry_path_remove(fib_index,
1994 tm->hw[0]->sw_if_index,
1995 ~0, // invalid fib index
1997 FIB_ROUTE_PATH_FLAG_NONE);
1999 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2000 FIB_TEST(fib_test_validate_entry(fei,
2001 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2003 &ip_6_6_6_6_o_10_10_10_1),
2004 "6.6.6.6/32 via 10.10.10.1");
2006 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2009 * A recursive via the two unequal cost entries
2011 fib_prefix_t bgp_44_s_32 = {
2013 .fp_proto = FIB_PROTOCOL_IP4,
2015 /* 200.200.200.201/32 */
2016 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2019 fei = fib_table_entry_path_add(fib_index,
2022 FIB_ENTRY_FLAG_NONE,
2024 &pfx_1_2_3_4_s_32.fp_addr,
2029 FIB_ROUTE_PATH_FLAG_NONE);
2030 fei = fib_table_entry_path_add(fib_index,
2033 FIB_ENTRY_FLAG_NONE,
2035 &pfx_1_2_3_5_s_32.fp_addr,
2040 FIB_ROUTE_PATH_FLAG_NONE);
2042 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2043 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2044 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2045 tm->hw[0]->sw_if_index,
2046 tm->hw[1]->sw_if_index),
2047 "RPF list for 1.2.3.4/32 contains both adjs");
2050 * test the uRPF check functions
2052 dpo_id_t dpo_44 = DPO_INVALID;
2055 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2056 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2058 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2059 "uRPF check for 68.68.68.68/32 on %d OK",
2060 tm->hw[0]->sw_if_index);
2061 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2062 "uRPF check for 68.68.68.68/32 on %d OK",
2063 tm->hw[1]->sw_if_index);
2064 FIB_TEST(!fib_urpf_check(urpfi, 99),
2065 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2069 fib_table_entry_delete(fib_index,
2072 fib_table_entry_delete(fib_index,
2075 fib_table_entry_delete(fib_index,
2080 * Add a recursive route:
2081 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2083 fib_prefix_t bgp_201_pfx = {
2085 .fp_proto = FIB_PROTOCOL_IP4,
2087 /* 200.200.200.201/32 */
2088 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2092 fib_prefix_t pfx_1_1_1_200_s_32 = {
2094 .fp_proto = FIB_PROTOCOL_IP4,
2096 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2100 fib_table_entry_path_add(fib_index,
2103 FIB_ENTRY_FLAG_NONE,
2105 &pfx_1_1_1_200_s_32.fp_addr,
2106 ~0, // no index provided.
2107 fib_index, // nexthop in same fib as route
2110 FIB_ROUTE_PATH_FLAG_NONE);
2112 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2114 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2115 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2116 "Flags set on RR via non-attached");
2117 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2118 "RPF list for BGP route empty");
2121 * +2 entry (BGP & RR) and +1 shared-path-list
2123 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2124 fib_path_list_db_size());
2125 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2126 fib_path_list_pool_size());
2127 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2128 fib_entry_pool_size());
2131 * insert a route that covers the missing 1.1.1.2/32. we epxect
2132 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2134 fib_prefix_t pfx_1_1_1_0_s_24 = {
2136 .fp_proto = FIB_PROTOCOL_IP4,
2139 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2143 fib_table_entry_path_add(fib_index,
2146 FIB_ENTRY_FLAG_NONE,
2149 tm->hw[0]->sw_if_index,
2150 ~0, // invalid fib index
2153 FIB_ROUTE_PATH_FLAG_NONE);
2154 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2155 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2156 ai = fib_entry_get_adj(fei);
2157 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2158 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2159 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2160 ai = fib_entry_get_adj(fei);
2161 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2162 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2163 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2164 ai = fib_entry_get_adj(fei);
2165 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2168 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2170 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2171 fib_path_list_db_size());
2172 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2173 fib_path_list_pool_size());
2174 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2175 fib_entry_pool_size());
2178 * the recursive adj for 200.200.200.200 should be updated.
2180 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2181 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2182 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2183 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2184 tm->hw[0]->sw_if_index),
2185 "RPF list for BGP route has itf index 0");
2188 * insert a more specific route than 1.1.1.0/24 that also covers the
2189 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2190 * 200.200.200.200 to resolve through it.
2192 fib_prefix_t pfx_1_1_1_0_s_28 = {
2194 .fp_proto = FIB_PROTOCOL_IP4,
2197 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2201 fib_table_entry_path_add(fib_index,
2204 FIB_ENTRY_FLAG_NONE,
2207 tm->hw[0]->sw_if_index,
2208 ~0, // invalid fib index
2211 FIB_ROUTE_PATH_FLAG_NONE);
2212 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2213 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2214 ai = fib_entry_get_adj(fei);
2215 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2218 * +1 entry. +1 shared path-list
2220 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2221 fib_path_list_db_size());
2222 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2223 fib_path_list_pool_size());
2224 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2225 fib_entry_pool_size());
2228 * the recursive adj for 200.200.200.200 should be updated.
2229 * 200.200.200.201 remains unchanged.
2231 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2232 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2235 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2237 fib_table_entry_path_remove(fib_index,
2242 tm->hw[0]->sw_if_index,
2245 FIB_ROUTE_PATH_FLAG_NONE);
2246 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2247 FIB_NODE_INDEX_INVALID),
2248 "1.1.1.0/28 removed");
2249 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2250 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2251 "1.1.1.0/28 lookup via /24");
2252 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2253 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2256 * -1 entry. -1 shared path-list
2258 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2259 fib_path_list_db_size());
2260 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2261 fib_path_list_pool_size());
2262 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2263 fib_entry_pool_size());
2266 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2268 fib_table_entry_path_remove(fib_index,
2273 tm->hw[0]->sw_if_index,
2276 FIB_ROUTE_PATH_FLAG_NONE);
2277 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2278 FIB_NODE_INDEX_INVALID),
2279 "1.1.1.0/24 removed");
2281 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2282 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2283 "1.1.1.2/32 route is DROP");
2284 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2285 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2286 "1.1.1.200/32 route is DROP");
2288 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2289 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2294 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2295 fib_path_list_db_size());
2296 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2297 fib_path_list_pool_size());
2298 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2299 fib_entry_pool_size());
2302 * insert the missing 1.1.1.2/32
2304 fei = fib_table_entry_path_add(fib_index,
2307 FIB_ENTRY_FLAG_NONE,
2310 tm->hw[0]->sw_if_index,
2311 ~0, // invalid fib index
2314 FIB_ROUTE_PATH_FLAG_NONE);
2315 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2316 ai = fib_entry_get_adj(fei);
2317 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2319 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2320 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2323 * no change. 1.1.1.2/32 was already there RR sourced.
2325 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2326 fib_path_list_db_size());
2327 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2328 fib_path_list_pool_size());
2329 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2330 fib_entry_pool_size());
2333 * remove 200.200.200.201/32 which does not have a valid via FIB
2335 fib_table_entry_path_remove(fib_index,
2339 &pfx_1_1_1_200_s_32.fp_addr,
2340 ~0, // no index provided.
2343 FIB_ROUTE_PATH_FLAG_NONE);
2346 * -2 entries (BGP and RR). -1 shared path-list;
2348 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2349 FIB_NODE_INDEX_INVALID),
2350 "200.200.200.201/32 removed");
2351 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2352 FIB_NODE_INDEX_INVALID),
2353 "1.1.1.200/32 removed");
2355 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2356 fib_path_list_db_size());
2357 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2358 fib_path_list_pool_size());
2359 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2360 fib_entry_pool_size());
2363 * remove 200.200.200.200/32 which does have a valid via FIB
2365 fib_table_entry_path_remove(fib_index,
2369 &pfx_1_1_1_2_s_32.fp_addr,
2370 ~0, // no index provided.
2373 FIB_ROUTE_PATH_FLAG_NONE);
2375 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2376 FIB_NODE_INDEX_INVALID),
2377 "200.200.200.200/32 removed");
2378 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2379 FIB_NODE_INDEX_INVALID),
2380 "1.1.1.2/32 still present");
2383 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2385 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2386 fib_path_list_db_size());
2387 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2388 fib_path_list_pool_size());
2389 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2390 fib_entry_pool_size());
2393 * A recursive prefix that has a 2 path load-balance.
2394 * It also shares a next-hop with other BGP prefixes and hence
2395 * test the ref counting of RR sourced prefixes and 2 level LB.
2397 const fib_prefix_t bgp_102 = {
2399 .fp_proto = FIB_PROTOCOL_IP4,
2401 /* 100.100.100.101/32 */
2402 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2405 fib_table_entry_path_add(fib_index,
2408 FIB_ENTRY_FLAG_NONE,
2410 &pfx_1_1_1_1_s_32.fp_addr,
2411 ~0, // no index provided.
2412 fib_index, // same as route
2415 FIB_ROUTE_PATH_FLAG_NONE);
2416 fib_table_entry_path_add(fib_index,
2419 FIB_ENTRY_FLAG_NONE,
2421 &pfx_1_1_1_2_s_32.fp_addr,
2422 ~0, // no index provided.
2423 fib_index, // same as route's FIB
2426 FIB_ROUTE_PATH_FLAG_NONE);
2427 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2428 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2429 dpo = fib_entry_contribute_ip_forwarding(fei);
2431 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2432 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2433 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2434 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2436 lb = load_balance_get(dpo->dpoi_index);
2437 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2438 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2439 "First via 10.10.10.1");
2440 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2441 "Second via 10.10.10.1");
2443 fib_table_entry_path_remove(fib_index,
2447 &pfx_1_1_1_1_s_32.fp_addr,
2448 ~0, // no index provided.
2449 fib_index, // same as route's FIB
2451 FIB_ROUTE_PATH_FLAG_NONE);
2452 fib_table_entry_path_remove(fib_index,
2456 &pfx_1_1_1_2_s_32.fp_addr,
2457 ~0, // no index provided.
2458 fib_index, // same as route's FIB
2460 FIB_ROUTE_PATH_FLAG_NONE);
2461 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2462 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2465 * remove the remaining recursives
2467 fib_table_entry_path_remove(fib_index,
2471 &pfx_1_1_1_1_s_32.fp_addr,
2472 ~0, // no index provided.
2473 fib_index, // same as route's FIB
2475 FIB_ROUTE_PATH_FLAG_NONE);
2476 fib_table_entry_path_remove(fib_index,
2480 &pfx_1_1_1_1_s_32.fp_addr,
2481 ~0, // no index provided.
2482 fib_index, // same as route's FIB
2484 FIB_ROUTE_PATH_FLAG_NONE);
2485 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2486 FIB_NODE_INDEX_INVALID),
2487 "100.100.100.100/32 removed");
2488 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2489 FIB_NODE_INDEX_INVALID),
2490 "100.100.100.101/32 removed");
2493 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2495 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2496 fib_path_list_db_size());
2497 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2498 fib_path_list_pool_size());
2499 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2500 fib_entry_pool_size());
2503 * Add a recursive route via a connected cover, using an adj-fib that does exist
2505 fib_table_entry_path_add(fib_index,
2508 FIB_ENTRY_FLAG_NONE,
2511 ~0, // no index provided.
2512 fib_index, // Same as route's FIB
2515 FIB_ROUTE_PATH_FLAG_NONE);
2518 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2520 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2521 fib_path_list_db_size());
2522 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2523 fib_path_list_pool_size());
2524 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2525 fib_entry_pool_size());
2527 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2528 dpo = fib_entry_contribute_ip_forwarding(fei);
2530 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2531 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2533 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2534 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2536 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2537 "Flags set on RR via existing attached");
2540 * Add a recursive route via a connected cover, using and adj-fib that does
2543 ip46_address_t nh_10_10_10_3 = {
2544 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2546 fib_prefix_t pfx_10_10_10_3 = {
2548 .fp_proto = FIB_PROTOCOL_IP4,
2549 .fp_addr = nh_10_10_10_3,
2552 fib_table_entry_path_add(fib_index,
2555 FIB_ENTRY_FLAG_NONE,
2558 ~0, // no index provided.
2562 FIB_ROUTE_PATH_FLAG_NONE);
2565 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2566 * one unshared non-recursive via 10.10.10.3
2568 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2569 fib_path_list_db_size());
2570 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2571 fib_path_list_pool_size());
2572 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2573 fib_entry_pool_size());
2575 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2578 tm->hw[0]->sw_if_index);
2580 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2581 dpo = fib_entry_contribute_ip_forwarding(fei);
2582 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2583 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2585 ai = fib_entry_get_adj(fei);
2586 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2587 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2588 fib_entry_get_flags(fei)),
2589 "Flags set on RR via non-existing attached");
2591 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2592 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2597 * remove the recursives
2599 fib_table_entry_path_remove(fib_index,
2604 ~0, // no index provided.
2605 fib_index, // same as route's FIB
2607 FIB_ROUTE_PATH_FLAG_NONE);
2608 fib_table_entry_path_remove(fib_index,
2613 ~0, // no index provided.
2614 fib_index, // same as route's FIB
2616 FIB_ROUTE_PATH_FLAG_NONE);
2618 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2619 FIB_NODE_INDEX_INVALID),
2620 "200.200.200.201/32 removed");
2621 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2622 FIB_NODE_INDEX_INVALID),
2623 "200.200.200.200/32 removed");
2624 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2625 FIB_NODE_INDEX_INVALID),
2626 "10.10.10.3/32 removed");
2629 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2630 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2632 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2633 fib_path_list_db_size());
2634 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2635 fib_path_list_pool_size());
2636 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2637 fib_entry_pool_size());
2642 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2644 fib_prefix_t pfx_5_5_5_5_s_32 = {
2646 .fp_proto = FIB_PROTOCOL_IP4,
2648 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2651 fib_prefix_t pfx_5_5_5_6_s_32 = {
2653 .fp_proto = FIB_PROTOCOL_IP4,
2655 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2658 fib_prefix_t pfx_5_5_5_7_s_32 = {
2660 .fp_proto = FIB_PROTOCOL_IP4,
2662 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2666 fib_table_entry_path_add(fib_index,
2669 FIB_ENTRY_FLAG_NONE,
2671 &pfx_5_5_5_6_s_32.fp_addr,
2672 ~0, // no index provided.
2676 FIB_ROUTE_PATH_FLAG_NONE);
2677 fib_table_entry_path_add(fib_index,
2680 FIB_ENTRY_FLAG_NONE,
2682 &pfx_5_5_5_7_s_32.fp_addr,
2683 ~0, // no index provided.
2687 FIB_ROUTE_PATH_FLAG_NONE);
2688 fib_table_entry_path_add(fib_index,
2691 FIB_ENTRY_FLAG_NONE,
2693 &pfx_5_5_5_5_s_32.fp_addr,
2694 ~0, // no index provided.
2698 FIB_ROUTE_PATH_FLAG_NONE);
2700 * +3 entries, +3 shared path-list
2702 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2703 fib_path_list_db_size());
2704 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2705 fib_path_list_pool_size());
2706 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2707 fib_entry_pool_size());
2710 * All the entries have only looped paths, so they are all drop
2712 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2713 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2714 "LB for 5.5.5.7/32 is via adj for DROP");
2715 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2716 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2717 "LB for 5.5.5.5/32 is via adj for DROP");
2718 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2719 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2720 "LB for 5.5.5.6/32 is via adj for DROP");
2723 * provide 5.5.5.6/32 with alternate path.
2724 * this will allow only 5.5.5.6/32 to forward with this path, the others
2725 * are still drop since the loop is still present.
2727 fib_table_entry_path_add(fib_index,
2730 FIB_ENTRY_FLAG_NONE,
2733 tm->hw[0]->sw_if_index,
2737 FIB_ROUTE_PATH_FLAG_NONE);
2739 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2740 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2742 lb = load_balance_get(dpo1->dpoi_index);
2743 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2745 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2746 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2747 FIB_TEST((ai_01 == dpo2->dpoi_index),
2748 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2750 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2751 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2752 "LB for 5.5.5.7/32 is via adj for DROP");
2753 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2754 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2755 "LB for 5.5.5.5/32 is via adj for DROP");
2758 * remove the alternate path for 5.5.5.6/32
2761 fib_table_entry_path_remove(fib_index,
2766 tm->hw[0]->sw_if_index,
2769 FIB_ROUTE_PATH_FLAG_NONE);
2771 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2772 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2773 "LB for 5.5.5.7/32 is via adj for DROP");
2774 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2775 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2776 "LB for 5.5.5.5/32 is via adj for DROP");
2777 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2778 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2779 "LB for 5.5.5.6/32 is via adj for DROP");
2782 * break the loop by giving 5.5.5.5/32 a new set of paths
2783 * expect all to forward via this new path.
2785 fib_table_entry_update_one_path(fib_index,
2788 FIB_ENTRY_FLAG_NONE,
2791 tm->hw[0]->sw_if_index,
2792 ~0, // invalid fib index
2795 FIB_ROUTE_PATH_FLAG_NONE);
2797 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2798 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2799 lb = load_balance_get(dpo1->dpoi_index);
2800 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2802 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2803 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2804 FIB_TEST((ai_01 == dpo2->dpoi_index),
2805 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2807 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2808 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2810 lb = load_balance_get(dpo2->dpoi_index);
2811 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2812 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2813 "5.5.5.5.7 via 5.5.5.5");
2815 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2816 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2818 lb = load_balance_get(dpo1->dpoi_index);
2819 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2820 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2821 "5.5.5.5.6 via 5.5.5.7");
2824 * revert back to the loop. so we can remove the prefixes with
2827 fib_table_entry_update_one_path(fib_index,
2830 FIB_ENTRY_FLAG_NONE,
2832 &pfx_5_5_5_6_s_32.fp_addr,
2833 ~0, // no index provided.
2837 FIB_ROUTE_PATH_FLAG_NONE);
2839 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2840 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2841 "LB for 5.5.5.7/32 is via adj for DROP");
2842 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2843 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2844 "LB for 5.5.5.5/32 is via adj for DROP");
2845 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2846 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2847 "LB for 5.5.5.6/32 is via adj for DROP");
2850 * remove all the 5.5.5.x/32 prefixes
2852 fib_table_entry_path_remove(fib_index,
2856 &pfx_5_5_5_6_s_32.fp_addr,
2857 ~0, // no index provided.
2858 fib_index, // same as route's FIB
2860 FIB_ROUTE_PATH_FLAG_NONE);
2861 fib_table_entry_path_remove(fib_index,
2865 &pfx_5_5_5_7_s_32.fp_addr,
2866 ~0, // no index provided.
2867 fib_index, // same as route's FIB
2869 FIB_ROUTE_PATH_FLAG_NONE);
2870 fib_table_entry_path_remove(fib_index,
2874 &pfx_5_5_5_5_s_32.fp_addr,
2875 ~0, // no index provided.
2876 fib_index, // same as route's FIB
2878 FIB_ROUTE_PATH_FLAG_NONE);
2879 fib_table_entry_path_remove(fib_index,
2884 ~0, // no index provided.
2885 fib_index, // same as route's FIB
2887 FIB_ROUTE_PATH_FLAG_NONE);
2890 * -3 entries, -3 shared path-list
2892 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2893 fib_path_list_db_size());
2894 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2895 fib_path_list_pool_size());
2896 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2897 fib_entry_pool_size());
2900 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2902 fib_table_entry_path_add(fib_index,
2905 FIB_ENTRY_FLAG_NONE,
2907 &pfx_5_5_5_6_s_32.fp_addr,
2908 ~0, // no index provided.
2912 FIB_ROUTE_PATH_FLAG_NONE);
2913 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2914 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2915 "1-level 5.5.5.6/32 loop is via adj for DROP");
2917 fib_table_entry_path_remove(fib_index,
2921 &pfx_5_5_5_6_s_32.fp_addr,
2922 ~0, // no index provided.
2923 fib_index, // same as route's FIB
2925 FIB_ROUTE_PATH_FLAG_NONE);
2926 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2927 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2928 "1-level 5.5.5.6/32 loop is removed");
2931 * A recursive route whose next-hop is covered by the prefix.
2932 * This would mean the via-fib, which inherits forwarding from its
2933 * cover, thus picks up forwarding from the prfix, which is via the
2934 * via-fib, and we have a loop.
2936 fib_prefix_t pfx_23_23_23_0_s_24 = {
2938 .fp_proto = FIB_PROTOCOL_IP4,
2940 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2943 fib_prefix_t pfx_23_23_23_23_s_32 = {
2945 .fp_proto = FIB_PROTOCOL_IP4,
2947 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2950 fei = fib_table_entry_path_add(fib_index,
2951 &pfx_23_23_23_0_s_24,
2953 FIB_ENTRY_FLAG_NONE,
2955 &pfx_23_23_23_23_s_32.fp_addr,
2960 FIB_ROUTE_PATH_FLAG_NONE);
2961 dpo = fib_entry_contribute_ip_forwarding(fei);
2962 FIB_TEST(load_balance_is_drop(dpo),
2963 "23.23.23.0/24 via covered is DROP");
2964 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2967 * add-remove test. no change.
2969 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2970 fib_path_list_db_size());
2971 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2972 fib_path_list_pool_size());
2973 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2974 fib_entry_pool_size());
2977 * A recursive route with recursion constraints.
2978 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2980 fib_table_entry_path_add(fib_index,
2983 FIB_ENTRY_FLAG_NONE,
2990 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2992 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2993 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2995 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2996 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2998 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2999 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3002 * save the load-balance. we expect it to be inplace modified
3004 lb = load_balance_get(dpo1->dpoi_index);
3007 * add a covering prefix for the via fib that would otherwise serve
3008 * as the resolving route when the host is removed
3010 fib_table_entry_path_add(fib_index,
3013 FIB_ENTRY_FLAG_NONE,
3016 tm->hw[0]->sw_if_index,
3017 ~0, // invalid fib index
3020 FIB_ROUTE_PATH_FLAG_NONE);
3021 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3022 ai = fib_entry_get_adj(fei);
3023 FIB_TEST((ai == ai_01),
3024 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3027 * remove the host via FIB - expect the BGP prefix to be drop
3029 fib_table_entry_path_remove(fib_index,
3034 tm->hw[0]->sw_if_index,
3035 ~0, // invalid fib index
3037 FIB_ROUTE_PATH_FLAG_NONE);
3039 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3040 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3043 * add the via-entry host reoute back. expect to resolve again
3045 fib_table_entry_path_add(fib_index,
3048 FIB_ENTRY_FLAG_NONE,
3051 tm->hw[0]->sw_if_index,
3052 ~0, // invalid fib index
3055 FIB_ROUTE_PATH_FLAG_NONE);
3056 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3057 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3060 * add another path for the recursive. it will then have 2.
3062 fib_prefix_t pfx_1_1_1_3_s_32 = {
3064 .fp_proto = FIB_PROTOCOL_IP4,
3066 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3069 fib_table_entry_path_add(fib_index,
3072 FIB_ENTRY_FLAG_NONE,
3075 tm->hw[0]->sw_if_index,
3076 ~0, // invalid fib index
3079 FIB_ROUTE_PATH_FLAG_NONE);
3081 fib_table_entry_path_add(fib_index,
3084 FIB_ENTRY_FLAG_NONE,
3086 &pfx_1_1_1_3_s_32.fp_addr,
3091 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3093 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3094 dpo = fib_entry_contribute_ip_forwarding(fei);
3096 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3097 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3098 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3099 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3100 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3101 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3102 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3103 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3106 * expect the lb-map used by the recursive's load-balance is using both buckets
3108 load_balance_map_t *lbm;
3111 lb = load_balance_get(dpo->dpoi_index);
3113 load_balance_map_lock(lbmi);
3114 lbm = load_balance_map_get(lbmi);
3116 FIB_TEST(lbm->lbm_buckets[0] == 0,
3117 "LB maps's bucket 0 is %d",
3118 lbm->lbm_buckets[0]);
3119 FIB_TEST(lbm->lbm_buckets[1] == 1,
3120 "LB maps's bucket 1 is %d",
3121 lbm->lbm_buckets[1]);
3124 * withdraw one of the /32 via-entrys.
3125 * that ECMP path will be unresolved and forwarding should continue on the
3126 * other available path. this is an iBGP PIC edge failover.
3127 * Test the forwarding changes without re-fetching the adj from the
3128 * recursive entry. this ensures its the same one that is updated; i.e. an
3131 fib_table_entry_path_remove(fib_index,
3136 tm->hw[0]->sw_if_index,
3137 ~0, // invalid fib index
3139 FIB_ROUTE_PATH_FLAG_NONE);
3141 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3142 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3143 "post PIC 200.200.200.200/32 was inplace modified");
3145 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3146 "post PIC adj for 200.200.200.200/32 is recursive"
3147 " via adj for 1.1.1.3");
3150 * the LB maps that was locked above should have been modified to remove
3151 * the path that was down, and thus its bucket points to a path that is
3154 FIB_TEST(lbm->lbm_buckets[0] == 1,
3155 "LB maps's bucket 0 is %d",
3156 lbm->lbm_buckets[0]);
3157 FIB_TEST(lbm->lbm_buckets[1] == 1,
3158 "LB maps's bucket 1 is %d",
3159 lbm->lbm_buckets[1]);
3161 load_balance_map_unlock(lbmi);
3164 * add it back. again
3166 fib_table_entry_path_add(fib_index,
3169 FIB_ENTRY_FLAG_NONE,
3172 tm->hw[0]->sw_if_index,
3173 ~0, // invalid fib index
3176 FIB_ROUTE_PATH_FLAG_NONE);
3178 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3179 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3180 "via adj for 1.1.1.1");
3181 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3182 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3183 "via adj for 1.1.1.3");
3185 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3186 dpo = fib_entry_contribute_ip_forwarding(fei);
3187 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3188 "post PIC 200.200.200.200/32 was inplace modified");
3191 * add a 3rd path. this makes the LB 16 buckets.
3193 fib_table_entry_path_add(fib_index,
3196 FIB_ENTRY_FLAG_NONE,
3198 &pfx_1_1_1_2_s_32.fp_addr,
3203 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3205 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3206 dpo = fib_entry_contribute_ip_forwarding(fei);
3207 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3208 "200.200.200.200/32 was inplace modified for 3rd path");
3209 FIB_TEST(16 == lb->lb_n_buckets,
3210 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3213 load_balance_map_lock(lbmi);
3214 lbm = load_balance_map_get(lbmi);
3216 for (ii = 0; ii < 16; ii++)
3218 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3219 "LB Map for 200.200.200.200/32 at %d is %d",
3220 ii, lbm->lbm_buckets[ii]);
3224 * trigger PIC by removing the first via-entry
3225 * the first 6 buckets of the map should map to the next 6
3227 fib_table_entry_path_remove(fib_index,
3232 tm->hw[0]->sw_if_index,
3235 FIB_ROUTE_PATH_FLAG_NONE);
3237 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3238 dpo = fib_entry_contribute_ip_forwarding(fei);
3239 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3240 "200.200.200.200/32 was inplace modified for 3rd path");
3241 FIB_TEST(2 == lb->lb_n_buckets,
3242 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3244 for (ii = 0; ii < 6; ii++)
3246 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3247 "LB Map for 200.200.200.200/32 at %d is %d",
3248 ii, lbm->lbm_buckets[ii]);
3250 for (ii = 6; ii < 16; ii++)
3252 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3253 "LB Map for 200.200.200.200/32 at %d is %d",
3254 ii, lbm->lbm_buckets[ii]);
3256 load_balance_map_unlock(lbmi);
3261 fib_table_entry_path_add(fib_index,
3264 FIB_ENTRY_FLAG_NONE,
3267 tm->hw[0]->sw_if_index,
3271 FIB_ROUTE_PATH_FLAG_NONE);
3273 fib_table_entry_path_remove(fib_index,
3277 &pfx_1_1_1_2_s_32.fp_addr,
3281 MPLS_LABEL_INVALID);
3282 fib_table_entry_path_remove(fib_index,
3290 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3291 fib_table_entry_path_remove(fib_index,
3295 &pfx_1_1_1_3_s_32.fp_addr,
3299 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3300 fib_table_entry_delete(fib_index,
3303 fib_table_entry_delete(fib_index,
3306 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3307 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3308 "1.1.1.1/28 removed");
3309 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3310 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3311 "1.1.1.3/32 removed");
3312 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3313 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3314 "200.200.200.200/32 removed");
3317 * add-remove test. no change.
3319 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3320 fib_path_list_db_size());
3321 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3322 fib_path_list_pool_size());
3323 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3324 fib_entry_pool_size());
3327 * A route whose paths are built up iteratively and then removed
3330 fib_prefix_t pfx_4_4_4_4_s_32 = {
3332 .fp_proto = FIB_PROTOCOL_IP4,
3335 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3339 fib_table_entry_path_add(fib_index,
3342 FIB_ENTRY_FLAG_NONE,
3345 tm->hw[0]->sw_if_index,
3349 FIB_ROUTE_PATH_FLAG_NONE);
3350 fib_table_entry_path_add(fib_index,
3353 FIB_ENTRY_FLAG_NONE,
3356 tm->hw[0]->sw_if_index,
3360 FIB_ROUTE_PATH_FLAG_NONE);
3361 fib_table_entry_path_add(fib_index,
3364 FIB_ENTRY_FLAG_NONE,
3367 tm->hw[0]->sw_if_index,
3371 FIB_ROUTE_PATH_FLAG_NONE);
3372 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3373 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3374 "4.4.4.4/32 present");
3376 fib_table_entry_delete(fib_index,
3379 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3380 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3381 "4.4.4.4/32 removed");
3384 * add-remove test. no change.
3386 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3387 fib_path_list_db_size());
3388 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3389 fib_path_list_pool_size());
3390 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3391 fib_entry_pool_size());
3394 * A route with multiple paths at once
3396 fib_route_path_t *r_paths = NULL;
3398 for (ii = 0; ii < 4; ii++)
3400 fib_route_path_t r_path = {
3401 .frp_proto = FIB_PROTOCOL_IP4,
3403 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3405 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3407 .frp_fib_index = ~0,
3409 vec_add1(r_paths, r_path);
3412 fib_table_entry_update(fib_index,
3415 FIB_ENTRY_FLAG_NONE,
3418 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3419 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3420 dpo = fib_entry_contribute_ip_forwarding(fei);
3422 lb = load_balance_get(dpo->dpoi_index);
3423 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3425 fib_table_entry_delete(fib_index,
3428 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3429 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3430 "4.4.4.4/32 removed");
3434 * add-remove test. no change.
3436 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3437 fib_path_list_db_size());
3438 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3439 fib_path_list_pool_size());
3440 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3441 fib_entry_pool_size());
3444 * A route deag route
3446 fib_table_entry_path_add(fib_index,
3449 FIB_ENTRY_FLAG_NONE,
3456 FIB_ROUTE_PATH_FLAG_NONE);
3458 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3459 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3461 dpo = fib_entry_contribute_ip_forwarding(fei);
3462 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3463 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3465 FIB_TEST((fib_index == lkd->lkd_fib_index),
3466 "4.4.4.4/32 is deag in %d %U",
3468 format_dpo_id, dpo, 0);
3470 fib_table_entry_delete(fib_index,
3473 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3474 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3475 "4.4.4.4/32 removed");
3479 * add-remove test. no change.
3481 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3482 fib_path_list_db_size());
3483 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3484 fib_path_list_pool_size());
3485 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3486 fib_entry_pool_size());
3490 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3492 fib_prefix_t pfx_34_1_1_1_s_32 = {
3494 .fp_proto = FIB_PROTOCOL_IP4,
3496 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3499 fib_prefix_t pfx_34_34_1_1_s_32 = {
3501 .fp_proto = FIB_PROTOCOL_IP4,
3503 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3506 fei = fib_table_entry_path_add(fib_index,
3509 FIB_ENTRY_FLAG_NONE,
3511 &pfx_34_34_1_1_s_32.fp_addr,
3516 FIB_ROUTE_PATH_FLAG_NONE);
3517 fei = fib_table_entry_path_add(fib_index,
3520 FIB_ENTRY_FLAG_NONE,
3522 &pfx_34_34_1_1_s_32.fp_addr,
3527 FIB_ROUTE_PATH_FLAG_NONE);
3528 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3529 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3533 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3534 * all of which are via 10.10.10.1, Itf1
3536 fib_table_entry_path_remove(fib_index,
3541 tm->hw[0]->sw_if_index,
3544 FIB_ROUTE_PATH_FLAG_NONE);
3545 fib_table_entry_path_remove(fib_index,
3550 tm->hw[0]->sw_if_index,
3553 FIB_ROUTE_PATH_FLAG_NONE);
3554 fib_table_entry_path_remove(fib_index,
3559 tm->hw[0]->sw_if_index,
3562 FIB_ROUTE_PATH_FLAG_NONE);
3564 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3565 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3566 "1.1.1.1/32 removed");
3567 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3568 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3569 "1.1.1.2/32 removed");
3570 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3571 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3572 "1.1.2.0/24 removed");
3575 * -3 entries and -1 shared path-list
3577 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3578 fib_path_list_db_size());
3579 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3580 fib_path_list_pool_size());
3581 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3582 fib_entry_pool_size());
3585 * An attached-host route. Expect to link to the incomplete adj
3587 fib_prefix_t pfx_4_1_1_1_s_32 = {
3589 .fp_proto = FIB_PROTOCOL_IP4,
3592 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3595 fib_table_entry_path_add(fib_index,
3598 FIB_ENTRY_FLAG_NONE,
3601 tm->hw[0]->sw_if_index,
3605 FIB_ROUTE_PATH_FLAG_NONE);
3607 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3608 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3609 ai = fib_entry_get_adj(fei);
3611 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3613 &pfx_4_1_1_1_s_32.fp_addr,
3614 tm->hw[0]->sw_if_index);
3615 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3619 * +1 entry and +1 shared path-list
3621 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3622 fib_path_list_db_size());
3623 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3624 fib_path_list_pool_size());
3625 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3626 fib_entry_pool_size());
3628 fib_table_entry_delete(fib_index,
3632 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3633 fib_path_list_db_size());
3634 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3635 fib_path_list_pool_size());
3636 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3637 fib_entry_pool_size());
3640 * add a v6 prefix via v4 next-hops
3642 fib_prefix_t pfx_2001_s_64 = {
3644 .fp_proto = FIB_PROTOCOL_IP6,
3646 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3649 fei = fib_table_entry_path_add(0, //default v6 table
3652 FIB_ENTRY_FLAG_NONE,
3655 tm->hw[0]->sw_if_index,
3659 FIB_ROUTE_PATH_FLAG_NONE);
3661 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3662 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3663 ai = fib_entry_get_adj(fei);
3665 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3666 "2001::/64 via ARP-adj");
3667 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3668 "2001::/64 is link type v6");
3669 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3670 "2001::/64 ADJ-adj is NH proto v4");
3671 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3674 * add a uRPF exempt prefix:
3676 * - it's forwarding is drop
3677 * - it's uRPF list is not empty
3678 * - the uRPF list for the default route (it's cover) is empty
3680 fei = fib_table_entry_special_add(fib_index,
3682 FIB_SOURCE_URPF_EXEMPT,
3683 FIB_ENTRY_FLAG_DROP);
3684 dpo = fib_entry_contribute_ip_forwarding(fei);
3685 FIB_TEST(load_balance_is_drop(dpo),
3686 "uRPF exempt 4.1.1.1/32 DROP");
3687 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3688 "uRPF list for exempt prefix has itf index 0");
3689 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3690 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3691 "uRPF list for 0.0.0.0/0 empty");
3693 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3696 * An adj-fib that fails the refinement criteria - no connected cover
3698 fib_prefix_t pfx_12_10_10_2_s_32 = {
3700 .fp_proto = FIB_PROTOCOL_IP4,
3703 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3707 fib_table_entry_update_one_path(fib_index,
3708 &pfx_12_10_10_2_s_32,
3710 FIB_ENTRY_FLAG_ATTACHED,
3712 &pfx_12_10_10_2_s_32.fp_addr,
3713 tm->hw[0]->sw_if_index,
3714 ~0, // invalid fib index
3717 FIB_ROUTE_PATH_FLAG_NONE);
3719 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3720 dpo = fib_entry_contribute_ip_forwarding(fei);
3721 FIB_TEST(!dpo_id_is_valid(dpo),
3722 "no connected cover adj-fib fails refinement");
3724 fib_table_entry_delete(fib_index,
3725 &pfx_12_10_10_2_s_32,
3729 * An adj-fib that fails the refinement criteria - cover is connected
3730 * but on a different interface
3732 fib_prefix_t pfx_10_10_10_127_s_32 = {
3734 .fp_proto = FIB_PROTOCOL_IP4,
3737 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3741 fib_table_entry_update_one_path(fib_index,
3742 &pfx_10_10_10_127_s_32,
3744 FIB_ENTRY_FLAG_ATTACHED,
3746 &pfx_10_10_10_127_s_32.fp_addr,
3747 tm->hw[1]->sw_if_index,
3748 ~0, // invalid fib index
3751 FIB_ROUTE_PATH_FLAG_NONE);
3753 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3754 dpo = fib_entry_contribute_ip_forwarding(fei);
3755 FIB_TEST(!dpo_id_is_valid(dpo),
3756 "wrong interface adj-fib fails refinement");
3758 fib_table_entry_delete(fib_index,
3759 &pfx_10_10_10_127_s_32,
3766 fib_table_entry_delete(fib_index,
3767 &pfx_10_10_10_1_s_32,
3769 fib_table_entry_delete(fib_index,
3770 &pfx_10_10_10_2_s_32,
3772 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3773 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
3774 "10.10.10.1/32 adj-fib removed");
3775 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3776 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
3777 "10.10.10.2/32 adj-fib removed");
3780 * -2 entries and -2 non-shared path-list
3782 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3783 fib_path_list_db_size());
3784 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
3785 fib_path_list_pool_size());
3786 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
3787 fib_entry_pool_size());
3790 * unlock the adjacencies for which this test provided a rewrite.
3791 * These are the last locks on these adjs. they should thus go away.
3795 adj_unlock(ai_12_12_12_12);
3797 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3802 * remove the interface prefixes
3804 local_pfx.fp_len = 32;
3805 fib_table_entry_special_remove(fib_index, &local_pfx,
3806 FIB_SOURCE_INTERFACE);
3807 fei = fib_table_lookup(fib_index, &local_pfx);
3809 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3810 fib_table_lookup_exact_match(fib_index, &local_pfx),
3811 "10.10.10.10/32 adj-fib removed");
3813 local_pfx.fp_len = 24;
3814 fib_table_entry_delete(fib_index, &local_pfx,
3815 FIB_SOURCE_INTERFACE);
3817 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3818 fib_table_lookup_exact_match(fib_index, &local_pfx),
3819 "10.10.10.10/24 adj-fib removed");
3822 * -2 entries and -2 non-shared path-list
3824 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3825 fib_path_list_db_size());
3826 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
3827 fib_path_list_pool_size());
3828 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
3829 fib_entry_pool_size());
3832 * Last but not least, remove the VRF
3834 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3837 "NO API Source'd prefixes");
3838 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3841 "NO RR Source'd prefixes");
3842 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3844 FIB_SOURCE_INTERFACE)),
3845 "NO INterface Source'd prefixes");
3847 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
3849 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3850 fib_path_list_db_size());
3851 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
3852 fib_path_list_pool_size());
3853 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
3854 fib_entry_pool_size());
3855 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
3856 pool_elts(fib_urpf_list_pool));
3857 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
3858 pool_elts(load_balance_map_pool));
3859 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
3860 pool_elts(load_balance_pool));
3869 * In the default table check for the presence and correct forwarding
3870 * of the special entries
3872 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
3873 const dpo_id_t *dpo, *dpo_drop;
3874 const ip_adjacency_t *adj;
3875 const receive_dpo_t *rd;
3880 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3883 /* via 2001:0:0:1::2 */
3884 ip46_address_t nh_2001_2 = {
3887 [0] = clib_host_to_net_u64(0x2001000000000001),
3888 [1] = clib_host_to_net_u64(0x0000000000000002),
3895 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
3897 /* Find or create FIB table 11 */
3898 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
3900 for (ii = 0; ii < 4; ii++)
3902 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
3905 fib_prefix_t pfx_0_0 = {
3907 .fp_proto = FIB_PROTOCOL_IP6,
3915 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
3916 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
3917 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3918 "Default route is DROP");
3920 dpo = fib_entry_contribute_ip_forwarding(dfrt);
3921 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3924 &pfx_0_0.fp_addr.ip6)),
3925 "default-route; fwd and non-fwd tables match");
3927 // FIXME - check specials.
3930 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
3931 * each with 2 entries and a v6 mfib with 4 path-lists.
3932 * All entries are special so no path-list sharing.
3935 #define PNPS (5+4+4)
3936 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3937 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
3938 fib_path_list_pool_size());
3939 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
3940 fib_entry_pool_size());
3943 * add interface routes.
3944 * validate presence of /64 attached and /128 recieve.
3945 * test for the presence of the receive address in the glean and local adj
3947 * receive on 2001:0:0:1::1/128
3949 fib_prefix_t local_pfx = {
3951 .fp_proto = FIB_PROTOCOL_IP6,
3955 [0] = clib_host_to_net_u64(0x2001000000000001),
3956 [1] = clib_host_to_net_u64(0x0000000000000001),
3962 fib_table_entry_update_one_path(fib_index, &local_pfx,
3963 FIB_SOURCE_INTERFACE,
3964 (FIB_ENTRY_FLAG_CONNECTED |
3965 FIB_ENTRY_FLAG_ATTACHED),
3968 tm->hw[0]->sw_if_index,
3972 FIB_ROUTE_PATH_FLAG_NONE);
3973 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3975 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3977 ai = fib_entry_get_adj(fei);
3978 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
3980 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3981 "attached interface adj is glean");
3982 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3983 &adj->sub_type.glean.receive_addr)),
3984 "attached interface adj is receive ok");
3985 dpo = fib_entry_contribute_ip_forwarding(fei);
3986 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3989 &local_pfx.fp_addr.ip6)),
3990 "attached-route; fwd and non-fwd tables match");
3992 local_pfx.fp_len = 128;
3993 fib_table_entry_update_one_path(fib_index, &local_pfx,
3994 FIB_SOURCE_INTERFACE,
3995 (FIB_ENTRY_FLAG_CONNECTED |
3996 FIB_ENTRY_FLAG_LOCAL),
3999 tm->hw[0]->sw_if_index,
4000 ~0, // invalid fib index
4003 FIB_ROUTE_PATH_FLAG_NONE);
4004 fei = fib_table_lookup(fib_index, &local_pfx);
4006 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4008 dpo = fib_entry_contribute_ip_forwarding(fei);
4009 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4010 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4011 "local interface adj is local");
4012 rd = receive_dpo_get(dpo->dpoi_index);
4014 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4016 "local interface adj is receive ok");
4018 dpo = fib_entry_contribute_ip_forwarding(fei);
4019 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4022 &local_pfx.fp_addr.ip6)),
4023 "local-route; fwd and non-fwd tables match");
4026 * +2 entries. +2 unshared path-lists
4028 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4029 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4030 fib_path_list_pool_size());
4031 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4032 fib_entry_pool_size());
4035 * Modify the default route to be via an adj not yet known.
4036 * this sources the defalut route with the API source, which is
4037 * a higher preference to the DEFAULT_ROUTE source
4039 fib_table_entry_path_add(fib_index, &pfx_0_0,
4041 FIB_ENTRY_FLAG_NONE,
4044 tm->hw[0]->sw_if_index,
4048 FIB_ROUTE_PATH_FLAG_NONE);
4049 fei = fib_table_lookup(fib_index, &pfx_0_0);
4051 FIB_TEST((fei == dfrt), "default route same index");
4052 ai = fib_entry_get_adj(fei);
4053 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4055 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4056 "adj is incomplete");
4057 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4058 "adj nbr next-hop ok");
4061 * find the adj in the shared db
4063 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4066 tm->hw[0]->sw_if_index);
4067 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4068 adj_unlock(locked_ai);
4071 * no more entires. +1 shared path-list
4073 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4074 fib_path_list_db_size());
4075 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4076 fib_path_list_pool_size());
4077 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4078 fib_entry_pool_size());
4081 * remove the API source from the default route. We expected
4082 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4084 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4088 tm->hw[0]->sw_if_index,
4091 FIB_ROUTE_PATH_FLAG_NONE);
4092 fei = fib_table_lookup(fib_index, &pfx_0_0);
4094 FIB_TEST((fei == dfrt), "default route same index");
4095 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4096 "Default route is DROP");
4099 * no more entires. -1 shared path-list
4101 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4102 fib_path_list_db_size());
4103 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4104 fib_path_list_pool_size());
4105 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4106 fib_entry_pool_size());
4109 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4111 fib_prefix_t pfx_2001_1_2_s_128 = {
4113 .fp_proto = FIB_PROTOCOL_IP6,
4117 [0] = clib_host_to_net_u64(0x2001000000000001),
4118 [1] = clib_host_to_net_u64(0x0000000000000002),
4123 fib_prefix_t pfx_2001_1_3_s_128 = {
4125 .fp_proto = FIB_PROTOCOL_IP6,
4129 [0] = clib_host_to_net_u64(0x2001000000000001),
4130 [1] = clib_host_to_net_u64(0x0000000000000003),
4136 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4139 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4141 &pfx_2001_1_2_s_128.fp_addr,
4142 tm->hw[0]->sw_if_index);
4143 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4144 adj = adj_get(ai_01);
4145 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4146 "adj is incomplete");
4147 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4148 &adj->sub_type.nbr.next_hop)),
4149 "adj nbr next-hop ok");
4151 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4152 fib_test_build_rewrite(eth_addr));
4153 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4155 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4156 &adj->sub_type.nbr.next_hop)),
4157 "adj nbr next-hop ok");
4159 fib_table_entry_update_one_path(fib_index,
4160 &pfx_2001_1_2_s_128,
4162 FIB_ENTRY_FLAG_ATTACHED,
4164 &pfx_2001_1_2_s_128.fp_addr,
4165 tm->hw[0]->sw_if_index,
4169 FIB_ROUTE_PATH_FLAG_NONE);
4171 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4172 ai = fib_entry_get_adj(fei);
4173 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4177 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4179 &pfx_2001_1_3_s_128.fp_addr,
4180 tm->hw[0]->sw_if_index);
4181 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4182 adj = adj_get(ai_02);
4183 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4184 "adj is incomplete");
4185 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4186 &adj->sub_type.nbr.next_hop)),
4187 "adj nbr next-hop ok");
4189 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4190 fib_test_build_rewrite(eth_addr));
4191 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4193 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4194 &adj->sub_type.nbr.next_hop)),
4195 "adj nbr next-hop ok");
4196 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4198 fib_table_entry_update_one_path(fib_index,
4199 &pfx_2001_1_3_s_128,
4201 FIB_ENTRY_FLAG_ATTACHED,
4203 &pfx_2001_1_3_s_128.fp_addr,
4204 tm->hw[0]->sw_if_index,
4208 FIB_ROUTE_PATH_FLAG_NONE);
4210 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4211 ai = fib_entry_get_adj(fei);
4212 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4215 * +2 entries, +2 unshread path-lists.
4217 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4218 fib_path_list_db_size());
4219 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4220 fib_path_list_pool_size());
4221 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4222 fib_entry_pool_size());
4225 * Add a 2 routes via the first ADJ. ensure path-list sharing
4227 fib_prefix_t pfx_2001_a_s_64 = {
4229 .fp_proto = FIB_PROTOCOL_IP6,
4233 [0] = clib_host_to_net_u64(0x200100000000000a),
4234 [1] = clib_host_to_net_u64(0x0000000000000000),
4239 fib_prefix_t pfx_2001_b_s_64 = {
4241 .fp_proto = FIB_PROTOCOL_IP6,
4245 [0] = clib_host_to_net_u64(0x200100000000000b),
4246 [1] = clib_host_to_net_u64(0x0000000000000000),
4252 fib_table_entry_path_add(fib_index,
4255 FIB_ENTRY_FLAG_NONE,
4258 tm->hw[0]->sw_if_index,
4262 FIB_ROUTE_PATH_FLAG_NONE);
4263 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4264 ai = fib_entry_get_adj(fei);
4265 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4266 fib_table_entry_path_add(fib_index,
4269 FIB_ENTRY_FLAG_NONE,
4272 tm->hw[0]->sw_if_index,
4276 FIB_ROUTE_PATH_FLAG_NONE);
4277 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4278 ai = fib_entry_get_adj(fei);
4279 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4282 * +2 entries, +1 shared path-list.
4284 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4285 fib_path_list_db_size());
4286 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4287 fib_path_list_pool_size());
4288 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4289 fib_entry_pool_size());
4292 * add a v4 prefix via a v6 next-hop
4294 fib_prefix_t pfx_1_1_1_1_s_32 = {
4296 .fp_proto = FIB_PROTOCOL_IP4,
4298 .ip4.as_u32 = 0x01010101,
4301 fei = fib_table_entry_path_add(0, // default table
4304 FIB_ENTRY_FLAG_NONE,
4307 tm->hw[0]->sw_if_index,
4311 FIB_ROUTE_PATH_FLAG_NONE);
4312 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4313 "1.1.1.1/32 o v6 route present");
4314 ai = fib_entry_get_adj(fei);
4316 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4317 "1.1.1.1/32 via ARP-adj");
4318 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4319 "1.1.1.1/32 ADJ-adj is link type v4");
4320 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4321 "1.1.1.1/32 ADJ-adj is NH proto v6");
4322 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4327 fib_prefix_t pfx_2001_c_s_64 = {
4329 .fp_proto = FIB_PROTOCOL_IP6,
4333 [0] = clib_host_to_net_u64(0x200100000000000c),
4334 [1] = clib_host_to_net_u64(0x0000000000000000),
4339 fib_table_entry_path_add(fib_index,
4342 FIB_ENTRY_FLAG_ATTACHED,
4345 tm->hw[0]->sw_if_index,
4349 FIB_ROUTE_PATH_FLAG_NONE);
4350 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4351 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4352 ai = fib_entry_get_adj(fei);
4354 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4355 "2001:0:0:c/64 attached resolves via glean");
4357 fib_table_entry_path_remove(fib_index,
4362 tm->hw[0]->sw_if_index,
4365 FIB_ROUTE_PATH_FLAG_NONE);
4366 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4367 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4370 * Shutdown the interface on which we have a connected and through
4371 * which the routes are reachable.
4372 * This will result in the connected, adj-fibs, and routes linking to drop
4373 * The local/for-us prefix continues to receive.
4375 clib_error_t * error;
4377 error = vnet_sw_interface_set_flags(vnet_get_main(),
4378 tm->hw[0]->sw_if_index,
4379 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4380 FIB_TEST((NULL == error), "Interface shutdown OK");
4382 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4383 dpo = fib_entry_contribute_ip_forwarding(fei);
4384 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4385 "2001::b/64 resolves via drop");
4387 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4388 dpo = fib_entry_contribute_ip_forwarding(fei);
4389 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4390 "2001::a/64 resolves via drop");
4391 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4392 dpo = fib_entry_contribute_ip_forwarding(fei);
4393 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4394 "2001:0:0:1::3/64 resolves via drop");
4395 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4396 dpo = fib_entry_contribute_ip_forwarding(fei);
4397 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4398 "2001:0:0:1::2/64 resolves via drop");
4399 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4400 dpo = fib_entry_contribute_ip_forwarding(fei);
4401 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4402 "2001:0:0:1::1/128 not drop");
4403 local_pfx.fp_len = 64;
4404 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
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/64 resolves via drop");
4412 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4413 fib_path_list_db_size());
4414 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4415 fib_path_list_pool_size());
4416 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4417 fib_entry_pool_size());
4420 * shutdown one of the other interfaces, then add a connected.
4421 * and swap one of the routes to it.
4423 error = vnet_sw_interface_set_flags(vnet_get_main(),
4424 tm->hw[1]->sw_if_index,
4425 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4426 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4428 fib_prefix_t connected_pfx = {
4430 .fp_proto = FIB_PROTOCOL_IP6,
4433 /* 2001:0:0:2::1/64 */
4435 [0] = clib_host_to_net_u64(0x2001000000000002),
4436 [1] = clib_host_to_net_u64(0x0000000000000001),
4441 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4442 FIB_SOURCE_INTERFACE,
4443 (FIB_ENTRY_FLAG_CONNECTED |
4444 FIB_ENTRY_FLAG_ATTACHED),
4447 tm->hw[1]->sw_if_index,
4451 FIB_ROUTE_PATH_FLAG_NONE);
4452 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4453 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4454 dpo = fib_entry_contribute_ip_forwarding(fei);
4455 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4456 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4457 "2001:0:0:2/64 not resolves via drop");
4459 connected_pfx.fp_len = 128;
4460 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4461 FIB_SOURCE_INTERFACE,
4462 (FIB_ENTRY_FLAG_CONNECTED |
4463 FIB_ENTRY_FLAG_LOCAL),
4466 tm->hw[0]->sw_if_index,
4467 ~0, // invalid fib index
4470 FIB_ROUTE_PATH_FLAG_NONE);
4471 fei = fib_table_lookup(fib_index, &connected_pfx);
4473 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4474 dpo = fib_entry_contribute_ip_forwarding(fei);
4475 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4476 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4477 "local interface adj is local");
4478 rd = receive_dpo_get(dpo->dpoi_index);
4479 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4481 "local interface adj is receive ok");
4484 * +2 entries, +2 unshared path-lists
4486 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4487 fib_path_list_db_size());
4488 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4489 fib_path_list_pool_size());
4490 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4491 fib_entry_pool_size());
4495 * bring the interface back up. we expected the routes to return
4496 * to normal forwarding.
4498 error = vnet_sw_interface_set_flags(vnet_get_main(),
4499 tm->hw[0]->sw_if_index,
4500 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4501 FIB_TEST((NULL == error), "Interface bring-up OK");
4502 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4503 ai = fib_entry_get_adj(fei);
4504 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4505 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4506 ai = fib_entry_get_adj(fei);
4507 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4508 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4509 ai = fib_entry_get_adj(fei);
4510 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4511 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4512 ai = fib_entry_get_adj(fei);
4513 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4514 local_pfx.fp_len = 64;
4515 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4516 ai = fib_entry_get_adj(fei);
4518 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4519 "attached interface adj is glean");
4522 * Same test as above, but this time the HW interface goes down
4524 error = vnet_hw_interface_set_flags(vnet_get_main(),
4525 tm->hw_if_indicies[0],
4526 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4527 FIB_TEST((NULL == error), "Interface shutdown OK");
4529 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4530 dpo = fib_entry_contribute_ip_forwarding(fei);
4531 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4532 "2001::b/64 resolves via drop");
4533 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4534 dpo = fib_entry_contribute_ip_forwarding(fei);
4535 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4536 "2001::a/64 resolves via drop");
4537 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4538 dpo = fib_entry_contribute_ip_forwarding(fei);
4539 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4540 "2001:0:0:1::3/128 resolves via drop");
4541 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4542 dpo = fib_entry_contribute_ip_forwarding(fei);
4543 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4544 "2001:0:0:1::2/128 resolves via drop");
4545 local_pfx.fp_len = 128;
4546 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4547 dpo = fib_entry_contribute_ip_forwarding(fei);
4548 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4549 "2001:0:0:1::1/128 not drop");
4550 local_pfx.fp_len = 64;
4551 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4552 dpo = fib_entry_contribute_ip_forwarding(fei);
4553 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4554 "2001:0:0:1/64 resolves via drop");
4556 error = vnet_hw_interface_set_flags(vnet_get_main(),
4557 tm->hw_if_indicies[0],
4558 VNET_HW_INTERFACE_FLAG_LINK_UP);
4559 FIB_TEST((NULL == error), "Interface bring-up OK");
4560 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4561 ai = fib_entry_get_adj(fei);
4562 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4563 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4564 ai = fib_entry_get_adj(fei);
4565 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4566 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4567 ai = fib_entry_get_adj(fei);
4568 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4569 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4570 ai = fib_entry_get_adj(fei);
4571 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4572 local_pfx.fp_len = 64;
4573 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4574 ai = fib_entry_get_adj(fei);
4576 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4577 "attached interface adj is glean");
4580 * Delete the interface that the routes reolve through.
4581 * Again no routes are removed. They all point to drop.
4583 * This is considered an error case. The control plane should
4584 * not remove interfaces through which routes resolve, but
4585 * such things can happen. ALL affected routes will drop.
4587 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4589 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4590 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4591 "2001::b/64 resolves via drop");
4592 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4593 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4594 "2001::b/64 resolves via drop");
4595 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4596 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4597 "2001:0:0:1::3/64 resolves via drop");
4598 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4599 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4600 "2001:0:0:1::2/64 resolves via drop");
4601 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4602 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4603 "2001:0:0:1::1/128 is drop");
4604 local_pfx.fp_len = 64;
4605 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4606 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4607 "2001:0:0:1/64 resolves via drop");
4612 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4613 fib_path_list_db_size());
4614 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4615 fib_path_list_pool_size());
4616 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4617 fib_entry_pool_size());
4620 * Add the interface back. routes stay unresolved.
4622 error = ethernet_register_interface(vnet_get_main(),
4623 test_interface_device_class.index,
4626 &tm->hw_if_indicies[0],
4627 /* flag change */ 0);
4629 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4630 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4631 "2001::b/64 resolves via drop");
4632 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4633 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4634 "2001::b/64 resolves via drop");
4635 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4636 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4637 "2001:0:0:1::3/64 resolves via drop");
4638 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4639 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4640 "2001:0:0:1::2/64 resolves via drop");
4641 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4642 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4643 "2001:0:0:1::1/128 is drop");
4644 local_pfx.fp_len = 64;
4645 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4646 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4647 "2001:0:0:1/64 resolves via drop");
4650 * CLEANUP ALL the routes
4652 fib_table_entry_delete(fib_index,
4655 fib_table_entry_delete(fib_index,
4658 fib_table_entry_delete(fib_index,
4661 fib_table_entry_delete(fib_index,
4662 &pfx_2001_1_3_s_128,
4664 fib_table_entry_delete(fib_index,
4665 &pfx_2001_1_2_s_128,
4667 local_pfx.fp_len = 64;
4668 fib_table_entry_delete(fib_index, &local_pfx,
4669 FIB_SOURCE_INTERFACE);
4670 local_pfx.fp_len = 128;
4671 fib_table_entry_special_remove(fib_index, &local_pfx,
4672 FIB_SOURCE_INTERFACE);
4673 connected_pfx.fp_len = 64;
4674 fib_table_entry_delete(fib_index, &connected_pfx,
4675 FIB_SOURCE_INTERFACE);
4676 connected_pfx.fp_len = 128;
4677 fib_table_entry_special_remove(fib_index, &connected_pfx,
4678 FIB_SOURCE_INTERFACE);
4680 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4681 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4682 "2001::a/64 removed");
4683 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4684 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4685 "2001::b/64 removed");
4686 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4687 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4688 "2001:0:0:1::3/128 removed");
4689 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4690 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4691 "2001:0:0:1::3/128 removed");
4692 local_pfx.fp_len = 64;
4693 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4694 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4695 "2001:0:0:1/64 removed");
4696 local_pfx.fp_len = 128;
4697 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4698 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4699 "2001:0:0:1::1/128 removed");
4700 connected_pfx.fp_len = 64;
4701 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4702 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4703 "2001:0:0:2/64 removed");
4704 connected_pfx.fp_len = 128;
4705 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4706 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4707 "2001:0:0:2::1/128 removed");
4710 * -8 entries. -7 path-lists (1 was shared).
4712 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4713 fib_path_list_db_size());
4714 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
4715 fib_path_list_pool_size());
4716 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4717 fib_entry_pool_size());
4720 * now remove the VRF
4722 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4724 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4725 fib_path_list_db_size());
4726 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
4727 fib_path_list_pool_size());
4728 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
4729 fib_entry_pool_size());
4735 * return the interfaces to up state
4737 error = vnet_sw_interface_set_flags(vnet_get_main(),
4738 tm->hw[0]->sw_if_index,
4739 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4740 error = vnet_sw_interface_set_flags(vnet_get_main(),
4741 tm->hw[1]->sw_if_index,
4742 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4744 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4751 * Test Attached Exports
4756 const dpo_id_t *dpo, *dpo_drop;
4757 const u32 fib_index = 0;
4758 fib_node_index_t fei;
4765 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4769 * add interface routes. We'll assume this works. It's more rigorously
4772 fib_prefix_t local_pfx = {
4774 .fp_proto = FIB_PROTOCOL_IP4,
4778 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4783 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4784 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4786 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4788 fib_table_entry_update_one_path(fib_index, &local_pfx,
4789 FIB_SOURCE_INTERFACE,
4790 (FIB_ENTRY_FLAG_CONNECTED |
4791 FIB_ENTRY_FLAG_ATTACHED),
4794 tm->hw[0]->sw_if_index,
4798 FIB_ROUTE_PATH_FLAG_NONE);
4799 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4800 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4801 "attached interface route present");
4803 local_pfx.fp_len = 32;
4804 fib_table_entry_update_one_path(fib_index, &local_pfx,
4805 FIB_SOURCE_INTERFACE,
4806 (FIB_ENTRY_FLAG_CONNECTED |
4807 FIB_ENTRY_FLAG_LOCAL),
4810 tm->hw[0]->sw_if_index,
4811 ~0, // invalid fib index
4814 FIB_ROUTE_PATH_FLAG_NONE);
4815 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4817 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4818 "local interface route present");
4821 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4823 fib_prefix_t pfx_10_10_10_1_s_32 = {
4825 .fp_proto = FIB_PROTOCOL_IP4,
4828 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4831 fib_node_index_t ai;
4833 fib_table_entry_update_one_path(fib_index,
4834 &pfx_10_10_10_1_s_32,
4836 FIB_ENTRY_FLAG_ATTACHED,
4838 &pfx_10_10_10_1_s_32.fp_addr,
4839 tm->hw[0]->sw_if_index,
4840 ~0, // invalid fib index
4843 FIB_ROUTE_PATH_FLAG_NONE);
4845 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4846 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4847 ai = fib_entry_get_adj(fei);
4850 * create another FIB table into which routes will be imported
4852 u32 import_fib_index1;
4854 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4857 * Add an attached route in the import FIB
4859 local_pfx.fp_len = 24;
4860 fib_table_entry_update_one_path(import_fib_index1,
4863 FIB_ENTRY_FLAG_NONE,
4866 tm->hw[0]->sw_if_index,
4867 ~0, // invalid fib index
4870 FIB_ROUTE_PATH_FLAG_NONE);
4871 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4872 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4875 * check for the presence of the adj-fibs in the import table
4877 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4878 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4879 FIB_TEST((ai == fib_entry_get_adj(fei)),
4880 "adj-fib1 Import uses same adj as export");
4883 * check for the presence of the local in the import table
4885 local_pfx.fp_len = 32;
4886 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4887 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4890 * Add another adj-fin in the export table. Expect this
4891 * to get magically exported;
4893 fib_prefix_t pfx_10_10_10_2_s_32 = {
4895 .fp_proto = FIB_PROTOCOL_IP4,
4898 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4902 fib_table_entry_update_one_path(fib_index,
4903 &pfx_10_10_10_2_s_32,
4905 FIB_ENTRY_FLAG_ATTACHED,
4907 &pfx_10_10_10_2_s_32.fp_addr,
4908 tm->hw[0]->sw_if_index,
4909 ~0, // invalid fib index
4912 FIB_ROUTE_PATH_FLAG_NONE);
4913 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4914 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4915 ai = fib_entry_get_adj(fei);
4917 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4918 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4919 FIB_TEST((ai == fib_entry_get_adj(fei)),
4920 "Import uses same adj as export");
4921 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
4922 "ADJ-fib2 imported flags %d",
4923 fib_entry_get_flags(fei));
4926 * create a 2nd FIB table into which routes will be imported
4928 u32 import_fib_index2;
4930 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4933 * Add an attached route in the import FIB
4935 local_pfx.fp_len = 24;
4936 fib_table_entry_update_one_path(import_fib_index2,
4939 FIB_ENTRY_FLAG_NONE,
4942 tm->hw[0]->sw_if_index,
4943 ~0, // invalid fib index
4946 FIB_ROUTE_PATH_FLAG_NONE);
4947 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4948 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4951 * check for the presence of all the adj-fibs and local in the import table
4953 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4954 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4955 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4956 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4957 local_pfx.fp_len = 32;
4958 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4959 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4962 * add a 3rd adj-fib. expect it to be exported to both tables.
4964 fib_prefix_t pfx_10_10_10_3_s_32 = {
4966 .fp_proto = FIB_PROTOCOL_IP4,
4969 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4973 fib_table_entry_update_one_path(fib_index,
4974 &pfx_10_10_10_3_s_32,
4976 FIB_ENTRY_FLAG_ATTACHED,
4978 &pfx_10_10_10_3_s_32.fp_addr,
4979 tm->hw[0]->sw_if_index,
4980 ~0, // invalid fib index
4983 FIB_ROUTE_PATH_FLAG_NONE);
4984 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4985 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4986 ai = fib_entry_get_adj(fei);
4988 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4989 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4990 FIB_TEST((ai == fib_entry_get_adj(fei)),
4991 "Import uses same adj as export");
4992 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4993 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4994 FIB_TEST((ai == fib_entry_get_adj(fei)),
4995 "Import uses same adj as export");
4998 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5000 fib_table_entry_delete(fib_index,
5001 &pfx_10_10_10_3_s_32,
5004 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5005 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5007 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5008 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5010 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5011 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5014 * remove the attached route from the 2nd FIB. expect the imported
5015 * entires to be removed
5017 local_pfx.fp_len = 24;
5018 fib_table_entry_delete(import_fib_index2,
5021 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5022 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5024 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5025 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5026 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5027 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5028 local_pfx.fp_len = 32;
5029 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5030 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5032 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5033 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5034 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5035 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5036 local_pfx.fp_len = 32;
5037 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5038 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5041 * modify the route in FIB1 so it is no longer attached. expect the imported
5042 * entires to be removed
5044 local_pfx.fp_len = 24;
5045 fib_table_entry_update_one_path(import_fib_index1,
5048 FIB_ENTRY_FLAG_NONE,
5050 &pfx_10_10_10_2_s_32.fp_addr,
5051 tm->hw[0]->sw_if_index,
5052 ~0, // invalid fib index
5055 FIB_ROUTE_PATH_FLAG_NONE);
5056 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5057 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5058 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5059 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5060 local_pfx.fp_len = 32;
5061 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5062 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5065 * modify it back to attached. expect the adj-fibs back
5067 local_pfx.fp_len = 24;
5068 fib_table_entry_update_one_path(import_fib_index1,
5071 FIB_ENTRY_FLAG_NONE,
5074 tm->hw[0]->sw_if_index,
5075 ~0, // invalid fib index
5078 FIB_ROUTE_PATH_FLAG_NONE);
5079 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5080 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5081 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5082 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5083 local_pfx.fp_len = 32;
5084 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5085 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5088 * add a covering attached next-hop for the interface address, so we have
5089 * a valid adj to find when we check the forwarding tables
5091 fib_prefix_t pfx_10_0_0_0_s_8 = {
5093 .fp_proto = FIB_PROTOCOL_IP4,
5096 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5100 fei = fib_table_entry_update_one_path(fib_index,
5103 FIB_ENTRY_FLAG_NONE,
5105 &pfx_10_10_10_3_s_32.fp_addr,
5106 tm->hw[0]->sw_if_index,
5107 ~0, // invalid fib index
5110 FIB_ROUTE_PATH_FLAG_NONE);
5111 dpo = fib_entry_contribute_ip_forwarding(fei);
5114 * remove the route in the export fib. expect the adj-fibs to be removed
5116 local_pfx.fp_len = 24;
5117 fib_table_entry_delete(fib_index,
5119 FIB_SOURCE_INTERFACE);
5121 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5122 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5123 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5124 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5125 local_pfx.fp_len = 32;
5126 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5127 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5130 * the adj-fibs in the export VRF are present in the FIB table,
5131 * but not installed in forwarding, since they have no attached cover.
5132 * Consequently a lookup in the MTRIE gives the adj for the covering
5135 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5136 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5139 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5140 FIB_TEST(lbi == dpo->dpoi_index,
5141 "10.10.10.1 forwards on \n%U not \n%U",
5142 format_load_balance, lbi, 0,
5143 format_dpo_id, dpo, 0);
5144 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5145 FIB_TEST(lbi == dpo->dpoi_index,
5146 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5147 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5148 FIB_TEST(lbi == dpo->dpoi_index,
5149 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5152 * add the export prefix back, but not as attached.
5153 * No adj-fibs in export nor import tables
5155 local_pfx.fp_len = 24;
5156 fei = fib_table_entry_update_one_path(fib_index,
5159 FIB_ENTRY_FLAG_NONE,
5161 &pfx_10_10_10_1_s_32.fp_addr,
5162 tm->hw[0]->sw_if_index,
5163 ~0, // invalid fib index
5166 FIB_ROUTE_PATH_FLAG_NONE);
5167 dpo = fib_entry_contribute_ip_forwarding(fei);
5169 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5170 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5171 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5172 FIB_TEST(lbi == dpo->dpoi_index,
5173 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5174 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5175 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5176 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5177 FIB_TEST(lbi == dpo->dpoi_index,
5178 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5180 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5181 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5182 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5183 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5184 local_pfx.fp_len = 32;
5185 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5186 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5189 * modify the export prefix so it is attached. expect all covereds to return
5191 local_pfx.fp_len = 24;
5192 fib_table_entry_update_one_path(fib_index,
5195 FIB_ENTRY_FLAG_NONE,
5198 tm->hw[0]->sw_if_index,
5199 ~0, // invalid fib index
5202 FIB_ROUTE_PATH_FLAG_NONE);
5204 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5205 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5206 dpo = fib_entry_contribute_ip_forwarding(fei);
5207 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5208 "Adj-fib1 is not drop in export");
5209 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5210 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5211 local_pfx.fp_len = 32;
5212 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5213 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5214 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5215 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5216 dpo = fib_entry_contribute_ip_forwarding(fei);
5217 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5218 "Adj-fib1 is not drop in export");
5219 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5220 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5221 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5222 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5223 local_pfx.fp_len = 32;
5224 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5225 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5228 * modify the export prefix so connected. no change.
5230 local_pfx.fp_len = 24;
5231 fib_table_entry_update_one_path(fib_index, &local_pfx,
5232 FIB_SOURCE_INTERFACE,
5233 (FIB_ENTRY_FLAG_CONNECTED |
5234 FIB_ENTRY_FLAG_ATTACHED),
5237 tm->hw[0]->sw_if_index,
5241 FIB_ROUTE_PATH_FLAG_NONE);
5243 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5244 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5245 dpo = fib_entry_contribute_ip_forwarding(fei);
5246 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5247 "Adj-fib1 is not drop in export");
5248 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5249 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5250 local_pfx.fp_len = 32;
5251 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5252 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5253 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5254 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5255 dpo = fib_entry_contribute_ip_forwarding(fei);
5256 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5257 "Adj-fib1 is not drop in export");
5258 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5259 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5260 local_pfx.fp_len = 32;
5261 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5262 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5267 fib_table_entry_delete(fib_index,
5270 fib_table_entry_delete(fib_index,
5271 &pfx_10_10_10_1_s_32,
5273 fib_table_entry_delete(fib_index,
5274 &pfx_10_10_10_2_s_32,
5276 local_pfx.fp_len = 32;
5277 fib_table_entry_delete(fib_index,
5279 FIB_SOURCE_INTERFACE);
5280 local_pfx.fp_len = 24;
5281 fib_table_entry_delete(fib_index,
5284 fib_table_entry_delete(fib_index,
5286 FIB_SOURCE_INTERFACE);
5287 local_pfx.fp_len = 24;
5288 fib_table_entry_delete(import_fib_index1,
5292 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5293 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5295 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5303 * Test the recursive route route handling for GRE tunnels
5306 fib_test_label (void)
5308 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;
5309 const u32 fib_index = 0;
5314 lb_count = pool_elts(load_balance_pool);
5319 * add interface routes. We'll assume this works. It's more rigorously
5322 fib_prefix_t local0_pfx = {
5324 .fp_proto = FIB_PROTOCOL_IP4,
5328 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5333 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5336 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5337 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5339 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5340 FIB_SOURCE_INTERFACE,
5341 (FIB_ENTRY_FLAG_CONNECTED |
5342 FIB_ENTRY_FLAG_ATTACHED),
5345 tm->hw[0]->sw_if_index,
5349 FIB_ROUTE_PATH_FLAG_NONE);
5350 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5351 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5352 "attached interface route present");
5354 local0_pfx.fp_len = 32;
5355 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5356 FIB_SOURCE_INTERFACE,
5357 (FIB_ENTRY_FLAG_CONNECTED |
5358 FIB_ENTRY_FLAG_LOCAL),
5361 tm->hw[0]->sw_if_index,
5362 ~0, // invalid fib index
5365 FIB_ROUTE_PATH_FLAG_NONE);
5366 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5368 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5369 "local interface route present");
5371 fib_prefix_t local1_pfx = {
5373 .fp_proto = FIB_PROTOCOL_IP4,
5377 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5382 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5383 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5385 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5386 FIB_SOURCE_INTERFACE,
5387 (FIB_ENTRY_FLAG_CONNECTED |
5388 FIB_ENTRY_FLAG_ATTACHED),
5391 tm->hw[1]->sw_if_index,
5395 FIB_ROUTE_PATH_FLAG_NONE);
5396 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5397 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5398 "attached interface route present");
5400 local1_pfx.fp_len = 32;
5401 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5402 FIB_SOURCE_INTERFACE,
5403 (FIB_ENTRY_FLAG_CONNECTED |
5404 FIB_ENTRY_FLAG_LOCAL),
5407 tm->hw[1]->sw_if_index,
5408 ~0, // invalid fib index
5411 FIB_ROUTE_PATH_FLAG_NONE);
5412 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5414 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5415 "local interface route present");
5417 ip46_address_t nh_10_10_10_1 = {
5419 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5422 ip46_address_t nh_10_10_11_1 = {
5424 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5427 ip46_address_t nh_10_10_11_2 = {
5429 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5433 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5436 tm->hw[1]->sw_if_index);
5437 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5440 tm->hw[1]->sw_if_index);
5441 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5444 tm->hw[0]->sw_if_index);
5445 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5448 tm->hw[1]->sw_if_index);
5449 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5452 tm->hw[1]->sw_if_index);
5455 * Add an etry with one path with a real out-going label
5457 fib_prefix_t pfx_1_1_1_1_s_32 = {
5459 .fp_proto = FIB_PROTOCOL_IP4,
5461 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5464 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5465 .type = FT_LB_LABEL_O_ADJ,
5467 .adj = ai_mpls_10_10_10_1,
5472 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5473 .type = FT_LB_LABEL_O_ADJ,
5475 .adj = ai_mpls_10_10_10_1,
5477 .eos = MPLS_NON_EOS,
5480 mpls_label_t *l99 = NULL;
5483 fib_table_entry_update_one_path(fib_index,
5486 FIB_ENTRY_FLAG_NONE,
5489 tm->hw[0]->sw_if_index,
5490 ~0, // invalid fib index
5493 FIB_ROUTE_PATH_FLAG_NONE);
5495 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5496 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5498 FIB_TEST(fib_test_validate_entry(fei,
5499 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5501 &l99_eos_o_10_10_10_1),
5502 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5505 * add a path with an implicit NULL label
5507 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5510 .adj = ai_v4_10_10_11_1,
5513 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5516 .adj = ai_mpls_10_10_11_1,
5519 mpls_label_t *l_imp_null = NULL;
5520 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5522 fei = fib_table_entry_path_add(fib_index,
5525 FIB_ENTRY_FLAG_NONE,
5528 tm->hw[1]->sw_if_index,
5529 ~0, // invalid fib index
5532 FIB_ROUTE_PATH_FLAG_NONE);
5534 FIB_TEST(fib_test_validate_entry(fei,
5535 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5537 &l99_eos_o_10_10_10_1,
5539 "1.1.1.1/32 LB 2 buckets via: "
5540 "label 99 over 10.10.10.1, "
5541 "adj over 10.10.11.1");
5544 * assign the route a local label
5546 fib_table_entry_local_label_add(fib_index,
5550 fib_prefix_t pfx_24001_eos = {
5551 .fp_proto = FIB_PROTOCOL_MPLS,
5555 fib_prefix_t pfx_24001_neos = {
5556 .fp_proto = FIB_PROTOCOL_MPLS,
5558 .fp_eos = MPLS_NON_EOS,
5562 * The EOS entry should link to both the paths,
5563 * and use an ip adj for the imp-null
5564 * The NON-EOS entry should link to both the paths,
5565 * and use an mpls adj for the imp-null
5567 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5569 FIB_TEST(fib_test_validate_entry(fei,
5570 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5572 &l99_eos_o_10_10_10_1,
5574 "24001/eos LB 2 buckets via: "
5575 "label 99 over 10.10.10.1, "
5576 "adj over 10.10.11.1");
5579 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5581 FIB_TEST(fib_test_validate_entry(fei,
5582 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5584 &l99_neos_o_10_10_10_1,
5585 &a_mpls_o_10_10_11_1),
5586 "24001/neos LB 1 bucket via: "
5587 "label 99 over 10.10.10.1 ",
5588 "mpls-adj via 10.10.11.1");
5591 * add an unlabelled path, this is excluded from the neos chains,
5593 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5596 .adj = ai_v4_10_10_11_2,
5600 fei = fib_table_entry_path_add(fib_index,
5603 FIB_ENTRY_FLAG_NONE,
5606 tm->hw[1]->sw_if_index,
5607 ~0, // invalid fib index
5610 FIB_ROUTE_PATH_FLAG_NONE);
5612 FIB_TEST(fib_test_validate_entry(fei,
5613 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5614 16, // 3 choices spread over 16 buckets
5615 &l99_eos_o_10_10_10_1,
5616 &l99_eos_o_10_10_10_1,
5617 &l99_eos_o_10_10_10_1,
5618 &l99_eos_o_10_10_10_1,
5619 &l99_eos_o_10_10_10_1,
5620 &l99_eos_o_10_10_10_1,
5631 "1.1.1.1/32 LB 16 buckets via: "
5632 "label 99 over 10.10.10.1, "
5633 "adj over 10.10.11.1",
5634 "adj over 10.10.11.2");
5637 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5639 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5640 fib_entry_contribute_forwarding(fei,
5641 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5645 * n-eos has only the 2 labelled paths
5647 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5650 FIB_TEST(fib_test_validate_entry(fei,
5651 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5653 &l99_neos_o_10_10_10_1,
5654 &a_mpls_o_10_10_11_1),
5655 "24001/neos LB 2 buckets via: "
5656 "label 99 over 10.10.10.1, "
5657 "adj-mpls over 10.10.11.2");
5660 * A labelled recursive
5662 fib_prefix_t pfx_2_2_2_2_s_32 = {
5664 .fp_proto = FIB_PROTOCOL_IP4,
5666 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5669 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5670 .type = FT_LB_LABEL_O_LB,
5672 .lb = non_eos_1_1_1_1.dpoi_index,
5677 mpls_label_t *l1600 = NULL;
5678 vec_add1(l1600, 1600);
5680 fib_table_entry_update_one_path(fib_index,
5683 FIB_ENTRY_FLAG_NONE,
5685 &pfx_1_1_1_1_s_32.fp_addr,
5690 FIB_ROUTE_PATH_FLAG_NONE);
5692 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5693 FIB_TEST(fib_test_validate_entry(fei,
5694 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5696 &l1600_eos_o_1_1_1_1),
5697 "2.2.2.2.2/32 LB 1 buckets via: "
5698 "label 1600 over 1.1.1.1");
5700 dpo_id_t dpo_44 = DPO_INVALID;
5703 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5704 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5706 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5707 "uRPF check for 2.2.2.2/32 on %d OK",
5708 tm->hw[0]->sw_if_index);
5709 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5710 "uRPF check for 2.2.2.2/32 on %d OK",
5711 tm->hw[1]->sw_if_index);
5712 FIB_TEST(!fib_urpf_check(urpfi, 99),
5713 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5716 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5717 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5718 "Shared uRPF on IP and non-EOS chain");
5723 * we are holding a lock on the non-eos LB of the via-entry.
5724 * do a PIC-core failover by shutting the link of the via-entry.
5726 * shut down the link with the valid label
5728 vnet_sw_interface_set_flags(vnet_get_main(),
5729 tm->hw[0]->sw_if_index,
5732 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5733 FIB_TEST(fib_test_validate_entry(fei,
5734 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5738 "1.1.1.1/32 LB 2 buckets via: "
5739 "adj over 10.10.11.1, ",
5740 "adj-v4 over 10.10.11.2");
5742 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5744 FIB_TEST(fib_test_validate_entry(fei,
5745 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5749 "24001/eos LB 2 buckets via: "
5750 "adj over 10.10.11.1, ",
5751 "adj-v4 over 10.10.11.2");
5753 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5755 FIB_TEST(fib_test_validate_entry(fei,
5756 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5758 &a_mpls_o_10_10_11_1),
5759 "24001/neos LB 1 buckets via: "
5760 "adj-mpls over 10.10.11.2");
5763 * test that the pre-failover load-balance has been in-place
5766 dpo_id_t current = DPO_INVALID;
5767 fib_entry_contribute_forwarding(fei,
5768 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5771 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5773 "PIC-core LB inplace modified %U %U",
5774 format_dpo_id, &non_eos_1_1_1_1, 0,
5775 format_dpo_id, ¤t, 0);
5777 dpo_reset(&non_eos_1_1_1_1);
5778 dpo_reset(¤t);
5781 * no-shut the link with the valid label
5783 vnet_sw_interface_set_flags(vnet_get_main(),
5784 tm->hw[0]->sw_if_index,
5785 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5787 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5788 FIB_TEST(fib_test_validate_entry(fei,
5789 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5790 16, // 3 choices spread over 16 buckets
5791 &l99_eos_o_10_10_10_1,
5792 &l99_eos_o_10_10_10_1,
5793 &l99_eos_o_10_10_10_1,
5794 &l99_eos_o_10_10_10_1,
5795 &l99_eos_o_10_10_10_1,
5796 &l99_eos_o_10_10_10_1,
5807 "1.1.1.1/32 LB 16 buckets via: "
5808 "label 99 over 10.10.10.1, "
5809 "adj over 10.10.11.1",
5810 "adj-v4 over 10.10.11.2");
5813 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5815 FIB_TEST(fib_test_validate_entry(fei,
5816 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5817 16, // 3 choices spread over 16 buckets
5818 &l99_eos_o_10_10_10_1,
5819 &l99_eos_o_10_10_10_1,
5820 &l99_eos_o_10_10_10_1,
5821 &l99_eos_o_10_10_10_1,
5822 &l99_eos_o_10_10_10_1,
5823 &l99_eos_o_10_10_10_1,
5834 "24001/eos LB 16 buckets via: "
5835 "label 99 over 10.10.10.1, "
5836 "adj over 10.10.11.1",
5837 "adj-v4 over 10.10.11.2");
5839 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5841 FIB_TEST(fib_test_validate_entry(fei,
5842 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5844 &l99_neos_o_10_10_10_1,
5845 &a_mpls_o_10_10_11_1),
5846 "24001/neos LB 2 buckets via: "
5847 "label 99 over 10.10.10.1, "
5848 "adj-mpls over 10.10.11.2");
5851 * remove the first path with the valid label
5853 fib_table_entry_path_remove(fib_index,
5858 tm->hw[0]->sw_if_index,
5859 ~0, // invalid fib index
5861 FIB_ROUTE_PATH_FLAG_NONE);
5863 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5864 FIB_TEST(fib_test_validate_entry(fei,
5865 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5869 "1.1.1.1/32 LB 2 buckets via: "
5870 "adj over 10.10.11.1, "
5871 "adj-v4 over 10.10.11.2");
5873 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5875 FIB_TEST(fib_test_validate_entry(fei,
5876 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5880 "24001/eos LB 2 buckets via: "
5881 "adj over 10.10.11.1, "
5882 "adj-v4 over 10.10.11.2");
5884 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5887 FIB_TEST(fib_test_validate_entry(fei,
5888 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5890 &a_mpls_o_10_10_11_1),
5891 "24001/neos LB 1 buckets via: "
5892 "adj-mpls over 10.10.11.2");
5895 * remove the other path with a valid label
5897 fib_test_lb_bucket_t bucket_drop = {
5898 .type = FT_LB_SPECIAL,
5900 .adj = DPO_PROTO_IP4,
5904 fib_table_entry_path_remove(fib_index,
5909 tm->hw[1]->sw_if_index,
5910 ~0, // invalid fib index
5912 FIB_ROUTE_PATH_FLAG_NONE);
5914 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5915 FIB_TEST(fib_test_validate_entry(fei,
5916 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5919 "1.1.1.1/32 LB 1 buckets via: "
5920 "adj over 10.10.11.2");
5922 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5924 FIB_TEST(fib_test_validate_entry(fei,
5925 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5928 "24001/eos LB 1 buckets via: "
5929 "adj over 10.10.11.2");
5931 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5933 FIB_TEST(fib_test_validate_entry(fei,
5934 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5937 "24001/eos LB 1 buckets via: DROP");
5940 * add back the path with the valid label
5945 fib_table_entry_path_add(fib_index,
5948 FIB_ENTRY_FLAG_NONE,
5951 tm->hw[0]->sw_if_index,
5952 ~0, // invalid fib index
5955 FIB_ROUTE_PATH_FLAG_NONE);
5957 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5958 FIB_TEST(fib_test_validate_entry(fei,
5959 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5961 &l99_eos_o_10_10_10_1,
5963 "1.1.1.1/32 LB 2 buckets via: "
5964 "label 99 over 10.10.10.1, "
5965 "adj over 10.10.11.2");
5967 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5969 FIB_TEST(fib_test_validate_entry(fei,
5970 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5972 &l99_eos_o_10_10_10_1,
5974 "24001/eos LB 2 buckets via: "
5975 "label 99 over 10.10.10.1, "
5976 "adj over 10.10.11.2");
5978 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5980 FIB_TEST(fib_test_validate_entry(fei,
5981 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5983 &l99_neos_o_10_10_10_1),
5984 "24001/neos LB 1 buckets via: "
5985 "label 99 over 10.10.10.1");
5988 * change the local label
5990 fib_table_entry_local_label_add(fib_index,
5994 fib_prefix_t pfx_25005_eos = {
5995 .fp_proto = FIB_PROTOCOL_MPLS,
5999 fib_prefix_t pfx_25005_neos = {
6000 .fp_proto = FIB_PROTOCOL_MPLS,
6002 .fp_eos = MPLS_NON_EOS,
6005 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6006 fib_table_lookup(fib_index, &pfx_24001_eos)),
6007 "24001/eos removed after label change");
6008 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6009 fib_table_lookup(fib_index, &pfx_24001_neos)),
6010 "24001/eos removed after label change");
6012 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6014 FIB_TEST(fib_test_validate_entry(fei,
6015 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6017 &l99_eos_o_10_10_10_1,
6019 "25005/eos LB 2 buckets via: "
6020 "label 99 over 10.10.10.1, "
6021 "adj over 10.10.11.2");
6023 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6025 FIB_TEST(fib_test_validate_entry(fei,
6026 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6028 &l99_neos_o_10_10_10_1),
6029 "25005/neos LB 1 buckets via: "
6030 "label 99 over 10.10.10.1");
6033 * remove the local label.
6034 * the check that the MPLS entries are gone is done by the fact the
6035 * MPLS table is no longer present.
6037 fib_table_entry_local_label_remove(fib_index,
6041 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6042 FIB_TEST(fib_test_validate_entry(fei,
6043 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6045 &l99_eos_o_10_10_10_1,
6047 "24001/eos LB 2 buckets via: "
6048 "label 99 over 10.10.10.1, "
6049 "adj over 10.10.11.2");
6051 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6052 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6053 "No more MPLS FIB entries => table removed");
6056 * add another via-entry for the recursive
6058 fib_prefix_t pfx_1_1_1_2_s_32 = {
6060 .fp_proto = FIB_PROTOCOL_IP4,
6062 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6065 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6066 .type = FT_LB_LABEL_O_ADJ,
6068 .adj = ai_mpls_10_10_10_1,
6073 mpls_label_t *l101 = NULL;
6074 vec_add1(l101, 101);
6076 fei = fib_table_entry_update_one_path(fib_index,
6079 FIB_ENTRY_FLAG_NONE,
6082 tm->hw[0]->sw_if_index,
6083 ~0, // invalid fib index
6086 FIB_ROUTE_PATH_FLAG_NONE);
6088 FIB_TEST(fib_test_validate_entry(fei,
6089 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6091 &l101_eos_o_10_10_10_1),
6092 "1.1.1.2/32 LB 1 buckets via: "
6093 "label 101 over 10.10.10.1");
6095 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6096 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6098 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6100 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6102 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6105 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6106 .type = FT_LB_LABEL_O_LB,
6108 .lb = non_eos_1_1_1_2.dpoi_index,
6113 mpls_label_t *l1601 = NULL;
6114 vec_add1(l1601, 1601);
6116 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6118 fei = fib_table_entry_path_add(fib_index,
6121 FIB_ENTRY_FLAG_NONE,
6123 &pfx_1_1_1_2_s_32.fp_addr,
6128 FIB_ROUTE_PATH_FLAG_NONE);
6130 FIB_TEST(fib_test_validate_entry(fei,
6131 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6133 &l1600_eos_o_1_1_1_1,
6134 &l1601_eos_o_1_1_1_2),
6135 "2.2.2.2/32 LB 2 buckets via: "
6136 "label 1600 via 1.1,1.1, "
6137 "label 16001 via 1.1.1.2");
6140 * update the via-entry so it no longer has an imp-null path.
6141 * the LB for the recursive can use an imp-null
6144 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6146 fei = fib_table_entry_update_one_path(fib_index,
6149 FIB_ENTRY_FLAG_NONE,
6152 tm->hw[1]->sw_if_index,
6153 ~0, // invalid fib index
6156 FIB_ROUTE_PATH_FLAG_NONE);
6158 FIB_TEST(fib_test_validate_entry(fei,
6159 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6162 "1.1.1.2/32 LB 1 buckets via: "
6165 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6166 FIB_TEST(fib_test_validate_entry(fei,
6167 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6169 &l1600_eos_o_1_1_1_1,
6170 &l1601_eos_o_1_1_1_2),
6171 "2.2.2.2/32 LB 2 buckets via: "
6172 "label 1600 via 1.1,1.1, "
6173 "label 16001 via 1.1.1.2");
6176 * update the via-entry so it no longer has labelled paths.
6177 * the LB for the recursive should exclue this via form its LB
6179 fei = fib_table_entry_update_one_path(fib_index,
6182 FIB_ENTRY_FLAG_NONE,
6185 tm->hw[1]->sw_if_index,
6186 ~0, // invalid fib index
6189 FIB_ROUTE_PATH_FLAG_NONE);
6191 FIB_TEST(fib_test_validate_entry(fei,
6192 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6195 "1.1.1.2/32 LB 1 buckets via: "
6198 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6199 FIB_TEST(fib_test_validate_entry(fei,
6200 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6202 &l1600_eos_o_1_1_1_1),
6203 "2.2.2.2/32 LB 1 buckets via: "
6204 "label 1600 via 1.1,1.1");
6206 dpo_reset(&non_eos_1_1_1_1);
6207 dpo_reset(&non_eos_1_1_1_2);
6210 * Add a recursive with no out-labels. We expect to use the IP of the via
6212 fib_prefix_t pfx_2_2_2_3_s_32 = {
6214 .fp_proto = FIB_PROTOCOL_IP4,
6216 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6219 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6221 fib_table_entry_update_one_path(fib_index,
6224 FIB_ENTRY_FLAG_NONE,
6226 &pfx_1_1_1_1_s_32.fp_addr,
6231 FIB_ROUTE_PATH_FLAG_NONE);
6233 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6235 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6238 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6241 .lb = ip_1_1_1_1.dpoi_index,
6245 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6246 FIB_TEST(fib_test_validate_entry(fei,
6247 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6250 "2.2.2.2.3/32 LB 1 buckets via: "
6254 * Add a recursive with an imp-null out-label.
6255 * We expect to use the IP of the via
6257 fib_prefix_t pfx_2_2_2_4_s_32 = {
6259 .fp_proto = FIB_PROTOCOL_IP4,
6261 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6265 fib_table_entry_update_one_path(fib_index,
6268 FIB_ENTRY_FLAG_NONE,
6270 &pfx_1_1_1_1_s_32.fp_addr,
6275 FIB_ROUTE_PATH_FLAG_NONE);
6277 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6278 FIB_TEST(fib_test_validate_entry(fei,
6279 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6282 "2.2.2.2.4/32 LB 1 buckets via: "
6285 dpo_reset(&ip_1_1_1_1);
6288 * Create an entry with a deep label stack
6290 fib_prefix_t pfx_2_2_5_5_s_32 = {
6292 .fp_proto = FIB_PROTOCOL_IP4,
6294 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6297 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6298 .type = FT_LB_LABEL_STACK_O_ADJ,
6299 .label_stack_o_adj = {
6300 .adj = ai_mpls_10_10_11_1,
6301 .label_stack_size = 8,
6303 200, 201, 202, 203, 204, 205, 206, 207
6308 mpls_label_t *label_stack = NULL;
6309 vec_validate(label_stack, 7);
6310 for (ii = 0; ii < 8; ii++)
6312 label_stack[ii] = ii + 200;
6315 fei = fib_table_entry_update_one_path(fib_index,
6318 FIB_ENTRY_FLAG_NONE,
6321 tm->hw[1]->sw_if_index,
6322 ~0, // invalid fib index
6325 FIB_ROUTE_PATH_FLAG_NONE);
6327 FIB_TEST(fib_test_validate_entry(fei,
6328 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6330 &ls_eos_o_10_10_10_1),
6331 "2.2.5.5/32 LB 1 buckets via: "
6333 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6338 fib_table_entry_delete(fib_index,
6342 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6343 FIB_TEST(fib_test_validate_entry(fei,
6344 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6346 &l1600_eos_o_1_1_1_1),
6347 "2.2.2.2/32 LB 1 buckets via: "
6348 "label 1600 via 1.1,1.1");
6350 fib_table_entry_delete(fib_index,
6354 FIB_TEST(fib_test_validate_entry(fei,
6355 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6358 "2.2.2.2/32 LB 1 buckets via: DROP");
6360 fib_table_entry_delete(fib_index,
6363 fib_table_entry_delete(fib_index,
6366 fib_table_entry_delete(fib_index,
6370 adj_unlock(ai_mpls_10_10_10_1);
6371 adj_unlock(ai_mpls_10_10_11_2);
6372 adj_unlock(ai_v4_10_10_11_1);
6373 adj_unlock(ai_v4_10_10_11_2);
6374 adj_unlock(ai_mpls_10_10_11_1);
6376 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6379 local0_pfx.fp_len = 32;
6380 fib_table_entry_delete(fib_index,
6382 FIB_SOURCE_INTERFACE);
6383 local0_pfx.fp_len = 24;
6384 fib_table_entry_delete(fib_index,
6386 FIB_SOURCE_INTERFACE);
6387 local1_pfx.fp_len = 32;
6388 fib_table_entry_delete(fib_index,
6390 FIB_SOURCE_INTERFACE);
6391 local1_pfx.fp_len = 24;
6392 fib_table_entry_delete(fib_index,
6394 FIB_SOURCE_INTERFACE);
6397 * +1 for the drop LB in the MPLS tables.
6399 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6400 "Load-balance resources freed %d of %d",
6401 lb_count+1, pool_elts(load_balance_pool));
6406 #define N_TEST_CHILDREN 4
6407 #define PARENT_INDEX 0
6409 typedef struct fib_node_test_t_
6414 fib_node_back_walk_ctx_t *ctxs;
6418 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6420 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6422 #define FOR_EACH_TEST_CHILD(_tc) \
6423 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
6424 ii < N_TEST_CHILDREN+1; \
6425 ii++, (_tc) = &fib_test_nodes[ii])
6428 fib_test_child_get_node (fib_node_index_t index)
6430 return (&fib_test_nodes[index].node);
6433 static int fib_test_walk_spawns_walks;
6435 static fib_node_back_walk_rc_t
6436 fib_test_child_back_walk_notify (fib_node_t *node,
6437 fib_node_back_walk_ctx_t *ctx)
6439 fib_node_test_t *tc = (fib_node_test_t*) node;
6441 vec_add1(tc->ctxs, *ctx);
6443 if (1 == fib_test_walk_spawns_walks)
6444 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6445 if (2 == fib_test_walk_spawns_walks)
6446 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6447 FIB_WALK_PRIORITY_HIGH, ctx);
6449 return (FIB_NODE_BACK_WALK_CONTINUE);
6453 fib_test_child_last_lock_gone (fib_node_t *node)
6455 fib_node_test_t *tc = (fib_node_test_t *)node;
6461 * The FIB walk's graph node virtual function table
6463 static const fib_node_vft_t fib_test_child_vft = {
6464 .fnv_get = fib_test_child_get_node,
6465 .fnv_last_lock = fib_test_child_last_lock_gone,
6466 .fnv_back_walk = fib_test_child_back_walk_notify,
6470 * the function (that should have been static but isn't so I can do this)
6471 * that processes the walk from the async queue,
6473 f64 fib_walk_process_queues(vlib_main_t * vm,
6475 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6478 fib_test_walk (void)
6480 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6481 fib_node_test_t *tc;
6485 vm = vlib_get_main();
6486 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6489 * init a fake node on which we will add children
6491 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6492 FIB_NODE_TYPE_TEST);
6494 FOR_EACH_TEST_CHILD(tc)
6496 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6497 fib_node_lock(&tc->node);
6500 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6502 FIB_NODE_TYPE_TEST, ii);
6506 * enqueue a walk across the parents children.
6508 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6510 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6511 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6512 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6513 "Parent has %d children pre-walk",
6514 fib_node_list_get_size(PARENT()->fn_children));
6517 * give the walk a large amount of time so it gets to the end
6519 fib_walk_process_queues(vm, 1);
6521 FOR_EACH_TEST_CHILD(tc)
6523 FIB_TEST(1 == vec_len(tc->ctxs),
6524 "%d child visitsed %d times",
6525 ii, vec_len(tc->ctxs));
6528 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6529 "Queue is empty post walk");
6530 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6531 "Parent has %d children post walk",
6532 fib_node_list_get_size(PARENT()->fn_children));
6535 * walk again. should be no increase in the number of visits, since
6536 * the walk will have terminated.
6538 fib_walk_process_queues(vm, 1);
6540 FOR_EACH_TEST_CHILD(tc)
6542 FIB_TEST(0 == vec_len(tc->ctxs),
6543 "%d child visitsed %d times",
6544 ii, vec_len(tc->ctxs));
6548 * schedule a low and hig priority walk. expect the high to be performed
6550 * schedule the high prio walk first so that it is further from the head
6551 * of the dependency list. that way it won't merge with the low one.
6553 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6554 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6556 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6557 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6558 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6559 FIB_WALK_PRIORITY_LOW, &low_ctx);
6561 fib_walk_process_queues(vm, 1);
6563 FOR_EACH_TEST_CHILD(tc)
6565 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6566 "%d child visitsed by high prio walk", ii);
6567 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6568 "%d child visitsed by low prio walk", ii);
6571 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6572 "Queue is empty post prio walk");
6573 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6574 "Parent has %d children post prio walk",
6575 fib_node_list_get_size(PARENT()->fn_children));
6578 * schedule 2 walks of the same priority that can be megred.
6579 * expect that each child is thus visited only once.
6581 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6582 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6584 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6585 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6586 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6587 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6589 fib_walk_process_queues(vm, 1);
6591 FOR_EACH_TEST_CHILD(tc)
6593 FIB_TEST(1 == vec_len(tc->ctxs),
6594 "%d child visitsed %d times during merge walk",
6595 ii, vec_len(tc->ctxs));
6598 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6599 "Queue is empty post merge walk");
6600 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6601 "Parent has %d children post merge walk",
6602 fib_node_list_get_size(PARENT()->fn_children));
6605 * schedule 2 walks of the same priority that cannot be megred.
6606 * expect that each child is thus visited twice and in the order
6607 * in which the walks were scheduled.
6609 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6610 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6612 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6613 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6614 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6615 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6617 fib_walk_process_queues(vm, 1);
6619 FOR_EACH_TEST_CHILD(tc)
6621 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6622 "%d child visitsed by high prio walk", ii);
6623 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6624 "%d child visitsed by low prio walk", ii);
6627 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6628 "Queue is empty post no-merge walk");
6629 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6630 "Parent has %d children post no-merge walk",
6631 fib_node_list_get_size(PARENT()->fn_children));
6634 * schedule a walk that makes one one child progress.
6635 * we do this by giving the queue draining process zero
6636 * time quanta. it's a do..while loop, so it does something.
6638 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6640 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6641 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6642 fib_walk_process_queues(vm, 0);
6644 FOR_EACH_TEST_CHILD(tc)
6646 if (ii == N_TEST_CHILDREN)
6648 FIB_TEST(1 == vec_len(tc->ctxs),
6649 "%d child visitsed %d times in zero quanta walk",
6650 ii, vec_len(tc->ctxs));
6654 FIB_TEST(0 == vec_len(tc->ctxs),
6655 "%d child visitsed %d times in 0 quanta walk",
6656 ii, vec_len(tc->ctxs));
6659 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6660 "Queue is not empty post zero quanta walk");
6661 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6662 "Parent has %d children post zero qunta walk",
6663 fib_node_list_get_size(PARENT()->fn_children));
6668 fib_walk_process_queues(vm, 0);
6670 FOR_EACH_TEST_CHILD(tc)
6672 if (ii >= N_TEST_CHILDREN-1)
6674 FIB_TEST(1 == vec_len(tc->ctxs),
6675 "%d child visitsed %d times in 2nd zero quanta walk",
6676 ii, vec_len(tc->ctxs));
6680 FIB_TEST(0 == vec_len(tc->ctxs),
6681 "%d child visitsed %d times in 2nd 0 quanta walk",
6682 ii, vec_len(tc->ctxs));
6685 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6686 "Queue is not empty post zero quanta walk");
6687 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6688 "Parent has %d children post zero qunta walk",
6689 fib_node_list_get_size(PARENT()->fn_children));
6692 * schedule another walk that will catch-up and merge.
6694 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6695 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6696 fib_walk_process_queues(vm, 1);
6698 FOR_EACH_TEST_CHILD(tc)
6700 if (ii >= N_TEST_CHILDREN-1)
6702 FIB_TEST(2 == vec_len(tc->ctxs),
6703 "%d child visitsed %d times in 2nd zero quanta merge walk",
6704 ii, vec_len(tc->ctxs));
6709 FIB_TEST(1 == vec_len(tc->ctxs),
6710 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6711 ii, vec_len(tc->ctxs));
6715 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6716 "Queue is not empty post 2nd zero quanta merge walk");
6717 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6718 "Parent has %d children post 2nd zero qunta merge walk",
6719 fib_node_list_get_size(PARENT()->fn_children));
6722 * park a async walk in the middle of the list, then have an sync walk catch
6723 * it. same expectations as async catches async.
6725 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6727 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6728 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6730 fib_walk_process_queues(vm, 0);
6731 fib_walk_process_queues(vm, 0);
6733 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6735 FOR_EACH_TEST_CHILD(tc)
6737 if (ii >= N_TEST_CHILDREN-1)
6739 FIB_TEST(2 == vec_len(tc->ctxs),
6740 "%d child visitsed %d times in sync catches async walk",
6741 ii, vec_len(tc->ctxs));
6746 FIB_TEST(1 == vec_len(tc->ctxs),
6747 "%d child visitsed %d times in sync catches async walk",
6748 ii, vec_len(tc->ctxs));
6752 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6753 "Queue is not empty post 2nd zero quanta merge walk");
6754 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6755 "Parent has %d children post 2nd zero qunta merge walk",
6756 fib_node_list_get_size(PARENT()->fn_children));
6759 * make the parent a child of one of its children, thus inducing a routing loop.
6761 fib_test_nodes[PARENT_INDEX].sibling =
6762 fib_node_child_add(FIB_NODE_TYPE_TEST,
6763 1, // the first child
6768 * execute a sync walk from the parent. each child visited spawns more sync
6769 * walks. we expect the walk to terminate.
6771 fib_test_walk_spawns_walks = 1;
6773 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6775 FOR_EACH_TEST_CHILD(tc)
6778 * child 1 - which is last in the list - has the loop.
6779 * the other children a re thus visitsed first. the we meet
6780 * child 1. we go round the loop again, visting the other children.
6781 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6786 FIB_TEST(1 == vec_len(tc->ctxs),
6787 "child %d visitsed %d times during looped sync walk",
6788 ii, vec_len(tc->ctxs));
6792 FIB_TEST(2 == vec_len(tc->ctxs),
6793 "child %d visitsed %d times during looped sync walk",
6794 ii, vec_len(tc->ctxs));
6798 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6799 "Parent has %d children post sync loop walk",
6800 fib_node_list_get_size(PARENT()->fn_children));
6803 * the walk doesn't reach the max depth because the infra knows that sync
6804 * meets sync implies a loop and bails early.
6806 FIB_TEST(high_ctx.fnbw_depth == 9,
6807 "Walk context depth %d post sync loop walk",
6808 high_ctx.fnbw_depth);
6811 * execute an async walk of the graph loop, with each child spawns sync walks
6813 high_ctx.fnbw_depth = 0;
6814 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6815 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6817 fib_walk_process_queues(vm, 1);
6819 FOR_EACH_TEST_CHILD(tc)
6822 * we don't really care how many times the children are visisted, as long as
6823 * it is more than once.
6825 FIB_TEST(1 <= vec_len(tc->ctxs),
6826 "child %d visitsed %d times during looped aync spawns sync walk",
6827 ii, vec_len(tc->ctxs));
6832 * execute an async walk of the graph loop, with each child spawns async walks
6834 fib_test_walk_spawns_walks = 2;
6835 high_ctx.fnbw_depth = 0;
6836 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6837 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6839 fib_walk_process_queues(vm, 1);
6841 FOR_EACH_TEST_CHILD(tc)
6844 * we don't really care how many times the children are visisted, as long as
6845 * it is more than once.
6847 FIB_TEST(1 <= vec_len(tc->ctxs),
6848 "child %d visitsed %d times during looped async spawns async walk",
6849 ii, vec_len(tc->ctxs));
6854 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6855 1, // the first child
6856 fib_test_nodes[PARENT_INDEX].sibling);
6861 FOR_EACH_TEST_CHILD(tc)
6863 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6865 fib_node_deinit(&tc->node);
6866 fib_node_unlock(&tc->node);
6868 fib_node_deinit(PARENT());
6871 * The parent will be destroyed when the last lock on it goes.
6872 * this test ensures all the walk objects are unlocking it.
6874 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6875 "Parent was destroyed");
6881 * declaration of the otherwise static callback functions
6883 void fib_bfd_notify (bfd_listen_event_e event,
6884 const bfd_session_t *session);
6885 void adj_bfd_notify (bfd_listen_event_e event,
6886 const bfd_session_t *session);
6889 * Test BFD session interaction with FIB
6894 fib_node_index_t fei;
6898 /* via 10.10.10.1 */
6899 ip46_address_t nh_10_10_10_1 = {
6900 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6902 /* via 10.10.10.2 */
6903 ip46_address_t nh_10_10_10_2 = {
6904 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
6906 /* via 10.10.10.10 */
6907 ip46_address_t nh_10_10_10_10 = {
6908 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6910 n_feis = fib_entry_pool_size();
6915 * add interface routes. we'll assume this works. it's tested elsewhere
6917 fib_prefix_t pfx_10_10_10_10_s_24 = {
6919 .fp_proto = FIB_PROTOCOL_IP4,
6920 .fp_addr = nh_10_10_10_10,
6923 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
6924 FIB_SOURCE_INTERFACE,
6925 (FIB_ENTRY_FLAG_CONNECTED |
6926 FIB_ENTRY_FLAG_ATTACHED),
6929 tm->hw[0]->sw_if_index,
6930 ~0, // invalid fib index
6933 FIB_ROUTE_PATH_FLAG_NONE);
6935 fib_prefix_t pfx_10_10_10_10_s_32 = {
6937 .fp_proto = FIB_PROTOCOL_IP4,
6938 .fp_addr = nh_10_10_10_10,
6940 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
6941 FIB_SOURCE_INTERFACE,
6942 (FIB_ENTRY_FLAG_CONNECTED |
6943 FIB_ENTRY_FLAG_LOCAL),
6946 tm->hw[0]->sw_if_index,
6947 ~0, // invalid fib index
6950 FIB_ROUTE_PATH_FLAG_NONE);
6953 * A BFD session via a neighbour we do not yet know
6955 bfd_session_t bfd_10_10_10_1 = {
6959 .peer_addr = nh_10_10_10_1,
6962 .hop_type = BFD_HOP_TYPE_MULTI,
6963 .local_state = BFD_STATE_init,
6966 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
6969 * A new entry will be created that forwards via the adj
6971 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6974 tm->hw[0]->sw_if_index);
6975 fib_prefix_t pfx_10_10_10_1_s_32 = {
6976 .fp_addr = nh_10_10_10_1,
6978 .fp_proto = FIB_PROTOCOL_IP4,
6980 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
6983 .adj = ai_10_10_10_1,
6987 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
6988 FIB_TEST(fib_test_validate_entry(fei,
6989 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6992 "BFD sourced %U via %U",
6993 format_fib_prefix, &pfx_10_10_10_1_s_32,
6994 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
6997 * Delete the BFD session. Expect the fib_entry to be removed
6999 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7001 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7002 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7003 "BFD sourced %U removed",
7004 format_fib_prefix, &pfx_10_10_10_1_s_32);
7007 * Add the BFD source back
7009 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7012 * source the entry via the ADJ fib
7014 fei = fib_table_entry_update_one_path(0,
7015 &pfx_10_10_10_1_s_32,
7017 FIB_ENTRY_FLAG_ATTACHED,
7020 tm->hw[0]->sw_if_index,
7021 ~0, // invalid fib index
7024 FIB_ROUTE_PATH_FLAG_NONE);
7027 * Delete the BFD session. Expect the fib_entry to remain
7029 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7031 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7032 FIB_TEST(fib_test_validate_entry(fei,
7033 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7036 "BFD sourced %U remains via %U",
7037 format_fib_prefix, &pfx_10_10_10_1_s_32,
7038 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7041 * Add the BFD source back
7043 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7046 * Create another ADJ FIB
7048 fib_prefix_t pfx_10_10_10_2_s_32 = {
7049 .fp_addr = nh_10_10_10_2,
7051 .fp_proto = FIB_PROTOCOL_IP4,
7053 fib_table_entry_update_one_path(0,
7054 &pfx_10_10_10_2_s_32,
7056 FIB_ENTRY_FLAG_ATTACHED,
7059 tm->hw[0]->sw_if_index,
7060 ~0, // invalid fib index
7063 FIB_ROUTE_PATH_FLAG_NONE);
7065 * A BFD session for the new ADJ FIB
7067 bfd_session_t bfd_10_10_10_2 = {
7071 .peer_addr = nh_10_10_10_2,
7074 .hop_type = BFD_HOP_TYPE_MULTI,
7075 .local_state = BFD_STATE_init,
7078 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7081 * remove the adj-fib source whilst the session is present
7084 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7085 fib_table_entry_update_one_path(0,
7086 &pfx_10_10_10_2_s_32,
7088 FIB_ENTRY_FLAG_ATTACHED,
7091 tm->hw[0]->sw_if_index,
7092 ~0, // invalid fib index
7095 FIB_ROUTE_PATH_FLAG_NONE);
7098 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7099 * bring one of the sessions UP, leave the other down
7101 bfd_10_10_10_1.local_state = BFD_STATE_up;
7102 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7103 bfd_10_10_10_2.local_state = BFD_STATE_down;
7104 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7107 * A recursive prefix via both of the ADJ FIBs
7109 fib_prefix_t pfx_200_0_0_0_s_24 = {
7110 .fp_proto = FIB_PROTOCOL_IP4,
7113 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7116 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7119 fib_entry_contribute_ip_forwarding(
7120 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7122 fib_entry_contribute_ip_forwarding(
7123 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7125 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7128 .lb = dpo_10_10_10_1->dpoi_index,
7131 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7134 .lb = dpo_10_10_10_2->dpoi_index,
7139 * A prefix via the adj-fib that is BFD down => DROP
7141 fei = fib_table_entry_path_add(0,
7142 &pfx_200_0_0_0_s_24,
7144 FIB_ENTRY_FLAG_NONE,
7148 0, // default fib index
7151 FIB_ROUTE_PATH_FLAG_NONE);
7152 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7153 "%U resolves via drop",
7154 format_fib_prefix, &pfx_200_0_0_0_s_24);
7157 * add a path via the UP BFD adj-fib.
7158 * we expect that the DOWN BFD ADJ FIB is not used.
7160 fei = fib_table_entry_path_add(0,
7161 &pfx_200_0_0_0_s_24,
7163 FIB_ENTRY_FLAG_NONE,
7167 0, // default fib index
7170 FIB_ROUTE_PATH_FLAG_NONE);
7172 FIB_TEST(fib_test_validate_entry(fei,
7173 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7176 "Recursive %U only UP BFD adj-fibs",
7177 format_fib_prefix, &pfx_200_0_0_0_s_24);
7180 * Send a BFD state change to UP - both sessions are now up
7181 * the recursive prefix should LB over both
7183 bfd_10_10_10_2.local_state = BFD_STATE_up;
7184 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7187 FIB_TEST(fib_test_validate_entry(fei,
7188 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7192 "Recursive %U via both UP BFD adj-fibs",
7193 format_fib_prefix, &pfx_200_0_0_0_s_24);
7196 * Send a BFD state change to DOWN
7197 * the recursive prefix should exclude the down
7199 bfd_10_10_10_2.local_state = BFD_STATE_down;
7200 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7203 FIB_TEST(fib_test_validate_entry(fei,
7204 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7207 "Recursive %U via only UP",
7208 format_fib_prefix, &pfx_200_0_0_0_s_24);
7211 * Delete the BFD session while it is in the DOWN state.
7212 * FIB should consider the entry's state as back up
7214 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
7216 FIB_TEST(fib_test_validate_entry(fei,
7217 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7221 "Recursive %U via both UP BFD adj-fibs post down session delete",
7222 format_fib_prefix, &pfx_200_0_0_0_s_24);
7225 * Delete the BFD other session while it is in the UP state.
7227 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7229 FIB_TEST(fib_test_validate_entry(fei,
7230 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7234 "Recursive %U via both UP BFD adj-fibs post up session delete",
7235 format_fib_prefix, &pfx_200_0_0_0_s_24);
7240 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
7241 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
7242 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7244 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
7245 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
7247 adj_unlock(ai_10_10_10_1);
7249 * test no-one left behind
7251 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7252 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7255 * Single-hop BFD tests
7257 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
7258 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
7260 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7262 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7265 tm->hw[0]->sw_if_index);
7267 * whilst the BFD session is not signalled, the adj is up
7269 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
7272 * bring the BFD session up
7274 bfd_10_10_10_1.local_state = BFD_STATE_up;
7275 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7276 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
7279 * bring the BFD session down
7281 bfd_10_10_10_1.local_state = BFD_STATE_down;
7282 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7283 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
7287 * add an attached next hop FIB entry via the down adj
7289 fib_prefix_t pfx_5_5_5_5_s_32 = {
7292 .as_u32 = clib_host_to_net_u32(0x05050505),
7296 .fp_proto = FIB_PROTOCOL_IP4,
7299 fei = fib_table_entry_path_add(0,
7302 FIB_ENTRY_FLAG_NONE,
7305 tm->hw[0]->sw_if_index,
7306 ~0, // invalid fib index
7309 FIB_ROUTE_PATH_FLAG_NONE);
7310 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7311 "%U resolves via drop",
7312 format_fib_prefix, &pfx_5_5_5_5_s_32);
7315 * Add a path via an ADJ that is up
7317 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7320 tm->hw[0]->sw_if_index);
7322 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
7325 .adj = ai_10_10_10_2,
7328 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
7330 fei = fib_table_entry_path_add(0,
7333 FIB_ENTRY_FLAG_NONE,
7336 tm->hw[0]->sw_if_index,
7337 ~0, // invalid fib index
7340 FIB_ROUTE_PATH_FLAG_NONE);
7342 FIB_TEST(fib_test_validate_entry(fei,
7343 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7346 "BFD sourced %U via %U",
7347 format_fib_prefix, &pfx_5_5_5_5_s_32,
7348 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
7351 * Bring up the down session - should now LB
7353 bfd_10_10_10_1.local_state = BFD_STATE_up;
7354 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7355 FIB_TEST(fib_test_validate_entry(fei,
7356 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7360 "BFD sourced %U via noth adjs",
7361 format_fib_prefix, &pfx_5_5_5_5_s_32);
7364 * remove the BFD session state from the adj
7366 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7371 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
7372 adj_unlock(ai_10_10_10_1);
7373 adj_unlock(ai_10_10_10_2);
7376 * test no-one left behind
7378 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7379 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7386 const mpls_label_t deag_label = 50;
7387 const u32 lfib_index = 0;
7388 const u32 fib_index = 0;
7389 dpo_id_t dpo = DPO_INVALID;
7390 const dpo_id_t *dpo1;
7391 fib_node_index_t lfe;
7395 adj_index_t ai_mpls_10_10_10_1;
7398 lb_count = pool_elts(load_balance_pool);
7400 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7404 * MPLS enable an interface so we get the MPLS table created
7406 mpls_sw_interface_enable_disable(&mpls_main,
7407 tm->hw[0]->sw_if_index,
7410 ip46_address_t nh_10_10_10_1 = {
7411 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7413 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7416 tm->hw[0]->sw_if_index);
7419 * Test the specials stack properly.
7421 fib_prefix_t exp_null_v6_pfx = {
7422 .fp_proto = FIB_PROTOCOL_MPLS,
7424 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7425 .fp_payload_proto = DPO_PROTO_IP6,
7427 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
7428 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
7430 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7431 format_mpls_eos_bit, MPLS_EOS);
7432 fib_entry_contribute_forwarding(lfe,
7433 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7435 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7436 lkd = lookup_dpo_get(dpo1->dpoi_index);
7438 FIB_TEST((fib_index == lkd->lkd_fib_index),
7439 "%U/%U is deag in %d %U",
7440 format_mpls_unicast_label, deag_label,
7441 format_mpls_eos_bit, MPLS_EOS,
7443 format_dpo_id, &dpo, 0);
7444 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7445 "%U/%U is dst deag",
7446 format_mpls_unicast_label, deag_label,
7447 format_mpls_eos_bit, MPLS_EOS);
7448 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
7449 "%U/%U is lookup in interface's table",
7450 format_mpls_unicast_label, deag_label,
7451 format_mpls_eos_bit, MPLS_EOS);
7452 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
7453 "%U/%U is %U dst deag",
7454 format_mpls_unicast_label, deag_label,
7455 format_mpls_eos_bit, MPLS_EOS,
7456 format_dpo_proto, lkd->lkd_proto);
7460 * A route deag route for EOS
7462 fib_prefix_t pfx = {
7463 .fp_proto = FIB_PROTOCOL_MPLS,
7465 .fp_label = deag_label,
7466 .fp_payload_proto = DPO_PROTO_IP4,
7468 lfe = fib_table_entry_path_add(lfib_index,
7471 FIB_ENTRY_FLAG_NONE,
7478 FIB_ROUTE_PATH_FLAG_NONE);
7480 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7482 format_mpls_unicast_label, deag_label,
7483 format_mpls_eos_bit, MPLS_EOS);
7485 fib_entry_contribute_forwarding(lfe,
7486 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7488 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7489 lkd = lookup_dpo_get(dpo1->dpoi_index);
7491 FIB_TEST((fib_index == lkd->lkd_fib_index),
7492 "%U/%U is deag in %d %U",
7493 format_mpls_unicast_label, deag_label,
7494 format_mpls_eos_bit, MPLS_EOS,
7496 format_dpo_id, &dpo, 0);
7497 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7498 "%U/%U is dst deag",
7499 format_mpls_unicast_label, deag_label,
7500 format_mpls_eos_bit, MPLS_EOS);
7501 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
7502 "%U/%U is %U dst deag",
7503 format_mpls_unicast_label, deag_label,
7504 format_mpls_eos_bit, MPLS_EOS,
7505 format_dpo_proto, lkd->lkd_proto);
7507 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7509 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7511 "%U/%U not present",
7512 format_mpls_unicast_label, deag_label,
7513 format_mpls_eos_bit, MPLS_EOS);
7516 * A route deag route for non-EOS
7518 pfx.fp_eos = MPLS_NON_EOS;
7519 lfe = fib_table_entry_path_add(lfib_index,
7522 FIB_ENTRY_FLAG_NONE,
7529 FIB_ROUTE_PATH_FLAG_NONE);
7531 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7533 format_mpls_unicast_label, deag_label,
7534 format_mpls_eos_bit, MPLS_NON_EOS);
7536 fib_entry_contribute_forwarding(lfe,
7537 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7539 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7540 lkd = lookup_dpo_get(dpo1->dpoi_index);
7542 FIB_TEST((fib_index == lkd->lkd_fib_index),
7543 "%U/%U is deag in %d %U",
7544 format_mpls_unicast_label, deag_label,
7545 format_mpls_eos_bit, MPLS_NON_EOS,
7547 format_dpo_id, &dpo, 0);
7548 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7549 "%U/%U is dst deag",
7550 format_mpls_unicast_label, deag_label,
7551 format_mpls_eos_bit, MPLS_NON_EOS);
7553 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
7554 "%U/%U is %U dst deag",
7555 format_mpls_unicast_label, deag_label,
7556 format_mpls_eos_bit, MPLS_NON_EOS,
7557 format_dpo_proto, lkd->lkd_proto);
7559 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7561 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7563 "%U/%U not present",
7564 format_mpls_unicast_label, deag_label,
7565 format_mpls_eos_bit, MPLS_EOS);
7572 fib_prefix_t pfx_1200 = {
7574 .fp_proto = FIB_PROTOCOL_MPLS,
7576 .fp_eos = MPLS_NON_EOS,
7578 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
7579 .type = FT_LB_LABEL_STACK_O_ADJ,
7580 .label_stack_o_adj = {
7581 .adj = ai_mpls_10_10_10_1,
7582 .label_stack_size = 4,
7586 .eos = MPLS_NON_EOS,
7589 dpo_id_t neos_1200 = DPO_INVALID;
7590 dpo_id_t ip_1200 = DPO_INVALID;
7591 mpls_label_t *l200 = NULL;
7592 vec_add1(l200, 200);
7593 vec_add1(l200, 300);
7594 vec_add1(l200, 400);
7595 vec_add1(l200, 500);
7597 lfe = fib_table_entry_update_one_path(fib_index,
7600 FIB_ENTRY_FLAG_NONE,
7603 tm->hw[0]->sw_if_index,
7604 ~0, // invalid fib index
7607 FIB_ROUTE_PATH_FLAG_NONE);
7609 FIB_TEST(fib_test_validate_entry(lfe,
7610 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7612 &neos_o_10_10_10_1),
7613 "1200/0 LB 1 buckets via: "
7617 * A recursive route via the MPLS x-connect
7619 fib_prefix_t pfx_2_2_2_3_s_32 = {
7621 .fp_proto = FIB_PROTOCOL_IP4,
7623 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7626 fib_route_path_t *rpaths = NULL, rpath = {
7627 .frp_proto = FIB_PROTOCOL_MPLS,
7628 .frp_local_label = 1200,
7629 .frp_eos = MPLS_NON_EOS,
7630 .frp_sw_if_index = ~0, // recurive
7631 .frp_fib_index = 0, // Default MPLS fib
7633 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
7634 .frp_label_stack = NULL,
7636 vec_add1(rpaths, rpath);
7638 fib_table_entry_path_add2(fib_index,
7641 FIB_ENTRY_FLAG_NONE,
7645 * A labelled recursive route via the MPLS x-connect
7647 fib_prefix_t pfx_2_2_2_4_s_32 = {
7649 .fp_proto = FIB_PROTOCOL_IP4,
7651 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7654 mpls_label_t *l999 = NULL;
7655 vec_add1(l999, 999);
7656 rpaths[0].frp_label_stack = l999,
7658 fib_table_entry_path_add2(fib_index,
7661 FIB_ENTRY_FLAG_NONE,
7664 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7665 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7667 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7668 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7671 fib_test_lb_bucket_t ip_o_1200 = {
7674 .lb = ip_1200.dpoi_index,
7677 fib_test_lb_bucket_t mpls_o_1200 = {
7678 .type = FT_LB_LABEL_O_LB,
7680 .lb = neos_1200.dpoi_index,
7686 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7687 FIB_TEST(fib_test_validate_entry(lfe,
7688 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7691 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
7692 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7693 FIB_TEST(fib_test_validate_entry(lfe,
7694 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7697 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
7699 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
7700 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
7701 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7703 dpo_reset(&neos_1200);
7704 dpo_reset(&ip_1200);
7707 * A recursive via a label that does not exist
7709 fib_test_lb_bucket_t bucket_drop = {
7710 .type = FT_LB_SPECIAL,
7712 .adj = DPO_PROTO_MPLS,
7716 rpaths[0].frp_label_stack = NULL;
7717 lfe = fib_table_entry_path_add2(fib_index,
7720 FIB_ENTRY_FLAG_NONE,
7723 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7724 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7726 ip_o_1200.lb.lb = ip_1200.dpoi_index;
7728 FIB_TEST(fib_test_validate_entry(lfe,
7729 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7732 "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
7733 lfe = fib_table_lookup(fib_index, &pfx_1200);
7734 FIB_TEST(fib_test_validate_entry(lfe,
7735 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7738 "2.2.2.4/32 LB 1 buckets via: ip4-DROP");
7740 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7742 dpo_reset(&ip_1200);
7745 * An rx-interface route.
7746 * like the tail of an mcast LSP
7748 dpo_id_t idpo = DPO_INVALID;
7750 interface_dpo_add_or_lock(DPO_PROTO_IP4,
7751 tm->hw[0]->sw_if_index,
7754 fib_prefix_t pfx_2500 = {
7756 .fp_proto = FIB_PROTOCOL_MPLS,
7759 .fp_payload_proto = DPO_PROTO_IP4,
7761 fib_test_lb_bucket_t rx_intf_0 = {
7764 .adj = idpo.dpoi_index,
7768 lfe = fib_table_entry_update_one_path(fib_index,
7771 FIB_ENTRY_FLAG_NONE,
7774 tm->hw[0]->sw_if_index,
7775 ~0, // invalid fib index
7778 FIB_ROUTE_PATH_INTF_RX);
7779 FIB_TEST(fib_test_validate_entry(lfe,
7780 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7783 "2500 rx-interface 0");
7784 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
7787 * An MPLS mulicast entry
7789 fib_prefix_t pfx_3500 = {
7791 .fp_proto = FIB_PROTOCOL_MPLS,
7794 .fp_payload_proto = DPO_PROTO_IP4,
7796 fib_test_rep_bucket_t mc_0 = {
7797 .type = FT_REP_LABEL_O_ADJ,
7799 .adj = ai_mpls_10_10_10_1,
7804 fib_test_rep_bucket_t mc_intf_0 = {
7805 .type = FT_REP_INTF,
7807 .adj = idpo.dpoi_index,
7810 mpls_label_t *l3300 = NULL;
7811 vec_add1(l3300, 3300);
7813 lfe = fib_table_entry_update_one_path(lfib_index,
7816 FIB_ENTRY_FLAG_MULTICAST,
7819 tm->hw[0]->sw_if_index,
7820 ~0, // invalid fib index
7823 FIB_ROUTE_PATH_FLAG_NONE);
7824 FIB_TEST(fib_test_validate_entry(lfe,
7825 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7828 "3500 via replicate over 10.10.10.1");
7831 * MPLS Bud-node. Add a replication via an interface-receieve path
7833 lfe = fib_table_entry_path_add(lfib_index,
7836 FIB_ENTRY_FLAG_MULTICAST,
7839 tm->hw[0]->sw_if_index,
7840 ~0, // invalid fib index
7843 FIB_ROUTE_PATH_INTF_RX);
7844 FIB_TEST(fib_test_validate_entry(lfe,
7845 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7849 "3500 via replicate over 10.10.10.1 and interface-rx");
7852 * Add a replication via an interface-free for-us path
7854 fib_test_rep_bucket_t mc_disp = {
7855 .type = FT_REP_DISP_MFIB_LOOKUP,
7857 .adj = idpo.dpoi_index,
7860 lfe = fib_table_entry_path_add(lfib_index,
7863 FIB_ENTRY_FLAG_MULTICAST,
7870 FIB_ROUTE_PATH_RPF_ID);
7871 FIB_TEST(fib_test_validate_entry(lfe,
7872 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7877 "3500 via replicate over 10.10.10.1 and interface-rx");
7881 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
7887 mpls_sw_interface_enable_disable(&mpls_main,
7888 tm->hw[0]->sw_if_index,
7891 FIB_TEST(lb_count == pool_elts(load_balance_pool),
7892 "Load-balance resources freed %d of %d",
7893 lb_count, pool_elts(load_balance_pool));
7894 FIB_TEST(0 == pool_elts(interface_dpo_pool),
7895 "interface_dpo resources freed %d of %d",
7896 0, pool_elts(interface_dpo_pool));
7901 static clib_error_t *
7902 fib_test (vlib_main_t * vm,
7903 unformat_input_t * input,
7904 vlib_cli_command_t * cmd_arg)
7909 fib_test_mk_intf(4);
7911 if (unformat (input, "debug"))
7913 fib_test_do_debug = 1;
7916 if (unformat (input, "ip"))
7918 res += fib_test_v4();
7919 res += fib_test_v6();
7921 else if (unformat (input, "label"))
7923 res += fib_test_label();
7925 else if (unformat (input, "ae"))
7927 res += fib_test_ae();
7929 else if (unformat (input, "lfib"))
7933 else if (unformat (input, "walk"))
7935 res += fib_test_walk();
7937 else if (unformat (input, "bfd"))
7939 res += fib_test_bfd();
7944 * These walk UT aren't run as part of the full suite, since the
7945 * fib-walk process must be disabled in order for the tests to work
7949 res += fib_test_v4();
7950 res += fib_test_v6();
7951 res += fib_test_ae();
7952 res += fib_test_bfd();
7953 res += fib_test_label();
7959 return clib_error_return(0, "FIB Unit Test Failed");
7967 VLIB_CLI_COMMAND (test_fib_command, static) = {
7969 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
7970 .function = fib_test,
7974 fib_test_init (vlib_main_t *vm)
7979 VLIB_INIT_FUNCTION (fib_test_init);