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);
744 for (ii = 0; ii < 4; ii++)
746 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
749 fib_prefix_t pfx_0_0_0_0_s_0 = {
751 .fp_proto = FIB_PROTOCOL_IP4,
761 .fp_proto = FIB_PROTOCOL_IP4,
769 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
771 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
772 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
773 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
774 "Default route is DROP");
777 fei = fib_table_lookup(fib_index, &pfx);
778 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
779 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
780 "all 0s route is DROP");
782 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
784 fei = fib_table_lookup(fib_index, &pfx);
785 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
786 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
787 "all 1s route is DROP");
789 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
791 fei = fib_table_lookup(fib_index, &pfx);
792 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
793 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
794 "all-mcast route is DROP");
796 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
798 fei = fib_table_lookup(fib_index, &pfx);
799 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
800 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
801 "class-e route is DROP");
804 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
805 * all of which are special sourced and so none of which share path-lists.
806 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
807 * table, and 4 path-lists in the v6 MFIB table
811 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
812 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
813 fib_path_list_pool_size());
814 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
815 fib_entry_pool_size());
818 * add interface routes.
819 * validate presence of /24 attached and /32 recieve.
820 * test for the presence of the receive address in the glean and local adj
822 fib_prefix_t local_pfx = {
824 .fp_proto = FIB_PROTOCOL_IP4,
827 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
832 fib_table_entry_update_one_path(fib_index, &local_pfx,
833 FIB_SOURCE_INTERFACE,
834 (FIB_ENTRY_FLAG_CONNECTED |
835 FIB_ENTRY_FLAG_ATTACHED),
838 tm->hw[0]->sw_if_index,
839 ~0, // invalid fib index
842 FIB_ROUTE_PATH_FLAG_NONE);
843 fei = fib_table_lookup(fib_index, &local_pfx);
844 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
845 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
846 fib_entry_get_flags(fei)),
847 "Flags set on attached interface");
849 ai = fib_entry_get_adj(fei);
850 FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
851 "attached interface route adj present %d", ai);
853 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
854 "attached interface adj is glean");
855 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
856 &adj->sub_type.glean.receive_addr)),
857 "attached interface adj is receive ok");
859 local_pfx.fp_len = 32;
860 fib_table_entry_update_one_path(fib_index, &local_pfx,
861 FIB_SOURCE_INTERFACE,
862 (FIB_ENTRY_FLAG_CONNECTED |
863 FIB_ENTRY_FLAG_LOCAL),
866 tm->hw[0]->sw_if_index,
867 ~0, // invalid fib index
870 FIB_ROUTE_PATH_FLAG_NONE);
871 fei = fib_table_lookup(fib_index, &local_pfx);
872 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
873 fib_entry_get_flags(fei)),
874 "Flags set on local interface");
876 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
878 dpo = fib_entry_contribute_ip_forwarding(fei);
879 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
880 "RPF list for local length 0");
881 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
882 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
883 "local interface adj is local");
884 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
886 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
888 "local interface adj is receive ok");
890 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
892 FIB_SOURCE_INTERFACE)),
893 "2 Interface Source'd prefixes");
896 * +2 interface routes +2 non-shared path-lists
898 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
899 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
900 fib_path_list_pool_size());
901 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
902 fib_entry_pool_size());
905 * Modify the default route to be via an adj not yet known.
906 * this sources the defalut route with the API source, which is
907 * a higher preference to the DEFAULT_ROUTE source
909 pfx.fp_addr.ip4.as_u32 = 0;
911 fib_table_entry_path_add(fib_index, &pfx,
916 tm->hw[0]->sw_if_index,
917 ~0, // invalid fib index
920 FIB_ROUTE_PATH_FLAG_NONE);
921 fei = fib_table_lookup(fib_index, &pfx);
922 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
923 "Flags set on API route");
925 FIB_TEST((fei == dfrt), "default route same index");
926 ai = fib_entry_get_adj(fei);
927 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
929 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
930 "adj is incomplete");
931 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
932 "adj nbr next-hop ok");
933 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
936 "1 API Source'd prefixes");
939 * find the adj in the shared db
941 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
944 tm->hw[0]->sw_if_index);
945 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
946 adj_unlock(locked_ai);
949 * +1 shared path-list
951 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
952 fib_path_list_db_size());
953 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
954 fib_path_list_pool_size());
955 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
956 fib_entry_pool_size());
959 * remove the API source from the default route. We expected
960 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
962 pfx.fp_addr.ip4.as_u32 = 0;
964 fib_table_entry_path_remove(fib_index, &pfx,
968 tm->hw[0]->sw_if_index,
969 ~0, // non-recursive path, so no FIB index
971 FIB_ROUTE_PATH_FLAG_NONE);
973 fei = fib_table_lookup(fib_index, &pfx);
975 FIB_TEST((fei == dfrt), "default route same index");
976 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
977 "Default route is DROP");
980 * -1 shared-path-list
982 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
983 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
984 fib_path_list_pool_size());
985 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
986 fib_entry_pool_size());
989 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
991 fib_prefix_t pfx_10_10_10_1_s_32 = {
993 .fp_proto = FIB_PROTOCOL_IP4,
996 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
999 fib_prefix_t pfx_10_10_10_2_s_32 = {
1001 .fp_proto = FIB_PROTOCOL_IP4,
1004 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1007 fib_prefix_t pfx_11_11_11_11_s_32 = {
1009 .fp_proto = FIB_PROTOCOL_IP4,
1012 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1016 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1019 ip46_address_t nh_12_12_12_12 = {
1020 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1022 adj_index_t ai_12_12_12_12;
1025 * Add a route via an incomplete ADJ. then complete the ADJ
1026 * Expect the route LB is updated to use complete adj type.
1028 fei = fib_table_entry_update_one_path(fib_index,
1029 &pfx_11_11_11_11_s_32,
1031 FIB_ENTRY_FLAG_ATTACHED,
1033 &pfx_10_10_10_1_s_32.fp_addr,
1034 tm->hw[0]->sw_if_index,
1035 ~0, // invalid fib index
1038 FIB_ROUTE_PATH_FLAG_NONE);
1040 dpo = fib_entry_contribute_ip_forwarding(fei);
1041 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1042 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1043 "11.11.11.11/32 via incomplete adj");
1045 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1047 &pfx_10_10_10_1_s_32.fp_addr,
1048 tm->hw[0]->sw_if_index);
1049 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1050 adj = adj_get(ai_01);
1051 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1052 "adj is incomplete");
1053 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1054 &adj->sub_type.nbr.next_hop)),
1055 "adj nbr next-hop ok");
1057 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1058 fib_test_build_rewrite(eth_addr));
1059 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1061 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1062 &adj->sub_type.nbr.next_hop)),
1063 "adj nbr next-hop ok");
1064 ai = fib_entry_get_adj(fei);
1065 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1067 dpo = fib_entry_contribute_ip_forwarding(fei);
1068 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1069 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1070 "11.11.11.11/32 via complete adj");
1071 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1072 tm->hw[0]->sw_if_index),
1073 "RPF list for adj-fib contains adj");
1075 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1078 tm->hw[1]->sw_if_index);
1079 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1080 adj = adj_get(ai_12_12_12_12);
1081 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1082 "adj is incomplete");
1083 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1084 &adj->sub_type.nbr.next_hop)),
1085 "adj nbr next-hop ok");
1086 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1087 fib_test_build_rewrite(eth_addr));
1088 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1094 fei = fib_table_entry_path_add(fib_index,
1095 &pfx_10_10_10_1_s_32,
1097 FIB_ENTRY_FLAG_ATTACHED,
1099 &pfx_10_10_10_1_s_32.fp_addr,
1100 tm->hw[0]->sw_if_index,
1101 ~0, // invalid fib index
1104 FIB_ROUTE_PATH_FLAG_NONE);
1105 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1106 "Flags set on adj-fib");
1107 ai = fib_entry_get_adj(fei);
1108 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1110 fib_table_entry_path_remove(fib_index,
1111 &pfx_11_11_11_11_s_32,
1114 &pfx_10_10_10_1_s_32.fp_addr,
1115 tm->hw[0]->sw_if_index,
1116 ~0, // invalid fib index
1118 FIB_ROUTE_PATH_FLAG_NONE);
1122 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1124 &pfx_10_10_10_2_s_32.fp_addr,
1125 tm->hw[0]->sw_if_index);
1126 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1127 adj = adj_get(ai_02);
1128 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1129 "adj is incomplete");
1130 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1131 &adj->sub_type.nbr.next_hop)),
1132 "adj nbr next-hop ok");
1134 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1135 fib_test_build_rewrite(eth_addr));
1136 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1138 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1139 &adj->sub_type.nbr.next_hop)),
1140 "adj nbr next-hop ok");
1141 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1143 fib_table_entry_path_add(fib_index,
1144 &pfx_10_10_10_2_s_32,
1146 FIB_ENTRY_FLAG_ATTACHED,
1148 &pfx_10_10_10_2_s_32.fp_addr,
1149 tm->hw[0]->sw_if_index,
1150 ~0, // invalid fib index
1153 FIB_ROUTE_PATH_FLAG_NONE);
1155 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1156 ai = fib_entry_get_adj(fei);
1157 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1160 * +2 adj-fibs, and their non-shared path-lists
1162 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1163 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1164 fib_path_list_pool_size());
1165 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1166 fib_entry_pool_size());
1169 * Add 2 routes via the first ADJ. ensure path-list sharing
1171 fib_prefix_t pfx_1_1_1_1_s_32 = {
1173 .fp_proto = FIB_PROTOCOL_IP4,
1176 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1180 fib_table_entry_path_add(fib_index,
1183 FIB_ENTRY_FLAG_NONE,
1186 tm->hw[0]->sw_if_index,
1187 ~0, // invalid fib index
1190 FIB_ROUTE_PATH_FLAG_NONE);
1191 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1192 ai = fib_entry_get_adj(fei);
1193 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1196 * +1 entry and a shared path-list
1198 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1199 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1200 fib_path_list_pool_size());
1201 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1202 fib_entry_pool_size());
1205 fib_prefix_t pfx_1_1_2_0_s_24 = {
1207 .fp_proto = FIB_PROTOCOL_IP4,
1209 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1213 fib_table_entry_path_add(fib_index,
1216 FIB_ENTRY_FLAG_NONE,
1219 tm->hw[0]->sw_if_index,
1220 ~0, // invalid fib index
1223 FIB_ROUTE_PATH_FLAG_NONE);
1224 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1225 ai = fib_entry_get_adj(fei);
1226 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1231 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1232 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1233 fib_path_list_pool_size());
1234 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1235 fib_entry_pool_size());
1238 * modify 1.1.2.0/24 to use multipath.
1240 fib_table_entry_path_add(fib_index,
1243 FIB_ENTRY_FLAG_NONE,
1246 tm->hw[0]->sw_if_index,
1247 ~0, // invalid fib index
1250 FIB_ROUTE_PATH_FLAG_NONE);
1251 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1252 dpo = fib_entry_contribute_ip_forwarding(fei);
1253 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1254 1, tm->hw[0]->sw_if_index),
1255 "RPF list for 1.1.2.0/24 contains both adjs");
1257 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1258 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1259 FIB_TEST((ai_01 == dpo1->dpoi_index),
1260 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1261 ai_01, dpo1->dpoi_index);
1263 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1264 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1265 FIB_TEST((ai_02 == dpo1->dpoi_index),
1266 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1269 * +1 shared-pathlist
1271 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1272 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1273 fib_path_list_pool_size());
1274 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1275 fib_entry_pool_size());
1280 fib_table_entry_path_remove(fib_index,
1285 tm->hw[0]->sw_if_index,
1288 FIB_ROUTE_PATH_FLAG_NONE);
1289 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1290 dpo = fib_entry_contribute_ip_forwarding(fei);
1291 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1292 1, tm->hw[0]->sw_if_index),
1293 "RPF list for 1.1.2.0/24 contains one adj");
1295 ai = fib_entry_get_adj(fei);
1296 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1299 * +1 shared-pathlist
1301 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1302 fib_path_list_db_size());
1303 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1304 fib_path_list_pool_size());
1305 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1306 fib_entry_pool_size());
1309 * Add 2 recursive routes:
1310 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1311 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1313 fib_prefix_t bgp_100_pfx = {
1315 .fp_proto = FIB_PROTOCOL_IP4,
1317 /* 100.100.100.100/32 */
1318 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1322 ip46_address_t nh_1_1_1_1 = {
1323 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1326 fei = fib_table_entry_path_add(fib_index,
1329 FIB_ENTRY_FLAG_NONE,
1332 ~0, // no index provided.
1333 fib_index, // nexthop in same fib as route
1336 FIB_ROUTE_PATH_FLAG_NONE);
1338 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1339 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1340 tm->hw[0]->sw_if_index),
1341 "RPF list for adj-fib contains adj");
1344 * +1 entry and +1 shared-path-list
1346 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1347 fib_path_list_db_size());
1348 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1349 fib_path_list_pool_size());
1350 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1351 fib_entry_pool_size());
1353 fib_prefix_t bgp_101_pfx = {
1355 .fp_proto = FIB_PROTOCOL_IP4,
1357 /* 100.100.100.101/32 */
1358 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1362 fib_table_entry_path_add(fib_index,
1365 FIB_ENTRY_FLAG_NONE,
1368 ~0, // no index provided.
1369 fib_index, // nexthop in same fib as route
1372 FIB_ROUTE_PATH_FLAG_NONE);
1374 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1375 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1376 tm->hw[0]->sw_if_index),
1377 "RPF list for adj-fib contains adj");
1380 * +1 entry, but the recursive path-list is shared.
1382 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1383 fib_path_list_db_size());
1384 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1385 fib_path_list_pool_size());
1386 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1387 fib_entry_pool_size());
1390 * An special route; one where the user (me) provides the
1391 * adjacency through which the route will resovle by setting the flags
1393 fib_prefix_t ex_pfx = {
1395 .fp_proto = FIB_PROTOCOL_IP4,
1398 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1402 fib_table_entry_special_add(fib_index,
1405 FIB_ENTRY_FLAG_LOCAL);
1406 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1407 dpo = fib_entry_contribute_ip_forwarding(fei);
1408 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1409 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1410 "local interface adj is local");
1412 fib_table_entry_special_remove(fib_index,
1414 FIB_SOURCE_SPECIAL);
1415 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1416 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1417 "Exclusive reoute removed");
1420 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1421 * adjacency through which the route will resovle
1423 dpo_id_t ex_dpo = DPO_INVALID;
1425 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1428 LOOKUP_INPUT_DST_ADDR,
1429 LOOKUP_TABLE_FROM_CONFIG,
1432 fib_table_entry_special_dpo_add(fib_index,
1435 FIB_ENTRY_FLAG_EXCLUSIVE,
1437 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1438 dpo = fib_entry_contribute_ip_forwarding(fei);
1439 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1440 "exclusive remote uses lookup DPO");
1443 * update the exclusive to use a different DPO
1445 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1446 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1448 fib_table_entry_special_dpo_update(fib_index,
1451 FIB_ENTRY_FLAG_EXCLUSIVE,
1453 dpo = fib_entry_contribute_ip_forwarding(fei);
1454 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1455 "exclusive remote uses now uses NULL DPO");
1457 fib_table_entry_special_remove(fib_index,
1459 FIB_SOURCE_SPECIAL);
1460 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1461 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1462 "Exclusive reoute removed");
1466 * Add a recursive route:
1467 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1469 fib_prefix_t bgp_200_pfx = {
1471 .fp_proto = FIB_PROTOCOL_IP4,
1473 /* 200.200.200.200/32 */
1474 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1478 fib_prefix_t pfx_1_1_1_2_s_32 = {
1480 .fp_proto = FIB_PROTOCOL_IP4,
1482 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1486 fei = fib_table_entry_path_add(fib_index,
1489 FIB_ENTRY_FLAG_NONE,
1491 &pfx_1_1_1_2_s_32.fp_addr,
1492 ~0, // no index provided.
1493 fib_index, // nexthop in same fib as route
1496 FIB_ROUTE_PATH_FLAG_NONE);
1498 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1499 "Recursive via unresolved is drop");
1502 * the adj should be recursive via drop, since the route resolves via
1503 * the default route, which is itself a DROP
1505 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1506 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1507 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1508 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1509 "RPF list for 1.1.1.2/32 contains 0 adjs");
1512 * +2 entry and +1 shared-path-list
1514 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1515 fib_path_list_db_size());
1516 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1517 fib_path_list_pool_size());
1518 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1519 fib_entry_pool_size());
1522 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1523 * The paths are sort by NH first. in this case the the path with greater
1524 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1526 fib_prefix_t pfx_1_2_3_4_s_32 = {
1528 .fp_proto = FIB_PROTOCOL_IP4,
1530 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1533 fib_table_entry_path_add(fib_index,
1536 FIB_ENTRY_FLAG_NONE,
1539 tm->hw[0]->sw_if_index,
1543 FIB_ROUTE_PATH_FLAG_NONE);
1544 fei = fib_table_entry_path_add(fib_index,
1547 FIB_ENTRY_FLAG_NONE,
1550 tm->hw[1]->sw_if_index,
1554 FIB_ROUTE_PATH_FLAG_NONE);
1556 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1557 dpo = fib_entry_contribute_ip_forwarding(fei);
1558 lb = load_balance_get(dpo->dpoi_index);
1559 FIB_TEST((lb->lb_n_buckets == 4),
1560 "1.2.3.4/32 LB has %d bucket",
1563 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1564 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1565 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1566 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1568 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1569 tm->hw[0]->sw_if_index,
1570 tm->hw[1]->sw_if_index),
1571 "RPF list for 1.2.3.4/32 contains both adjs");
1575 * Unequal Cost load-balance. 4:1 ratio.
1576 * fits in a 16 bucket LB with ratio 13:3
1578 fib_prefix_t pfx_1_2_3_5_s_32 = {
1580 .fp_proto = FIB_PROTOCOL_IP4,
1582 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1585 fib_table_entry_path_add(fib_index,
1588 FIB_ENTRY_FLAG_NONE,
1591 tm->hw[1]->sw_if_index,
1595 FIB_ROUTE_PATH_FLAG_NONE);
1596 fei = fib_table_entry_path_add(fib_index,
1599 FIB_ENTRY_FLAG_NONE,
1602 tm->hw[0]->sw_if_index,
1606 FIB_ROUTE_PATH_FLAG_NONE);
1608 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1609 dpo = fib_entry_contribute_ip_forwarding(fei);
1610 lb = load_balance_get(dpo->dpoi_index);
1611 FIB_TEST((lb->lb_n_buckets == 16),
1612 "1.2.3.5/32 LB has %d bucket",
1615 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1616 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1617 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1618 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1619 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1620 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1621 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1622 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1623 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1624 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1625 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1626 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1627 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1628 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1629 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1630 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1632 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1633 tm->hw[0]->sw_if_index,
1634 tm->hw[1]->sw_if_index),
1635 "RPF list for 1.2.3.4/32 contains both adjs");
1638 * Test UCMP with a large weight skew - this produces load-balance objects with large
1639 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1640 * laso testing the LB in placce modify code when number of buckets is large.
1642 fib_prefix_t pfx_6_6_6_6_s_32 = {
1644 .fp_proto = FIB_PROTOCOL_IP4,
1647 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1650 fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1656 fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1662 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1665 .adj = ai_12_12_12_12,
1668 fib_table_entry_update_one_path(fib_index,
1671 FIB_ENTRY_FLAG_NONE,
1674 tm->hw[0]->sw_if_index,
1675 ~0, // invalid fib index
1678 FIB_ROUTE_PATH_FLAG_NONE);
1680 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1681 FIB_TEST(fib_test_validate_entry(fei,
1682 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1685 "6.6.6.6/32 via 10.10.10.1");
1687 fib_table_entry_path_add(fib_index,
1690 FIB_ENTRY_FLAG_NONE,
1693 tm->hw[0]->sw_if_index,
1694 ~0, // invalid fib index
1697 FIB_ROUTE_PATH_FLAG_NONE);
1699 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1700 FIB_TEST(fib_test_validate_entry(fei,
1701 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1767 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1769 fib_table_entry_path_add(fib_index,
1772 FIB_ENTRY_FLAG_NONE,
1775 tm->hw[1]->sw_if_index,
1776 ~0, // invalid fib index
1779 FIB_ROUTE_PATH_FLAG_NONE);
1781 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1782 FIB_TEST(fib_test_validate_entry(fei,
1783 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1850 &ip_6_6_6_6_o_12_12_12_12,
1851 &ip_6_6_6_6_o_12_12_12_12,
1852 &ip_6_6_6_6_o_12_12_12_12,
1853 &ip_6_6_6_6_o_12_12_12_12,
1854 &ip_6_6_6_6_o_12_12_12_12,
1855 &ip_6_6_6_6_o_12_12_12_12,
1856 &ip_6_6_6_6_o_12_12_12_12,
1857 &ip_6_6_6_6_o_12_12_12_12,
1858 &ip_6_6_6_6_o_12_12_12_12,
1859 &ip_6_6_6_6_o_12_12_12_12,
1860 &ip_6_6_6_6_o_12_12_12_12,
1861 &ip_6_6_6_6_o_12_12_12_12,
1862 &ip_6_6_6_6_o_12_12_12_12,
1863 &ip_6_6_6_6_o_12_12_12_12,
1864 &ip_6_6_6_6_o_12_12_12_12,
1865 &ip_6_6_6_6_o_12_12_12_12,
1866 &ip_6_6_6_6_o_12_12_12_12,
1867 &ip_6_6_6_6_o_12_12_12_12,
1868 &ip_6_6_6_6_o_12_12_12_12,
1869 &ip_6_6_6_6_o_12_12_12_12,
1870 &ip_6_6_6_6_o_12_12_12_12,
1871 &ip_6_6_6_6_o_12_12_12_12,
1872 &ip_6_6_6_6_o_12_12_12_12,
1873 &ip_6_6_6_6_o_12_12_12_12,
1874 &ip_6_6_6_6_o_12_12_12_12,
1875 &ip_6_6_6_6_o_12_12_12_12,
1876 &ip_6_6_6_6_o_12_12_12_12,
1877 &ip_6_6_6_6_o_12_12_12_12,
1878 &ip_6_6_6_6_o_12_12_12_12,
1879 &ip_6_6_6_6_o_12_12_12_12,
1880 &ip_6_6_6_6_o_12_12_12_12,
1881 &ip_6_6_6_6_o_12_12_12_12,
1882 &ip_6_6_6_6_o_12_12_12_12,
1883 &ip_6_6_6_6_o_12_12_12_12,
1884 &ip_6_6_6_6_o_12_12_12_12,
1885 &ip_6_6_6_6_o_12_12_12_12,
1886 &ip_6_6_6_6_o_12_12_12_12,
1887 &ip_6_6_6_6_o_12_12_12_12,
1888 &ip_6_6_6_6_o_12_12_12_12,
1889 &ip_6_6_6_6_o_12_12_12_12,
1890 &ip_6_6_6_6_o_12_12_12_12,
1891 &ip_6_6_6_6_o_12_12_12_12,
1892 &ip_6_6_6_6_o_12_12_12_12,
1893 &ip_6_6_6_6_o_12_12_12_12,
1894 &ip_6_6_6_6_o_12_12_12_12,
1895 &ip_6_6_6_6_o_12_12_12_12,
1896 &ip_6_6_6_6_o_12_12_12_12,
1897 &ip_6_6_6_6_o_12_12_12_12,
1898 &ip_6_6_6_6_o_12_12_12_12,
1899 &ip_6_6_6_6_o_12_12_12_12,
1900 &ip_6_6_6_6_o_12_12_12_12,
1901 &ip_6_6_6_6_o_12_12_12_12,
1902 &ip_6_6_6_6_o_12_12_12_12,
1903 &ip_6_6_6_6_o_12_12_12_12,
1904 &ip_6_6_6_6_o_12_12_12_12,
1905 &ip_6_6_6_6_o_12_12_12_12,
1906 &ip_6_6_6_6_o_12_12_12_12,
1907 &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 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1915 fib_table_entry_path_remove(fib_index,
1920 tm->hw[1]->sw_if_index,
1921 ~0, // invalid fib index
1923 FIB_ROUTE_PATH_FLAG_NONE);
1925 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1926 FIB_TEST(fib_test_validate_entry(fei,
1927 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1993 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1995 fib_table_entry_path_remove(fib_index,
2000 tm->hw[0]->sw_if_index,
2001 ~0, // invalid fib index
2003 FIB_ROUTE_PATH_FLAG_NONE);
2005 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2006 FIB_TEST(fib_test_validate_entry(fei,
2007 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2010 "6.6.6.6/32 via 10.10.10.1");
2012 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2015 * A recursive via the two unequal cost entries
2017 fib_prefix_t bgp_44_s_32 = {
2019 .fp_proto = FIB_PROTOCOL_IP4,
2021 /* 200.200.200.201/32 */
2022 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2025 fei = fib_table_entry_path_add(fib_index,
2028 FIB_ENTRY_FLAG_NONE,
2030 &pfx_1_2_3_4_s_32.fp_addr,
2035 FIB_ROUTE_PATH_FLAG_NONE);
2036 fei = fib_table_entry_path_add(fib_index,
2039 FIB_ENTRY_FLAG_NONE,
2041 &pfx_1_2_3_5_s_32.fp_addr,
2046 FIB_ROUTE_PATH_FLAG_NONE);
2048 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2049 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2050 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2051 tm->hw[0]->sw_if_index,
2052 tm->hw[1]->sw_if_index),
2053 "RPF list for 1.2.3.4/32 contains both adjs");
2056 * test the uRPF check functions
2058 dpo_id_t dpo_44 = DPO_INVALID;
2061 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2062 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2064 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2065 "uRPF check for 68.68.68.68/32 on %d OK",
2066 tm->hw[0]->sw_if_index);
2067 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2068 "uRPF check for 68.68.68.68/32 on %d OK",
2069 tm->hw[1]->sw_if_index);
2070 FIB_TEST(!fib_urpf_check(urpfi, 99),
2071 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2075 fib_table_entry_delete(fib_index,
2078 fib_table_entry_delete(fib_index,
2081 fib_table_entry_delete(fib_index,
2086 * Add a recursive route:
2087 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2089 fib_prefix_t bgp_201_pfx = {
2091 .fp_proto = FIB_PROTOCOL_IP4,
2093 /* 200.200.200.201/32 */
2094 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2098 fib_prefix_t pfx_1_1_1_200_s_32 = {
2100 .fp_proto = FIB_PROTOCOL_IP4,
2102 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2106 fei = fib_table_entry_path_add(fib_index,
2109 FIB_ENTRY_FLAG_NONE,
2111 &pfx_1_1_1_200_s_32.fp_addr,
2112 ~0, // no index provided.
2113 fib_index, // nexthop in same fib as route
2116 FIB_ROUTE_PATH_FLAG_NONE);
2118 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2119 "Recursive via unresolved is drop");
2121 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2122 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2123 "Flags set on RR via non-attached");
2124 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2125 "RPF list for BGP route empty");
2128 * +2 entry (BGP & RR) and +1 shared-path-list
2130 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2131 fib_path_list_db_size());
2132 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2133 fib_path_list_pool_size());
2134 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2135 fib_entry_pool_size());
2138 * insert a route that covers the missing 1.1.1.2/32. we epxect
2139 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2141 fib_prefix_t pfx_1_1_1_0_s_24 = {
2143 .fp_proto = FIB_PROTOCOL_IP4,
2146 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2150 fib_table_entry_path_add(fib_index,
2153 FIB_ENTRY_FLAG_NONE,
2156 tm->hw[0]->sw_if_index,
2157 ~0, // invalid fib index
2160 FIB_ROUTE_PATH_FLAG_NONE);
2161 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2162 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2163 ai = fib_entry_get_adj(fei);
2164 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2165 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2166 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2167 ai = fib_entry_get_adj(fei);
2168 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2169 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2170 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2171 ai = fib_entry_get_adj(fei);
2172 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2175 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2177 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2178 fib_path_list_db_size());
2179 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2180 fib_path_list_pool_size());
2181 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2182 fib_entry_pool_size());
2185 * the recursive adj for 200.200.200.200 should be updated.
2187 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2188 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2189 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2190 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2191 tm->hw[0]->sw_if_index),
2192 "RPF list for BGP route has itf index 0");
2195 * insert a more specific route than 1.1.1.0/24 that also covers the
2196 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2197 * 200.200.200.200 to resolve through it.
2199 fib_prefix_t pfx_1_1_1_0_s_28 = {
2201 .fp_proto = FIB_PROTOCOL_IP4,
2204 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2208 fib_table_entry_path_add(fib_index,
2211 FIB_ENTRY_FLAG_NONE,
2214 tm->hw[0]->sw_if_index,
2215 ~0, // invalid fib index
2218 FIB_ROUTE_PATH_FLAG_NONE);
2219 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2220 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2221 ai = fib_entry_get_adj(fei);
2222 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2225 * +1 entry. +1 shared path-list
2227 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2228 fib_path_list_db_size());
2229 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2230 fib_path_list_pool_size());
2231 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2232 fib_entry_pool_size());
2235 * the recursive adj for 200.200.200.200 should be updated.
2236 * 200.200.200.201 remains unchanged.
2238 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2239 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2242 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2244 fib_table_entry_path_remove(fib_index,
2249 tm->hw[0]->sw_if_index,
2252 FIB_ROUTE_PATH_FLAG_NONE);
2253 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2254 FIB_NODE_INDEX_INVALID),
2255 "1.1.1.0/28 removed");
2256 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2257 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2258 "1.1.1.0/28 lookup via /24");
2259 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2260 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2263 * -1 entry. -1 shared path-list
2265 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2266 fib_path_list_db_size());
2267 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2268 fib_path_list_pool_size());
2269 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2270 fib_entry_pool_size());
2273 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2275 fib_table_entry_path_remove(fib_index,
2280 tm->hw[0]->sw_if_index,
2283 FIB_ROUTE_PATH_FLAG_NONE);
2284 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2285 FIB_NODE_INDEX_INVALID),
2286 "1.1.1.0/24 removed");
2288 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2289 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2290 "1.1.1.2/32 route is DROP");
2291 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2292 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2293 "1.1.1.200/32 route is DROP");
2295 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2296 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2298 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2299 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2305 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2306 fib_path_list_db_size());
2307 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2308 fib_path_list_pool_size());
2309 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2310 fib_entry_pool_size());
2313 * insert the missing 1.1.1.2/32
2315 fei = fib_table_entry_path_add(fib_index,
2318 FIB_ENTRY_FLAG_NONE,
2321 tm->hw[0]->sw_if_index,
2322 ~0, // invalid fib index
2325 FIB_ROUTE_PATH_FLAG_NONE);
2326 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2327 ai = fib_entry_get_adj(fei);
2328 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2330 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2331 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2333 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2336 * no change. 1.1.1.2/32 was already there RR sourced.
2338 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2339 fib_path_list_db_size());
2340 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2341 fib_path_list_pool_size());
2342 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2343 fib_entry_pool_size());
2346 * give 201 a resolved path.
2347 * it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
2348 * only the latter contributes forwarding.
2350 fei = fib_table_entry_path_add(fib_index,
2353 FIB_ENTRY_FLAG_NONE,
2355 &pfx_1_1_1_2_s_32.fp_addr,
2360 FIB_ROUTE_PATH_FLAG_NONE);
2361 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
2362 fib_table_entry_path_remove(fib_index,
2366 &pfx_1_1_1_2_s_32.fp_addr,
2370 FIB_ROUTE_PATH_FLAG_NONE);
2373 * remove 200.200.200.201/32 which does not have a valid via FIB
2375 fib_table_entry_path_remove(fib_index,
2379 &pfx_1_1_1_200_s_32.fp_addr,
2380 ~0, // no index provided.
2383 FIB_ROUTE_PATH_FLAG_NONE);
2386 * -2 entries (BGP and RR). -1 shared path-list;
2388 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2389 FIB_NODE_INDEX_INVALID),
2390 "200.200.200.201/32 removed");
2391 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2392 FIB_NODE_INDEX_INVALID),
2393 "1.1.1.200/32 removed");
2395 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2396 fib_path_list_db_size());
2397 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2398 fib_path_list_pool_size());
2399 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2400 fib_entry_pool_size());
2403 * remove 200.200.200.200/32 which does have a valid via FIB
2405 fib_table_entry_path_remove(fib_index,
2409 &pfx_1_1_1_2_s_32.fp_addr,
2410 ~0, // no index provided.
2413 FIB_ROUTE_PATH_FLAG_NONE);
2415 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2416 FIB_NODE_INDEX_INVALID),
2417 "200.200.200.200/32 removed");
2418 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2419 FIB_NODE_INDEX_INVALID),
2420 "1.1.1.2/32 still present");
2423 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2425 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2426 fib_path_list_db_size());
2427 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2428 fib_path_list_pool_size());
2429 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2430 fib_entry_pool_size());
2433 * A recursive prefix that has a 2 path load-balance.
2434 * It also shares a next-hop with other BGP prefixes and hence
2435 * test the ref counting of RR sourced prefixes and 2 level LB.
2437 const fib_prefix_t bgp_102 = {
2439 .fp_proto = FIB_PROTOCOL_IP4,
2441 /* 100.100.100.101/32 */
2442 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2445 fib_table_entry_path_add(fib_index,
2448 FIB_ENTRY_FLAG_NONE,
2450 &pfx_1_1_1_1_s_32.fp_addr,
2451 ~0, // no index provided.
2452 fib_index, // same as route
2455 FIB_ROUTE_PATH_FLAG_NONE);
2456 fib_table_entry_path_add(fib_index,
2459 FIB_ENTRY_FLAG_NONE,
2461 &pfx_1_1_1_2_s_32.fp_addr,
2462 ~0, // no index provided.
2463 fib_index, // same as route's FIB
2466 FIB_ROUTE_PATH_FLAG_NONE);
2467 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2468 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2469 dpo = fib_entry_contribute_ip_forwarding(fei);
2471 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2472 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2473 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2474 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2476 lb = load_balance_get(dpo->dpoi_index);
2477 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2478 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2479 "First via 10.10.10.1");
2480 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2481 "Second via 10.10.10.1");
2483 fib_table_entry_path_remove(fib_index,
2487 &pfx_1_1_1_1_s_32.fp_addr,
2488 ~0, // no index provided.
2489 fib_index, // same as route's FIB
2491 FIB_ROUTE_PATH_FLAG_NONE);
2492 fib_table_entry_path_remove(fib_index,
2496 &pfx_1_1_1_2_s_32.fp_addr,
2497 ~0, // no index provided.
2498 fib_index, // same as route's FIB
2500 FIB_ROUTE_PATH_FLAG_NONE);
2501 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2502 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2505 * remove the remaining recursives
2507 fib_table_entry_path_remove(fib_index,
2511 &pfx_1_1_1_1_s_32.fp_addr,
2512 ~0, // no index provided.
2513 fib_index, // same as route's FIB
2515 FIB_ROUTE_PATH_FLAG_NONE);
2516 fib_table_entry_path_remove(fib_index,
2520 &pfx_1_1_1_1_s_32.fp_addr,
2521 ~0, // no index provided.
2522 fib_index, // same as route's FIB
2524 FIB_ROUTE_PATH_FLAG_NONE);
2525 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2526 FIB_NODE_INDEX_INVALID),
2527 "100.100.100.100/32 removed");
2528 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2529 FIB_NODE_INDEX_INVALID),
2530 "100.100.100.101/32 removed");
2533 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2535 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2536 fib_path_list_db_size());
2537 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2538 fib_path_list_pool_size());
2539 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2540 fib_entry_pool_size());
2543 * Add a recursive route via a connected cover, using an adj-fib that does exist
2545 fib_table_entry_path_add(fib_index,
2548 FIB_ENTRY_FLAG_NONE,
2551 ~0, // no index provided.
2552 fib_index, // Same as route's FIB
2555 FIB_ROUTE_PATH_FLAG_NONE);
2558 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2560 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2561 fib_path_list_db_size());
2562 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2563 fib_path_list_pool_size());
2564 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2565 fib_entry_pool_size());
2567 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2568 dpo = fib_entry_contribute_ip_forwarding(fei);
2570 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2571 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2573 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2574 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2576 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2577 "Flags set on RR via existing attached");
2580 * Add a recursive route via a connected cover, using and adj-fib that does
2583 ip46_address_t nh_10_10_10_3 = {
2584 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2586 fib_prefix_t pfx_10_10_10_3 = {
2588 .fp_proto = FIB_PROTOCOL_IP4,
2589 .fp_addr = nh_10_10_10_3,
2592 fib_table_entry_path_add(fib_index,
2595 FIB_ENTRY_FLAG_NONE,
2598 ~0, // no index provided.
2602 FIB_ROUTE_PATH_FLAG_NONE);
2605 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2606 * one unshared non-recursive via 10.10.10.3
2608 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2609 fib_path_list_db_size());
2610 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2611 fib_path_list_pool_size());
2612 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2613 fib_entry_pool_size());
2615 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2618 tm->hw[0]->sw_if_index);
2620 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2621 dpo = fib_entry_contribute_ip_forwarding(fei);
2622 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2623 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2625 ai = fib_entry_get_adj(fei);
2626 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2627 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2628 fib_entry_get_flags(fei)),
2629 "Flags set on RR via non-existing attached");
2631 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2632 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2637 * remove the recursives
2639 fib_table_entry_path_remove(fib_index,
2644 ~0, // no index provided.
2645 fib_index, // same as route's FIB
2647 FIB_ROUTE_PATH_FLAG_NONE);
2648 fib_table_entry_path_remove(fib_index,
2653 ~0, // no index provided.
2654 fib_index, // same as route's FIB
2656 FIB_ROUTE_PATH_FLAG_NONE);
2658 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2659 FIB_NODE_INDEX_INVALID),
2660 "200.200.200.201/32 removed");
2661 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2662 FIB_NODE_INDEX_INVALID),
2663 "200.200.200.200/32 removed");
2664 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2665 FIB_NODE_INDEX_INVALID),
2666 "10.10.10.3/32 removed");
2669 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2670 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2672 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2673 fib_path_list_db_size());
2674 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2675 fib_path_list_pool_size());
2676 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2677 fib_entry_pool_size());
2682 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2684 fib_prefix_t pfx_5_5_5_5_s_32 = {
2686 .fp_proto = FIB_PROTOCOL_IP4,
2688 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2691 fib_prefix_t pfx_5_5_5_6_s_32 = {
2693 .fp_proto = FIB_PROTOCOL_IP4,
2695 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2698 fib_prefix_t pfx_5_5_5_7_s_32 = {
2700 .fp_proto = FIB_PROTOCOL_IP4,
2702 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2706 fib_table_entry_path_add(fib_index,
2709 FIB_ENTRY_FLAG_NONE,
2711 &pfx_5_5_5_6_s_32.fp_addr,
2712 ~0, // no index provided.
2716 FIB_ROUTE_PATH_FLAG_NONE);
2717 fib_table_entry_path_add(fib_index,
2720 FIB_ENTRY_FLAG_NONE,
2722 &pfx_5_5_5_7_s_32.fp_addr,
2723 ~0, // no index provided.
2727 FIB_ROUTE_PATH_FLAG_NONE);
2728 fib_table_entry_path_add(fib_index,
2731 FIB_ENTRY_FLAG_NONE,
2733 &pfx_5_5_5_5_s_32.fp_addr,
2734 ~0, // no index provided.
2738 FIB_ROUTE_PATH_FLAG_NONE);
2740 * +3 entries, +3 shared path-list
2742 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2743 fib_path_list_db_size());
2744 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2745 fib_path_list_pool_size());
2746 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2747 fib_entry_pool_size());
2750 * All the entries have only looped paths, so they are all drop
2752 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2753 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2754 "LB for 5.5.5.7/32 is via adj for DROP");
2755 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2756 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2757 "LB for 5.5.5.5/32 is via adj for DROP");
2758 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2759 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2760 "LB for 5.5.5.6/32 is via adj for DROP");
2763 * provide 5.5.5.6/32 with alternate path.
2764 * this will allow only 5.5.5.6/32 to forward with this path, the others
2765 * are still drop since the loop is still present.
2767 fib_table_entry_path_add(fib_index,
2770 FIB_ENTRY_FLAG_NONE,
2773 tm->hw[0]->sw_if_index,
2777 FIB_ROUTE_PATH_FLAG_NONE);
2779 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2780 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2782 lb = load_balance_get(dpo1->dpoi_index);
2783 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2785 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2786 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2787 FIB_TEST((ai_01 == dpo2->dpoi_index),
2788 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2790 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2791 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2792 "LB for 5.5.5.7/32 is via adj for DROP");
2793 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2794 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2795 "LB for 5.5.5.5/32 is via adj for DROP");
2798 * remove the alternate path for 5.5.5.6/32
2801 fib_table_entry_path_remove(fib_index,
2806 tm->hw[0]->sw_if_index,
2809 FIB_ROUTE_PATH_FLAG_NONE);
2811 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2812 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2813 "LB for 5.5.5.7/32 is via adj for DROP");
2814 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2815 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2816 "LB for 5.5.5.5/32 is via adj for DROP");
2817 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2818 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2819 "LB for 5.5.5.6/32 is via adj for DROP");
2822 * break the loop by giving 5.5.5.5/32 a new set of paths
2823 * expect all to forward via this new path.
2825 fib_table_entry_update_one_path(fib_index,
2828 FIB_ENTRY_FLAG_NONE,
2831 tm->hw[0]->sw_if_index,
2832 ~0, // invalid fib index
2835 FIB_ROUTE_PATH_FLAG_NONE);
2837 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2838 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2839 lb = load_balance_get(dpo1->dpoi_index);
2840 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2842 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2843 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2844 FIB_TEST((ai_01 == dpo2->dpoi_index),
2845 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2847 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2848 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2850 lb = load_balance_get(dpo2->dpoi_index);
2851 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2852 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2853 "5.5.5.5.7 via 5.5.5.5");
2855 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2856 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2858 lb = load_balance_get(dpo1->dpoi_index);
2859 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2860 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2861 "5.5.5.5.6 via 5.5.5.7");
2864 * revert back to the loop. so we can remove the prefixes with
2867 fib_table_entry_update_one_path(fib_index,
2870 FIB_ENTRY_FLAG_NONE,
2872 &pfx_5_5_5_6_s_32.fp_addr,
2873 ~0, // no index provided.
2877 FIB_ROUTE_PATH_FLAG_NONE);
2879 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2880 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2881 "LB for 5.5.5.7/32 is via adj for DROP");
2882 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2883 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2884 "LB for 5.5.5.5/32 is via adj for DROP");
2885 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2886 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2887 "LB for 5.5.5.6/32 is via adj for DROP");
2890 * remove all the 5.5.5.x/32 prefixes
2892 fib_table_entry_path_remove(fib_index,
2896 &pfx_5_5_5_6_s_32.fp_addr,
2897 ~0, // no index provided.
2898 fib_index, // same as route's FIB
2900 FIB_ROUTE_PATH_FLAG_NONE);
2901 fib_table_entry_path_remove(fib_index,
2905 &pfx_5_5_5_7_s_32.fp_addr,
2906 ~0, // no index provided.
2907 fib_index, // same as route's FIB
2909 FIB_ROUTE_PATH_FLAG_NONE);
2910 fib_table_entry_path_remove(fib_index,
2914 &pfx_5_5_5_5_s_32.fp_addr,
2915 ~0, // no index provided.
2916 fib_index, // same as route's FIB
2918 FIB_ROUTE_PATH_FLAG_NONE);
2919 fib_table_entry_path_remove(fib_index,
2924 ~0, // no index provided.
2925 fib_index, // same as route's FIB
2927 FIB_ROUTE_PATH_FLAG_NONE);
2930 * -3 entries, -3 shared path-list
2932 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2933 fib_path_list_db_size());
2934 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2935 fib_path_list_pool_size());
2936 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2937 fib_entry_pool_size());
2940 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2942 fib_table_entry_path_add(fib_index,
2945 FIB_ENTRY_FLAG_NONE,
2947 &pfx_5_5_5_6_s_32.fp_addr,
2948 ~0, // no index provided.
2952 FIB_ROUTE_PATH_FLAG_NONE);
2953 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2954 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2955 "1-level 5.5.5.6/32 loop is via adj for DROP");
2957 fib_table_entry_path_remove(fib_index,
2961 &pfx_5_5_5_6_s_32.fp_addr,
2962 ~0, // no index provided.
2963 fib_index, // same as route's FIB
2965 FIB_ROUTE_PATH_FLAG_NONE);
2966 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2967 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2968 "1-level 5.5.5.6/32 loop is removed");
2971 * A recursive route whose next-hop is covered by the prefix.
2972 * This would mean the via-fib, which inherits forwarding from its
2973 * cover, thus picks up forwarding from the prfix, which is via the
2974 * via-fib, and we have a loop.
2976 fib_prefix_t pfx_23_23_23_0_s_24 = {
2978 .fp_proto = FIB_PROTOCOL_IP4,
2980 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2983 fib_prefix_t pfx_23_23_23_23_s_32 = {
2985 .fp_proto = FIB_PROTOCOL_IP4,
2987 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2990 fei = fib_table_entry_path_add(fib_index,
2991 &pfx_23_23_23_0_s_24,
2993 FIB_ENTRY_FLAG_NONE,
2995 &pfx_23_23_23_23_s_32.fp_addr,
3000 FIB_ROUTE_PATH_FLAG_NONE);
3001 dpo = fib_entry_contribute_ip_forwarding(fei);
3002 FIB_TEST(load_balance_is_drop(dpo),
3003 "23.23.23.0/24 via covered is DROP");
3004 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3007 * add-remove test. no change.
3009 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3010 fib_path_list_db_size());
3011 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3012 fib_path_list_pool_size());
3013 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3014 fib_entry_pool_size());
3017 * Make the default route recursive via a unknown next-hop. Thus the
3018 * next hop's cover would be the default route
3020 fei = fib_table_entry_path_add(fib_index,
3023 FIB_ENTRY_FLAG_NONE,
3025 &pfx_23_23_23_23_s_32.fp_addr,
3030 FIB_ROUTE_PATH_FLAG_NONE);
3031 dpo = fib_entry_contribute_ip_forwarding(fei);
3032 FIB_TEST(load_balance_is_drop(dpo),
3033 "0.0.0.0.0/0 via is DROP");
3034 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3035 "no resolving interface for looped 0.0.0.0/0");
3037 fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3038 dpo = fib_entry_contribute_ip_forwarding(fei);
3039 FIB_TEST(load_balance_is_drop(dpo),
3040 "23.23.23.23/32 via is DROP");
3041 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3042 "no resolving interface for looped 23.23.23.23/32");
3044 fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3047 * A recursive route with recursion constraints.
3048 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3050 fib_table_entry_path_add(fib_index,
3053 FIB_ENTRY_FLAG_NONE,
3060 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3062 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3063 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3065 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3066 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3068 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3069 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3072 * save the load-balance. we expect it to be inplace modified
3074 lb = load_balance_get(dpo1->dpoi_index);
3077 * add a covering prefix for the via fib that would otherwise serve
3078 * as the resolving route when the host is removed
3080 fib_table_entry_path_add(fib_index,
3083 FIB_ENTRY_FLAG_NONE,
3086 tm->hw[0]->sw_if_index,
3087 ~0, // invalid fib index
3090 FIB_ROUTE_PATH_FLAG_NONE);
3091 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3092 ai = fib_entry_get_adj(fei);
3093 FIB_TEST((ai == ai_01),
3094 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3097 * remove the host via FIB - expect the BGP prefix to be drop
3099 fib_table_entry_path_remove(fib_index,
3104 tm->hw[0]->sw_if_index,
3105 ~0, // invalid fib index
3107 FIB_ROUTE_PATH_FLAG_NONE);
3109 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3110 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3113 * add the via-entry host reoute back. expect to resolve again
3115 fib_table_entry_path_add(fib_index,
3118 FIB_ENTRY_FLAG_NONE,
3121 tm->hw[0]->sw_if_index,
3122 ~0, // invalid fib index
3125 FIB_ROUTE_PATH_FLAG_NONE);
3126 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3127 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3130 * add another path for the recursive. it will then have 2.
3132 fib_prefix_t pfx_1_1_1_3_s_32 = {
3134 .fp_proto = FIB_PROTOCOL_IP4,
3136 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3139 fib_table_entry_path_add(fib_index,
3142 FIB_ENTRY_FLAG_NONE,
3145 tm->hw[0]->sw_if_index,
3146 ~0, // invalid fib index
3149 FIB_ROUTE_PATH_FLAG_NONE);
3151 fib_table_entry_path_add(fib_index,
3154 FIB_ENTRY_FLAG_NONE,
3156 &pfx_1_1_1_3_s_32.fp_addr,
3161 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3164 * add a bunch load more entries using this path combo so that we get
3165 * an LB-map created.
3168 fib_prefix_t bgp_78s[N_P];
3169 for (ii = 0; ii < N_P; ii++)
3171 bgp_78s[ii].fp_len = 32;
3172 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3173 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3176 fib_table_entry_path_add(fib_index,
3179 FIB_ENTRY_FLAG_NONE,
3181 &pfx_1_1_1_3_s_32.fp_addr,
3186 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3187 fib_table_entry_path_add(fib_index,
3190 FIB_ENTRY_FLAG_NONE,
3197 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3200 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3201 dpo = fib_entry_contribute_ip_forwarding(fei);
3203 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3204 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3205 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3206 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3207 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3208 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3209 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3210 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3213 * expect the lb-map used by the recursive's load-balance is using both buckets
3215 load_balance_map_t *lbm;
3218 lb = load_balance_get(dpo->dpoi_index);
3220 load_balance_map_lock(lbmi);
3221 lbm = load_balance_map_get(lbmi);
3223 FIB_TEST(lbm->lbm_buckets[0] == 0,
3224 "LB maps's bucket 0 is %d",
3225 lbm->lbm_buckets[0]);
3226 FIB_TEST(lbm->lbm_buckets[1] == 1,
3227 "LB maps's bucket 1 is %d",
3228 lbm->lbm_buckets[1]);
3231 * withdraw one of the /32 via-entrys.
3232 * that ECMP path will be unresolved and forwarding should continue on the
3233 * other available path. this is an iBGP PIC edge failover.
3234 * Test the forwarding changes without re-fetching the adj from the
3235 * recursive entry. this ensures its the same one that is updated; i.e. an
3238 fib_table_entry_path_remove(fib_index,
3243 tm->hw[0]->sw_if_index,
3244 ~0, // invalid fib index
3246 FIB_ROUTE_PATH_FLAG_NONE);
3248 /* suspend so the update walk kicks int */
3249 vlib_process_suspend(vlib_get_main(), 1e-5);
3251 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3252 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3253 "post PIC 200.200.200.200/32 was inplace modified");
3255 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3256 "post PIC adj for 200.200.200.200/32 is recursive"
3257 " via adj for 1.1.1.3");
3260 * the LB maps that was locked above should have been modified to remove
3261 * the path that was down, and thus its bucket points to a path that is
3264 FIB_TEST(lbm->lbm_buckets[0] == 1,
3265 "LB maps's bucket 0 is %d",
3266 lbm->lbm_buckets[0]);
3267 FIB_TEST(lbm->lbm_buckets[1] == 1,
3268 "LB maps's bucket 1 is %d",
3269 lbm->lbm_buckets[1]);
3271 load_balance_map_unlock(lbmi);
3274 * add it back. again
3276 fib_table_entry_path_add(fib_index,
3279 FIB_ENTRY_FLAG_NONE,
3282 tm->hw[0]->sw_if_index,
3283 ~0, // invalid fib index
3286 FIB_ROUTE_PATH_FLAG_NONE);
3288 /* suspend so the update walk kicks in */
3289 vlib_process_suspend(vlib_get_main(), 1e-5);
3291 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3292 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3293 "via adj for 1.1.1.1");
3294 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3295 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3296 "via adj for 1.1.1.3");
3298 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3299 dpo = fib_entry_contribute_ip_forwarding(fei);
3300 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3301 "post PIC 200.200.200.200/32 was inplace modified");
3304 * add a 3rd path. this makes the LB 16 buckets.
3306 fib_table_entry_path_add(fib_index,
3309 FIB_ENTRY_FLAG_NONE,
3311 &pfx_1_1_1_2_s_32.fp_addr,
3316 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3317 for (ii = 0; ii < N_P; ii++)
3319 fib_table_entry_path_add(fib_index,
3322 FIB_ENTRY_FLAG_NONE,
3324 &pfx_1_1_1_2_s_32.fp_addr,
3329 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3332 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3333 dpo = fib_entry_contribute_ip_forwarding(fei);
3334 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3335 "200.200.200.200/32 was inplace modified for 3rd path");
3336 FIB_TEST(16 == lb->lb_n_buckets,
3337 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3340 load_balance_map_lock(lbmi);
3341 lbm = load_balance_map_get(lbmi);
3343 for (ii = 0; ii < 16; ii++)
3345 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3346 "LB Map for 200.200.200.200/32 at %d is %d",
3347 ii, lbm->lbm_buckets[ii]);
3351 * trigger PIC by removing the first via-entry
3352 * the first 6 buckets of the map should map to the next 6
3354 fib_table_entry_path_remove(fib_index,
3359 tm->hw[0]->sw_if_index,
3362 FIB_ROUTE_PATH_FLAG_NONE);
3363 /* suspend so the update walk kicks int */
3364 vlib_process_suspend(vlib_get_main(), 1e-5);
3366 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3367 dpo = fib_entry_contribute_ip_forwarding(fei);
3368 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3369 "200.200.200.200/32 was inplace modified for 3rd path");
3370 FIB_TEST(2 == lb->lb_n_buckets,
3371 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3373 for (ii = 0; ii < 6; ii++)
3375 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3376 "LB Map for 200.200.200.200/32 at %d is %d",
3377 ii, lbm->lbm_buckets[ii]);
3379 for (ii = 6; ii < 16; ii++)
3381 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3382 "LB Map for 200.200.200.200/32 at %d is %d",
3383 ii, lbm->lbm_buckets[ii]);
3385 load_balance_map_unlock(lbmi);
3390 fib_table_entry_path_add(fib_index,
3393 FIB_ENTRY_FLAG_NONE,
3396 tm->hw[0]->sw_if_index,
3400 FIB_ROUTE_PATH_FLAG_NONE);
3402 for (ii = 0; ii < N_P; ii++)
3404 fib_table_entry_delete(fib_index,
3407 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3408 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3410 format_fib_prefix, &bgp_78s[ii]);
3412 fib_table_entry_path_remove(fib_index,
3416 &pfx_1_1_1_2_s_32.fp_addr,
3420 MPLS_LABEL_INVALID);
3421 fib_table_entry_path_remove(fib_index,
3429 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3430 fib_table_entry_path_remove(fib_index,
3434 &pfx_1_1_1_3_s_32.fp_addr,
3438 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3439 fib_table_entry_delete(fib_index,
3442 fib_table_entry_delete(fib_index,
3445 /* suspend so the update walk kicks int */
3446 vlib_process_suspend(vlib_get_main(), 1e-5);
3447 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3448 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3449 "1.1.1.1/28 removed");
3450 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3451 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3452 "1.1.1.3/32 removed");
3453 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3454 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3455 "200.200.200.200/32 removed");
3458 * add-remove test. no change.
3460 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3461 fib_path_list_db_size());
3462 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3463 fib_path_list_pool_size());
3464 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3465 fib_entry_pool_size());
3468 * A route whose paths are built up iteratively and then removed
3471 fib_prefix_t pfx_4_4_4_4_s_32 = {
3473 .fp_proto = FIB_PROTOCOL_IP4,
3476 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3480 fib_table_entry_path_add(fib_index,
3483 FIB_ENTRY_FLAG_NONE,
3486 tm->hw[0]->sw_if_index,
3490 FIB_ROUTE_PATH_FLAG_NONE);
3491 fib_table_entry_path_add(fib_index,
3494 FIB_ENTRY_FLAG_NONE,
3497 tm->hw[0]->sw_if_index,
3501 FIB_ROUTE_PATH_FLAG_NONE);
3502 fib_table_entry_path_add(fib_index,
3505 FIB_ENTRY_FLAG_NONE,
3508 tm->hw[0]->sw_if_index,
3512 FIB_ROUTE_PATH_FLAG_NONE);
3513 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3514 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3515 "4.4.4.4/32 present");
3517 fib_table_entry_delete(fib_index,
3520 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3521 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3522 "4.4.4.4/32 removed");
3525 * add-remove test. no change.
3527 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3528 fib_path_list_db_size());
3529 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3530 fib_path_list_pool_size());
3531 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3532 fib_entry_pool_size());
3535 * A route with multiple paths at once
3537 fib_route_path_t *r_paths = NULL;
3539 for (ii = 0; ii < 4; ii++)
3541 fib_route_path_t r_path = {
3542 .frp_proto = DPO_PROTO_IP4,
3544 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3546 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3548 .frp_fib_index = ~0,
3550 vec_add1(r_paths, r_path);
3553 fib_table_entry_update(fib_index,
3556 FIB_ENTRY_FLAG_NONE,
3559 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3560 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3561 dpo = fib_entry_contribute_ip_forwarding(fei);
3563 lb = load_balance_get(dpo->dpoi_index);
3564 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3566 fib_table_entry_delete(fib_index,
3569 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3570 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3571 "4.4.4.4/32 removed");
3575 * add-remove test. no change.
3577 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3578 fib_path_list_db_size());
3579 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3580 fib_path_list_pool_size());
3581 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3582 fib_entry_pool_size());
3585 * A route deag route
3587 fib_table_entry_path_add(fib_index,
3590 FIB_ENTRY_FLAG_NONE,
3597 FIB_ROUTE_PATH_FLAG_NONE);
3599 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3600 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3602 dpo = fib_entry_contribute_ip_forwarding(fei);
3603 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3604 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3606 FIB_TEST((fib_index == lkd->lkd_fib_index),
3607 "4.4.4.4/32 is deag in %d %U",
3609 format_dpo_id, dpo, 0);
3611 fib_table_entry_delete(fib_index,
3614 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3615 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3616 "4.4.4.4/32 removed");
3620 * add-remove test. no change.
3622 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3623 fib_path_list_db_size());
3624 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3625 fib_path_list_pool_size());
3626 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3627 fib_entry_pool_size());
3631 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3633 fib_prefix_t pfx_34_1_1_1_s_32 = {
3635 .fp_proto = FIB_PROTOCOL_IP4,
3637 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3640 fib_prefix_t pfx_34_34_1_1_s_32 = {
3642 .fp_proto = FIB_PROTOCOL_IP4,
3644 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3647 fei = fib_table_entry_path_add(fib_index,
3648 &pfx_34_34_1_1_s_32,
3650 FIB_ENTRY_FLAG_NONE,
3653 tm->hw[0]->sw_if_index,
3657 FIB_ROUTE_PATH_FLAG_NONE);
3658 fei = fib_table_entry_path_add(fib_index,
3661 FIB_ENTRY_FLAG_NONE,
3663 &pfx_34_34_1_1_s_32.fp_addr,
3668 FIB_ROUTE_PATH_FLAG_NONE);
3669 fei = fib_table_entry_path_add(fib_index,
3672 FIB_ENTRY_FLAG_NONE,
3674 &pfx_34_34_1_1_s_32.fp_addr,
3679 FIB_ROUTE_PATH_FLAG_NONE);
3680 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3681 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3682 fib_table_entry_delete(fib_index,
3683 &pfx_34_34_1_1_s_32,
3688 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3689 * all of which are via 10.10.10.1, Itf1
3691 fib_table_entry_path_remove(fib_index,
3696 tm->hw[0]->sw_if_index,
3699 FIB_ROUTE_PATH_FLAG_NONE);
3700 fib_table_entry_path_remove(fib_index,
3705 tm->hw[0]->sw_if_index,
3708 FIB_ROUTE_PATH_FLAG_NONE);
3709 fib_table_entry_path_remove(fib_index,
3714 tm->hw[0]->sw_if_index,
3717 FIB_ROUTE_PATH_FLAG_NONE);
3719 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3720 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3721 "1.1.1.1/32 removed");
3722 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3723 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3724 "1.1.1.2/32 removed");
3725 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3726 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3727 "1.1.2.0/24 removed");
3730 * -3 entries and -1 shared path-list
3732 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3733 fib_path_list_db_size());
3734 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3735 fib_path_list_pool_size());
3736 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3737 fib_entry_pool_size());
3740 * An attached-host route. Expect to link to the incomplete adj
3742 fib_prefix_t pfx_4_1_1_1_s_32 = {
3744 .fp_proto = FIB_PROTOCOL_IP4,
3747 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3750 fib_table_entry_path_add(fib_index,
3753 FIB_ENTRY_FLAG_NONE,
3756 tm->hw[0]->sw_if_index,
3760 FIB_ROUTE_PATH_FLAG_NONE);
3762 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3763 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3764 ai = fib_entry_get_adj(fei);
3766 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3768 &pfx_4_1_1_1_s_32.fp_addr,
3769 tm->hw[0]->sw_if_index);
3770 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3774 * +1 entry and +1 shared path-list
3776 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3777 fib_path_list_db_size());
3778 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3779 fib_path_list_pool_size());
3780 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3781 fib_entry_pool_size());
3783 fib_table_entry_delete(fib_index,
3787 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3788 fib_path_list_db_size());
3789 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3790 fib_path_list_pool_size());
3791 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3792 fib_entry_pool_size());
3795 * add a v6 prefix via v4 next-hops
3797 fib_prefix_t pfx_2001_s_64 = {
3799 .fp_proto = FIB_PROTOCOL_IP6,
3801 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3804 fei = fib_table_entry_path_add(0, //default v6 table
3807 FIB_ENTRY_FLAG_NONE,
3810 tm->hw[0]->sw_if_index,
3814 FIB_ROUTE_PATH_FLAG_NONE);
3816 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3817 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3818 ai = fib_entry_get_adj(fei);
3820 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3821 "2001::/64 via ARP-adj");
3822 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3823 "2001::/64 is link type v6");
3824 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3825 "2001::/64 ADJ-adj is NH proto v4");
3826 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3829 * add a uRPF exempt prefix:
3831 * - it's forwarding is drop
3832 * - it's uRPF list is not empty
3833 * - the uRPF list for the default route (it's cover) is empty
3835 fei = fib_table_entry_special_add(fib_index,
3837 FIB_SOURCE_URPF_EXEMPT,
3838 FIB_ENTRY_FLAG_DROP);
3839 dpo = fib_entry_contribute_ip_forwarding(fei);
3840 FIB_TEST(load_balance_is_drop(dpo),
3841 "uRPF exempt 4.1.1.1/32 DROP");
3842 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3843 "uRPF list for exempt prefix has itf index 0");
3844 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3845 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3846 "uRPF list for 0.0.0.0/0 empty");
3848 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3851 * An adj-fib that fails the refinement criteria - no connected cover
3853 fib_prefix_t pfx_12_10_10_2_s_32 = {
3855 .fp_proto = FIB_PROTOCOL_IP4,
3858 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3862 fib_table_entry_path_add(fib_index,
3863 &pfx_12_10_10_2_s_32,
3865 FIB_ENTRY_FLAG_ATTACHED,
3867 &pfx_12_10_10_2_s_32.fp_addr,
3868 tm->hw[0]->sw_if_index,
3869 ~0, // invalid fib index
3872 FIB_ROUTE_PATH_FLAG_NONE);
3874 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3875 dpo = fib_entry_contribute_ip_forwarding(fei);
3876 FIB_TEST(!dpo_id_is_valid(dpo),
3877 "no connected cover adj-fib fails refinement");
3879 fib_table_entry_delete(fib_index,
3880 &pfx_12_10_10_2_s_32,
3884 * An adj-fib that fails the refinement criteria - cover is connected
3885 * but on a different interface
3887 fib_prefix_t pfx_10_10_10_127_s_32 = {
3889 .fp_proto = FIB_PROTOCOL_IP4,
3892 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3896 fib_table_entry_path_add(fib_index,
3897 &pfx_10_10_10_127_s_32,
3899 FIB_ENTRY_FLAG_ATTACHED,
3901 &pfx_10_10_10_127_s_32.fp_addr,
3902 tm->hw[1]->sw_if_index,
3903 ~0, // invalid fib index
3906 FIB_ROUTE_PATH_FLAG_NONE);
3908 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3909 dpo = fib_entry_contribute_ip_forwarding(fei);
3910 FIB_TEST(!dpo_id_is_valid(dpo),
3911 "wrong interface adj-fib fails refinement");
3913 fib_table_entry_delete(fib_index,
3914 &pfx_10_10_10_127_s_32,
3918 * add a second path to an adj-fib
3919 * this is a sumiluation of another ARP entry created
3920 * on an interface on which the connected prefi does not exist.
3921 * The second path fails refinement. Expect to forward through the
3924 fib_prefix_t pfx_10_10_10_3_s_32 = {
3926 .fp_proto = FIB_PROTOCOL_IP4,
3929 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
3933 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3936 tm->hw[0]->sw_if_index);
3938 fib_test_lb_bucket_t ip_o_10_10_10_3 = {
3944 fei = fib_table_entry_path_add(fib_index,
3945 &pfx_10_10_10_3_s_32,
3947 FIB_ENTRY_FLAG_NONE,
3950 tm->hw[0]->sw_if_index,
3954 FIB_ROUTE_PATH_FLAG_NONE);
3955 fei = fib_table_entry_path_add(fib_index,
3956 &pfx_10_10_10_3_s_32,
3958 FIB_ENTRY_FLAG_NONE,
3961 tm->hw[1]->sw_if_index,
3965 FIB_ROUTE_PATH_FLAG_NONE);
3966 FIB_TEST(fib_test_validate_entry(fei,
3967 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3970 "10.10.10.3 via 10.10.10.3/Eth0 only");
3973 * remove the path that refines the cover, should go unresolved
3975 fib_table_entry_path_remove(fib_index,
3976 &pfx_10_10_10_3_s_32,
3980 tm->hw[0]->sw_if_index,
3983 FIB_ROUTE_PATH_FLAG_NONE);
3984 dpo = fib_entry_contribute_ip_forwarding(fei);
3985 FIB_TEST(!dpo_id_is_valid(dpo),
3986 "wrong interface adj-fib fails refinement");
3989 * add back the path that refines the cover
3991 fei = fib_table_entry_path_add(fib_index,
3992 &pfx_10_10_10_3_s_32,
3994 FIB_ENTRY_FLAG_NONE,
3997 tm->hw[0]->sw_if_index,
4001 FIB_ROUTE_PATH_FLAG_NONE);
4002 FIB_TEST(fib_test_validate_entry(fei,
4003 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4006 "10.10.10.3 via 10.10.10.3/Eth0 only");
4009 * remove the path that does not refine the cover
4011 fib_table_entry_path_remove(fib_index,
4012 &pfx_10_10_10_3_s_32,
4016 tm->hw[1]->sw_if_index,
4019 FIB_ROUTE_PATH_FLAG_NONE);
4020 FIB_TEST(fib_test_validate_entry(fei,
4021 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4024 "10.10.10.3 via 10.10.10.3/Eth0 only");
4027 * remove the path that does refine, it's the last path, so
4028 * the entry should be gone
4030 fib_table_entry_path_remove(fib_index,
4031 &pfx_10_10_10_3_s_32,
4035 tm->hw[0]->sw_if_index,
4038 FIB_ROUTE_PATH_FLAG_NONE);
4039 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4040 FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4045 * change the table's flow-hash config - expect the update to propagete to
4046 * the entries' load-balance objects
4048 flow_hash_config_t old_hash_config, new_hash_config;
4050 old_hash_config = fib_table_get_flow_hash_config(fib_index,
4052 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4053 IP_FLOW_HASH_DST_ADDR);
4055 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4056 dpo = fib_entry_contribute_ip_forwarding(fei);
4057 lb = load_balance_get(dpo->dpoi_index);
4058 FIB_TEST((lb->lb_hash_config == old_hash_config),
4059 "Table and LB hash config match: %U",
4060 format_ip_flow_hash_config, lb->lb_hash_config);
4062 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4064 FIB_TEST((lb->lb_hash_config == new_hash_config),
4065 "Table and LB newhash config match: %U",
4066 format_ip_flow_hash_config, lb->lb_hash_config);
4072 fib_table_entry_delete(fib_index,
4073 &pfx_10_10_10_1_s_32,
4075 fib_table_entry_delete(fib_index,
4076 &pfx_10_10_10_2_s_32,
4078 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4079 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4080 "10.10.10.1/32 adj-fib removed");
4081 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4082 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4083 "10.10.10.2/32 adj-fib removed");
4086 * -2 entries and -2 non-shared path-list
4088 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4089 fib_path_list_db_size());
4090 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4091 fib_path_list_pool_size());
4092 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4093 fib_entry_pool_size());
4096 * unlock the adjacencies for which this test provided a rewrite.
4097 * These are the last locks on these adjs. they should thus go away.
4101 adj_unlock(ai_12_12_12_12);
4103 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4108 * remove the interface prefixes
4110 local_pfx.fp_len = 32;
4111 fib_table_entry_special_remove(fib_index, &local_pfx,
4112 FIB_SOURCE_INTERFACE);
4113 fei = fib_table_lookup(fib_index, &local_pfx);
4115 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4116 fib_table_lookup_exact_match(fib_index, &local_pfx),
4117 "10.10.10.10/32 adj-fib removed");
4119 local_pfx.fp_len = 24;
4120 fib_table_entry_delete(fib_index, &local_pfx,
4121 FIB_SOURCE_INTERFACE);
4123 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4124 fib_table_lookup_exact_match(fib_index, &local_pfx),
4125 "10.10.10.10/24 adj-fib removed");
4128 * -2 entries and -2 non-shared path-list
4130 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4131 fib_path_list_db_size());
4132 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4133 fib_path_list_pool_size());
4134 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4135 fib_entry_pool_size());
4138 * Last but not least, remove the VRF
4140 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4143 "NO API Source'd prefixes");
4144 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4147 "NO RR Source'd prefixes");
4148 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4150 FIB_SOURCE_INTERFACE)),
4151 "NO INterface Source'd prefixes");
4153 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
4155 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4156 fib_path_list_db_size());
4157 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4158 fib_path_list_pool_size());
4159 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4160 fib_entry_pool_size());
4161 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4162 pool_elts(fib_urpf_list_pool));
4163 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4164 pool_elts(load_balance_map_pool));
4165 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4166 pool_elts(load_balance_pool));
4175 * In the default table check for the presence and correct forwarding
4176 * of the special entries
4178 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4179 const dpo_id_t *dpo, *dpo_drop;
4180 const ip_adjacency_t *adj;
4181 const receive_dpo_t *rd;
4186 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4189 /* via 2001:0:0:1::2 */
4190 ip46_address_t nh_2001_2 = {
4193 [0] = clib_host_to_net_u64(0x2001000000000001),
4194 [1] = clib_host_to_net_u64(0x0000000000000002),
4201 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4203 /* Find or create FIB table 11 */
4204 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
4206 for (ii = 0; ii < 4; ii++)
4208 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4211 fib_prefix_t pfx_0_0 = {
4213 .fp_proto = FIB_PROTOCOL_IP6,
4221 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4222 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4223 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4224 "Default route is DROP");
4226 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4227 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4230 &pfx_0_0.fp_addr.ip6)),
4231 "default-route; fwd and non-fwd tables match");
4233 // FIXME - check specials.
4236 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4237 * each with 2 entries and a v6 mfib with 4 path-lists.
4238 * All entries are special so no path-list sharing.
4241 #define PNPS (5+4+4)
4242 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4243 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4244 fib_path_list_pool_size());
4245 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4246 fib_entry_pool_size());
4249 * add interface routes.
4250 * validate presence of /64 attached and /128 recieve.
4251 * test for the presence of the receive address in the glean and local adj
4253 * receive on 2001:0:0:1::1/128
4255 fib_prefix_t local_pfx = {
4257 .fp_proto = FIB_PROTOCOL_IP6,
4261 [0] = clib_host_to_net_u64(0x2001000000000001),
4262 [1] = clib_host_to_net_u64(0x0000000000000001),
4268 fib_table_entry_update_one_path(fib_index, &local_pfx,
4269 FIB_SOURCE_INTERFACE,
4270 (FIB_ENTRY_FLAG_CONNECTED |
4271 FIB_ENTRY_FLAG_ATTACHED),
4274 tm->hw[0]->sw_if_index,
4278 FIB_ROUTE_PATH_FLAG_NONE);
4279 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4281 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4283 ai = fib_entry_get_adj(fei);
4284 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4286 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4287 "attached interface adj is glean");
4288 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4289 &adj->sub_type.glean.receive_addr)),
4290 "attached interface adj is receive ok");
4291 dpo = fib_entry_contribute_ip_forwarding(fei);
4292 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4295 &local_pfx.fp_addr.ip6)),
4296 "attached-route; fwd and non-fwd tables match");
4298 local_pfx.fp_len = 128;
4299 fib_table_entry_update_one_path(fib_index, &local_pfx,
4300 FIB_SOURCE_INTERFACE,
4301 (FIB_ENTRY_FLAG_CONNECTED |
4302 FIB_ENTRY_FLAG_LOCAL),
4305 tm->hw[0]->sw_if_index,
4306 ~0, // invalid fib index
4309 FIB_ROUTE_PATH_FLAG_NONE);
4310 fei = fib_table_lookup(fib_index, &local_pfx);
4312 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4314 dpo = fib_entry_contribute_ip_forwarding(fei);
4315 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4316 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4317 "local interface adj is local");
4318 rd = receive_dpo_get(dpo->dpoi_index);
4320 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4322 "local interface adj is receive ok");
4324 dpo = fib_entry_contribute_ip_forwarding(fei);
4325 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4328 &local_pfx.fp_addr.ip6)),
4329 "local-route; fwd and non-fwd tables match");
4332 * +2 entries. +2 unshared path-lists
4334 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4335 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4336 fib_path_list_pool_size());
4337 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4338 fib_entry_pool_size());
4341 * Modify the default route to be via an adj not yet known.
4342 * this sources the defalut route with the API source, which is
4343 * a higher preference to the DEFAULT_ROUTE source
4345 fib_table_entry_path_add(fib_index, &pfx_0_0,
4347 FIB_ENTRY_FLAG_NONE,
4350 tm->hw[0]->sw_if_index,
4354 FIB_ROUTE_PATH_FLAG_NONE);
4355 fei = fib_table_lookup(fib_index, &pfx_0_0);
4357 FIB_TEST((fei == dfrt), "default route same index");
4358 ai = fib_entry_get_adj(fei);
4359 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4361 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4362 "adj is incomplete");
4363 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4364 "adj nbr next-hop ok");
4367 * find the adj in the shared db
4369 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4372 tm->hw[0]->sw_if_index);
4373 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4374 adj_unlock(locked_ai);
4377 * no more entires. +1 shared path-list
4379 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4380 fib_path_list_db_size());
4381 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4382 fib_path_list_pool_size());
4383 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4384 fib_entry_pool_size());
4387 * remove the API source from the default route. We expected
4388 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4390 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4394 tm->hw[0]->sw_if_index,
4397 FIB_ROUTE_PATH_FLAG_NONE);
4398 fei = fib_table_lookup(fib_index, &pfx_0_0);
4400 FIB_TEST((fei == dfrt), "default route same index");
4401 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4402 "Default route is DROP");
4405 * no more entires. -1 shared path-list
4407 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4408 fib_path_list_db_size());
4409 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4410 fib_path_list_pool_size());
4411 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4412 fib_entry_pool_size());
4415 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4417 fib_prefix_t pfx_2001_1_2_s_128 = {
4419 .fp_proto = FIB_PROTOCOL_IP6,
4423 [0] = clib_host_to_net_u64(0x2001000000000001),
4424 [1] = clib_host_to_net_u64(0x0000000000000002),
4429 fib_prefix_t pfx_2001_1_3_s_128 = {
4431 .fp_proto = FIB_PROTOCOL_IP6,
4435 [0] = clib_host_to_net_u64(0x2001000000000001),
4436 [1] = clib_host_to_net_u64(0x0000000000000003),
4442 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4445 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4447 &pfx_2001_1_2_s_128.fp_addr,
4448 tm->hw[0]->sw_if_index);
4449 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4450 adj = adj_get(ai_01);
4451 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4452 "adj is incomplete");
4453 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4454 &adj->sub_type.nbr.next_hop)),
4455 "adj nbr next-hop ok");
4457 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4458 fib_test_build_rewrite(eth_addr));
4459 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4461 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4462 &adj->sub_type.nbr.next_hop)),
4463 "adj nbr next-hop ok");
4465 fib_table_entry_path_add(fib_index,
4466 &pfx_2001_1_2_s_128,
4468 FIB_ENTRY_FLAG_ATTACHED,
4470 &pfx_2001_1_2_s_128.fp_addr,
4471 tm->hw[0]->sw_if_index,
4475 FIB_ROUTE_PATH_FLAG_NONE);
4477 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4478 ai = fib_entry_get_adj(fei);
4479 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4483 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4485 &pfx_2001_1_3_s_128.fp_addr,
4486 tm->hw[0]->sw_if_index);
4487 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4488 adj = adj_get(ai_02);
4489 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4490 "adj is incomplete");
4491 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4492 &adj->sub_type.nbr.next_hop)),
4493 "adj nbr next-hop ok");
4495 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4496 fib_test_build_rewrite(eth_addr));
4497 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4499 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4500 &adj->sub_type.nbr.next_hop)),
4501 "adj nbr next-hop ok");
4502 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4504 fib_table_entry_path_add(fib_index,
4505 &pfx_2001_1_3_s_128,
4507 FIB_ENTRY_FLAG_ATTACHED,
4509 &pfx_2001_1_3_s_128.fp_addr,
4510 tm->hw[0]->sw_if_index,
4514 FIB_ROUTE_PATH_FLAG_NONE);
4516 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4517 ai = fib_entry_get_adj(fei);
4518 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4521 * +2 entries, +2 unshread path-lists.
4523 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4524 fib_path_list_db_size());
4525 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4526 fib_path_list_pool_size());
4527 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4528 fib_entry_pool_size());
4531 * Add a 2 routes via the first ADJ. ensure path-list sharing
4533 fib_prefix_t pfx_2001_a_s_64 = {
4535 .fp_proto = FIB_PROTOCOL_IP6,
4539 [0] = clib_host_to_net_u64(0x200100000000000a),
4540 [1] = clib_host_to_net_u64(0x0000000000000000),
4545 fib_prefix_t pfx_2001_b_s_64 = {
4547 .fp_proto = FIB_PROTOCOL_IP6,
4551 [0] = clib_host_to_net_u64(0x200100000000000b),
4552 [1] = clib_host_to_net_u64(0x0000000000000000),
4558 fib_table_entry_path_add(fib_index,
4561 FIB_ENTRY_FLAG_NONE,
4564 tm->hw[0]->sw_if_index,
4568 FIB_ROUTE_PATH_FLAG_NONE);
4569 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4570 ai = fib_entry_get_adj(fei);
4571 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4572 fib_table_entry_path_add(fib_index,
4575 FIB_ENTRY_FLAG_NONE,
4578 tm->hw[0]->sw_if_index,
4582 FIB_ROUTE_PATH_FLAG_NONE);
4583 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4584 ai = fib_entry_get_adj(fei);
4585 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4588 * +2 entries, +1 shared path-list.
4590 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4591 fib_path_list_db_size());
4592 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4593 fib_path_list_pool_size());
4594 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4595 fib_entry_pool_size());
4598 * add a v4 prefix via a v6 next-hop
4600 fib_prefix_t pfx_1_1_1_1_s_32 = {
4602 .fp_proto = FIB_PROTOCOL_IP4,
4604 .ip4.as_u32 = 0x01010101,
4607 fei = fib_table_entry_path_add(0, // default table
4610 FIB_ENTRY_FLAG_NONE,
4613 tm->hw[0]->sw_if_index,
4617 FIB_ROUTE_PATH_FLAG_NONE);
4618 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4619 "1.1.1.1/32 o v6 route present");
4620 ai = fib_entry_get_adj(fei);
4622 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4623 "1.1.1.1/32 via ARP-adj");
4624 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4625 "1.1.1.1/32 ADJ-adj is link type v4");
4626 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4627 "1.1.1.1/32 ADJ-adj is NH proto v6");
4628 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4633 fib_prefix_t pfx_2001_c_s_64 = {
4635 .fp_proto = FIB_PROTOCOL_IP6,
4639 [0] = clib_host_to_net_u64(0x200100000000000c),
4640 [1] = clib_host_to_net_u64(0x0000000000000000),
4645 fib_table_entry_path_add(fib_index,
4648 FIB_ENTRY_FLAG_ATTACHED,
4651 tm->hw[0]->sw_if_index,
4655 FIB_ROUTE_PATH_FLAG_NONE);
4656 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4657 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4658 ai = fib_entry_get_adj(fei);
4660 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4661 "2001:0:0:c/64 attached resolves via glean");
4663 fib_table_entry_path_remove(fib_index,
4668 tm->hw[0]->sw_if_index,
4671 FIB_ROUTE_PATH_FLAG_NONE);
4672 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4673 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4676 * Shutdown the interface on which we have a connected and through
4677 * which the routes are reachable.
4678 * This will result in the connected, adj-fibs, and routes linking to drop
4679 * The local/for-us prefix continues to receive.
4681 clib_error_t * error;
4683 error = vnet_sw_interface_set_flags(vnet_get_main(),
4684 tm->hw[0]->sw_if_index,
4685 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4686 FIB_TEST((NULL == error), "Interface shutdown OK");
4688 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4689 dpo = fib_entry_contribute_ip_forwarding(fei);
4690 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4691 "2001::b/64 resolves via drop");
4693 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4694 dpo = fib_entry_contribute_ip_forwarding(fei);
4695 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4696 "2001::a/64 resolves via drop");
4697 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4698 dpo = fib_entry_contribute_ip_forwarding(fei);
4699 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4700 "2001:0:0:1::3/64 resolves via drop");
4701 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4702 dpo = fib_entry_contribute_ip_forwarding(fei);
4703 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4704 "2001:0:0:1::2/64 resolves via drop");
4705 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4706 dpo = fib_entry_contribute_ip_forwarding(fei);
4707 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4708 "2001:0:0:1::1/128 not drop");
4709 local_pfx.fp_len = 64;
4710 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4711 dpo = fib_entry_contribute_ip_forwarding(fei);
4712 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4713 "2001:0:0:1/64 resolves via drop");
4718 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4719 fib_path_list_db_size());
4720 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4721 fib_path_list_pool_size());
4722 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4723 fib_entry_pool_size());
4726 * shutdown one of the other interfaces, then add a connected.
4727 * and swap one of the routes to it.
4729 error = vnet_sw_interface_set_flags(vnet_get_main(),
4730 tm->hw[1]->sw_if_index,
4731 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4732 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4734 fib_prefix_t connected_pfx = {
4736 .fp_proto = FIB_PROTOCOL_IP6,
4739 /* 2001:0:0:2::1/64 */
4741 [0] = clib_host_to_net_u64(0x2001000000000002),
4742 [1] = clib_host_to_net_u64(0x0000000000000001),
4747 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4748 FIB_SOURCE_INTERFACE,
4749 (FIB_ENTRY_FLAG_CONNECTED |
4750 FIB_ENTRY_FLAG_ATTACHED),
4753 tm->hw[1]->sw_if_index,
4757 FIB_ROUTE_PATH_FLAG_NONE);
4758 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4759 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4760 dpo = fib_entry_contribute_ip_forwarding(fei);
4761 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4762 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4763 "2001:0:0:2/64 not resolves via drop");
4765 connected_pfx.fp_len = 128;
4766 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4767 FIB_SOURCE_INTERFACE,
4768 (FIB_ENTRY_FLAG_CONNECTED |
4769 FIB_ENTRY_FLAG_LOCAL),
4772 tm->hw[0]->sw_if_index,
4773 ~0, // invalid fib index
4776 FIB_ROUTE_PATH_FLAG_NONE);
4777 fei = fib_table_lookup(fib_index, &connected_pfx);
4779 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4780 dpo = fib_entry_contribute_ip_forwarding(fei);
4781 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4782 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4783 "local interface adj is local");
4784 rd = receive_dpo_get(dpo->dpoi_index);
4785 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4787 "local interface adj is receive ok");
4790 * +2 entries, +2 unshared path-lists
4792 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4793 fib_path_list_db_size());
4794 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4795 fib_path_list_pool_size());
4796 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4797 fib_entry_pool_size());
4801 * bring the interface back up. we expected the routes to return
4802 * to normal forwarding.
4804 error = vnet_sw_interface_set_flags(vnet_get_main(),
4805 tm->hw[0]->sw_if_index,
4806 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4807 FIB_TEST((NULL == error), "Interface bring-up OK");
4808 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4809 ai = fib_entry_get_adj(fei);
4810 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4811 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4812 ai = fib_entry_get_adj(fei);
4813 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4814 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4815 ai = fib_entry_get_adj(fei);
4816 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4817 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4818 ai = fib_entry_get_adj(fei);
4819 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4820 local_pfx.fp_len = 64;
4821 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4822 ai = fib_entry_get_adj(fei);
4824 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4825 "attached interface adj is glean");
4828 * Same test as above, but this time the HW interface goes down
4830 error = vnet_hw_interface_set_flags(vnet_get_main(),
4831 tm->hw_if_indicies[0],
4832 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4833 FIB_TEST((NULL == error), "Interface shutdown OK");
4835 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4836 dpo = fib_entry_contribute_ip_forwarding(fei);
4837 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4838 "2001::b/64 resolves via drop");
4839 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4840 dpo = fib_entry_contribute_ip_forwarding(fei);
4841 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4842 "2001::a/64 resolves via drop");
4843 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4844 dpo = fib_entry_contribute_ip_forwarding(fei);
4845 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4846 "2001:0:0:1::3/128 resolves via drop");
4847 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4848 dpo = fib_entry_contribute_ip_forwarding(fei);
4849 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4850 "2001:0:0:1::2/128 resolves via drop");
4851 local_pfx.fp_len = 128;
4852 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4853 dpo = fib_entry_contribute_ip_forwarding(fei);
4854 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4855 "2001:0:0:1::1/128 not drop");
4856 local_pfx.fp_len = 64;
4857 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4858 dpo = fib_entry_contribute_ip_forwarding(fei);
4859 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4860 "2001:0:0:1/64 resolves via drop");
4862 error = vnet_hw_interface_set_flags(vnet_get_main(),
4863 tm->hw_if_indicies[0],
4864 VNET_HW_INTERFACE_FLAG_LINK_UP);
4865 FIB_TEST((NULL == error), "Interface bring-up OK");
4866 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4867 ai = fib_entry_get_adj(fei);
4868 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4869 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4870 ai = fib_entry_get_adj(fei);
4871 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4872 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4873 ai = fib_entry_get_adj(fei);
4874 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4875 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4876 ai = fib_entry_get_adj(fei);
4877 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4878 local_pfx.fp_len = 64;
4879 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4880 ai = fib_entry_get_adj(fei);
4882 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4883 "attached interface adj is glean");
4886 * Delete the interface that the routes reolve through.
4887 * Again no routes are removed. They all point to drop.
4889 * This is considered an error case. The control plane should
4890 * not remove interfaces through which routes resolve, but
4891 * such things can happen. ALL affected routes will drop.
4893 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4895 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4896 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4897 "2001::b/64 resolves via drop");
4898 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4899 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4900 "2001::b/64 resolves via drop");
4901 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4902 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4903 "2001:0:0:1::3/64 resolves via drop");
4904 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4905 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4906 "2001:0:0:1::2/64 resolves via drop");
4907 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4908 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4909 "2001:0:0:1::1/128 is drop");
4910 local_pfx.fp_len = 64;
4911 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4912 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4913 "2001:0:0:1/64 resolves via drop");
4918 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4919 fib_path_list_db_size());
4920 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4921 fib_path_list_pool_size());
4922 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4923 fib_entry_pool_size());
4926 * Add the interface back. routes stay unresolved.
4928 error = ethernet_register_interface(vnet_get_main(),
4929 test_interface_device_class.index,
4932 &tm->hw_if_indicies[0],
4933 /* flag change */ 0);
4935 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4936 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4937 "2001::b/64 resolves via drop");
4938 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4939 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4940 "2001::b/64 resolves via drop");
4941 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4942 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4943 "2001:0:0:1::3/64 resolves via drop");
4944 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4945 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4946 "2001:0:0:1::2/64 resolves via drop");
4947 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4948 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4949 "2001:0:0:1::1/128 is drop");
4950 local_pfx.fp_len = 64;
4951 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4952 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4953 "2001:0:0:1/64 resolves via drop");
4956 * CLEANUP ALL the routes
4958 fib_table_entry_delete(fib_index,
4961 fib_table_entry_delete(fib_index,
4964 fib_table_entry_delete(fib_index,
4967 fib_table_entry_delete(fib_index,
4968 &pfx_2001_1_3_s_128,
4970 fib_table_entry_delete(fib_index,
4971 &pfx_2001_1_2_s_128,
4973 local_pfx.fp_len = 64;
4974 fib_table_entry_delete(fib_index, &local_pfx,
4975 FIB_SOURCE_INTERFACE);
4976 local_pfx.fp_len = 128;
4977 fib_table_entry_special_remove(fib_index, &local_pfx,
4978 FIB_SOURCE_INTERFACE);
4979 connected_pfx.fp_len = 64;
4980 fib_table_entry_delete(fib_index, &connected_pfx,
4981 FIB_SOURCE_INTERFACE);
4982 connected_pfx.fp_len = 128;
4983 fib_table_entry_special_remove(fib_index, &connected_pfx,
4984 FIB_SOURCE_INTERFACE);
4986 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4987 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4988 "2001::a/64 removed");
4989 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4990 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4991 "2001::b/64 removed");
4992 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4993 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4994 "2001:0:0:1::3/128 removed");
4995 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4996 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4997 "2001:0:0:1::3/128 removed");
4998 local_pfx.fp_len = 64;
4999 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5000 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5001 "2001:0:0:1/64 removed");
5002 local_pfx.fp_len = 128;
5003 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5004 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5005 "2001:0:0:1::1/128 removed");
5006 connected_pfx.fp_len = 64;
5007 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5008 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5009 "2001:0:0:2/64 removed");
5010 connected_pfx.fp_len = 128;
5011 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5012 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5013 "2001:0:0:2::1/128 removed");
5016 * -8 entries. -7 path-lists (1 was shared).
5018 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5019 fib_path_list_db_size());
5020 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5021 fib_path_list_pool_size());
5022 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5023 fib_entry_pool_size());
5026 * now remove the VRF
5028 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
5030 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5031 fib_path_list_db_size());
5032 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5033 fib_path_list_pool_size());
5034 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5035 fib_entry_pool_size());
5041 * return the interfaces to up state
5043 error = vnet_sw_interface_set_flags(vnet_get_main(),
5044 tm->hw[0]->sw_if_index,
5045 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5046 error = vnet_sw_interface_set_flags(vnet_get_main(),
5047 tm->hw[1]->sw_if_index,
5048 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5050 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5057 * Test Attached Exports
5062 const dpo_id_t *dpo, *dpo_drop;
5063 const u32 fib_index = 0;
5064 fib_node_index_t fei;
5071 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5075 * add interface routes. We'll assume this works. It's more rigorously
5078 fib_prefix_t local_pfx = {
5080 .fp_proto = FIB_PROTOCOL_IP4,
5084 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5089 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5090 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5092 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5094 fib_table_entry_update_one_path(fib_index, &local_pfx,
5095 FIB_SOURCE_INTERFACE,
5096 (FIB_ENTRY_FLAG_CONNECTED |
5097 FIB_ENTRY_FLAG_ATTACHED),
5100 tm->hw[0]->sw_if_index,
5104 FIB_ROUTE_PATH_FLAG_NONE);
5105 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5106 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5107 "attached interface route present");
5109 local_pfx.fp_len = 32;
5110 fib_table_entry_update_one_path(fib_index, &local_pfx,
5111 FIB_SOURCE_INTERFACE,
5112 (FIB_ENTRY_FLAG_CONNECTED |
5113 FIB_ENTRY_FLAG_LOCAL),
5116 tm->hw[0]->sw_if_index,
5117 ~0, // invalid fib index
5120 FIB_ROUTE_PATH_FLAG_NONE);
5121 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5123 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5124 "local interface route present");
5127 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5129 fib_prefix_t pfx_10_10_10_1_s_32 = {
5131 .fp_proto = FIB_PROTOCOL_IP4,
5134 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5137 fib_node_index_t ai;
5139 fib_table_entry_path_add(fib_index,
5140 &pfx_10_10_10_1_s_32,
5142 FIB_ENTRY_FLAG_ATTACHED,
5144 &pfx_10_10_10_1_s_32.fp_addr,
5145 tm->hw[0]->sw_if_index,
5146 ~0, // invalid fib index
5149 FIB_ROUTE_PATH_FLAG_NONE);
5151 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5152 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5153 ai = fib_entry_get_adj(fei);
5156 * create another FIB table into which routes will be imported
5158 u32 import_fib_index1;
5160 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
5163 * Add an attached route in the import FIB
5165 local_pfx.fp_len = 24;
5166 fib_table_entry_update_one_path(import_fib_index1,
5169 FIB_ENTRY_FLAG_NONE,
5172 tm->hw[0]->sw_if_index,
5173 ~0, // invalid fib index
5176 FIB_ROUTE_PATH_FLAG_NONE);
5177 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5178 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5181 * check for the presence of the adj-fibs in the import table
5183 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5184 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5185 FIB_TEST((ai == fib_entry_get_adj(fei)),
5186 "adj-fib1 Import uses same adj as export");
5189 * check for the presence of the local in the import table
5191 local_pfx.fp_len = 32;
5192 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5193 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5196 * Add another adj-fin in the export table. Expect this
5197 * to get magically exported;
5199 fib_prefix_t pfx_10_10_10_2_s_32 = {
5201 .fp_proto = FIB_PROTOCOL_IP4,
5204 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5208 fib_table_entry_path_add(fib_index,
5209 &pfx_10_10_10_2_s_32,
5211 FIB_ENTRY_FLAG_ATTACHED,
5213 &pfx_10_10_10_2_s_32.fp_addr,
5214 tm->hw[0]->sw_if_index,
5215 ~0, // invalid fib index
5218 FIB_ROUTE_PATH_FLAG_NONE);
5219 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5220 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5221 ai = fib_entry_get_adj(fei);
5223 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5224 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5225 FIB_TEST((ai == fib_entry_get_adj(fei)),
5226 "Import uses same adj as export");
5227 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5228 "ADJ-fib2 imported flags %d",
5229 fib_entry_get_flags(fei));
5232 * create a 2nd FIB table into which routes will be imported
5234 u32 import_fib_index2;
5236 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
5239 * Add an attached route in the import FIB
5241 local_pfx.fp_len = 24;
5242 fib_table_entry_update_one_path(import_fib_index2,
5245 FIB_ENTRY_FLAG_NONE,
5248 tm->hw[0]->sw_if_index,
5249 ~0, // invalid fib index
5252 FIB_ROUTE_PATH_FLAG_NONE);
5253 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5254 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5257 * check for the presence of all the adj-fibs and local in the import table
5259 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5260 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5261 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5262 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5263 local_pfx.fp_len = 32;
5264 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5265 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5268 * add a 3rd adj-fib. expect it to be exported to both tables.
5270 fib_prefix_t pfx_10_10_10_3_s_32 = {
5272 .fp_proto = FIB_PROTOCOL_IP4,
5275 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5279 fib_table_entry_path_add(fib_index,
5280 &pfx_10_10_10_3_s_32,
5282 FIB_ENTRY_FLAG_ATTACHED,
5284 &pfx_10_10_10_3_s_32.fp_addr,
5285 tm->hw[0]->sw_if_index,
5286 ~0, // invalid fib index
5289 FIB_ROUTE_PATH_FLAG_NONE);
5290 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5291 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5292 ai = fib_entry_get_adj(fei);
5294 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5295 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5296 FIB_TEST((ai == fib_entry_get_adj(fei)),
5297 "Import uses same adj as export");
5298 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5299 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5300 FIB_TEST((ai == fib_entry_get_adj(fei)),
5301 "Import uses same adj as export");
5304 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5306 fib_table_entry_delete(fib_index,
5307 &pfx_10_10_10_3_s_32,
5310 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5311 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5313 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5314 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5316 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5317 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5320 * remove the attached route from the 2nd FIB. expect the imported
5321 * entires to be removed
5323 local_pfx.fp_len = 24;
5324 fib_table_entry_delete(import_fib_index2,
5327 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5328 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5330 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5331 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5332 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5333 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5334 local_pfx.fp_len = 32;
5335 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5336 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5338 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5339 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5340 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5341 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5342 local_pfx.fp_len = 32;
5343 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5344 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5347 * modify the route in FIB1 so it is no longer attached. expect the imported
5348 * entires to be removed
5350 local_pfx.fp_len = 24;
5351 fib_table_entry_update_one_path(import_fib_index1,
5354 FIB_ENTRY_FLAG_NONE,
5356 &pfx_10_10_10_2_s_32.fp_addr,
5357 tm->hw[0]->sw_if_index,
5358 ~0, // invalid fib index
5361 FIB_ROUTE_PATH_FLAG_NONE);
5362 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5363 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5364 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5365 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5366 local_pfx.fp_len = 32;
5367 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5368 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5371 * modify it back to attached. expect the adj-fibs back
5373 local_pfx.fp_len = 24;
5374 fib_table_entry_update_one_path(import_fib_index1,
5377 FIB_ENTRY_FLAG_NONE,
5380 tm->hw[0]->sw_if_index,
5381 ~0, // invalid fib index
5384 FIB_ROUTE_PATH_FLAG_NONE);
5385 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5386 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5387 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5388 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5389 local_pfx.fp_len = 32;
5390 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5391 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5394 * add a covering attached next-hop for the interface address, so we have
5395 * a valid adj to find when we check the forwarding tables
5397 fib_prefix_t pfx_10_0_0_0_s_8 = {
5399 .fp_proto = FIB_PROTOCOL_IP4,
5402 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5406 fei = fib_table_entry_update_one_path(fib_index,
5409 FIB_ENTRY_FLAG_NONE,
5411 &pfx_10_10_10_3_s_32.fp_addr,
5412 tm->hw[0]->sw_if_index,
5413 ~0, // invalid fib index
5416 FIB_ROUTE_PATH_FLAG_NONE);
5417 dpo = fib_entry_contribute_ip_forwarding(fei);
5420 * remove the route in the export fib. expect the adj-fibs to be removed
5422 local_pfx.fp_len = 24;
5423 fib_table_entry_delete(fib_index,
5425 FIB_SOURCE_INTERFACE);
5427 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5428 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5429 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5430 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5431 local_pfx.fp_len = 32;
5432 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5433 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5436 * the adj-fibs in the export VRF are present in the FIB table,
5437 * but not installed in forwarding, since they have no attached cover.
5438 * Consequently a lookup in the MTRIE gives the adj for the covering
5441 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5442 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5445 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5446 FIB_TEST(lbi == dpo->dpoi_index,
5447 "10.10.10.1 forwards on \n%U not \n%U",
5448 format_load_balance, lbi, 0,
5449 format_dpo_id, dpo, 0);
5450 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5451 FIB_TEST(lbi == dpo->dpoi_index,
5452 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5453 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5454 FIB_TEST(lbi == dpo->dpoi_index,
5455 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5458 * add the export prefix back, but not as attached.
5459 * No adj-fibs in export nor import tables
5461 local_pfx.fp_len = 24;
5462 fei = fib_table_entry_update_one_path(fib_index,
5465 FIB_ENTRY_FLAG_NONE,
5467 &pfx_10_10_10_1_s_32.fp_addr,
5468 tm->hw[0]->sw_if_index,
5469 ~0, // invalid fib index
5472 FIB_ROUTE_PATH_FLAG_NONE);
5473 dpo = fib_entry_contribute_ip_forwarding(fei);
5475 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5476 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5477 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5478 FIB_TEST(lbi == dpo->dpoi_index,
5479 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5480 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5481 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5482 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5483 FIB_TEST(lbi == dpo->dpoi_index,
5484 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5486 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5487 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5488 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5489 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5490 local_pfx.fp_len = 32;
5491 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5492 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5495 * modify the export prefix so it is attached. expect all covereds to return
5497 local_pfx.fp_len = 24;
5498 fib_table_entry_update_one_path(fib_index,
5501 FIB_ENTRY_FLAG_NONE,
5504 tm->hw[0]->sw_if_index,
5505 ~0, // invalid fib index
5508 FIB_ROUTE_PATH_FLAG_NONE);
5510 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5511 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5512 dpo = fib_entry_contribute_ip_forwarding(fei);
5513 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5514 "Adj-fib1 is not drop in export");
5515 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5516 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5517 local_pfx.fp_len = 32;
5518 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5519 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5520 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5521 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5522 dpo = fib_entry_contribute_ip_forwarding(fei);
5523 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5524 "Adj-fib1 is not drop 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), "ADJ-fib1 imported");
5527 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5528 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5529 local_pfx.fp_len = 32;
5530 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5531 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5534 * modify the export prefix so connected. no change.
5536 local_pfx.fp_len = 24;
5537 fib_table_entry_update_one_path(fib_index, &local_pfx,
5538 FIB_SOURCE_INTERFACE,
5539 (FIB_ENTRY_FLAG_CONNECTED |
5540 FIB_ENTRY_FLAG_ATTACHED),
5543 tm->hw[0]->sw_if_index,
5547 FIB_ROUTE_PATH_FLAG_NONE);
5549 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5550 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5551 dpo = fib_entry_contribute_ip_forwarding(fei);
5552 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5553 "Adj-fib1 is not drop in export");
5554 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5555 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5556 local_pfx.fp_len = 32;
5557 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5558 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5559 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5560 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5561 dpo = fib_entry_contribute_ip_forwarding(fei);
5562 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5563 "Adj-fib1 is not drop in export");
5564 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5565 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5566 local_pfx.fp_len = 32;
5567 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5568 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5573 fib_table_entry_delete(fib_index,
5576 fib_table_entry_delete(fib_index,
5577 &pfx_10_10_10_1_s_32,
5579 fib_table_entry_delete(fib_index,
5580 &pfx_10_10_10_2_s_32,
5582 local_pfx.fp_len = 32;
5583 fib_table_entry_delete(fib_index,
5585 FIB_SOURCE_INTERFACE);
5586 local_pfx.fp_len = 24;
5587 fib_table_entry_delete(fib_index,
5590 fib_table_entry_delete(fib_index,
5592 FIB_SOURCE_INTERFACE);
5593 local_pfx.fp_len = 24;
5594 fib_table_entry_delete(import_fib_index1,
5598 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5599 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5601 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5608 * Test Path Preference
5611 fib_test_pref (void)
5613 test_main_t *tm = &test_main;
5615 const fib_prefix_t pfx_1_1_1_1_s_32 = {
5617 .fp_proto = FIB_PROTOCOL_IP4,
5620 .as_u32 = clib_host_to_net_u32(0x01010101),
5626 * 2 high, 2 medium and 2 low preference non-recursive paths
5628 fib_route_path_t nr_path_hi_1 = {
5629 .frp_proto = DPO_PROTO_IP4,
5630 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5631 .frp_fib_index = ~0,
5633 .frp_preference = 0,
5634 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5636 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5639 fib_route_path_t nr_path_hi_2 = {
5640 .frp_proto = DPO_PROTO_IP4,
5641 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5642 .frp_fib_index = ~0,
5644 .frp_preference = 0,
5645 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5647 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5650 fib_route_path_t nr_path_med_1 = {
5651 .frp_proto = DPO_PROTO_IP4,
5652 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5653 .frp_fib_index = ~0,
5655 .frp_preference = 1,
5656 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5658 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5661 fib_route_path_t nr_path_med_2 = {
5662 .frp_proto = DPO_PROTO_IP4,
5663 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5664 .frp_fib_index = ~0,
5666 .frp_preference = 1,
5667 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5669 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5672 fib_route_path_t nr_path_low_1 = {
5673 .frp_proto = DPO_PROTO_IP4,
5674 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5675 .frp_fib_index = ~0,
5677 .frp_preference = 2,
5678 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5680 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5683 fib_route_path_t nr_path_low_2 = {
5684 .frp_proto = DPO_PROTO_IP4,
5685 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5686 .frp_fib_index = ~0,
5688 .frp_preference = 2,
5689 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5691 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5694 fib_route_path_t *nr_paths = NULL;
5696 vec_add1(nr_paths, nr_path_hi_1);
5697 vec_add1(nr_paths, nr_path_hi_2);
5698 vec_add1(nr_paths, nr_path_med_1);
5699 vec_add1(nr_paths, nr_path_med_2);
5700 vec_add1(nr_paths, nr_path_low_1);
5701 vec_add1(nr_paths, nr_path_low_2);
5703 adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5705 &nr_path_hi_1.frp_addr,
5706 nr_path_hi_1.frp_sw_if_index);
5707 adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5709 &nr_path_hi_2.frp_addr,
5710 nr_path_hi_2.frp_sw_if_index);
5711 adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5713 &nr_path_med_1.frp_addr,
5714 nr_path_med_1.frp_sw_if_index);
5715 adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5717 &nr_path_med_2.frp_addr,
5718 nr_path_med_2.frp_sw_if_index);
5719 adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5721 &nr_path_low_1.frp_addr,
5722 nr_path_low_1.frp_sw_if_index);
5723 adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5725 &nr_path_low_2.frp_addr,
5726 nr_path_low_2.frp_sw_if_index);
5728 fib_test_lb_bucket_t ip_hi_1 = {
5734 fib_test_lb_bucket_t ip_hi_2 = {
5740 fib_test_lb_bucket_t ip_med_1 = {
5746 fib_test_lb_bucket_t ip_med_2 = {
5752 fib_test_lb_bucket_t ip_low_1 = {
5758 fib_test_lb_bucket_t ip_low_2 = {
5765 fib_node_index_t fei;
5767 fei = fib_table_entry_path_add2(0,
5770 FIB_ENTRY_FLAG_NONE,
5773 FIB_TEST(fib_test_validate_entry(fei,
5774 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5778 "1.1.1.1/32 via high preference paths");
5781 * bring down the interface on which the high preference path lie
5783 vnet_sw_interface_set_flags(vnet_get_main(),
5784 tm->hw[0]->sw_if_index,
5787 FIB_TEST(fib_test_validate_entry(fei,
5788 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5792 "1.1.1.1/32 via medium preference paths");
5795 * bring down the interface on which the medium preference path lie
5797 vnet_sw_interface_set_flags(vnet_get_main(),
5798 tm->hw[1]->sw_if_index,
5801 FIB_TEST(fib_test_validate_entry(fei,
5802 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5806 "1.1.1.1/32 via low preference paths");
5809 * bring up the interface on which the high preference path lie
5811 vnet_sw_interface_set_flags(vnet_get_main(),
5812 tm->hw[0]->sw_if_index,
5813 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5815 FIB_TEST(fib_test_validate_entry(fei,
5816 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5820 "1.1.1.1/32 via high preference paths");
5823 * bring up the interface on which the medium preference path lie
5825 vnet_sw_interface_set_flags(vnet_get_main(),
5826 tm->hw[1]->sw_if_index,
5827 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5829 FIB_TEST(fib_test_validate_entry(fei,
5830 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5834 "1.1.1.1/32 via high preference paths");
5836 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5837 fib_entry_contribute_forwarding(fei,
5838 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5842 * 3 recursive paths of different preference
5844 const fib_prefix_t pfx_1_1_1_2_s_32 = {
5846 .fp_proto = FIB_PROTOCOL_IP4,
5849 .as_u32 = clib_host_to_net_u32(0x01010102),
5853 const fib_prefix_t pfx_1_1_1_3_s_32 = {
5855 .fp_proto = FIB_PROTOCOL_IP4,
5858 .as_u32 = clib_host_to_net_u32(0x01010103),
5862 fei = fib_table_entry_path_add2(0,
5865 FIB_ENTRY_FLAG_NONE,
5867 dpo_id_t ip_1_1_1_2 = DPO_INVALID;
5868 fib_entry_contribute_forwarding(fei,
5869 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5871 fei = fib_table_entry_path_add2(0,
5874 FIB_ENTRY_FLAG_NONE,
5876 dpo_id_t ip_1_1_1_3 = DPO_INVALID;
5877 fib_entry_contribute_forwarding(fei,
5878 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5881 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5884 .lb = ip_1_1_1_1.dpoi_index,
5887 fib_test_lb_bucket_t ip_o_1_1_1_2 = {
5890 .lb = ip_1_1_1_2.dpoi_index,
5893 fib_test_lb_bucket_t ip_o_1_1_1_3 = {
5896 .lb = ip_1_1_1_3.dpoi_index,
5899 fib_route_path_t r_path_hi = {
5900 .frp_proto = DPO_PROTO_IP4,
5901 .frp_sw_if_index = ~0,
5904 .frp_preference = 0,
5905 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5906 .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
5908 fib_route_path_t r_path_med = {
5909 .frp_proto = DPO_PROTO_IP4,
5910 .frp_sw_if_index = ~0,
5913 .frp_preference = 10,
5914 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5915 .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
5917 fib_route_path_t r_path_low = {
5918 .frp_proto = DPO_PROTO_IP4,
5919 .frp_sw_if_index = ~0,
5922 .frp_preference = 255,
5923 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5924 .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
5926 fib_route_path_t *r_paths = NULL;
5928 vec_add1(r_paths, r_path_hi);
5929 vec_add1(r_paths, r_path_low);
5930 vec_add1(r_paths, r_path_med);
5933 * add many recursive so we get the LB MAp created
5936 fib_prefix_t pfx_r[N_PFXS];
5937 unsigned int n_pfxs;
5938 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
5940 pfx_r[n_pfxs].fp_len = 32;
5941 pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
5942 pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
5943 clib_host_to_net_u32(0x02000000 + n_pfxs);
5945 fei = fib_table_entry_path_add2(0,
5948 FIB_ENTRY_FLAG_NONE,
5951 FIB_TEST(fib_test_validate_entry(fei,
5952 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5955 "recursive via high preference paths");
5958 * withdraw hig pref resolving entry
5960 fib_table_entry_delete(0,
5964 /* suspend so the update walk kicks int */
5965 vlib_process_suspend(vlib_get_main(), 1e-5);
5967 FIB_TEST(fib_test_validate_entry(fei,
5968 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5971 "recursive via medium preference paths");
5974 * withdraw medium pref resolving entry
5976 fib_table_entry_delete(0,
5980 /* suspend so the update walk kicks int */
5981 vlib_process_suspend(vlib_get_main(), 1e-5);
5983 FIB_TEST(fib_test_validate_entry(fei,
5984 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5987 "recursive via low preference paths");
5990 * add back paths for next iteration
5992 fei = fib_table_entry_update(0,
5995 FIB_ENTRY_FLAG_NONE,
5997 fei = fib_table_entry_update(0,
6000 FIB_ENTRY_FLAG_NONE,
6003 /* suspend so the update walk kicks int */
6004 vlib_process_suspend(vlib_get_main(), 1e-5);
6006 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6007 FIB_TEST(fib_test_validate_entry(fei,
6008 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6011 "recursive via high preference paths");
6015 fib_table_entry_delete(0,
6019 /* suspend so the update walk kicks int */
6020 vlib_process_suspend(vlib_get_main(), 1e-5);
6022 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6024 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6026 FIB_TEST(fib_test_validate_entry(fei,
6027 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6030 "recursive via medium preference paths");
6032 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6034 fib_table_entry_delete(0,
6042 fib_table_entry_delete(0,
6045 fib_table_entry_delete(0,
6049 dpo_reset(&ip_1_1_1_1);
6050 dpo_reset(&ip_1_1_1_2);
6051 dpo_reset(&ip_1_1_1_3);
6052 adj_unlock(ai_low_2);
6053 adj_unlock(ai_low_1);
6054 adj_unlock(ai_med_2);
6055 adj_unlock(ai_med_1);
6056 adj_unlock(ai_hi_2);
6057 adj_unlock(ai_hi_1);
6062 * Test the recursive route route handling for GRE tunnels
6065 fib_test_label (void)
6067 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;
6068 const u32 fib_index = 0;
6073 lb_count = pool_elts(load_balance_pool);
6078 * add interface routes. We'll assume this works. It's more rigorously
6081 fib_prefix_t local0_pfx = {
6083 .fp_proto = FIB_PROTOCOL_IP4,
6087 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6092 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6095 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6096 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6098 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6099 FIB_SOURCE_INTERFACE,
6100 (FIB_ENTRY_FLAG_CONNECTED |
6101 FIB_ENTRY_FLAG_ATTACHED),
6104 tm->hw[0]->sw_if_index,
6108 FIB_ROUTE_PATH_FLAG_NONE);
6109 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6110 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6111 "attached interface route present");
6113 local0_pfx.fp_len = 32;
6114 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6115 FIB_SOURCE_INTERFACE,
6116 (FIB_ENTRY_FLAG_CONNECTED |
6117 FIB_ENTRY_FLAG_LOCAL),
6120 tm->hw[0]->sw_if_index,
6121 ~0, // invalid fib index
6124 FIB_ROUTE_PATH_FLAG_NONE);
6125 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6127 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6128 "local interface route present");
6130 fib_prefix_t local1_pfx = {
6132 .fp_proto = FIB_PROTOCOL_IP4,
6136 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6141 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6142 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6144 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6145 FIB_SOURCE_INTERFACE,
6146 (FIB_ENTRY_FLAG_CONNECTED |
6147 FIB_ENTRY_FLAG_ATTACHED),
6150 tm->hw[1]->sw_if_index,
6154 FIB_ROUTE_PATH_FLAG_NONE);
6155 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6156 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6157 "attached interface route present");
6159 local1_pfx.fp_len = 32;
6160 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6161 FIB_SOURCE_INTERFACE,
6162 (FIB_ENTRY_FLAG_CONNECTED |
6163 FIB_ENTRY_FLAG_LOCAL),
6166 tm->hw[1]->sw_if_index,
6167 ~0, // invalid fib index
6170 FIB_ROUTE_PATH_FLAG_NONE);
6171 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6173 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6174 "local interface route present");
6176 ip46_address_t nh_10_10_10_1 = {
6178 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6181 ip46_address_t nh_10_10_11_1 = {
6183 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6186 ip46_address_t nh_10_10_11_2 = {
6188 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6192 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6195 tm->hw[1]->sw_if_index);
6196 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6199 tm->hw[1]->sw_if_index);
6200 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6203 tm->hw[0]->sw_if_index);
6204 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6207 tm->hw[1]->sw_if_index);
6208 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6211 tm->hw[1]->sw_if_index);
6214 * Add an etry with one path with a real out-going label
6216 fib_prefix_t pfx_1_1_1_1_s_32 = {
6218 .fp_proto = FIB_PROTOCOL_IP4,
6220 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6223 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6224 .type = FT_LB_LABEL_O_ADJ,
6226 .adj = ai_mpls_10_10_10_1,
6231 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6232 .type = FT_LB_LABEL_O_ADJ,
6234 .adj = ai_mpls_10_10_10_1,
6236 .eos = MPLS_NON_EOS,
6239 mpls_label_t *l99 = NULL;
6242 fib_table_entry_update_one_path(fib_index,
6245 FIB_ENTRY_FLAG_NONE,
6248 tm->hw[0]->sw_if_index,
6249 ~0, // invalid fib index
6252 FIB_ROUTE_PATH_FLAG_NONE);
6254 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6255 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6257 FIB_TEST(fib_test_validate_entry(fei,
6258 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6260 &l99_eos_o_10_10_10_1),
6261 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6264 * add a path with an implicit NULL label
6266 fib_test_lb_bucket_t a_o_10_10_11_1 = {
6269 .adj = ai_v4_10_10_11_1,
6272 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6275 .adj = ai_mpls_10_10_11_1,
6278 mpls_label_t *l_imp_null = NULL;
6279 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6281 fei = fib_table_entry_path_add(fib_index,
6284 FIB_ENTRY_FLAG_NONE,
6287 tm->hw[1]->sw_if_index,
6288 ~0, // invalid fib index
6291 FIB_ROUTE_PATH_FLAG_NONE);
6293 FIB_TEST(fib_test_validate_entry(fei,
6294 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6296 &l99_eos_o_10_10_10_1,
6298 "1.1.1.1/32 LB 2 buckets via: "
6299 "label 99 over 10.10.10.1, "
6300 "adj over 10.10.11.1");
6303 * assign the route a local label
6305 fib_table_entry_local_label_add(fib_index,
6309 fib_prefix_t pfx_24001_eos = {
6310 .fp_proto = FIB_PROTOCOL_MPLS,
6314 fib_prefix_t pfx_24001_neos = {
6315 .fp_proto = FIB_PROTOCOL_MPLS,
6317 .fp_eos = MPLS_NON_EOS,
6321 * The EOS entry should link to both the paths,
6322 * and use an ip adj for the imp-null
6323 * The NON-EOS entry should link to both the paths,
6324 * and use an mpls adj for the imp-null
6326 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6328 FIB_TEST(fib_test_validate_entry(fei,
6329 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6331 &l99_eos_o_10_10_10_1,
6333 "24001/eos LB 2 buckets via: "
6334 "label 99 over 10.10.10.1, "
6335 "adj over 10.10.11.1");
6338 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6340 FIB_TEST(fib_test_validate_entry(fei,
6341 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6343 &l99_neos_o_10_10_10_1,
6344 &a_mpls_o_10_10_11_1),
6345 "24001/neos LB 1 bucket via: "
6346 "label 99 over 10.10.10.1 ",
6347 "mpls-adj via 10.10.11.1");
6350 * add an unlabelled path, this is excluded from the neos chains,
6352 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6355 .adj = ai_v4_10_10_11_2,
6359 fei = fib_table_entry_path_add(fib_index,
6362 FIB_ENTRY_FLAG_NONE,
6365 tm->hw[1]->sw_if_index,
6366 ~0, // invalid fib index
6369 FIB_ROUTE_PATH_FLAG_NONE);
6371 FIB_TEST(fib_test_validate_entry(fei,
6372 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6373 16, // 3 choices spread over 16 buckets
6374 &l99_eos_o_10_10_10_1,
6375 &l99_eos_o_10_10_10_1,
6376 &l99_eos_o_10_10_10_1,
6377 &l99_eos_o_10_10_10_1,
6378 &l99_eos_o_10_10_10_1,
6379 &l99_eos_o_10_10_10_1,
6390 "1.1.1.1/32 LB 16 buckets via: "
6391 "label 99 over 10.10.10.1, "
6392 "adj over 10.10.11.1",
6393 "adj over 10.10.11.2");
6396 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6398 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6399 fib_entry_contribute_forwarding(fei,
6400 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6404 * n-eos has only the 2 labelled paths
6406 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6409 FIB_TEST(fib_test_validate_entry(fei,
6410 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6412 &l99_neos_o_10_10_10_1,
6413 &a_mpls_o_10_10_11_1),
6414 "24001/neos LB 2 buckets via: "
6415 "label 99 over 10.10.10.1, "
6416 "adj-mpls over 10.10.11.2");
6419 * A labelled recursive
6421 fib_prefix_t pfx_2_2_2_2_s_32 = {
6423 .fp_proto = FIB_PROTOCOL_IP4,
6425 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6428 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6429 .type = FT_LB_LABEL_O_LB,
6431 .lb = non_eos_1_1_1_1.dpoi_index,
6436 mpls_label_t *l1600 = NULL;
6437 vec_add1(l1600, 1600);
6439 fib_table_entry_update_one_path(fib_index,
6442 FIB_ENTRY_FLAG_NONE,
6444 &pfx_1_1_1_1_s_32.fp_addr,
6449 FIB_ROUTE_PATH_FLAG_NONE);
6451 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6452 FIB_TEST(fib_test_validate_entry(fei,
6453 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6455 &l1600_eos_o_1_1_1_1),
6456 "2.2.2.2.2/32 LB 1 buckets via: "
6457 "label 1600 over 1.1.1.1");
6459 dpo_id_t dpo_44 = DPO_INVALID;
6462 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6463 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6465 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6466 "uRPF check for 2.2.2.2/32 on %d OK",
6467 tm->hw[0]->sw_if_index);
6468 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6469 "uRPF check for 2.2.2.2/32 on %d OK",
6470 tm->hw[1]->sw_if_index);
6471 FIB_TEST(!fib_urpf_check(urpfi, 99),
6472 "uRPF check for 2.2.2.2/32 on 99 not-OK",
6475 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6476 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6477 "Shared uRPF on IP and non-EOS chain");
6482 * we are holding a lock on the non-eos LB of the via-entry.
6483 * do a PIC-core failover by shutting the link of the via-entry.
6485 * shut down the link with the valid label
6487 vnet_sw_interface_set_flags(vnet_get_main(),
6488 tm->hw[0]->sw_if_index,
6491 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6492 FIB_TEST(fib_test_validate_entry(fei,
6493 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6497 "1.1.1.1/32 LB 2 buckets via: "
6498 "adj over 10.10.11.1, ",
6499 "adj-v4 over 10.10.11.2");
6501 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6503 FIB_TEST(fib_test_validate_entry(fei,
6504 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6508 "24001/eos LB 2 buckets via: "
6509 "adj over 10.10.11.1, ",
6510 "adj-v4 over 10.10.11.2");
6512 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6514 FIB_TEST(fib_test_validate_entry(fei,
6515 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6517 &a_mpls_o_10_10_11_1),
6518 "24001/neos LB 1 buckets via: "
6519 "adj-mpls over 10.10.11.2");
6522 * test that the pre-failover load-balance has been in-place
6525 dpo_id_t current = DPO_INVALID;
6526 fib_entry_contribute_forwarding(fei,
6527 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6530 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6532 "PIC-core LB inplace modified %U %U",
6533 format_dpo_id, &non_eos_1_1_1_1, 0,
6534 format_dpo_id, ¤t, 0);
6536 dpo_reset(&non_eos_1_1_1_1);
6537 dpo_reset(¤t);
6540 * no-shut the link with the valid label
6542 vnet_sw_interface_set_flags(vnet_get_main(),
6543 tm->hw[0]->sw_if_index,
6544 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6546 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6547 FIB_TEST(fib_test_validate_entry(fei,
6548 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6549 16, // 3 choices spread over 16 buckets
6550 &l99_eos_o_10_10_10_1,
6551 &l99_eos_o_10_10_10_1,
6552 &l99_eos_o_10_10_10_1,
6553 &l99_eos_o_10_10_10_1,
6554 &l99_eos_o_10_10_10_1,
6555 &l99_eos_o_10_10_10_1,
6566 "1.1.1.1/32 LB 16 buckets via: "
6567 "label 99 over 10.10.10.1, "
6568 "adj over 10.10.11.1",
6569 "adj-v4 over 10.10.11.2");
6572 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6574 FIB_TEST(fib_test_validate_entry(fei,
6575 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6576 16, // 3 choices spread over 16 buckets
6577 &l99_eos_o_10_10_10_1,
6578 &l99_eos_o_10_10_10_1,
6579 &l99_eos_o_10_10_10_1,
6580 &l99_eos_o_10_10_10_1,
6581 &l99_eos_o_10_10_10_1,
6582 &l99_eos_o_10_10_10_1,
6593 "24001/eos LB 16 buckets via: "
6594 "label 99 over 10.10.10.1, "
6595 "adj over 10.10.11.1",
6596 "adj-v4 over 10.10.11.2");
6598 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6600 FIB_TEST(fib_test_validate_entry(fei,
6601 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6603 &l99_neos_o_10_10_10_1,
6604 &a_mpls_o_10_10_11_1),
6605 "24001/neos LB 2 buckets via: "
6606 "label 99 over 10.10.10.1, "
6607 "adj-mpls over 10.10.11.2");
6610 * remove the first path with the valid label
6612 fib_table_entry_path_remove(fib_index,
6617 tm->hw[0]->sw_if_index,
6618 ~0, // invalid fib index
6620 FIB_ROUTE_PATH_FLAG_NONE);
6622 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6623 FIB_TEST(fib_test_validate_entry(fei,
6624 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6628 "1.1.1.1/32 LB 2 buckets via: "
6629 "adj over 10.10.11.1, "
6630 "adj-v4 over 10.10.11.2");
6632 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6634 FIB_TEST(fib_test_validate_entry(fei,
6635 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6639 "24001/eos LB 2 buckets via: "
6640 "adj over 10.10.11.1, "
6641 "adj-v4 over 10.10.11.2");
6643 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6646 FIB_TEST(fib_test_validate_entry(fei,
6647 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6649 &a_mpls_o_10_10_11_1),
6650 "24001/neos LB 1 buckets via: "
6651 "adj-mpls over 10.10.11.2");
6654 * remove the other path with a valid label
6656 fib_test_lb_bucket_t bucket_drop = {
6657 .type = FT_LB_SPECIAL,
6659 .adj = DPO_PROTO_IP4,
6662 fib_test_lb_bucket_t mpls_bucket_drop = {
6663 .type = FT_LB_SPECIAL,
6665 .adj = DPO_PROTO_MPLS,
6669 fib_table_entry_path_remove(fib_index,
6674 tm->hw[1]->sw_if_index,
6675 ~0, // invalid fib index
6677 FIB_ROUTE_PATH_FLAG_NONE);
6679 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6680 FIB_TEST(fib_test_validate_entry(fei,
6681 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6684 "1.1.1.1/32 LB 1 buckets via: "
6685 "adj over 10.10.11.2");
6687 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6689 FIB_TEST(fib_test_validate_entry(fei,
6690 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6693 "24001/eos LB 1 buckets via: "
6694 "adj over 10.10.11.2");
6696 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6698 FIB_TEST(fib_test_validate_entry(fei,
6699 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6702 "24001/neos LB 1 buckets via: DROP");
6705 * add back the path with the valid label
6710 fib_table_entry_path_add(fib_index,
6713 FIB_ENTRY_FLAG_NONE,
6716 tm->hw[0]->sw_if_index,
6717 ~0, // invalid fib index
6720 FIB_ROUTE_PATH_FLAG_NONE);
6722 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6723 FIB_TEST(fib_test_validate_entry(fei,
6724 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6726 &l99_eos_o_10_10_10_1,
6728 "1.1.1.1/32 LB 2 buckets via: "
6729 "label 99 over 10.10.10.1, "
6730 "adj over 10.10.11.2");
6732 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6734 FIB_TEST(fib_test_validate_entry(fei,
6735 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6737 &l99_eos_o_10_10_10_1,
6739 "24001/eos LB 2 buckets via: "
6740 "label 99 over 10.10.10.1, "
6741 "adj over 10.10.11.2");
6743 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6745 FIB_TEST(fib_test_validate_entry(fei,
6746 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6748 &l99_neos_o_10_10_10_1),
6749 "24001/neos LB 1 buckets via: "
6750 "label 99 over 10.10.10.1");
6753 * change the local label
6755 fib_table_entry_local_label_add(fib_index,
6759 fib_prefix_t pfx_25005_eos = {
6760 .fp_proto = FIB_PROTOCOL_MPLS,
6764 fib_prefix_t pfx_25005_neos = {
6765 .fp_proto = FIB_PROTOCOL_MPLS,
6767 .fp_eos = MPLS_NON_EOS,
6770 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6771 fib_table_lookup(fib_index, &pfx_24001_eos)),
6772 "24001/eos removed after label change");
6773 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6774 fib_table_lookup(fib_index, &pfx_24001_neos)),
6775 "24001/eos removed after label change");
6777 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6779 FIB_TEST(fib_test_validate_entry(fei,
6780 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6782 &l99_eos_o_10_10_10_1,
6784 "25005/eos LB 2 buckets via: "
6785 "label 99 over 10.10.10.1, "
6786 "adj over 10.10.11.2");
6788 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6790 FIB_TEST(fib_test_validate_entry(fei,
6791 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6793 &l99_neos_o_10_10_10_1),
6794 "25005/neos LB 1 buckets via: "
6795 "label 99 over 10.10.10.1");
6798 * remove the local label.
6799 * the check that the MPLS entries are gone is done by the fact the
6800 * MPLS table is no longer present.
6802 fib_table_entry_local_label_remove(fib_index,
6806 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6807 FIB_TEST(fib_test_validate_entry(fei,
6808 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6810 &l99_eos_o_10_10_10_1,
6812 "24001/eos LB 2 buckets via: "
6813 "label 99 over 10.10.10.1, "
6814 "adj over 10.10.11.2");
6816 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6817 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6818 "No more MPLS FIB entries => table removed");
6821 * add another via-entry for the recursive
6823 fib_prefix_t pfx_1_1_1_2_s_32 = {
6825 .fp_proto = FIB_PROTOCOL_IP4,
6827 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6830 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6831 .type = FT_LB_LABEL_O_ADJ,
6833 .adj = ai_mpls_10_10_10_1,
6838 mpls_label_t *l101 = NULL;
6839 vec_add1(l101, 101);
6841 fei = fib_table_entry_update_one_path(fib_index,
6844 FIB_ENTRY_FLAG_NONE,
6847 tm->hw[0]->sw_if_index,
6848 ~0, // invalid fib index
6851 FIB_ROUTE_PATH_FLAG_NONE);
6853 FIB_TEST(fib_test_validate_entry(fei,
6854 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6856 &l101_eos_o_10_10_10_1),
6857 "1.1.1.2/32 LB 1 buckets via: "
6858 "label 101 over 10.10.10.1");
6860 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6861 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6863 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6865 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6867 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6870 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6871 .type = FT_LB_LABEL_O_LB,
6873 .lb = non_eos_1_1_1_2.dpoi_index,
6878 mpls_label_t *l1601 = NULL;
6879 vec_add1(l1601, 1601);
6881 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6883 fei = fib_table_entry_path_add(fib_index,
6886 FIB_ENTRY_FLAG_NONE,
6888 &pfx_1_1_1_2_s_32.fp_addr,
6893 FIB_ROUTE_PATH_FLAG_NONE);
6895 FIB_TEST(fib_test_validate_entry(fei,
6896 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6898 &l1600_eos_o_1_1_1_1,
6899 &l1601_eos_o_1_1_1_2),
6900 "2.2.2.2/32 LB 2 buckets via: "
6901 "label 1600 via 1.1,1.1, "
6902 "label 16001 via 1.1.1.2");
6905 * update the via-entry so it no longer has an imp-null path.
6906 * the LB for the recursive can use an imp-null
6909 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6911 fei = fib_table_entry_update_one_path(fib_index,
6914 FIB_ENTRY_FLAG_NONE,
6917 tm->hw[1]->sw_if_index,
6918 ~0, // invalid fib index
6921 FIB_ROUTE_PATH_FLAG_NONE);
6923 FIB_TEST(fib_test_validate_entry(fei,
6924 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6927 "1.1.1.2/32 LB 1 buckets via: "
6930 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6931 FIB_TEST(fib_test_validate_entry(fei,
6932 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6934 &l1600_eos_o_1_1_1_1,
6935 &l1601_eos_o_1_1_1_2),
6936 "2.2.2.2/32 LB 2 buckets via: "
6937 "label 1600 via 1.1,1.1, "
6938 "label 16001 via 1.1.1.2");
6941 * update the via-entry so it no longer has labelled paths.
6942 * the LB for the recursive should exclue this via form its LB
6944 fei = fib_table_entry_update_one_path(fib_index,
6947 FIB_ENTRY_FLAG_NONE,
6950 tm->hw[1]->sw_if_index,
6951 ~0, // invalid fib index
6954 FIB_ROUTE_PATH_FLAG_NONE);
6956 FIB_TEST(fib_test_validate_entry(fei,
6957 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6960 "1.1.1.2/32 LB 1 buckets via: "
6963 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6964 FIB_TEST(fib_test_validate_entry(fei,
6965 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6967 &l1600_eos_o_1_1_1_1),
6968 "2.2.2.2/32 LB 1 buckets via: "
6969 "label 1600 via 1.1,1.1");
6971 dpo_reset(&non_eos_1_1_1_1);
6972 dpo_reset(&non_eos_1_1_1_2);
6975 * Add a recursive with no out-labels. We expect to use the IP of the via
6977 fib_prefix_t pfx_2_2_2_3_s_32 = {
6979 .fp_proto = FIB_PROTOCOL_IP4,
6981 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6984 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6986 fib_table_entry_update_one_path(fib_index,
6989 FIB_ENTRY_FLAG_NONE,
6991 &pfx_1_1_1_1_s_32.fp_addr,
6996 FIB_ROUTE_PATH_FLAG_NONE);
6998 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7000 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7003 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7006 .lb = ip_1_1_1_1.dpoi_index,
7010 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7011 FIB_TEST(fib_test_validate_entry(fei,
7012 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7015 "2.2.2.2.3/32 LB 1 buckets via: "
7019 * Add a recursive with an imp-null out-label.
7020 * We expect to use the IP of the via
7022 fib_prefix_t pfx_2_2_2_4_s_32 = {
7024 .fp_proto = FIB_PROTOCOL_IP4,
7026 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7030 fib_table_entry_update_one_path(fib_index,
7033 FIB_ENTRY_FLAG_NONE,
7035 &pfx_1_1_1_1_s_32.fp_addr,
7040 FIB_ROUTE_PATH_FLAG_NONE);
7042 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7043 FIB_TEST(fib_test_validate_entry(fei,
7044 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7047 "2.2.2.2.4/32 LB 1 buckets via: "
7050 dpo_reset(&ip_1_1_1_1);
7053 * Create an entry with a deep label stack
7055 fib_prefix_t pfx_2_2_5_5_s_32 = {
7057 .fp_proto = FIB_PROTOCOL_IP4,
7059 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7062 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7063 .type = FT_LB_LABEL_STACK_O_ADJ,
7064 .label_stack_o_adj = {
7065 .adj = ai_mpls_10_10_11_1,
7066 .label_stack_size = 8,
7068 200, 201, 202, 203, 204, 205, 206, 207
7073 mpls_label_t *label_stack = NULL;
7074 vec_validate(label_stack, 7);
7075 for (ii = 0; ii < 8; ii++)
7077 label_stack[ii] = ii + 200;
7080 fei = fib_table_entry_update_one_path(fib_index,
7083 FIB_ENTRY_FLAG_NONE,
7086 tm->hw[1]->sw_if_index,
7087 ~0, // invalid fib index
7090 FIB_ROUTE_PATH_FLAG_NONE);
7092 FIB_TEST(fib_test_validate_entry(fei,
7093 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7095 &ls_eos_o_10_10_10_1),
7096 "2.2.5.5/32 LB 1 buckets via: "
7098 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7103 fib_table_entry_delete(fib_index,
7107 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7108 FIB_TEST(fib_test_validate_entry(fei,
7109 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7111 &l1600_eos_o_1_1_1_1),
7112 "2.2.2.2/32 LB 1 buckets via: "
7113 "label 1600 via 1.1,1.1");
7115 fib_table_entry_delete(fib_index,
7119 FIB_TEST(fib_test_validate_entry(fei,
7120 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7123 "2.2.2.2/32 LB 1 buckets via: DROP");
7125 fib_table_entry_delete(fib_index,
7128 fib_table_entry_delete(fib_index,
7131 fib_table_entry_delete(fib_index,
7135 adj_unlock(ai_mpls_10_10_10_1);
7136 adj_unlock(ai_mpls_10_10_11_2);
7137 adj_unlock(ai_v4_10_10_11_1);
7138 adj_unlock(ai_v4_10_10_11_2);
7139 adj_unlock(ai_mpls_10_10_11_1);
7141 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7144 local0_pfx.fp_len = 32;
7145 fib_table_entry_delete(fib_index,
7147 FIB_SOURCE_INTERFACE);
7148 local0_pfx.fp_len = 24;
7149 fib_table_entry_delete(fib_index,
7151 FIB_SOURCE_INTERFACE);
7152 local1_pfx.fp_len = 32;
7153 fib_table_entry_delete(fib_index,
7155 FIB_SOURCE_INTERFACE);
7156 local1_pfx.fp_len = 24;
7157 fib_table_entry_delete(fib_index,
7159 FIB_SOURCE_INTERFACE);
7162 * +1 for the drop LB in the MPLS tables.
7164 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7165 "Load-balance resources freed %d of %d",
7166 lb_count+1, pool_elts(load_balance_pool));
7171 #define N_TEST_CHILDREN 4
7172 #define PARENT_INDEX 0
7174 typedef struct fib_node_test_t_
7179 fib_node_back_walk_ctx_t *ctxs;
7183 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7185 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7187 #define FOR_EACH_TEST_CHILD(_tc) \
7188 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
7189 ii < N_TEST_CHILDREN+1; \
7190 ii++, (_tc) = &fib_test_nodes[ii])
7193 fib_test_child_get_node (fib_node_index_t index)
7195 return (&fib_test_nodes[index].node);
7198 static int fib_test_walk_spawns_walks;
7200 static fib_node_back_walk_rc_t
7201 fib_test_child_back_walk_notify (fib_node_t *node,
7202 fib_node_back_walk_ctx_t *ctx)
7204 fib_node_test_t *tc = (fib_node_test_t*) node;
7206 vec_add1(tc->ctxs, *ctx);
7208 if (1 == fib_test_walk_spawns_walks)
7209 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7210 if (2 == fib_test_walk_spawns_walks)
7211 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7212 FIB_WALK_PRIORITY_HIGH, ctx);
7214 return (FIB_NODE_BACK_WALK_CONTINUE);
7218 fib_test_child_last_lock_gone (fib_node_t *node)
7220 fib_node_test_t *tc = (fib_node_test_t *)node;
7226 * The FIB walk's graph node virtual function table
7228 static const fib_node_vft_t fib_test_child_vft = {
7229 .fnv_get = fib_test_child_get_node,
7230 .fnv_last_lock = fib_test_child_last_lock_gone,
7231 .fnv_back_walk = fib_test_child_back_walk_notify,
7235 * the function (that should have been static but isn't so I can do this)
7236 * that processes the walk from the async queue,
7238 f64 fib_walk_process_queues(vlib_main_t * vm,
7240 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7243 fib_test_walk (void)
7245 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7246 fib_node_test_t *tc;
7250 vm = vlib_get_main();
7251 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7254 * init a fake node on which we will add children
7256 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7257 FIB_NODE_TYPE_TEST);
7259 FOR_EACH_TEST_CHILD(tc)
7261 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7262 fib_node_lock(&tc->node);
7265 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7267 FIB_NODE_TYPE_TEST, ii);
7271 * enqueue a walk across the parents children.
7273 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7275 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7276 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7277 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7278 "Parent has %d children pre-walk",
7279 fib_node_list_get_size(PARENT()->fn_children));
7282 * give the walk a large amount of time so it gets to the end
7284 fib_walk_process_queues(vm, 1);
7286 FOR_EACH_TEST_CHILD(tc)
7288 FIB_TEST(1 == vec_len(tc->ctxs),
7289 "%d child visitsed %d times",
7290 ii, vec_len(tc->ctxs));
7293 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7294 "Queue is empty post walk");
7295 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7296 "Parent has %d children post walk",
7297 fib_node_list_get_size(PARENT()->fn_children));
7300 * walk again. should be no increase in the number of visits, since
7301 * the walk will have terminated.
7303 fib_walk_process_queues(vm, 1);
7305 FOR_EACH_TEST_CHILD(tc)
7307 FIB_TEST(0 == vec_len(tc->ctxs),
7308 "%d child visitsed %d times",
7309 ii, vec_len(tc->ctxs));
7313 * schedule a low and hig priority walk. expect the high to be performed
7315 * schedule the high prio walk first so that it is further from the head
7316 * of the dependency list. that way it won't merge with the low one.
7318 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7319 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7321 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7322 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7323 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7324 FIB_WALK_PRIORITY_LOW, &low_ctx);
7326 fib_walk_process_queues(vm, 1);
7328 FOR_EACH_TEST_CHILD(tc)
7330 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7331 "%d child visitsed by high prio walk", ii);
7332 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7333 "%d child visitsed by low prio walk", ii);
7336 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7337 "Queue is empty post prio walk");
7338 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7339 "Parent has %d children post prio walk",
7340 fib_node_list_get_size(PARENT()->fn_children));
7343 * schedule 2 walks of the same priority that can be megred.
7344 * expect that each child is thus visited only once.
7346 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7347 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7349 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7350 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7351 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7352 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7354 fib_walk_process_queues(vm, 1);
7356 FOR_EACH_TEST_CHILD(tc)
7358 FIB_TEST(1 == vec_len(tc->ctxs),
7359 "%d child visitsed %d times during merge walk",
7360 ii, vec_len(tc->ctxs));
7363 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7364 "Queue is empty post merge walk");
7365 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7366 "Parent has %d children post merge walk",
7367 fib_node_list_get_size(PARENT()->fn_children));
7370 * schedule 2 walks of the same priority that cannot be megred.
7371 * expect that each child is thus visited twice and in the order
7372 * in which the walks were scheduled.
7374 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7375 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7377 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7378 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7379 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7380 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7382 fib_walk_process_queues(vm, 1);
7384 FOR_EACH_TEST_CHILD(tc)
7386 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7387 "%d child visitsed by high prio walk", ii);
7388 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7389 "%d child visitsed by low prio walk", ii);
7392 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7393 "Queue is empty post no-merge walk");
7394 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7395 "Parent has %d children post no-merge walk",
7396 fib_node_list_get_size(PARENT()->fn_children));
7399 * schedule a walk that makes one one child progress.
7400 * we do this by giving the queue draining process zero
7401 * time quanta. it's a do..while loop, so it does something.
7403 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7405 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7406 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7407 fib_walk_process_queues(vm, 0);
7409 FOR_EACH_TEST_CHILD(tc)
7411 if (ii == N_TEST_CHILDREN)
7413 FIB_TEST(1 == vec_len(tc->ctxs),
7414 "%d child visitsed %d times in zero quanta walk",
7415 ii, vec_len(tc->ctxs));
7419 FIB_TEST(0 == vec_len(tc->ctxs),
7420 "%d child visitsed %d times in 0 quanta walk",
7421 ii, vec_len(tc->ctxs));
7424 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7425 "Queue is not empty post zero quanta walk");
7426 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7427 "Parent has %d children post zero qunta walk",
7428 fib_node_list_get_size(PARENT()->fn_children));
7433 fib_walk_process_queues(vm, 0);
7435 FOR_EACH_TEST_CHILD(tc)
7437 if (ii >= N_TEST_CHILDREN-1)
7439 FIB_TEST(1 == vec_len(tc->ctxs),
7440 "%d child visitsed %d times in 2nd zero quanta walk",
7441 ii, vec_len(tc->ctxs));
7445 FIB_TEST(0 == vec_len(tc->ctxs),
7446 "%d child visitsed %d times in 2nd 0 quanta walk",
7447 ii, vec_len(tc->ctxs));
7450 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7451 "Queue is not empty post zero quanta walk");
7452 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7453 "Parent has %d children post zero qunta walk",
7454 fib_node_list_get_size(PARENT()->fn_children));
7457 * schedule another walk that will catch-up and merge.
7459 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7460 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7461 fib_walk_process_queues(vm, 1);
7463 FOR_EACH_TEST_CHILD(tc)
7465 if (ii >= N_TEST_CHILDREN-1)
7467 FIB_TEST(2 == vec_len(tc->ctxs),
7468 "%d child visitsed %d times in 2nd zero quanta merge walk",
7469 ii, vec_len(tc->ctxs));
7474 FIB_TEST(1 == vec_len(tc->ctxs),
7475 "%d child visitsed %d times in 2nd 0 quanta merge walk",
7476 ii, vec_len(tc->ctxs));
7480 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7481 "Queue is not empty post 2nd zero quanta merge walk");
7482 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7483 "Parent has %d children post 2nd zero qunta merge walk",
7484 fib_node_list_get_size(PARENT()->fn_children));
7487 * park a async walk in the middle of the list, then have an sync walk catch
7488 * it. same expectations as async catches async.
7490 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7492 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7493 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7495 fib_walk_process_queues(vm, 0);
7496 fib_walk_process_queues(vm, 0);
7498 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7500 FOR_EACH_TEST_CHILD(tc)
7502 if (ii >= N_TEST_CHILDREN-1)
7504 FIB_TEST(2 == vec_len(tc->ctxs),
7505 "%d child visitsed %d times in sync catches async walk",
7506 ii, vec_len(tc->ctxs));
7511 FIB_TEST(1 == vec_len(tc->ctxs),
7512 "%d child visitsed %d times in sync catches async walk",
7513 ii, vec_len(tc->ctxs));
7517 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7518 "Queue is not empty post 2nd zero quanta merge walk");
7519 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7520 "Parent has %d children post 2nd zero qunta merge walk",
7521 fib_node_list_get_size(PARENT()->fn_children));
7524 * make the parent a child of one of its children, thus inducing a routing loop.
7526 fib_test_nodes[PARENT_INDEX].sibling =
7527 fib_node_child_add(FIB_NODE_TYPE_TEST,
7528 1, // the first child
7533 * execute a sync walk from the parent. each child visited spawns more sync
7534 * walks. we expect the walk to terminate.
7536 fib_test_walk_spawns_walks = 1;
7538 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7540 FOR_EACH_TEST_CHILD(tc)
7543 * child 1 - which is last in the list - has the loop.
7544 * the other children a re thus visitsed first. the we meet
7545 * child 1. we go round the loop again, visting the other children.
7546 * then we meet the walk in the dep list and bail. child 1 is not visitsed
7551 FIB_TEST(1 == vec_len(tc->ctxs),
7552 "child %d visitsed %d times during looped sync walk",
7553 ii, vec_len(tc->ctxs));
7557 FIB_TEST(2 == vec_len(tc->ctxs),
7558 "child %d visitsed %d times during looped sync walk",
7559 ii, vec_len(tc->ctxs));
7563 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7564 "Parent has %d children post sync loop walk",
7565 fib_node_list_get_size(PARENT()->fn_children));
7568 * the walk doesn't reach the max depth because the infra knows that sync
7569 * meets sync implies a loop and bails early.
7571 FIB_TEST(high_ctx.fnbw_depth == 9,
7572 "Walk context depth %d post sync loop walk",
7573 high_ctx.fnbw_depth);
7576 * execute an async walk of the graph loop, with each child spawns sync walks
7578 high_ctx.fnbw_depth = 0;
7579 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7580 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7582 fib_walk_process_queues(vm, 1);
7584 FOR_EACH_TEST_CHILD(tc)
7587 * we don't really care how many times the children are visisted, as long as
7588 * it is more than once.
7590 FIB_TEST(1 <= vec_len(tc->ctxs),
7591 "child %d visitsed %d times during looped aync spawns sync walk",
7592 ii, vec_len(tc->ctxs));
7597 * execute an async walk of the graph loop, with each child spawns async walks
7599 fib_test_walk_spawns_walks = 2;
7600 high_ctx.fnbw_depth = 0;
7601 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7602 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7604 fib_walk_process_queues(vm, 1);
7606 FOR_EACH_TEST_CHILD(tc)
7609 * we don't really care how many times the children are visisted, as long as
7610 * it is more than once.
7612 FIB_TEST(1 <= vec_len(tc->ctxs),
7613 "child %d visitsed %d times during looped async spawns async walk",
7614 ii, vec_len(tc->ctxs));
7619 fib_node_child_remove(FIB_NODE_TYPE_TEST,
7620 1, // the first child
7621 fib_test_nodes[PARENT_INDEX].sibling);
7626 FOR_EACH_TEST_CHILD(tc)
7628 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7630 fib_node_deinit(&tc->node);
7631 fib_node_unlock(&tc->node);
7633 fib_node_deinit(PARENT());
7636 * The parent will be destroyed when the last lock on it goes.
7637 * this test ensures all the walk objects are unlocking it.
7639 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7640 "Parent was destroyed");
7646 * declaration of the otherwise static callback functions
7648 void fib_bfd_notify (bfd_listen_event_e event,
7649 const bfd_session_t *session);
7650 void adj_bfd_notify (bfd_listen_event_e event,
7651 const bfd_session_t *session);
7654 * Test BFD session interaction with FIB
7659 fib_node_index_t fei;
7663 /* via 10.10.10.1 */
7664 ip46_address_t nh_10_10_10_1 = {
7665 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7667 /* via 10.10.10.2 */
7668 ip46_address_t nh_10_10_10_2 = {
7669 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7671 /* via 10.10.10.10 */
7672 ip46_address_t nh_10_10_10_10 = {
7673 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7675 n_feis = fib_entry_pool_size();
7680 * add interface routes. we'll assume this works. it's tested elsewhere
7682 fib_prefix_t pfx_10_10_10_10_s_24 = {
7684 .fp_proto = FIB_PROTOCOL_IP4,
7685 .fp_addr = nh_10_10_10_10,
7688 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7689 FIB_SOURCE_INTERFACE,
7690 (FIB_ENTRY_FLAG_CONNECTED |
7691 FIB_ENTRY_FLAG_ATTACHED),
7694 tm->hw[0]->sw_if_index,
7695 ~0, // invalid fib index
7698 FIB_ROUTE_PATH_FLAG_NONE);
7700 fib_prefix_t pfx_10_10_10_10_s_32 = {
7702 .fp_proto = FIB_PROTOCOL_IP4,
7703 .fp_addr = nh_10_10_10_10,
7705 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7706 FIB_SOURCE_INTERFACE,
7707 (FIB_ENTRY_FLAG_CONNECTED |
7708 FIB_ENTRY_FLAG_LOCAL),
7711 tm->hw[0]->sw_if_index,
7712 ~0, // invalid fib index
7715 FIB_ROUTE_PATH_FLAG_NONE);
7718 * A BFD session via a neighbour we do not yet know
7720 bfd_session_t bfd_10_10_10_1 = {
7724 .peer_addr = nh_10_10_10_1,
7727 .hop_type = BFD_HOP_TYPE_MULTI,
7728 .local_state = BFD_STATE_init,
7731 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7734 * A new entry will be created that forwards via the adj
7736 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7739 tm->hw[0]->sw_if_index);
7740 fib_prefix_t pfx_10_10_10_1_s_32 = {
7741 .fp_addr = nh_10_10_10_1,
7743 .fp_proto = FIB_PROTOCOL_IP4,
7745 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7748 .adj = ai_10_10_10_1,
7752 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7753 FIB_TEST(fib_test_validate_entry(fei,
7754 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7757 "BFD sourced %U via %U",
7758 format_fib_prefix, &pfx_10_10_10_1_s_32,
7759 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7762 * Delete the BFD session. Expect the fib_entry to be removed
7764 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7766 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7767 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7768 "BFD sourced %U removed",
7769 format_fib_prefix, &pfx_10_10_10_1_s_32);
7772 * Add the BFD source back
7774 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7777 * source the entry via the ADJ fib
7779 fei = fib_table_entry_path_add(0,
7780 &pfx_10_10_10_1_s_32,
7782 FIB_ENTRY_FLAG_ATTACHED,
7785 tm->hw[0]->sw_if_index,
7786 ~0, // invalid fib index
7789 FIB_ROUTE_PATH_FLAG_NONE);
7792 * Delete the BFD session. Expect the fib_entry to remain
7794 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7796 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7797 FIB_TEST(fib_test_validate_entry(fei,
7798 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7801 "BFD sourced %U remains via %U",
7802 format_fib_prefix, &pfx_10_10_10_1_s_32,
7803 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7806 * Add the BFD source back
7808 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7811 * Create another ADJ FIB
7813 fib_prefix_t pfx_10_10_10_2_s_32 = {
7814 .fp_addr = nh_10_10_10_2,
7816 .fp_proto = FIB_PROTOCOL_IP4,
7818 fib_table_entry_path_add(0,
7819 &pfx_10_10_10_2_s_32,
7821 FIB_ENTRY_FLAG_ATTACHED,
7824 tm->hw[0]->sw_if_index,
7825 ~0, // invalid fib index
7828 FIB_ROUTE_PATH_FLAG_NONE);
7830 * A BFD session for the new ADJ FIB
7832 bfd_session_t bfd_10_10_10_2 = {
7836 .peer_addr = nh_10_10_10_2,
7839 .hop_type = BFD_HOP_TYPE_MULTI,
7840 .local_state = BFD_STATE_init,
7843 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7846 * remove the adj-fib source whilst the session is present
7849 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7850 fib_table_entry_path_add(0,
7851 &pfx_10_10_10_2_s_32,
7853 FIB_ENTRY_FLAG_ATTACHED,
7856 tm->hw[0]->sw_if_index,
7857 ~0, // invalid fib index
7860 FIB_ROUTE_PATH_FLAG_NONE);
7863 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7864 * bring one of the sessions UP, leave the other down
7866 bfd_10_10_10_1.local_state = BFD_STATE_up;
7867 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7868 bfd_10_10_10_2.local_state = BFD_STATE_down;
7869 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7872 * A recursive prefix via both of the ADJ FIBs
7874 fib_prefix_t pfx_200_0_0_0_s_24 = {
7875 .fp_proto = FIB_PROTOCOL_IP4,
7878 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7881 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7884 fib_entry_contribute_ip_forwarding(
7885 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7887 fib_entry_contribute_ip_forwarding(
7888 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7890 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7893 .lb = dpo_10_10_10_1->dpoi_index,
7896 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7899 .lb = dpo_10_10_10_2->dpoi_index,
7904 * A prefix via the adj-fib that is BFD down => DROP
7906 fei = fib_table_entry_path_add(0,
7907 &pfx_200_0_0_0_s_24,
7909 FIB_ENTRY_FLAG_NONE,
7913 0, // default fib index
7916 FIB_ROUTE_PATH_FLAG_NONE);
7917 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7918 "%U resolves via drop",
7919 format_fib_prefix, &pfx_200_0_0_0_s_24);
7922 * add a path via the UP BFD adj-fib.
7923 * we expect that the DOWN BFD ADJ FIB is not used.
7925 fei = fib_table_entry_path_add(0,
7926 &pfx_200_0_0_0_s_24,
7928 FIB_ENTRY_FLAG_NONE,
7932 0, // default fib index
7935 FIB_ROUTE_PATH_FLAG_NONE);
7937 FIB_TEST(fib_test_validate_entry(fei,
7938 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7941 "Recursive %U only UP BFD adj-fibs",
7942 format_fib_prefix, &pfx_200_0_0_0_s_24);
7945 * Send a BFD state change to UP - both sessions are now up
7946 * the recursive prefix should LB over both
7948 bfd_10_10_10_2.local_state = BFD_STATE_up;
7949 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7952 FIB_TEST(fib_test_validate_entry(fei,
7953 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7957 "Recursive %U via both UP BFD adj-fibs",
7958 format_fib_prefix, &pfx_200_0_0_0_s_24);
7961 * Send a BFD state change to DOWN
7962 * the recursive prefix should exclude the down
7964 bfd_10_10_10_2.local_state = BFD_STATE_down;
7965 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7968 FIB_TEST(fib_test_validate_entry(fei,
7969 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7972 "Recursive %U via only UP",
7973 format_fib_prefix, &pfx_200_0_0_0_s_24);
7976 * Delete the BFD session while it is in the DOWN state.
7977 * FIB should consider the entry's state as back up
7979 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
7981 FIB_TEST(fib_test_validate_entry(fei,
7982 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7986 "Recursive %U via both UP BFD adj-fibs post down session delete",
7987 format_fib_prefix, &pfx_200_0_0_0_s_24);
7990 * Delete the BFD other session while it is in the UP state.
7992 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7994 FIB_TEST(fib_test_validate_entry(fei,
7995 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7999 "Recursive %U via both UP BFD adj-fibs post up session delete",
8000 format_fib_prefix, &pfx_200_0_0_0_s_24);
8005 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8006 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8007 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8009 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8010 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8012 adj_unlock(ai_10_10_10_1);
8014 * test no-one left behind
8016 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8017 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8020 * Single-hop BFD tests
8022 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8023 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8025 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8027 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8030 tm->hw[0]->sw_if_index);
8032 * whilst the BFD session is not signalled, the adj is up
8034 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
8037 * bring the BFD session up
8039 bfd_10_10_10_1.local_state = BFD_STATE_up;
8040 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8041 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8044 * bring the BFD session down
8046 bfd_10_10_10_1.local_state = BFD_STATE_down;
8047 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8048 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8052 * add an attached next hop FIB entry via the down adj
8054 fib_prefix_t pfx_5_5_5_5_s_32 = {
8057 .as_u32 = clib_host_to_net_u32(0x05050505),
8061 .fp_proto = FIB_PROTOCOL_IP4,
8064 fei = fib_table_entry_path_add(0,
8067 FIB_ENTRY_FLAG_NONE,
8070 tm->hw[0]->sw_if_index,
8071 ~0, // invalid fib index
8074 FIB_ROUTE_PATH_FLAG_NONE);
8075 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8076 "%U resolves via drop",
8077 format_fib_prefix, &pfx_5_5_5_5_s_32);
8080 * Add a path via an ADJ that is up
8082 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8085 tm->hw[0]->sw_if_index);
8087 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8090 .adj = ai_10_10_10_2,
8093 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8095 fei = fib_table_entry_path_add(0,
8098 FIB_ENTRY_FLAG_NONE,
8101 tm->hw[0]->sw_if_index,
8102 ~0, // invalid fib index
8105 FIB_ROUTE_PATH_FLAG_NONE);
8107 FIB_TEST(fib_test_validate_entry(fei,
8108 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8111 "BFD sourced %U via %U",
8112 format_fib_prefix, &pfx_5_5_5_5_s_32,
8113 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8116 * Bring up the down session - should now LB
8118 bfd_10_10_10_1.local_state = BFD_STATE_up;
8119 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8120 FIB_TEST(fib_test_validate_entry(fei,
8121 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8125 "BFD sourced %U via noth adjs",
8126 format_fib_prefix, &pfx_5_5_5_5_s_32);
8129 * remove the BFD session state from the adj
8131 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8136 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8137 adj_unlock(ai_10_10_10_1);
8138 adj_unlock(ai_10_10_10_2);
8141 * test no-one left behind
8143 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8144 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8151 const mpls_label_t deag_label = 50;
8152 const u32 lfib_index = 0;
8153 const u32 fib_index = 0;
8154 dpo_id_t dpo = DPO_INVALID;
8155 const dpo_id_t *dpo1;
8156 fib_node_index_t lfe;
8160 adj_index_t ai_mpls_10_10_10_1;
8163 lb_count = pool_elts(load_balance_pool);
8165 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8169 * MPLS enable an interface so we get the MPLS table created
8171 mpls_sw_interface_enable_disable(&mpls_main,
8172 tm->hw[0]->sw_if_index,
8175 ip46_address_t nh_10_10_10_1 = {
8176 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8178 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8181 tm->hw[0]->sw_if_index);
8184 * Test the specials stack properly.
8186 fib_prefix_t exp_null_v6_pfx = {
8187 .fp_proto = FIB_PROTOCOL_MPLS,
8189 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8190 .fp_payload_proto = DPO_PROTO_IP6,
8192 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8193 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8195 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8196 format_mpls_eos_bit, MPLS_EOS);
8197 fib_entry_contribute_forwarding(lfe,
8198 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8200 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8201 lkd = lookup_dpo_get(dpo1->dpoi_index);
8203 FIB_TEST((fib_index == lkd->lkd_fib_index),
8204 "%U/%U is deag in %d %U",
8205 format_mpls_unicast_label, deag_label,
8206 format_mpls_eos_bit, MPLS_EOS,
8208 format_dpo_id, &dpo, 0);
8209 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8210 "%U/%U is dst deag",
8211 format_mpls_unicast_label, deag_label,
8212 format_mpls_eos_bit, MPLS_EOS);
8213 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8214 "%U/%U is lookup in interface's table",
8215 format_mpls_unicast_label, deag_label,
8216 format_mpls_eos_bit, MPLS_EOS);
8217 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8218 "%U/%U is %U dst deag",
8219 format_mpls_unicast_label, deag_label,
8220 format_mpls_eos_bit, MPLS_EOS,
8221 format_dpo_proto, lkd->lkd_proto);
8225 * A route deag route for EOS
8227 fib_prefix_t pfx = {
8228 .fp_proto = FIB_PROTOCOL_MPLS,
8230 .fp_label = deag_label,
8231 .fp_payload_proto = DPO_PROTO_IP4,
8233 lfe = fib_table_entry_path_add(lfib_index,
8236 FIB_ENTRY_FLAG_NONE,
8243 FIB_ROUTE_PATH_FLAG_NONE);
8245 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8247 format_mpls_unicast_label, deag_label,
8248 format_mpls_eos_bit, MPLS_EOS);
8250 fib_entry_contribute_forwarding(lfe,
8251 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8253 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8254 lkd = lookup_dpo_get(dpo1->dpoi_index);
8256 FIB_TEST((fib_index == lkd->lkd_fib_index),
8257 "%U/%U is deag in %d %U",
8258 format_mpls_unicast_label, deag_label,
8259 format_mpls_eos_bit, MPLS_EOS,
8261 format_dpo_id, &dpo, 0);
8262 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8263 "%U/%U is dst deag",
8264 format_mpls_unicast_label, deag_label,
8265 format_mpls_eos_bit, MPLS_EOS);
8266 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8267 "%U/%U is %U dst deag",
8268 format_mpls_unicast_label, deag_label,
8269 format_mpls_eos_bit, MPLS_EOS,
8270 format_dpo_proto, lkd->lkd_proto);
8272 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8274 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8276 "%U/%U not present",
8277 format_mpls_unicast_label, deag_label,
8278 format_mpls_eos_bit, MPLS_EOS);
8281 * A route deag route for non-EOS
8283 pfx.fp_eos = MPLS_NON_EOS;
8284 lfe = fib_table_entry_path_add(lfib_index,
8287 FIB_ENTRY_FLAG_NONE,
8294 FIB_ROUTE_PATH_FLAG_NONE);
8296 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8298 format_mpls_unicast_label, deag_label,
8299 format_mpls_eos_bit, MPLS_NON_EOS);
8301 fib_entry_contribute_forwarding(lfe,
8302 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8304 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8305 lkd = lookup_dpo_get(dpo1->dpoi_index);
8307 FIB_TEST((fib_index == lkd->lkd_fib_index),
8308 "%U/%U is deag in %d %U",
8309 format_mpls_unicast_label, deag_label,
8310 format_mpls_eos_bit, MPLS_NON_EOS,
8312 format_dpo_id, &dpo, 0);
8313 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8314 "%U/%U is dst deag",
8315 format_mpls_unicast_label, deag_label,
8316 format_mpls_eos_bit, MPLS_NON_EOS);
8318 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8319 "%U/%U is %U dst deag",
8320 format_mpls_unicast_label, deag_label,
8321 format_mpls_eos_bit, MPLS_NON_EOS,
8322 format_dpo_proto, lkd->lkd_proto);
8324 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8326 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8328 "%U/%U not present",
8329 format_mpls_unicast_label, deag_label,
8330 format_mpls_eos_bit, MPLS_EOS);
8337 fib_prefix_t pfx_1200 = {
8339 .fp_proto = FIB_PROTOCOL_MPLS,
8341 .fp_eos = MPLS_NON_EOS,
8343 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8344 .type = FT_LB_LABEL_STACK_O_ADJ,
8345 .label_stack_o_adj = {
8346 .adj = ai_mpls_10_10_10_1,
8347 .label_stack_size = 4,
8351 .eos = MPLS_NON_EOS,
8354 dpo_id_t neos_1200 = DPO_INVALID;
8355 dpo_id_t ip_1200 = DPO_INVALID;
8356 mpls_label_t *l200 = NULL;
8357 vec_add1(l200, 200);
8358 vec_add1(l200, 300);
8359 vec_add1(l200, 400);
8360 vec_add1(l200, 500);
8362 lfe = fib_table_entry_update_one_path(fib_index,
8365 FIB_ENTRY_FLAG_NONE,
8368 tm->hw[0]->sw_if_index,
8369 ~0, // invalid fib index
8372 FIB_ROUTE_PATH_FLAG_NONE);
8374 FIB_TEST(fib_test_validate_entry(lfe,
8375 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8377 &neos_o_10_10_10_1),
8378 "1200/0 LB 1 buckets via: "
8382 * A recursive route via the MPLS x-connect
8384 fib_prefix_t pfx_2_2_2_3_s_32 = {
8386 .fp_proto = FIB_PROTOCOL_IP4,
8388 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8391 fib_route_path_t *rpaths = NULL, rpath = {
8392 .frp_proto = DPO_PROTO_MPLS,
8393 .frp_local_label = 1200,
8394 .frp_eos = MPLS_NON_EOS,
8395 .frp_sw_if_index = ~0, // recurive
8396 .frp_fib_index = 0, // Default MPLS fib
8398 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8399 .frp_label_stack = NULL,
8401 vec_add1(rpaths, rpath);
8403 fib_table_entry_path_add2(fib_index,
8406 FIB_ENTRY_FLAG_NONE,
8410 * A labelled recursive route via the MPLS x-connect
8412 fib_prefix_t pfx_2_2_2_4_s_32 = {
8414 .fp_proto = FIB_PROTOCOL_IP4,
8416 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8419 mpls_label_t *l999 = NULL;
8420 vec_add1(l999, 999);
8421 rpaths[0].frp_label_stack = l999,
8423 fib_table_entry_path_add2(fib_index,
8426 FIB_ENTRY_FLAG_NONE,
8429 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8430 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8432 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8433 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8436 fib_test_lb_bucket_t ip_o_1200 = {
8439 .lb = ip_1200.dpoi_index,
8442 fib_test_lb_bucket_t mpls_o_1200 = {
8443 .type = FT_LB_LABEL_O_LB,
8445 .lb = neos_1200.dpoi_index,
8451 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8452 FIB_TEST(fib_test_validate_entry(lfe,
8453 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8456 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8457 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8458 FIB_TEST(fib_test_validate_entry(lfe,
8459 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8462 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8464 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8465 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8466 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8468 dpo_reset(&neos_1200);
8469 dpo_reset(&ip_1200);
8472 * A recursive via a label that does not exist
8474 fib_test_lb_bucket_t bucket_drop = {
8475 .type = FT_LB_SPECIAL,
8477 .adj = DPO_PROTO_IP4,
8480 fib_test_lb_bucket_t mpls_bucket_drop = {
8481 .type = FT_LB_SPECIAL,
8483 .adj = DPO_PROTO_MPLS,
8487 rpaths[0].frp_label_stack = NULL;
8488 lfe = fib_table_entry_path_add2(fib_index,
8491 FIB_ENTRY_FLAG_NONE,
8494 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8495 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8497 ip_o_1200.lb.lb = ip_1200.dpoi_index;
8499 FIB_TEST(fib_test_validate_entry(lfe,
8500 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8503 "2.2.2.2.4/32 LB 1 buckets via: drop");
8504 lfe = fib_table_lookup(fib_index, &pfx_1200);
8505 FIB_TEST(fib_test_validate_entry(lfe,
8506 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8509 "1200/neos LB 1 buckets via: ip4-DROP");
8510 FIB_TEST(fib_test_validate_entry(lfe,
8511 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8514 "1200/neos LB 1 buckets via: mpls-DROP");
8516 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8518 dpo_reset(&ip_1200);
8521 * An rx-interface route.
8522 * like the tail of an mcast LSP
8524 dpo_id_t idpo = DPO_INVALID;
8526 interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8527 tm->hw[0]->sw_if_index,
8530 fib_prefix_t pfx_2500 = {
8532 .fp_proto = FIB_PROTOCOL_MPLS,
8535 .fp_payload_proto = DPO_PROTO_IP4,
8537 fib_test_lb_bucket_t rx_intf_0 = {
8540 .adj = idpo.dpoi_index,
8544 lfe = fib_table_entry_update_one_path(fib_index,
8547 FIB_ENTRY_FLAG_NONE,
8550 tm->hw[0]->sw_if_index,
8551 ~0, // invalid fib index
8554 FIB_ROUTE_PATH_INTF_RX);
8555 FIB_TEST(fib_test_validate_entry(lfe,
8556 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8559 "2500 rx-interface 0");
8560 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8563 * An MPLS mulicast entry
8565 fib_prefix_t pfx_3500 = {
8567 .fp_proto = FIB_PROTOCOL_MPLS,
8570 .fp_payload_proto = DPO_PROTO_IP4,
8572 fib_test_rep_bucket_t mc_0 = {
8573 .type = FT_REP_LABEL_O_ADJ,
8575 .adj = ai_mpls_10_10_10_1,
8580 fib_test_rep_bucket_t mc_intf_0 = {
8581 .type = FT_REP_INTF,
8583 .adj = idpo.dpoi_index,
8586 mpls_label_t *l3300 = NULL;
8587 vec_add1(l3300, 3300);
8589 lfe = fib_table_entry_update_one_path(lfib_index,
8592 FIB_ENTRY_FLAG_MULTICAST,
8595 tm->hw[0]->sw_if_index,
8596 ~0, // invalid fib index
8599 FIB_ROUTE_PATH_FLAG_NONE);
8600 FIB_TEST(fib_test_validate_entry(lfe,
8601 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8604 "3500 via replicate over 10.10.10.1");
8607 * MPLS Bud-node. Add a replication via an interface-receieve path
8609 lfe = fib_table_entry_path_add(lfib_index,
8612 FIB_ENTRY_FLAG_MULTICAST,
8615 tm->hw[0]->sw_if_index,
8616 ~0, // invalid fib index
8619 FIB_ROUTE_PATH_INTF_RX);
8620 FIB_TEST(fib_test_validate_entry(lfe,
8621 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8625 "3500 via replicate over 10.10.10.1 and interface-rx");
8628 * Add a replication via an interface-free for-us path
8630 fib_test_rep_bucket_t mc_disp = {
8631 .type = FT_REP_DISP_MFIB_LOOKUP,
8633 .adj = idpo.dpoi_index,
8636 lfe = fib_table_entry_path_add(lfib_index,
8639 FIB_ENTRY_FLAG_MULTICAST,
8646 FIB_ROUTE_PATH_RPF_ID);
8647 FIB_TEST(fib_test_validate_entry(lfe,
8648 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8653 "3500 via replicate over 10.10.10.1 and interface-rx");
8657 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8663 mpls_sw_interface_enable_disable(&mpls_main,
8664 tm->hw[0]->sw_if_index,
8667 FIB_TEST(lb_count == pool_elts(load_balance_pool),
8668 "Load-balance resources freed %d of %d",
8669 lb_count, pool_elts(load_balance_pool));
8670 FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
8671 "interface_rx_dpo resources freed %d of %d",
8672 0, pool_elts(interface_rx_dpo_pool));
8677 static clib_error_t *
8678 fib_test (vlib_main_t * vm,
8679 unformat_input_t * input,
8680 vlib_cli_command_t * cmd_arg)
8685 fib_test_mk_intf(4);
8687 if (unformat (input, "debug"))
8689 fib_test_do_debug = 1;
8692 if (unformat (input, "ip"))
8694 res += fib_test_v4();
8695 res += fib_test_v6();
8697 else if (unformat (input, "label"))
8699 res += fib_test_label();
8701 else if (unformat (input, "ae"))
8703 res += fib_test_ae();
8705 else if (unformat (input, "pref"))
8707 res += fib_test_pref();
8709 else if (unformat (input, "lfib"))
8713 else if (unformat (input, "walk"))
8715 res += fib_test_walk();
8717 else if (unformat (input, "bfd"))
8719 res += fib_test_bfd();
8723 res += fib_test_v4();
8724 res += fib_test_v6();
8725 res += fib_test_ae();
8726 res += fib_test_bfd();
8727 res += fib_test_pref();
8728 res += fib_test_label();
8732 * fib-walk process must be disabled in order for the walk tests to work
8734 fib_walk_process_disable();
8735 res += fib_test_walk();
8736 fib_walk_process_enable();
8741 return clib_error_return(0, "FIB Unit Test Failed");
8749 VLIB_CLI_COMMAND (test_fib_command, static) = {
8751 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8752 .function = fib_test,
8756 fib_test_init (vlib_main_t *vm)
8761 VLIB_INIT_FUNCTION (fib_test_init);