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_rx_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_RX == 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_RX == 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 not %d",
613 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
614 "bucket %d stacks on %U",
616 format_dpo_type, dpo->dpoi_type);
617 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
618 "bucket %d stacks on drop %d",
628 fib_test_validate_entry (fib_node_index_t fei,
629 fib_forward_chain_type_t fct,
633 dpo_id_t dpo = DPO_INVALID;
640 va_start(ap, n_buckets);
642 fib_entry_get_prefix(fei, &pfx);
643 fib_index = fib_entry_get_fib_index(fei);
644 fib_entry_contribute_forwarding(fei, fct, &dpo);
646 if (DPO_REPLICATE == dpo.dpoi_type)
648 const replicate_t *rep;
650 rep = replicate_get(dpo.dpoi_index);
651 res = fib_test_validate_rep_v(rep, n_buckets, ap);
655 const load_balance_t *lb;
657 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
659 format_dpo_type, dpo.dpoi_type);
661 lb = load_balance_get(dpo.dpoi_index);
662 res = fib_test_validate_lb_v(lb, n_buckets, ap);
665 * ensure that the LB contributed by the entry is the
666 * same as the LB in the forwarding tables
668 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
670 switch (pfx.fp_proto)
672 case FIB_PROTOCOL_IP4:
673 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
675 case FIB_PROTOCOL_IP6:
676 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
678 case FIB_PROTOCOL_MPLS:
680 mpls_unicast_header_t hdr = {
681 .label_exp_s_ttl = 0,
684 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
685 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
686 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
688 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
694 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
695 "Contributed LB = FW LB: %U\n %U",
696 format_load_balance, fw_lbi, 0,
697 format_load_balance, dpo.dpoi_index, 0);
712 * In the default table check for the presence and correct forwarding
713 * of the special entries
715 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
716 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
717 const ip_adjacency_t *adj;
718 const load_balance_t *lb;
725 ip46_address_t nh_10_10_10_1 = {
726 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
729 ip46_address_t nh_10_10_10_2 = {
730 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
733 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
734 pool_elts(load_balance_map_pool));
738 /* record the nubmer of load-balances in use before we start */
739 lb_count = pool_elts(load_balance_pool);
741 /* Find or create FIB table 11 */
742 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
745 for (ii = 0; ii < 4; ii++)
747 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
750 fib_prefix_t pfx_0_0_0_0_s_0 = {
752 .fp_proto = FIB_PROTOCOL_IP4,
762 .fp_proto = FIB_PROTOCOL_IP4,
770 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
772 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
773 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
774 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
775 "Default route is DROP");
778 fei = fib_table_lookup(fib_index, &pfx);
779 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
780 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
781 "all 0s route is DROP");
783 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
785 fei = fib_table_lookup(fib_index, &pfx);
786 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
787 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
788 "all 1s route is DROP");
790 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
792 fei = fib_table_lookup(fib_index, &pfx);
793 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
794 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
795 "all-mcast route is DROP");
797 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
799 fei = fib_table_lookup(fib_index, &pfx);
800 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
801 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
802 "class-e route is DROP");
805 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
806 * all of which are special sourced and so none of which share path-lists.
807 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
808 * table, and 4 path-lists in the v6 MFIB table
812 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
813 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
814 fib_path_list_pool_size());
815 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
816 fib_entry_pool_size());
819 * add interface routes.
820 * validate presence of /24 attached and /32 recieve.
821 * test for the presence of the receive address in the glean and local adj
823 fib_prefix_t local_pfx = {
825 .fp_proto = FIB_PROTOCOL_IP4,
828 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
833 fib_table_entry_update_one_path(fib_index, &local_pfx,
834 FIB_SOURCE_INTERFACE,
835 (FIB_ENTRY_FLAG_CONNECTED |
836 FIB_ENTRY_FLAG_ATTACHED),
839 tm->hw[0]->sw_if_index,
840 ~0, // invalid fib index
843 FIB_ROUTE_PATH_FLAG_NONE);
844 fei = fib_table_lookup(fib_index, &local_pfx);
845 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
846 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
847 fib_entry_get_flags(fei)),
848 "Flags set on attached interface");
850 ai = fib_entry_get_adj(fei);
851 FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
852 "attached interface route adj present %d", ai);
854 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
855 "attached interface adj is glean");
856 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
857 &adj->sub_type.glean.receive_addr)),
858 "attached interface adj is receive ok");
860 local_pfx.fp_len = 32;
861 fib_table_entry_update_one_path(fib_index, &local_pfx,
862 FIB_SOURCE_INTERFACE,
863 (FIB_ENTRY_FLAG_CONNECTED |
864 FIB_ENTRY_FLAG_LOCAL),
867 tm->hw[0]->sw_if_index,
868 ~0, // invalid fib index
871 FIB_ROUTE_PATH_FLAG_NONE);
872 fei = fib_table_lookup(fib_index, &local_pfx);
873 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
874 fib_entry_get_flags(fei)),
875 "Flags set on local interface");
877 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
879 dpo = fib_entry_contribute_ip_forwarding(fei);
880 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
881 "RPF list for local length 0");
882 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
883 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
884 "local interface adj is local");
885 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
887 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
889 "local interface adj is receive ok");
891 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
893 FIB_SOURCE_INTERFACE)),
894 "2 Interface Source'd prefixes");
897 * +2 interface routes +2 non-shared path-lists
899 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
900 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
901 fib_path_list_pool_size());
902 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
903 fib_entry_pool_size());
906 * Modify the default route to be via an adj not yet known.
907 * this sources the defalut route with the API source, which is
908 * a higher preference to the DEFAULT_ROUTE source
910 pfx.fp_addr.ip4.as_u32 = 0;
912 fib_table_entry_path_add(fib_index, &pfx,
917 tm->hw[0]->sw_if_index,
918 ~0, // invalid fib index
921 FIB_ROUTE_PATH_FLAG_NONE);
922 fei = fib_table_lookup(fib_index, &pfx);
923 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
924 "Flags set on API route");
926 FIB_TEST((fei == dfrt), "default route same index");
927 ai = fib_entry_get_adj(fei);
928 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
930 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
931 "adj is incomplete");
932 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
933 "adj nbr next-hop ok");
934 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
937 "1 API Source'd prefixes");
940 * find the adj in the shared db
942 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
945 tm->hw[0]->sw_if_index);
946 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
947 adj_unlock(locked_ai);
950 * +1 shared path-list
952 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
953 fib_path_list_db_size());
954 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
955 fib_path_list_pool_size());
956 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
957 fib_entry_pool_size());
960 * remove the API source from the default route. We expected
961 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
963 pfx.fp_addr.ip4.as_u32 = 0;
965 fib_table_entry_path_remove(fib_index, &pfx,
969 tm->hw[0]->sw_if_index,
970 ~0, // non-recursive path, so no FIB index
972 FIB_ROUTE_PATH_FLAG_NONE);
974 fei = fib_table_lookup(fib_index, &pfx);
976 FIB_TEST((fei == dfrt), "default route same index");
977 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
978 "Default route is DROP");
981 * -1 shared-path-list
983 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
984 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
985 fib_path_list_pool_size());
986 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
987 fib_entry_pool_size());
990 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
992 fib_prefix_t pfx_10_10_10_1_s_32 = {
994 .fp_proto = FIB_PROTOCOL_IP4,
997 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1000 fib_prefix_t pfx_10_10_10_2_s_32 = {
1002 .fp_proto = FIB_PROTOCOL_IP4,
1005 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1008 fib_prefix_t pfx_11_11_11_11_s_32 = {
1010 .fp_proto = FIB_PROTOCOL_IP4,
1013 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1017 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1020 ip46_address_t nh_12_12_12_12 = {
1021 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1023 adj_index_t ai_12_12_12_12;
1026 * Add a route via an incomplete ADJ. then complete the ADJ
1027 * Expect the route LB is updated to use complete adj type.
1029 fei = fib_table_entry_update_one_path(fib_index,
1030 &pfx_11_11_11_11_s_32,
1032 FIB_ENTRY_FLAG_ATTACHED,
1034 &pfx_10_10_10_1_s_32.fp_addr,
1035 tm->hw[0]->sw_if_index,
1036 ~0, // invalid fib index
1039 FIB_ROUTE_PATH_FLAG_NONE);
1041 dpo = fib_entry_contribute_ip_forwarding(fei);
1042 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1043 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1044 "11.11.11.11/32 via incomplete adj");
1046 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1048 &pfx_10_10_10_1_s_32.fp_addr,
1049 tm->hw[0]->sw_if_index);
1050 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1051 adj = adj_get(ai_01);
1052 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1053 "adj is incomplete");
1054 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1055 &adj->sub_type.nbr.next_hop)),
1056 "adj nbr next-hop ok");
1058 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1059 fib_test_build_rewrite(eth_addr));
1060 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1062 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1063 &adj->sub_type.nbr.next_hop)),
1064 "adj nbr next-hop ok");
1065 ai = fib_entry_get_adj(fei);
1066 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1068 dpo = fib_entry_contribute_ip_forwarding(fei);
1069 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1070 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1071 "11.11.11.11/32 via complete adj");
1072 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1073 tm->hw[0]->sw_if_index),
1074 "RPF list for adj-fib contains adj");
1076 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1079 tm->hw[1]->sw_if_index);
1080 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1081 adj = adj_get(ai_12_12_12_12);
1082 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1083 "adj is incomplete");
1084 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1085 &adj->sub_type.nbr.next_hop)),
1086 "adj nbr next-hop ok");
1087 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1088 fib_test_build_rewrite(eth_addr));
1089 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1095 fei = fib_table_entry_path_add(fib_index,
1096 &pfx_10_10_10_1_s_32,
1098 FIB_ENTRY_FLAG_ATTACHED,
1100 &pfx_10_10_10_1_s_32.fp_addr,
1101 tm->hw[0]->sw_if_index,
1102 ~0, // invalid fib index
1105 FIB_ROUTE_PATH_FLAG_NONE);
1106 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1107 "Flags set on adj-fib");
1108 ai = fib_entry_get_adj(fei);
1109 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1111 fib_table_entry_path_remove(fib_index,
1112 &pfx_11_11_11_11_s_32,
1115 &pfx_10_10_10_1_s_32.fp_addr,
1116 tm->hw[0]->sw_if_index,
1117 ~0, // invalid fib index
1119 FIB_ROUTE_PATH_FLAG_NONE);
1123 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1125 &pfx_10_10_10_2_s_32.fp_addr,
1126 tm->hw[0]->sw_if_index);
1127 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1128 adj = adj_get(ai_02);
1129 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1130 "adj is incomplete");
1131 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1132 &adj->sub_type.nbr.next_hop)),
1133 "adj nbr next-hop ok");
1135 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1136 fib_test_build_rewrite(eth_addr));
1137 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1139 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1140 &adj->sub_type.nbr.next_hop)),
1141 "adj nbr next-hop ok");
1142 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1144 fib_table_entry_path_add(fib_index,
1145 &pfx_10_10_10_2_s_32,
1147 FIB_ENTRY_FLAG_ATTACHED,
1149 &pfx_10_10_10_2_s_32.fp_addr,
1150 tm->hw[0]->sw_if_index,
1151 ~0, // invalid fib index
1154 FIB_ROUTE_PATH_FLAG_NONE);
1156 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1157 ai = fib_entry_get_adj(fei);
1158 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1161 * +2 adj-fibs, and their non-shared path-lists
1163 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1164 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1165 fib_path_list_pool_size());
1166 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1167 fib_entry_pool_size());
1170 * Add 2 routes via the first ADJ. ensure path-list sharing
1172 fib_prefix_t pfx_1_1_1_1_s_32 = {
1174 .fp_proto = FIB_PROTOCOL_IP4,
1177 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1181 fib_table_entry_path_add(fib_index,
1184 FIB_ENTRY_FLAG_NONE,
1187 tm->hw[0]->sw_if_index,
1188 ~0, // invalid fib index
1191 FIB_ROUTE_PATH_FLAG_NONE);
1192 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1193 ai = fib_entry_get_adj(fei);
1194 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1197 * +1 entry and a shared path-list
1199 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1200 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1201 fib_path_list_pool_size());
1202 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1203 fib_entry_pool_size());
1206 fib_prefix_t pfx_1_1_2_0_s_24 = {
1208 .fp_proto = FIB_PROTOCOL_IP4,
1210 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1214 fib_table_entry_path_add(fib_index,
1217 FIB_ENTRY_FLAG_NONE,
1220 tm->hw[0]->sw_if_index,
1221 ~0, // invalid fib index
1224 FIB_ROUTE_PATH_FLAG_NONE);
1225 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1226 ai = fib_entry_get_adj(fei);
1227 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1232 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1233 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1234 fib_path_list_pool_size());
1235 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1236 fib_entry_pool_size());
1239 * modify 1.1.2.0/24 to use multipath.
1241 fib_table_entry_path_add(fib_index,
1244 FIB_ENTRY_FLAG_NONE,
1247 tm->hw[0]->sw_if_index,
1248 ~0, // invalid fib index
1251 FIB_ROUTE_PATH_FLAG_NONE);
1252 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1253 dpo = fib_entry_contribute_ip_forwarding(fei);
1254 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1255 1, tm->hw[0]->sw_if_index),
1256 "RPF list for 1.1.2.0/24 contains both adjs");
1258 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1259 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1260 FIB_TEST((ai_01 == dpo1->dpoi_index),
1261 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1262 ai_01, dpo1->dpoi_index);
1264 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1265 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1266 FIB_TEST((ai_02 == dpo1->dpoi_index),
1267 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1270 * +1 shared-pathlist
1272 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1273 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1274 fib_path_list_pool_size());
1275 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1276 fib_entry_pool_size());
1281 fib_table_entry_path_remove(fib_index,
1286 tm->hw[0]->sw_if_index,
1289 FIB_ROUTE_PATH_FLAG_NONE);
1290 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1291 dpo = fib_entry_contribute_ip_forwarding(fei);
1292 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1293 1, tm->hw[0]->sw_if_index),
1294 "RPF list for 1.1.2.0/24 contains one adj");
1296 ai = fib_entry_get_adj(fei);
1297 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1300 * +1 shared-pathlist
1302 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1303 fib_path_list_db_size());
1304 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1305 fib_path_list_pool_size());
1306 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1307 fib_entry_pool_size());
1310 * Add 2 recursive routes:
1311 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1312 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1314 fib_prefix_t bgp_100_pfx = {
1316 .fp_proto = FIB_PROTOCOL_IP4,
1318 /* 100.100.100.100/32 */
1319 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1323 ip46_address_t nh_1_1_1_1 = {
1324 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1327 fei = fib_table_entry_path_add(fib_index,
1330 FIB_ENTRY_FLAG_NONE,
1333 ~0, // no index provided.
1334 fib_index, // nexthop in same fib as route
1337 FIB_ROUTE_PATH_FLAG_NONE);
1339 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1340 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1341 tm->hw[0]->sw_if_index),
1342 "RPF list for adj-fib contains adj");
1345 * +1 entry and +1 shared-path-list
1347 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1348 fib_path_list_db_size());
1349 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1350 fib_path_list_pool_size());
1351 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1352 fib_entry_pool_size());
1354 fib_prefix_t bgp_101_pfx = {
1356 .fp_proto = FIB_PROTOCOL_IP4,
1358 /* 100.100.100.101/32 */
1359 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1363 fib_table_entry_path_add(fib_index,
1366 FIB_ENTRY_FLAG_NONE,
1369 ~0, // no index provided.
1370 fib_index, // nexthop in same fib as route
1373 FIB_ROUTE_PATH_FLAG_NONE);
1375 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1376 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1377 tm->hw[0]->sw_if_index),
1378 "RPF list for adj-fib contains adj");
1381 * +1 entry, but the recursive path-list is shared.
1383 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1384 fib_path_list_db_size());
1385 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1386 fib_path_list_pool_size());
1387 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1388 fib_entry_pool_size());
1391 * An special route; one where the user (me) provides the
1392 * adjacency through which the route will resovle by setting the flags
1394 fib_prefix_t ex_pfx = {
1396 .fp_proto = FIB_PROTOCOL_IP4,
1399 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1403 fib_table_entry_special_add(fib_index,
1406 FIB_ENTRY_FLAG_LOCAL);
1407 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1408 dpo = fib_entry_contribute_ip_forwarding(fei);
1409 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1410 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1411 "local interface adj is local");
1413 fib_table_entry_special_remove(fib_index,
1415 FIB_SOURCE_SPECIAL);
1416 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1417 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1418 "Exclusive reoute removed");
1421 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1422 * adjacency through which the route will resovle
1424 dpo_id_t ex_dpo = DPO_INVALID;
1426 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1429 LOOKUP_INPUT_DST_ADDR,
1430 LOOKUP_TABLE_FROM_CONFIG,
1433 fib_table_entry_special_dpo_add(fib_index,
1436 FIB_ENTRY_FLAG_EXCLUSIVE,
1438 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1439 dpo = fib_entry_contribute_ip_forwarding(fei);
1440 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1441 "exclusive remote uses lookup DPO");
1444 * update the exclusive to use a different DPO
1446 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1447 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1449 fib_table_entry_special_dpo_update(fib_index,
1452 FIB_ENTRY_FLAG_EXCLUSIVE,
1454 dpo = fib_entry_contribute_ip_forwarding(fei);
1455 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1456 "exclusive remote uses now uses NULL DPO");
1458 fib_table_entry_special_remove(fib_index,
1460 FIB_SOURCE_SPECIAL);
1461 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1462 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1463 "Exclusive reoute removed");
1467 * Add a recursive route:
1468 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1470 fib_prefix_t bgp_200_pfx = {
1472 .fp_proto = FIB_PROTOCOL_IP4,
1474 /* 200.200.200.200/32 */
1475 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1479 fib_prefix_t pfx_1_1_1_2_s_32 = {
1481 .fp_proto = FIB_PROTOCOL_IP4,
1483 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1487 fei = fib_table_entry_path_add(fib_index,
1490 FIB_ENTRY_FLAG_NONE,
1492 &pfx_1_1_1_2_s_32.fp_addr,
1493 ~0, // no index provided.
1494 fib_index, // nexthop in same fib as route
1497 FIB_ROUTE_PATH_FLAG_NONE);
1499 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1500 "Recursive via unresolved is drop");
1503 * the adj should be recursive via drop, since the route resolves via
1504 * the default route, which is itself a DROP
1506 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1507 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1508 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1509 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1510 "RPF list for 1.1.1.2/32 contains 0 adjs");
1513 * +2 entry and +1 shared-path-list
1515 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1516 fib_path_list_db_size());
1517 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1518 fib_path_list_pool_size());
1519 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1520 fib_entry_pool_size());
1523 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1524 * The paths are sort by NH first. in this case the the path with greater
1525 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1527 fib_prefix_t pfx_1_2_3_4_s_32 = {
1529 .fp_proto = FIB_PROTOCOL_IP4,
1531 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1534 fib_table_entry_path_add(fib_index,
1537 FIB_ENTRY_FLAG_NONE,
1540 tm->hw[0]->sw_if_index,
1544 FIB_ROUTE_PATH_FLAG_NONE);
1545 fei = fib_table_entry_path_add(fib_index,
1548 FIB_ENTRY_FLAG_NONE,
1551 tm->hw[1]->sw_if_index,
1555 FIB_ROUTE_PATH_FLAG_NONE);
1557 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1558 dpo = fib_entry_contribute_ip_forwarding(fei);
1559 lb = load_balance_get(dpo->dpoi_index);
1560 FIB_TEST((lb->lb_n_buckets == 4),
1561 "1.2.3.4/32 LB has %d bucket",
1564 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1565 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1566 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1567 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1569 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1570 tm->hw[0]->sw_if_index,
1571 tm->hw[1]->sw_if_index),
1572 "RPF list for 1.2.3.4/32 contains both adjs");
1576 * Unequal Cost load-balance. 4:1 ratio.
1577 * fits in a 16 bucket LB with ratio 13:3
1579 fib_prefix_t pfx_1_2_3_5_s_32 = {
1581 .fp_proto = FIB_PROTOCOL_IP4,
1583 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1586 fib_table_entry_path_add(fib_index,
1589 FIB_ENTRY_FLAG_NONE,
1592 tm->hw[1]->sw_if_index,
1596 FIB_ROUTE_PATH_FLAG_NONE);
1597 fei = fib_table_entry_path_add(fib_index,
1600 FIB_ENTRY_FLAG_NONE,
1603 tm->hw[0]->sw_if_index,
1607 FIB_ROUTE_PATH_FLAG_NONE);
1609 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1610 dpo = fib_entry_contribute_ip_forwarding(fei);
1611 lb = load_balance_get(dpo->dpoi_index);
1612 FIB_TEST((lb->lb_n_buckets == 16),
1613 "1.2.3.5/32 LB has %d bucket",
1616 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1617 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1618 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1619 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1620 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1621 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1622 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1623 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1624 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1625 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1626 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1627 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1628 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1629 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1630 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1631 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1633 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1634 tm->hw[0]->sw_if_index,
1635 tm->hw[1]->sw_if_index),
1636 "RPF list for 1.2.3.4/32 contains both adjs");
1639 * Test UCMP with a large weight skew - this produces load-balance objects with large
1640 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1641 * laso testing the LB in placce modify code when number of buckets is large.
1643 fib_prefix_t pfx_6_6_6_6_s_32 = {
1645 .fp_proto = FIB_PROTOCOL_IP4,
1648 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1651 fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1657 fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1663 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1666 .adj = ai_12_12_12_12,
1669 fib_table_entry_update_one_path(fib_index,
1672 FIB_ENTRY_FLAG_NONE,
1675 tm->hw[0]->sw_if_index,
1676 ~0, // invalid fib index
1679 FIB_ROUTE_PATH_FLAG_NONE);
1681 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1682 FIB_TEST(fib_test_validate_entry(fei,
1683 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1686 "6.6.6.6/32 via 10.10.10.1");
1688 fib_table_entry_path_add(fib_index,
1691 FIB_ENTRY_FLAG_NONE,
1694 tm->hw[0]->sw_if_index,
1695 ~0, // invalid fib index
1698 FIB_ROUTE_PATH_FLAG_NONE);
1700 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1701 FIB_TEST(fib_test_validate_entry(fei,
1702 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1768 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1770 fib_table_entry_path_add(fib_index,
1773 FIB_ENTRY_FLAG_NONE,
1776 tm->hw[1]->sw_if_index,
1777 ~0, // invalid fib index
1780 FIB_ROUTE_PATH_FLAG_NONE);
1782 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1783 FIB_TEST(fib_test_validate_entry(fei,
1784 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1851 &ip_6_6_6_6_o_12_12_12_12,
1852 &ip_6_6_6_6_o_12_12_12_12,
1853 &ip_6_6_6_6_o_12_12_12_12,
1854 &ip_6_6_6_6_o_12_12_12_12,
1855 &ip_6_6_6_6_o_12_12_12_12,
1856 &ip_6_6_6_6_o_12_12_12_12,
1857 &ip_6_6_6_6_o_12_12_12_12,
1858 &ip_6_6_6_6_o_12_12_12_12,
1859 &ip_6_6_6_6_o_12_12_12_12,
1860 &ip_6_6_6_6_o_12_12_12_12,
1861 &ip_6_6_6_6_o_12_12_12_12,
1862 &ip_6_6_6_6_o_12_12_12_12,
1863 &ip_6_6_6_6_o_12_12_12_12,
1864 &ip_6_6_6_6_o_12_12_12_12,
1865 &ip_6_6_6_6_o_12_12_12_12,
1866 &ip_6_6_6_6_o_12_12_12_12,
1867 &ip_6_6_6_6_o_12_12_12_12,
1868 &ip_6_6_6_6_o_12_12_12_12,
1869 &ip_6_6_6_6_o_12_12_12_12,
1870 &ip_6_6_6_6_o_12_12_12_12,
1871 &ip_6_6_6_6_o_12_12_12_12,
1872 &ip_6_6_6_6_o_12_12_12_12,
1873 &ip_6_6_6_6_o_12_12_12_12,
1874 &ip_6_6_6_6_o_12_12_12_12,
1875 &ip_6_6_6_6_o_12_12_12_12,
1876 &ip_6_6_6_6_o_12_12_12_12,
1877 &ip_6_6_6_6_o_12_12_12_12,
1878 &ip_6_6_6_6_o_12_12_12_12,
1879 &ip_6_6_6_6_o_12_12_12_12,
1880 &ip_6_6_6_6_o_12_12_12_12,
1881 &ip_6_6_6_6_o_12_12_12_12,
1882 &ip_6_6_6_6_o_12_12_12_12,
1883 &ip_6_6_6_6_o_12_12_12_12,
1884 &ip_6_6_6_6_o_12_12_12_12,
1885 &ip_6_6_6_6_o_12_12_12_12,
1886 &ip_6_6_6_6_o_12_12_12_12,
1887 &ip_6_6_6_6_o_12_12_12_12,
1888 &ip_6_6_6_6_o_12_12_12_12,
1889 &ip_6_6_6_6_o_12_12_12_12,
1890 &ip_6_6_6_6_o_12_12_12_12,
1891 &ip_6_6_6_6_o_12_12_12_12,
1892 &ip_6_6_6_6_o_12_12_12_12,
1893 &ip_6_6_6_6_o_12_12_12_12,
1894 &ip_6_6_6_6_o_12_12_12_12,
1895 &ip_6_6_6_6_o_12_12_12_12,
1896 &ip_6_6_6_6_o_12_12_12_12,
1897 &ip_6_6_6_6_o_12_12_12_12,
1898 &ip_6_6_6_6_o_12_12_12_12,
1899 &ip_6_6_6_6_o_12_12_12_12,
1900 &ip_6_6_6_6_o_12_12_12_12,
1901 &ip_6_6_6_6_o_12_12_12_12,
1902 &ip_6_6_6_6_o_12_12_12_12,
1903 &ip_6_6_6_6_o_12_12_12_12,
1904 &ip_6_6_6_6_o_12_12_12_12,
1905 &ip_6_6_6_6_o_12_12_12_12,
1906 &ip_6_6_6_6_o_12_12_12_12,
1907 &ip_6_6_6_6_o_12_12_12_12,
1908 &ip_6_6_6_6_o_12_12_12_12,
1909 &ip_6_6_6_6_o_12_12_12_12,
1910 &ip_6_6_6_6_o_12_12_12_12,
1911 &ip_6_6_6_6_o_12_12_12_12,
1912 &ip_6_6_6_6_o_12_12_12_12,
1913 &ip_6_6_6_6_o_12_12_12_12),
1914 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1916 fib_table_entry_path_remove(fib_index,
1921 tm->hw[1]->sw_if_index,
1922 ~0, // invalid fib index
1924 FIB_ROUTE_PATH_FLAG_NONE);
1926 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1927 FIB_TEST(fib_test_validate_entry(fei,
1928 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1994 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1996 fib_table_entry_path_remove(fib_index,
2001 tm->hw[0]->sw_if_index,
2002 ~0, // invalid fib index
2004 FIB_ROUTE_PATH_FLAG_NONE);
2006 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2007 FIB_TEST(fib_test_validate_entry(fei,
2008 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2011 "6.6.6.6/32 via 10.10.10.1");
2013 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2016 * A recursive via the two unequal cost entries
2018 fib_prefix_t bgp_44_s_32 = {
2020 .fp_proto = FIB_PROTOCOL_IP4,
2022 /* 200.200.200.201/32 */
2023 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2026 fei = fib_table_entry_path_add(fib_index,
2029 FIB_ENTRY_FLAG_NONE,
2031 &pfx_1_2_3_4_s_32.fp_addr,
2036 FIB_ROUTE_PATH_FLAG_NONE);
2037 fei = fib_table_entry_path_add(fib_index,
2040 FIB_ENTRY_FLAG_NONE,
2042 &pfx_1_2_3_5_s_32.fp_addr,
2047 FIB_ROUTE_PATH_FLAG_NONE);
2049 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2050 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2051 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2052 tm->hw[0]->sw_if_index,
2053 tm->hw[1]->sw_if_index),
2054 "RPF list for 1.2.3.4/32 contains both adjs");
2057 * test the uRPF check functions
2059 dpo_id_t dpo_44 = DPO_INVALID;
2062 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2063 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2065 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2066 "uRPF check for 68.68.68.68/32 on %d OK",
2067 tm->hw[0]->sw_if_index);
2068 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2069 "uRPF check for 68.68.68.68/32 on %d OK",
2070 tm->hw[1]->sw_if_index);
2071 FIB_TEST(!fib_urpf_check(urpfi, 99),
2072 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2076 fib_table_entry_delete(fib_index,
2079 fib_table_entry_delete(fib_index,
2082 fib_table_entry_delete(fib_index,
2087 * Add a recursive route:
2088 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2090 fib_prefix_t bgp_201_pfx = {
2092 .fp_proto = FIB_PROTOCOL_IP4,
2094 /* 200.200.200.201/32 */
2095 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2099 fib_prefix_t pfx_1_1_1_200_s_32 = {
2101 .fp_proto = FIB_PROTOCOL_IP4,
2103 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2107 fei = fib_table_entry_path_add(fib_index,
2110 FIB_ENTRY_FLAG_NONE,
2112 &pfx_1_1_1_200_s_32.fp_addr,
2113 ~0, // no index provided.
2114 fib_index, // nexthop in same fib as route
2117 FIB_ROUTE_PATH_FLAG_NONE);
2119 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2120 "Recursive via unresolved is drop");
2122 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2123 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2124 "Flags set on RR via non-attached");
2125 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2126 "RPF list for BGP route empty");
2129 * +2 entry (BGP & RR) and +1 shared-path-list
2131 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2132 fib_path_list_db_size());
2133 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2134 fib_path_list_pool_size());
2135 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2136 fib_entry_pool_size());
2139 * insert a route that covers the missing 1.1.1.2/32. we epxect
2140 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2142 fib_prefix_t pfx_1_1_1_0_s_24 = {
2144 .fp_proto = FIB_PROTOCOL_IP4,
2147 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2151 fib_table_entry_path_add(fib_index,
2154 FIB_ENTRY_FLAG_NONE,
2157 tm->hw[0]->sw_if_index,
2158 ~0, // invalid fib index
2161 FIB_ROUTE_PATH_FLAG_NONE);
2162 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2163 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2164 ai = fib_entry_get_adj(fei);
2165 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2166 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2167 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2168 ai = fib_entry_get_adj(fei);
2169 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2170 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2171 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2172 ai = fib_entry_get_adj(fei);
2173 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2176 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2178 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2179 fib_path_list_db_size());
2180 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2181 fib_path_list_pool_size());
2182 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2183 fib_entry_pool_size());
2186 * the recursive adj for 200.200.200.200 should be updated.
2188 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2189 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2190 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2191 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2192 tm->hw[0]->sw_if_index),
2193 "RPF list for BGP route has itf index 0");
2196 * insert a more specific route than 1.1.1.0/24 that also covers the
2197 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2198 * 200.200.200.200 to resolve through it.
2200 fib_prefix_t pfx_1_1_1_0_s_28 = {
2202 .fp_proto = FIB_PROTOCOL_IP4,
2205 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2209 fib_table_entry_path_add(fib_index,
2212 FIB_ENTRY_FLAG_NONE,
2215 tm->hw[0]->sw_if_index,
2216 ~0, // invalid fib index
2219 FIB_ROUTE_PATH_FLAG_NONE);
2220 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2221 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2222 ai = fib_entry_get_adj(fei);
2223 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2226 * +1 entry. +1 shared path-list
2228 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2229 fib_path_list_db_size());
2230 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2231 fib_path_list_pool_size());
2232 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2233 fib_entry_pool_size());
2236 * the recursive adj for 200.200.200.200 should be updated.
2237 * 200.200.200.201 remains unchanged.
2239 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2240 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2243 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2245 fib_table_entry_path_remove(fib_index,
2250 tm->hw[0]->sw_if_index,
2253 FIB_ROUTE_PATH_FLAG_NONE);
2254 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2255 FIB_NODE_INDEX_INVALID),
2256 "1.1.1.0/28 removed");
2257 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2258 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2259 "1.1.1.0/28 lookup via /24");
2260 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2261 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2264 * -1 entry. -1 shared path-list
2266 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2267 fib_path_list_db_size());
2268 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2269 fib_path_list_pool_size());
2270 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2271 fib_entry_pool_size());
2274 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2276 fib_table_entry_path_remove(fib_index,
2281 tm->hw[0]->sw_if_index,
2284 FIB_ROUTE_PATH_FLAG_NONE);
2285 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2286 FIB_NODE_INDEX_INVALID),
2287 "1.1.1.0/24 removed");
2289 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2290 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2291 "1.1.1.2/32 route is DROP");
2292 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2293 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2294 "1.1.1.200/32 route is DROP");
2296 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2297 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2299 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2300 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2306 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2307 fib_path_list_db_size());
2308 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2309 fib_path_list_pool_size());
2310 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2311 fib_entry_pool_size());
2314 * insert the missing 1.1.1.2/32
2316 fei = fib_table_entry_path_add(fib_index,
2319 FIB_ENTRY_FLAG_NONE,
2322 tm->hw[0]->sw_if_index,
2323 ~0, // invalid fib index
2326 FIB_ROUTE_PATH_FLAG_NONE);
2327 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2328 ai = fib_entry_get_adj(fei);
2329 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2331 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2332 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2334 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2337 * no change. 1.1.1.2/32 was already there RR sourced.
2339 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2340 fib_path_list_db_size());
2341 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2342 fib_path_list_pool_size());
2343 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2344 fib_entry_pool_size());
2347 * give 201 a resolved path.
2348 * it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
2349 * only the latter contributes forwarding.
2351 fei = fib_table_entry_path_add(fib_index,
2354 FIB_ENTRY_FLAG_NONE,
2356 &pfx_1_1_1_2_s_32.fp_addr,
2361 FIB_ROUTE_PATH_FLAG_NONE);
2362 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
2363 fib_table_entry_path_remove(fib_index,
2367 &pfx_1_1_1_2_s_32.fp_addr,
2371 FIB_ROUTE_PATH_FLAG_NONE);
2374 * remove 200.200.200.201/32 which does not have a valid via FIB
2376 fib_table_entry_path_remove(fib_index,
2380 &pfx_1_1_1_200_s_32.fp_addr,
2381 ~0, // no index provided.
2384 FIB_ROUTE_PATH_FLAG_NONE);
2387 * -2 entries (BGP and RR). -1 shared path-list;
2389 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2390 FIB_NODE_INDEX_INVALID),
2391 "200.200.200.201/32 removed");
2392 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2393 FIB_NODE_INDEX_INVALID),
2394 "1.1.1.200/32 removed");
2396 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2397 fib_path_list_db_size());
2398 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2399 fib_path_list_pool_size());
2400 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2401 fib_entry_pool_size());
2404 * remove 200.200.200.200/32 which does have a valid via FIB
2406 fib_table_entry_path_remove(fib_index,
2410 &pfx_1_1_1_2_s_32.fp_addr,
2411 ~0, // no index provided.
2414 FIB_ROUTE_PATH_FLAG_NONE);
2416 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2417 FIB_NODE_INDEX_INVALID),
2418 "200.200.200.200/32 removed");
2419 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2420 FIB_NODE_INDEX_INVALID),
2421 "1.1.1.2/32 still present");
2424 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2426 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2427 fib_path_list_db_size());
2428 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2429 fib_path_list_pool_size());
2430 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2431 fib_entry_pool_size());
2434 * A recursive prefix that has a 2 path load-balance.
2435 * It also shares a next-hop with other BGP prefixes and hence
2436 * test the ref counting of RR sourced prefixes and 2 level LB.
2438 const fib_prefix_t bgp_102 = {
2440 .fp_proto = FIB_PROTOCOL_IP4,
2442 /* 100.100.100.101/32 */
2443 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2446 fib_table_entry_path_add(fib_index,
2449 FIB_ENTRY_FLAG_NONE,
2451 &pfx_1_1_1_1_s_32.fp_addr,
2452 ~0, // no index provided.
2453 fib_index, // same as route
2456 FIB_ROUTE_PATH_FLAG_NONE);
2457 fib_table_entry_path_add(fib_index,
2460 FIB_ENTRY_FLAG_NONE,
2462 &pfx_1_1_1_2_s_32.fp_addr,
2463 ~0, // no index provided.
2464 fib_index, // same as route's FIB
2467 FIB_ROUTE_PATH_FLAG_NONE);
2468 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2469 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2470 dpo = fib_entry_contribute_ip_forwarding(fei);
2472 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2473 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2474 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2475 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2477 lb = load_balance_get(dpo->dpoi_index);
2478 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2479 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2480 "First via 10.10.10.1");
2481 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2482 "Second via 10.10.10.1");
2484 fib_table_entry_path_remove(fib_index,
2488 &pfx_1_1_1_1_s_32.fp_addr,
2489 ~0, // no index provided.
2490 fib_index, // same as route's FIB
2492 FIB_ROUTE_PATH_FLAG_NONE);
2493 fib_table_entry_path_remove(fib_index,
2497 &pfx_1_1_1_2_s_32.fp_addr,
2498 ~0, // no index provided.
2499 fib_index, // same as route's FIB
2501 FIB_ROUTE_PATH_FLAG_NONE);
2502 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2503 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2506 * remove the remaining recursives
2508 fib_table_entry_path_remove(fib_index,
2512 &pfx_1_1_1_1_s_32.fp_addr,
2513 ~0, // no index provided.
2514 fib_index, // same as route's FIB
2516 FIB_ROUTE_PATH_FLAG_NONE);
2517 fib_table_entry_path_remove(fib_index,
2521 &pfx_1_1_1_1_s_32.fp_addr,
2522 ~0, // no index provided.
2523 fib_index, // same as route's FIB
2525 FIB_ROUTE_PATH_FLAG_NONE);
2526 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2527 FIB_NODE_INDEX_INVALID),
2528 "100.100.100.100/32 removed");
2529 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2530 FIB_NODE_INDEX_INVALID),
2531 "100.100.100.101/32 removed");
2534 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2536 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2537 fib_path_list_db_size());
2538 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2539 fib_path_list_pool_size());
2540 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2541 fib_entry_pool_size());
2544 * Add a recursive route via a connected cover, using an adj-fib that does exist
2546 fib_table_entry_path_add(fib_index,
2549 FIB_ENTRY_FLAG_NONE,
2552 ~0, // no index provided.
2553 fib_index, // Same as route's FIB
2556 FIB_ROUTE_PATH_FLAG_NONE);
2559 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2561 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2562 fib_path_list_db_size());
2563 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2564 fib_path_list_pool_size());
2565 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2566 fib_entry_pool_size());
2568 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2569 dpo = fib_entry_contribute_ip_forwarding(fei);
2571 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2572 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2574 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2575 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2577 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2578 "Flags set on RR via existing attached");
2581 * Add a recursive route via a connected cover, using and adj-fib that does
2584 ip46_address_t nh_10_10_10_3 = {
2585 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2587 fib_prefix_t pfx_10_10_10_3 = {
2589 .fp_proto = FIB_PROTOCOL_IP4,
2590 .fp_addr = nh_10_10_10_3,
2593 fib_table_entry_path_add(fib_index,
2596 FIB_ENTRY_FLAG_NONE,
2599 ~0, // no index provided.
2603 FIB_ROUTE_PATH_FLAG_NONE);
2606 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2607 * one unshared non-recursive via 10.10.10.3
2609 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2610 fib_path_list_db_size());
2611 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2612 fib_path_list_pool_size());
2613 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2614 fib_entry_pool_size());
2616 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2619 tm->hw[0]->sw_if_index);
2621 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2622 dpo = fib_entry_contribute_ip_forwarding(fei);
2623 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2624 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2626 ai = fib_entry_get_adj(fei);
2627 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2628 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2629 fib_entry_get_flags(fei)),
2630 "Flags set on RR via non-existing attached");
2632 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2633 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2638 * remove the recursives
2640 fib_table_entry_path_remove(fib_index,
2645 ~0, // no index provided.
2646 fib_index, // same as route's FIB
2648 FIB_ROUTE_PATH_FLAG_NONE);
2649 fib_table_entry_path_remove(fib_index,
2654 ~0, // no index provided.
2655 fib_index, // same as route's FIB
2657 FIB_ROUTE_PATH_FLAG_NONE);
2659 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2660 FIB_NODE_INDEX_INVALID),
2661 "200.200.200.201/32 removed");
2662 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2663 FIB_NODE_INDEX_INVALID),
2664 "200.200.200.200/32 removed");
2665 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2666 FIB_NODE_INDEX_INVALID),
2667 "10.10.10.3/32 removed");
2670 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2671 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2673 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2674 fib_path_list_db_size());
2675 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2676 fib_path_list_pool_size());
2677 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2678 fib_entry_pool_size());
2683 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2685 fib_prefix_t pfx_5_5_5_5_s_32 = {
2687 .fp_proto = FIB_PROTOCOL_IP4,
2689 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2692 fib_prefix_t pfx_5_5_5_6_s_32 = {
2694 .fp_proto = FIB_PROTOCOL_IP4,
2696 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2699 fib_prefix_t pfx_5_5_5_7_s_32 = {
2701 .fp_proto = FIB_PROTOCOL_IP4,
2703 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2707 fib_table_entry_path_add(fib_index,
2710 FIB_ENTRY_FLAG_NONE,
2712 &pfx_5_5_5_6_s_32.fp_addr,
2713 ~0, // no index provided.
2717 FIB_ROUTE_PATH_FLAG_NONE);
2718 fib_table_entry_path_add(fib_index,
2721 FIB_ENTRY_FLAG_NONE,
2723 &pfx_5_5_5_7_s_32.fp_addr,
2724 ~0, // no index provided.
2728 FIB_ROUTE_PATH_FLAG_NONE);
2729 fib_table_entry_path_add(fib_index,
2732 FIB_ENTRY_FLAG_NONE,
2734 &pfx_5_5_5_5_s_32.fp_addr,
2735 ~0, // no index provided.
2739 FIB_ROUTE_PATH_FLAG_NONE);
2741 * +3 entries, +3 shared path-list
2743 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2744 fib_path_list_db_size());
2745 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2746 fib_path_list_pool_size());
2747 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2748 fib_entry_pool_size());
2751 * All the entries have only looped paths, so they are all drop
2753 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2754 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2755 "LB for 5.5.5.7/32 is via adj for DROP");
2756 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2757 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2758 "LB for 5.5.5.5/32 is via adj for DROP");
2759 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2760 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2761 "LB for 5.5.5.6/32 is via adj for DROP");
2764 * provide 5.5.5.6/32 with alternate path.
2765 * this will allow only 5.5.5.6/32 to forward with this path, the others
2766 * are still drop since the loop is still present.
2768 fib_table_entry_path_add(fib_index,
2771 FIB_ENTRY_FLAG_NONE,
2774 tm->hw[0]->sw_if_index,
2778 FIB_ROUTE_PATH_FLAG_NONE);
2780 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2781 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2783 lb = load_balance_get(dpo1->dpoi_index);
2784 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2786 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2787 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2788 FIB_TEST((ai_01 == dpo2->dpoi_index),
2789 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2791 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2792 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2793 "LB for 5.5.5.7/32 is via adj for DROP");
2794 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2795 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2796 "LB for 5.5.5.5/32 is via adj for DROP");
2799 * remove the alternate path for 5.5.5.6/32
2802 fib_table_entry_path_remove(fib_index,
2807 tm->hw[0]->sw_if_index,
2810 FIB_ROUTE_PATH_FLAG_NONE);
2812 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2813 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2814 "LB for 5.5.5.7/32 is via adj for DROP");
2815 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2816 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2817 "LB for 5.5.5.5/32 is via adj for DROP");
2818 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2819 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2820 "LB for 5.5.5.6/32 is via adj for DROP");
2823 * break the loop by giving 5.5.5.5/32 a new set of paths
2824 * expect all to forward via this new path.
2826 fib_table_entry_update_one_path(fib_index,
2829 FIB_ENTRY_FLAG_NONE,
2832 tm->hw[0]->sw_if_index,
2833 ~0, // invalid fib index
2836 FIB_ROUTE_PATH_FLAG_NONE);
2838 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2839 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2840 lb = load_balance_get(dpo1->dpoi_index);
2841 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2843 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2844 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2845 FIB_TEST((ai_01 == dpo2->dpoi_index),
2846 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2848 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2849 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2851 lb = load_balance_get(dpo2->dpoi_index);
2852 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2853 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2854 "5.5.5.5.7 via 5.5.5.5");
2856 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2857 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2859 lb = load_balance_get(dpo1->dpoi_index);
2860 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2861 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2862 "5.5.5.5.6 via 5.5.5.7");
2865 * revert back to the loop. so we can remove the prefixes with
2868 fib_table_entry_update_one_path(fib_index,
2871 FIB_ENTRY_FLAG_NONE,
2873 &pfx_5_5_5_6_s_32.fp_addr,
2874 ~0, // no index provided.
2878 FIB_ROUTE_PATH_FLAG_NONE);
2880 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2881 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2882 "LB for 5.5.5.7/32 is via adj for DROP");
2883 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2884 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2885 "LB for 5.5.5.5/32 is via adj for DROP");
2886 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2887 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2888 "LB for 5.5.5.6/32 is via adj for DROP");
2891 * remove all the 5.5.5.x/32 prefixes
2893 fib_table_entry_path_remove(fib_index,
2897 &pfx_5_5_5_6_s_32.fp_addr,
2898 ~0, // no index provided.
2899 fib_index, // same as route's FIB
2901 FIB_ROUTE_PATH_FLAG_NONE);
2902 fib_table_entry_path_remove(fib_index,
2906 &pfx_5_5_5_7_s_32.fp_addr,
2907 ~0, // no index provided.
2908 fib_index, // same as route's FIB
2910 FIB_ROUTE_PATH_FLAG_NONE);
2911 fib_table_entry_path_remove(fib_index,
2915 &pfx_5_5_5_5_s_32.fp_addr,
2916 ~0, // no index provided.
2917 fib_index, // same as route's FIB
2919 FIB_ROUTE_PATH_FLAG_NONE);
2920 fib_table_entry_path_remove(fib_index,
2925 ~0, // no index provided.
2926 fib_index, // same as route's FIB
2928 FIB_ROUTE_PATH_FLAG_NONE);
2931 * -3 entries, -3 shared path-list
2933 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2934 fib_path_list_db_size());
2935 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2936 fib_path_list_pool_size());
2937 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2938 fib_entry_pool_size());
2941 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2943 fib_table_entry_path_add(fib_index,
2946 FIB_ENTRY_FLAG_NONE,
2948 &pfx_5_5_5_6_s_32.fp_addr,
2949 ~0, // no index provided.
2953 FIB_ROUTE_PATH_FLAG_NONE);
2954 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2955 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2956 "1-level 5.5.5.6/32 loop is via adj for DROP");
2958 fib_table_entry_path_remove(fib_index,
2962 &pfx_5_5_5_6_s_32.fp_addr,
2963 ~0, // no index provided.
2964 fib_index, // same as route's FIB
2966 FIB_ROUTE_PATH_FLAG_NONE);
2967 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2968 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2969 "1-level 5.5.5.6/32 loop is removed");
2972 * A recursive route whose next-hop is covered by the prefix.
2973 * This would mean the via-fib, which inherits forwarding from its
2974 * cover, thus picks up forwarding from the prfix, which is via the
2975 * via-fib, and we have a loop.
2977 fib_prefix_t pfx_23_23_23_0_s_24 = {
2979 .fp_proto = FIB_PROTOCOL_IP4,
2981 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2984 fib_prefix_t pfx_23_23_23_23_s_32 = {
2986 .fp_proto = FIB_PROTOCOL_IP4,
2988 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2991 fei = fib_table_entry_path_add(fib_index,
2992 &pfx_23_23_23_0_s_24,
2994 FIB_ENTRY_FLAG_NONE,
2996 &pfx_23_23_23_23_s_32.fp_addr,
3001 FIB_ROUTE_PATH_FLAG_NONE);
3002 dpo = fib_entry_contribute_ip_forwarding(fei);
3003 FIB_TEST(load_balance_is_drop(dpo),
3004 "23.23.23.0/24 via covered is DROP");
3005 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3008 * add-remove test. no change.
3010 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3011 fib_path_list_db_size());
3012 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3013 fib_path_list_pool_size());
3014 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3015 fib_entry_pool_size());
3018 * Make the default route recursive via a unknown next-hop. Thus the
3019 * next hop's cover would be the default route
3021 fei = fib_table_entry_path_add(fib_index,
3024 FIB_ENTRY_FLAG_NONE,
3026 &pfx_23_23_23_23_s_32.fp_addr,
3031 FIB_ROUTE_PATH_FLAG_NONE);
3032 dpo = fib_entry_contribute_ip_forwarding(fei);
3033 FIB_TEST(load_balance_is_drop(dpo),
3034 "0.0.0.0.0/0 via is DROP");
3035 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3036 "no resolving interface for looped 0.0.0.0/0");
3038 fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3039 dpo = fib_entry_contribute_ip_forwarding(fei);
3040 FIB_TEST(load_balance_is_drop(dpo),
3041 "23.23.23.23/32 via is DROP");
3042 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3043 "no resolving interface for looped 23.23.23.23/32");
3045 fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3048 * A recursive route with recursion constraints.
3049 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3051 fib_table_entry_path_add(fib_index,
3054 FIB_ENTRY_FLAG_NONE,
3061 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3063 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3064 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3066 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3067 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3069 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3070 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3073 * save the load-balance. we expect it to be inplace modified
3075 lb = load_balance_get(dpo1->dpoi_index);
3078 * add a covering prefix for the via fib that would otherwise serve
3079 * as the resolving route when the host is removed
3081 fib_table_entry_path_add(fib_index,
3084 FIB_ENTRY_FLAG_NONE,
3087 tm->hw[0]->sw_if_index,
3088 ~0, // invalid fib index
3091 FIB_ROUTE_PATH_FLAG_NONE);
3092 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3093 ai = fib_entry_get_adj(fei);
3094 FIB_TEST((ai == ai_01),
3095 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3098 * remove the host via FIB - expect the BGP prefix to be drop
3100 fib_table_entry_path_remove(fib_index,
3105 tm->hw[0]->sw_if_index,
3106 ~0, // invalid fib index
3108 FIB_ROUTE_PATH_FLAG_NONE);
3110 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3111 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3114 * add the via-entry host reoute back. expect to resolve again
3116 fib_table_entry_path_add(fib_index,
3119 FIB_ENTRY_FLAG_NONE,
3122 tm->hw[0]->sw_if_index,
3123 ~0, // invalid fib index
3126 FIB_ROUTE_PATH_FLAG_NONE);
3127 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3128 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3131 * add another path for the recursive. it will then have 2.
3133 fib_prefix_t pfx_1_1_1_3_s_32 = {
3135 .fp_proto = FIB_PROTOCOL_IP4,
3137 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3140 fib_table_entry_path_add(fib_index,
3143 FIB_ENTRY_FLAG_NONE,
3146 tm->hw[0]->sw_if_index,
3147 ~0, // invalid fib index
3150 FIB_ROUTE_PATH_FLAG_NONE);
3152 fib_table_entry_path_add(fib_index,
3155 FIB_ENTRY_FLAG_NONE,
3157 &pfx_1_1_1_3_s_32.fp_addr,
3162 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3165 * add a bunch load more entries using this path combo so that we get
3166 * an LB-map created.
3169 fib_prefix_t bgp_78s[N_P];
3170 for (ii = 0; ii < N_P; ii++)
3172 bgp_78s[ii].fp_len = 32;
3173 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3174 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3177 fib_table_entry_path_add(fib_index,
3180 FIB_ENTRY_FLAG_NONE,
3182 &pfx_1_1_1_3_s_32.fp_addr,
3187 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3188 fib_table_entry_path_add(fib_index,
3191 FIB_ENTRY_FLAG_NONE,
3198 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3201 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3202 dpo = fib_entry_contribute_ip_forwarding(fei);
3204 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3205 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3206 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3207 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3208 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3209 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3210 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3211 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3214 * expect the lb-map used by the recursive's load-balance is using both buckets
3216 load_balance_map_t *lbm;
3219 lb = load_balance_get(dpo->dpoi_index);
3221 load_balance_map_lock(lbmi);
3222 lbm = load_balance_map_get(lbmi);
3224 FIB_TEST(lbm->lbm_buckets[0] == 0,
3225 "LB maps's bucket 0 is %d",
3226 lbm->lbm_buckets[0]);
3227 FIB_TEST(lbm->lbm_buckets[1] == 1,
3228 "LB maps's bucket 1 is %d",
3229 lbm->lbm_buckets[1]);
3232 * withdraw one of the /32 via-entrys.
3233 * that ECMP path will be unresolved and forwarding should continue on the
3234 * other available path. this is an iBGP PIC edge failover.
3235 * Test the forwarding changes without re-fetching the adj from the
3236 * recursive entry. this ensures its the same one that is updated; i.e. an
3239 fib_table_entry_path_remove(fib_index,
3244 tm->hw[0]->sw_if_index,
3245 ~0, // invalid fib index
3247 FIB_ROUTE_PATH_FLAG_NONE);
3249 /* suspend so the update walk kicks int */
3250 vlib_process_suspend(vlib_get_main(), 1e-5);
3252 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3253 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3254 "post PIC 200.200.200.200/32 was inplace modified");
3256 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3257 "post PIC adj for 200.200.200.200/32 is recursive"
3258 " via adj for 1.1.1.3");
3261 * the LB maps that was locked above should have been modified to remove
3262 * the path that was down, and thus its bucket points to a path that is
3265 FIB_TEST(lbm->lbm_buckets[0] == 1,
3266 "LB maps's bucket 0 is %d",
3267 lbm->lbm_buckets[0]);
3268 FIB_TEST(lbm->lbm_buckets[1] == 1,
3269 "LB maps's bucket 1 is %d",
3270 lbm->lbm_buckets[1]);
3272 load_balance_map_unlock(lbmi);
3275 * add it back. again
3277 fib_table_entry_path_add(fib_index,
3280 FIB_ENTRY_FLAG_NONE,
3283 tm->hw[0]->sw_if_index,
3284 ~0, // invalid fib index
3287 FIB_ROUTE_PATH_FLAG_NONE);
3289 /* suspend so the update walk kicks in */
3290 vlib_process_suspend(vlib_get_main(), 1e-5);
3292 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3293 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3294 "via adj for 1.1.1.1");
3295 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3296 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3297 "via adj for 1.1.1.3");
3299 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3300 dpo = fib_entry_contribute_ip_forwarding(fei);
3301 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3302 "post PIC 200.200.200.200/32 was inplace modified");
3305 * add a 3rd path. this makes the LB 16 buckets.
3307 fib_table_entry_path_add(fib_index,
3310 FIB_ENTRY_FLAG_NONE,
3312 &pfx_1_1_1_2_s_32.fp_addr,
3317 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3318 for (ii = 0; ii < N_P; ii++)
3320 fib_table_entry_path_add(fib_index,
3323 FIB_ENTRY_FLAG_NONE,
3325 &pfx_1_1_1_2_s_32.fp_addr,
3330 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3333 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3334 dpo = fib_entry_contribute_ip_forwarding(fei);
3335 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3336 "200.200.200.200/32 was inplace modified for 3rd path");
3337 FIB_TEST(16 == lb->lb_n_buckets,
3338 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3341 load_balance_map_lock(lbmi);
3342 lbm = load_balance_map_get(lbmi);
3344 for (ii = 0; ii < 16; ii++)
3346 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3347 "LB Map for 200.200.200.200/32 at %d is %d",
3348 ii, lbm->lbm_buckets[ii]);
3352 * trigger PIC by removing the first via-entry
3353 * the first 6 buckets of the map should map to the next 6
3355 fib_table_entry_path_remove(fib_index,
3360 tm->hw[0]->sw_if_index,
3363 FIB_ROUTE_PATH_FLAG_NONE);
3364 /* suspend so the update walk kicks int */
3365 vlib_process_suspend(vlib_get_main(), 1e-5);
3367 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3368 dpo = fib_entry_contribute_ip_forwarding(fei);
3369 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3370 "200.200.200.200/32 was inplace modified for 3rd path");
3371 FIB_TEST(2 == lb->lb_n_buckets,
3372 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3374 for (ii = 0; ii < 6; ii++)
3376 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3377 "LB Map for 200.200.200.200/32 at %d is %d",
3378 ii, lbm->lbm_buckets[ii]);
3380 for (ii = 6; ii < 16; ii++)
3382 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3383 "LB Map for 200.200.200.200/32 at %d is %d",
3384 ii, lbm->lbm_buckets[ii]);
3386 load_balance_map_unlock(lbmi);
3391 fib_table_entry_path_add(fib_index,
3394 FIB_ENTRY_FLAG_NONE,
3397 tm->hw[0]->sw_if_index,
3401 FIB_ROUTE_PATH_FLAG_NONE);
3403 for (ii = 0; ii < N_P; ii++)
3405 fib_table_entry_delete(fib_index,
3408 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3409 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3411 format_fib_prefix, &bgp_78s[ii]);
3413 fib_table_entry_path_remove(fib_index,
3417 &pfx_1_1_1_2_s_32.fp_addr,
3421 MPLS_LABEL_INVALID);
3422 fib_table_entry_path_remove(fib_index,
3430 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3431 fib_table_entry_path_remove(fib_index,
3435 &pfx_1_1_1_3_s_32.fp_addr,
3439 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3440 fib_table_entry_delete(fib_index,
3443 fib_table_entry_delete(fib_index,
3446 /* suspend so the update walk kicks int */
3447 vlib_process_suspend(vlib_get_main(), 1e-5);
3448 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3449 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3450 "1.1.1.1/28 removed");
3451 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3452 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3453 "1.1.1.3/32 removed");
3454 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3455 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3456 "200.200.200.200/32 removed");
3459 * add-remove test. no change.
3461 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3462 fib_path_list_db_size());
3463 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3464 fib_path_list_pool_size());
3465 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3466 fib_entry_pool_size());
3469 * A route whose paths are built up iteratively and then removed
3472 fib_prefix_t pfx_4_4_4_4_s_32 = {
3474 .fp_proto = FIB_PROTOCOL_IP4,
3477 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3481 fib_table_entry_path_add(fib_index,
3484 FIB_ENTRY_FLAG_NONE,
3487 tm->hw[0]->sw_if_index,
3491 FIB_ROUTE_PATH_FLAG_NONE);
3492 fib_table_entry_path_add(fib_index,
3495 FIB_ENTRY_FLAG_NONE,
3498 tm->hw[0]->sw_if_index,
3502 FIB_ROUTE_PATH_FLAG_NONE);
3503 fib_table_entry_path_add(fib_index,
3506 FIB_ENTRY_FLAG_NONE,
3509 tm->hw[0]->sw_if_index,
3513 FIB_ROUTE_PATH_FLAG_NONE);
3514 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3515 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3516 "4.4.4.4/32 present");
3518 fib_table_entry_delete(fib_index,
3521 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3522 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3523 "4.4.4.4/32 removed");
3526 * add-remove test. no change.
3528 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3529 fib_path_list_db_size());
3530 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3531 fib_path_list_pool_size());
3532 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3533 fib_entry_pool_size());
3536 * A route with multiple paths at once
3538 fib_route_path_t *r_paths = NULL;
3540 for (ii = 0; ii < 4; ii++)
3542 fib_route_path_t r_path = {
3543 .frp_proto = DPO_PROTO_IP4,
3545 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3547 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3549 .frp_fib_index = ~0,
3551 vec_add1(r_paths, r_path);
3554 fib_table_entry_update(fib_index,
3557 FIB_ENTRY_FLAG_NONE,
3560 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3561 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3562 dpo = fib_entry_contribute_ip_forwarding(fei);
3564 lb = load_balance_get(dpo->dpoi_index);
3565 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3567 fib_table_entry_delete(fib_index,
3570 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3571 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3572 "4.4.4.4/32 removed");
3576 * add-remove test. no change.
3578 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3579 fib_path_list_db_size());
3580 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3581 fib_path_list_pool_size());
3582 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3583 fib_entry_pool_size());
3586 * A route deag route
3588 fib_table_entry_path_add(fib_index,
3591 FIB_ENTRY_FLAG_NONE,
3598 FIB_ROUTE_PATH_FLAG_NONE);
3600 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3601 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3603 dpo = fib_entry_contribute_ip_forwarding(fei);
3604 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3605 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3607 FIB_TEST((fib_index == lkd->lkd_fib_index),
3608 "4.4.4.4/32 is deag in %d %U",
3610 format_dpo_id, dpo, 0);
3612 fib_table_entry_delete(fib_index,
3615 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3616 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3617 "4.4.4.4/32 removed");
3621 * add-remove test. no change.
3623 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3624 fib_path_list_db_size());
3625 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3626 fib_path_list_pool_size());
3627 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3628 fib_entry_pool_size());
3632 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3634 fib_prefix_t pfx_34_1_1_1_s_32 = {
3636 .fp_proto = FIB_PROTOCOL_IP4,
3638 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3641 fib_prefix_t pfx_34_34_1_1_s_32 = {
3643 .fp_proto = FIB_PROTOCOL_IP4,
3645 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3648 fei = fib_table_entry_path_add(fib_index,
3649 &pfx_34_34_1_1_s_32,
3651 FIB_ENTRY_FLAG_NONE,
3654 tm->hw[0]->sw_if_index,
3658 FIB_ROUTE_PATH_FLAG_NONE);
3659 fei = fib_table_entry_path_add(fib_index,
3662 FIB_ENTRY_FLAG_NONE,
3664 &pfx_34_34_1_1_s_32.fp_addr,
3669 FIB_ROUTE_PATH_FLAG_NONE);
3670 fei = fib_table_entry_path_add(fib_index,
3673 FIB_ENTRY_FLAG_NONE,
3675 &pfx_34_34_1_1_s_32.fp_addr,
3680 FIB_ROUTE_PATH_FLAG_NONE);
3681 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3682 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3683 fib_table_entry_delete(fib_index,
3684 &pfx_34_34_1_1_s_32,
3689 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3690 * all of which are via 10.10.10.1, Itf1
3692 fib_table_entry_path_remove(fib_index,
3697 tm->hw[0]->sw_if_index,
3700 FIB_ROUTE_PATH_FLAG_NONE);
3701 fib_table_entry_path_remove(fib_index,
3706 tm->hw[0]->sw_if_index,
3709 FIB_ROUTE_PATH_FLAG_NONE);
3710 fib_table_entry_path_remove(fib_index,
3715 tm->hw[0]->sw_if_index,
3718 FIB_ROUTE_PATH_FLAG_NONE);
3720 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3721 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3722 "1.1.1.1/32 removed");
3723 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3724 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3725 "1.1.1.2/32 removed");
3726 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3727 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3728 "1.1.2.0/24 removed");
3731 * -3 entries and -1 shared path-list
3733 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3734 fib_path_list_db_size());
3735 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3736 fib_path_list_pool_size());
3737 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3738 fib_entry_pool_size());
3741 * An attached-host route. Expect to link to the incomplete adj
3743 fib_prefix_t pfx_4_1_1_1_s_32 = {
3745 .fp_proto = FIB_PROTOCOL_IP4,
3748 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3751 fib_table_entry_path_add(fib_index,
3754 FIB_ENTRY_FLAG_NONE,
3757 tm->hw[0]->sw_if_index,
3761 FIB_ROUTE_PATH_FLAG_NONE);
3763 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3764 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3765 ai = fib_entry_get_adj(fei);
3767 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3769 &pfx_4_1_1_1_s_32.fp_addr,
3770 tm->hw[0]->sw_if_index);
3771 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3775 * +1 entry and +1 shared path-list
3777 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3778 fib_path_list_db_size());
3779 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3780 fib_path_list_pool_size());
3781 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3782 fib_entry_pool_size());
3784 fib_table_entry_delete(fib_index,
3788 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3789 fib_path_list_db_size());
3790 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3791 fib_path_list_pool_size());
3792 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3793 fib_entry_pool_size());
3796 * add a v6 prefix via v4 next-hops
3798 fib_prefix_t pfx_2001_s_64 = {
3800 .fp_proto = FIB_PROTOCOL_IP6,
3802 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3805 fei = fib_table_entry_path_add(0, //default v6 table
3808 FIB_ENTRY_FLAG_NONE,
3811 tm->hw[0]->sw_if_index,
3815 FIB_ROUTE_PATH_FLAG_NONE);
3817 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3818 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3819 ai = fib_entry_get_adj(fei);
3821 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3822 "2001::/64 via ARP-adj");
3823 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3824 "2001::/64 is link type v6");
3825 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3826 "2001::/64 ADJ-adj is NH proto v4");
3827 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3830 * add a uRPF exempt prefix:
3832 * - it's forwarding is drop
3833 * - it's uRPF list is not empty
3834 * - the uRPF list for the default route (it's cover) is empty
3836 fei = fib_table_entry_special_add(fib_index,
3838 FIB_SOURCE_URPF_EXEMPT,
3839 FIB_ENTRY_FLAG_DROP);
3840 dpo = fib_entry_contribute_ip_forwarding(fei);
3841 FIB_TEST(load_balance_is_drop(dpo),
3842 "uRPF exempt 4.1.1.1/32 DROP");
3843 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3844 "uRPF list for exempt prefix has itf index 0");
3845 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3846 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3847 "uRPF list for 0.0.0.0/0 empty");
3849 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3852 * An adj-fib that fails the refinement criteria - no connected cover
3854 fib_prefix_t pfx_12_10_10_2_s_32 = {
3856 .fp_proto = FIB_PROTOCOL_IP4,
3859 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3863 fib_table_entry_path_add(fib_index,
3864 &pfx_12_10_10_2_s_32,
3866 FIB_ENTRY_FLAG_ATTACHED,
3868 &pfx_12_10_10_2_s_32.fp_addr,
3869 tm->hw[0]->sw_if_index,
3870 ~0, // invalid fib index
3873 FIB_ROUTE_PATH_FLAG_NONE);
3875 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3876 dpo = fib_entry_contribute_ip_forwarding(fei);
3877 FIB_TEST(!dpo_id_is_valid(dpo),
3878 "no connected cover adj-fib fails refinement");
3880 fib_table_entry_delete(fib_index,
3881 &pfx_12_10_10_2_s_32,
3885 * An adj-fib that fails the refinement criteria - cover is connected
3886 * but on a different interface
3888 fib_prefix_t pfx_10_10_10_127_s_32 = {
3890 .fp_proto = FIB_PROTOCOL_IP4,
3893 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3897 fib_table_entry_path_add(fib_index,
3898 &pfx_10_10_10_127_s_32,
3900 FIB_ENTRY_FLAG_ATTACHED,
3902 &pfx_10_10_10_127_s_32.fp_addr,
3903 tm->hw[1]->sw_if_index,
3904 ~0, // invalid fib index
3907 FIB_ROUTE_PATH_FLAG_NONE);
3909 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3910 dpo = fib_entry_contribute_ip_forwarding(fei);
3911 FIB_TEST(!dpo_id_is_valid(dpo),
3912 "wrong interface adj-fib fails refinement");
3914 fib_table_entry_delete(fib_index,
3915 &pfx_10_10_10_127_s_32,
3919 * add a second path to an adj-fib
3920 * this is a sumiluation of another ARP entry created
3921 * on an interface on which the connected prefi does not exist.
3922 * The second path fails refinement. Expect to forward through the
3925 fib_prefix_t pfx_10_10_10_3_s_32 = {
3927 .fp_proto = FIB_PROTOCOL_IP4,
3930 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
3934 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3937 tm->hw[0]->sw_if_index);
3939 fib_test_lb_bucket_t ip_o_10_10_10_3 = {
3945 fei = fib_table_entry_path_add(fib_index,
3946 &pfx_10_10_10_3_s_32,
3948 FIB_ENTRY_FLAG_NONE,
3951 tm->hw[0]->sw_if_index,
3955 FIB_ROUTE_PATH_FLAG_NONE);
3956 fei = fib_table_entry_path_add(fib_index,
3957 &pfx_10_10_10_3_s_32,
3959 FIB_ENTRY_FLAG_NONE,
3962 tm->hw[1]->sw_if_index,
3966 FIB_ROUTE_PATH_FLAG_NONE);
3967 FIB_TEST(fib_test_validate_entry(fei,
3968 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3971 "10.10.10.3 via 10.10.10.3/Eth0 only");
3974 * remove the path that refines the cover, should go unresolved
3976 fib_table_entry_path_remove(fib_index,
3977 &pfx_10_10_10_3_s_32,
3981 tm->hw[0]->sw_if_index,
3984 FIB_ROUTE_PATH_FLAG_NONE);
3985 dpo = fib_entry_contribute_ip_forwarding(fei);
3986 FIB_TEST(!dpo_id_is_valid(dpo),
3987 "wrong interface adj-fib fails refinement");
3990 * add back the path that refines the cover
3992 fei = fib_table_entry_path_add(fib_index,
3993 &pfx_10_10_10_3_s_32,
3995 FIB_ENTRY_FLAG_NONE,
3998 tm->hw[0]->sw_if_index,
4002 FIB_ROUTE_PATH_FLAG_NONE);
4003 FIB_TEST(fib_test_validate_entry(fei,
4004 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4007 "10.10.10.3 via 10.10.10.3/Eth0 only");
4010 * remove the path that does not refine the cover
4012 fib_table_entry_path_remove(fib_index,
4013 &pfx_10_10_10_3_s_32,
4017 tm->hw[1]->sw_if_index,
4020 FIB_ROUTE_PATH_FLAG_NONE);
4021 FIB_TEST(fib_test_validate_entry(fei,
4022 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4025 "10.10.10.3 via 10.10.10.3/Eth0 only");
4028 * remove the path that does refine, it's the last path, so
4029 * the entry should be gone
4031 fib_table_entry_path_remove(fib_index,
4032 &pfx_10_10_10_3_s_32,
4036 tm->hw[0]->sw_if_index,
4039 FIB_ROUTE_PATH_FLAG_NONE);
4040 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4041 FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4046 * change the table's flow-hash config - expect the update to propagete to
4047 * the entries' load-balance objects
4049 flow_hash_config_t old_hash_config, new_hash_config;
4051 old_hash_config = fib_table_get_flow_hash_config(fib_index,
4053 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4054 IP_FLOW_HASH_DST_ADDR);
4056 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4057 dpo = fib_entry_contribute_ip_forwarding(fei);
4058 lb = load_balance_get(dpo->dpoi_index);
4059 FIB_TEST((lb->lb_hash_config == old_hash_config),
4060 "Table and LB hash config match: %U",
4061 format_ip_flow_hash_config, lb->lb_hash_config);
4063 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4065 FIB_TEST((lb->lb_hash_config == new_hash_config),
4066 "Table and LB newhash config match: %U",
4067 format_ip_flow_hash_config, lb->lb_hash_config);
4073 fib_table_entry_delete(fib_index,
4074 &pfx_10_10_10_1_s_32,
4076 fib_table_entry_delete(fib_index,
4077 &pfx_10_10_10_2_s_32,
4079 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4080 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4081 "10.10.10.1/32 adj-fib removed");
4082 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4083 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4084 "10.10.10.2/32 adj-fib removed");
4087 * -2 entries and -2 non-shared path-list
4089 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4090 fib_path_list_db_size());
4091 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4092 fib_path_list_pool_size());
4093 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4094 fib_entry_pool_size());
4097 * unlock the adjacencies for which this test provided a rewrite.
4098 * These are the last locks on these adjs. they should thus go away.
4102 adj_unlock(ai_12_12_12_12);
4104 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4109 * remove the interface prefixes
4111 local_pfx.fp_len = 32;
4112 fib_table_entry_special_remove(fib_index, &local_pfx,
4113 FIB_SOURCE_INTERFACE);
4114 fei = fib_table_lookup(fib_index, &local_pfx);
4116 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4117 fib_table_lookup_exact_match(fib_index, &local_pfx),
4118 "10.10.10.10/32 adj-fib removed");
4120 local_pfx.fp_len = 24;
4121 fib_table_entry_delete(fib_index, &local_pfx,
4122 FIB_SOURCE_INTERFACE);
4124 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4125 fib_table_lookup_exact_match(fib_index, &local_pfx),
4126 "10.10.10.10/24 adj-fib removed");
4129 * -2 entries and -2 non-shared path-list
4131 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4132 fib_path_list_db_size());
4133 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4134 fib_path_list_pool_size());
4135 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4136 fib_entry_pool_size());
4139 * Last but not least, remove the VRF
4141 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4144 "NO API Source'd prefixes");
4145 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4148 "NO RR Source'd prefixes");
4149 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4151 FIB_SOURCE_INTERFACE)),
4152 "NO INterface Source'd prefixes");
4154 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4156 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4157 fib_path_list_db_size());
4158 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4159 fib_path_list_pool_size());
4160 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4161 fib_entry_pool_size());
4162 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4163 pool_elts(fib_urpf_list_pool));
4164 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4165 pool_elts(load_balance_map_pool));
4166 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4167 pool_elts(load_balance_pool));
4176 * In the default table check for the presence and correct forwarding
4177 * of the special entries
4179 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4180 const dpo_id_t *dpo, *dpo_drop;
4181 const ip_adjacency_t *adj;
4182 const receive_dpo_t *rd;
4187 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4190 /* via 2001:0:0:1::2 */
4191 ip46_address_t nh_2001_2 = {
4194 [0] = clib_host_to_net_u64(0x2001000000000001),
4195 [1] = clib_host_to_net_u64(0x0000000000000002),
4202 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4204 /* Find or create FIB table 11 */
4205 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4208 for (ii = 0; ii < 4; ii++)
4210 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4213 fib_prefix_t pfx_0_0 = {
4215 .fp_proto = FIB_PROTOCOL_IP6,
4223 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4224 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4225 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4226 "Default route is DROP");
4228 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4229 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4232 &pfx_0_0.fp_addr.ip6)),
4233 "default-route; fwd and non-fwd tables match");
4235 // FIXME - check specials.
4238 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4239 * each with 2 entries and a v6 mfib with 4 path-lists.
4240 * All entries are special so no path-list sharing.
4243 #define PNPS (5+4+4)
4244 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4245 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4246 fib_path_list_pool_size());
4247 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4248 fib_entry_pool_size());
4251 * add interface routes.
4252 * validate presence of /64 attached and /128 recieve.
4253 * test for the presence of the receive address in the glean and local adj
4255 * receive on 2001:0:0:1::1/128
4257 fib_prefix_t local_pfx = {
4259 .fp_proto = FIB_PROTOCOL_IP6,
4263 [0] = clib_host_to_net_u64(0x2001000000000001),
4264 [1] = clib_host_to_net_u64(0x0000000000000001),
4270 fib_table_entry_update_one_path(fib_index, &local_pfx,
4271 FIB_SOURCE_INTERFACE,
4272 (FIB_ENTRY_FLAG_CONNECTED |
4273 FIB_ENTRY_FLAG_ATTACHED),
4276 tm->hw[0]->sw_if_index,
4280 FIB_ROUTE_PATH_FLAG_NONE);
4281 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4283 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4285 ai = fib_entry_get_adj(fei);
4286 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4288 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4289 "attached interface adj is glean");
4290 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4291 &adj->sub_type.glean.receive_addr)),
4292 "attached interface adj is receive ok");
4293 dpo = fib_entry_contribute_ip_forwarding(fei);
4294 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4297 &local_pfx.fp_addr.ip6)),
4298 "attached-route; fwd and non-fwd tables match");
4300 local_pfx.fp_len = 128;
4301 fib_table_entry_update_one_path(fib_index, &local_pfx,
4302 FIB_SOURCE_INTERFACE,
4303 (FIB_ENTRY_FLAG_CONNECTED |
4304 FIB_ENTRY_FLAG_LOCAL),
4307 tm->hw[0]->sw_if_index,
4308 ~0, // invalid fib index
4311 FIB_ROUTE_PATH_FLAG_NONE);
4312 fei = fib_table_lookup(fib_index, &local_pfx);
4314 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4316 dpo = fib_entry_contribute_ip_forwarding(fei);
4317 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4318 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4319 "local interface adj is local");
4320 rd = receive_dpo_get(dpo->dpoi_index);
4322 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4324 "local interface adj is receive ok");
4326 dpo = fib_entry_contribute_ip_forwarding(fei);
4327 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4330 &local_pfx.fp_addr.ip6)),
4331 "local-route; fwd and non-fwd tables match");
4334 * +2 entries. +2 unshared path-lists
4336 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4337 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4338 fib_path_list_pool_size());
4339 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4340 fib_entry_pool_size());
4343 * Modify the default route to be via an adj not yet known.
4344 * this sources the defalut route with the API source, which is
4345 * a higher preference to the DEFAULT_ROUTE source
4347 fib_table_entry_path_add(fib_index, &pfx_0_0,
4349 FIB_ENTRY_FLAG_NONE,
4352 tm->hw[0]->sw_if_index,
4356 FIB_ROUTE_PATH_FLAG_NONE);
4357 fei = fib_table_lookup(fib_index, &pfx_0_0);
4359 FIB_TEST((fei == dfrt), "default route same index");
4360 ai = fib_entry_get_adj(fei);
4361 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4363 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4364 "adj is incomplete");
4365 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4366 "adj nbr next-hop ok");
4369 * find the adj in the shared db
4371 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4374 tm->hw[0]->sw_if_index);
4375 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4376 adj_unlock(locked_ai);
4379 * no more entires. +1 shared path-list
4381 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4382 fib_path_list_db_size());
4383 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4384 fib_path_list_pool_size());
4385 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4386 fib_entry_pool_size());
4389 * remove the API source from the default route. We expected
4390 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4392 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4396 tm->hw[0]->sw_if_index,
4399 FIB_ROUTE_PATH_FLAG_NONE);
4400 fei = fib_table_lookup(fib_index, &pfx_0_0);
4402 FIB_TEST((fei == dfrt), "default route same index");
4403 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4404 "Default route is DROP");
4407 * no more entires. -1 shared path-list
4409 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4410 fib_path_list_db_size());
4411 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4412 fib_path_list_pool_size());
4413 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4414 fib_entry_pool_size());
4417 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4419 fib_prefix_t pfx_2001_1_2_s_128 = {
4421 .fp_proto = FIB_PROTOCOL_IP6,
4425 [0] = clib_host_to_net_u64(0x2001000000000001),
4426 [1] = clib_host_to_net_u64(0x0000000000000002),
4431 fib_prefix_t pfx_2001_1_3_s_128 = {
4433 .fp_proto = FIB_PROTOCOL_IP6,
4437 [0] = clib_host_to_net_u64(0x2001000000000001),
4438 [1] = clib_host_to_net_u64(0x0000000000000003),
4444 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4447 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4449 &pfx_2001_1_2_s_128.fp_addr,
4450 tm->hw[0]->sw_if_index);
4451 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4452 adj = adj_get(ai_01);
4453 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4454 "adj is incomplete");
4455 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4456 &adj->sub_type.nbr.next_hop)),
4457 "adj nbr next-hop ok");
4459 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4460 fib_test_build_rewrite(eth_addr));
4461 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4463 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4464 &adj->sub_type.nbr.next_hop)),
4465 "adj nbr next-hop ok");
4467 fib_table_entry_path_add(fib_index,
4468 &pfx_2001_1_2_s_128,
4470 FIB_ENTRY_FLAG_ATTACHED,
4472 &pfx_2001_1_2_s_128.fp_addr,
4473 tm->hw[0]->sw_if_index,
4477 FIB_ROUTE_PATH_FLAG_NONE);
4479 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4480 ai = fib_entry_get_adj(fei);
4481 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4485 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4487 &pfx_2001_1_3_s_128.fp_addr,
4488 tm->hw[0]->sw_if_index);
4489 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4490 adj = adj_get(ai_02);
4491 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4492 "adj is incomplete");
4493 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4494 &adj->sub_type.nbr.next_hop)),
4495 "adj nbr next-hop ok");
4497 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4498 fib_test_build_rewrite(eth_addr));
4499 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4501 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4502 &adj->sub_type.nbr.next_hop)),
4503 "adj nbr next-hop ok");
4504 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4506 fib_table_entry_path_add(fib_index,
4507 &pfx_2001_1_3_s_128,
4509 FIB_ENTRY_FLAG_ATTACHED,
4511 &pfx_2001_1_3_s_128.fp_addr,
4512 tm->hw[0]->sw_if_index,
4516 FIB_ROUTE_PATH_FLAG_NONE);
4518 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4519 ai = fib_entry_get_adj(fei);
4520 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4523 * +2 entries, +2 unshread path-lists.
4525 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4526 fib_path_list_db_size());
4527 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4528 fib_path_list_pool_size());
4529 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4530 fib_entry_pool_size());
4533 * Add a 2 routes via the first ADJ. ensure path-list sharing
4535 fib_prefix_t pfx_2001_a_s_64 = {
4537 .fp_proto = FIB_PROTOCOL_IP6,
4541 [0] = clib_host_to_net_u64(0x200100000000000a),
4542 [1] = clib_host_to_net_u64(0x0000000000000000),
4547 fib_prefix_t pfx_2001_b_s_64 = {
4549 .fp_proto = FIB_PROTOCOL_IP6,
4553 [0] = clib_host_to_net_u64(0x200100000000000b),
4554 [1] = clib_host_to_net_u64(0x0000000000000000),
4560 fib_table_entry_path_add(fib_index,
4563 FIB_ENTRY_FLAG_NONE,
4566 tm->hw[0]->sw_if_index,
4570 FIB_ROUTE_PATH_FLAG_NONE);
4571 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4572 ai = fib_entry_get_adj(fei);
4573 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4574 fib_table_entry_path_add(fib_index,
4577 FIB_ENTRY_FLAG_NONE,
4580 tm->hw[0]->sw_if_index,
4584 FIB_ROUTE_PATH_FLAG_NONE);
4585 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4586 ai = fib_entry_get_adj(fei);
4587 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4590 * +2 entries, +1 shared path-list.
4592 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4593 fib_path_list_db_size());
4594 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4595 fib_path_list_pool_size());
4596 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4597 fib_entry_pool_size());
4600 * add a v4 prefix via a v6 next-hop
4602 fib_prefix_t pfx_1_1_1_1_s_32 = {
4604 .fp_proto = FIB_PROTOCOL_IP4,
4606 .ip4.as_u32 = 0x01010101,
4609 fei = fib_table_entry_path_add(0, // default table
4612 FIB_ENTRY_FLAG_NONE,
4615 tm->hw[0]->sw_if_index,
4619 FIB_ROUTE_PATH_FLAG_NONE);
4620 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4621 "1.1.1.1/32 o v6 route present");
4622 ai = fib_entry_get_adj(fei);
4624 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4625 "1.1.1.1/32 via ARP-adj");
4626 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4627 "1.1.1.1/32 ADJ-adj is link type v4");
4628 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4629 "1.1.1.1/32 ADJ-adj is NH proto v6");
4630 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4635 fib_prefix_t pfx_2001_c_s_64 = {
4637 .fp_proto = FIB_PROTOCOL_IP6,
4641 [0] = clib_host_to_net_u64(0x200100000000000c),
4642 [1] = clib_host_to_net_u64(0x0000000000000000),
4647 fib_table_entry_path_add(fib_index,
4650 FIB_ENTRY_FLAG_ATTACHED,
4653 tm->hw[0]->sw_if_index,
4657 FIB_ROUTE_PATH_FLAG_NONE);
4658 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4659 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4660 ai = fib_entry_get_adj(fei);
4662 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4663 "2001:0:0:c/64 attached resolves via glean");
4665 fib_table_entry_path_remove(fib_index,
4670 tm->hw[0]->sw_if_index,
4673 FIB_ROUTE_PATH_FLAG_NONE);
4674 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4675 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4678 * Shutdown the interface on which we have a connected and through
4679 * which the routes are reachable.
4680 * This will result in the connected, adj-fibs, and routes linking to drop
4681 * The local/for-us prefix continues to receive.
4683 clib_error_t * error;
4685 error = vnet_sw_interface_set_flags(vnet_get_main(),
4686 tm->hw[0]->sw_if_index,
4687 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4688 FIB_TEST((NULL == error), "Interface shutdown OK");
4690 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4691 dpo = fib_entry_contribute_ip_forwarding(fei);
4692 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4693 "2001::b/64 resolves via drop");
4695 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4696 dpo = fib_entry_contribute_ip_forwarding(fei);
4697 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4698 "2001::a/64 resolves via drop");
4699 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4700 dpo = fib_entry_contribute_ip_forwarding(fei);
4701 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4702 "2001:0:0:1::3/64 resolves via drop");
4703 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4704 dpo = fib_entry_contribute_ip_forwarding(fei);
4705 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4706 "2001:0:0:1::2/64 resolves via drop");
4707 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4708 dpo = fib_entry_contribute_ip_forwarding(fei);
4709 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4710 "2001:0:0:1::1/128 not drop");
4711 local_pfx.fp_len = 64;
4712 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4713 dpo = fib_entry_contribute_ip_forwarding(fei);
4714 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4715 "2001:0:0:1/64 resolves via drop");
4720 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4721 fib_path_list_db_size());
4722 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4723 fib_path_list_pool_size());
4724 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4725 fib_entry_pool_size());
4728 * shutdown one of the other interfaces, then add a connected.
4729 * and swap one of the routes to it.
4731 error = vnet_sw_interface_set_flags(vnet_get_main(),
4732 tm->hw[1]->sw_if_index,
4733 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4734 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4736 fib_prefix_t connected_pfx = {
4738 .fp_proto = FIB_PROTOCOL_IP6,
4741 /* 2001:0:0:2::1/64 */
4743 [0] = clib_host_to_net_u64(0x2001000000000002),
4744 [1] = clib_host_to_net_u64(0x0000000000000001),
4749 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4750 FIB_SOURCE_INTERFACE,
4751 (FIB_ENTRY_FLAG_CONNECTED |
4752 FIB_ENTRY_FLAG_ATTACHED),
4755 tm->hw[1]->sw_if_index,
4759 FIB_ROUTE_PATH_FLAG_NONE);
4760 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4761 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4762 dpo = fib_entry_contribute_ip_forwarding(fei);
4763 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4764 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4765 "2001:0:0:2/64 not resolves via drop");
4767 connected_pfx.fp_len = 128;
4768 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4769 FIB_SOURCE_INTERFACE,
4770 (FIB_ENTRY_FLAG_CONNECTED |
4771 FIB_ENTRY_FLAG_LOCAL),
4774 tm->hw[0]->sw_if_index,
4775 ~0, // invalid fib index
4778 FIB_ROUTE_PATH_FLAG_NONE);
4779 fei = fib_table_lookup(fib_index, &connected_pfx);
4781 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4782 dpo = fib_entry_contribute_ip_forwarding(fei);
4783 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4784 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4785 "local interface adj is local");
4786 rd = receive_dpo_get(dpo->dpoi_index);
4787 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4789 "local interface adj is receive ok");
4792 * +2 entries, +2 unshared path-lists
4794 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4795 fib_path_list_db_size());
4796 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4797 fib_path_list_pool_size());
4798 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4799 fib_entry_pool_size());
4803 * bring the interface back up. we expected the routes to return
4804 * to normal forwarding.
4806 error = vnet_sw_interface_set_flags(vnet_get_main(),
4807 tm->hw[0]->sw_if_index,
4808 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4809 FIB_TEST((NULL == error), "Interface bring-up OK");
4810 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4811 ai = fib_entry_get_adj(fei);
4812 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4813 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4814 ai = fib_entry_get_adj(fei);
4815 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4816 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4817 ai = fib_entry_get_adj(fei);
4818 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4819 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4820 ai = fib_entry_get_adj(fei);
4821 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4822 local_pfx.fp_len = 64;
4823 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4824 ai = fib_entry_get_adj(fei);
4826 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4827 "attached interface adj is glean");
4830 * Same test as above, but this time the HW interface goes down
4832 error = vnet_hw_interface_set_flags(vnet_get_main(),
4833 tm->hw_if_indicies[0],
4834 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4835 FIB_TEST((NULL == error), "Interface shutdown OK");
4837 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4838 dpo = fib_entry_contribute_ip_forwarding(fei);
4839 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4840 "2001::b/64 resolves via drop");
4841 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4842 dpo = fib_entry_contribute_ip_forwarding(fei);
4843 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4844 "2001::a/64 resolves via drop");
4845 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4846 dpo = fib_entry_contribute_ip_forwarding(fei);
4847 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4848 "2001:0:0:1::3/128 resolves via drop");
4849 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4850 dpo = fib_entry_contribute_ip_forwarding(fei);
4851 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4852 "2001:0:0:1::2/128 resolves via drop");
4853 local_pfx.fp_len = 128;
4854 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4855 dpo = fib_entry_contribute_ip_forwarding(fei);
4856 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4857 "2001:0:0:1::1/128 not drop");
4858 local_pfx.fp_len = 64;
4859 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4860 dpo = fib_entry_contribute_ip_forwarding(fei);
4861 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4862 "2001:0:0:1/64 resolves via drop");
4864 error = vnet_hw_interface_set_flags(vnet_get_main(),
4865 tm->hw_if_indicies[0],
4866 VNET_HW_INTERFACE_FLAG_LINK_UP);
4867 FIB_TEST((NULL == error), "Interface bring-up OK");
4868 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4869 ai = fib_entry_get_adj(fei);
4870 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4871 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4872 ai = fib_entry_get_adj(fei);
4873 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4874 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4875 ai = fib_entry_get_adj(fei);
4876 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4877 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4878 ai = fib_entry_get_adj(fei);
4879 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4880 local_pfx.fp_len = 64;
4881 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4882 ai = fib_entry_get_adj(fei);
4884 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4885 "attached interface adj is glean");
4888 * Delete the interface that the routes reolve through.
4889 * Again no routes are removed. They all point to drop.
4891 * This is considered an error case. The control plane should
4892 * not remove interfaces through which routes resolve, but
4893 * such things can happen. ALL affected routes will drop.
4895 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4897 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4898 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4899 "2001::b/64 resolves via drop");
4900 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4901 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4902 "2001::b/64 resolves via drop");
4903 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4904 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4905 "2001:0:0:1::3/64 resolves via drop");
4906 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4907 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4908 "2001:0:0:1::2/64 resolves via drop");
4909 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4910 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4911 "2001:0:0:1::1/128 is drop");
4912 local_pfx.fp_len = 64;
4913 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4914 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4915 "2001:0:0:1/64 resolves via drop");
4920 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4921 fib_path_list_db_size());
4922 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4923 fib_path_list_pool_size());
4924 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4925 fib_entry_pool_size());
4928 * Add the interface back. routes stay unresolved.
4930 error = ethernet_register_interface(vnet_get_main(),
4931 test_interface_device_class.index,
4934 &tm->hw_if_indicies[0],
4935 /* flag change */ 0);
4937 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4938 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4939 "2001::b/64 resolves via drop");
4940 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4941 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4942 "2001::b/64 resolves via drop");
4943 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4944 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4945 "2001:0:0:1::3/64 resolves via drop");
4946 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4947 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4948 "2001:0:0:1::2/64 resolves via drop");
4949 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4950 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4951 "2001:0:0:1::1/128 is drop");
4952 local_pfx.fp_len = 64;
4953 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4954 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4955 "2001:0:0:1/64 resolves via drop");
4958 * CLEANUP ALL the routes
4960 fib_table_entry_delete(fib_index,
4963 fib_table_entry_delete(fib_index,
4966 fib_table_entry_delete(fib_index,
4969 fib_table_entry_delete(fib_index,
4970 &pfx_2001_1_3_s_128,
4972 fib_table_entry_delete(fib_index,
4973 &pfx_2001_1_2_s_128,
4975 local_pfx.fp_len = 64;
4976 fib_table_entry_delete(fib_index, &local_pfx,
4977 FIB_SOURCE_INTERFACE);
4978 local_pfx.fp_len = 128;
4979 fib_table_entry_special_remove(fib_index, &local_pfx,
4980 FIB_SOURCE_INTERFACE);
4981 connected_pfx.fp_len = 64;
4982 fib_table_entry_delete(fib_index, &connected_pfx,
4983 FIB_SOURCE_INTERFACE);
4984 connected_pfx.fp_len = 128;
4985 fib_table_entry_special_remove(fib_index, &connected_pfx,
4986 FIB_SOURCE_INTERFACE);
4988 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4989 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4990 "2001::a/64 removed");
4991 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4992 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4993 "2001::b/64 removed");
4994 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4995 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4996 "2001:0:0:1::3/128 removed");
4997 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4998 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4999 "2001:0:0:1::3/128 removed");
5000 local_pfx.fp_len = 64;
5001 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5002 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5003 "2001:0:0:1/64 removed");
5004 local_pfx.fp_len = 128;
5005 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5006 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5007 "2001:0:0:1::1/128 removed");
5008 connected_pfx.fp_len = 64;
5009 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5010 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5011 "2001:0:0:2/64 removed");
5012 connected_pfx.fp_len = 128;
5013 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5014 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5015 "2001:0:0:2::1/128 removed");
5018 * -8 entries. -7 path-lists (1 was shared).
5020 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5021 fib_path_list_db_size());
5022 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5023 fib_path_list_pool_size());
5024 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5025 fib_entry_pool_size());
5028 * now remove the VRF
5030 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5032 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5033 fib_path_list_db_size());
5034 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5035 fib_path_list_pool_size());
5036 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5037 fib_entry_pool_size());
5043 * return the interfaces to up state
5045 error = vnet_sw_interface_set_flags(vnet_get_main(),
5046 tm->hw[0]->sw_if_index,
5047 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5048 error = vnet_sw_interface_set_flags(vnet_get_main(),
5049 tm->hw[1]->sw_if_index,
5050 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5052 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5059 * Test Attached Exports
5064 const dpo_id_t *dpo, *dpo_drop;
5065 const u32 fib_index = 0;
5066 fib_node_index_t fei;
5073 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5077 * add interface routes. We'll assume this works. It's more rigorously
5080 fib_prefix_t local_pfx = {
5082 .fp_proto = FIB_PROTOCOL_IP4,
5086 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5091 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5092 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5094 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5096 fib_table_entry_update_one_path(fib_index, &local_pfx,
5097 FIB_SOURCE_INTERFACE,
5098 (FIB_ENTRY_FLAG_CONNECTED |
5099 FIB_ENTRY_FLAG_ATTACHED),
5102 tm->hw[0]->sw_if_index,
5106 FIB_ROUTE_PATH_FLAG_NONE);
5107 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5108 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5109 "attached interface route present");
5111 local_pfx.fp_len = 32;
5112 fib_table_entry_update_one_path(fib_index, &local_pfx,
5113 FIB_SOURCE_INTERFACE,
5114 (FIB_ENTRY_FLAG_CONNECTED |
5115 FIB_ENTRY_FLAG_LOCAL),
5118 tm->hw[0]->sw_if_index,
5119 ~0, // invalid fib index
5122 FIB_ROUTE_PATH_FLAG_NONE);
5123 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5125 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5126 "local interface route present");
5129 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5131 fib_prefix_t pfx_10_10_10_1_s_32 = {
5133 .fp_proto = FIB_PROTOCOL_IP4,
5136 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5139 fib_node_index_t ai;
5141 fib_table_entry_path_add(fib_index,
5142 &pfx_10_10_10_1_s_32,
5144 FIB_ENTRY_FLAG_ATTACHED,
5146 &pfx_10_10_10_1_s_32.fp_addr,
5147 tm->hw[0]->sw_if_index,
5148 ~0, // invalid fib index
5151 FIB_ROUTE_PATH_FLAG_NONE);
5153 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5154 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5155 ai = fib_entry_get_adj(fei);
5158 * create another FIB table into which routes will be imported
5160 u32 import_fib_index1;
5162 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5167 * Add an attached route in the import FIB
5169 local_pfx.fp_len = 24;
5170 fib_table_entry_update_one_path(import_fib_index1,
5173 FIB_ENTRY_FLAG_NONE,
5176 tm->hw[0]->sw_if_index,
5177 ~0, // invalid fib index
5180 FIB_ROUTE_PATH_FLAG_NONE);
5181 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5182 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5185 * check for the presence of the adj-fibs in the import table
5187 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5188 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5189 FIB_TEST((ai == fib_entry_get_adj(fei)),
5190 "adj-fib1 Import uses same adj as export");
5193 * check for the presence of the local in the import table
5195 local_pfx.fp_len = 32;
5196 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5197 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5200 * Add another adj-fin in the export table. Expect this
5201 * to get magically exported;
5203 fib_prefix_t pfx_10_10_10_2_s_32 = {
5205 .fp_proto = FIB_PROTOCOL_IP4,
5208 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5212 fib_table_entry_path_add(fib_index,
5213 &pfx_10_10_10_2_s_32,
5215 FIB_ENTRY_FLAG_ATTACHED,
5217 &pfx_10_10_10_2_s_32.fp_addr,
5218 tm->hw[0]->sw_if_index,
5219 ~0, // invalid fib index
5222 FIB_ROUTE_PATH_FLAG_NONE);
5223 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5224 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5225 ai = fib_entry_get_adj(fei);
5227 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5228 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5229 FIB_TEST((ai == fib_entry_get_adj(fei)),
5230 "Import uses same adj as export");
5231 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5232 "ADJ-fib2 imported flags %d",
5233 fib_entry_get_flags(fei));
5236 * create a 2nd FIB table into which routes will be imported
5238 u32 import_fib_index2;
5240 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5244 * Add an attached route in the import FIB
5246 local_pfx.fp_len = 24;
5247 fib_table_entry_update_one_path(import_fib_index2,
5250 FIB_ENTRY_FLAG_NONE,
5253 tm->hw[0]->sw_if_index,
5254 ~0, // invalid fib index
5257 FIB_ROUTE_PATH_FLAG_NONE);
5258 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5259 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5262 * check for the presence of all the adj-fibs and local in the import table
5264 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5265 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5266 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5267 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5268 local_pfx.fp_len = 32;
5269 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5270 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5273 * add a 3rd adj-fib. expect it to be exported to both tables.
5275 fib_prefix_t pfx_10_10_10_3_s_32 = {
5277 .fp_proto = FIB_PROTOCOL_IP4,
5280 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5284 fib_table_entry_path_add(fib_index,
5285 &pfx_10_10_10_3_s_32,
5287 FIB_ENTRY_FLAG_ATTACHED,
5289 &pfx_10_10_10_3_s_32.fp_addr,
5290 tm->hw[0]->sw_if_index,
5291 ~0, // invalid fib index
5294 FIB_ROUTE_PATH_FLAG_NONE);
5295 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5296 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5297 ai = fib_entry_get_adj(fei);
5299 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5300 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5301 FIB_TEST((ai == fib_entry_get_adj(fei)),
5302 "Import uses same adj as export");
5303 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5304 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5305 FIB_TEST((ai == fib_entry_get_adj(fei)),
5306 "Import uses same adj as export");
5309 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5311 fib_table_entry_delete(fib_index,
5312 &pfx_10_10_10_3_s_32,
5315 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5316 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5318 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5319 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5321 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5322 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5325 * remove the attached route from the 2nd FIB. expect the imported
5326 * entires to be removed
5328 local_pfx.fp_len = 24;
5329 fib_table_entry_delete(import_fib_index2,
5332 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5333 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5335 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5336 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5337 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5338 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5339 local_pfx.fp_len = 32;
5340 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5341 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5343 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5344 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5345 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5346 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5347 local_pfx.fp_len = 32;
5348 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5349 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5352 * modify the route in FIB1 so it is no longer attached. expect the imported
5353 * entires to be removed
5355 local_pfx.fp_len = 24;
5356 fib_table_entry_update_one_path(import_fib_index1,
5359 FIB_ENTRY_FLAG_NONE,
5361 &pfx_10_10_10_2_s_32.fp_addr,
5362 tm->hw[0]->sw_if_index,
5363 ~0, // invalid fib index
5366 FIB_ROUTE_PATH_FLAG_NONE);
5367 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5368 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5369 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5370 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5371 local_pfx.fp_len = 32;
5372 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5373 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5376 * modify it back to attached. expect the adj-fibs back
5378 local_pfx.fp_len = 24;
5379 fib_table_entry_update_one_path(import_fib_index1,
5382 FIB_ENTRY_FLAG_NONE,
5385 tm->hw[0]->sw_if_index,
5386 ~0, // invalid fib index
5389 FIB_ROUTE_PATH_FLAG_NONE);
5390 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5391 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5392 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5393 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5394 local_pfx.fp_len = 32;
5395 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5396 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5399 * add a covering attached next-hop for the interface address, so we have
5400 * a valid adj to find when we check the forwarding tables
5402 fib_prefix_t pfx_10_0_0_0_s_8 = {
5404 .fp_proto = FIB_PROTOCOL_IP4,
5407 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5411 fei = fib_table_entry_update_one_path(fib_index,
5414 FIB_ENTRY_FLAG_NONE,
5416 &pfx_10_10_10_3_s_32.fp_addr,
5417 tm->hw[0]->sw_if_index,
5418 ~0, // invalid fib index
5421 FIB_ROUTE_PATH_FLAG_NONE);
5422 dpo = fib_entry_contribute_ip_forwarding(fei);
5425 * remove the route in the export fib. expect the adj-fibs to be removed
5427 local_pfx.fp_len = 24;
5428 fib_table_entry_delete(fib_index,
5430 FIB_SOURCE_INTERFACE);
5432 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5433 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5434 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5435 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5436 local_pfx.fp_len = 32;
5437 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5438 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5441 * the adj-fibs in the export VRF are present in the FIB table,
5442 * but not installed in forwarding, since they have no attached cover.
5443 * Consequently a lookup in the MTRIE gives the adj for the covering
5446 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5447 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5450 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5451 FIB_TEST(lbi == dpo->dpoi_index,
5452 "10.10.10.1 forwards on \n%U not \n%U",
5453 format_load_balance, lbi, 0,
5454 format_dpo_id, dpo, 0);
5455 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5456 FIB_TEST(lbi == dpo->dpoi_index,
5457 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5458 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5459 FIB_TEST(lbi == dpo->dpoi_index,
5460 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5463 * add the export prefix back, but not as attached.
5464 * No adj-fibs in export nor import tables
5466 local_pfx.fp_len = 24;
5467 fei = fib_table_entry_update_one_path(fib_index,
5470 FIB_ENTRY_FLAG_NONE,
5472 &pfx_10_10_10_1_s_32.fp_addr,
5473 tm->hw[0]->sw_if_index,
5474 ~0, // invalid fib index
5477 FIB_ROUTE_PATH_FLAG_NONE);
5478 dpo = fib_entry_contribute_ip_forwarding(fei);
5480 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5481 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5482 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5483 FIB_TEST(lbi == dpo->dpoi_index,
5484 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5485 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5486 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5487 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5488 FIB_TEST(lbi == dpo->dpoi_index,
5489 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5491 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5492 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5493 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5494 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5495 local_pfx.fp_len = 32;
5496 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5497 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5500 * modify the export prefix so it is attached. expect all covereds to return
5502 local_pfx.fp_len = 24;
5503 fib_table_entry_update_one_path(fib_index,
5506 FIB_ENTRY_FLAG_NONE,
5509 tm->hw[0]->sw_if_index,
5510 ~0, // invalid fib index
5513 FIB_ROUTE_PATH_FLAG_NONE);
5515 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5516 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5517 dpo = fib_entry_contribute_ip_forwarding(fei);
5518 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5519 "Adj-fib1 is not drop in export");
5520 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5521 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5522 local_pfx.fp_len = 32;
5523 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5524 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5525 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5526 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5527 dpo = fib_entry_contribute_ip_forwarding(fei);
5528 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5529 "Adj-fib1 is not drop in export");
5530 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5531 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5532 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5533 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5534 local_pfx.fp_len = 32;
5535 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5536 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5539 * modify the export prefix so connected. no change.
5541 local_pfx.fp_len = 24;
5542 fib_table_entry_update_one_path(fib_index, &local_pfx,
5543 FIB_SOURCE_INTERFACE,
5544 (FIB_ENTRY_FLAG_CONNECTED |
5545 FIB_ENTRY_FLAG_ATTACHED),
5548 tm->hw[0]->sw_if_index,
5552 FIB_ROUTE_PATH_FLAG_NONE);
5554 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5555 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5556 dpo = fib_entry_contribute_ip_forwarding(fei);
5557 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5558 "Adj-fib1 is not drop in export");
5559 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5560 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5561 local_pfx.fp_len = 32;
5562 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5563 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5564 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5565 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5566 dpo = fib_entry_contribute_ip_forwarding(fei);
5567 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5568 "Adj-fib1 is not drop in export");
5569 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5570 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5571 local_pfx.fp_len = 32;
5572 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5573 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5578 fib_table_entry_delete(fib_index,
5581 fib_table_entry_delete(fib_index,
5582 &pfx_10_10_10_1_s_32,
5584 fib_table_entry_delete(fib_index,
5585 &pfx_10_10_10_2_s_32,
5587 local_pfx.fp_len = 32;
5588 fib_table_entry_delete(fib_index,
5590 FIB_SOURCE_INTERFACE);
5591 local_pfx.fp_len = 24;
5592 fib_table_entry_delete(fib_index,
5595 fib_table_entry_delete(fib_index,
5597 FIB_SOURCE_INTERFACE);
5598 local_pfx.fp_len = 24;
5599 fib_table_entry_delete(import_fib_index1,
5603 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5604 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5606 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5613 * Test Path Preference
5616 fib_test_pref (void)
5618 test_main_t *tm = &test_main;
5620 const fib_prefix_t pfx_1_1_1_1_s_32 = {
5622 .fp_proto = FIB_PROTOCOL_IP4,
5625 .as_u32 = clib_host_to_net_u32(0x01010101),
5631 * 2 high, 2 medium and 2 low preference non-recursive paths
5633 fib_route_path_t nr_path_hi_1 = {
5634 .frp_proto = DPO_PROTO_IP4,
5635 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5636 .frp_fib_index = ~0,
5638 .frp_preference = 0,
5639 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5641 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5644 fib_route_path_t nr_path_hi_2 = {
5645 .frp_proto = DPO_PROTO_IP4,
5646 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5647 .frp_fib_index = ~0,
5649 .frp_preference = 0,
5650 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5652 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5655 fib_route_path_t nr_path_med_1 = {
5656 .frp_proto = DPO_PROTO_IP4,
5657 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5658 .frp_fib_index = ~0,
5660 .frp_preference = 1,
5661 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5663 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5666 fib_route_path_t nr_path_med_2 = {
5667 .frp_proto = DPO_PROTO_IP4,
5668 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5669 .frp_fib_index = ~0,
5671 .frp_preference = 1,
5672 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5674 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5677 fib_route_path_t nr_path_low_1 = {
5678 .frp_proto = DPO_PROTO_IP4,
5679 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5680 .frp_fib_index = ~0,
5682 .frp_preference = 2,
5683 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5685 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5688 fib_route_path_t nr_path_low_2 = {
5689 .frp_proto = DPO_PROTO_IP4,
5690 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5691 .frp_fib_index = ~0,
5693 .frp_preference = 2,
5694 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5696 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5699 fib_route_path_t *nr_paths = NULL;
5701 vec_add1(nr_paths, nr_path_hi_1);
5702 vec_add1(nr_paths, nr_path_hi_2);
5703 vec_add1(nr_paths, nr_path_med_1);
5704 vec_add1(nr_paths, nr_path_med_2);
5705 vec_add1(nr_paths, nr_path_low_1);
5706 vec_add1(nr_paths, nr_path_low_2);
5708 adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5710 &nr_path_hi_1.frp_addr,
5711 nr_path_hi_1.frp_sw_if_index);
5712 adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5714 &nr_path_hi_2.frp_addr,
5715 nr_path_hi_2.frp_sw_if_index);
5716 adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5718 &nr_path_med_1.frp_addr,
5719 nr_path_med_1.frp_sw_if_index);
5720 adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5722 &nr_path_med_2.frp_addr,
5723 nr_path_med_2.frp_sw_if_index);
5724 adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5726 &nr_path_low_1.frp_addr,
5727 nr_path_low_1.frp_sw_if_index);
5728 adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5730 &nr_path_low_2.frp_addr,
5731 nr_path_low_2.frp_sw_if_index);
5733 fib_test_lb_bucket_t ip_hi_1 = {
5739 fib_test_lb_bucket_t ip_hi_2 = {
5745 fib_test_lb_bucket_t ip_med_1 = {
5751 fib_test_lb_bucket_t ip_med_2 = {
5757 fib_test_lb_bucket_t ip_low_1 = {
5763 fib_test_lb_bucket_t ip_low_2 = {
5770 fib_node_index_t fei;
5772 fei = fib_table_entry_path_add2(0,
5775 FIB_ENTRY_FLAG_NONE,
5778 FIB_TEST(fib_test_validate_entry(fei,
5779 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5783 "1.1.1.1/32 via high preference paths");
5786 * bring down the interface on which the high preference path lie
5788 vnet_sw_interface_set_flags(vnet_get_main(),
5789 tm->hw[0]->sw_if_index,
5792 FIB_TEST(fib_test_validate_entry(fei,
5793 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5797 "1.1.1.1/32 via medium preference paths");
5800 * bring down the interface on which the medium preference path lie
5802 vnet_sw_interface_set_flags(vnet_get_main(),
5803 tm->hw[1]->sw_if_index,
5806 FIB_TEST(fib_test_validate_entry(fei,
5807 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5811 "1.1.1.1/32 via low preference paths");
5814 * bring up the interface on which the high preference path lie
5816 vnet_sw_interface_set_flags(vnet_get_main(),
5817 tm->hw[0]->sw_if_index,
5818 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5820 FIB_TEST(fib_test_validate_entry(fei,
5821 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5825 "1.1.1.1/32 via high preference paths");
5828 * bring up the interface on which the medium preference path lie
5830 vnet_sw_interface_set_flags(vnet_get_main(),
5831 tm->hw[1]->sw_if_index,
5832 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5834 FIB_TEST(fib_test_validate_entry(fei,
5835 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5839 "1.1.1.1/32 via high preference paths");
5841 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5842 fib_entry_contribute_forwarding(fei,
5843 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5847 * 3 recursive paths of different preference
5849 const fib_prefix_t pfx_1_1_1_2_s_32 = {
5851 .fp_proto = FIB_PROTOCOL_IP4,
5854 .as_u32 = clib_host_to_net_u32(0x01010102),
5858 const fib_prefix_t pfx_1_1_1_3_s_32 = {
5860 .fp_proto = FIB_PROTOCOL_IP4,
5863 .as_u32 = clib_host_to_net_u32(0x01010103),
5867 fei = fib_table_entry_path_add2(0,
5870 FIB_ENTRY_FLAG_NONE,
5872 dpo_id_t ip_1_1_1_2 = DPO_INVALID;
5873 fib_entry_contribute_forwarding(fei,
5874 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5876 fei = fib_table_entry_path_add2(0,
5879 FIB_ENTRY_FLAG_NONE,
5881 dpo_id_t ip_1_1_1_3 = DPO_INVALID;
5882 fib_entry_contribute_forwarding(fei,
5883 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5886 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5889 .lb = ip_1_1_1_1.dpoi_index,
5892 fib_test_lb_bucket_t ip_o_1_1_1_2 = {
5895 .lb = ip_1_1_1_2.dpoi_index,
5898 fib_test_lb_bucket_t ip_o_1_1_1_3 = {
5901 .lb = ip_1_1_1_3.dpoi_index,
5904 fib_route_path_t r_path_hi = {
5905 .frp_proto = DPO_PROTO_IP4,
5906 .frp_sw_if_index = ~0,
5909 .frp_preference = 0,
5910 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5911 .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
5913 fib_route_path_t r_path_med = {
5914 .frp_proto = DPO_PROTO_IP4,
5915 .frp_sw_if_index = ~0,
5918 .frp_preference = 10,
5919 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5920 .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
5922 fib_route_path_t r_path_low = {
5923 .frp_proto = DPO_PROTO_IP4,
5924 .frp_sw_if_index = ~0,
5927 .frp_preference = 255,
5928 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5929 .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
5931 fib_route_path_t *r_paths = NULL;
5933 vec_add1(r_paths, r_path_hi);
5934 vec_add1(r_paths, r_path_low);
5935 vec_add1(r_paths, r_path_med);
5938 * add many recursive so we get the LB MAp created
5941 fib_prefix_t pfx_r[N_PFXS];
5942 unsigned int n_pfxs;
5943 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
5945 pfx_r[n_pfxs].fp_len = 32;
5946 pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
5947 pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
5948 clib_host_to_net_u32(0x02000000 + n_pfxs);
5950 fei = fib_table_entry_path_add2(0,
5953 FIB_ENTRY_FLAG_NONE,
5956 FIB_TEST(fib_test_validate_entry(fei,
5957 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5960 "recursive via high preference paths");
5963 * withdraw hig pref resolving entry
5965 fib_table_entry_delete(0,
5969 /* suspend so the update walk kicks int */
5970 vlib_process_suspend(vlib_get_main(), 1e-5);
5972 FIB_TEST(fib_test_validate_entry(fei,
5973 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5976 "recursive via medium preference paths");
5979 * withdraw medium pref resolving entry
5981 fib_table_entry_delete(0,
5985 /* suspend so the update walk kicks int */
5986 vlib_process_suspend(vlib_get_main(), 1e-5);
5988 FIB_TEST(fib_test_validate_entry(fei,
5989 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5992 "recursive via low preference paths");
5995 * add back paths for next iteration
5997 fei = fib_table_entry_update(0,
6000 FIB_ENTRY_FLAG_NONE,
6002 fei = fib_table_entry_update(0,
6005 FIB_ENTRY_FLAG_NONE,
6008 /* suspend so the update walk kicks int */
6009 vlib_process_suspend(vlib_get_main(), 1e-5);
6011 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6012 FIB_TEST(fib_test_validate_entry(fei,
6013 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6016 "recursive via high preference paths");
6020 fib_table_entry_delete(0,
6024 /* suspend so the update walk kicks int */
6025 vlib_process_suspend(vlib_get_main(), 1e-5);
6027 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6029 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6031 FIB_TEST(fib_test_validate_entry(fei,
6032 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6035 "recursive via medium preference paths");
6037 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6039 fib_table_entry_delete(0,
6047 fib_table_entry_delete(0,
6050 fib_table_entry_delete(0,
6054 dpo_reset(&ip_1_1_1_1);
6055 dpo_reset(&ip_1_1_1_2);
6056 dpo_reset(&ip_1_1_1_3);
6057 adj_unlock(ai_low_2);
6058 adj_unlock(ai_low_1);
6059 adj_unlock(ai_med_2);
6060 adj_unlock(ai_med_1);
6061 adj_unlock(ai_hi_2);
6062 adj_unlock(ai_hi_1);
6067 * Test the recursive route route handling for GRE tunnels
6070 fib_test_label (void)
6072 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;
6073 const u32 fib_index = 0;
6078 lb_count = pool_elts(load_balance_pool);
6083 * add interface routes. We'll assume this works. It's more rigorously
6086 fib_prefix_t local0_pfx = {
6088 .fp_proto = FIB_PROTOCOL_IP4,
6092 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6097 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6100 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6101 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6103 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6104 FIB_SOURCE_INTERFACE,
6105 (FIB_ENTRY_FLAG_CONNECTED |
6106 FIB_ENTRY_FLAG_ATTACHED),
6109 tm->hw[0]->sw_if_index,
6113 FIB_ROUTE_PATH_FLAG_NONE);
6114 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6115 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6116 "attached interface route present");
6118 local0_pfx.fp_len = 32;
6119 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6120 FIB_SOURCE_INTERFACE,
6121 (FIB_ENTRY_FLAG_CONNECTED |
6122 FIB_ENTRY_FLAG_LOCAL),
6125 tm->hw[0]->sw_if_index,
6126 ~0, // invalid fib index
6129 FIB_ROUTE_PATH_FLAG_NONE);
6130 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6132 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6133 "local interface route present");
6135 fib_prefix_t local1_pfx = {
6137 .fp_proto = FIB_PROTOCOL_IP4,
6141 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6146 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6147 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6149 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6150 FIB_SOURCE_INTERFACE,
6151 (FIB_ENTRY_FLAG_CONNECTED |
6152 FIB_ENTRY_FLAG_ATTACHED),
6155 tm->hw[1]->sw_if_index,
6159 FIB_ROUTE_PATH_FLAG_NONE);
6160 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6161 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6162 "attached interface route present");
6164 local1_pfx.fp_len = 32;
6165 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6166 FIB_SOURCE_INTERFACE,
6167 (FIB_ENTRY_FLAG_CONNECTED |
6168 FIB_ENTRY_FLAG_LOCAL),
6171 tm->hw[1]->sw_if_index,
6172 ~0, // invalid fib index
6175 FIB_ROUTE_PATH_FLAG_NONE);
6176 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6178 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6179 "local interface route present");
6181 ip46_address_t nh_10_10_10_1 = {
6183 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6186 ip46_address_t nh_10_10_11_1 = {
6188 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6191 ip46_address_t nh_10_10_11_2 = {
6193 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6197 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6200 tm->hw[1]->sw_if_index);
6201 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6204 tm->hw[1]->sw_if_index);
6205 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6208 tm->hw[0]->sw_if_index);
6209 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6212 tm->hw[1]->sw_if_index);
6213 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6216 tm->hw[1]->sw_if_index);
6219 * Add an etry with one path with a real out-going label
6221 fib_prefix_t pfx_1_1_1_1_s_32 = {
6223 .fp_proto = FIB_PROTOCOL_IP4,
6225 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6228 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6229 .type = FT_LB_LABEL_O_ADJ,
6231 .adj = ai_mpls_10_10_10_1,
6236 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6237 .type = FT_LB_LABEL_O_ADJ,
6239 .adj = ai_mpls_10_10_10_1,
6241 .eos = MPLS_NON_EOS,
6244 mpls_label_t *l99 = NULL;
6247 fib_table_entry_update_one_path(fib_index,
6250 FIB_ENTRY_FLAG_NONE,
6253 tm->hw[0]->sw_if_index,
6254 ~0, // invalid fib index
6257 FIB_ROUTE_PATH_FLAG_NONE);
6259 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6260 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6262 FIB_TEST(fib_test_validate_entry(fei,
6263 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6265 &l99_eos_o_10_10_10_1),
6266 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6269 * add a path with an implicit NULL label
6271 fib_test_lb_bucket_t a_o_10_10_11_1 = {
6274 .adj = ai_v4_10_10_11_1,
6277 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6280 .adj = ai_mpls_10_10_11_1,
6283 mpls_label_t *l_imp_null = NULL;
6284 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6286 fei = fib_table_entry_path_add(fib_index,
6289 FIB_ENTRY_FLAG_NONE,
6292 tm->hw[1]->sw_if_index,
6293 ~0, // invalid fib index
6296 FIB_ROUTE_PATH_FLAG_NONE);
6298 FIB_TEST(fib_test_validate_entry(fei,
6299 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6301 &l99_eos_o_10_10_10_1,
6303 "1.1.1.1/32 LB 2 buckets via: "
6304 "label 99 over 10.10.10.1, "
6305 "adj over 10.10.11.1");
6308 * assign the route a local label
6310 fib_table_entry_local_label_add(fib_index,
6314 fib_prefix_t pfx_24001_eos = {
6315 .fp_proto = FIB_PROTOCOL_MPLS,
6319 fib_prefix_t pfx_24001_neos = {
6320 .fp_proto = FIB_PROTOCOL_MPLS,
6322 .fp_eos = MPLS_NON_EOS,
6326 * The EOS entry should link to both the paths,
6327 * and use an ip adj for the imp-null
6328 * The NON-EOS entry should link to both the paths,
6329 * and use an mpls adj for the imp-null
6331 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6333 FIB_TEST(fib_test_validate_entry(fei,
6334 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6336 &l99_eos_o_10_10_10_1,
6338 "24001/eos LB 2 buckets via: "
6339 "label 99 over 10.10.10.1, "
6340 "adj over 10.10.11.1");
6343 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6345 FIB_TEST(fib_test_validate_entry(fei,
6346 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6348 &l99_neos_o_10_10_10_1,
6349 &a_mpls_o_10_10_11_1),
6350 "24001/neos LB 1 bucket via: "
6351 "label 99 over 10.10.10.1 ",
6352 "mpls-adj via 10.10.11.1");
6355 * add an unlabelled path, this is excluded from the neos chains,
6357 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6360 .adj = ai_v4_10_10_11_2,
6364 fei = fib_table_entry_path_add(fib_index,
6367 FIB_ENTRY_FLAG_NONE,
6370 tm->hw[1]->sw_if_index,
6371 ~0, // invalid fib index
6374 FIB_ROUTE_PATH_FLAG_NONE);
6376 FIB_TEST(fib_test_validate_entry(fei,
6377 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6378 16, // 3 choices spread over 16 buckets
6379 &l99_eos_o_10_10_10_1,
6380 &l99_eos_o_10_10_10_1,
6381 &l99_eos_o_10_10_10_1,
6382 &l99_eos_o_10_10_10_1,
6383 &l99_eos_o_10_10_10_1,
6384 &l99_eos_o_10_10_10_1,
6395 "1.1.1.1/32 LB 16 buckets via: "
6396 "label 99 over 10.10.10.1, "
6397 "adj over 10.10.11.1",
6398 "adj over 10.10.11.2");
6401 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6403 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6404 fib_entry_contribute_forwarding(fei,
6405 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6409 * n-eos has only the 2 labelled paths
6411 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6414 FIB_TEST(fib_test_validate_entry(fei,
6415 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6417 &l99_neos_o_10_10_10_1,
6418 &a_mpls_o_10_10_11_1),
6419 "24001/neos LB 2 buckets via: "
6420 "label 99 over 10.10.10.1, "
6421 "adj-mpls over 10.10.11.2");
6424 * A labelled recursive
6426 fib_prefix_t pfx_2_2_2_2_s_32 = {
6428 .fp_proto = FIB_PROTOCOL_IP4,
6430 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6433 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6434 .type = FT_LB_LABEL_O_LB,
6436 .lb = non_eos_1_1_1_1.dpoi_index,
6441 mpls_label_t *l1600 = NULL;
6442 vec_add1(l1600, 1600);
6444 fib_table_entry_update_one_path(fib_index,
6447 FIB_ENTRY_FLAG_NONE,
6449 &pfx_1_1_1_1_s_32.fp_addr,
6454 FIB_ROUTE_PATH_FLAG_NONE);
6456 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6457 FIB_TEST(fib_test_validate_entry(fei,
6458 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6460 &l1600_eos_o_1_1_1_1),
6461 "2.2.2.2.2/32 LB 1 buckets via: "
6462 "label 1600 over 1.1.1.1");
6464 dpo_id_t dpo_44 = DPO_INVALID;
6467 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6468 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6470 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6471 "uRPF check for 2.2.2.2/32 on %d OK",
6472 tm->hw[0]->sw_if_index);
6473 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6474 "uRPF check for 2.2.2.2/32 on %d OK",
6475 tm->hw[1]->sw_if_index);
6476 FIB_TEST(!fib_urpf_check(urpfi, 99),
6477 "uRPF check for 2.2.2.2/32 on 99 not-OK",
6480 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6481 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6482 "Shared uRPF on IP and non-EOS chain");
6487 * we are holding a lock on the non-eos LB of the via-entry.
6488 * do a PIC-core failover by shutting the link of the via-entry.
6490 * shut down the link with the valid label
6492 vnet_sw_interface_set_flags(vnet_get_main(),
6493 tm->hw[0]->sw_if_index,
6496 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6497 FIB_TEST(fib_test_validate_entry(fei,
6498 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6502 "1.1.1.1/32 LB 2 buckets via: "
6503 "adj over 10.10.11.1, ",
6504 "adj-v4 over 10.10.11.2");
6506 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6508 FIB_TEST(fib_test_validate_entry(fei,
6509 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6513 "24001/eos LB 2 buckets via: "
6514 "adj over 10.10.11.1, ",
6515 "adj-v4 over 10.10.11.2");
6517 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6519 FIB_TEST(fib_test_validate_entry(fei,
6520 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6522 &a_mpls_o_10_10_11_1),
6523 "24001/neos LB 1 buckets via: "
6524 "adj-mpls over 10.10.11.2");
6527 * test that the pre-failover load-balance has been in-place
6530 dpo_id_t current = DPO_INVALID;
6531 fib_entry_contribute_forwarding(fei,
6532 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6535 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6537 "PIC-core LB inplace modified %U %U",
6538 format_dpo_id, &non_eos_1_1_1_1, 0,
6539 format_dpo_id, ¤t, 0);
6541 dpo_reset(&non_eos_1_1_1_1);
6542 dpo_reset(¤t);
6545 * no-shut the link with the valid label
6547 vnet_sw_interface_set_flags(vnet_get_main(),
6548 tm->hw[0]->sw_if_index,
6549 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6551 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6552 FIB_TEST(fib_test_validate_entry(fei,
6553 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6554 16, // 3 choices spread over 16 buckets
6555 &l99_eos_o_10_10_10_1,
6556 &l99_eos_o_10_10_10_1,
6557 &l99_eos_o_10_10_10_1,
6558 &l99_eos_o_10_10_10_1,
6559 &l99_eos_o_10_10_10_1,
6560 &l99_eos_o_10_10_10_1,
6571 "1.1.1.1/32 LB 16 buckets via: "
6572 "label 99 over 10.10.10.1, "
6573 "adj over 10.10.11.1",
6574 "adj-v4 over 10.10.11.2");
6577 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6579 FIB_TEST(fib_test_validate_entry(fei,
6580 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6581 16, // 3 choices spread over 16 buckets
6582 &l99_eos_o_10_10_10_1,
6583 &l99_eos_o_10_10_10_1,
6584 &l99_eos_o_10_10_10_1,
6585 &l99_eos_o_10_10_10_1,
6586 &l99_eos_o_10_10_10_1,
6587 &l99_eos_o_10_10_10_1,
6598 "24001/eos LB 16 buckets via: "
6599 "label 99 over 10.10.10.1, "
6600 "adj over 10.10.11.1",
6601 "adj-v4 over 10.10.11.2");
6603 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6605 FIB_TEST(fib_test_validate_entry(fei,
6606 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6608 &l99_neos_o_10_10_10_1,
6609 &a_mpls_o_10_10_11_1),
6610 "24001/neos LB 2 buckets via: "
6611 "label 99 over 10.10.10.1, "
6612 "adj-mpls over 10.10.11.2");
6615 * remove the first path with the valid label
6617 fib_table_entry_path_remove(fib_index,
6622 tm->hw[0]->sw_if_index,
6623 ~0, // invalid fib index
6625 FIB_ROUTE_PATH_FLAG_NONE);
6627 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6628 FIB_TEST(fib_test_validate_entry(fei,
6629 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6633 "1.1.1.1/32 LB 2 buckets via: "
6634 "adj over 10.10.11.1, "
6635 "adj-v4 over 10.10.11.2");
6637 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6639 FIB_TEST(fib_test_validate_entry(fei,
6640 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6644 "24001/eos LB 2 buckets via: "
6645 "adj over 10.10.11.1, "
6646 "adj-v4 over 10.10.11.2");
6648 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6651 FIB_TEST(fib_test_validate_entry(fei,
6652 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6654 &a_mpls_o_10_10_11_1),
6655 "24001/neos LB 1 buckets via: "
6656 "adj-mpls over 10.10.11.2");
6659 * remove the other path with a valid label
6661 fib_test_lb_bucket_t bucket_drop = {
6662 .type = FT_LB_SPECIAL,
6664 .adj = DPO_PROTO_IP4,
6667 fib_test_lb_bucket_t mpls_bucket_drop = {
6668 .type = FT_LB_SPECIAL,
6670 .adj = DPO_PROTO_MPLS,
6674 fib_table_entry_path_remove(fib_index,
6679 tm->hw[1]->sw_if_index,
6680 ~0, // invalid fib index
6682 FIB_ROUTE_PATH_FLAG_NONE);
6684 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6685 FIB_TEST(fib_test_validate_entry(fei,
6686 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6689 "1.1.1.1/32 LB 1 buckets via: "
6690 "adj over 10.10.11.2");
6692 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6694 FIB_TEST(fib_test_validate_entry(fei,
6695 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6698 "24001/eos LB 1 buckets via: "
6699 "adj over 10.10.11.2");
6701 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6703 FIB_TEST(fib_test_validate_entry(fei,
6704 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6707 "24001/neos LB 1 buckets via: DROP");
6710 * add back the path with the valid label
6715 fib_table_entry_path_add(fib_index,
6718 FIB_ENTRY_FLAG_NONE,
6721 tm->hw[0]->sw_if_index,
6722 ~0, // invalid fib index
6725 FIB_ROUTE_PATH_FLAG_NONE);
6727 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6728 FIB_TEST(fib_test_validate_entry(fei,
6729 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6731 &l99_eos_o_10_10_10_1,
6733 "1.1.1.1/32 LB 2 buckets via: "
6734 "label 99 over 10.10.10.1, "
6735 "adj over 10.10.11.2");
6737 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6739 FIB_TEST(fib_test_validate_entry(fei,
6740 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6742 &l99_eos_o_10_10_10_1,
6744 "24001/eos LB 2 buckets via: "
6745 "label 99 over 10.10.10.1, "
6746 "adj over 10.10.11.2");
6748 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6750 FIB_TEST(fib_test_validate_entry(fei,
6751 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6753 &l99_neos_o_10_10_10_1),
6754 "24001/neos LB 1 buckets via: "
6755 "label 99 over 10.10.10.1");
6758 * change the local label
6760 fib_table_entry_local_label_add(fib_index,
6764 fib_prefix_t pfx_25005_eos = {
6765 .fp_proto = FIB_PROTOCOL_MPLS,
6769 fib_prefix_t pfx_25005_neos = {
6770 .fp_proto = FIB_PROTOCOL_MPLS,
6772 .fp_eos = MPLS_NON_EOS,
6775 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6776 fib_table_lookup(fib_index, &pfx_24001_eos)),
6777 "24001/eos removed after label change");
6778 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6779 fib_table_lookup(fib_index, &pfx_24001_neos)),
6780 "24001/eos removed after label change");
6782 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6784 FIB_TEST(fib_test_validate_entry(fei,
6785 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6787 &l99_eos_o_10_10_10_1,
6789 "25005/eos LB 2 buckets via: "
6790 "label 99 over 10.10.10.1, "
6791 "adj over 10.10.11.2");
6793 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6795 FIB_TEST(fib_test_validate_entry(fei,
6796 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6798 &l99_neos_o_10_10_10_1),
6799 "25005/neos LB 1 buckets via: "
6800 "label 99 over 10.10.10.1");
6803 * remove the local label.
6804 * the check that the MPLS entries are gone is done by the fact the
6805 * MPLS table is no longer present.
6807 fib_table_entry_local_label_remove(fib_index,
6811 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6812 FIB_TEST(fib_test_validate_entry(fei,
6813 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6815 &l99_eos_o_10_10_10_1,
6817 "24001/eos LB 2 buckets via: "
6818 "label 99 over 10.10.10.1, "
6819 "adj over 10.10.11.2");
6821 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6822 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6823 "No more MPLS FIB entries => table removed");
6826 * add another via-entry for the recursive
6828 fib_prefix_t pfx_1_1_1_2_s_32 = {
6830 .fp_proto = FIB_PROTOCOL_IP4,
6832 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6835 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6836 .type = FT_LB_LABEL_O_ADJ,
6838 .adj = ai_mpls_10_10_10_1,
6843 mpls_label_t *l101 = NULL;
6844 vec_add1(l101, 101);
6846 fei = fib_table_entry_update_one_path(fib_index,
6849 FIB_ENTRY_FLAG_NONE,
6852 tm->hw[0]->sw_if_index,
6853 ~0, // invalid fib index
6856 FIB_ROUTE_PATH_FLAG_NONE);
6858 FIB_TEST(fib_test_validate_entry(fei,
6859 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6861 &l101_eos_o_10_10_10_1),
6862 "1.1.1.2/32 LB 1 buckets via: "
6863 "label 101 over 10.10.10.1");
6865 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6866 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6868 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6870 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6872 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6875 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6876 .type = FT_LB_LABEL_O_LB,
6878 .lb = non_eos_1_1_1_2.dpoi_index,
6883 mpls_label_t *l1601 = NULL;
6884 vec_add1(l1601, 1601);
6886 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6888 fei = fib_table_entry_path_add(fib_index,
6891 FIB_ENTRY_FLAG_NONE,
6893 &pfx_1_1_1_2_s_32.fp_addr,
6898 FIB_ROUTE_PATH_FLAG_NONE);
6900 FIB_TEST(fib_test_validate_entry(fei,
6901 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6903 &l1600_eos_o_1_1_1_1,
6904 &l1601_eos_o_1_1_1_2),
6905 "2.2.2.2/32 LB 2 buckets via: "
6906 "label 1600 via 1.1,1.1, "
6907 "label 16001 via 1.1.1.2");
6910 * update the via-entry so it no longer has an imp-null path.
6911 * the LB for the recursive can use an imp-null
6914 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6916 fei = fib_table_entry_update_one_path(fib_index,
6919 FIB_ENTRY_FLAG_NONE,
6922 tm->hw[1]->sw_if_index,
6923 ~0, // invalid fib index
6926 FIB_ROUTE_PATH_FLAG_NONE);
6928 FIB_TEST(fib_test_validate_entry(fei,
6929 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6932 "1.1.1.2/32 LB 1 buckets via: "
6935 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6936 FIB_TEST(fib_test_validate_entry(fei,
6937 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6939 &l1600_eos_o_1_1_1_1,
6940 &l1601_eos_o_1_1_1_2),
6941 "2.2.2.2/32 LB 2 buckets via: "
6942 "label 1600 via 1.1,1.1, "
6943 "label 16001 via 1.1.1.2");
6946 * update the via-entry so it no longer has labelled paths.
6947 * the LB for the recursive should exclue this via form its LB
6949 fei = fib_table_entry_update_one_path(fib_index,
6952 FIB_ENTRY_FLAG_NONE,
6955 tm->hw[1]->sw_if_index,
6956 ~0, // invalid fib index
6959 FIB_ROUTE_PATH_FLAG_NONE);
6961 FIB_TEST(fib_test_validate_entry(fei,
6962 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6965 "1.1.1.2/32 LB 1 buckets via: "
6968 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6969 FIB_TEST(fib_test_validate_entry(fei,
6970 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6972 &l1600_eos_o_1_1_1_1),
6973 "2.2.2.2/32 LB 1 buckets via: "
6974 "label 1600 via 1.1,1.1");
6976 dpo_reset(&non_eos_1_1_1_1);
6977 dpo_reset(&non_eos_1_1_1_2);
6980 * Add a recursive with no out-labels. We expect to use the IP of the via
6982 fib_prefix_t pfx_2_2_2_3_s_32 = {
6984 .fp_proto = FIB_PROTOCOL_IP4,
6986 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6989 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6991 fib_table_entry_update_one_path(fib_index,
6994 FIB_ENTRY_FLAG_NONE,
6996 &pfx_1_1_1_1_s_32.fp_addr,
7001 FIB_ROUTE_PATH_FLAG_NONE);
7003 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7005 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7008 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7011 .lb = ip_1_1_1_1.dpoi_index,
7015 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7016 FIB_TEST(fib_test_validate_entry(fei,
7017 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7020 "2.2.2.2.3/32 LB 1 buckets via: "
7024 * Add a recursive with an imp-null out-label.
7025 * We expect to use the IP of the via
7027 fib_prefix_t pfx_2_2_2_4_s_32 = {
7029 .fp_proto = FIB_PROTOCOL_IP4,
7031 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7035 fib_table_entry_update_one_path(fib_index,
7038 FIB_ENTRY_FLAG_NONE,
7040 &pfx_1_1_1_1_s_32.fp_addr,
7045 FIB_ROUTE_PATH_FLAG_NONE);
7047 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7048 FIB_TEST(fib_test_validate_entry(fei,
7049 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7052 "2.2.2.2.4/32 LB 1 buckets via: "
7055 dpo_reset(&ip_1_1_1_1);
7058 * Create an entry with a deep label stack
7060 fib_prefix_t pfx_2_2_5_5_s_32 = {
7062 .fp_proto = FIB_PROTOCOL_IP4,
7064 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7067 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7068 .type = FT_LB_LABEL_STACK_O_ADJ,
7069 .label_stack_o_adj = {
7070 .adj = ai_mpls_10_10_11_1,
7071 .label_stack_size = 8,
7073 200, 201, 202, 203, 204, 205, 206, 207
7078 mpls_label_t *label_stack = NULL;
7079 vec_validate(label_stack, 7);
7080 for (ii = 0; ii < 8; ii++)
7082 label_stack[ii] = ii + 200;
7085 fei = fib_table_entry_update_one_path(fib_index,
7088 FIB_ENTRY_FLAG_NONE,
7091 tm->hw[1]->sw_if_index,
7092 ~0, // invalid fib index
7095 FIB_ROUTE_PATH_FLAG_NONE);
7097 FIB_TEST(fib_test_validate_entry(fei,
7098 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7100 &ls_eos_o_10_10_10_1),
7101 "2.2.5.5/32 LB 1 buckets via: "
7103 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7108 fib_table_entry_delete(fib_index,
7112 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7113 FIB_TEST(fib_test_validate_entry(fei,
7114 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7116 &l1600_eos_o_1_1_1_1),
7117 "2.2.2.2/32 LB 1 buckets via: "
7118 "label 1600 via 1.1,1.1");
7120 fib_table_entry_delete(fib_index,
7124 FIB_TEST(fib_test_validate_entry(fei,
7125 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7128 "2.2.2.2/32 LB 1 buckets via: DROP");
7130 fib_table_entry_delete(fib_index,
7133 fib_table_entry_delete(fib_index,
7136 fib_table_entry_delete(fib_index,
7140 adj_unlock(ai_mpls_10_10_10_1);
7141 adj_unlock(ai_mpls_10_10_11_2);
7142 adj_unlock(ai_v4_10_10_11_1);
7143 adj_unlock(ai_v4_10_10_11_2);
7144 adj_unlock(ai_mpls_10_10_11_1);
7146 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7149 local0_pfx.fp_len = 32;
7150 fib_table_entry_delete(fib_index,
7152 FIB_SOURCE_INTERFACE);
7153 local0_pfx.fp_len = 24;
7154 fib_table_entry_delete(fib_index,
7156 FIB_SOURCE_INTERFACE);
7157 local1_pfx.fp_len = 32;
7158 fib_table_entry_delete(fib_index,
7160 FIB_SOURCE_INTERFACE);
7161 local1_pfx.fp_len = 24;
7162 fib_table_entry_delete(fib_index,
7164 FIB_SOURCE_INTERFACE);
7167 * +1 for the drop LB in the MPLS tables.
7169 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7170 "Load-balance resources freed %d of %d",
7171 lb_count+1, pool_elts(load_balance_pool));
7176 #define N_TEST_CHILDREN 4
7177 #define PARENT_INDEX 0
7179 typedef struct fib_node_test_t_
7184 fib_node_back_walk_ctx_t *ctxs;
7188 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7190 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7192 #define FOR_EACH_TEST_CHILD(_tc) \
7193 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
7194 ii < N_TEST_CHILDREN+1; \
7195 ii++, (_tc) = &fib_test_nodes[ii])
7198 fib_test_child_get_node (fib_node_index_t index)
7200 return (&fib_test_nodes[index].node);
7203 static int fib_test_walk_spawns_walks;
7205 static fib_node_back_walk_rc_t
7206 fib_test_child_back_walk_notify (fib_node_t *node,
7207 fib_node_back_walk_ctx_t *ctx)
7209 fib_node_test_t *tc = (fib_node_test_t*) node;
7211 vec_add1(tc->ctxs, *ctx);
7213 if (1 == fib_test_walk_spawns_walks)
7214 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7215 if (2 == fib_test_walk_spawns_walks)
7216 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7217 FIB_WALK_PRIORITY_HIGH, ctx);
7219 return (FIB_NODE_BACK_WALK_CONTINUE);
7223 fib_test_child_last_lock_gone (fib_node_t *node)
7225 fib_node_test_t *tc = (fib_node_test_t *)node;
7231 * The FIB walk's graph node virtual function table
7233 static const fib_node_vft_t fib_test_child_vft = {
7234 .fnv_get = fib_test_child_get_node,
7235 .fnv_last_lock = fib_test_child_last_lock_gone,
7236 .fnv_back_walk = fib_test_child_back_walk_notify,
7240 * the function (that should have been static but isn't so I can do this)
7241 * that processes the walk from the async queue,
7243 f64 fib_walk_process_queues(vlib_main_t * vm,
7245 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7248 fib_test_walk (void)
7250 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7251 fib_node_test_t *tc;
7255 vm = vlib_get_main();
7256 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7259 * init a fake node on which we will add children
7261 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7262 FIB_NODE_TYPE_TEST);
7264 FOR_EACH_TEST_CHILD(tc)
7266 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7267 fib_node_lock(&tc->node);
7270 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7272 FIB_NODE_TYPE_TEST, ii);
7276 * enqueue a walk across the parents children.
7278 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7280 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7281 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7282 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7283 "Parent has %d children pre-walk",
7284 fib_node_list_get_size(PARENT()->fn_children));
7287 * give the walk a large amount of time so it gets to the end
7289 fib_walk_process_queues(vm, 1);
7291 FOR_EACH_TEST_CHILD(tc)
7293 FIB_TEST(1 == vec_len(tc->ctxs),
7294 "%d child visitsed %d times",
7295 ii, vec_len(tc->ctxs));
7298 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7299 "Queue is empty post walk");
7300 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7301 "Parent has %d children post walk",
7302 fib_node_list_get_size(PARENT()->fn_children));
7305 * walk again. should be no increase in the number of visits, since
7306 * the walk will have terminated.
7308 fib_walk_process_queues(vm, 1);
7310 FOR_EACH_TEST_CHILD(tc)
7312 FIB_TEST(0 == vec_len(tc->ctxs),
7313 "%d child visitsed %d times",
7314 ii, vec_len(tc->ctxs));
7318 * schedule a low and hig priority walk. expect the high to be performed
7320 * schedule the high prio walk first so that it is further from the head
7321 * of the dependency list. that way it won't merge with the low one.
7323 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7324 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7326 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7327 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7328 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7329 FIB_WALK_PRIORITY_LOW, &low_ctx);
7331 fib_walk_process_queues(vm, 1);
7333 FOR_EACH_TEST_CHILD(tc)
7335 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7336 "%d child visitsed by high prio walk", ii);
7337 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7338 "%d child visitsed by low prio walk", ii);
7341 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7342 "Queue is empty post prio walk");
7343 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7344 "Parent has %d children post prio walk",
7345 fib_node_list_get_size(PARENT()->fn_children));
7348 * schedule 2 walks of the same priority that can be megred.
7349 * expect that each child is thus visited only once.
7351 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7352 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7354 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7355 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7356 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7357 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7359 fib_walk_process_queues(vm, 1);
7361 FOR_EACH_TEST_CHILD(tc)
7363 FIB_TEST(1 == vec_len(tc->ctxs),
7364 "%d child visitsed %d times during merge walk",
7365 ii, vec_len(tc->ctxs));
7368 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7369 "Queue is empty post merge walk");
7370 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7371 "Parent has %d children post merge walk",
7372 fib_node_list_get_size(PARENT()->fn_children));
7375 * schedule 2 walks of the same priority that cannot be megred.
7376 * expect that each child is thus visited twice and in the order
7377 * in which the walks were scheduled.
7379 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7380 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7382 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7383 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7384 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7385 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7387 fib_walk_process_queues(vm, 1);
7389 FOR_EACH_TEST_CHILD(tc)
7391 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7392 "%d child visitsed by high prio walk", ii);
7393 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7394 "%d child visitsed by low prio walk", ii);
7397 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7398 "Queue is empty post no-merge walk");
7399 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7400 "Parent has %d children post no-merge walk",
7401 fib_node_list_get_size(PARENT()->fn_children));
7404 * schedule a walk that makes one one child progress.
7405 * we do this by giving the queue draining process zero
7406 * time quanta. it's a do..while loop, so it does something.
7408 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7410 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7411 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7412 fib_walk_process_queues(vm, 0);
7414 FOR_EACH_TEST_CHILD(tc)
7416 if (ii == N_TEST_CHILDREN)
7418 FIB_TEST(1 == vec_len(tc->ctxs),
7419 "%d child visitsed %d times in zero quanta walk",
7420 ii, vec_len(tc->ctxs));
7424 FIB_TEST(0 == vec_len(tc->ctxs),
7425 "%d child visitsed %d times in 0 quanta walk",
7426 ii, vec_len(tc->ctxs));
7429 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7430 "Queue is not empty post zero quanta walk");
7431 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7432 "Parent has %d children post zero qunta walk",
7433 fib_node_list_get_size(PARENT()->fn_children));
7438 fib_walk_process_queues(vm, 0);
7440 FOR_EACH_TEST_CHILD(tc)
7442 if (ii >= N_TEST_CHILDREN-1)
7444 FIB_TEST(1 == vec_len(tc->ctxs),
7445 "%d child visitsed %d times in 2nd zero quanta walk",
7446 ii, vec_len(tc->ctxs));
7450 FIB_TEST(0 == vec_len(tc->ctxs),
7451 "%d child visitsed %d times in 2nd 0 quanta walk",
7452 ii, vec_len(tc->ctxs));
7455 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7456 "Queue is not empty post zero quanta walk");
7457 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7458 "Parent has %d children post zero qunta walk",
7459 fib_node_list_get_size(PARENT()->fn_children));
7462 * schedule another walk that will catch-up and merge.
7464 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7465 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7466 fib_walk_process_queues(vm, 1);
7468 FOR_EACH_TEST_CHILD(tc)
7470 if (ii >= N_TEST_CHILDREN-1)
7472 FIB_TEST(2 == vec_len(tc->ctxs),
7473 "%d child visitsed %d times in 2nd zero quanta merge walk",
7474 ii, vec_len(tc->ctxs));
7479 FIB_TEST(1 == vec_len(tc->ctxs),
7480 "%d child visitsed %d times in 2nd 0 quanta merge walk",
7481 ii, vec_len(tc->ctxs));
7485 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7486 "Queue is not empty post 2nd zero quanta merge walk");
7487 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7488 "Parent has %d children post 2nd zero qunta merge walk",
7489 fib_node_list_get_size(PARENT()->fn_children));
7492 * park a async walk in the middle of the list, then have an sync walk catch
7493 * it. same expectations as async catches async.
7495 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7497 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7498 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7500 fib_walk_process_queues(vm, 0);
7501 fib_walk_process_queues(vm, 0);
7503 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7505 FOR_EACH_TEST_CHILD(tc)
7507 if (ii >= N_TEST_CHILDREN-1)
7509 FIB_TEST(2 == vec_len(tc->ctxs),
7510 "%d child visitsed %d times in sync catches async walk",
7511 ii, vec_len(tc->ctxs));
7516 FIB_TEST(1 == vec_len(tc->ctxs),
7517 "%d child visitsed %d times in sync catches async walk",
7518 ii, vec_len(tc->ctxs));
7522 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7523 "Queue is not empty post 2nd zero quanta merge walk");
7524 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7525 "Parent has %d children post 2nd zero qunta merge walk",
7526 fib_node_list_get_size(PARENT()->fn_children));
7529 * make the parent a child of one of its children, thus inducing a routing loop.
7531 fib_test_nodes[PARENT_INDEX].sibling =
7532 fib_node_child_add(FIB_NODE_TYPE_TEST,
7533 1, // the first child
7538 * execute a sync walk from the parent. each child visited spawns more sync
7539 * walks. we expect the walk to terminate.
7541 fib_test_walk_spawns_walks = 1;
7543 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7545 FOR_EACH_TEST_CHILD(tc)
7548 * child 1 - which is last in the list - has the loop.
7549 * the other children a re thus visitsed first. the we meet
7550 * child 1. we go round the loop again, visting the other children.
7551 * then we meet the walk in the dep list and bail. child 1 is not visitsed
7556 FIB_TEST(1 == vec_len(tc->ctxs),
7557 "child %d visitsed %d times during looped sync walk",
7558 ii, vec_len(tc->ctxs));
7562 FIB_TEST(2 == vec_len(tc->ctxs),
7563 "child %d visitsed %d times during looped sync walk",
7564 ii, vec_len(tc->ctxs));
7568 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7569 "Parent has %d children post sync loop walk",
7570 fib_node_list_get_size(PARENT()->fn_children));
7573 * the walk doesn't reach the max depth because the infra knows that sync
7574 * meets sync implies a loop and bails early.
7576 FIB_TEST(high_ctx.fnbw_depth == 9,
7577 "Walk context depth %d post sync loop walk",
7578 high_ctx.fnbw_depth);
7581 * execute an async walk of the graph loop, with each child spawns sync walks
7583 high_ctx.fnbw_depth = 0;
7584 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7585 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7587 fib_walk_process_queues(vm, 1);
7589 FOR_EACH_TEST_CHILD(tc)
7592 * we don't really care how many times the children are visisted, as long as
7593 * it is more than once.
7595 FIB_TEST(1 <= vec_len(tc->ctxs),
7596 "child %d visitsed %d times during looped aync spawns sync walk",
7597 ii, vec_len(tc->ctxs));
7602 * execute an async walk of the graph loop, with each child spawns async walks
7604 fib_test_walk_spawns_walks = 2;
7605 high_ctx.fnbw_depth = 0;
7606 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7607 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7609 fib_walk_process_queues(vm, 1);
7611 FOR_EACH_TEST_CHILD(tc)
7614 * we don't really care how many times the children are visisted, as long as
7615 * it is more than once.
7617 FIB_TEST(1 <= vec_len(tc->ctxs),
7618 "child %d visitsed %d times during looped async spawns async walk",
7619 ii, vec_len(tc->ctxs));
7624 fib_node_child_remove(FIB_NODE_TYPE_TEST,
7625 1, // the first child
7626 fib_test_nodes[PARENT_INDEX].sibling);
7631 FOR_EACH_TEST_CHILD(tc)
7633 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7635 fib_node_deinit(&tc->node);
7636 fib_node_unlock(&tc->node);
7638 fib_node_deinit(PARENT());
7641 * The parent will be destroyed when the last lock on it goes.
7642 * this test ensures all the walk objects are unlocking it.
7644 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7645 "Parent was destroyed");
7651 * declaration of the otherwise static callback functions
7653 void fib_bfd_notify (bfd_listen_event_e event,
7654 const bfd_session_t *session);
7655 void adj_bfd_notify (bfd_listen_event_e event,
7656 const bfd_session_t *session);
7659 * Test BFD session interaction with FIB
7664 fib_node_index_t fei;
7668 /* via 10.10.10.1 */
7669 ip46_address_t nh_10_10_10_1 = {
7670 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7672 /* via 10.10.10.2 */
7673 ip46_address_t nh_10_10_10_2 = {
7674 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7676 /* via 10.10.10.10 */
7677 ip46_address_t nh_10_10_10_10 = {
7678 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7680 n_feis = fib_entry_pool_size();
7685 * add interface routes. we'll assume this works. it's tested elsewhere
7687 fib_prefix_t pfx_10_10_10_10_s_24 = {
7689 .fp_proto = FIB_PROTOCOL_IP4,
7690 .fp_addr = nh_10_10_10_10,
7693 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7694 FIB_SOURCE_INTERFACE,
7695 (FIB_ENTRY_FLAG_CONNECTED |
7696 FIB_ENTRY_FLAG_ATTACHED),
7699 tm->hw[0]->sw_if_index,
7700 ~0, // invalid fib index
7703 FIB_ROUTE_PATH_FLAG_NONE);
7705 fib_prefix_t pfx_10_10_10_10_s_32 = {
7707 .fp_proto = FIB_PROTOCOL_IP4,
7708 .fp_addr = nh_10_10_10_10,
7710 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7711 FIB_SOURCE_INTERFACE,
7712 (FIB_ENTRY_FLAG_CONNECTED |
7713 FIB_ENTRY_FLAG_LOCAL),
7716 tm->hw[0]->sw_if_index,
7717 ~0, // invalid fib index
7720 FIB_ROUTE_PATH_FLAG_NONE);
7723 * A BFD session via a neighbour we do not yet know
7725 bfd_session_t bfd_10_10_10_1 = {
7729 .peer_addr = nh_10_10_10_1,
7732 .hop_type = BFD_HOP_TYPE_MULTI,
7733 .local_state = BFD_STATE_init,
7736 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7739 * A new entry will be created that forwards via the adj
7741 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7744 tm->hw[0]->sw_if_index);
7745 fib_prefix_t pfx_10_10_10_1_s_32 = {
7746 .fp_addr = nh_10_10_10_1,
7748 .fp_proto = FIB_PROTOCOL_IP4,
7750 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7753 .adj = ai_10_10_10_1,
7757 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7758 FIB_TEST(fib_test_validate_entry(fei,
7759 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7762 "BFD sourced %U via %U",
7763 format_fib_prefix, &pfx_10_10_10_1_s_32,
7764 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7767 * Delete the BFD session. Expect the fib_entry to be removed
7769 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7771 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7772 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7773 "BFD sourced %U removed",
7774 format_fib_prefix, &pfx_10_10_10_1_s_32);
7777 * Add the BFD source back
7779 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7782 * source the entry via the ADJ fib
7784 fei = fib_table_entry_path_add(0,
7785 &pfx_10_10_10_1_s_32,
7787 FIB_ENTRY_FLAG_ATTACHED,
7790 tm->hw[0]->sw_if_index,
7791 ~0, // invalid fib index
7794 FIB_ROUTE_PATH_FLAG_NONE);
7797 * Delete the BFD session. Expect the fib_entry to remain
7799 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7801 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7802 FIB_TEST(fib_test_validate_entry(fei,
7803 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7806 "BFD sourced %U remains via %U",
7807 format_fib_prefix, &pfx_10_10_10_1_s_32,
7808 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7811 * Add the BFD source back
7813 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7816 * Create another ADJ FIB
7818 fib_prefix_t pfx_10_10_10_2_s_32 = {
7819 .fp_addr = nh_10_10_10_2,
7821 .fp_proto = FIB_PROTOCOL_IP4,
7823 fib_table_entry_path_add(0,
7824 &pfx_10_10_10_2_s_32,
7826 FIB_ENTRY_FLAG_ATTACHED,
7829 tm->hw[0]->sw_if_index,
7830 ~0, // invalid fib index
7833 FIB_ROUTE_PATH_FLAG_NONE);
7835 * A BFD session for the new ADJ FIB
7837 bfd_session_t bfd_10_10_10_2 = {
7841 .peer_addr = nh_10_10_10_2,
7844 .hop_type = BFD_HOP_TYPE_MULTI,
7845 .local_state = BFD_STATE_init,
7848 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7851 * remove the adj-fib source whilst the session is present
7854 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7855 fib_table_entry_path_add(0,
7856 &pfx_10_10_10_2_s_32,
7858 FIB_ENTRY_FLAG_ATTACHED,
7861 tm->hw[0]->sw_if_index,
7862 ~0, // invalid fib index
7865 FIB_ROUTE_PATH_FLAG_NONE);
7868 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7869 * bring one of the sessions UP, leave the other down
7871 bfd_10_10_10_1.local_state = BFD_STATE_up;
7872 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7873 bfd_10_10_10_2.local_state = BFD_STATE_down;
7874 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7877 * A recursive prefix via both of the ADJ FIBs
7879 fib_prefix_t pfx_200_0_0_0_s_24 = {
7880 .fp_proto = FIB_PROTOCOL_IP4,
7883 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7886 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7889 fib_entry_contribute_ip_forwarding(
7890 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7892 fib_entry_contribute_ip_forwarding(
7893 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7895 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7898 .lb = dpo_10_10_10_1->dpoi_index,
7901 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7904 .lb = dpo_10_10_10_2->dpoi_index,
7909 * A prefix via the adj-fib that is BFD down => DROP
7911 fei = fib_table_entry_path_add(0,
7912 &pfx_200_0_0_0_s_24,
7914 FIB_ENTRY_FLAG_NONE,
7918 0, // default fib index
7921 FIB_ROUTE_PATH_FLAG_NONE);
7922 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7923 "%U resolves via drop",
7924 format_fib_prefix, &pfx_200_0_0_0_s_24);
7927 * add a path via the UP BFD adj-fib.
7928 * we expect that the DOWN BFD ADJ FIB is not used.
7930 fei = fib_table_entry_path_add(0,
7931 &pfx_200_0_0_0_s_24,
7933 FIB_ENTRY_FLAG_NONE,
7937 0, // default fib index
7940 FIB_ROUTE_PATH_FLAG_NONE);
7942 FIB_TEST(fib_test_validate_entry(fei,
7943 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7946 "Recursive %U only UP BFD adj-fibs",
7947 format_fib_prefix, &pfx_200_0_0_0_s_24);
7950 * Send a BFD state change to UP - both sessions are now up
7951 * the recursive prefix should LB over both
7953 bfd_10_10_10_2.local_state = BFD_STATE_up;
7954 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7957 FIB_TEST(fib_test_validate_entry(fei,
7958 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7962 "Recursive %U via both UP BFD adj-fibs",
7963 format_fib_prefix, &pfx_200_0_0_0_s_24);
7966 * Send a BFD state change to DOWN
7967 * the recursive prefix should exclude the down
7969 bfd_10_10_10_2.local_state = BFD_STATE_down;
7970 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7973 FIB_TEST(fib_test_validate_entry(fei,
7974 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7977 "Recursive %U via only UP",
7978 format_fib_prefix, &pfx_200_0_0_0_s_24);
7981 * Delete the BFD session while it is in the DOWN state.
7982 * FIB should consider the entry's state as back up
7984 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
7986 FIB_TEST(fib_test_validate_entry(fei,
7987 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7991 "Recursive %U via both UP BFD adj-fibs post down session delete",
7992 format_fib_prefix, &pfx_200_0_0_0_s_24);
7995 * Delete the BFD other session while it is in the UP state.
7997 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7999 FIB_TEST(fib_test_validate_entry(fei,
8000 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8004 "Recursive %U via both UP BFD adj-fibs post up session delete",
8005 format_fib_prefix, &pfx_200_0_0_0_s_24);
8010 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8011 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8012 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8014 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8015 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8017 adj_unlock(ai_10_10_10_1);
8019 * test no-one left behind
8021 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8022 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8025 * Single-hop BFD tests
8027 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8028 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8030 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8032 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8035 tm->hw[0]->sw_if_index);
8037 * whilst the BFD session is not signalled, the adj is up
8039 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
8042 * bring the BFD session up
8044 bfd_10_10_10_1.local_state = BFD_STATE_up;
8045 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8046 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8049 * bring the BFD session down
8051 bfd_10_10_10_1.local_state = BFD_STATE_down;
8052 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8053 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8057 * add an attached next hop FIB entry via the down adj
8059 fib_prefix_t pfx_5_5_5_5_s_32 = {
8062 .as_u32 = clib_host_to_net_u32(0x05050505),
8066 .fp_proto = FIB_PROTOCOL_IP4,
8069 fei = fib_table_entry_path_add(0,
8072 FIB_ENTRY_FLAG_NONE,
8075 tm->hw[0]->sw_if_index,
8076 ~0, // invalid fib index
8079 FIB_ROUTE_PATH_FLAG_NONE);
8080 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8081 "%U resolves via drop",
8082 format_fib_prefix, &pfx_5_5_5_5_s_32);
8085 * Add a path via an ADJ that is up
8087 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8090 tm->hw[0]->sw_if_index);
8092 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8095 .adj = ai_10_10_10_2,
8098 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8100 fei = fib_table_entry_path_add(0,
8103 FIB_ENTRY_FLAG_NONE,
8106 tm->hw[0]->sw_if_index,
8107 ~0, // invalid fib index
8110 FIB_ROUTE_PATH_FLAG_NONE);
8112 FIB_TEST(fib_test_validate_entry(fei,
8113 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8116 "BFD sourced %U via %U",
8117 format_fib_prefix, &pfx_5_5_5_5_s_32,
8118 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8121 * Bring up the down session - should now LB
8123 bfd_10_10_10_1.local_state = BFD_STATE_up;
8124 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8125 FIB_TEST(fib_test_validate_entry(fei,
8126 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8130 "BFD sourced %U via noth adjs",
8131 format_fib_prefix, &pfx_5_5_5_5_s_32);
8134 * remove the BFD session state from the adj
8136 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8141 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8142 adj_unlock(ai_10_10_10_1);
8143 adj_unlock(ai_10_10_10_2);
8146 * test no-one left behind
8148 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8149 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8156 const mpls_label_t deag_label = 50;
8157 const u32 lfib_index = 0;
8158 const u32 fib_index = 0;
8159 dpo_id_t dpo = DPO_INVALID;
8160 const dpo_id_t *dpo1;
8161 fib_node_index_t lfe;
8165 adj_index_t ai_mpls_10_10_10_1;
8168 lb_count = pool_elts(load_balance_pool);
8170 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8174 * MPLS enable an interface so we get the MPLS table created
8176 mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8177 mpls_sw_interface_enable_disable(&mpls_main,
8178 tm->hw[0]->sw_if_index,
8181 ip46_address_t nh_10_10_10_1 = {
8182 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8184 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8187 tm->hw[0]->sw_if_index);
8190 * Test the specials stack properly.
8192 fib_prefix_t exp_null_v6_pfx = {
8193 .fp_proto = FIB_PROTOCOL_MPLS,
8195 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8196 .fp_payload_proto = DPO_PROTO_IP6,
8198 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8199 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8201 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8202 format_mpls_eos_bit, MPLS_EOS);
8203 fib_entry_contribute_forwarding(lfe,
8204 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8206 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8207 lkd = lookup_dpo_get(dpo1->dpoi_index);
8209 FIB_TEST((fib_index == lkd->lkd_fib_index),
8210 "%U/%U is deag in %d %U",
8211 format_mpls_unicast_label, deag_label,
8212 format_mpls_eos_bit, MPLS_EOS,
8214 format_dpo_id, &dpo, 0);
8215 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8216 "%U/%U is dst deag",
8217 format_mpls_unicast_label, deag_label,
8218 format_mpls_eos_bit, MPLS_EOS);
8219 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8220 "%U/%U is lookup in interface's table",
8221 format_mpls_unicast_label, deag_label,
8222 format_mpls_eos_bit, MPLS_EOS);
8223 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8224 "%U/%U is %U dst deag",
8225 format_mpls_unicast_label, deag_label,
8226 format_mpls_eos_bit, MPLS_EOS,
8227 format_dpo_proto, lkd->lkd_proto);
8231 * A route deag route for EOS
8233 fib_prefix_t pfx = {
8234 .fp_proto = FIB_PROTOCOL_MPLS,
8236 .fp_label = deag_label,
8237 .fp_payload_proto = DPO_PROTO_IP4,
8239 lfe = fib_table_entry_path_add(lfib_index,
8242 FIB_ENTRY_FLAG_NONE,
8249 FIB_ROUTE_PATH_FLAG_NONE);
8251 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8253 format_mpls_unicast_label, deag_label,
8254 format_mpls_eos_bit, MPLS_EOS);
8256 fib_entry_contribute_forwarding(lfe,
8257 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8259 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8260 lkd = lookup_dpo_get(dpo1->dpoi_index);
8262 FIB_TEST((fib_index == lkd->lkd_fib_index),
8263 "%U/%U is deag in %d %U",
8264 format_mpls_unicast_label, deag_label,
8265 format_mpls_eos_bit, MPLS_EOS,
8267 format_dpo_id, &dpo, 0);
8268 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8269 "%U/%U is dst deag",
8270 format_mpls_unicast_label, deag_label,
8271 format_mpls_eos_bit, MPLS_EOS);
8272 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8273 "%U/%U is %U dst deag",
8274 format_mpls_unicast_label, deag_label,
8275 format_mpls_eos_bit, MPLS_EOS,
8276 format_dpo_proto, lkd->lkd_proto);
8278 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8280 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8282 "%U/%U not present",
8283 format_mpls_unicast_label, deag_label,
8284 format_mpls_eos_bit, MPLS_EOS);
8287 * A route deag route for non-EOS
8289 pfx.fp_eos = MPLS_NON_EOS;
8290 lfe = fib_table_entry_path_add(lfib_index,
8293 FIB_ENTRY_FLAG_NONE,
8300 FIB_ROUTE_PATH_FLAG_NONE);
8302 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8304 format_mpls_unicast_label, deag_label,
8305 format_mpls_eos_bit, MPLS_NON_EOS);
8307 fib_entry_contribute_forwarding(lfe,
8308 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8310 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8311 lkd = lookup_dpo_get(dpo1->dpoi_index);
8313 FIB_TEST((fib_index == lkd->lkd_fib_index),
8314 "%U/%U is deag in %d %U",
8315 format_mpls_unicast_label, deag_label,
8316 format_mpls_eos_bit, MPLS_NON_EOS,
8318 format_dpo_id, &dpo, 0);
8319 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8320 "%U/%U is dst deag",
8321 format_mpls_unicast_label, deag_label,
8322 format_mpls_eos_bit, MPLS_NON_EOS);
8324 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8325 "%U/%U is %U dst deag",
8326 format_mpls_unicast_label, deag_label,
8327 format_mpls_eos_bit, MPLS_NON_EOS,
8328 format_dpo_proto, lkd->lkd_proto);
8330 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8332 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8334 "%U/%U not present",
8335 format_mpls_unicast_label, deag_label,
8336 format_mpls_eos_bit, MPLS_EOS);
8343 fib_prefix_t pfx_1200 = {
8345 .fp_proto = FIB_PROTOCOL_MPLS,
8347 .fp_eos = MPLS_NON_EOS,
8349 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8350 .type = FT_LB_LABEL_STACK_O_ADJ,
8351 .label_stack_o_adj = {
8352 .adj = ai_mpls_10_10_10_1,
8353 .label_stack_size = 4,
8357 .eos = MPLS_NON_EOS,
8360 dpo_id_t neos_1200 = DPO_INVALID;
8361 dpo_id_t ip_1200 = DPO_INVALID;
8362 mpls_label_t *l200 = NULL;
8363 vec_add1(l200, 200);
8364 vec_add1(l200, 300);
8365 vec_add1(l200, 400);
8366 vec_add1(l200, 500);
8368 lfe = fib_table_entry_update_one_path(fib_index,
8371 FIB_ENTRY_FLAG_NONE,
8374 tm->hw[0]->sw_if_index,
8375 ~0, // invalid fib index
8378 FIB_ROUTE_PATH_FLAG_NONE);
8380 FIB_TEST(fib_test_validate_entry(lfe,
8381 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8383 &neos_o_10_10_10_1),
8384 "1200/0 LB 1 buckets via: "
8388 * A recursive route via the MPLS x-connect
8390 fib_prefix_t pfx_2_2_2_3_s_32 = {
8392 .fp_proto = FIB_PROTOCOL_IP4,
8394 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8397 fib_route_path_t *rpaths = NULL, rpath = {
8398 .frp_proto = DPO_PROTO_MPLS,
8399 .frp_local_label = 1200,
8400 .frp_eos = MPLS_NON_EOS,
8401 .frp_sw_if_index = ~0, // recurive
8402 .frp_fib_index = 0, // Default MPLS fib
8404 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8405 .frp_label_stack = NULL,
8407 vec_add1(rpaths, rpath);
8409 fib_table_entry_path_add2(fib_index,
8412 FIB_ENTRY_FLAG_NONE,
8416 * A labelled recursive route via the MPLS x-connect
8418 fib_prefix_t pfx_2_2_2_4_s_32 = {
8420 .fp_proto = FIB_PROTOCOL_IP4,
8422 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8425 mpls_label_t *l999 = NULL;
8426 vec_add1(l999, 999);
8427 rpaths[0].frp_label_stack = l999,
8429 fib_table_entry_path_add2(fib_index,
8432 FIB_ENTRY_FLAG_NONE,
8435 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8436 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8438 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8439 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8442 fib_test_lb_bucket_t ip_o_1200 = {
8445 .lb = ip_1200.dpoi_index,
8448 fib_test_lb_bucket_t mpls_o_1200 = {
8449 .type = FT_LB_LABEL_O_LB,
8451 .lb = neos_1200.dpoi_index,
8457 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8458 FIB_TEST(fib_test_validate_entry(lfe,
8459 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8462 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8463 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8464 FIB_TEST(fib_test_validate_entry(lfe,
8465 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8468 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8470 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8471 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8472 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8474 dpo_reset(&neos_1200);
8475 dpo_reset(&ip_1200);
8478 * A recursive via a label that does not exist
8480 fib_test_lb_bucket_t bucket_drop = {
8481 .type = FT_LB_SPECIAL,
8483 .adj = DPO_PROTO_IP4,
8486 fib_test_lb_bucket_t mpls_bucket_drop = {
8487 .type = FT_LB_SPECIAL,
8489 .adj = DPO_PROTO_MPLS,
8493 rpaths[0].frp_label_stack = NULL;
8494 lfe = fib_table_entry_path_add2(fib_index,
8497 FIB_ENTRY_FLAG_NONE,
8500 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8501 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8503 ip_o_1200.lb.lb = ip_1200.dpoi_index;
8505 FIB_TEST(fib_test_validate_entry(lfe,
8506 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8509 "2.2.2.2.4/32 LB 1 buckets via: drop");
8510 lfe = fib_table_lookup(fib_index, &pfx_1200);
8511 FIB_TEST(fib_test_validate_entry(lfe,
8512 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8515 "1200/neos LB 1 buckets via: ip4-DROP");
8516 FIB_TEST(fib_test_validate_entry(lfe,
8517 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8520 "1200/neos LB 1 buckets via: mpls-DROP");
8522 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8524 dpo_reset(&ip_1200);
8527 * An rx-interface route.
8528 * like the tail of an mcast LSP
8530 dpo_id_t idpo = DPO_INVALID;
8532 interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8533 tm->hw[0]->sw_if_index,
8536 fib_prefix_t pfx_2500 = {
8538 .fp_proto = FIB_PROTOCOL_MPLS,
8541 .fp_payload_proto = DPO_PROTO_IP4,
8543 fib_test_lb_bucket_t rx_intf_0 = {
8546 .adj = idpo.dpoi_index,
8550 lfe = fib_table_entry_update_one_path(fib_index,
8553 FIB_ENTRY_FLAG_NONE,
8556 tm->hw[0]->sw_if_index,
8557 ~0, // invalid fib index
8560 FIB_ROUTE_PATH_INTF_RX);
8561 FIB_TEST(fib_test_validate_entry(lfe,
8562 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8565 "2500 rx-interface 0");
8566 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8569 * An MPLS mulicast entry
8571 fib_prefix_t pfx_3500 = {
8573 .fp_proto = FIB_PROTOCOL_MPLS,
8576 .fp_payload_proto = DPO_PROTO_IP4,
8578 fib_test_rep_bucket_t mc_0 = {
8579 .type = FT_REP_LABEL_O_ADJ,
8581 .adj = ai_mpls_10_10_10_1,
8586 fib_test_rep_bucket_t mc_intf_0 = {
8587 .type = FT_REP_INTF,
8589 .adj = idpo.dpoi_index,
8592 mpls_label_t *l3300 = NULL;
8593 vec_add1(l3300, 3300);
8595 lfe = fib_table_entry_update_one_path(lfib_index,
8598 FIB_ENTRY_FLAG_MULTICAST,
8601 tm->hw[0]->sw_if_index,
8602 ~0, // invalid fib index
8605 FIB_ROUTE_PATH_FLAG_NONE);
8606 FIB_TEST(fib_test_validate_entry(lfe,
8607 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8610 "3500 via replicate over 10.10.10.1");
8613 * MPLS Bud-node. Add a replication via an interface-receieve path
8615 lfe = fib_table_entry_path_add(lfib_index,
8618 FIB_ENTRY_FLAG_MULTICAST,
8621 tm->hw[0]->sw_if_index,
8622 ~0, // invalid fib index
8625 FIB_ROUTE_PATH_INTF_RX);
8626 FIB_TEST(fib_test_validate_entry(lfe,
8627 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8631 "3500 via replicate over 10.10.10.1 and interface-rx");
8634 * Add a replication via an interface-free for-us path
8636 fib_test_rep_bucket_t mc_disp = {
8637 .type = FT_REP_DISP_MFIB_LOOKUP,
8639 .adj = idpo.dpoi_index,
8642 lfe = fib_table_entry_path_add(lfib_index,
8645 FIB_ENTRY_FLAG_MULTICAST,
8652 FIB_ROUTE_PATH_RPF_ID);
8653 FIB_TEST(fib_test_validate_entry(lfe,
8654 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8659 "3500 via replicate over 10.10.10.1 and interface-rx");
8663 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8669 mpls_sw_interface_enable_disable(&mpls_main,
8670 tm->hw[0]->sw_if_index,
8672 mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
8674 FIB_TEST(lb_count == pool_elts(load_balance_pool),
8675 "Load-balance resources freed %d of %d",
8676 lb_count, pool_elts(load_balance_pool));
8677 FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
8678 "interface_rx_dpo resources freed %d of %d",
8679 0, pool_elts(interface_rx_dpo_pool));
8684 static clib_error_t *
8685 fib_test (vlib_main_t * vm,
8686 unformat_input_t * input,
8687 vlib_cli_command_t * cmd_arg)
8692 fib_test_mk_intf(4);
8694 if (unformat (input, "debug"))
8696 fib_test_do_debug = 1;
8699 if (unformat (input, "ip"))
8701 res += fib_test_v4();
8702 res += fib_test_v6();
8704 else if (unformat (input, "label"))
8706 res += fib_test_label();
8708 else if (unformat (input, "ae"))
8710 res += fib_test_ae();
8712 else if (unformat (input, "pref"))
8714 res += fib_test_pref();
8716 else if (unformat (input, "lfib"))
8720 else if (unformat (input, "walk"))
8722 res += fib_test_walk();
8724 else if (unformat (input, "bfd"))
8726 res += fib_test_bfd();
8730 res += fib_test_v4();
8731 res += fib_test_v6();
8732 res += fib_test_ae();
8733 res += fib_test_bfd();
8734 res += fib_test_pref();
8735 res += fib_test_label();
8739 * fib-walk process must be disabled in order for the walk tests to work
8741 fib_walk_process_disable();
8742 res += fib_test_walk();
8743 fib_walk_process_enable();
8748 return clib_error_return(0, "FIB Unit Test Failed");
8756 VLIB_CLI_COMMAND (test_fib_command, static) = {
8758 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8759 .function = fib_test,
8763 fib_test_init (vlib_main_t *vm)
8768 VLIB_INIT_FUNCTION (fib_test_init);