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;
723 ip46_address_t nh_10_10_10_1 = {
724 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
727 ip46_address_t nh_10_10_10_2 = {
728 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
733 /* Find or create FIB table 11 */
734 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
736 for (ii = 0; ii < 4; ii++)
738 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
741 fib_prefix_t pfx_0_0_0_0_s_0 = {
743 .fp_proto = FIB_PROTOCOL_IP4,
753 .fp_proto = FIB_PROTOCOL_IP4,
761 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
763 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
764 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
765 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
766 "Default route is DROP");
769 fei = fib_table_lookup(fib_index, &pfx);
770 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
771 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
772 "all 0s route is DROP");
774 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
776 fei = fib_table_lookup(fib_index, &pfx);
777 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
778 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
779 "all 1s route is DROP");
781 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
783 fei = fib_table_lookup(fib_index, &pfx);
784 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
785 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
786 "all-mcast route is DROP");
788 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
790 fei = fib_table_lookup(fib_index, &pfx);
791 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
792 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
793 "class-e route is DROP");
796 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
797 * all of which are special sourced and so none of which share path-lists.
798 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
799 * table, and 4 path-lists in the v6 MFIB table
803 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
804 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
805 fib_path_list_pool_size());
806 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
807 fib_entry_pool_size());
810 * add interface routes.
811 * validate presence of /24 attached and /32 recieve.
812 * test for the presence of the receive address in the glean and local adj
814 fib_prefix_t local_pfx = {
816 .fp_proto = FIB_PROTOCOL_IP4,
819 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
824 fib_table_entry_update_one_path(fib_index, &local_pfx,
825 FIB_SOURCE_INTERFACE,
826 (FIB_ENTRY_FLAG_CONNECTED |
827 FIB_ENTRY_FLAG_ATTACHED),
830 tm->hw[0]->sw_if_index,
831 ~0, // invalid fib index
834 FIB_ROUTE_PATH_FLAG_NONE);
835 fei = fib_table_lookup(fib_index, &local_pfx);
836 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
837 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
838 fib_entry_get_flags(fei)),
839 "Flags set on attached interface");
841 ai = fib_entry_get_adj(fei);
842 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
844 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
845 "attached interface adj is glean");
846 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
847 &adj->sub_type.glean.receive_addr)),
848 "attached interface adj is receive ok");
850 local_pfx.fp_len = 32;
851 fib_table_entry_update_one_path(fib_index, &local_pfx,
852 FIB_SOURCE_INTERFACE,
853 (FIB_ENTRY_FLAG_CONNECTED |
854 FIB_ENTRY_FLAG_LOCAL),
857 tm->hw[0]->sw_if_index,
858 ~0, // invalid fib index
861 FIB_ROUTE_PATH_FLAG_NONE);
862 fei = fib_table_lookup(fib_index, &local_pfx);
863 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
864 fib_entry_get_flags(fei)),
865 "Flags set on local interface");
867 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
869 dpo = fib_entry_contribute_ip_forwarding(fei);
870 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
871 "RPF list for local length 0");
872 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
873 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
874 "local interface adj is local");
875 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
877 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
879 "local interface adj is receive ok");
881 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
883 FIB_SOURCE_INTERFACE)),
884 "2 Interface Source'd prefixes");
887 * +2 interface routes +2 non-shared path-lists
889 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
890 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
891 fib_path_list_pool_size());
892 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
893 fib_entry_pool_size());
896 * Modify the default route to be via an adj not yet known.
897 * this sources the defalut route with the API source, which is
898 * a higher preference to the DEFAULT_ROUTE source
900 pfx.fp_addr.ip4.as_u32 = 0;
902 fib_table_entry_path_add(fib_index, &pfx,
907 tm->hw[0]->sw_if_index,
908 ~0, // invalid fib index
911 FIB_ROUTE_PATH_FLAG_NONE);
912 fei = fib_table_lookup(fib_index, &pfx);
913 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
914 "Flags set on API route");
916 FIB_TEST((fei == dfrt), "default route same index");
917 ai = fib_entry_get_adj(fei);
918 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
920 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
921 "adj is incomplete");
922 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
923 "adj nbr next-hop ok");
924 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
927 "1 API Source'd prefixes");
930 * find the adj in the shared db
932 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
935 tm->hw[0]->sw_if_index);
936 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
937 adj_unlock(locked_ai);
940 * +1 shared path-list
942 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
943 fib_path_list_db_size());
944 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
945 fib_path_list_pool_size());
946 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
947 fib_entry_pool_size());
950 * remove the API source from the default route. We expected
951 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
953 pfx.fp_addr.ip4.as_u32 = 0;
955 fib_table_entry_path_remove(fib_index, &pfx,
959 tm->hw[0]->sw_if_index,
960 ~0, // non-recursive path, so no FIB index
962 FIB_ROUTE_PATH_FLAG_NONE);
964 fei = fib_table_lookup(fib_index, &pfx);
966 FIB_TEST((fei == dfrt), "default route same index");
967 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
968 "Default route is DROP");
971 * -1 shared-path-list
973 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
974 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
975 fib_path_list_pool_size());
976 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
977 fib_entry_pool_size());
980 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
982 fib_prefix_t pfx_10_10_10_1_s_32 = {
984 .fp_proto = FIB_PROTOCOL_IP4,
987 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
990 fib_prefix_t pfx_10_10_10_2_s_32 = {
992 .fp_proto = FIB_PROTOCOL_IP4,
995 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
998 fib_prefix_t pfx_11_11_11_11_s_32 = {
1000 .fp_proto = FIB_PROTOCOL_IP4,
1003 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1007 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1010 ip46_address_t nh_12_12_12_12 = {
1011 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1013 adj_index_t ai_12_12_12_12;
1016 * Add a route via an incomplete ADJ. then complete the ADJ
1017 * Expect the route LB is updated to use complete adj type.
1019 fei = fib_table_entry_update_one_path(fib_index,
1020 &pfx_11_11_11_11_s_32,
1022 FIB_ENTRY_FLAG_ATTACHED,
1024 &pfx_10_10_10_1_s_32.fp_addr,
1025 tm->hw[0]->sw_if_index,
1026 ~0, // invalid fib index
1029 FIB_ROUTE_PATH_FLAG_NONE);
1031 dpo = fib_entry_contribute_ip_forwarding(fei);
1032 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1033 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1034 "11.11.11.11/32 via incomplete adj");
1036 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1038 &pfx_10_10_10_1_s_32.fp_addr,
1039 tm->hw[0]->sw_if_index);
1040 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1041 adj = adj_get(ai_01);
1042 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1043 "adj is incomplete");
1044 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1045 &adj->sub_type.nbr.next_hop)),
1046 "adj nbr next-hop ok");
1048 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1049 fib_test_build_rewrite(eth_addr));
1050 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1052 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1053 &adj->sub_type.nbr.next_hop)),
1054 "adj nbr next-hop ok");
1055 ai = fib_entry_get_adj(fei);
1056 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1058 dpo = fib_entry_contribute_ip_forwarding(fei);
1059 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1060 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1061 "11.11.11.11/32 via complete adj");
1062 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1063 tm->hw[0]->sw_if_index),
1064 "RPF list for adj-fib contains adj");
1066 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1069 tm->hw[1]->sw_if_index);
1070 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1071 adj = adj_get(ai_12_12_12_12);
1072 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1073 "adj is incomplete");
1074 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1075 &adj->sub_type.nbr.next_hop)),
1076 "adj nbr next-hop ok");
1077 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1078 fib_test_build_rewrite(eth_addr));
1079 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1085 fei = fib_table_entry_update_one_path(fib_index,
1086 &pfx_10_10_10_1_s_32,
1088 FIB_ENTRY_FLAG_ATTACHED,
1090 &pfx_10_10_10_1_s_32.fp_addr,
1091 tm->hw[0]->sw_if_index,
1092 ~0, // invalid fib index
1095 FIB_ROUTE_PATH_FLAG_NONE);
1096 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1097 "Flags set on adj-fib");
1098 ai = fib_entry_get_adj(fei);
1099 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1101 fib_table_entry_path_remove(fib_index,
1102 &pfx_11_11_11_11_s_32,
1105 &pfx_10_10_10_1_s_32.fp_addr,
1106 tm->hw[0]->sw_if_index,
1107 ~0, // invalid fib index
1109 FIB_ROUTE_PATH_FLAG_NONE);
1113 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1115 &pfx_10_10_10_2_s_32.fp_addr,
1116 tm->hw[0]->sw_if_index);
1117 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1118 adj = adj_get(ai_02);
1119 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1120 "adj is incomplete");
1121 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1122 &adj->sub_type.nbr.next_hop)),
1123 "adj nbr next-hop ok");
1125 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1126 fib_test_build_rewrite(eth_addr));
1127 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1129 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1130 &adj->sub_type.nbr.next_hop)),
1131 "adj nbr next-hop ok");
1132 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1134 fib_table_entry_update_one_path(fib_index,
1135 &pfx_10_10_10_2_s_32,
1137 FIB_ENTRY_FLAG_ATTACHED,
1139 &pfx_10_10_10_2_s_32.fp_addr,
1140 tm->hw[0]->sw_if_index,
1141 ~0, // invalid fib index
1144 FIB_ROUTE_PATH_FLAG_NONE);
1146 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1147 ai = fib_entry_get_adj(fei);
1148 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1151 * +2 adj-fibs, and their non-shared path-lists
1153 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1154 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1155 fib_path_list_pool_size());
1156 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1157 fib_entry_pool_size());
1160 * Add 2 routes via the first ADJ. ensure path-list sharing
1162 fib_prefix_t pfx_1_1_1_1_s_32 = {
1164 .fp_proto = FIB_PROTOCOL_IP4,
1167 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1171 fib_table_entry_path_add(fib_index,
1174 FIB_ENTRY_FLAG_NONE,
1177 tm->hw[0]->sw_if_index,
1178 ~0, // invalid fib index
1181 FIB_ROUTE_PATH_FLAG_NONE);
1182 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1183 ai = fib_entry_get_adj(fei);
1184 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1187 * +1 entry and a shared path-list
1189 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1190 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1191 fib_path_list_pool_size());
1192 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1193 fib_entry_pool_size());
1196 fib_prefix_t pfx_1_1_2_0_s_24 = {
1198 .fp_proto = FIB_PROTOCOL_IP4,
1200 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1204 fib_table_entry_path_add(fib_index,
1207 FIB_ENTRY_FLAG_NONE,
1210 tm->hw[0]->sw_if_index,
1211 ~0, // invalid fib index
1214 FIB_ROUTE_PATH_FLAG_NONE);
1215 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1216 ai = fib_entry_get_adj(fei);
1217 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1222 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1223 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1224 fib_path_list_pool_size());
1225 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1226 fib_entry_pool_size());
1229 * modify 1.1.2.0/24 to use multipath.
1231 fib_table_entry_path_add(fib_index,
1234 FIB_ENTRY_FLAG_NONE,
1237 tm->hw[0]->sw_if_index,
1238 ~0, // invalid fib index
1241 FIB_ROUTE_PATH_FLAG_NONE);
1242 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1243 dpo = fib_entry_contribute_ip_forwarding(fei);
1244 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1245 1, tm->hw[0]->sw_if_index),
1246 "RPF list for 1.1.2.0/24 contains both adjs");
1248 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1249 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1250 FIB_TEST((ai_01 == dpo1->dpoi_index),
1251 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1252 ai_01, dpo1->dpoi_index);
1254 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1255 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1256 FIB_TEST((ai_02 == dpo1->dpoi_index),
1257 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1260 * +1 shared-pathlist
1262 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1263 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1264 fib_path_list_pool_size());
1265 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1266 fib_entry_pool_size());
1271 fib_table_entry_path_remove(fib_index,
1276 tm->hw[0]->sw_if_index,
1279 FIB_ROUTE_PATH_FLAG_NONE);
1280 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1281 dpo = fib_entry_contribute_ip_forwarding(fei);
1282 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1283 1, tm->hw[0]->sw_if_index),
1284 "RPF list for 1.1.2.0/24 contains one adj");
1286 ai = fib_entry_get_adj(fei);
1287 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1290 * +1 shared-pathlist
1292 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1293 fib_path_list_db_size());
1294 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1295 fib_path_list_pool_size());
1296 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1297 fib_entry_pool_size());
1300 * Add 2 recursive routes:
1301 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1302 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1304 fib_prefix_t bgp_100_pfx = {
1306 .fp_proto = FIB_PROTOCOL_IP4,
1308 /* 100.100.100.100/32 */
1309 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1313 ip46_address_t nh_1_1_1_1 = {
1314 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1317 fei = fib_table_entry_path_add(fib_index,
1320 FIB_ENTRY_FLAG_NONE,
1323 ~0, // no index provided.
1324 fib_index, // nexthop in same fib as route
1327 FIB_ROUTE_PATH_FLAG_NONE);
1329 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1330 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1331 tm->hw[0]->sw_if_index),
1332 "RPF list for adj-fib contains adj");
1335 * +1 entry and +1 shared-path-list
1337 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1338 fib_path_list_db_size());
1339 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1340 fib_path_list_pool_size());
1341 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1342 fib_entry_pool_size());
1344 fib_prefix_t bgp_101_pfx = {
1346 .fp_proto = FIB_PROTOCOL_IP4,
1348 /* 100.100.100.101/32 */
1349 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1353 fib_table_entry_path_add(fib_index,
1356 FIB_ENTRY_FLAG_NONE,
1359 ~0, // no index provided.
1360 fib_index, // nexthop in same fib as route
1363 FIB_ROUTE_PATH_FLAG_NONE);
1365 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1366 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1367 tm->hw[0]->sw_if_index),
1368 "RPF list for adj-fib contains adj");
1371 * +1 entry, but the recursive path-list is shared.
1373 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1374 fib_path_list_db_size());
1375 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1376 fib_path_list_pool_size());
1377 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1378 fib_entry_pool_size());
1381 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1382 * adjacency through which the route will resovle
1384 fib_prefix_t ex_pfx = {
1386 .fp_proto = FIB_PROTOCOL_IP4,
1389 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1393 fib_table_entry_special_add(fib_index,
1396 FIB_ENTRY_FLAG_EXCLUSIVE,
1398 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1399 FIB_TEST((ai == fib_entry_get_adj(fei)),
1400 "Exclusive route links to user adj");
1402 fib_table_entry_special_remove(fib_index,
1404 FIB_SOURCE_SPECIAL);
1405 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1406 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1407 "Exclusive reoute removed");
1410 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1411 * adjacency through which the route will resovle
1413 dpo_id_t ex_dpo = DPO_INVALID;
1415 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1418 LOOKUP_INPUT_DST_ADDR,
1419 LOOKUP_TABLE_FROM_CONFIG,
1422 fib_table_entry_special_dpo_add(fib_index,
1425 FIB_ENTRY_FLAG_EXCLUSIVE,
1427 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1428 dpo = fib_entry_contribute_ip_forwarding(fei);
1429 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1430 "exclusive remote uses lookup DPO");
1433 * update the exclusive to use a different DPO
1435 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1436 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1438 fib_table_entry_special_dpo_update(fib_index,
1441 FIB_ENTRY_FLAG_EXCLUSIVE,
1443 dpo = fib_entry_contribute_ip_forwarding(fei);
1444 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1445 "exclusive remote uses now uses NULL DPO");
1447 fib_table_entry_special_remove(fib_index,
1449 FIB_SOURCE_SPECIAL);
1450 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1451 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1452 "Exclusive reoute removed");
1456 * Add a recursive route:
1457 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1459 fib_prefix_t bgp_200_pfx = {
1461 .fp_proto = FIB_PROTOCOL_IP4,
1463 /* 200.200.200.200/32 */
1464 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1468 fib_prefix_t pfx_1_1_1_2_s_32 = {
1470 .fp_proto = FIB_PROTOCOL_IP4,
1472 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1476 fib_table_entry_path_add(fib_index,
1479 FIB_ENTRY_FLAG_NONE,
1481 &pfx_1_1_1_2_s_32.fp_addr,
1482 ~0, // no index provided.
1483 fib_index, // nexthop in same fib as route
1486 FIB_ROUTE_PATH_FLAG_NONE);
1488 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1491 * the adj should be recursive via drop, since the route resolves via
1492 * the default route, which is itself a DROP
1494 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1495 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1496 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1497 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1498 "RPF list for 1.1.1.2/32 contains 0 adjs");
1501 * +2 entry and +1 shared-path-list
1503 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1504 fib_path_list_db_size());
1505 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1506 fib_path_list_pool_size());
1507 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1508 fib_entry_pool_size());
1511 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1512 * The paths are sort by NH first. in this case the the path with greater
1513 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1515 fib_prefix_t pfx_1_2_3_4_s_32 = {
1517 .fp_proto = FIB_PROTOCOL_IP4,
1519 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1522 fib_table_entry_path_add(fib_index,
1525 FIB_ENTRY_FLAG_NONE,
1528 tm->hw[0]->sw_if_index,
1532 FIB_ROUTE_PATH_FLAG_NONE);
1533 fei = fib_table_entry_path_add(fib_index,
1536 FIB_ENTRY_FLAG_NONE,
1539 tm->hw[1]->sw_if_index,
1543 FIB_ROUTE_PATH_FLAG_NONE);
1545 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1546 dpo = fib_entry_contribute_ip_forwarding(fei);
1547 lb = load_balance_get(dpo->dpoi_index);
1548 FIB_TEST((lb->lb_n_buckets == 4),
1549 "1.2.3.4/32 LB has %d bucket",
1552 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1553 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1554 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1555 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1557 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1558 tm->hw[0]->sw_if_index,
1559 tm->hw[1]->sw_if_index),
1560 "RPF list for 1.2.3.4/32 contains both adjs");
1564 * Unequal Cost load-balance. 4:1 ratio.
1565 * fits in a 16 bucket LB with ratio 13:3
1567 fib_prefix_t pfx_1_2_3_5_s_32 = {
1569 .fp_proto = FIB_PROTOCOL_IP4,
1571 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1574 fib_table_entry_path_add(fib_index,
1577 FIB_ENTRY_FLAG_NONE,
1580 tm->hw[1]->sw_if_index,
1584 FIB_ROUTE_PATH_FLAG_NONE);
1585 fei = fib_table_entry_path_add(fib_index,
1588 FIB_ENTRY_FLAG_NONE,
1591 tm->hw[0]->sw_if_index,
1595 FIB_ROUTE_PATH_FLAG_NONE);
1597 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1598 dpo = fib_entry_contribute_ip_forwarding(fei);
1599 lb = load_balance_get(dpo->dpoi_index);
1600 FIB_TEST((lb->lb_n_buckets == 16),
1601 "1.2.3.5/32 LB has %d bucket",
1604 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1605 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1606 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1607 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1608 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1609 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1610 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1611 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1612 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1613 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1614 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1615 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1616 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1617 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1618 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1619 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1621 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1622 tm->hw[0]->sw_if_index,
1623 tm->hw[1]->sw_if_index),
1624 "RPF list for 1.2.3.4/32 contains both adjs");
1627 * Test UCMP with a large weight skew - this produces load-balance objects with large
1628 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1629 * laso testing the LB in placce modify code when number of buckets is large.
1631 fib_prefix_t pfx_6_6_6_6_s_32 = {
1633 .fp_proto = FIB_PROTOCOL_IP4,
1636 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1639 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_1 = {
1645 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_2 = {
1651 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1654 .adj = ai_12_12_12_12,
1657 fib_table_entry_update_one_path(fib_index,
1660 FIB_ENTRY_FLAG_NONE,
1663 tm->hw[0]->sw_if_index,
1664 ~0, // invalid fib index
1667 FIB_ROUTE_PATH_FLAG_NONE);
1669 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1670 FIB_TEST(fib_test_validate_entry(fei,
1671 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1673 &ip_6_6_6_6_o_10_10_10_1),
1674 "6.6.6.6/32 via 10.10.10.1");
1676 fib_table_entry_path_add(fib_index,
1679 FIB_ENTRY_FLAG_NONE,
1682 tm->hw[0]->sw_if_index,
1683 ~0, // invalid fib index
1686 FIB_ROUTE_PATH_FLAG_NONE);
1688 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1689 FIB_TEST(fib_test_validate_entry(fei,
1690 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1692 &ip_6_6_6_6_o_10_10_10_2,
1693 &ip_6_6_6_6_o_10_10_10_2,
1694 &ip_6_6_6_6_o_10_10_10_2,
1695 &ip_6_6_6_6_o_10_10_10_2,
1696 &ip_6_6_6_6_o_10_10_10_2,
1697 &ip_6_6_6_6_o_10_10_10_2,
1698 &ip_6_6_6_6_o_10_10_10_2,
1699 &ip_6_6_6_6_o_10_10_10_2,
1700 &ip_6_6_6_6_o_10_10_10_2,
1701 &ip_6_6_6_6_o_10_10_10_2,
1702 &ip_6_6_6_6_o_10_10_10_2,
1703 &ip_6_6_6_6_o_10_10_10_2,
1704 &ip_6_6_6_6_o_10_10_10_2,
1705 &ip_6_6_6_6_o_10_10_10_2,
1706 &ip_6_6_6_6_o_10_10_10_2,
1707 &ip_6_6_6_6_o_10_10_10_2,
1708 &ip_6_6_6_6_o_10_10_10_2,
1709 &ip_6_6_6_6_o_10_10_10_2,
1710 &ip_6_6_6_6_o_10_10_10_2,
1711 &ip_6_6_6_6_o_10_10_10_2,
1712 &ip_6_6_6_6_o_10_10_10_2,
1713 &ip_6_6_6_6_o_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_1),
1756 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1758 fib_table_entry_path_add(fib_index,
1761 FIB_ENTRY_FLAG_NONE,
1764 tm->hw[1]->sw_if_index,
1765 ~0, // invalid fib index
1768 FIB_ROUTE_PATH_FLAG_NONE);
1770 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1771 FIB_TEST(fib_test_validate_entry(fei,
1772 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1774 &ip_6_6_6_6_o_10_10_10_1,
1775 &ip_6_6_6_6_o_10_10_10_2,
1776 &ip_6_6_6_6_o_10_10_10_2,
1777 &ip_6_6_6_6_o_10_10_10_2,
1778 &ip_6_6_6_6_o_10_10_10_2,
1779 &ip_6_6_6_6_o_10_10_10_2,
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_12_12_12_12,
1840 &ip_6_6_6_6_o_12_12_12_12,
1841 &ip_6_6_6_6_o_12_12_12_12,
1842 &ip_6_6_6_6_o_12_12_12_12,
1843 &ip_6_6_6_6_o_12_12_12_12,
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 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1904 fib_table_entry_path_remove(fib_index,
1909 tm->hw[1]->sw_if_index,
1910 ~0, // invalid fib index
1912 FIB_ROUTE_PATH_FLAG_NONE);
1914 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1915 FIB_TEST(fib_test_validate_entry(fei,
1916 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1918 &ip_6_6_6_6_o_10_10_10_2,
1919 &ip_6_6_6_6_o_10_10_10_2,
1920 &ip_6_6_6_6_o_10_10_10_2,
1921 &ip_6_6_6_6_o_10_10_10_2,
1922 &ip_6_6_6_6_o_10_10_10_2,
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_1),
1982 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1984 fib_table_entry_path_remove(fib_index,
1989 tm->hw[0]->sw_if_index,
1990 ~0, // invalid fib index
1992 FIB_ROUTE_PATH_FLAG_NONE);
1994 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1995 FIB_TEST(fib_test_validate_entry(fei,
1996 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1998 &ip_6_6_6_6_o_10_10_10_1),
1999 "6.6.6.6/32 via 10.10.10.1");
2001 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2004 * A recursive via the two unequal cost entries
2006 fib_prefix_t bgp_44_s_32 = {
2008 .fp_proto = FIB_PROTOCOL_IP4,
2010 /* 200.200.200.201/32 */
2011 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2014 fei = fib_table_entry_path_add(fib_index,
2017 FIB_ENTRY_FLAG_NONE,
2019 &pfx_1_2_3_4_s_32.fp_addr,
2024 FIB_ROUTE_PATH_FLAG_NONE);
2025 fei = fib_table_entry_path_add(fib_index,
2028 FIB_ENTRY_FLAG_NONE,
2030 &pfx_1_2_3_5_s_32.fp_addr,
2035 FIB_ROUTE_PATH_FLAG_NONE);
2037 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2038 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2039 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2040 tm->hw[0]->sw_if_index,
2041 tm->hw[1]->sw_if_index),
2042 "RPF list for 1.2.3.4/32 contains both adjs");
2045 * test the uRPF check functions
2047 dpo_id_t dpo_44 = DPO_INVALID;
2050 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2051 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2053 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2054 "uRPF check for 68.68.68.68/32 on %d OK",
2055 tm->hw[0]->sw_if_index);
2056 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2057 "uRPF check for 68.68.68.68/32 on %d OK",
2058 tm->hw[1]->sw_if_index);
2059 FIB_TEST(!fib_urpf_check(urpfi, 99),
2060 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2064 fib_table_entry_delete(fib_index,
2067 fib_table_entry_delete(fib_index,
2070 fib_table_entry_delete(fib_index,
2075 * Add a recursive route:
2076 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2078 fib_prefix_t bgp_201_pfx = {
2080 .fp_proto = FIB_PROTOCOL_IP4,
2082 /* 200.200.200.201/32 */
2083 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2087 fib_prefix_t pfx_1_1_1_200_s_32 = {
2089 .fp_proto = FIB_PROTOCOL_IP4,
2091 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2095 fib_table_entry_path_add(fib_index,
2098 FIB_ENTRY_FLAG_NONE,
2100 &pfx_1_1_1_200_s_32.fp_addr,
2101 ~0, // no index provided.
2102 fib_index, // nexthop in same fib as route
2105 FIB_ROUTE_PATH_FLAG_NONE);
2107 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2109 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2110 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2111 "Flags set on RR via non-attached");
2112 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2113 "RPF list for BGP route empty");
2116 * +2 entry (BGP & RR) and +1 shared-path-list
2118 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2119 fib_path_list_db_size());
2120 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2121 fib_path_list_pool_size());
2122 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2123 fib_entry_pool_size());
2126 * insert a route that covers the missing 1.1.1.2/32. we epxect
2127 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2129 fib_prefix_t pfx_1_1_1_0_s_24 = {
2131 .fp_proto = FIB_PROTOCOL_IP4,
2134 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2138 fib_table_entry_path_add(fib_index,
2141 FIB_ENTRY_FLAG_NONE,
2144 tm->hw[0]->sw_if_index,
2145 ~0, // invalid fib index
2148 FIB_ROUTE_PATH_FLAG_NONE);
2149 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2150 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2151 ai = fib_entry_get_adj(fei);
2152 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2153 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2154 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2155 ai = fib_entry_get_adj(fei);
2156 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2157 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2158 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2159 ai = fib_entry_get_adj(fei);
2160 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2163 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2165 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2166 fib_path_list_db_size());
2167 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2168 fib_path_list_pool_size());
2169 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2170 fib_entry_pool_size());
2173 * the recursive adj for 200.200.200.200 should be updated.
2175 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2176 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2177 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2178 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2179 tm->hw[0]->sw_if_index),
2180 "RPF list for BGP route has itf index 0");
2183 * insert a more specific route than 1.1.1.0/24 that also covers the
2184 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2185 * 200.200.200.200 to resolve through it.
2187 fib_prefix_t pfx_1_1_1_0_s_28 = {
2189 .fp_proto = FIB_PROTOCOL_IP4,
2192 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2196 fib_table_entry_path_add(fib_index,
2199 FIB_ENTRY_FLAG_NONE,
2202 tm->hw[0]->sw_if_index,
2203 ~0, // invalid fib index
2206 FIB_ROUTE_PATH_FLAG_NONE);
2207 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2208 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2209 ai = fib_entry_get_adj(fei);
2210 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2213 * +1 entry. +1 shared path-list
2215 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2216 fib_path_list_db_size());
2217 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2218 fib_path_list_pool_size());
2219 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2220 fib_entry_pool_size());
2223 * the recursive adj for 200.200.200.200 should be updated.
2224 * 200.200.200.201 remains unchanged.
2226 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2227 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2230 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2232 fib_table_entry_path_remove(fib_index,
2237 tm->hw[0]->sw_if_index,
2240 FIB_ROUTE_PATH_FLAG_NONE);
2241 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2242 FIB_NODE_INDEX_INVALID),
2243 "1.1.1.0/28 removed");
2244 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2245 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2246 "1.1.1.0/28 lookup via /24");
2247 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2248 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2251 * -1 entry. -1 shared path-list
2253 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2254 fib_path_list_db_size());
2255 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2256 fib_path_list_pool_size());
2257 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2258 fib_entry_pool_size());
2261 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2263 fib_table_entry_path_remove(fib_index,
2268 tm->hw[0]->sw_if_index,
2271 FIB_ROUTE_PATH_FLAG_NONE);
2272 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2273 FIB_NODE_INDEX_INVALID),
2274 "1.1.1.0/24 removed");
2276 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2277 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2278 "1.1.1.2/32 route is DROP");
2279 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2280 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2281 "1.1.1.200/32 route is DROP");
2283 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2284 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2289 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2290 fib_path_list_db_size());
2291 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2292 fib_path_list_pool_size());
2293 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2294 fib_entry_pool_size());
2297 * insert the missing 1.1.1.2/32
2299 fei = fib_table_entry_path_add(fib_index,
2302 FIB_ENTRY_FLAG_NONE,
2305 tm->hw[0]->sw_if_index,
2306 ~0, // invalid fib index
2309 FIB_ROUTE_PATH_FLAG_NONE);
2310 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2311 ai = fib_entry_get_adj(fei);
2312 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2314 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2315 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2318 * no change. 1.1.1.2/32 was already there RR sourced.
2320 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2321 fib_path_list_db_size());
2322 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2323 fib_path_list_pool_size());
2324 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2325 fib_entry_pool_size());
2328 * remove 200.200.200.201/32 which does not have a valid via FIB
2330 fib_table_entry_path_remove(fib_index,
2334 &pfx_1_1_1_200_s_32.fp_addr,
2335 ~0, // no index provided.
2338 FIB_ROUTE_PATH_FLAG_NONE);
2341 * -2 entries (BGP and RR). -1 shared path-list;
2343 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2344 FIB_NODE_INDEX_INVALID),
2345 "200.200.200.201/32 removed");
2346 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2347 FIB_NODE_INDEX_INVALID),
2348 "1.1.1.200/32 removed");
2350 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2351 fib_path_list_db_size());
2352 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2353 fib_path_list_pool_size());
2354 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2355 fib_entry_pool_size());
2358 * remove 200.200.200.200/32 which does have a valid via FIB
2360 fib_table_entry_path_remove(fib_index,
2364 &pfx_1_1_1_2_s_32.fp_addr,
2365 ~0, // no index provided.
2368 FIB_ROUTE_PATH_FLAG_NONE);
2370 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2371 FIB_NODE_INDEX_INVALID),
2372 "200.200.200.200/32 removed");
2373 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2374 FIB_NODE_INDEX_INVALID),
2375 "1.1.1.2/32 still present");
2378 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2380 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2381 fib_path_list_db_size());
2382 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2383 fib_path_list_pool_size());
2384 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2385 fib_entry_pool_size());
2388 * A recursive prefix that has a 2 path load-balance.
2389 * It also shares a next-hop with other BGP prefixes and hence
2390 * test the ref counting of RR sourced prefixes and 2 level LB.
2392 const fib_prefix_t bgp_102 = {
2394 .fp_proto = FIB_PROTOCOL_IP4,
2396 /* 100.100.100.101/32 */
2397 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2400 fib_table_entry_path_add(fib_index,
2403 FIB_ENTRY_FLAG_NONE,
2405 &pfx_1_1_1_1_s_32.fp_addr,
2406 ~0, // no index provided.
2407 fib_index, // same as route
2410 FIB_ROUTE_PATH_FLAG_NONE);
2411 fib_table_entry_path_add(fib_index,
2414 FIB_ENTRY_FLAG_NONE,
2416 &pfx_1_1_1_2_s_32.fp_addr,
2417 ~0, // no index provided.
2418 fib_index, // same as route's FIB
2421 FIB_ROUTE_PATH_FLAG_NONE);
2422 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2423 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2424 dpo = fib_entry_contribute_ip_forwarding(fei);
2426 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2427 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2428 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2429 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2431 lb = load_balance_get(dpo->dpoi_index);
2432 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2433 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2434 "First via 10.10.10.1");
2435 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2436 "Second via 10.10.10.1");
2438 fib_table_entry_path_remove(fib_index,
2442 &pfx_1_1_1_1_s_32.fp_addr,
2443 ~0, // no index provided.
2444 fib_index, // same as route's FIB
2446 FIB_ROUTE_PATH_FLAG_NONE);
2447 fib_table_entry_path_remove(fib_index,
2451 &pfx_1_1_1_2_s_32.fp_addr,
2452 ~0, // no index provided.
2453 fib_index, // same as route's FIB
2455 FIB_ROUTE_PATH_FLAG_NONE);
2456 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2457 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2460 * remove the remaining recursives
2462 fib_table_entry_path_remove(fib_index,
2466 &pfx_1_1_1_1_s_32.fp_addr,
2467 ~0, // no index provided.
2468 fib_index, // same as route's FIB
2470 FIB_ROUTE_PATH_FLAG_NONE);
2471 fib_table_entry_path_remove(fib_index,
2475 &pfx_1_1_1_1_s_32.fp_addr,
2476 ~0, // no index provided.
2477 fib_index, // same as route's FIB
2479 FIB_ROUTE_PATH_FLAG_NONE);
2480 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2481 FIB_NODE_INDEX_INVALID),
2482 "100.100.100.100/32 removed");
2483 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2484 FIB_NODE_INDEX_INVALID),
2485 "100.100.100.101/32 removed");
2488 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2490 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2491 fib_path_list_db_size());
2492 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2493 fib_path_list_pool_size());
2494 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2495 fib_entry_pool_size());
2498 * Add a recursive route via a connected cover, using an adj-fib that does exist
2500 fib_table_entry_path_add(fib_index,
2503 FIB_ENTRY_FLAG_NONE,
2506 ~0, // no index provided.
2507 fib_index, // Same as route's FIB
2510 FIB_ROUTE_PATH_FLAG_NONE);
2513 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2515 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2516 fib_path_list_db_size());
2517 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2518 fib_path_list_pool_size());
2519 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2520 fib_entry_pool_size());
2522 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2523 dpo = fib_entry_contribute_ip_forwarding(fei);
2525 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2526 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2528 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2529 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2531 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2532 "Flags set on RR via existing attached");
2535 * Add a recursive route via a connected cover, using and adj-fib that does
2538 ip46_address_t nh_10_10_10_3 = {
2539 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2541 fib_prefix_t pfx_10_10_10_3 = {
2543 .fp_proto = FIB_PROTOCOL_IP4,
2544 .fp_addr = nh_10_10_10_3,
2547 fib_table_entry_path_add(fib_index,
2550 FIB_ENTRY_FLAG_NONE,
2553 ~0, // no index provided.
2557 FIB_ROUTE_PATH_FLAG_NONE);
2560 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2561 * one unshared non-recursive via 10.10.10.3
2563 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2564 fib_path_list_db_size());
2565 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2566 fib_path_list_pool_size());
2567 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2568 fib_entry_pool_size());
2570 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2573 tm->hw[0]->sw_if_index);
2575 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2576 dpo = fib_entry_contribute_ip_forwarding(fei);
2577 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2578 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2580 ai = fib_entry_get_adj(fei);
2581 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2582 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2583 fib_entry_get_flags(fei)),
2584 "Flags set on RR via non-existing attached");
2586 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2587 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2592 * remove the recursives
2594 fib_table_entry_path_remove(fib_index,
2599 ~0, // no index provided.
2600 fib_index, // same as route's FIB
2602 FIB_ROUTE_PATH_FLAG_NONE);
2603 fib_table_entry_path_remove(fib_index,
2608 ~0, // no index provided.
2609 fib_index, // same as route's FIB
2611 FIB_ROUTE_PATH_FLAG_NONE);
2613 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2614 FIB_NODE_INDEX_INVALID),
2615 "200.200.200.201/32 removed");
2616 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2617 FIB_NODE_INDEX_INVALID),
2618 "200.200.200.200/32 removed");
2619 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2620 FIB_NODE_INDEX_INVALID),
2621 "10.10.10.3/32 removed");
2624 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2625 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2627 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2628 fib_path_list_db_size());
2629 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2630 fib_path_list_pool_size());
2631 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2632 fib_entry_pool_size());
2637 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2639 fib_prefix_t pfx_5_5_5_5_s_32 = {
2641 .fp_proto = FIB_PROTOCOL_IP4,
2643 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2646 fib_prefix_t pfx_5_5_5_6_s_32 = {
2648 .fp_proto = FIB_PROTOCOL_IP4,
2650 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2653 fib_prefix_t pfx_5_5_5_7_s_32 = {
2655 .fp_proto = FIB_PROTOCOL_IP4,
2657 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2661 fib_table_entry_path_add(fib_index,
2664 FIB_ENTRY_FLAG_NONE,
2666 &pfx_5_5_5_6_s_32.fp_addr,
2667 ~0, // no index provided.
2671 FIB_ROUTE_PATH_FLAG_NONE);
2672 fib_table_entry_path_add(fib_index,
2675 FIB_ENTRY_FLAG_NONE,
2677 &pfx_5_5_5_7_s_32.fp_addr,
2678 ~0, // no index provided.
2682 FIB_ROUTE_PATH_FLAG_NONE);
2683 fib_table_entry_path_add(fib_index,
2686 FIB_ENTRY_FLAG_NONE,
2688 &pfx_5_5_5_5_s_32.fp_addr,
2689 ~0, // no index provided.
2693 FIB_ROUTE_PATH_FLAG_NONE);
2695 * +3 entries, +3 shared path-list
2697 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2698 fib_path_list_db_size());
2699 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2700 fib_path_list_pool_size());
2701 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2702 fib_entry_pool_size());
2705 * All the entries have only looped paths, so they are all drop
2707 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2708 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2709 "LB for 5.5.5.7/32 is via adj for DROP");
2710 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2711 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2712 "LB for 5.5.5.5/32 is via adj for DROP");
2713 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2714 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2715 "LB for 5.5.5.6/32 is via adj for DROP");
2718 * provide 5.5.5.6/32 with alternate path.
2719 * this will allow only 5.5.5.6/32 to forward with this path, the others
2720 * are still drop since the loop is still present.
2722 fib_table_entry_path_add(fib_index,
2725 FIB_ENTRY_FLAG_NONE,
2728 tm->hw[0]->sw_if_index,
2732 FIB_ROUTE_PATH_FLAG_NONE);
2734 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2735 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2737 lb = load_balance_get(dpo1->dpoi_index);
2738 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2740 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2741 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2742 FIB_TEST((ai_01 == dpo2->dpoi_index),
2743 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2745 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2746 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2747 "LB for 5.5.5.7/32 is via adj for DROP");
2748 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2749 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2750 "LB for 5.5.5.5/32 is via adj for DROP");
2753 * remove the alternate path for 5.5.5.6/32
2756 fib_table_entry_path_remove(fib_index,
2761 tm->hw[0]->sw_if_index,
2764 FIB_ROUTE_PATH_FLAG_NONE);
2766 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2767 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2768 "LB for 5.5.5.7/32 is via adj for DROP");
2769 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2770 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2771 "LB for 5.5.5.5/32 is via adj for DROP");
2772 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2773 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2774 "LB for 5.5.5.6/32 is via adj for DROP");
2777 * break the loop by giving 5.5.5.5/32 a new set of paths
2778 * expect all to forward via this new path.
2780 fib_table_entry_update_one_path(fib_index,
2783 FIB_ENTRY_FLAG_NONE,
2786 tm->hw[0]->sw_if_index,
2787 ~0, // invalid fib index
2790 FIB_ROUTE_PATH_FLAG_NONE);
2792 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2793 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2794 lb = load_balance_get(dpo1->dpoi_index);
2795 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2797 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2798 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2799 FIB_TEST((ai_01 == dpo2->dpoi_index),
2800 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2802 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2803 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2805 lb = load_balance_get(dpo2->dpoi_index);
2806 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2807 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2808 "5.5.5.5.7 via 5.5.5.5");
2810 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2811 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2813 lb = load_balance_get(dpo1->dpoi_index);
2814 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2815 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2816 "5.5.5.5.6 via 5.5.5.7");
2819 * revert back to the loop. so we can remove the prefixes with
2822 fib_table_entry_update_one_path(fib_index,
2825 FIB_ENTRY_FLAG_NONE,
2827 &pfx_5_5_5_6_s_32.fp_addr,
2828 ~0, // no index provided.
2832 FIB_ROUTE_PATH_FLAG_NONE);
2834 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2835 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2836 "LB for 5.5.5.7/32 is via adj for DROP");
2837 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2838 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2839 "LB for 5.5.5.5/32 is via adj for DROP");
2840 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2841 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2842 "LB for 5.5.5.6/32 is via adj for DROP");
2845 * remove all the 5.5.5.x/32 prefixes
2847 fib_table_entry_path_remove(fib_index,
2851 &pfx_5_5_5_6_s_32.fp_addr,
2852 ~0, // no index provided.
2853 fib_index, // same as route's FIB
2855 FIB_ROUTE_PATH_FLAG_NONE);
2856 fib_table_entry_path_remove(fib_index,
2860 &pfx_5_5_5_7_s_32.fp_addr,
2861 ~0, // no index provided.
2862 fib_index, // same as route's FIB
2864 FIB_ROUTE_PATH_FLAG_NONE);
2865 fib_table_entry_path_remove(fib_index,
2869 &pfx_5_5_5_5_s_32.fp_addr,
2870 ~0, // no index provided.
2871 fib_index, // same as route's FIB
2873 FIB_ROUTE_PATH_FLAG_NONE);
2874 fib_table_entry_path_remove(fib_index,
2879 ~0, // no index provided.
2880 fib_index, // same as route's FIB
2882 FIB_ROUTE_PATH_FLAG_NONE);
2885 * -3 entries, -3 shared path-list
2887 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2888 fib_path_list_db_size());
2889 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2890 fib_path_list_pool_size());
2891 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2892 fib_entry_pool_size());
2895 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2897 fib_table_entry_path_add(fib_index,
2900 FIB_ENTRY_FLAG_NONE,
2902 &pfx_5_5_5_6_s_32.fp_addr,
2903 ~0, // no index provided.
2907 FIB_ROUTE_PATH_FLAG_NONE);
2908 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2909 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2910 "1-level 5.5.5.6/32 loop is via adj for DROP");
2912 fib_table_entry_path_remove(fib_index,
2916 &pfx_5_5_5_6_s_32.fp_addr,
2917 ~0, // no index provided.
2918 fib_index, // same as route's FIB
2920 FIB_ROUTE_PATH_FLAG_NONE);
2921 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2922 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2923 "1-level 5.5.5.6/32 loop is removed");
2926 * A recursive route whose next-hop is covered by the prefix.
2927 * This would mean the via-fib, which inherits forwarding from its
2928 * cover, thus picks up forwarding from the prfix, which is via the
2929 * via-fib, and we have a loop.
2931 fib_prefix_t pfx_23_23_23_0_s_24 = {
2933 .fp_proto = FIB_PROTOCOL_IP4,
2935 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2938 fib_prefix_t pfx_23_23_23_23_s_32 = {
2940 .fp_proto = FIB_PROTOCOL_IP4,
2942 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2945 fei = fib_table_entry_path_add(fib_index,
2946 &pfx_23_23_23_0_s_24,
2948 FIB_ENTRY_FLAG_NONE,
2950 &pfx_23_23_23_23_s_32.fp_addr,
2955 FIB_ROUTE_PATH_FLAG_NONE);
2956 dpo = fib_entry_contribute_ip_forwarding(fei);
2957 FIB_TEST(load_balance_is_drop(dpo),
2958 "23.23.23.0/24 via covered is DROP");
2959 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2962 * add-remove test. no change.
2964 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2965 fib_path_list_db_size());
2966 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2967 fib_path_list_pool_size());
2968 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2969 fib_entry_pool_size());
2972 * A recursive route with recursion constraints.
2973 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2975 fib_table_entry_path_add(fib_index,
2978 FIB_ENTRY_FLAG_NONE,
2985 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2987 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2988 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2990 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2991 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2993 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2994 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
2997 * save the load-balance. we expect it to be inplace modified
2999 lb = load_balance_get(dpo1->dpoi_index);
3002 * add a covering prefix for the via fib that would otherwise serve
3003 * as the resolving route when the host is removed
3005 fib_table_entry_path_add(fib_index,
3008 FIB_ENTRY_FLAG_NONE,
3011 tm->hw[0]->sw_if_index,
3012 ~0, // invalid fib index
3015 FIB_ROUTE_PATH_FLAG_NONE);
3016 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3017 ai = fib_entry_get_adj(fei);
3018 FIB_TEST((ai == ai_01),
3019 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3022 * remove the host via FIB - expect the BGP prefix to be drop
3024 fib_table_entry_path_remove(fib_index,
3029 tm->hw[0]->sw_if_index,
3030 ~0, // invalid fib index
3032 FIB_ROUTE_PATH_FLAG_NONE);
3034 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3035 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3038 * add the via-entry host reoute back. expect to resolve again
3040 fib_table_entry_path_add(fib_index,
3043 FIB_ENTRY_FLAG_NONE,
3046 tm->hw[0]->sw_if_index,
3047 ~0, // invalid fib index
3050 FIB_ROUTE_PATH_FLAG_NONE);
3051 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3052 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3055 * add another path for the recursive. it will then have 2.
3057 fib_prefix_t pfx_1_1_1_3_s_32 = {
3059 .fp_proto = FIB_PROTOCOL_IP4,
3061 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3064 fib_table_entry_path_add(fib_index,
3067 FIB_ENTRY_FLAG_NONE,
3070 tm->hw[0]->sw_if_index,
3071 ~0, // invalid fib index
3074 FIB_ROUTE_PATH_FLAG_NONE);
3076 fib_table_entry_path_add(fib_index,
3079 FIB_ENTRY_FLAG_NONE,
3081 &pfx_1_1_1_3_s_32.fp_addr,
3086 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3088 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3089 dpo = fib_entry_contribute_ip_forwarding(fei);
3091 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3092 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3093 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3094 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3095 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3096 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3097 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3098 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3101 * expect the lb-map used by the recursive's load-balance is using both buckets
3103 load_balance_map_t *lbm;
3106 lb = load_balance_get(dpo->dpoi_index);
3108 load_balance_map_lock(lbmi);
3109 lbm = load_balance_map_get(lbmi);
3111 FIB_TEST(lbm->lbm_buckets[0] == 0,
3112 "LB maps's bucket 0 is %d",
3113 lbm->lbm_buckets[0]);
3114 FIB_TEST(lbm->lbm_buckets[1] == 1,
3115 "LB maps's bucket 1 is %d",
3116 lbm->lbm_buckets[1]);
3119 * withdraw one of the /32 via-entrys.
3120 * that ECMP path will be unresolved and forwarding should continue on the
3121 * other available path. this is an iBGP PIC edge failover.
3122 * Test the forwarding changes without re-fetching the adj from the
3123 * recursive entry. this ensures its the same one that is updated; i.e. an
3126 fib_table_entry_path_remove(fib_index,
3131 tm->hw[0]->sw_if_index,
3132 ~0, // invalid fib index
3134 FIB_ROUTE_PATH_FLAG_NONE);
3136 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3137 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3138 "post PIC 200.200.200.200/32 was inplace modified");
3140 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3141 "post PIC adj for 200.200.200.200/32 is recursive"
3142 " via adj for 1.1.1.3");
3145 * the LB maps that was locked above should have been modified to remove
3146 * the path that was down, and thus its bucket points to a path that is
3149 FIB_TEST(lbm->lbm_buckets[0] == 1,
3150 "LB maps's bucket 0 is %d",
3151 lbm->lbm_buckets[0]);
3152 FIB_TEST(lbm->lbm_buckets[1] == 1,
3153 "LB maps's bucket 1 is %d",
3154 lbm->lbm_buckets[1]);
3156 load_balance_map_unlock(lb->lb_map);
3159 * add it back. again
3161 fib_table_entry_path_add(fib_index,
3164 FIB_ENTRY_FLAG_NONE,
3167 tm->hw[0]->sw_if_index,
3168 ~0, // invalid fib index
3171 FIB_ROUTE_PATH_FLAG_NONE);
3173 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3174 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3175 "via adj for 1.1.1.1");
3176 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3177 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3178 "via adj for 1.1.1.3");
3180 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3181 dpo = fib_entry_contribute_ip_forwarding(fei);
3182 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3183 "post PIC 200.200.200.200/32 was inplace modified");
3186 * add a 3rd path. this makes the LB 16 buckets.
3188 fib_table_entry_path_add(fib_index,
3191 FIB_ENTRY_FLAG_NONE,
3193 &pfx_1_1_1_2_s_32.fp_addr,
3198 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3200 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3201 dpo = fib_entry_contribute_ip_forwarding(fei);
3202 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3203 "200.200.200.200/32 was inplace modified for 3rd path");
3204 FIB_TEST(16 == lb->lb_n_buckets,
3205 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3208 load_balance_map_lock(lbmi);
3209 lbm = load_balance_map_get(lbmi);
3211 for (ii = 0; ii < 16; ii++)
3213 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3214 "LB Map for 200.200.200.200/32 at %d is %d",
3215 ii, lbm->lbm_buckets[ii]);
3219 * trigger PIC by removing the first via-entry
3220 * the first 6 buckets of the map should map to the next 6
3222 fib_table_entry_path_remove(fib_index,
3227 tm->hw[0]->sw_if_index,
3230 FIB_ROUTE_PATH_FLAG_NONE);
3232 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3233 dpo = fib_entry_contribute_ip_forwarding(fei);
3234 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3235 "200.200.200.200/32 was inplace modified for 3rd path");
3236 FIB_TEST(2 == lb->lb_n_buckets,
3237 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3239 for (ii = 0; ii < 6; ii++)
3241 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3242 "LB Map for 200.200.200.200/32 at %d is %d",
3243 ii, lbm->lbm_buckets[ii]);
3245 for (ii = 6; ii < 16; ii++)
3247 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3248 "LB Map for 200.200.200.200/32 at %d is %d",
3249 ii, lbm->lbm_buckets[ii]);
3256 fib_table_entry_path_add(fib_index,
3259 FIB_ENTRY_FLAG_NONE,
3262 tm->hw[0]->sw_if_index,
3266 FIB_ROUTE_PATH_FLAG_NONE);
3268 fib_table_entry_path_remove(fib_index,
3272 &pfx_1_1_1_2_s_32.fp_addr,
3276 MPLS_LABEL_INVALID);
3277 fib_table_entry_path_remove(fib_index,
3285 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3286 fib_table_entry_path_remove(fib_index,
3290 &pfx_1_1_1_3_s_32.fp_addr,
3294 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3295 fib_table_entry_delete(fib_index,
3298 fib_table_entry_delete(fib_index,
3301 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3302 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3303 "1.1.1.1/28 removed");
3304 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3305 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3306 "1.1.1.3/32 removed");
3307 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3308 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3309 "200.200.200.200/32 removed");
3312 * add-remove test. no change.
3314 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3315 fib_path_list_db_size());
3316 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3317 fib_path_list_pool_size());
3318 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3319 fib_entry_pool_size());
3322 * A route whose paths are built up iteratively and then removed
3325 fib_prefix_t pfx_4_4_4_4_s_32 = {
3327 .fp_proto = FIB_PROTOCOL_IP4,
3330 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3334 fib_table_entry_path_add(fib_index,
3337 FIB_ENTRY_FLAG_NONE,
3340 tm->hw[0]->sw_if_index,
3344 FIB_ROUTE_PATH_FLAG_NONE);
3345 fib_table_entry_path_add(fib_index,
3348 FIB_ENTRY_FLAG_NONE,
3351 tm->hw[0]->sw_if_index,
3355 FIB_ROUTE_PATH_FLAG_NONE);
3356 fib_table_entry_path_add(fib_index,
3359 FIB_ENTRY_FLAG_NONE,
3362 tm->hw[0]->sw_if_index,
3366 FIB_ROUTE_PATH_FLAG_NONE);
3367 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3368 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3369 "4.4.4.4/32 present");
3371 fib_table_entry_delete(fib_index,
3374 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3375 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3376 "4.4.4.4/32 removed");
3379 * add-remove test. no change.
3381 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3382 fib_path_list_db_size());
3383 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3384 fib_path_list_pool_size());
3385 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3386 fib_entry_pool_size());
3389 * A route with multiple paths at once
3391 fib_route_path_t *r_paths = NULL;
3393 for (ii = 0; ii < 4; ii++)
3395 fib_route_path_t r_path = {
3396 .frp_proto = FIB_PROTOCOL_IP4,
3398 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3400 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3402 .frp_fib_index = ~0,
3404 vec_add1(r_paths, r_path);
3407 fib_table_entry_update(fib_index,
3410 FIB_ENTRY_FLAG_NONE,
3413 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3414 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3415 dpo = fib_entry_contribute_ip_forwarding(fei);
3417 lb = load_balance_get(dpo->dpoi_index);
3418 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3420 fib_table_entry_delete(fib_index,
3423 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3424 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3425 "4.4.4.4/32 removed");
3429 * add-remove test. no change.
3431 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3432 fib_path_list_db_size());
3433 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3434 fib_path_list_pool_size());
3435 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3436 fib_entry_pool_size());
3439 * A route deag route
3441 fib_table_entry_path_add(fib_index,
3444 FIB_ENTRY_FLAG_NONE,
3451 FIB_ROUTE_PATH_FLAG_NONE);
3453 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3454 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3456 dpo = fib_entry_contribute_ip_forwarding(fei);
3457 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3458 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3460 FIB_TEST((fib_index == lkd->lkd_fib_index),
3461 "4.4.4.4/32 is deag in %d %U",
3463 format_dpo_id, dpo, 0);
3465 fib_table_entry_delete(fib_index,
3468 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3469 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3470 "4.4.4.4/32 removed");
3474 * add-remove test. no change.
3476 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3477 fib_path_list_db_size());
3478 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3479 fib_path_list_pool_size());
3480 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3481 fib_entry_pool_size());
3485 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3487 fib_prefix_t pfx_34_1_1_1_s_32 = {
3489 .fp_proto = FIB_PROTOCOL_IP4,
3491 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3494 fib_prefix_t pfx_34_34_1_1_s_32 = {
3496 .fp_proto = FIB_PROTOCOL_IP4,
3498 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3501 fei = fib_table_entry_path_add(fib_index,
3504 FIB_ENTRY_FLAG_NONE,
3506 &pfx_34_34_1_1_s_32.fp_addr,
3511 FIB_ROUTE_PATH_FLAG_NONE);
3512 fei = fib_table_entry_path_add(fib_index,
3515 FIB_ENTRY_FLAG_NONE,
3517 &pfx_34_34_1_1_s_32.fp_addr,
3522 FIB_ROUTE_PATH_FLAG_NONE);
3523 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3524 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3528 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3529 * all of which are via 10.10.10.1, Itf1
3531 fib_table_entry_path_remove(fib_index,
3536 tm->hw[0]->sw_if_index,
3539 FIB_ROUTE_PATH_FLAG_NONE);
3540 fib_table_entry_path_remove(fib_index,
3545 tm->hw[0]->sw_if_index,
3548 FIB_ROUTE_PATH_FLAG_NONE);
3549 fib_table_entry_path_remove(fib_index,
3554 tm->hw[0]->sw_if_index,
3557 FIB_ROUTE_PATH_FLAG_NONE);
3559 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3560 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3561 "1.1.1.1/32 removed");
3562 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3563 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3564 "1.1.1.2/32 removed");
3565 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3566 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3567 "1.1.2.0/24 removed");
3570 * -3 entries and -1 shared path-list
3572 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3573 fib_path_list_db_size());
3574 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3575 fib_path_list_pool_size());
3576 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3577 fib_entry_pool_size());
3580 * An attached-host route. Expect to link to the incomplete adj
3582 fib_prefix_t pfx_4_1_1_1_s_32 = {
3584 .fp_proto = FIB_PROTOCOL_IP4,
3587 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3590 fib_table_entry_path_add(fib_index,
3593 FIB_ENTRY_FLAG_NONE,
3596 tm->hw[0]->sw_if_index,
3600 FIB_ROUTE_PATH_FLAG_NONE);
3602 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3603 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3604 ai = fib_entry_get_adj(fei);
3606 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3608 &pfx_4_1_1_1_s_32.fp_addr,
3609 tm->hw[0]->sw_if_index);
3610 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3614 * +1 entry and +1 shared path-list
3616 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3617 fib_path_list_db_size());
3618 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3619 fib_path_list_pool_size());
3620 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3621 fib_entry_pool_size());
3623 fib_table_entry_delete(fib_index,
3627 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3628 fib_path_list_db_size());
3629 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3630 fib_path_list_pool_size());
3631 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3632 fib_entry_pool_size());
3635 * add a v6 prefix via v4 next-hops
3637 fib_prefix_t pfx_2001_s_64 = {
3639 .fp_proto = FIB_PROTOCOL_IP6,
3641 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3644 fei = fib_table_entry_path_add(0, //default v6 table
3647 FIB_ENTRY_FLAG_NONE,
3650 tm->hw[0]->sw_if_index,
3654 FIB_ROUTE_PATH_FLAG_NONE);
3656 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3657 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3658 ai = fib_entry_get_adj(fei);
3660 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3661 "2001::/64 via ARP-adj");
3662 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3663 "2001::/64 is link type v6");
3664 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3665 "2001::/64 ADJ-adj is NH proto v4");
3666 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3669 * add a uRPF exempt prefix:
3671 * - it's forwarding is drop
3672 * - it's uRPF list is not empty
3673 * - the uRPF list for the default route (it's cover) is empty
3675 fei = fib_table_entry_special_add(fib_index,
3677 FIB_SOURCE_URPF_EXEMPT,
3678 FIB_ENTRY_FLAG_DROP,
3680 dpo = fib_entry_contribute_ip_forwarding(fei);
3681 FIB_TEST(load_balance_is_drop(dpo),
3682 "uRPF exempt 4.1.1.1/32 DROP");
3683 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3684 "uRPF list for exempt prefix has itf index 0");
3685 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3686 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3687 "uRPF list for 0.0.0.0/0 empty");
3689 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3692 * An adj-fib that fails the refinement criteria - no connected cover
3694 fib_prefix_t pfx_12_10_10_2_s_32 = {
3696 .fp_proto = FIB_PROTOCOL_IP4,
3699 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3703 fib_table_entry_update_one_path(fib_index,
3704 &pfx_12_10_10_2_s_32,
3706 FIB_ENTRY_FLAG_ATTACHED,
3708 &pfx_12_10_10_2_s_32.fp_addr,
3709 tm->hw[0]->sw_if_index,
3710 ~0, // invalid fib index
3713 FIB_ROUTE_PATH_FLAG_NONE);
3715 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3716 dpo = fib_entry_contribute_ip_forwarding(fei);
3717 FIB_TEST(!dpo_id_is_valid(dpo),
3718 "no connected cover adj-fib fails refinement");
3720 fib_table_entry_delete(fib_index,
3721 &pfx_12_10_10_2_s_32,
3725 * An adj-fib that fails the refinement criteria - cover is connected
3726 * but on a different interface
3728 fib_prefix_t pfx_10_10_10_127_s_32 = {
3730 .fp_proto = FIB_PROTOCOL_IP4,
3733 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3737 fib_table_entry_update_one_path(fib_index,
3738 &pfx_10_10_10_127_s_32,
3740 FIB_ENTRY_FLAG_ATTACHED,
3742 &pfx_10_10_10_127_s_32.fp_addr,
3743 tm->hw[1]->sw_if_index,
3744 ~0, // invalid fib index
3747 FIB_ROUTE_PATH_FLAG_NONE);
3749 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3750 dpo = fib_entry_contribute_ip_forwarding(fei);
3751 FIB_TEST(!dpo_id_is_valid(dpo),
3752 "wrong interface adj-fib fails refinement");
3754 fib_table_entry_delete(fib_index,
3755 &pfx_10_10_10_127_s_32,
3762 fib_table_entry_delete(fib_index,
3763 &pfx_10_10_10_1_s_32,
3765 fib_table_entry_delete(fib_index,
3766 &pfx_10_10_10_2_s_32,
3768 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3769 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
3770 "10.10.10.1/32 adj-fib removed");
3771 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3772 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
3773 "10.10.10.2/32 adj-fib removed");
3776 * -2 entries and -2 non-shared path-list
3778 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3779 fib_path_list_db_size());
3780 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
3781 fib_path_list_pool_size());
3782 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
3783 fib_entry_pool_size());
3786 * unlock the adjacencies for which this test provided a rewrite.
3787 * These are the last locks on these adjs. they should thus go away.
3791 adj_unlock(ai_12_12_12_12);
3793 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3798 * remove the interface prefixes
3800 local_pfx.fp_len = 32;
3801 fib_table_entry_special_remove(fib_index, &local_pfx,
3802 FIB_SOURCE_INTERFACE);
3803 fei = fib_table_lookup(fib_index, &local_pfx);
3805 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3806 fib_table_lookup_exact_match(fib_index, &local_pfx),
3807 "10.10.10.10/32 adj-fib removed");
3809 local_pfx.fp_len = 24;
3810 fib_table_entry_delete(fib_index, &local_pfx,
3811 FIB_SOURCE_INTERFACE);
3813 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3814 fib_table_lookup_exact_match(fib_index, &local_pfx),
3815 "10.10.10.10/24 adj-fib removed");
3818 * -2 entries and -2 non-shared path-list
3820 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3821 fib_path_list_db_size());
3822 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
3823 fib_path_list_pool_size());
3824 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
3825 fib_entry_pool_size());
3828 * Last but not least, remove the VRF
3830 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3833 "NO API Source'd prefixes");
3834 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3837 "NO RR Source'd prefixes");
3838 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3840 FIB_SOURCE_INTERFACE)),
3841 "NO INterface Source'd prefixes");
3843 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
3845 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3846 fib_path_list_db_size());
3847 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
3848 fib_path_list_pool_size());
3849 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
3850 fib_entry_pool_size());
3851 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
3852 pool_elts(fib_urpf_list_pool));
3861 * In the default table check for the presence and correct forwarding
3862 * of the special entries
3864 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
3865 const dpo_id_t *dpo, *dpo_drop;
3866 const ip_adjacency_t *adj;
3867 const receive_dpo_t *rd;
3872 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3875 /* via 2001:0:0:1::2 */
3876 ip46_address_t nh_2001_2 = {
3879 [0] = clib_host_to_net_u64(0x2001000000000001),
3880 [1] = clib_host_to_net_u64(0x0000000000000002),
3887 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
3889 /* Find or create FIB table 11 */
3890 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
3892 for (ii = 0; ii < 4; ii++)
3894 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
3897 fib_prefix_t pfx_0_0 = {
3899 .fp_proto = FIB_PROTOCOL_IP6,
3907 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
3908 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
3909 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
3910 "Default route is DROP");
3912 dpo = fib_entry_contribute_ip_forwarding(dfrt);
3913 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3916 &pfx_0_0.fp_addr.ip6)),
3917 "default-route; fwd and non-fwd tables match");
3919 // FIXME - check specials.
3922 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
3923 * each with 2 entries and a v6 mfib with 4 path-lists.
3924 * All entries are special so no path-list sharing.
3927 #define PNPS (5+4+4)
3928 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
3929 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
3930 fib_path_list_pool_size());
3931 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
3932 fib_entry_pool_size());
3935 * add interface routes.
3936 * validate presence of /64 attached and /128 recieve.
3937 * test for the presence of the receive address in the glean and local adj
3939 * receive on 2001:0:0:1::1/128
3941 fib_prefix_t local_pfx = {
3943 .fp_proto = FIB_PROTOCOL_IP6,
3947 [0] = clib_host_to_net_u64(0x2001000000000001),
3948 [1] = clib_host_to_net_u64(0x0000000000000001),
3954 fib_table_entry_update_one_path(fib_index, &local_pfx,
3955 FIB_SOURCE_INTERFACE,
3956 (FIB_ENTRY_FLAG_CONNECTED |
3957 FIB_ENTRY_FLAG_ATTACHED),
3960 tm->hw[0]->sw_if_index,
3964 FIB_ROUTE_PATH_FLAG_NONE);
3965 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
3967 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
3969 ai = fib_entry_get_adj(fei);
3970 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
3972 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
3973 "attached interface adj is glean");
3974 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
3975 &adj->sub_type.glean.receive_addr)),
3976 "attached interface adj is receive ok");
3977 dpo = fib_entry_contribute_ip_forwarding(fei);
3978 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
3981 &local_pfx.fp_addr.ip6)),
3982 "attached-route; fwd and non-fwd tables match");
3984 local_pfx.fp_len = 128;
3985 fib_table_entry_update_one_path(fib_index, &local_pfx,
3986 FIB_SOURCE_INTERFACE,
3987 (FIB_ENTRY_FLAG_CONNECTED |
3988 FIB_ENTRY_FLAG_LOCAL),
3991 tm->hw[0]->sw_if_index,
3992 ~0, // invalid fib index
3995 FIB_ROUTE_PATH_FLAG_NONE);
3996 fei = fib_table_lookup(fib_index, &local_pfx);
3998 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4000 dpo = fib_entry_contribute_ip_forwarding(fei);
4001 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4002 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4003 "local interface adj is local");
4004 rd = receive_dpo_get(dpo->dpoi_index);
4006 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4008 "local interface adj is receive ok");
4010 dpo = fib_entry_contribute_ip_forwarding(fei);
4011 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4014 &local_pfx.fp_addr.ip6)),
4015 "local-route; fwd and non-fwd tables match");
4018 * +2 entries. +2 unshared path-lists
4020 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4021 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4022 fib_path_list_pool_size());
4023 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4024 fib_entry_pool_size());
4027 * Modify the default route to be via an adj not yet known.
4028 * this sources the defalut route with the API source, which is
4029 * a higher preference to the DEFAULT_ROUTE source
4031 fib_table_entry_path_add(fib_index, &pfx_0_0,
4033 FIB_ENTRY_FLAG_NONE,
4036 tm->hw[0]->sw_if_index,
4040 FIB_ROUTE_PATH_FLAG_NONE);
4041 fei = fib_table_lookup(fib_index, &pfx_0_0);
4043 FIB_TEST((fei == dfrt), "default route same index");
4044 ai = fib_entry_get_adj(fei);
4045 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4047 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4048 "adj is incomplete");
4049 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4050 "adj nbr next-hop ok");
4053 * find the adj in the shared db
4055 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4058 tm->hw[0]->sw_if_index);
4059 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4060 adj_unlock(locked_ai);
4063 * no more entires. +1 shared path-list
4065 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4066 fib_path_list_db_size());
4067 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4068 fib_path_list_pool_size());
4069 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4070 fib_entry_pool_size());
4073 * remove the API source from the default route. We expected
4074 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4076 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4080 tm->hw[0]->sw_if_index,
4083 FIB_ROUTE_PATH_FLAG_NONE);
4084 fei = fib_table_lookup(fib_index, &pfx_0_0);
4086 FIB_TEST((fei == dfrt), "default route same index");
4087 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4088 "Default route is DROP");
4091 * no more entires. -1 shared path-list
4093 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4094 fib_path_list_db_size());
4095 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4096 fib_path_list_pool_size());
4097 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4098 fib_entry_pool_size());
4101 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4103 fib_prefix_t pfx_2001_1_2_s_128 = {
4105 .fp_proto = FIB_PROTOCOL_IP6,
4109 [0] = clib_host_to_net_u64(0x2001000000000001),
4110 [1] = clib_host_to_net_u64(0x0000000000000002),
4115 fib_prefix_t pfx_2001_1_3_s_128 = {
4117 .fp_proto = FIB_PROTOCOL_IP6,
4121 [0] = clib_host_to_net_u64(0x2001000000000001),
4122 [1] = clib_host_to_net_u64(0x0000000000000003),
4128 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4131 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4133 &pfx_2001_1_2_s_128.fp_addr,
4134 tm->hw[0]->sw_if_index);
4135 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4136 adj = adj_get(ai_01);
4137 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4138 "adj is incomplete");
4139 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4140 &adj->sub_type.nbr.next_hop)),
4141 "adj nbr next-hop ok");
4143 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4144 fib_test_build_rewrite(eth_addr));
4145 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
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 fib_table_entry_update_one_path(fib_index,
4152 &pfx_2001_1_2_s_128,
4154 FIB_ENTRY_FLAG_ATTACHED,
4156 &pfx_2001_1_2_s_128.fp_addr,
4157 tm->hw[0]->sw_if_index,
4161 FIB_ROUTE_PATH_FLAG_NONE);
4163 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4164 ai = fib_entry_get_adj(fei);
4165 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4169 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4171 &pfx_2001_1_3_s_128.fp_addr,
4172 tm->hw[0]->sw_if_index);
4173 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4174 adj = adj_get(ai_02);
4175 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4176 "adj is incomplete");
4177 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4178 &adj->sub_type.nbr.next_hop)),
4179 "adj nbr next-hop ok");
4181 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4182 fib_test_build_rewrite(eth_addr));
4183 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
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");
4188 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4190 fib_table_entry_update_one_path(fib_index,
4191 &pfx_2001_1_3_s_128,
4193 FIB_ENTRY_FLAG_ATTACHED,
4195 &pfx_2001_1_3_s_128.fp_addr,
4196 tm->hw[0]->sw_if_index,
4200 FIB_ROUTE_PATH_FLAG_NONE);
4202 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4203 ai = fib_entry_get_adj(fei);
4204 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4207 * +2 entries, +2 unshread path-lists.
4209 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4210 fib_path_list_db_size());
4211 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4212 fib_path_list_pool_size());
4213 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4214 fib_entry_pool_size());
4217 * Add a 2 routes via the first ADJ. ensure path-list sharing
4219 fib_prefix_t pfx_2001_a_s_64 = {
4221 .fp_proto = FIB_PROTOCOL_IP6,
4225 [0] = clib_host_to_net_u64(0x200100000000000a),
4226 [1] = clib_host_to_net_u64(0x0000000000000000),
4231 fib_prefix_t pfx_2001_b_s_64 = {
4233 .fp_proto = FIB_PROTOCOL_IP6,
4237 [0] = clib_host_to_net_u64(0x200100000000000b),
4238 [1] = clib_host_to_net_u64(0x0000000000000000),
4244 fib_table_entry_path_add(fib_index,
4247 FIB_ENTRY_FLAG_NONE,
4250 tm->hw[0]->sw_if_index,
4254 FIB_ROUTE_PATH_FLAG_NONE);
4255 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4256 ai = fib_entry_get_adj(fei);
4257 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4258 fib_table_entry_path_add(fib_index,
4261 FIB_ENTRY_FLAG_NONE,
4264 tm->hw[0]->sw_if_index,
4268 FIB_ROUTE_PATH_FLAG_NONE);
4269 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4270 ai = fib_entry_get_adj(fei);
4271 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4274 * +2 entries, +1 shared path-list.
4276 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4277 fib_path_list_db_size());
4278 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4279 fib_path_list_pool_size());
4280 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4281 fib_entry_pool_size());
4284 * add a v4 prefix via a v6 next-hop
4286 fib_prefix_t pfx_1_1_1_1_s_32 = {
4288 .fp_proto = FIB_PROTOCOL_IP4,
4290 .ip4.as_u32 = 0x01010101,
4293 fei = fib_table_entry_path_add(0, // default table
4296 FIB_ENTRY_FLAG_NONE,
4299 tm->hw[0]->sw_if_index,
4303 FIB_ROUTE_PATH_FLAG_NONE);
4304 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4305 "1.1.1.1/32 o v6 route present");
4306 ai = fib_entry_get_adj(fei);
4308 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4309 "1.1.1.1/32 via ARP-adj");
4310 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4311 "1.1.1.1/32 ADJ-adj is link type v4");
4312 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4313 "1.1.1.1/32 ADJ-adj is NH proto v6");
4314 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4319 fib_prefix_t pfx_2001_c_s_64 = {
4321 .fp_proto = FIB_PROTOCOL_IP6,
4325 [0] = clib_host_to_net_u64(0x200100000000000c),
4326 [1] = clib_host_to_net_u64(0x0000000000000000),
4331 fib_table_entry_path_add(fib_index,
4334 FIB_ENTRY_FLAG_ATTACHED,
4337 tm->hw[0]->sw_if_index,
4341 FIB_ROUTE_PATH_FLAG_NONE);
4342 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4343 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4344 ai = fib_entry_get_adj(fei);
4346 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4347 "2001:0:0:c/64 attached resolves via glean");
4349 fib_table_entry_path_remove(fib_index,
4354 tm->hw[0]->sw_if_index,
4357 FIB_ROUTE_PATH_FLAG_NONE);
4358 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4359 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4362 * Shutdown the interface on which we have a connected and through
4363 * which the routes are reachable.
4364 * This will result in the connected, adj-fibs, and routes linking to drop
4365 * The local/for-us prefix continues to receive.
4367 clib_error_t * error;
4369 error = vnet_sw_interface_set_flags(vnet_get_main(),
4370 tm->hw[0]->sw_if_index,
4371 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4372 FIB_TEST((NULL == error), "Interface shutdown OK");
4374 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4375 dpo = fib_entry_contribute_ip_forwarding(fei);
4376 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4377 "2001::b/64 resolves via drop");
4379 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4380 dpo = fib_entry_contribute_ip_forwarding(fei);
4381 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4382 "2001::a/64 resolves via drop");
4383 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4384 dpo = fib_entry_contribute_ip_forwarding(fei);
4385 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4386 "2001:0:0:1::3/64 resolves via drop");
4387 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
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:0:0:1::2/64 resolves via drop");
4391 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
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::1/128 not drop");
4395 local_pfx.fp_len = 64;
4396 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4397 dpo = fib_entry_contribute_ip_forwarding(fei);
4398 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4399 "2001:0:0:1/64 resolves via drop");
4404 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4405 fib_path_list_db_size());
4406 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4407 fib_path_list_pool_size());
4408 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4409 fib_entry_pool_size());
4412 * shutdown one of the other interfaces, then add a connected.
4413 * and swap one of the routes to it.
4415 error = vnet_sw_interface_set_flags(vnet_get_main(),
4416 tm->hw[1]->sw_if_index,
4417 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4418 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4420 fib_prefix_t connected_pfx = {
4422 .fp_proto = FIB_PROTOCOL_IP6,
4425 /* 2001:0:0:2::1/64 */
4427 [0] = clib_host_to_net_u64(0x2001000000000002),
4428 [1] = clib_host_to_net_u64(0x0000000000000001),
4433 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4434 FIB_SOURCE_INTERFACE,
4435 (FIB_ENTRY_FLAG_CONNECTED |
4436 FIB_ENTRY_FLAG_ATTACHED),
4439 tm->hw[1]->sw_if_index,
4443 FIB_ROUTE_PATH_FLAG_NONE);
4444 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4445 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4446 dpo = fib_entry_contribute_ip_forwarding(fei);
4447 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4448 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4449 "2001:0:0:2/64 not resolves via drop");
4451 connected_pfx.fp_len = 128;
4452 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4453 FIB_SOURCE_INTERFACE,
4454 (FIB_ENTRY_FLAG_CONNECTED |
4455 FIB_ENTRY_FLAG_LOCAL),
4458 tm->hw[0]->sw_if_index,
4459 ~0, // invalid fib index
4462 FIB_ROUTE_PATH_FLAG_NONE);
4463 fei = fib_table_lookup(fib_index, &connected_pfx);
4465 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4466 dpo = fib_entry_contribute_ip_forwarding(fei);
4467 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4468 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4469 "local interface adj is local");
4470 rd = receive_dpo_get(dpo->dpoi_index);
4471 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4473 "local interface adj is receive ok");
4476 * +2 entries, +2 unshared path-lists
4478 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4479 fib_path_list_db_size());
4480 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4481 fib_path_list_pool_size());
4482 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4483 fib_entry_pool_size());
4487 * bring the interface back up. we expected the routes to return
4488 * to normal forwarding.
4490 error = vnet_sw_interface_set_flags(vnet_get_main(),
4491 tm->hw[0]->sw_if_index,
4492 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4493 FIB_TEST((NULL == error), "Interface bring-up OK");
4494 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4495 ai = fib_entry_get_adj(fei);
4496 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4497 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4498 ai = fib_entry_get_adj(fei);
4499 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4500 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4501 ai = fib_entry_get_adj(fei);
4502 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4503 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4504 ai = fib_entry_get_adj(fei);
4505 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4506 local_pfx.fp_len = 64;
4507 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4508 ai = fib_entry_get_adj(fei);
4510 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4511 "attached interface adj is glean");
4514 * Same test as above, but this time the HW interface goes down
4516 error = vnet_hw_interface_set_flags(vnet_get_main(),
4517 tm->hw_if_indicies[0],
4518 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4519 FIB_TEST((NULL == error), "Interface shutdown OK");
4521 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4522 dpo = fib_entry_contribute_ip_forwarding(fei);
4523 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4524 "2001::b/64 resolves via drop");
4525 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4526 dpo = fib_entry_contribute_ip_forwarding(fei);
4527 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4528 "2001::a/64 resolves via drop");
4529 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
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:0:0:1::3/128 resolves via drop");
4533 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
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:0:0:1::2/128 resolves via drop");
4537 local_pfx.fp_len = 128;
4538 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4539 dpo = fib_entry_contribute_ip_forwarding(fei);
4540 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4541 "2001:0:0:1::1/128 not drop");
4542 local_pfx.fp_len = 64;
4543 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4544 dpo = fib_entry_contribute_ip_forwarding(fei);
4545 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4546 "2001:0:0:1/64 resolves via drop");
4548 error = vnet_hw_interface_set_flags(vnet_get_main(),
4549 tm->hw_if_indicies[0],
4550 VNET_HW_INTERFACE_FLAG_LINK_UP);
4551 FIB_TEST((NULL == error), "Interface bring-up OK");
4552 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4553 ai = fib_entry_get_adj(fei);
4554 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4555 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4556 ai = fib_entry_get_adj(fei);
4557 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4558 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4559 ai = fib_entry_get_adj(fei);
4560 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4561 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4562 ai = fib_entry_get_adj(fei);
4563 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4564 local_pfx.fp_len = 64;
4565 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4566 ai = fib_entry_get_adj(fei);
4568 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4569 "attached interface adj is glean");
4572 * Delete the interface that the routes reolve through.
4573 * Again no routes are removed. They all point to drop.
4575 * This is considered an error case. The control plane should
4576 * not remove interfaces through which routes resolve, but
4577 * such things can happen. ALL affected routes will drop.
4579 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4581 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4582 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4583 "2001::b/64 resolves via drop");
4584 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4585 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4586 "2001::b/64 resolves via drop");
4587 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4588 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4589 "2001:0:0:1::3/64 resolves via drop");
4590 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4591 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4592 "2001:0:0:1::2/64 resolves via drop");
4593 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4594 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4595 "2001:0:0:1::1/128 is drop");
4596 local_pfx.fp_len = 64;
4597 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4598 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4599 "2001:0:0:1/64 resolves via drop");
4604 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4605 fib_path_list_db_size());
4606 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4607 fib_path_list_pool_size());
4608 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4609 fib_entry_pool_size());
4612 * Add the interface back. routes stay unresolved.
4614 error = ethernet_register_interface(vnet_get_main(),
4615 test_interface_device_class.index,
4618 &tm->hw_if_indicies[0],
4619 /* flag change */ 0);
4621 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4622 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4623 "2001::b/64 resolves via drop");
4624 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4625 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4626 "2001::b/64 resolves via drop");
4627 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4628 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4629 "2001:0:0:1::3/64 resolves via drop");
4630 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4631 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4632 "2001:0:0:1::2/64 resolves via drop");
4633 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4634 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4635 "2001:0:0:1::1/128 is drop");
4636 local_pfx.fp_len = 64;
4637 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4638 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4639 "2001:0:0:1/64 resolves via drop");
4642 * CLEANUP ALL the routes
4644 fib_table_entry_delete(fib_index,
4647 fib_table_entry_delete(fib_index,
4650 fib_table_entry_delete(fib_index,
4653 fib_table_entry_delete(fib_index,
4654 &pfx_2001_1_3_s_128,
4656 fib_table_entry_delete(fib_index,
4657 &pfx_2001_1_2_s_128,
4659 local_pfx.fp_len = 64;
4660 fib_table_entry_delete(fib_index, &local_pfx,
4661 FIB_SOURCE_INTERFACE);
4662 local_pfx.fp_len = 128;
4663 fib_table_entry_special_remove(fib_index, &local_pfx,
4664 FIB_SOURCE_INTERFACE);
4665 connected_pfx.fp_len = 64;
4666 fib_table_entry_delete(fib_index, &connected_pfx,
4667 FIB_SOURCE_INTERFACE);
4668 connected_pfx.fp_len = 128;
4669 fib_table_entry_special_remove(fib_index, &connected_pfx,
4670 FIB_SOURCE_INTERFACE);
4672 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4673 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4674 "2001::a/64 removed");
4675 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4676 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4677 "2001::b/64 removed");
4678 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4679 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4680 "2001:0:0:1::3/128 removed");
4681 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4682 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4683 "2001:0:0:1::3/128 removed");
4684 local_pfx.fp_len = 64;
4685 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4686 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4687 "2001:0:0:1/64 removed");
4688 local_pfx.fp_len = 128;
4689 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4690 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4691 "2001:0:0:1::1/128 removed");
4692 connected_pfx.fp_len = 64;
4693 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4694 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4695 "2001:0:0:2/64 removed");
4696 connected_pfx.fp_len = 128;
4697 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4698 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4699 "2001:0:0:2::1/128 removed");
4702 * -8 entries. -7 path-lists (1 was shared).
4704 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4705 fib_path_list_db_size());
4706 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
4707 fib_path_list_pool_size());
4708 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4709 fib_entry_pool_size());
4712 * now remove the VRF
4714 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4716 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4717 fib_path_list_db_size());
4718 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
4719 fib_path_list_pool_size());
4720 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
4721 fib_entry_pool_size());
4727 * return the interfaces to up state
4729 error = vnet_sw_interface_set_flags(vnet_get_main(),
4730 tm->hw[0]->sw_if_index,
4731 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4732 error = vnet_sw_interface_set_flags(vnet_get_main(),
4733 tm->hw[1]->sw_if_index,
4734 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4736 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4743 * Test Attached Exports
4748 const dpo_id_t *dpo, *dpo_drop;
4749 const u32 fib_index = 0;
4750 fib_node_index_t fei;
4757 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4761 * add interface routes. We'll assume this works. It's more rigorously
4764 fib_prefix_t local_pfx = {
4766 .fp_proto = FIB_PROTOCOL_IP4,
4770 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4775 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4776 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4778 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4780 fib_table_entry_update_one_path(fib_index, &local_pfx,
4781 FIB_SOURCE_INTERFACE,
4782 (FIB_ENTRY_FLAG_CONNECTED |
4783 FIB_ENTRY_FLAG_ATTACHED),
4786 tm->hw[0]->sw_if_index,
4790 FIB_ROUTE_PATH_FLAG_NONE);
4791 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4792 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4793 "attached interface route present");
4795 local_pfx.fp_len = 32;
4796 fib_table_entry_update_one_path(fib_index, &local_pfx,
4797 FIB_SOURCE_INTERFACE,
4798 (FIB_ENTRY_FLAG_CONNECTED |
4799 FIB_ENTRY_FLAG_LOCAL),
4802 tm->hw[0]->sw_if_index,
4803 ~0, // invalid fib index
4806 FIB_ROUTE_PATH_FLAG_NONE);
4807 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4809 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4810 "local interface route present");
4813 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4815 fib_prefix_t pfx_10_10_10_1_s_32 = {
4817 .fp_proto = FIB_PROTOCOL_IP4,
4820 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4823 fib_node_index_t ai;
4825 fib_table_entry_update_one_path(fib_index,
4826 &pfx_10_10_10_1_s_32,
4828 FIB_ENTRY_FLAG_ATTACHED,
4830 &pfx_10_10_10_1_s_32.fp_addr,
4831 tm->hw[0]->sw_if_index,
4832 ~0, // invalid fib index
4835 FIB_ROUTE_PATH_FLAG_NONE);
4837 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4838 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4839 ai = fib_entry_get_adj(fei);
4842 * create another FIB table into which routes will be imported
4844 u32 import_fib_index1;
4846 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4849 * Add an attached route in the import FIB
4851 local_pfx.fp_len = 24;
4852 fib_table_entry_update_one_path(import_fib_index1,
4855 FIB_ENTRY_FLAG_NONE,
4858 tm->hw[0]->sw_if_index,
4859 ~0, // invalid fib index
4862 FIB_ROUTE_PATH_FLAG_NONE);
4863 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4864 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4867 * check for the presence of the adj-fibs in the import table
4869 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4870 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4871 FIB_TEST((ai == fib_entry_get_adj(fei)),
4872 "adj-fib1 Import uses same adj as export");
4875 * check for the presence of the local in the import table
4877 local_pfx.fp_len = 32;
4878 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4879 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4882 * Add another adj-fin in the export table. Expect this
4883 * to get magically exported;
4885 fib_prefix_t pfx_10_10_10_2_s_32 = {
4887 .fp_proto = FIB_PROTOCOL_IP4,
4890 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4894 fib_table_entry_update_one_path(fib_index,
4895 &pfx_10_10_10_2_s_32,
4897 FIB_ENTRY_FLAG_ATTACHED,
4899 &pfx_10_10_10_2_s_32.fp_addr,
4900 tm->hw[0]->sw_if_index,
4901 ~0, // invalid fib index
4904 FIB_ROUTE_PATH_FLAG_NONE);
4905 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
4906 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
4907 ai = fib_entry_get_adj(fei);
4909 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
4910 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4911 FIB_TEST((ai == fib_entry_get_adj(fei)),
4912 "Import uses same adj as export");
4913 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
4914 "ADJ-fib2 imported flags %d",
4915 fib_entry_get_flags(fei));
4918 * create a 2nd FIB table into which routes will be imported
4920 u32 import_fib_index2;
4922 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
4925 * Add an attached route in the import FIB
4927 local_pfx.fp_len = 24;
4928 fib_table_entry_update_one_path(import_fib_index2,
4931 FIB_ENTRY_FLAG_NONE,
4934 tm->hw[0]->sw_if_index,
4935 ~0, // invalid fib index
4938 FIB_ROUTE_PATH_FLAG_NONE);
4939 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4940 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4943 * check for the presence of all the adj-fibs and local in the import table
4945 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
4946 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4947 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
4948 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
4949 local_pfx.fp_len = 32;
4950 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
4951 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4954 * add a 3rd adj-fib. expect it to be exported to both tables.
4956 fib_prefix_t pfx_10_10_10_3_s_32 = {
4958 .fp_proto = FIB_PROTOCOL_IP4,
4961 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4965 fib_table_entry_update_one_path(fib_index,
4966 &pfx_10_10_10_3_s_32,
4968 FIB_ENTRY_FLAG_ATTACHED,
4970 &pfx_10_10_10_3_s_32.fp_addr,
4971 tm->hw[0]->sw_if_index,
4972 ~0, // invalid fib index
4975 FIB_ROUTE_PATH_FLAG_NONE);
4976 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4977 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
4978 ai = fib_entry_get_adj(fei);
4980 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
4981 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
4982 FIB_TEST((ai == fib_entry_get_adj(fei)),
4983 "Import uses same adj as export");
4984 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
4985 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
4986 FIB_TEST((ai == fib_entry_get_adj(fei)),
4987 "Import uses same adj as export");
4990 * remove the 3rd adj fib. we expect it to be removed from both FIBs
4992 fib_table_entry_delete(fib_index,
4993 &pfx_10_10_10_3_s_32,
4996 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4997 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
4999 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5000 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5002 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5003 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5006 * remove the attached route from the 2nd FIB. expect the imported
5007 * entires to be removed
5009 local_pfx.fp_len = 24;
5010 fib_table_entry_delete(import_fib_index2,
5013 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5014 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5016 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5017 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5018 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5019 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5020 local_pfx.fp_len = 32;
5021 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5022 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5024 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5025 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5026 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5027 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5028 local_pfx.fp_len = 32;
5029 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5030 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5033 * modify the route in FIB1 so it is no longer attached. expect the imported
5034 * entires to be removed
5036 local_pfx.fp_len = 24;
5037 fib_table_entry_update_one_path(import_fib_index1,
5040 FIB_ENTRY_FLAG_NONE,
5042 &pfx_10_10_10_2_s_32.fp_addr,
5043 tm->hw[0]->sw_if_index,
5044 ~0, // invalid fib index
5047 FIB_ROUTE_PATH_FLAG_NONE);
5048 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5049 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5050 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5051 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5052 local_pfx.fp_len = 32;
5053 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5054 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5057 * modify it back to attached. expect the adj-fibs back
5059 local_pfx.fp_len = 24;
5060 fib_table_entry_update_one_path(import_fib_index1,
5063 FIB_ENTRY_FLAG_NONE,
5066 tm->hw[0]->sw_if_index,
5067 ~0, // invalid fib index
5070 FIB_ROUTE_PATH_FLAG_NONE);
5071 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5072 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5073 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5074 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5075 local_pfx.fp_len = 32;
5076 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5077 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5080 * add a covering attached next-hop for the interface address, so we have
5081 * a valid adj to find when we check the forwarding tables
5083 fib_prefix_t pfx_10_0_0_0_s_8 = {
5085 .fp_proto = FIB_PROTOCOL_IP4,
5088 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5092 fei = fib_table_entry_update_one_path(fib_index,
5095 FIB_ENTRY_FLAG_NONE,
5097 &pfx_10_10_10_3_s_32.fp_addr,
5098 tm->hw[0]->sw_if_index,
5099 ~0, // invalid fib index
5102 FIB_ROUTE_PATH_FLAG_NONE);
5103 dpo = fib_entry_contribute_ip_forwarding(fei);
5106 * remove the route in the export fib. expect the adj-fibs to be removed
5108 local_pfx.fp_len = 24;
5109 fib_table_entry_delete(fib_index,
5111 FIB_SOURCE_INTERFACE);
5113 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5114 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5115 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5116 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5117 local_pfx.fp_len = 32;
5118 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5119 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5122 * the adj-fibs in the export VRF are present in the FIB table,
5123 * but not installed in forwarding, since they have no attached cover.
5124 * Consequently a lookup in the MTRIE gives the adj for the covering
5127 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5128 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5131 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5132 FIB_TEST(lbi == dpo->dpoi_index,
5133 "10.10.10.1 forwards on \n%U not \n%U",
5134 format_load_balance, lbi, 0,
5135 format_dpo_id, dpo, 0);
5136 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5137 FIB_TEST(lbi == dpo->dpoi_index,
5138 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5139 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5140 FIB_TEST(lbi == dpo->dpoi_index,
5141 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5144 * add the export prefix back, but not as attached.
5145 * No adj-fibs in export nor import tables
5147 local_pfx.fp_len = 24;
5148 fei = fib_table_entry_update_one_path(fib_index,
5151 FIB_ENTRY_FLAG_NONE,
5153 &pfx_10_10_10_1_s_32.fp_addr,
5154 tm->hw[0]->sw_if_index,
5155 ~0, // invalid fib index
5158 FIB_ROUTE_PATH_FLAG_NONE);
5159 dpo = fib_entry_contribute_ip_forwarding(fei);
5161 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5162 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5163 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5164 FIB_TEST(lbi == dpo->dpoi_index,
5165 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5166 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5167 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5168 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5169 FIB_TEST(lbi == dpo->dpoi_index,
5170 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5172 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5173 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5174 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5175 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5176 local_pfx.fp_len = 32;
5177 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5178 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5181 * modify the export prefix so it is attached. expect all covereds to return
5183 local_pfx.fp_len = 24;
5184 fib_table_entry_update_one_path(fib_index,
5187 FIB_ENTRY_FLAG_NONE,
5190 tm->hw[0]->sw_if_index,
5191 ~0, // invalid fib index
5194 FIB_ROUTE_PATH_FLAG_NONE);
5196 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5197 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5198 dpo = fib_entry_contribute_ip_forwarding(fei);
5199 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5200 "Adj-fib1 is not drop in export");
5201 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5202 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5203 local_pfx.fp_len = 32;
5204 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5205 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5206 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5207 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5208 dpo = fib_entry_contribute_ip_forwarding(fei);
5209 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5210 "Adj-fib1 is not drop in export");
5211 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5212 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5213 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5214 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5215 local_pfx.fp_len = 32;
5216 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5217 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5220 * modify the export prefix so connected. no change.
5222 local_pfx.fp_len = 24;
5223 fib_table_entry_update_one_path(fib_index, &local_pfx,
5224 FIB_SOURCE_INTERFACE,
5225 (FIB_ENTRY_FLAG_CONNECTED |
5226 FIB_ENTRY_FLAG_ATTACHED),
5229 tm->hw[0]->sw_if_index,
5233 FIB_ROUTE_PATH_FLAG_NONE);
5235 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5236 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5237 dpo = fib_entry_contribute_ip_forwarding(fei);
5238 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5239 "Adj-fib1 is not drop in export");
5240 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5241 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5242 local_pfx.fp_len = 32;
5243 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5244 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5245 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5246 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5247 dpo = fib_entry_contribute_ip_forwarding(fei);
5248 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5249 "Adj-fib1 is not drop in export");
5250 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5251 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5252 local_pfx.fp_len = 32;
5253 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5254 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5259 fib_table_entry_delete(fib_index,
5262 fib_table_entry_delete(fib_index,
5263 &pfx_10_10_10_1_s_32,
5265 fib_table_entry_delete(fib_index,
5266 &pfx_10_10_10_2_s_32,
5268 local_pfx.fp_len = 32;
5269 fib_table_entry_delete(fib_index,
5271 FIB_SOURCE_INTERFACE);
5272 local_pfx.fp_len = 24;
5273 fib_table_entry_delete(fib_index,
5276 fib_table_entry_delete(fib_index,
5278 FIB_SOURCE_INTERFACE);
5279 local_pfx.fp_len = 24;
5280 fib_table_entry_delete(import_fib_index1,
5284 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5285 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5287 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5295 * Test the recursive route route handling for GRE tunnels
5298 fib_test_label (void)
5300 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;
5301 const u32 fib_index = 0;
5306 lb_count = pool_elts(load_balance_pool);
5311 * add interface routes. We'll assume this works. It's more rigorously
5314 fib_prefix_t local0_pfx = {
5316 .fp_proto = FIB_PROTOCOL_IP4,
5320 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5325 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5328 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5329 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5331 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5332 FIB_SOURCE_INTERFACE,
5333 (FIB_ENTRY_FLAG_CONNECTED |
5334 FIB_ENTRY_FLAG_ATTACHED),
5337 tm->hw[0]->sw_if_index,
5341 FIB_ROUTE_PATH_FLAG_NONE);
5342 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5343 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5344 "attached interface route present");
5346 local0_pfx.fp_len = 32;
5347 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5348 FIB_SOURCE_INTERFACE,
5349 (FIB_ENTRY_FLAG_CONNECTED |
5350 FIB_ENTRY_FLAG_LOCAL),
5353 tm->hw[0]->sw_if_index,
5354 ~0, // invalid fib index
5357 FIB_ROUTE_PATH_FLAG_NONE);
5358 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5360 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5361 "local interface route present");
5363 fib_prefix_t local1_pfx = {
5365 .fp_proto = FIB_PROTOCOL_IP4,
5369 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5374 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5375 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5377 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5378 FIB_SOURCE_INTERFACE,
5379 (FIB_ENTRY_FLAG_CONNECTED |
5380 FIB_ENTRY_FLAG_ATTACHED),
5383 tm->hw[1]->sw_if_index,
5387 FIB_ROUTE_PATH_FLAG_NONE);
5388 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5389 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5390 "attached interface route present");
5392 local1_pfx.fp_len = 32;
5393 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5394 FIB_SOURCE_INTERFACE,
5395 (FIB_ENTRY_FLAG_CONNECTED |
5396 FIB_ENTRY_FLAG_LOCAL),
5399 tm->hw[1]->sw_if_index,
5400 ~0, // invalid fib index
5403 FIB_ROUTE_PATH_FLAG_NONE);
5404 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5406 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5407 "local interface route present");
5409 ip46_address_t nh_10_10_10_1 = {
5411 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5414 ip46_address_t nh_10_10_11_1 = {
5416 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5419 ip46_address_t nh_10_10_11_2 = {
5421 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5425 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5428 tm->hw[1]->sw_if_index);
5429 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5432 tm->hw[1]->sw_if_index);
5433 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5436 tm->hw[0]->sw_if_index);
5437 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5440 tm->hw[1]->sw_if_index);
5441 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5444 tm->hw[1]->sw_if_index);
5447 * Add an etry with one path with a real out-going label
5449 fib_prefix_t pfx_1_1_1_1_s_32 = {
5451 .fp_proto = FIB_PROTOCOL_IP4,
5453 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5456 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5457 .type = FT_LB_LABEL_O_ADJ,
5459 .adj = ai_mpls_10_10_10_1,
5464 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5465 .type = FT_LB_LABEL_O_ADJ,
5467 .adj = ai_mpls_10_10_10_1,
5469 .eos = MPLS_NON_EOS,
5472 mpls_label_t *l99 = NULL;
5475 fib_table_entry_update_one_path(fib_index,
5478 FIB_ENTRY_FLAG_NONE,
5481 tm->hw[0]->sw_if_index,
5482 ~0, // invalid fib index
5485 FIB_ROUTE_PATH_FLAG_NONE);
5487 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5488 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5490 FIB_TEST(fib_test_validate_entry(fei,
5491 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5493 &l99_eos_o_10_10_10_1),
5494 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5497 * add a path with an implicit NULL label
5499 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5502 .adj = ai_v4_10_10_11_1,
5505 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5508 .adj = ai_mpls_10_10_11_1,
5511 mpls_label_t *l_imp_null = NULL;
5512 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5514 fei = fib_table_entry_path_add(fib_index,
5517 FIB_ENTRY_FLAG_NONE,
5520 tm->hw[1]->sw_if_index,
5521 ~0, // invalid fib index
5524 FIB_ROUTE_PATH_FLAG_NONE);
5526 FIB_TEST(fib_test_validate_entry(fei,
5527 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5529 &l99_eos_o_10_10_10_1,
5531 "1.1.1.1/32 LB 2 buckets via: "
5532 "label 99 over 10.10.10.1, "
5533 "adj over 10.10.11.1");
5536 * assign the route a local label
5538 fib_table_entry_local_label_add(fib_index,
5542 fib_prefix_t pfx_24001_eos = {
5543 .fp_proto = FIB_PROTOCOL_MPLS,
5547 fib_prefix_t pfx_24001_neos = {
5548 .fp_proto = FIB_PROTOCOL_MPLS,
5550 .fp_eos = MPLS_NON_EOS,
5554 * The EOS entry should link to both the paths,
5555 * and use an ip adj for the imp-null
5556 * The NON-EOS entry should link to both the paths,
5557 * and use an mpls adj for the imp-null
5559 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5561 FIB_TEST(fib_test_validate_entry(fei,
5562 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5564 &l99_eos_o_10_10_10_1,
5566 "24001/eos LB 2 buckets via: "
5567 "label 99 over 10.10.10.1, "
5568 "adj over 10.10.11.1");
5571 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5573 FIB_TEST(fib_test_validate_entry(fei,
5574 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5576 &l99_neos_o_10_10_10_1,
5577 &a_mpls_o_10_10_11_1),
5578 "24001/neos LB 1 bucket via: "
5579 "label 99 over 10.10.10.1 ",
5580 "mpls-adj via 10.10.11.1");
5583 * add an unlabelled path, this is excluded from the neos chains,
5585 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5588 .adj = ai_v4_10_10_11_2,
5592 fei = fib_table_entry_path_add(fib_index,
5595 FIB_ENTRY_FLAG_NONE,
5598 tm->hw[1]->sw_if_index,
5599 ~0, // invalid fib index
5602 FIB_ROUTE_PATH_FLAG_NONE);
5604 FIB_TEST(fib_test_validate_entry(fei,
5605 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5606 16, // 3 choices spread over 16 buckets
5607 &l99_eos_o_10_10_10_1,
5608 &l99_eos_o_10_10_10_1,
5609 &l99_eos_o_10_10_10_1,
5610 &l99_eos_o_10_10_10_1,
5611 &l99_eos_o_10_10_10_1,
5612 &l99_eos_o_10_10_10_1,
5623 "1.1.1.1/32 LB 16 buckets via: "
5624 "label 99 over 10.10.10.1, "
5625 "adj over 10.10.11.1",
5626 "adj over 10.10.11.2");
5629 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5631 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5632 fib_entry_contribute_forwarding(fei,
5633 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5637 * n-eos has only the 2 labelled paths
5639 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5642 FIB_TEST(fib_test_validate_entry(fei,
5643 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5645 &l99_neos_o_10_10_10_1,
5646 &a_mpls_o_10_10_11_1),
5647 "24001/neos LB 2 buckets via: "
5648 "label 99 over 10.10.10.1, "
5649 "adj-mpls over 10.10.11.2");
5652 * A labelled recursive
5654 fib_prefix_t pfx_2_2_2_2_s_32 = {
5656 .fp_proto = FIB_PROTOCOL_IP4,
5658 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5661 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5662 .type = FT_LB_LABEL_O_LB,
5664 .lb = non_eos_1_1_1_1.dpoi_index,
5669 mpls_label_t *l1600 = NULL;
5670 vec_add1(l1600, 1600);
5672 fib_table_entry_update_one_path(fib_index,
5675 FIB_ENTRY_FLAG_NONE,
5677 &pfx_1_1_1_1_s_32.fp_addr,
5682 FIB_ROUTE_PATH_FLAG_NONE);
5684 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5685 FIB_TEST(fib_test_validate_entry(fei,
5686 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5688 &l1600_eos_o_1_1_1_1),
5689 "2.2.2.2.2/32 LB 1 buckets via: "
5690 "label 1600 over 1.1.1.1");
5692 dpo_id_t dpo_44 = DPO_INVALID;
5695 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5696 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5698 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5699 "uRPF check for 2.2.2.2/32 on %d OK",
5700 tm->hw[0]->sw_if_index);
5701 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5702 "uRPF check for 2.2.2.2/32 on %d OK",
5703 tm->hw[1]->sw_if_index);
5704 FIB_TEST(!fib_urpf_check(urpfi, 99),
5705 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5708 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5709 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5710 "Shared uRPF on IP and non-EOS chain");
5715 * we are holding a lock on the non-eos LB of the via-entry.
5716 * do a PIC-core failover by shutting the link of the via-entry.
5718 * shut down the link with the valid label
5720 vnet_sw_interface_set_flags(vnet_get_main(),
5721 tm->hw[0]->sw_if_index,
5724 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5725 FIB_TEST(fib_test_validate_entry(fei,
5726 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5730 "1.1.1.1/32 LB 2 buckets via: "
5731 "adj over 10.10.11.1, ",
5732 "adj-v4 over 10.10.11.2");
5734 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5736 FIB_TEST(fib_test_validate_entry(fei,
5737 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5741 "24001/eos LB 2 buckets via: "
5742 "adj over 10.10.11.1, ",
5743 "adj-v4 over 10.10.11.2");
5745 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5747 FIB_TEST(fib_test_validate_entry(fei,
5748 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5750 &a_mpls_o_10_10_11_1),
5751 "24001/neos LB 1 buckets via: "
5752 "adj-mpls over 10.10.11.2");
5755 * test that the pre-failover load-balance has been in-place
5758 dpo_id_t current = DPO_INVALID;
5759 fib_entry_contribute_forwarding(fei,
5760 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5763 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5765 "PIC-core LB inplace modified %U %U",
5766 format_dpo_id, &non_eos_1_1_1_1, 0,
5767 format_dpo_id, ¤t, 0);
5769 dpo_reset(&non_eos_1_1_1_1);
5770 dpo_reset(¤t);
5773 * no-shut the link with the valid label
5775 vnet_sw_interface_set_flags(vnet_get_main(),
5776 tm->hw[0]->sw_if_index,
5777 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5779 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5780 FIB_TEST(fib_test_validate_entry(fei,
5781 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5782 16, // 3 choices spread over 16 buckets
5783 &l99_eos_o_10_10_10_1,
5784 &l99_eos_o_10_10_10_1,
5785 &l99_eos_o_10_10_10_1,
5786 &l99_eos_o_10_10_10_1,
5787 &l99_eos_o_10_10_10_1,
5788 &l99_eos_o_10_10_10_1,
5799 "1.1.1.1/32 LB 16 buckets via: "
5800 "label 99 over 10.10.10.1, "
5801 "adj over 10.10.11.1",
5802 "adj-v4 over 10.10.11.2");
5805 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5807 FIB_TEST(fib_test_validate_entry(fei,
5808 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5809 16, // 3 choices spread over 16 buckets
5810 &l99_eos_o_10_10_10_1,
5811 &l99_eos_o_10_10_10_1,
5812 &l99_eos_o_10_10_10_1,
5813 &l99_eos_o_10_10_10_1,
5814 &l99_eos_o_10_10_10_1,
5815 &l99_eos_o_10_10_10_1,
5826 "24001/eos LB 16 buckets via: "
5827 "label 99 over 10.10.10.1, "
5828 "adj over 10.10.11.1",
5829 "adj-v4 over 10.10.11.2");
5831 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5833 FIB_TEST(fib_test_validate_entry(fei,
5834 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5836 &l99_neos_o_10_10_10_1,
5837 &a_mpls_o_10_10_11_1),
5838 "24001/neos LB 2 buckets via: "
5839 "label 99 over 10.10.10.1, "
5840 "adj-mpls over 10.10.11.2");
5843 * remove the first path with the valid label
5845 fib_table_entry_path_remove(fib_index,
5850 tm->hw[0]->sw_if_index,
5851 ~0, // invalid fib index
5853 FIB_ROUTE_PATH_FLAG_NONE);
5855 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5856 FIB_TEST(fib_test_validate_entry(fei,
5857 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5861 "1.1.1.1/32 LB 2 buckets via: "
5862 "adj over 10.10.11.1, "
5863 "adj-v4 over 10.10.11.2");
5865 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5867 FIB_TEST(fib_test_validate_entry(fei,
5868 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5872 "24001/eos LB 2 buckets via: "
5873 "adj over 10.10.11.1, "
5874 "adj-v4 over 10.10.11.2");
5876 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5879 FIB_TEST(fib_test_validate_entry(fei,
5880 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5882 &a_mpls_o_10_10_11_1),
5883 "24001/neos LB 1 buckets via: "
5884 "adj-mpls over 10.10.11.2");
5887 * remove the other path with a valid label
5889 fib_test_lb_bucket_t bucket_drop = {
5890 .type = FT_LB_SPECIAL,
5892 .adj = DPO_PROTO_IP4,
5896 fib_table_entry_path_remove(fib_index,
5901 tm->hw[1]->sw_if_index,
5902 ~0, // invalid fib index
5904 FIB_ROUTE_PATH_FLAG_NONE);
5906 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5907 FIB_TEST(fib_test_validate_entry(fei,
5908 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5911 "1.1.1.1/32 LB 1 buckets via: "
5912 "adj over 10.10.11.2");
5914 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5916 FIB_TEST(fib_test_validate_entry(fei,
5917 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5920 "24001/eos LB 1 buckets via: "
5921 "adj over 10.10.11.2");
5923 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5925 FIB_TEST(fib_test_validate_entry(fei,
5926 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5929 "24001/eos LB 1 buckets via: DROP");
5932 * add back the path with the valid label
5937 fib_table_entry_path_add(fib_index,
5940 FIB_ENTRY_FLAG_NONE,
5943 tm->hw[0]->sw_if_index,
5944 ~0, // invalid fib index
5947 FIB_ROUTE_PATH_FLAG_NONE);
5949 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5950 FIB_TEST(fib_test_validate_entry(fei,
5951 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5953 &l99_eos_o_10_10_10_1,
5955 "1.1.1.1/32 LB 2 buckets via: "
5956 "label 99 over 10.10.10.1, "
5957 "adj over 10.10.11.2");
5959 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5961 FIB_TEST(fib_test_validate_entry(fei,
5962 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5964 &l99_eos_o_10_10_10_1,
5966 "24001/eos LB 2 buckets via: "
5967 "label 99 over 10.10.10.1, "
5968 "adj over 10.10.11.2");
5970 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5972 FIB_TEST(fib_test_validate_entry(fei,
5973 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5975 &l99_neos_o_10_10_10_1),
5976 "24001/neos LB 1 buckets via: "
5977 "label 99 over 10.10.10.1");
5980 * change the local label
5982 fib_table_entry_local_label_add(fib_index,
5986 fib_prefix_t pfx_25005_eos = {
5987 .fp_proto = FIB_PROTOCOL_MPLS,
5991 fib_prefix_t pfx_25005_neos = {
5992 .fp_proto = FIB_PROTOCOL_MPLS,
5994 .fp_eos = MPLS_NON_EOS,
5997 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5998 fib_table_lookup(fib_index, &pfx_24001_eos)),
5999 "24001/eos removed after label change");
6000 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6001 fib_table_lookup(fib_index, &pfx_24001_neos)),
6002 "24001/eos removed after label change");
6004 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6006 FIB_TEST(fib_test_validate_entry(fei,
6007 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6009 &l99_eos_o_10_10_10_1,
6011 "25005/eos LB 2 buckets via: "
6012 "label 99 over 10.10.10.1, "
6013 "adj over 10.10.11.2");
6015 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6017 FIB_TEST(fib_test_validate_entry(fei,
6018 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6020 &l99_neos_o_10_10_10_1),
6021 "25005/neos LB 1 buckets via: "
6022 "label 99 over 10.10.10.1");
6025 * remove the local label.
6026 * the check that the MPLS entries are gone is done by the fact the
6027 * MPLS table is no longer present.
6029 fib_table_entry_local_label_remove(fib_index,
6033 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6034 FIB_TEST(fib_test_validate_entry(fei,
6035 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6037 &l99_eos_o_10_10_10_1,
6039 "24001/eos LB 2 buckets via: "
6040 "label 99 over 10.10.10.1, "
6041 "adj over 10.10.11.2");
6043 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6044 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6045 "No more MPLS FIB entries => table removed");
6048 * add another via-entry for the recursive
6050 fib_prefix_t pfx_1_1_1_2_s_32 = {
6052 .fp_proto = FIB_PROTOCOL_IP4,
6054 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6057 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6058 .type = FT_LB_LABEL_O_ADJ,
6060 .adj = ai_mpls_10_10_10_1,
6065 mpls_label_t *l101 = NULL;
6066 vec_add1(l101, 101);
6068 fei = fib_table_entry_update_one_path(fib_index,
6071 FIB_ENTRY_FLAG_NONE,
6074 tm->hw[0]->sw_if_index,
6075 ~0, // invalid fib index
6078 FIB_ROUTE_PATH_FLAG_NONE);
6080 FIB_TEST(fib_test_validate_entry(fei,
6081 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6083 &l101_eos_o_10_10_10_1),
6084 "1.1.1.2/32 LB 1 buckets via: "
6085 "label 101 over 10.10.10.1");
6087 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6088 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6090 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6092 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6094 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6097 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6098 .type = FT_LB_LABEL_O_LB,
6100 .lb = non_eos_1_1_1_2.dpoi_index,
6105 mpls_label_t *l1601 = NULL;
6106 vec_add1(l1601, 1601);
6108 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6110 fei = fib_table_entry_path_add(fib_index,
6113 FIB_ENTRY_FLAG_NONE,
6115 &pfx_1_1_1_2_s_32.fp_addr,
6120 FIB_ROUTE_PATH_FLAG_NONE);
6122 FIB_TEST(fib_test_validate_entry(fei,
6123 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6125 &l1600_eos_o_1_1_1_1,
6126 &l1601_eos_o_1_1_1_2),
6127 "2.2.2.2/32 LB 2 buckets via: "
6128 "label 1600 via 1.1,1.1, "
6129 "label 16001 via 1.1.1.2");
6132 * update the via-entry so it no longer has an imp-null path.
6133 * the LB for the recursive can use an imp-null
6136 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6138 fei = fib_table_entry_update_one_path(fib_index,
6141 FIB_ENTRY_FLAG_NONE,
6144 tm->hw[1]->sw_if_index,
6145 ~0, // invalid fib index
6148 FIB_ROUTE_PATH_FLAG_NONE);
6150 FIB_TEST(fib_test_validate_entry(fei,
6151 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6154 "1.1.1.2/32 LB 1 buckets via: "
6157 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6158 FIB_TEST(fib_test_validate_entry(fei,
6159 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6161 &l1600_eos_o_1_1_1_1,
6162 &l1601_eos_o_1_1_1_2),
6163 "2.2.2.2/32 LB 2 buckets via: "
6164 "label 1600 via 1.1,1.1, "
6165 "label 16001 via 1.1.1.2");
6168 * update the via-entry so it no longer has labelled paths.
6169 * the LB for the recursive should exclue this via form its LB
6171 fei = fib_table_entry_update_one_path(fib_index,
6174 FIB_ENTRY_FLAG_NONE,
6177 tm->hw[1]->sw_if_index,
6178 ~0, // invalid fib index
6181 FIB_ROUTE_PATH_FLAG_NONE);
6183 FIB_TEST(fib_test_validate_entry(fei,
6184 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6187 "1.1.1.2/32 LB 1 buckets via: "
6190 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6191 FIB_TEST(fib_test_validate_entry(fei,
6192 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6194 &l1600_eos_o_1_1_1_1),
6195 "2.2.2.2/32 LB 1 buckets via: "
6196 "label 1600 via 1.1,1.1");
6198 dpo_reset(&non_eos_1_1_1_1);
6199 dpo_reset(&non_eos_1_1_1_2);
6202 * Add a recursive with no out-labels. We expect to use the IP of the via
6204 fib_prefix_t pfx_2_2_2_3_s_32 = {
6206 .fp_proto = FIB_PROTOCOL_IP4,
6208 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6211 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6213 fib_table_entry_update_one_path(fib_index,
6216 FIB_ENTRY_FLAG_NONE,
6218 &pfx_1_1_1_1_s_32.fp_addr,
6223 FIB_ROUTE_PATH_FLAG_NONE);
6225 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6227 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6230 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6233 .lb = ip_1_1_1_1.dpoi_index,
6237 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6238 FIB_TEST(fib_test_validate_entry(fei,
6239 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6242 "2.2.2.2.3/32 LB 1 buckets via: "
6246 * Add a recursive with an imp-null out-label.
6247 * We expect to use the IP of the via
6249 fib_prefix_t pfx_2_2_2_4_s_32 = {
6251 .fp_proto = FIB_PROTOCOL_IP4,
6253 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6257 fib_table_entry_update_one_path(fib_index,
6260 FIB_ENTRY_FLAG_NONE,
6262 &pfx_1_1_1_1_s_32.fp_addr,
6267 FIB_ROUTE_PATH_FLAG_NONE);
6269 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6270 FIB_TEST(fib_test_validate_entry(fei,
6271 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6274 "2.2.2.2.4/32 LB 1 buckets via: "
6277 dpo_reset(&ip_1_1_1_1);
6280 * Create an entry with a deep label stack
6282 fib_prefix_t pfx_2_2_5_5_s_32 = {
6284 .fp_proto = FIB_PROTOCOL_IP4,
6286 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6289 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6290 .type = FT_LB_LABEL_STACK_O_ADJ,
6291 .label_stack_o_adj = {
6292 .adj = ai_mpls_10_10_11_1,
6293 .label_stack_size = 8,
6295 200, 201, 202, 203, 204, 205, 206, 207
6300 mpls_label_t *label_stack = NULL;
6301 vec_validate(label_stack, 7);
6302 for (ii = 0; ii < 8; ii++)
6304 label_stack[ii] = ii + 200;
6307 fei = fib_table_entry_update_one_path(fib_index,
6310 FIB_ENTRY_FLAG_NONE,
6313 tm->hw[1]->sw_if_index,
6314 ~0, // invalid fib index
6317 FIB_ROUTE_PATH_FLAG_NONE);
6319 FIB_TEST(fib_test_validate_entry(fei,
6320 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6322 &ls_eos_o_10_10_10_1),
6323 "2.2.5.5/32 LB 1 buckets via: "
6325 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6330 fib_table_entry_delete(fib_index,
6334 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6335 FIB_TEST(fib_test_validate_entry(fei,
6336 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6338 &l1600_eos_o_1_1_1_1),
6339 "2.2.2.2/32 LB 1 buckets via: "
6340 "label 1600 via 1.1,1.1");
6342 fib_table_entry_delete(fib_index,
6346 FIB_TEST(fib_test_validate_entry(fei,
6347 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6350 "2.2.2.2/32 LB 1 buckets via: DROP");
6352 fib_table_entry_delete(fib_index,
6355 fib_table_entry_delete(fib_index,
6358 fib_table_entry_delete(fib_index,
6362 adj_unlock(ai_mpls_10_10_10_1);
6363 adj_unlock(ai_mpls_10_10_11_2);
6364 adj_unlock(ai_v4_10_10_11_1);
6365 adj_unlock(ai_v4_10_10_11_2);
6366 adj_unlock(ai_mpls_10_10_11_1);
6368 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6371 local0_pfx.fp_len = 32;
6372 fib_table_entry_delete(fib_index,
6374 FIB_SOURCE_INTERFACE);
6375 local0_pfx.fp_len = 24;
6376 fib_table_entry_delete(fib_index,
6378 FIB_SOURCE_INTERFACE);
6379 local1_pfx.fp_len = 32;
6380 fib_table_entry_delete(fib_index,
6382 FIB_SOURCE_INTERFACE);
6383 local1_pfx.fp_len = 24;
6384 fib_table_entry_delete(fib_index,
6386 FIB_SOURCE_INTERFACE);
6389 * +1 for the drop LB in the MPLS tables.
6391 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6392 "Load-balance resources freed %d of %d",
6393 lb_count+1, pool_elts(load_balance_pool));
6398 #define N_TEST_CHILDREN 4
6399 #define PARENT_INDEX 0
6401 typedef struct fib_node_test_t_
6406 fib_node_back_walk_ctx_t *ctxs;
6410 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6412 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6414 #define FOR_EACH_TEST_CHILD(_tc) \
6415 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
6416 ii < N_TEST_CHILDREN+1; \
6417 ii++, (_tc) = &fib_test_nodes[ii])
6420 fib_test_child_get_node (fib_node_index_t index)
6422 return (&fib_test_nodes[index].node);
6425 static int fib_test_walk_spawns_walks;
6427 static fib_node_back_walk_rc_t
6428 fib_test_child_back_walk_notify (fib_node_t *node,
6429 fib_node_back_walk_ctx_t *ctx)
6431 fib_node_test_t *tc = (fib_node_test_t*) node;
6433 vec_add1(tc->ctxs, *ctx);
6435 if (1 == fib_test_walk_spawns_walks)
6436 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6437 if (2 == fib_test_walk_spawns_walks)
6438 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6439 FIB_WALK_PRIORITY_HIGH, ctx);
6441 return (FIB_NODE_BACK_WALK_CONTINUE);
6445 fib_test_child_last_lock_gone (fib_node_t *node)
6447 fib_node_test_t *tc = (fib_node_test_t *)node;
6453 * The FIB walk's graph node virtual function table
6455 static const fib_node_vft_t fib_test_child_vft = {
6456 .fnv_get = fib_test_child_get_node,
6457 .fnv_last_lock = fib_test_child_last_lock_gone,
6458 .fnv_back_walk = fib_test_child_back_walk_notify,
6462 * the function (that should have been static but isn't so I can do this)
6463 * that processes the walk from the async queue,
6465 f64 fib_walk_process_queues(vlib_main_t * vm,
6467 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6470 fib_test_walk (void)
6472 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6473 fib_node_test_t *tc;
6477 vm = vlib_get_main();
6478 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6481 * init a fake node on which we will add children
6483 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6484 FIB_NODE_TYPE_TEST);
6486 FOR_EACH_TEST_CHILD(tc)
6488 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6489 fib_node_lock(&tc->node);
6492 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6494 FIB_NODE_TYPE_TEST, ii);
6498 * enqueue a walk across the parents children.
6500 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6502 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6503 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6504 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6505 "Parent has %d children pre-walk",
6506 fib_node_list_get_size(PARENT()->fn_children));
6509 * give the walk a large amount of time so it gets to the end
6511 fib_walk_process_queues(vm, 1);
6513 FOR_EACH_TEST_CHILD(tc)
6515 FIB_TEST(1 == vec_len(tc->ctxs),
6516 "%d child visitsed %d times",
6517 ii, vec_len(tc->ctxs));
6520 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6521 "Queue is empty post walk");
6522 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6523 "Parent has %d children post walk",
6524 fib_node_list_get_size(PARENT()->fn_children));
6527 * walk again. should be no increase in the number of visits, since
6528 * the walk will have terminated.
6530 fib_walk_process_queues(vm, 1);
6532 FOR_EACH_TEST_CHILD(tc)
6534 FIB_TEST(0 == vec_len(tc->ctxs),
6535 "%d child visitsed %d times",
6536 ii, vec_len(tc->ctxs));
6540 * schedule a low and hig priority walk. expect the high to be performed
6542 * schedule the high prio walk first so that it is further from the head
6543 * of the dependency list. that way it won't merge with the low one.
6545 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6546 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6548 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6549 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6550 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6551 FIB_WALK_PRIORITY_LOW, &low_ctx);
6553 fib_walk_process_queues(vm, 1);
6555 FOR_EACH_TEST_CHILD(tc)
6557 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6558 "%d child visitsed by high prio walk", ii);
6559 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6560 "%d child visitsed by low prio walk", ii);
6563 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6564 "Queue is empty post prio walk");
6565 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6566 "Parent has %d children post prio walk",
6567 fib_node_list_get_size(PARENT()->fn_children));
6570 * schedule 2 walks of the same priority that can be megred.
6571 * expect that each child is thus visited only once.
6573 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6574 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6576 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6577 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6578 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6579 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6581 fib_walk_process_queues(vm, 1);
6583 FOR_EACH_TEST_CHILD(tc)
6585 FIB_TEST(1 == vec_len(tc->ctxs),
6586 "%d child visitsed %d times during merge walk",
6587 ii, vec_len(tc->ctxs));
6590 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6591 "Queue is empty post merge walk");
6592 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6593 "Parent has %d children post merge walk",
6594 fib_node_list_get_size(PARENT()->fn_children));
6597 * schedule 2 walks of the same priority that cannot be megred.
6598 * expect that each child is thus visited twice and in the order
6599 * in which the walks were scheduled.
6601 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6602 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6604 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6605 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6606 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6607 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6609 fib_walk_process_queues(vm, 1);
6611 FOR_EACH_TEST_CHILD(tc)
6613 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6614 "%d child visitsed by high prio walk", ii);
6615 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6616 "%d child visitsed by low prio walk", ii);
6619 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6620 "Queue is empty post no-merge walk");
6621 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6622 "Parent has %d children post no-merge walk",
6623 fib_node_list_get_size(PARENT()->fn_children));
6626 * schedule a walk that makes one one child progress.
6627 * we do this by giving the queue draining process zero
6628 * time quanta. it's a do..while loop, so it does something.
6630 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6632 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6633 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6634 fib_walk_process_queues(vm, 0);
6636 FOR_EACH_TEST_CHILD(tc)
6638 if (ii == N_TEST_CHILDREN)
6640 FIB_TEST(1 == vec_len(tc->ctxs),
6641 "%d child visitsed %d times in zero quanta walk",
6642 ii, vec_len(tc->ctxs));
6646 FIB_TEST(0 == vec_len(tc->ctxs),
6647 "%d child visitsed %d times in 0 quanta walk",
6648 ii, vec_len(tc->ctxs));
6651 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6652 "Queue is not empty post zero quanta walk");
6653 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6654 "Parent has %d children post zero qunta walk",
6655 fib_node_list_get_size(PARENT()->fn_children));
6660 fib_walk_process_queues(vm, 0);
6662 FOR_EACH_TEST_CHILD(tc)
6664 if (ii >= N_TEST_CHILDREN-1)
6666 FIB_TEST(1 == vec_len(tc->ctxs),
6667 "%d child visitsed %d times in 2nd zero quanta walk",
6668 ii, vec_len(tc->ctxs));
6672 FIB_TEST(0 == vec_len(tc->ctxs),
6673 "%d child visitsed %d times in 2nd 0 quanta walk",
6674 ii, vec_len(tc->ctxs));
6677 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6678 "Queue is not empty post zero quanta walk");
6679 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6680 "Parent has %d children post zero qunta walk",
6681 fib_node_list_get_size(PARENT()->fn_children));
6684 * schedule another walk that will catch-up and merge.
6686 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6687 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6688 fib_walk_process_queues(vm, 1);
6690 FOR_EACH_TEST_CHILD(tc)
6692 if (ii >= N_TEST_CHILDREN-1)
6694 FIB_TEST(2 == vec_len(tc->ctxs),
6695 "%d child visitsed %d times in 2nd zero quanta merge walk",
6696 ii, vec_len(tc->ctxs));
6701 FIB_TEST(1 == vec_len(tc->ctxs),
6702 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6703 ii, vec_len(tc->ctxs));
6707 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6708 "Queue is not empty post 2nd zero quanta merge walk");
6709 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6710 "Parent has %d children post 2nd zero qunta merge walk",
6711 fib_node_list_get_size(PARENT()->fn_children));
6714 * park a async walk in the middle of the list, then have an sync walk catch
6715 * it. same expectations as async catches async.
6717 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6719 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6720 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6722 fib_walk_process_queues(vm, 0);
6723 fib_walk_process_queues(vm, 0);
6725 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6727 FOR_EACH_TEST_CHILD(tc)
6729 if (ii >= N_TEST_CHILDREN-1)
6731 FIB_TEST(2 == vec_len(tc->ctxs),
6732 "%d child visitsed %d times in sync catches async walk",
6733 ii, vec_len(tc->ctxs));
6738 FIB_TEST(1 == vec_len(tc->ctxs),
6739 "%d child visitsed %d times in sync catches async walk",
6740 ii, vec_len(tc->ctxs));
6744 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6745 "Queue is not empty post 2nd zero quanta merge walk");
6746 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6747 "Parent has %d children post 2nd zero qunta merge walk",
6748 fib_node_list_get_size(PARENT()->fn_children));
6751 * make the parent a child of one of its children, thus inducing a routing loop.
6753 fib_test_nodes[PARENT_INDEX].sibling =
6754 fib_node_child_add(FIB_NODE_TYPE_TEST,
6755 1, // the first child
6760 * execute a sync walk from the parent. each child visited spawns more sync
6761 * walks. we expect the walk to terminate.
6763 fib_test_walk_spawns_walks = 1;
6765 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6767 FOR_EACH_TEST_CHILD(tc)
6770 * child 1 - which is last in the list - has the loop.
6771 * the other children a re thus visitsed first. the we meet
6772 * child 1. we go round the loop again, visting the other children.
6773 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6778 FIB_TEST(1 == vec_len(tc->ctxs),
6779 "child %d visitsed %d times during looped sync walk",
6780 ii, vec_len(tc->ctxs));
6784 FIB_TEST(2 == vec_len(tc->ctxs),
6785 "child %d visitsed %d times during looped sync walk",
6786 ii, vec_len(tc->ctxs));
6790 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6791 "Parent has %d children post sync loop walk",
6792 fib_node_list_get_size(PARENT()->fn_children));
6795 * the walk doesn't reach the max depth because the infra knows that sync
6796 * meets sync implies a loop and bails early.
6798 FIB_TEST(high_ctx.fnbw_depth == 9,
6799 "Walk context depth %d post sync loop walk",
6800 high_ctx.fnbw_depth);
6803 * execute an async walk of the graph loop, with each child spawns sync walks
6805 high_ctx.fnbw_depth = 0;
6806 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6807 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6809 fib_walk_process_queues(vm, 1);
6811 FOR_EACH_TEST_CHILD(tc)
6814 * we don't really care how many times the children are visisted, as long as
6815 * it is more than once.
6817 FIB_TEST(1 <= vec_len(tc->ctxs),
6818 "child %d visitsed %d times during looped aync spawns sync walk",
6819 ii, vec_len(tc->ctxs));
6824 * execute an async walk of the graph loop, with each child spawns async walks
6826 fib_test_walk_spawns_walks = 2;
6827 high_ctx.fnbw_depth = 0;
6828 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6829 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6831 fib_walk_process_queues(vm, 1);
6833 FOR_EACH_TEST_CHILD(tc)
6836 * we don't really care how many times the children are visisted, as long as
6837 * it is more than once.
6839 FIB_TEST(1 <= vec_len(tc->ctxs),
6840 "child %d visitsed %d times during looped async spawns async walk",
6841 ii, vec_len(tc->ctxs));
6846 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6847 1, // the first child
6848 fib_test_nodes[PARENT_INDEX].sibling);
6853 FOR_EACH_TEST_CHILD(tc)
6855 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6857 fib_node_deinit(&tc->node);
6858 fib_node_unlock(&tc->node);
6860 fib_node_deinit(PARENT());
6863 * The parent will be destroyed when the last lock on it goes.
6864 * this test ensures all the walk objects are unlocking it.
6866 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6867 "Parent was destroyed");
6873 * declaration of the otherwise static callback functions
6875 void fib_bfd_notify (bfd_listen_event_e event,
6876 const bfd_session_t *session);
6877 void adj_bfd_notify (bfd_listen_event_e event,
6878 const bfd_session_t *session);
6881 * Test BFD session interaction with FIB
6886 fib_node_index_t fei;
6890 /* via 10.10.10.1 */
6891 ip46_address_t nh_10_10_10_1 = {
6892 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6894 /* via 10.10.10.2 */
6895 ip46_address_t nh_10_10_10_2 = {
6896 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
6898 /* via 10.10.10.10 */
6899 ip46_address_t nh_10_10_10_10 = {
6900 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6902 n_feis = fib_entry_pool_size();
6907 * add interface routes. we'll assume this works. it's tested elsewhere
6909 fib_prefix_t pfx_10_10_10_10_s_24 = {
6911 .fp_proto = FIB_PROTOCOL_IP4,
6912 .fp_addr = nh_10_10_10_10,
6915 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
6916 FIB_SOURCE_INTERFACE,
6917 (FIB_ENTRY_FLAG_CONNECTED |
6918 FIB_ENTRY_FLAG_ATTACHED),
6921 tm->hw[0]->sw_if_index,
6922 ~0, // invalid fib index
6925 FIB_ROUTE_PATH_FLAG_NONE);
6927 fib_prefix_t pfx_10_10_10_10_s_32 = {
6929 .fp_proto = FIB_PROTOCOL_IP4,
6930 .fp_addr = nh_10_10_10_10,
6932 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
6933 FIB_SOURCE_INTERFACE,
6934 (FIB_ENTRY_FLAG_CONNECTED |
6935 FIB_ENTRY_FLAG_LOCAL),
6938 tm->hw[0]->sw_if_index,
6939 ~0, // invalid fib index
6942 FIB_ROUTE_PATH_FLAG_NONE);
6945 * A BFD session via a neighbour we do not yet know
6947 bfd_session_t bfd_10_10_10_1 = {
6951 .peer_addr = nh_10_10_10_1,
6954 .hop_type = BFD_HOP_TYPE_MULTI,
6955 .local_state = BFD_STATE_init,
6958 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
6961 * A new entry will be created that forwards via the adj
6963 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6966 tm->hw[0]->sw_if_index);
6967 fib_prefix_t pfx_10_10_10_1_s_32 = {
6968 .fp_addr = nh_10_10_10_1,
6970 .fp_proto = FIB_PROTOCOL_IP4,
6972 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
6975 .adj = ai_10_10_10_1,
6979 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
6980 FIB_TEST(fib_test_validate_entry(fei,
6981 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6984 "BFD sourced %U via %U",
6985 format_fib_prefix, &pfx_10_10_10_1_s_32,
6986 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
6989 * Delete the BFD session. Expect the fib_entry to be removed
6991 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
6993 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
6994 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
6995 "BFD sourced %U removed",
6996 format_fib_prefix, &pfx_10_10_10_1_s_32);
6999 * Add the BFD source back
7001 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7004 * source the entry via the ADJ fib
7006 fei = fib_table_entry_update_one_path(0,
7007 &pfx_10_10_10_1_s_32,
7009 FIB_ENTRY_FLAG_ATTACHED,
7012 tm->hw[0]->sw_if_index,
7013 ~0, // invalid fib index
7016 FIB_ROUTE_PATH_FLAG_NONE);
7019 * Delete the BFD session. Expect the fib_entry to remain
7021 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7023 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7024 FIB_TEST(fib_test_validate_entry(fei,
7025 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7028 "BFD sourced %U remains via %U",
7029 format_fib_prefix, &pfx_10_10_10_1_s_32,
7030 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7033 * Add the BFD source back
7035 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7038 * Create another ADJ FIB
7040 fib_prefix_t pfx_10_10_10_2_s_32 = {
7041 .fp_addr = nh_10_10_10_2,
7043 .fp_proto = FIB_PROTOCOL_IP4,
7045 fib_table_entry_update_one_path(0,
7046 &pfx_10_10_10_2_s_32,
7048 FIB_ENTRY_FLAG_ATTACHED,
7051 tm->hw[0]->sw_if_index,
7052 ~0, // invalid fib index
7055 FIB_ROUTE_PATH_FLAG_NONE);
7057 * A BFD session for the new ADJ FIB
7059 bfd_session_t bfd_10_10_10_2 = {
7063 .peer_addr = nh_10_10_10_2,
7066 .hop_type = BFD_HOP_TYPE_MULTI,
7067 .local_state = BFD_STATE_init,
7070 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7073 * remove the adj-fib source whilst the session is present
7076 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7077 fib_table_entry_update_one_path(0,
7078 &pfx_10_10_10_2_s_32,
7080 FIB_ENTRY_FLAG_ATTACHED,
7083 tm->hw[0]->sw_if_index,
7084 ~0, // invalid fib index
7087 FIB_ROUTE_PATH_FLAG_NONE);
7090 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7091 * bring one of the sessions UP, leave the other down
7093 bfd_10_10_10_1.local_state = BFD_STATE_up;
7094 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7095 bfd_10_10_10_2.local_state = BFD_STATE_down;
7096 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7099 * A recursive prefix via both of the ADJ FIBs
7101 fib_prefix_t pfx_200_0_0_0_s_24 = {
7102 .fp_proto = FIB_PROTOCOL_IP4,
7105 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7108 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7111 fib_entry_contribute_ip_forwarding(
7112 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7114 fib_entry_contribute_ip_forwarding(
7115 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7117 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7120 .lb = dpo_10_10_10_1->dpoi_index,
7123 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7126 .lb = dpo_10_10_10_2->dpoi_index,
7131 * A prefix via the adj-fib that is BFD down => DROP
7133 fei = fib_table_entry_path_add(0,
7134 &pfx_200_0_0_0_s_24,
7136 FIB_ENTRY_FLAG_NONE,
7140 0, // default fib index
7143 FIB_ROUTE_PATH_FLAG_NONE);
7144 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7145 "%U resolves via drop",
7146 format_fib_prefix, &pfx_200_0_0_0_s_24);
7149 * add a path via the UP BFD adj-fib.
7150 * we expect that the DOWN BFD ADJ FIB is not used.
7152 fei = fib_table_entry_path_add(0,
7153 &pfx_200_0_0_0_s_24,
7155 FIB_ENTRY_FLAG_NONE,
7159 0, // default fib index
7162 FIB_ROUTE_PATH_FLAG_NONE);
7164 FIB_TEST(fib_test_validate_entry(fei,
7165 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7168 "Recursive %U only UP BFD adj-fibs",
7169 format_fib_prefix, &pfx_200_0_0_0_s_24);
7172 * Send a BFD state change to UP - both sessions are now up
7173 * the recursive prefix should LB over both
7175 bfd_10_10_10_2.local_state = BFD_STATE_up;
7176 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7179 FIB_TEST(fib_test_validate_entry(fei,
7180 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7184 "Recursive %U via both UP BFD adj-fibs",
7185 format_fib_prefix, &pfx_200_0_0_0_s_24);
7188 * Send a BFD state change to DOWN
7189 * the recursive prefix should exclude the down
7191 bfd_10_10_10_2.local_state = BFD_STATE_down;
7192 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7195 FIB_TEST(fib_test_validate_entry(fei,
7196 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7199 "Recursive %U via only UP",
7200 format_fib_prefix, &pfx_200_0_0_0_s_24);
7203 * Delete the BFD session while it is in the DOWN state.
7204 * FIB should consider the entry's state as back up
7206 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
7208 FIB_TEST(fib_test_validate_entry(fei,
7209 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7213 "Recursive %U via both UP BFD adj-fibs post down session delete",
7214 format_fib_prefix, &pfx_200_0_0_0_s_24);
7217 * Delete the BFD other session while it is in the UP state.
7219 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7221 FIB_TEST(fib_test_validate_entry(fei,
7222 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7226 "Recursive %U via both UP BFD adj-fibs post up session delete",
7227 format_fib_prefix, &pfx_200_0_0_0_s_24);
7232 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
7233 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
7234 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7236 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
7237 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
7239 adj_unlock(ai_10_10_10_1);
7241 * test no-one left behind
7243 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7244 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7247 * Single-hop BFD tests
7249 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
7250 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
7252 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7254 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7257 tm->hw[0]->sw_if_index);
7259 * whilst the BFD session is not signalled, the adj is up
7261 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
7264 * bring the BFD session up
7266 bfd_10_10_10_1.local_state = BFD_STATE_up;
7267 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7268 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
7271 * bring the BFD session down
7273 bfd_10_10_10_1.local_state = BFD_STATE_down;
7274 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7275 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
7279 * add an attached next hop FIB entry via the down adj
7281 fib_prefix_t pfx_5_5_5_5_s_32 = {
7284 .as_u32 = clib_host_to_net_u32(0x05050505),
7288 .fp_proto = FIB_PROTOCOL_IP4,
7291 fei = fib_table_entry_path_add(0,
7294 FIB_ENTRY_FLAG_NONE,
7297 tm->hw[0]->sw_if_index,
7298 ~0, // invalid fib index
7301 FIB_ROUTE_PATH_FLAG_NONE);
7302 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7303 "%U resolves via drop",
7304 format_fib_prefix, &pfx_5_5_5_5_s_32);
7307 * Add a path via an ADJ that is up
7309 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7312 tm->hw[0]->sw_if_index);
7314 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
7317 .adj = ai_10_10_10_2,
7320 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
7322 fei = fib_table_entry_path_add(0,
7325 FIB_ENTRY_FLAG_NONE,
7328 tm->hw[0]->sw_if_index,
7329 ~0, // invalid fib index
7332 FIB_ROUTE_PATH_FLAG_NONE);
7334 FIB_TEST(fib_test_validate_entry(fei,
7335 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7338 "BFD sourced %U via %U",
7339 format_fib_prefix, &pfx_5_5_5_5_s_32,
7340 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
7343 * Bring up the down session - should now LB
7345 bfd_10_10_10_1.local_state = BFD_STATE_up;
7346 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7347 FIB_TEST(fib_test_validate_entry(fei,
7348 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7352 "BFD sourced %U via noth adjs",
7353 format_fib_prefix, &pfx_5_5_5_5_s_32);
7356 * remove the BFD session state from the adj
7358 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7363 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
7364 adj_unlock(ai_10_10_10_1);
7365 adj_unlock(ai_10_10_10_2);
7368 * test no-one left behind
7370 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7371 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7378 const mpls_label_t deag_label = 50;
7379 const u32 lfib_index = 0;
7380 const u32 fib_index = 0;
7381 dpo_id_t dpo = DPO_INVALID;
7382 const dpo_id_t *dpo1;
7383 fib_node_index_t lfe;
7387 adj_index_t ai_mpls_10_10_10_1;
7390 lb_count = pool_elts(load_balance_pool);
7392 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7396 * MPLS enable an interface so we get the MPLS table created
7398 mpls_sw_interface_enable_disable(&mpls_main,
7399 tm->hw[0]->sw_if_index,
7402 ip46_address_t nh_10_10_10_1 = {
7403 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7405 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7408 tm->hw[0]->sw_if_index);
7411 * Test the specials stack properly.
7413 fib_prefix_t exp_null_v6_pfx = {
7414 .fp_proto = FIB_PROTOCOL_MPLS,
7416 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7417 .fp_payload_proto = DPO_PROTO_IP6,
7419 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
7420 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
7422 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7423 format_mpls_eos_bit, MPLS_EOS);
7424 fib_entry_contribute_forwarding(lfe,
7425 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7427 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7428 lkd = lookup_dpo_get(dpo1->dpoi_index);
7430 FIB_TEST((fib_index == lkd->lkd_fib_index),
7431 "%U/%U is deag in %d %U",
7432 format_mpls_unicast_label, deag_label,
7433 format_mpls_eos_bit, MPLS_EOS,
7435 format_dpo_id, &dpo, 0);
7436 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7437 "%U/%U is dst deag",
7438 format_mpls_unicast_label, deag_label,
7439 format_mpls_eos_bit, MPLS_EOS);
7440 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
7441 "%U/%U is lookup in interface's table",
7442 format_mpls_unicast_label, deag_label,
7443 format_mpls_eos_bit, MPLS_EOS);
7444 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
7445 "%U/%U is %U dst deag",
7446 format_mpls_unicast_label, deag_label,
7447 format_mpls_eos_bit, MPLS_EOS,
7448 format_dpo_proto, lkd->lkd_proto);
7452 * A route deag route for EOS
7454 fib_prefix_t pfx = {
7455 .fp_proto = FIB_PROTOCOL_MPLS,
7457 .fp_label = deag_label,
7458 .fp_payload_proto = DPO_PROTO_IP4,
7460 lfe = fib_table_entry_path_add(lfib_index,
7463 FIB_ENTRY_FLAG_NONE,
7470 FIB_ROUTE_PATH_FLAG_NONE);
7472 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7474 format_mpls_unicast_label, deag_label,
7475 format_mpls_eos_bit, MPLS_EOS);
7477 fib_entry_contribute_forwarding(lfe,
7478 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7480 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7481 lkd = lookup_dpo_get(dpo1->dpoi_index);
7483 FIB_TEST((fib_index == lkd->lkd_fib_index),
7484 "%U/%U is deag in %d %U",
7485 format_mpls_unicast_label, deag_label,
7486 format_mpls_eos_bit, MPLS_EOS,
7488 format_dpo_id, &dpo, 0);
7489 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7490 "%U/%U is dst deag",
7491 format_mpls_unicast_label, deag_label,
7492 format_mpls_eos_bit, MPLS_EOS);
7493 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
7494 "%U/%U is %U dst deag",
7495 format_mpls_unicast_label, deag_label,
7496 format_mpls_eos_bit, MPLS_EOS,
7497 format_dpo_proto, lkd->lkd_proto);
7499 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7501 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7503 "%U/%U not present",
7504 format_mpls_unicast_label, deag_label,
7505 format_mpls_eos_bit, MPLS_EOS);
7508 * A route deag route for non-EOS
7510 pfx.fp_eos = MPLS_NON_EOS;
7511 lfe = fib_table_entry_path_add(lfib_index,
7514 FIB_ENTRY_FLAG_NONE,
7521 FIB_ROUTE_PATH_FLAG_NONE);
7523 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7525 format_mpls_unicast_label, deag_label,
7526 format_mpls_eos_bit, MPLS_NON_EOS);
7528 fib_entry_contribute_forwarding(lfe,
7529 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7531 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7532 lkd = lookup_dpo_get(dpo1->dpoi_index);
7534 FIB_TEST((fib_index == lkd->lkd_fib_index),
7535 "%U/%U is deag in %d %U",
7536 format_mpls_unicast_label, deag_label,
7537 format_mpls_eos_bit, MPLS_NON_EOS,
7539 format_dpo_id, &dpo, 0);
7540 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7541 "%U/%U is dst deag",
7542 format_mpls_unicast_label, deag_label,
7543 format_mpls_eos_bit, MPLS_NON_EOS);
7545 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
7546 "%U/%U is %U dst deag",
7547 format_mpls_unicast_label, deag_label,
7548 format_mpls_eos_bit, MPLS_NON_EOS,
7549 format_dpo_proto, lkd->lkd_proto);
7551 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7553 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7555 "%U/%U not present",
7556 format_mpls_unicast_label, deag_label,
7557 format_mpls_eos_bit, MPLS_EOS);
7564 fib_prefix_t pfx_1200 = {
7566 .fp_proto = FIB_PROTOCOL_MPLS,
7568 .fp_eos = MPLS_NON_EOS,
7570 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
7571 .type = FT_LB_LABEL_STACK_O_ADJ,
7572 .label_stack_o_adj = {
7573 .adj = ai_mpls_10_10_10_1,
7574 .label_stack_size = 4,
7578 .eos = MPLS_NON_EOS,
7581 dpo_id_t neos_1200 = DPO_INVALID;
7582 dpo_id_t ip_1200 = DPO_INVALID;
7583 mpls_label_t *l200 = NULL;
7584 vec_add1(l200, 200);
7585 vec_add1(l200, 300);
7586 vec_add1(l200, 400);
7587 vec_add1(l200, 500);
7589 lfe = fib_table_entry_update_one_path(fib_index,
7592 FIB_ENTRY_FLAG_NONE,
7595 tm->hw[0]->sw_if_index,
7596 ~0, // invalid fib index
7599 FIB_ROUTE_PATH_FLAG_NONE);
7601 FIB_TEST(fib_test_validate_entry(lfe,
7602 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7604 &neos_o_10_10_10_1),
7605 "1200/0 LB 1 buckets via: "
7609 * A recursive route via the MPLS x-connect
7611 fib_prefix_t pfx_2_2_2_3_s_32 = {
7613 .fp_proto = FIB_PROTOCOL_IP4,
7615 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7618 fib_route_path_t *rpaths = NULL, rpath = {
7619 .frp_proto = FIB_PROTOCOL_MPLS,
7620 .frp_local_label = 1200,
7621 .frp_eos = MPLS_NON_EOS,
7622 .frp_sw_if_index = ~0, // recurive
7623 .frp_fib_index = 0, // Default MPLS fib
7625 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
7626 .frp_label_stack = NULL,
7628 vec_add1(rpaths, rpath);
7630 fib_table_entry_path_add2(fib_index,
7633 FIB_ENTRY_FLAG_NONE,
7637 * A labelled recursive route via the MPLS x-connect
7639 fib_prefix_t pfx_2_2_2_4_s_32 = {
7641 .fp_proto = FIB_PROTOCOL_IP4,
7643 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7646 mpls_label_t *l999 = NULL;
7647 vec_add1(l999, 999);
7648 rpaths[0].frp_label_stack = l999,
7650 fib_table_entry_path_add2(fib_index,
7653 FIB_ENTRY_FLAG_NONE,
7656 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7657 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7659 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7660 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7663 fib_test_lb_bucket_t ip_o_1200 = {
7666 .lb = ip_1200.dpoi_index,
7669 fib_test_lb_bucket_t mpls_o_1200 = {
7670 .type = FT_LB_LABEL_O_LB,
7672 .lb = neos_1200.dpoi_index,
7678 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7679 FIB_TEST(fib_test_validate_entry(lfe,
7680 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7683 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
7684 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7685 FIB_TEST(fib_test_validate_entry(lfe,
7686 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7689 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
7691 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
7692 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
7693 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7695 dpo_reset(&neos_1200);
7696 dpo_reset(&ip_1200);
7699 * A recursive via a label that does not exist
7701 fib_test_lb_bucket_t bucket_drop = {
7702 .type = FT_LB_SPECIAL,
7704 .adj = DPO_PROTO_MPLS,
7708 rpaths[0].frp_label_stack = NULL;
7709 lfe = fib_table_entry_path_add2(fib_index,
7712 FIB_ENTRY_FLAG_NONE,
7715 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7716 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7718 ip_o_1200.lb.lb = ip_1200.dpoi_index;
7720 FIB_TEST(fib_test_validate_entry(lfe,
7721 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7724 "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
7725 lfe = fib_table_lookup(fib_index, &pfx_1200);
7726 FIB_TEST(fib_test_validate_entry(lfe,
7727 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7730 "2.2.2.4/32 LB 1 buckets via: ip4-DROP");
7732 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7734 dpo_reset(&ip_1200);
7737 * An rx-interface route.
7738 * like the tail of an mcast LSP
7740 dpo_id_t idpo = DPO_INVALID;
7742 interface_dpo_add_or_lock(DPO_PROTO_IP4,
7743 tm->hw[0]->sw_if_index,
7746 fib_prefix_t pfx_2500 = {
7748 .fp_proto = FIB_PROTOCOL_MPLS,
7751 .fp_payload_proto = DPO_PROTO_IP4,
7753 fib_test_lb_bucket_t rx_intf_0 = {
7756 .adj = idpo.dpoi_index,
7760 lfe = fib_table_entry_update_one_path(fib_index,
7763 FIB_ENTRY_FLAG_NONE,
7766 tm->hw[0]->sw_if_index,
7767 ~0, // invalid fib index
7770 FIB_ROUTE_PATH_INTF_RX);
7771 FIB_TEST(fib_test_validate_entry(lfe,
7772 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7775 "2500 rx-interface 0");
7776 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
7779 * An MPLS mulicast entry
7781 fib_prefix_t pfx_3500 = {
7783 .fp_proto = FIB_PROTOCOL_MPLS,
7786 .fp_payload_proto = DPO_PROTO_IP4,
7788 fib_test_rep_bucket_t mc_0 = {
7789 .type = FT_REP_LABEL_O_ADJ,
7791 .adj = ai_mpls_10_10_10_1,
7796 fib_test_rep_bucket_t mc_intf_0 = {
7797 .type = FT_REP_INTF,
7799 .adj = idpo.dpoi_index,
7802 mpls_label_t *l3300 = NULL;
7803 vec_add1(l3300, 3300);
7805 lfe = fib_table_entry_update_one_path(lfib_index,
7808 FIB_ENTRY_FLAG_MULTICAST,
7811 tm->hw[0]->sw_if_index,
7812 ~0, // invalid fib index
7815 FIB_ROUTE_PATH_FLAG_NONE);
7816 FIB_TEST(fib_test_validate_entry(lfe,
7817 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7820 "3500 via replicate over 10.10.10.1");
7823 * MPLS Bud-node. Add a replication via an interface-receieve path
7825 lfe = fib_table_entry_path_add(lfib_index,
7828 FIB_ENTRY_FLAG_MULTICAST,
7831 tm->hw[0]->sw_if_index,
7832 ~0, // invalid fib index
7835 FIB_ROUTE_PATH_INTF_RX);
7836 FIB_TEST(fib_test_validate_entry(lfe,
7837 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7841 "3500 via replicate over 10.10.10.1 and interface-rx");
7844 * Add a replication via an interface-free for-us path
7846 fib_test_rep_bucket_t mc_disp = {
7847 .type = FT_REP_DISP_MFIB_LOOKUP,
7849 .adj = idpo.dpoi_index,
7852 lfe = fib_table_entry_path_add(lfib_index,
7855 FIB_ENTRY_FLAG_MULTICAST,
7862 FIB_ROUTE_PATH_RPF_ID);
7863 FIB_TEST(fib_test_validate_entry(lfe,
7864 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7869 "3500 via replicate over 10.10.10.1 and interface-rx");
7873 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
7879 mpls_sw_interface_enable_disable(&mpls_main,
7880 tm->hw[0]->sw_if_index,
7883 FIB_TEST(lb_count == pool_elts(load_balance_pool),
7884 "Load-balance resources freed %d of %d",
7885 lb_count, pool_elts(load_balance_pool));
7886 FIB_TEST(0 == pool_elts(interface_dpo_pool),
7887 "interface_dpo resources freed %d of %d",
7888 0, pool_elts(interface_dpo_pool));
7893 static clib_error_t *
7894 fib_test (vlib_main_t * vm,
7895 unformat_input_t * input,
7896 vlib_cli_command_t * cmd_arg)
7901 fib_test_mk_intf(4);
7903 if (unformat (input, "debug"))
7905 fib_test_do_debug = 1;
7908 if (unformat (input, "ip"))
7910 res += fib_test_v4();
7911 res += fib_test_v6();
7913 else if (unformat (input, "label"))
7915 res += fib_test_label();
7917 else if (unformat (input, "ae"))
7919 res += fib_test_ae();
7921 else if (unformat (input, "lfib"))
7925 else if (unformat (input, "walk"))
7927 res += fib_test_walk();
7929 else if (unformat (input, "bfd"))
7931 res += fib_test_bfd();
7936 * These walk UT aren't run as part of the full suite, since the
7937 * fib-walk process must be disabled in order for the tests to work
7941 res += fib_test_v4();
7942 res += fib_test_v6();
7943 res += fib_test_ae();
7944 res += fib_test_bfd();
7945 res += fib_test_label();
7951 return clib_error_return(0, "FIB Unit Test Failed");
7959 VLIB_CLI_COMMAND (test_fib_command, static) = {
7961 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
7962 .function = fib_test,
7966 fib_test_init (vlib_main_t *vm)
7971 VLIB_INIT_FUNCTION (fib_test_init);