2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/fib/ip6_fib.h>
17 #include <vnet/fib/ip4_fib.h>
18 #include <vnet/fib/mpls_fib.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/dpo/load_balance_map.h>
22 #include <vnet/dpo/mpls_label_dpo.h>
23 #include <vnet/dpo/lookup_dpo.h>
24 #include <vnet/dpo/drop_dpo.h>
25 #include <vnet/dpo/receive_dpo.h>
26 #include <vnet/dpo/ip_null_dpo.h>
27 #include <vnet/bfd/bfd_main.h>
28 #include <vnet/dpo/interface_dpo.h>
29 #include <vnet/dpo/replicate_dpo.h>
31 #include <vnet/mpls/mpls.h>
33 #include <vnet/fib/fib_path_list.h>
34 #include <vnet/fib/fib_entry_src.h>
35 #include <vnet/fib/fib_walk.h>
36 #include <vnet/fib/fib_node_list.h>
37 #include <vnet/fib/fib_urpf_list.h>
40 * Add debugs for passing tests
42 static int fib_test_do_debug;
44 #define FIB_TEST_I(_cond, _comment, _args...) \
46 int _evald = (_cond); \
48 fformat(stderr, "FAIL:%d: " _comment "\n", \
51 if (fib_test_do_debug) \
52 fformat(stderr, "PASS:%d: " _comment "\n", \
57 #define FIB_TEST(_cond, _comment, _args...) \
59 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
61 ASSERT(!("FAIL: " _comment)); \
66 * A 'i'm not fussed is this is not efficient' store of test data
68 typedef struct test_main_t_ {
72 u32 hw_if_indicies[4];
76 vnet_hw_interface_t * hw[4];
79 static test_main_t test_main;
81 /* fake ethernet device class, distinct from "fake-ethX" */
82 static u8 * format_test_interface_name (u8 * s, va_list * args)
84 u32 dev_instance = va_arg (*args, u32);
85 return format (s, "test-eth%d", dev_instance);
88 static uword dummy_interface_tx (vlib_main_t * vm,
89 vlib_node_runtime_t * node,
92 clib_warning ("you shouldn't be here, leaking buffers...");
93 return frame->n_vectors;
97 test_interface_admin_up_down (vnet_main_t * vnm,
101 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
102 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
103 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
107 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
108 .name = "Test interface",
109 .format_device_name = format_test_interface_name,
110 .tx_function = dummy_interface_tx,
111 .admin_up_down_function = test_interface_admin_up_down,
114 static u8 *hw_address;
117 fib_test_mk_intf (u32 ninterfaces)
119 clib_error_t * error = NULL;
120 test_main_t *tm = &test_main;
124 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
129 vec_add1(hw_address, byte);
132 for (i = 0; i < ninterfaces; i++)
136 error = ethernet_register_interface(vnet_get_main(),
137 test_interface_device_class.index,
140 &tm->hw_if_indicies[i],
141 /* flag change */ 0);
143 FIB_TEST((NULL == error), "ADD interface %d", i);
145 error = vnet_hw_interface_set_flags(vnet_get_main(),
146 tm->hw_if_indicies[i],
147 VNET_HW_INTERFACE_FLAG_LINK_UP);
148 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
149 tm->hw_if_indicies[i]);
150 vec_validate (ip4_main.fib_index_by_sw_if_index,
151 tm->hw[i]->sw_if_index);
152 vec_validate (ip6_main.fib_index_by_sw_if_index,
153 tm->hw[i]->sw_if_index);
154 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
155 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
157 error = vnet_sw_interface_set_flags(vnet_get_main(),
158 tm->hw[i]->sw_if_index,
159 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
160 FIB_TEST((NULL == error), "UP interface %d", i);
163 * re-eval after the inevitable realloc
165 for (i = 0; i < ninterfaces; i++)
167 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
168 tm->hw_if_indicies[i]);
174 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
176 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
177 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
178 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
179 fib_table_lookup(fib_index, (_via_prefix))); \
180 FIB_TEST(!dpo_cmp(_via_dpo, \
181 load_balance_get_bucket(_rec_dpo->dpoi_index, \
183 "%U is recursive via %U", \
184 format_fib_prefix, (_rec_prefix), \
185 format_fib_prefix, _via_prefix); \
188 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
190 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
191 fib_table_lookup_exact_match(fib_index, (_prefix))); \
192 const dpo_id_t *_dpo1 = \
193 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
194 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
195 format_dpo_type, _dpo1->dpoi_type); \
196 FIB_TEST((_ai == _dpo1->dpoi_index), \
197 "%U bucket %d resolves via %U", \
198 format_fib_prefix, (_prefix), \
200 format_dpo_id, _dpo1, 0); \
203 #define FIB_TEST_RPF(_cond, _comment, _args...) \
205 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
211 fib_test_urpf_is_equal (fib_node_index_t fei,
212 fib_forward_chain_type_t fct,
215 dpo_id_t dpo = DPO_INVALID;
216 fib_urpf_list_t *urpf;
223 fib_entry_contribute_forwarding(fei, fct, &dpo);
224 ui = load_balance_get_urpf(dpo.dpoi_index);
226 urpf = fib_urpf_list_get(ui);
228 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
229 "RPF:%U len %d == %d",
230 format_fib_urpf_list, ui,
231 num, vec_len(urpf->furpf_itfs));
232 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
233 "RPF:%U check-size %d == %d",
234 format_fib_urpf_list, ui,
235 num, vec_len(urpf->furpf_itfs));
237 for (ii = 0; ii < num; ii++)
239 adj_index_t ai = va_arg(ap, adj_index_t);
241 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
242 "RPF:%d item:%d - %d == %d",
243 ui, ii, ai, urpf->furpf_itfs[ii]);
244 FIB_TEST_RPF(fib_urpf_check(ui, ai),
257 fib_test_build_rewrite (u8 *eth_addr)
261 vec_validate(rewrite, 13);
263 memcpy(rewrite, eth_addr, 6);
264 memcpy(rewrite+6, eth_addr, 6);
269 typedef enum fib_test_lb_bucket_type_t_ {
271 FT_LB_LABEL_STACK_O_ADJ,
277 } fib_test_lb_bucket_type_t;
279 typedef struct fib_test_lb_bucket_t_ {
280 fib_test_lb_bucket_type_t type;
294 mpls_label_t label_stack[8];
319 } fib_test_lb_bucket_t;
321 typedef enum fib_test_rep_bucket_type_t_ {
323 FT_REP_DISP_MFIB_LOOKUP,
325 } fib_test_rep_bucket_type_t;
327 typedef struct fib_test_rep_bucket_t_ {
328 fib_test_rep_bucket_type_t type;
344 } fib_test_rep_bucket_t;
346 #define FIB_TEST_LB(_cond, _comment, _args...) \
348 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
354 fib_test_validate_rep_v (const replicate_t *rep,
358 const fib_test_rep_bucket_t *exp;
362 FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
363 "n_buckets = %d", rep->rep_n_buckets);
365 for (bucket = 0; bucket < n_buckets; bucket++)
367 exp = va_arg(ap, fib_test_rep_bucket_t*);
369 dpo = replicate_get_bucket_i(rep, bucket);
373 case FT_REP_LABEL_O_ADJ:
375 const mpls_label_dpo_t *mld;
377 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
378 "bucket %d stacks on %U",
380 format_dpo_type, dpo->dpoi_type);
382 mld = mpls_label_dpo_get(dpo->dpoi_index);
383 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
385 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
386 exp->label_o_adj.label),
387 "bucket %d stacks on label %d",
389 exp->label_o_adj.label);
391 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
392 exp->label_o_adj.eos),
393 "bucket %d stacks on label %d %U",
395 exp->label_o_adj.label,
396 format_mpls_eos_bit, exp->label_o_adj.eos);
398 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
399 "bucket %d label stacks on %U",
401 format_dpo_type, mld->mld_dpo.dpoi_type);
403 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
404 "bucket %d label stacks on adj %d",
406 exp->label_o_adj.adj);
410 FIB_TEST_LB((DPO_INTERFACE == dpo->dpoi_type),
411 "bucket %d stacks on %U",
413 format_dpo_type, dpo->dpoi_type);
415 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
416 "bucket %d stacks on adj %d",
420 case FT_REP_DISP_MFIB_LOOKUP:
430 fib_test_validate_lb_v (const load_balance_t *lb,
437 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
439 for (bucket = 0; bucket < n_buckets; bucket++)
441 const fib_test_lb_bucket_t *exp;
443 exp = va_arg(ap, fib_test_lb_bucket_t*);
444 dpo = load_balance_get_bucket_i(lb, bucket);
448 case FT_LB_LABEL_STACK_O_ADJ:
450 const mpls_label_dpo_t *mld;
454 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
455 "bucket %d stacks on %U",
457 format_dpo_type, dpo->dpoi_type);
459 mld = mpls_label_dpo_get(dpo->dpoi_index);
461 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
465 for (ii = 0; ii < mld->mld_n_labels; ii++)
467 hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
468 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
469 exp->label_stack_o_adj.label_stack[ii]),
470 "bucket %d stacks on label %d",
472 exp->label_stack_o_adj.label_stack[ii]);
474 if (ii == mld->mld_n_labels-1)
476 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
477 exp->label_o_adj.eos),
478 "bucket %d stacks on label %d %U!=%U",
480 exp->label_stack_o_adj.label_stack[ii],
481 format_mpls_eos_bit, exp->label_o_adj.eos,
482 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
486 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
487 "bucket %d stacks on label %d %U",
489 exp->label_stack_o_adj.label_stack[ii],
490 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
494 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
495 "bucket %d label stacks on %U",
497 format_dpo_type, mld->mld_dpo.dpoi_type);
499 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
500 "bucket %d label stacks on adj %d",
502 exp->label_stack_o_adj.adj);
505 case FT_LB_LABEL_O_ADJ:
507 const mpls_label_dpo_t *mld;
509 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
510 "bucket %d stacks on %U",
512 format_dpo_type, dpo->dpoi_type);
514 mld = mpls_label_dpo_get(dpo->dpoi_index);
515 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
517 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
518 exp->label_o_adj.label),
519 "bucket %d stacks on label %d",
521 exp->label_o_adj.label);
523 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
524 exp->label_o_adj.eos),
525 "bucket %d stacks on label %d %U",
527 exp->label_o_adj.label,
528 format_mpls_eos_bit, exp->label_o_adj.eos);
530 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
531 "bucket %d label stacks on %U",
533 format_dpo_type, mld->mld_dpo.dpoi_type);
535 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
536 "bucket %d label stacks on adj %d",
538 exp->label_o_adj.adj);
541 case FT_LB_LABEL_O_LB:
543 const mpls_label_dpo_t *mld;
546 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
547 "bucket %d stacks on %U",
549 format_dpo_type, dpo->dpoi_type);
551 mld = mpls_label_dpo_get(dpo->dpoi_index);
552 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
554 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
556 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
557 exp->label_o_lb.label),
558 "bucket %d stacks on label %d",
560 exp->label_o_lb.label);
562 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
563 exp->label_o_lb.eos),
564 "bucket %d stacks on label %d %U",
566 exp->label_o_lb.label,
567 format_mpls_eos_bit, exp->label_o_lb.eos);
569 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
570 "bucket %d label stacks on %U",
572 format_dpo_type, mld->mld_dpo.dpoi_type);
574 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
575 "bucket %d label stacks on LB %d",
581 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
582 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
583 "bucket %d stacks on %U",
585 format_dpo_type, dpo->dpoi_type);
586 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
587 "bucket %d stacks on adj %d",
592 FIB_TEST_I((DPO_INTERFACE == dpo->dpoi_type),
593 "bucket %d stacks on %U",
595 format_dpo_type, dpo->dpoi_type);
596 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
597 "bucket %d stacks on adj %d",
602 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
603 "bucket %d stacks on %U",
605 format_dpo_type, dpo->dpoi_type);
606 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
607 "bucket %d stacks on lb %d",
612 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
613 "bucket %d stacks on %U",
615 format_dpo_type, dpo->dpoi_type);
616 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
617 "bucket %d stacks on drop %d",
627 fib_test_validate_entry (fib_node_index_t fei,
628 fib_forward_chain_type_t fct,
632 dpo_id_t dpo = DPO_INVALID;
639 va_start(ap, n_buckets);
641 fib_entry_get_prefix(fei, &pfx);
642 fib_index = fib_entry_get_fib_index(fei);
643 fib_entry_contribute_forwarding(fei, fct, &dpo);
645 if (DPO_REPLICATE == dpo.dpoi_type)
647 const replicate_t *rep;
649 rep = replicate_get(dpo.dpoi_index);
650 res = fib_test_validate_rep_v(rep, n_buckets, ap);
654 const load_balance_t *lb;
656 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
658 format_dpo_type, dpo.dpoi_type);
660 lb = load_balance_get(dpo.dpoi_index);
661 res = fib_test_validate_lb_v(lb, n_buckets, ap);
664 * ensure that the LB contributed by the entry is the
665 * same as the LB in the forwarding tables
667 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
669 switch (pfx.fp_proto)
671 case FIB_PROTOCOL_IP4:
672 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
674 case FIB_PROTOCOL_IP6:
675 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
677 case FIB_PROTOCOL_MPLS:
679 mpls_unicast_header_t hdr = {
680 .label_exp_s_ttl = 0,
683 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
684 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
685 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
687 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
693 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
694 "Contributed LB = FW LB: %U\n %U",
695 format_load_balance, fw_lbi, 0,
696 format_load_balance, dpo.dpoi_index, 0);
711 * In the default table check for the presence and correct forwarding
712 * of the special entries
714 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
715 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
716 const ip_adjacency_t *adj;
717 const load_balance_t *lb;
724 ip46_address_t nh_10_10_10_1 = {
725 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
728 ip46_address_t nh_10_10_10_2 = {
729 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
732 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
733 pool_elts(load_balance_map_pool));
737 /* record the nubmer of load-balances in use before we start */
738 lb_count = pool_elts(load_balance_pool);
740 /* Find or create FIB table 11 */
741 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
743 for (ii = 0; ii < 4; ii++)
745 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
748 fib_prefix_t pfx_0_0_0_0_s_0 = {
750 .fp_proto = FIB_PROTOCOL_IP4,
760 .fp_proto = FIB_PROTOCOL_IP4,
768 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
770 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
771 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
772 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
773 "Default route is DROP");
776 fei = fib_table_lookup(fib_index, &pfx);
777 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
778 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
779 "all 0s route is DROP");
781 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
783 fei = fib_table_lookup(fib_index, &pfx);
784 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
785 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
786 "all 1s route is DROP");
788 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
790 fei = fib_table_lookup(fib_index, &pfx);
791 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
792 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
793 "all-mcast route is DROP");
795 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
797 fei = fib_table_lookup(fib_index, &pfx);
798 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
799 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
800 "class-e route is DROP");
803 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
804 * all of which are special sourced and so none of which share path-lists.
805 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
806 * table, and 4 path-lists in the v6 MFIB table
810 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
811 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
812 fib_path_list_pool_size());
813 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
814 fib_entry_pool_size());
817 * add interface routes.
818 * validate presence of /24 attached and /32 recieve.
819 * test for the presence of the receive address in the glean and local adj
821 fib_prefix_t local_pfx = {
823 .fp_proto = FIB_PROTOCOL_IP4,
826 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
831 fib_table_entry_update_one_path(fib_index, &local_pfx,
832 FIB_SOURCE_INTERFACE,
833 (FIB_ENTRY_FLAG_CONNECTED |
834 FIB_ENTRY_FLAG_ATTACHED),
837 tm->hw[0]->sw_if_index,
838 ~0, // invalid fib index
841 FIB_ROUTE_PATH_FLAG_NONE);
842 fei = fib_table_lookup(fib_index, &local_pfx);
843 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
844 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
845 fib_entry_get_flags(fei)),
846 "Flags set on attached interface");
848 ai = fib_entry_get_adj(fei);
849 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
851 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
852 "attached interface adj is glean");
853 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
854 &adj->sub_type.glean.receive_addr)),
855 "attached interface adj is receive ok");
857 local_pfx.fp_len = 32;
858 fib_table_entry_update_one_path(fib_index, &local_pfx,
859 FIB_SOURCE_INTERFACE,
860 (FIB_ENTRY_FLAG_CONNECTED |
861 FIB_ENTRY_FLAG_LOCAL),
864 tm->hw[0]->sw_if_index,
865 ~0, // invalid fib index
868 FIB_ROUTE_PATH_FLAG_NONE);
869 fei = fib_table_lookup(fib_index, &local_pfx);
870 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
871 fib_entry_get_flags(fei)),
872 "Flags set on local interface");
874 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
876 dpo = fib_entry_contribute_ip_forwarding(fei);
877 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
878 "RPF list for local length 0");
879 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
880 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
881 "local interface adj is local");
882 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
884 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
886 "local interface adj is receive ok");
888 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
890 FIB_SOURCE_INTERFACE)),
891 "2 Interface Source'd prefixes");
894 * +2 interface routes +2 non-shared path-lists
896 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
897 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
898 fib_path_list_pool_size());
899 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
900 fib_entry_pool_size());
903 * Modify the default route to be via an adj not yet known.
904 * this sources the defalut route with the API source, which is
905 * a higher preference to the DEFAULT_ROUTE source
907 pfx.fp_addr.ip4.as_u32 = 0;
909 fib_table_entry_path_add(fib_index, &pfx,
914 tm->hw[0]->sw_if_index,
915 ~0, // invalid fib index
918 FIB_ROUTE_PATH_FLAG_NONE);
919 fei = fib_table_lookup(fib_index, &pfx);
920 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
921 "Flags set on API route");
923 FIB_TEST((fei == dfrt), "default route same index");
924 ai = fib_entry_get_adj(fei);
925 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
927 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
928 "adj is incomplete");
929 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
930 "adj nbr next-hop ok");
931 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
934 "1 API Source'd prefixes");
937 * find the adj in the shared db
939 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
942 tm->hw[0]->sw_if_index);
943 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
944 adj_unlock(locked_ai);
947 * +1 shared path-list
949 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
950 fib_path_list_db_size());
951 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
952 fib_path_list_pool_size());
953 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
954 fib_entry_pool_size());
957 * remove the API source from the default route. We expected
958 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
960 pfx.fp_addr.ip4.as_u32 = 0;
962 fib_table_entry_path_remove(fib_index, &pfx,
966 tm->hw[0]->sw_if_index,
967 ~0, // non-recursive path, so no FIB index
969 FIB_ROUTE_PATH_FLAG_NONE);
971 fei = fib_table_lookup(fib_index, &pfx);
973 FIB_TEST((fei == dfrt), "default route same index");
974 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
975 "Default route is DROP");
978 * -1 shared-path-list
980 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
981 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
982 fib_path_list_pool_size());
983 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
984 fib_entry_pool_size());
987 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
989 fib_prefix_t pfx_10_10_10_1_s_32 = {
991 .fp_proto = FIB_PROTOCOL_IP4,
994 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
997 fib_prefix_t pfx_10_10_10_2_s_32 = {
999 .fp_proto = FIB_PROTOCOL_IP4,
1002 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1005 fib_prefix_t pfx_11_11_11_11_s_32 = {
1007 .fp_proto = FIB_PROTOCOL_IP4,
1010 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1014 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1017 ip46_address_t nh_12_12_12_12 = {
1018 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1020 adj_index_t ai_12_12_12_12;
1023 * Add a route via an incomplete ADJ. then complete the ADJ
1024 * Expect the route LB is updated to use complete adj type.
1026 fei = fib_table_entry_update_one_path(fib_index,
1027 &pfx_11_11_11_11_s_32,
1029 FIB_ENTRY_FLAG_ATTACHED,
1031 &pfx_10_10_10_1_s_32.fp_addr,
1032 tm->hw[0]->sw_if_index,
1033 ~0, // invalid fib index
1036 FIB_ROUTE_PATH_FLAG_NONE);
1038 dpo = fib_entry_contribute_ip_forwarding(fei);
1039 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1040 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1041 "11.11.11.11/32 via incomplete adj");
1043 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1045 &pfx_10_10_10_1_s_32.fp_addr,
1046 tm->hw[0]->sw_if_index);
1047 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1048 adj = adj_get(ai_01);
1049 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1050 "adj is incomplete");
1051 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1052 &adj->sub_type.nbr.next_hop)),
1053 "adj nbr next-hop ok");
1055 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1056 fib_test_build_rewrite(eth_addr));
1057 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1059 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1060 &adj->sub_type.nbr.next_hop)),
1061 "adj nbr next-hop ok");
1062 ai = fib_entry_get_adj(fei);
1063 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1065 dpo = fib_entry_contribute_ip_forwarding(fei);
1066 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1067 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1068 "11.11.11.11/32 via complete adj");
1069 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1070 tm->hw[0]->sw_if_index),
1071 "RPF list for adj-fib contains adj");
1073 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1076 tm->hw[1]->sw_if_index);
1077 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1078 adj = adj_get(ai_12_12_12_12);
1079 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1080 "adj is incomplete");
1081 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1082 &adj->sub_type.nbr.next_hop)),
1083 "adj nbr next-hop ok");
1084 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1085 fib_test_build_rewrite(eth_addr));
1086 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1092 fei = fib_table_entry_update_one_path(fib_index,
1093 &pfx_10_10_10_1_s_32,
1095 FIB_ENTRY_FLAG_ATTACHED,
1097 &pfx_10_10_10_1_s_32.fp_addr,
1098 tm->hw[0]->sw_if_index,
1099 ~0, // invalid fib index
1102 FIB_ROUTE_PATH_FLAG_NONE);
1103 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1104 "Flags set on adj-fib");
1105 ai = fib_entry_get_adj(fei);
1106 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1108 fib_table_entry_path_remove(fib_index,
1109 &pfx_11_11_11_11_s_32,
1112 &pfx_10_10_10_1_s_32.fp_addr,
1113 tm->hw[0]->sw_if_index,
1114 ~0, // invalid fib index
1116 FIB_ROUTE_PATH_FLAG_NONE);
1120 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1122 &pfx_10_10_10_2_s_32.fp_addr,
1123 tm->hw[0]->sw_if_index);
1124 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1125 adj = adj_get(ai_02);
1126 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1127 "adj is incomplete");
1128 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1129 &adj->sub_type.nbr.next_hop)),
1130 "adj nbr next-hop ok");
1132 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1133 fib_test_build_rewrite(eth_addr));
1134 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1136 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1137 &adj->sub_type.nbr.next_hop)),
1138 "adj nbr next-hop ok");
1139 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1141 fib_table_entry_update_one_path(fib_index,
1142 &pfx_10_10_10_2_s_32,
1144 FIB_ENTRY_FLAG_ATTACHED,
1146 &pfx_10_10_10_2_s_32.fp_addr,
1147 tm->hw[0]->sw_if_index,
1148 ~0, // invalid fib index
1151 FIB_ROUTE_PATH_FLAG_NONE);
1153 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1154 ai = fib_entry_get_adj(fei);
1155 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1158 * +2 adj-fibs, and their non-shared path-lists
1160 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1161 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1162 fib_path_list_pool_size());
1163 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1164 fib_entry_pool_size());
1167 * Add 2 routes via the first ADJ. ensure path-list sharing
1169 fib_prefix_t pfx_1_1_1_1_s_32 = {
1171 .fp_proto = FIB_PROTOCOL_IP4,
1174 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1178 fib_table_entry_path_add(fib_index,
1181 FIB_ENTRY_FLAG_NONE,
1184 tm->hw[0]->sw_if_index,
1185 ~0, // invalid fib index
1188 FIB_ROUTE_PATH_FLAG_NONE);
1189 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1190 ai = fib_entry_get_adj(fei);
1191 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1194 * +1 entry and a shared path-list
1196 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1197 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1198 fib_path_list_pool_size());
1199 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1200 fib_entry_pool_size());
1203 fib_prefix_t pfx_1_1_2_0_s_24 = {
1205 .fp_proto = FIB_PROTOCOL_IP4,
1207 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1211 fib_table_entry_path_add(fib_index,
1214 FIB_ENTRY_FLAG_NONE,
1217 tm->hw[0]->sw_if_index,
1218 ~0, // invalid fib index
1221 FIB_ROUTE_PATH_FLAG_NONE);
1222 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1223 ai = fib_entry_get_adj(fei);
1224 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1229 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1230 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1231 fib_path_list_pool_size());
1232 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1233 fib_entry_pool_size());
1236 * modify 1.1.2.0/24 to use multipath.
1238 fib_table_entry_path_add(fib_index,
1241 FIB_ENTRY_FLAG_NONE,
1244 tm->hw[0]->sw_if_index,
1245 ~0, // invalid fib index
1248 FIB_ROUTE_PATH_FLAG_NONE);
1249 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1250 dpo = fib_entry_contribute_ip_forwarding(fei);
1251 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1252 1, tm->hw[0]->sw_if_index),
1253 "RPF list for 1.1.2.0/24 contains both adjs");
1255 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1256 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1257 FIB_TEST((ai_01 == dpo1->dpoi_index),
1258 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1259 ai_01, dpo1->dpoi_index);
1261 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1262 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1263 FIB_TEST((ai_02 == dpo1->dpoi_index),
1264 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1267 * +1 shared-pathlist
1269 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1270 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1271 fib_path_list_pool_size());
1272 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1273 fib_entry_pool_size());
1278 fib_table_entry_path_remove(fib_index,
1283 tm->hw[0]->sw_if_index,
1286 FIB_ROUTE_PATH_FLAG_NONE);
1287 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1288 dpo = fib_entry_contribute_ip_forwarding(fei);
1289 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1290 1, tm->hw[0]->sw_if_index),
1291 "RPF list for 1.1.2.0/24 contains one adj");
1293 ai = fib_entry_get_adj(fei);
1294 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1297 * +1 shared-pathlist
1299 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1300 fib_path_list_db_size());
1301 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1302 fib_path_list_pool_size());
1303 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1304 fib_entry_pool_size());
1307 * Add 2 recursive routes:
1308 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1309 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1311 fib_prefix_t bgp_100_pfx = {
1313 .fp_proto = FIB_PROTOCOL_IP4,
1315 /* 100.100.100.100/32 */
1316 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1320 ip46_address_t nh_1_1_1_1 = {
1321 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1324 fei = fib_table_entry_path_add(fib_index,
1327 FIB_ENTRY_FLAG_NONE,
1330 ~0, // no index provided.
1331 fib_index, // nexthop in same fib as route
1334 FIB_ROUTE_PATH_FLAG_NONE);
1336 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1337 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1338 tm->hw[0]->sw_if_index),
1339 "RPF list for adj-fib contains adj");
1342 * +1 entry and +1 shared-path-list
1344 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1345 fib_path_list_db_size());
1346 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1347 fib_path_list_pool_size());
1348 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1349 fib_entry_pool_size());
1351 fib_prefix_t bgp_101_pfx = {
1353 .fp_proto = FIB_PROTOCOL_IP4,
1355 /* 100.100.100.101/32 */
1356 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1360 fib_table_entry_path_add(fib_index,
1363 FIB_ENTRY_FLAG_NONE,
1366 ~0, // no index provided.
1367 fib_index, // nexthop in same fib as route
1370 FIB_ROUTE_PATH_FLAG_NONE);
1372 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1373 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1374 tm->hw[0]->sw_if_index),
1375 "RPF list for adj-fib contains adj");
1378 * +1 entry, but the recursive path-list is shared.
1380 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1381 fib_path_list_db_size());
1382 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1383 fib_path_list_pool_size());
1384 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1385 fib_entry_pool_size());
1388 * An special route; one where the user (me) provides the
1389 * adjacency through which the route will resovle by setting the flags
1391 fib_prefix_t ex_pfx = {
1393 .fp_proto = FIB_PROTOCOL_IP4,
1396 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1400 fib_table_entry_special_add(fib_index,
1403 FIB_ENTRY_FLAG_LOCAL);
1404 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1405 dpo = fib_entry_contribute_ip_forwarding(fei);
1406 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1407 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1408 "local interface adj is local");
1410 fib_table_entry_special_remove(fib_index,
1412 FIB_SOURCE_SPECIAL);
1413 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1414 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1415 "Exclusive reoute removed");
1418 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1419 * adjacency through which the route will resovle
1421 dpo_id_t ex_dpo = DPO_INVALID;
1423 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1426 LOOKUP_INPUT_DST_ADDR,
1427 LOOKUP_TABLE_FROM_CONFIG,
1430 fib_table_entry_special_dpo_add(fib_index,
1433 FIB_ENTRY_FLAG_EXCLUSIVE,
1435 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1436 dpo = fib_entry_contribute_ip_forwarding(fei);
1437 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1438 "exclusive remote uses lookup DPO");
1441 * update the exclusive to use a different DPO
1443 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1444 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1446 fib_table_entry_special_dpo_update(fib_index,
1449 FIB_ENTRY_FLAG_EXCLUSIVE,
1451 dpo = fib_entry_contribute_ip_forwarding(fei);
1452 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1453 "exclusive remote uses now uses NULL DPO");
1455 fib_table_entry_special_remove(fib_index,
1457 FIB_SOURCE_SPECIAL);
1458 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1459 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1460 "Exclusive reoute removed");
1464 * Add a recursive route:
1465 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1467 fib_prefix_t bgp_200_pfx = {
1469 .fp_proto = FIB_PROTOCOL_IP4,
1471 /* 200.200.200.200/32 */
1472 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1476 fib_prefix_t pfx_1_1_1_2_s_32 = {
1478 .fp_proto = FIB_PROTOCOL_IP4,
1480 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1484 fib_table_entry_path_add(fib_index,
1487 FIB_ENTRY_FLAG_NONE,
1489 &pfx_1_1_1_2_s_32.fp_addr,
1490 ~0, // no index provided.
1491 fib_index, // nexthop in same fib as route
1494 FIB_ROUTE_PATH_FLAG_NONE);
1496 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1499 * the adj should be recursive via drop, since the route resolves via
1500 * the default route, which is itself a DROP
1502 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1503 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1504 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1505 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1506 "RPF list for 1.1.1.2/32 contains 0 adjs");
1509 * +2 entry and +1 shared-path-list
1511 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1512 fib_path_list_db_size());
1513 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1514 fib_path_list_pool_size());
1515 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1516 fib_entry_pool_size());
1519 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1520 * The paths are sort by NH first. in this case the the path with greater
1521 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1523 fib_prefix_t pfx_1_2_3_4_s_32 = {
1525 .fp_proto = FIB_PROTOCOL_IP4,
1527 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1530 fib_table_entry_path_add(fib_index,
1533 FIB_ENTRY_FLAG_NONE,
1536 tm->hw[0]->sw_if_index,
1540 FIB_ROUTE_PATH_FLAG_NONE);
1541 fei = fib_table_entry_path_add(fib_index,
1544 FIB_ENTRY_FLAG_NONE,
1547 tm->hw[1]->sw_if_index,
1551 FIB_ROUTE_PATH_FLAG_NONE);
1553 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1554 dpo = fib_entry_contribute_ip_forwarding(fei);
1555 lb = load_balance_get(dpo->dpoi_index);
1556 FIB_TEST((lb->lb_n_buckets == 4),
1557 "1.2.3.4/32 LB has %d bucket",
1560 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1561 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1562 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1563 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1565 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1566 tm->hw[0]->sw_if_index,
1567 tm->hw[1]->sw_if_index),
1568 "RPF list for 1.2.3.4/32 contains both adjs");
1572 * Unequal Cost load-balance. 4:1 ratio.
1573 * fits in a 16 bucket LB with ratio 13:3
1575 fib_prefix_t pfx_1_2_3_5_s_32 = {
1577 .fp_proto = FIB_PROTOCOL_IP4,
1579 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1582 fib_table_entry_path_add(fib_index,
1585 FIB_ENTRY_FLAG_NONE,
1588 tm->hw[1]->sw_if_index,
1592 FIB_ROUTE_PATH_FLAG_NONE);
1593 fei = fib_table_entry_path_add(fib_index,
1596 FIB_ENTRY_FLAG_NONE,
1599 tm->hw[0]->sw_if_index,
1603 FIB_ROUTE_PATH_FLAG_NONE);
1605 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1606 dpo = fib_entry_contribute_ip_forwarding(fei);
1607 lb = load_balance_get(dpo->dpoi_index);
1608 FIB_TEST((lb->lb_n_buckets == 16),
1609 "1.2.3.5/32 LB has %d bucket",
1612 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1613 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1614 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1615 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1616 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1617 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1618 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1619 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1620 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1621 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1622 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1623 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1624 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1625 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1626 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1627 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1629 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1630 tm->hw[0]->sw_if_index,
1631 tm->hw[1]->sw_if_index),
1632 "RPF list for 1.2.3.4/32 contains both adjs");
1635 * Test UCMP with a large weight skew - this produces load-balance objects with large
1636 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1637 * laso testing the LB in placce modify code when number of buckets is large.
1639 fib_prefix_t pfx_6_6_6_6_s_32 = {
1641 .fp_proto = FIB_PROTOCOL_IP4,
1644 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1647 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_1 = {
1653 fib_test_lb_bucket_t ip_6_6_6_6_o_10_10_10_2 = {
1659 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1662 .adj = ai_12_12_12_12,
1665 fib_table_entry_update_one_path(fib_index,
1668 FIB_ENTRY_FLAG_NONE,
1671 tm->hw[0]->sw_if_index,
1672 ~0, // invalid fib index
1675 FIB_ROUTE_PATH_FLAG_NONE);
1677 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1678 FIB_TEST(fib_test_validate_entry(fei,
1679 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1681 &ip_6_6_6_6_o_10_10_10_1),
1682 "6.6.6.6/32 via 10.10.10.1");
1684 fib_table_entry_path_add(fib_index,
1687 FIB_ENTRY_FLAG_NONE,
1690 tm->hw[0]->sw_if_index,
1691 ~0, // invalid fib index
1694 FIB_ROUTE_PATH_FLAG_NONE);
1696 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1697 FIB_TEST(fib_test_validate_entry(fei,
1698 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1700 &ip_6_6_6_6_o_10_10_10_2,
1701 &ip_6_6_6_6_o_10_10_10_2,
1702 &ip_6_6_6_6_o_10_10_10_2,
1703 &ip_6_6_6_6_o_10_10_10_2,
1704 &ip_6_6_6_6_o_10_10_10_2,
1705 &ip_6_6_6_6_o_10_10_10_2,
1706 &ip_6_6_6_6_o_10_10_10_2,
1707 &ip_6_6_6_6_o_10_10_10_2,
1708 &ip_6_6_6_6_o_10_10_10_2,
1709 &ip_6_6_6_6_o_10_10_10_2,
1710 &ip_6_6_6_6_o_10_10_10_2,
1711 &ip_6_6_6_6_o_10_10_10_2,
1712 &ip_6_6_6_6_o_10_10_10_2,
1713 &ip_6_6_6_6_o_10_10_10_2,
1714 &ip_6_6_6_6_o_10_10_10_2,
1715 &ip_6_6_6_6_o_10_10_10_2,
1716 &ip_6_6_6_6_o_10_10_10_2,
1717 &ip_6_6_6_6_o_10_10_10_2,
1718 &ip_6_6_6_6_o_10_10_10_2,
1719 &ip_6_6_6_6_o_10_10_10_2,
1720 &ip_6_6_6_6_o_10_10_10_2,
1721 &ip_6_6_6_6_o_10_10_10_2,
1722 &ip_6_6_6_6_o_10_10_10_2,
1723 &ip_6_6_6_6_o_10_10_10_2,
1724 &ip_6_6_6_6_o_10_10_10_2,
1725 &ip_6_6_6_6_o_10_10_10_2,
1726 &ip_6_6_6_6_o_10_10_10_2,
1727 &ip_6_6_6_6_o_10_10_10_2,
1728 &ip_6_6_6_6_o_10_10_10_2,
1729 &ip_6_6_6_6_o_10_10_10_2,
1730 &ip_6_6_6_6_o_10_10_10_2,
1731 &ip_6_6_6_6_o_10_10_10_2,
1732 &ip_6_6_6_6_o_10_10_10_2,
1733 &ip_6_6_6_6_o_10_10_10_2,
1734 &ip_6_6_6_6_o_10_10_10_2,
1735 &ip_6_6_6_6_o_10_10_10_2,
1736 &ip_6_6_6_6_o_10_10_10_2,
1737 &ip_6_6_6_6_o_10_10_10_2,
1738 &ip_6_6_6_6_o_10_10_10_2,
1739 &ip_6_6_6_6_o_10_10_10_2,
1740 &ip_6_6_6_6_o_10_10_10_2,
1741 &ip_6_6_6_6_o_10_10_10_2,
1742 &ip_6_6_6_6_o_10_10_10_2,
1743 &ip_6_6_6_6_o_10_10_10_2,
1744 &ip_6_6_6_6_o_10_10_10_2,
1745 &ip_6_6_6_6_o_10_10_10_2,
1746 &ip_6_6_6_6_o_10_10_10_2,
1747 &ip_6_6_6_6_o_10_10_10_2,
1748 &ip_6_6_6_6_o_10_10_10_2,
1749 &ip_6_6_6_6_o_10_10_10_2,
1750 &ip_6_6_6_6_o_10_10_10_2,
1751 &ip_6_6_6_6_o_10_10_10_2,
1752 &ip_6_6_6_6_o_10_10_10_2,
1753 &ip_6_6_6_6_o_10_10_10_2,
1754 &ip_6_6_6_6_o_10_10_10_2,
1755 &ip_6_6_6_6_o_10_10_10_2,
1756 &ip_6_6_6_6_o_10_10_10_2,
1757 &ip_6_6_6_6_o_10_10_10_2,
1758 &ip_6_6_6_6_o_10_10_10_2,
1759 &ip_6_6_6_6_o_10_10_10_2,
1760 &ip_6_6_6_6_o_10_10_10_2,
1761 &ip_6_6_6_6_o_10_10_10_2,
1762 &ip_6_6_6_6_o_10_10_10_2,
1763 &ip_6_6_6_6_o_10_10_10_1),
1764 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1766 fib_table_entry_path_add(fib_index,
1769 FIB_ENTRY_FLAG_NONE,
1772 tm->hw[1]->sw_if_index,
1773 ~0, // invalid fib index
1776 FIB_ROUTE_PATH_FLAG_NONE);
1778 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1779 FIB_TEST(fib_test_validate_entry(fei,
1780 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1782 &ip_6_6_6_6_o_10_10_10_1,
1783 &ip_6_6_6_6_o_10_10_10_2,
1784 &ip_6_6_6_6_o_10_10_10_2,
1785 &ip_6_6_6_6_o_10_10_10_2,
1786 &ip_6_6_6_6_o_10_10_10_2,
1787 &ip_6_6_6_6_o_10_10_10_2,
1788 &ip_6_6_6_6_o_10_10_10_2,
1789 &ip_6_6_6_6_o_10_10_10_2,
1790 &ip_6_6_6_6_o_10_10_10_2,
1791 &ip_6_6_6_6_o_10_10_10_2,
1792 &ip_6_6_6_6_o_10_10_10_2,
1793 &ip_6_6_6_6_o_10_10_10_2,
1794 &ip_6_6_6_6_o_10_10_10_2,
1795 &ip_6_6_6_6_o_10_10_10_2,
1796 &ip_6_6_6_6_o_10_10_10_2,
1797 &ip_6_6_6_6_o_10_10_10_2,
1798 &ip_6_6_6_6_o_10_10_10_2,
1799 &ip_6_6_6_6_o_10_10_10_2,
1800 &ip_6_6_6_6_o_10_10_10_2,
1801 &ip_6_6_6_6_o_10_10_10_2,
1802 &ip_6_6_6_6_o_10_10_10_2,
1803 &ip_6_6_6_6_o_10_10_10_2,
1804 &ip_6_6_6_6_o_10_10_10_2,
1805 &ip_6_6_6_6_o_10_10_10_2,
1806 &ip_6_6_6_6_o_10_10_10_2,
1807 &ip_6_6_6_6_o_10_10_10_2,
1808 &ip_6_6_6_6_o_10_10_10_2,
1809 &ip_6_6_6_6_o_10_10_10_2,
1810 &ip_6_6_6_6_o_10_10_10_2,
1811 &ip_6_6_6_6_o_10_10_10_2,
1812 &ip_6_6_6_6_o_10_10_10_2,
1813 &ip_6_6_6_6_o_10_10_10_2,
1814 &ip_6_6_6_6_o_10_10_10_2,
1815 &ip_6_6_6_6_o_10_10_10_2,
1816 &ip_6_6_6_6_o_10_10_10_2,
1817 &ip_6_6_6_6_o_10_10_10_2,
1818 &ip_6_6_6_6_o_10_10_10_2,
1819 &ip_6_6_6_6_o_10_10_10_2,
1820 &ip_6_6_6_6_o_10_10_10_2,
1821 &ip_6_6_6_6_o_10_10_10_2,
1822 &ip_6_6_6_6_o_10_10_10_2,
1823 &ip_6_6_6_6_o_10_10_10_2,
1824 &ip_6_6_6_6_o_10_10_10_2,
1825 &ip_6_6_6_6_o_10_10_10_2,
1826 &ip_6_6_6_6_o_10_10_10_2,
1827 &ip_6_6_6_6_o_10_10_10_2,
1828 &ip_6_6_6_6_o_10_10_10_2,
1829 &ip_6_6_6_6_o_10_10_10_2,
1830 &ip_6_6_6_6_o_10_10_10_2,
1831 &ip_6_6_6_6_o_10_10_10_2,
1832 &ip_6_6_6_6_o_10_10_10_2,
1833 &ip_6_6_6_6_o_10_10_10_2,
1834 &ip_6_6_6_6_o_10_10_10_2,
1835 &ip_6_6_6_6_o_10_10_10_2,
1836 &ip_6_6_6_6_o_10_10_10_2,
1837 &ip_6_6_6_6_o_10_10_10_2,
1838 &ip_6_6_6_6_o_10_10_10_2,
1839 &ip_6_6_6_6_o_10_10_10_2,
1840 &ip_6_6_6_6_o_10_10_10_2,
1841 &ip_6_6_6_6_o_10_10_10_2,
1842 &ip_6_6_6_6_o_10_10_10_2,
1843 &ip_6_6_6_6_o_10_10_10_2,
1844 &ip_6_6_6_6_o_10_10_10_2,
1845 &ip_6_6_6_6_o_10_10_10_2,
1846 &ip_6_6_6_6_o_10_10_10_2,
1847 &ip_6_6_6_6_o_12_12_12_12,
1848 &ip_6_6_6_6_o_12_12_12_12,
1849 &ip_6_6_6_6_o_12_12_12_12,
1850 &ip_6_6_6_6_o_12_12_12_12,
1851 &ip_6_6_6_6_o_12_12_12_12,
1852 &ip_6_6_6_6_o_12_12_12_12,
1853 &ip_6_6_6_6_o_12_12_12_12,
1854 &ip_6_6_6_6_o_12_12_12_12,
1855 &ip_6_6_6_6_o_12_12_12_12,
1856 &ip_6_6_6_6_o_12_12_12_12,
1857 &ip_6_6_6_6_o_12_12_12_12,
1858 &ip_6_6_6_6_o_12_12_12_12,
1859 &ip_6_6_6_6_o_12_12_12_12,
1860 &ip_6_6_6_6_o_12_12_12_12,
1861 &ip_6_6_6_6_o_12_12_12_12,
1862 &ip_6_6_6_6_o_12_12_12_12,
1863 &ip_6_6_6_6_o_12_12_12_12,
1864 &ip_6_6_6_6_o_12_12_12_12,
1865 &ip_6_6_6_6_o_12_12_12_12,
1866 &ip_6_6_6_6_o_12_12_12_12,
1867 &ip_6_6_6_6_o_12_12_12_12,
1868 &ip_6_6_6_6_o_12_12_12_12,
1869 &ip_6_6_6_6_o_12_12_12_12,
1870 &ip_6_6_6_6_o_12_12_12_12,
1871 &ip_6_6_6_6_o_12_12_12_12,
1872 &ip_6_6_6_6_o_12_12_12_12,
1873 &ip_6_6_6_6_o_12_12_12_12,
1874 &ip_6_6_6_6_o_12_12_12_12,
1875 &ip_6_6_6_6_o_12_12_12_12,
1876 &ip_6_6_6_6_o_12_12_12_12,
1877 &ip_6_6_6_6_o_12_12_12_12,
1878 &ip_6_6_6_6_o_12_12_12_12,
1879 &ip_6_6_6_6_o_12_12_12_12,
1880 &ip_6_6_6_6_o_12_12_12_12,
1881 &ip_6_6_6_6_o_12_12_12_12,
1882 &ip_6_6_6_6_o_12_12_12_12,
1883 &ip_6_6_6_6_o_12_12_12_12,
1884 &ip_6_6_6_6_o_12_12_12_12,
1885 &ip_6_6_6_6_o_12_12_12_12,
1886 &ip_6_6_6_6_o_12_12_12_12,
1887 &ip_6_6_6_6_o_12_12_12_12,
1888 &ip_6_6_6_6_o_12_12_12_12,
1889 &ip_6_6_6_6_o_12_12_12_12,
1890 &ip_6_6_6_6_o_12_12_12_12,
1891 &ip_6_6_6_6_o_12_12_12_12,
1892 &ip_6_6_6_6_o_12_12_12_12,
1893 &ip_6_6_6_6_o_12_12_12_12,
1894 &ip_6_6_6_6_o_12_12_12_12,
1895 &ip_6_6_6_6_o_12_12_12_12,
1896 &ip_6_6_6_6_o_12_12_12_12,
1897 &ip_6_6_6_6_o_12_12_12_12,
1898 &ip_6_6_6_6_o_12_12_12_12,
1899 &ip_6_6_6_6_o_12_12_12_12,
1900 &ip_6_6_6_6_o_12_12_12_12,
1901 &ip_6_6_6_6_o_12_12_12_12,
1902 &ip_6_6_6_6_o_12_12_12_12,
1903 &ip_6_6_6_6_o_12_12_12_12,
1904 &ip_6_6_6_6_o_12_12_12_12,
1905 &ip_6_6_6_6_o_12_12_12_12,
1906 &ip_6_6_6_6_o_12_12_12_12,
1907 &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 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1912 fib_table_entry_path_remove(fib_index,
1917 tm->hw[1]->sw_if_index,
1918 ~0, // invalid fib index
1920 FIB_ROUTE_PATH_FLAG_NONE);
1922 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1923 FIB_TEST(fib_test_validate_entry(fei,
1924 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1926 &ip_6_6_6_6_o_10_10_10_2,
1927 &ip_6_6_6_6_o_10_10_10_2,
1928 &ip_6_6_6_6_o_10_10_10_2,
1929 &ip_6_6_6_6_o_10_10_10_2,
1930 &ip_6_6_6_6_o_10_10_10_2,
1931 &ip_6_6_6_6_o_10_10_10_2,
1932 &ip_6_6_6_6_o_10_10_10_2,
1933 &ip_6_6_6_6_o_10_10_10_2,
1934 &ip_6_6_6_6_o_10_10_10_2,
1935 &ip_6_6_6_6_o_10_10_10_2,
1936 &ip_6_6_6_6_o_10_10_10_2,
1937 &ip_6_6_6_6_o_10_10_10_2,
1938 &ip_6_6_6_6_o_10_10_10_2,
1939 &ip_6_6_6_6_o_10_10_10_2,
1940 &ip_6_6_6_6_o_10_10_10_2,
1941 &ip_6_6_6_6_o_10_10_10_2,
1942 &ip_6_6_6_6_o_10_10_10_2,
1943 &ip_6_6_6_6_o_10_10_10_2,
1944 &ip_6_6_6_6_o_10_10_10_2,
1945 &ip_6_6_6_6_o_10_10_10_2,
1946 &ip_6_6_6_6_o_10_10_10_2,
1947 &ip_6_6_6_6_o_10_10_10_2,
1948 &ip_6_6_6_6_o_10_10_10_2,
1949 &ip_6_6_6_6_o_10_10_10_2,
1950 &ip_6_6_6_6_o_10_10_10_2,
1951 &ip_6_6_6_6_o_10_10_10_2,
1952 &ip_6_6_6_6_o_10_10_10_2,
1953 &ip_6_6_6_6_o_10_10_10_2,
1954 &ip_6_6_6_6_o_10_10_10_2,
1955 &ip_6_6_6_6_o_10_10_10_2,
1956 &ip_6_6_6_6_o_10_10_10_2,
1957 &ip_6_6_6_6_o_10_10_10_2,
1958 &ip_6_6_6_6_o_10_10_10_2,
1959 &ip_6_6_6_6_o_10_10_10_2,
1960 &ip_6_6_6_6_o_10_10_10_2,
1961 &ip_6_6_6_6_o_10_10_10_2,
1962 &ip_6_6_6_6_o_10_10_10_2,
1963 &ip_6_6_6_6_o_10_10_10_2,
1964 &ip_6_6_6_6_o_10_10_10_2,
1965 &ip_6_6_6_6_o_10_10_10_2,
1966 &ip_6_6_6_6_o_10_10_10_2,
1967 &ip_6_6_6_6_o_10_10_10_2,
1968 &ip_6_6_6_6_o_10_10_10_2,
1969 &ip_6_6_6_6_o_10_10_10_2,
1970 &ip_6_6_6_6_o_10_10_10_2,
1971 &ip_6_6_6_6_o_10_10_10_2,
1972 &ip_6_6_6_6_o_10_10_10_2,
1973 &ip_6_6_6_6_o_10_10_10_2,
1974 &ip_6_6_6_6_o_10_10_10_2,
1975 &ip_6_6_6_6_o_10_10_10_2,
1976 &ip_6_6_6_6_o_10_10_10_2,
1977 &ip_6_6_6_6_o_10_10_10_2,
1978 &ip_6_6_6_6_o_10_10_10_2,
1979 &ip_6_6_6_6_o_10_10_10_2,
1980 &ip_6_6_6_6_o_10_10_10_2,
1981 &ip_6_6_6_6_o_10_10_10_2,
1982 &ip_6_6_6_6_o_10_10_10_2,
1983 &ip_6_6_6_6_o_10_10_10_2,
1984 &ip_6_6_6_6_o_10_10_10_2,
1985 &ip_6_6_6_6_o_10_10_10_2,
1986 &ip_6_6_6_6_o_10_10_10_2,
1987 &ip_6_6_6_6_o_10_10_10_2,
1988 &ip_6_6_6_6_o_10_10_10_2,
1989 &ip_6_6_6_6_o_10_10_10_1),
1990 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1992 fib_table_entry_path_remove(fib_index,
1997 tm->hw[0]->sw_if_index,
1998 ~0, // invalid fib index
2000 FIB_ROUTE_PATH_FLAG_NONE);
2002 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2003 FIB_TEST(fib_test_validate_entry(fei,
2004 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2006 &ip_6_6_6_6_o_10_10_10_1),
2007 "6.6.6.6/32 via 10.10.10.1");
2009 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2012 * A recursive via the two unequal cost entries
2014 fib_prefix_t bgp_44_s_32 = {
2016 .fp_proto = FIB_PROTOCOL_IP4,
2018 /* 200.200.200.201/32 */
2019 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2022 fei = fib_table_entry_path_add(fib_index,
2025 FIB_ENTRY_FLAG_NONE,
2027 &pfx_1_2_3_4_s_32.fp_addr,
2032 FIB_ROUTE_PATH_FLAG_NONE);
2033 fei = fib_table_entry_path_add(fib_index,
2036 FIB_ENTRY_FLAG_NONE,
2038 &pfx_1_2_3_5_s_32.fp_addr,
2043 FIB_ROUTE_PATH_FLAG_NONE);
2045 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2046 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2047 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2048 tm->hw[0]->sw_if_index,
2049 tm->hw[1]->sw_if_index),
2050 "RPF list for 1.2.3.4/32 contains both adjs");
2053 * test the uRPF check functions
2055 dpo_id_t dpo_44 = DPO_INVALID;
2058 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2059 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2061 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2062 "uRPF check for 68.68.68.68/32 on %d OK",
2063 tm->hw[0]->sw_if_index);
2064 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2065 "uRPF check for 68.68.68.68/32 on %d OK",
2066 tm->hw[1]->sw_if_index);
2067 FIB_TEST(!fib_urpf_check(urpfi, 99),
2068 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2072 fib_table_entry_delete(fib_index,
2075 fib_table_entry_delete(fib_index,
2078 fib_table_entry_delete(fib_index,
2083 * Add a recursive route:
2084 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2086 fib_prefix_t bgp_201_pfx = {
2088 .fp_proto = FIB_PROTOCOL_IP4,
2090 /* 200.200.200.201/32 */
2091 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2095 fib_prefix_t pfx_1_1_1_200_s_32 = {
2097 .fp_proto = FIB_PROTOCOL_IP4,
2099 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2103 fib_table_entry_path_add(fib_index,
2106 FIB_ENTRY_FLAG_NONE,
2108 &pfx_1_1_1_200_s_32.fp_addr,
2109 ~0, // no index provided.
2110 fib_index, // nexthop in same fib as route
2113 FIB_ROUTE_PATH_FLAG_NONE);
2115 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2117 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2118 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2119 "Flags set on RR via non-attached");
2120 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2121 "RPF list for BGP route empty");
2124 * +2 entry (BGP & RR) and +1 shared-path-list
2126 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2127 fib_path_list_db_size());
2128 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2129 fib_path_list_pool_size());
2130 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2131 fib_entry_pool_size());
2134 * insert a route that covers the missing 1.1.1.2/32. we epxect
2135 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2137 fib_prefix_t pfx_1_1_1_0_s_24 = {
2139 .fp_proto = FIB_PROTOCOL_IP4,
2142 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2146 fib_table_entry_path_add(fib_index,
2149 FIB_ENTRY_FLAG_NONE,
2152 tm->hw[0]->sw_if_index,
2153 ~0, // invalid fib index
2156 FIB_ROUTE_PATH_FLAG_NONE);
2157 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2158 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2159 ai = fib_entry_get_adj(fei);
2160 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2161 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2162 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2163 ai = fib_entry_get_adj(fei);
2164 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2165 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_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.200/24 resolves via 10.10.10.1");
2171 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2173 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2174 fib_path_list_db_size());
2175 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2176 fib_path_list_pool_size());
2177 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2178 fib_entry_pool_size());
2181 * the recursive adj for 200.200.200.200 should be updated.
2183 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2184 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2185 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2186 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2187 tm->hw[0]->sw_if_index),
2188 "RPF list for BGP route has itf index 0");
2191 * insert a more specific route than 1.1.1.0/24 that also covers the
2192 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2193 * 200.200.200.200 to resolve through it.
2195 fib_prefix_t pfx_1_1_1_0_s_28 = {
2197 .fp_proto = FIB_PROTOCOL_IP4,
2200 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2204 fib_table_entry_path_add(fib_index,
2207 FIB_ENTRY_FLAG_NONE,
2210 tm->hw[0]->sw_if_index,
2211 ~0, // invalid fib index
2214 FIB_ROUTE_PATH_FLAG_NONE);
2215 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2216 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2217 ai = fib_entry_get_adj(fei);
2218 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2221 * +1 entry. +1 shared path-list
2223 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2224 fib_path_list_db_size());
2225 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2226 fib_path_list_pool_size());
2227 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2228 fib_entry_pool_size());
2231 * the recursive adj for 200.200.200.200 should be updated.
2232 * 200.200.200.201 remains unchanged.
2234 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2235 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2238 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2240 fib_table_entry_path_remove(fib_index,
2245 tm->hw[0]->sw_if_index,
2248 FIB_ROUTE_PATH_FLAG_NONE);
2249 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2250 FIB_NODE_INDEX_INVALID),
2251 "1.1.1.0/28 removed");
2252 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2253 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2254 "1.1.1.0/28 lookup via /24");
2255 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2256 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2259 * -1 entry. -1 shared path-list
2261 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2262 fib_path_list_db_size());
2263 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2264 fib_path_list_pool_size());
2265 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2266 fib_entry_pool_size());
2269 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2271 fib_table_entry_path_remove(fib_index,
2276 tm->hw[0]->sw_if_index,
2279 FIB_ROUTE_PATH_FLAG_NONE);
2280 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2281 FIB_NODE_INDEX_INVALID),
2282 "1.1.1.0/24 removed");
2284 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2285 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2286 "1.1.1.2/32 route is DROP");
2287 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2288 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2289 "1.1.1.200/32 route is DROP");
2291 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2292 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2297 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2298 fib_path_list_db_size());
2299 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2300 fib_path_list_pool_size());
2301 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2302 fib_entry_pool_size());
2305 * insert the missing 1.1.1.2/32
2307 fei = fib_table_entry_path_add(fib_index,
2310 FIB_ENTRY_FLAG_NONE,
2313 tm->hw[0]->sw_if_index,
2314 ~0, // invalid fib index
2317 FIB_ROUTE_PATH_FLAG_NONE);
2318 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2319 ai = fib_entry_get_adj(fei);
2320 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2322 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2323 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2326 * no change. 1.1.1.2/32 was already there RR sourced.
2328 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2329 fib_path_list_db_size());
2330 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2331 fib_path_list_pool_size());
2332 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2333 fib_entry_pool_size());
2336 * remove 200.200.200.201/32 which does not have a valid via FIB
2338 fib_table_entry_path_remove(fib_index,
2342 &pfx_1_1_1_200_s_32.fp_addr,
2343 ~0, // no index provided.
2346 FIB_ROUTE_PATH_FLAG_NONE);
2349 * -2 entries (BGP and RR). -1 shared path-list;
2351 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2352 FIB_NODE_INDEX_INVALID),
2353 "200.200.200.201/32 removed");
2354 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2355 FIB_NODE_INDEX_INVALID),
2356 "1.1.1.200/32 removed");
2358 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2359 fib_path_list_db_size());
2360 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2361 fib_path_list_pool_size());
2362 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2363 fib_entry_pool_size());
2366 * remove 200.200.200.200/32 which does have a valid via FIB
2368 fib_table_entry_path_remove(fib_index,
2372 &pfx_1_1_1_2_s_32.fp_addr,
2373 ~0, // no index provided.
2376 FIB_ROUTE_PATH_FLAG_NONE);
2378 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2379 FIB_NODE_INDEX_INVALID),
2380 "200.200.200.200/32 removed");
2381 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2382 FIB_NODE_INDEX_INVALID),
2383 "1.1.1.2/32 still present");
2386 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2388 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2389 fib_path_list_db_size());
2390 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2391 fib_path_list_pool_size());
2392 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2393 fib_entry_pool_size());
2396 * A recursive prefix that has a 2 path load-balance.
2397 * It also shares a next-hop with other BGP prefixes and hence
2398 * test the ref counting of RR sourced prefixes and 2 level LB.
2400 const fib_prefix_t bgp_102 = {
2402 .fp_proto = FIB_PROTOCOL_IP4,
2404 /* 100.100.100.101/32 */
2405 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2408 fib_table_entry_path_add(fib_index,
2411 FIB_ENTRY_FLAG_NONE,
2413 &pfx_1_1_1_1_s_32.fp_addr,
2414 ~0, // no index provided.
2415 fib_index, // same as route
2418 FIB_ROUTE_PATH_FLAG_NONE);
2419 fib_table_entry_path_add(fib_index,
2422 FIB_ENTRY_FLAG_NONE,
2424 &pfx_1_1_1_2_s_32.fp_addr,
2425 ~0, // no index provided.
2426 fib_index, // same as route's FIB
2429 FIB_ROUTE_PATH_FLAG_NONE);
2430 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2431 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2432 dpo = fib_entry_contribute_ip_forwarding(fei);
2434 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2435 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2436 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2437 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2439 lb = load_balance_get(dpo->dpoi_index);
2440 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2441 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2442 "First via 10.10.10.1");
2443 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2444 "Second via 10.10.10.1");
2446 fib_table_entry_path_remove(fib_index,
2450 &pfx_1_1_1_1_s_32.fp_addr,
2451 ~0, // no index provided.
2452 fib_index, // same as route's FIB
2454 FIB_ROUTE_PATH_FLAG_NONE);
2455 fib_table_entry_path_remove(fib_index,
2459 &pfx_1_1_1_2_s_32.fp_addr,
2460 ~0, // no index provided.
2461 fib_index, // same as route's FIB
2463 FIB_ROUTE_PATH_FLAG_NONE);
2464 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2465 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2468 * remove the remaining recursives
2470 fib_table_entry_path_remove(fib_index,
2474 &pfx_1_1_1_1_s_32.fp_addr,
2475 ~0, // no index provided.
2476 fib_index, // same as route's FIB
2478 FIB_ROUTE_PATH_FLAG_NONE);
2479 fib_table_entry_path_remove(fib_index,
2483 &pfx_1_1_1_1_s_32.fp_addr,
2484 ~0, // no index provided.
2485 fib_index, // same as route's FIB
2487 FIB_ROUTE_PATH_FLAG_NONE);
2488 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2489 FIB_NODE_INDEX_INVALID),
2490 "100.100.100.100/32 removed");
2491 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2492 FIB_NODE_INDEX_INVALID),
2493 "100.100.100.101/32 removed");
2496 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2498 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2499 fib_path_list_db_size());
2500 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2501 fib_path_list_pool_size());
2502 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2503 fib_entry_pool_size());
2506 * Add a recursive route via a connected cover, using an adj-fib that does exist
2508 fib_table_entry_path_add(fib_index,
2511 FIB_ENTRY_FLAG_NONE,
2514 ~0, // no index provided.
2515 fib_index, // Same as route's FIB
2518 FIB_ROUTE_PATH_FLAG_NONE);
2521 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2523 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2524 fib_path_list_db_size());
2525 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2526 fib_path_list_pool_size());
2527 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2528 fib_entry_pool_size());
2530 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2531 dpo = fib_entry_contribute_ip_forwarding(fei);
2533 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2534 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2536 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2537 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2539 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2540 "Flags set on RR via existing attached");
2543 * Add a recursive route via a connected cover, using and adj-fib that does
2546 ip46_address_t nh_10_10_10_3 = {
2547 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2549 fib_prefix_t pfx_10_10_10_3 = {
2551 .fp_proto = FIB_PROTOCOL_IP4,
2552 .fp_addr = nh_10_10_10_3,
2555 fib_table_entry_path_add(fib_index,
2558 FIB_ENTRY_FLAG_NONE,
2561 ~0, // no index provided.
2565 FIB_ROUTE_PATH_FLAG_NONE);
2568 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2569 * one unshared non-recursive via 10.10.10.3
2571 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2572 fib_path_list_db_size());
2573 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2574 fib_path_list_pool_size());
2575 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2576 fib_entry_pool_size());
2578 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2581 tm->hw[0]->sw_if_index);
2583 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2584 dpo = fib_entry_contribute_ip_forwarding(fei);
2585 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2586 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2588 ai = fib_entry_get_adj(fei);
2589 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2590 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2591 fib_entry_get_flags(fei)),
2592 "Flags set on RR via non-existing attached");
2594 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2595 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2600 * remove the recursives
2602 fib_table_entry_path_remove(fib_index,
2607 ~0, // no index provided.
2608 fib_index, // same as route's FIB
2610 FIB_ROUTE_PATH_FLAG_NONE);
2611 fib_table_entry_path_remove(fib_index,
2616 ~0, // no index provided.
2617 fib_index, // same as route's FIB
2619 FIB_ROUTE_PATH_FLAG_NONE);
2621 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2622 FIB_NODE_INDEX_INVALID),
2623 "200.200.200.201/32 removed");
2624 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2625 FIB_NODE_INDEX_INVALID),
2626 "200.200.200.200/32 removed");
2627 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2628 FIB_NODE_INDEX_INVALID),
2629 "10.10.10.3/32 removed");
2632 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2633 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2635 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2636 fib_path_list_db_size());
2637 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2638 fib_path_list_pool_size());
2639 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2640 fib_entry_pool_size());
2645 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2647 fib_prefix_t pfx_5_5_5_5_s_32 = {
2649 .fp_proto = FIB_PROTOCOL_IP4,
2651 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2654 fib_prefix_t pfx_5_5_5_6_s_32 = {
2656 .fp_proto = FIB_PROTOCOL_IP4,
2658 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2661 fib_prefix_t pfx_5_5_5_7_s_32 = {
2663 .fp_proto = FIB_PROTOCOL_IP4,
2665 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2669 fib_table_entry_path_add(fib_index,
2672 FIB_ENTRY_FLAG_NONE,
2674 &pfx_5_5_5_6_s_32.fp_addr,
2675 ~0, // no index provided.
2679 FIB_ROUTE_PATH_FLAG_NONE);
2680 fib_table_entry_path_add(fib_index,
2683 FIB_ENTRY_FLAG_NONE,
2685 &pfx_5_5_5_7_s_32.fp_addr,
2686 ~0, // no index provided.
2690 FIB_ROUTE_PATH_FLAG_NONE);
2691 fib_table_entry_path_add(fib_index,
2694 FIB_ENTRY_FLAG_NONE,
2696 &pfx_5_5_5_5_s_32.fp_addr,
2697 ~0, // no index provided.
2701 FIB_ROUTE_PATH_FLAG_NONE);
2703 * +3 entries, +3 shared path-list
2705 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2706 fib_path_list_db_size());
2707 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2708 fib_path_list_pool_size());
2709 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2710 fib_entry_pool_size());
2713 * All the entries have only looped paths, so they are all drop
2715 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2716 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2717 "LB for 5.5.5.7/32 is via adj for DROP");
2718 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2719 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2720 "LB for 5.5.5.5/32 is via adj for DROP");
2721 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2722 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2723 "LB for 5.5.5.6/32 is via adj for DROP");
2726 * provide 5.5.5.6/32 with alternate path.
2727 * this will allow only 5.5.5.6/32 to forward with this path, the others
2728 * are still drop since the loop is still present.
2730 fib_table_entry_path_add(fib_index,
2733 FIB_ENTRY_FLAG_NONE,
2736 tm->hw[0]->sw_if_index,
2740 FIB_ROUTE_PATH_FLAG_NONE);
2742 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2743 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2745 lb = load_balance_get(dpo1->dpoi_index);
2746 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2748 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2749 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2750 FIB_TEST((ai_01 == dpo2->dpoi_index),
2751 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2753 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2754 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2755 "LB for 5.5.5.7/32 is via adj for DROP");
2756 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2757 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2758 "LB for 5.5.5.5/32 is via adj for DROP");
2761 * remove the alternate path for 5.5.5.6/32
2764 fib_table_entry_path_remove(fib_index,
2769 tm->hw[0]->sw_if_index,
2772 FIB_ROUTE_PATH_FLAG_NONE);
2774 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2775 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2776 "LB for 5.5.5.7/32 is via adj for DROP");
2777 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2778 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2779 "LB for 5.5.5.5/32 is via adj for DROP");
2780 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2781 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2782 "LB for 5.5.5.6/32 is via adj for DROP");
2785 * break the loop by giving 5.5.5.5/32 a new set of paths
2786 * expect all to forward via this new path.
2788 fib_table_entry_update_one_path(fib_index,
2791 FIB_ENTRY_FLAG_NONE,
2794 tm->hw[0]->sw_if_index,
2795 ~0, // invalid fib index
2798 FIB_ROUTE_PATH_FLAG_NONE);
2800 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2801 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2802 lb = load_balance_get(dpo1->dpoi_index);
2803 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2805 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2806 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2807 FIB_TEST((ai_01 == dpo2->dpoi_index),
2808 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2810 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2811 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2813 lb = load_balance_get(dpo2->dpoi_index);
2814 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2815 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2816 "5.5.5.5.7 via 5.5.5.5");
2818 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2819 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2821 lb = load_balance_get(dpo1->dpoi_index);
2822 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2823 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2824 "5.5.5.5.6 via 5.5.5.7");
2827 * revert back to the loop. so we can remove the prefixes with
2830 fib_table_entry_update_one_path(fib_index,
2833 FIB_ENTRY_FLAG_NONE,
2835 &pfx_5_5_5_6_s_32.fp_addr,
2836 ~0, // no index provided.
2840 FIB_ROUTE_PATH_FLAG_NONE);
2842 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2843 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2844 "LB for 5.5.5.7/32 is via adj for DROP");
2845 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2846 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2847 "LB for 5.5.5.5/32 is via adj for DROP");
2848 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2849 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2850 "LB for 5.5.5.6/32 is via adj for DROP");
2853 * remove all the 5.5.5.x/32 prefixes
2855 fib_table_entry_path_remove(fib_index,
2859 &pfx_5_5_5_6_s_32.fp_addr,
2860 ~0, // no index provided.
2861 fib_index, // same as route's FIB
2863 FIB_ROUTE_PATH_FLAG_NONE);
2864 fib_table_entry_path_remove(fib_index,
2868 &pfx_5_5_5_7_s_32.fp_addr,
2869 ~0, // no index provided.
2870 fib_index, // same as route's FIB
2872 FIB_ROUTE_PATH_FLAG_NONE);
2873 fib_table_entry_path_remove(fib_index,
2877 &pfx_5_5_5_5_s_32.fp_addr,
2878 ~0, // no index provided.
2879 fib_index, // same as route's FIB
2881 FIB_ROUTE_PATH_FLAG_NONE);
2882 fib_table_entry_path_remove(fib_index,
2887 ~0, // no index provided.
2888 fib_index, // same as route's FIB
2890 FIB_ROUTE_PATH_FLAG_NONE);
2893 * -3 entries, -3 shared path-list
2895 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2896 fib_path_list_db_size());
2897 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2898 fib_path_list_pool_size());
2899 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2900 fib_entry_pool_size());
2903 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2905 fib_table_entry_path_add(fib_index,
2908 FIB_ENTRY_FLAG_NONE,
2910 &pfx_5_5_5_6_s_32.fp_addr,
2911 ~0, // no index provided.
2915 FIB_ROUTE_PATH_FLAG_NONE);
2916 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2917 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2918 "1-level 5.5.5.6/32 loop is via adj for DROP");
2920 fib_table_entry_path_remove(fib_index,
2924 &pfx_5_5_5_6_s_32.fp_addr,
2925 ~0, // no index provided.
2926 fib_index, // same as route's FIB
2928 FIB_ROUTE_PATH_FLAG_NONE);
2929 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2930 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2931 "1-level 5.5.5.6/32 loop is removed");
2934 * A recursive route whose next-hop is covered by the prefix.
2935 * This would mean the via-fib, which inherits forwarding from its
2936 * cover, thus picks up forwarding from the prfix, which is via the
2937 * via-fib, and we have a loop.
2939 fib_prefix_t pfx_23_23_23_0_s_24 = {
2941 .fp_proto = FIB_PROTOCOL_IP4,
2943 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2946 fib_prefix_t pfx_23_23_23_23_s_32 = {
2948 .fp_proto = FIB_PROTOCOL_IP4,
2950 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2953 fei = fib_table_entry_path_add(fib_index,
2954 &pfx_23_23_23_0_s_24,
2956 FIB_ENTRY_FLAG_NONE,
2958 &pfx_23_23_23_23_s_32.fp_addr,
2963 FIB_ROUTE_PATH_FLAG_NONE);
2964 dpo = fib_entry_contribute_ip_forwarding(fei);
2965 FIB_TEST(load_balance_is_drop(dpo),
2966 "23.23.23.0/24 via covered is DROP");
2967 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2970 * add-remove test. no change.
2972 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2973 fib_path_list_db_size());
2974 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2975 fib_path_list_pool_size());
2976 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2977 fib_entry_pool_size());
2980 * A recursive route with recursion constraints.
2981 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2983 fib_table_entry_path_add(fib_index,
2986 FIB_ENTRY_FLAG_NONE,
2993 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2995 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2996 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2998 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2999 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3001 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3002 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3005 * save the load-balance. we expect it to be inplace modified
3007 lb = load_balance_get(dpo1->dpoi_index);
3010 * add a covering prefix for the via fib that would otherwise serve
3011 * as the resolving route when the host is removed
3013 fib_table_entry_path_add(fib_index,
3016 FIB_ENTRY_FLAG_NONE,
3019 tm->hw[0]->sw_if_index,
3020 ~0, // invalid fib index
3023 FIB_ROUTE_PATH_FLAG_NONE);
3024 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3025 ai = fib_entry_get_adj(fei);
3026 FIB_TEST((ai == ai_01),
3027 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3030 * remove the host via FIB - expect the BGP prefix to be drop
3032 fib_table_entry_path_remove(fib_index,
3037 tm->hw[0]->sw_if_index,
3038 ~0, // invalid fib index
3040 FIB_ROUTE_PATH_FLAG_NONE);
3042 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3043 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3046 * add the via-entry host reoute back. expect to resolve again
3048 fib_table_entry_path_add(fib_index,
3051 FIB_ENTRY_FLAG_NONE,
3054 tm->hw[0]->sw_if_index,
3055 ~0, // invalid fib index
3058 FIB_ROUTE_PATH_FLAG_NONE);
3059 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3060 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3063 * add another path for the recursive. it will then have 2.
3065 fib_prefix_t pfx_1_1_1_3_s_32 = {
3067 .fp_proto = FIB_PROTOCOL_IP4,
3069 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3072 fib_table_entry_path_add(fib_index,
3075 FIB_ENTRY_FLAG_NONE,
3078 tm->hw[0]->sw_if_index,
3079 ~0, // invalid fib index
3082 FIB_ROUTE_PATH_FLAG_NONE);
3084 fib_table_entry_path_add(fib_index,
3087 FIB_ENTRY_FLAG_NONE,
3089 &pfx_1_1_1_3_s_32.fp_addr,
3094 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3097 * add a bunch load more entries using this path combo so that we get
3098 * an LB-map created.
3101 fib_prefix_t bgp_78s[N_P];
3102 for (ii = 0; ii < N_P; ii++)
3104 bgp_78s[ii].fp_len = 32;
3105 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3106 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3109 fib_table_entry_path_add(fib_index,
3112 FIB_ENTRY_FLAG_NONE,
3114 &pfx_1_1_1_3_s_32.fp_addr,
3119 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3120 fib_table_entry_path_add(fib_index,
3123 FIB_ENTRY_FLAG_NONE,
3130 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3133 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3134 dpo = fib_entry_contribute_ip_forwarding(fei);
3136 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3137 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3138 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3139 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3140 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3141 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3142 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3143 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3146 * expect the lb-map used by the recursive's load-balance is using both buckets
3148 load_balance_map_t *lbm;
3151 lb = load_balance_get(dpo->dpoi_index);
3153 load_balance_map_lock(lbmi);
3154 lbm = load_balance_map_get(lbmi);
3156 FIB_TEST(lbm->lbm_buckets[0] == 0,
3157 "LB maps's bucket 0 is %d",
3158 lbm->lbm_buckets[0]);
3159 FIB_TEST(lbm->lbm_buckets[1] == 1,
3160 "LB maps's bucket 1 is %d",
3161 lbm->lbm_buckets[1]);
3164 * withdraw one of the /32 via-entrys.
3165 * that ECMP path will be unresolved and forwarding should continue on the
3166 * other available path. this is an iBGP PIC edge failover.
3167 * Test the forwarding changes without re-fetching the adj from the
3168 * recursive entry. this ensures its the same one that is updated; i.e. an
3171 fib_table_entry_path_remove(fib_index,
3176 tm->hw[0]->sw_if_index,
3177 ~0, // invalid fib index
3179 FIB_ROUTE_PATH_FLAG_NONE);
3181 /* suspend so the update walk kicks int */
3182 vlib_process_suspend(vlib_get_main(), 1e-5);
3184 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3185 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3186 "post PIC 200.200.200.200/32 was inplace modified");
3188 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3189 "post PIC adj for 200.200.200.200/32 is recursive"
3190 " via adj for 1.1.1.3");
3193 * the LB maps that was locked above should have been modified to remove
3194 * the path that was down, and thus its bucket points to a path that is
3197 FIB_TEST(lbm->lbm_buckets[0] == 1,
3198 "LB maps's bucket 0 is %d",
3199 lbm->lbm_buckets[0]);
3200 FIB_TEST(lbm->lbm_buckets[1] == 1,
3201 "LB maps's bucket 1 is %d",
3202 lbm->lbm_buckets[1]);
3204 load_balance_map_unlock(lbmi);
3207 * add it back. again
3209 fib_table_entry_path_add(fib_index,
3212 FIB_ENTRY_FLAG_NONE,
3215 tm->hw[0]->sw_if_index,
3216 ~0, // invalid fib index
3219 FIB_ROUTE_PATH_FLAG_NONE);
3221 /* suspend so the update walk kicks in */
3222 vlib_process_suspend(vlib_get_main(), 1e-5);
3224 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3225 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3226 "via adj for 1.1.1.1");
3227 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3228 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3229 "via adj for 1.1.1.3");
3231 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3232 dpo = fib_entry_contribute_ip_forwarding(fei);
3233 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3234 "post PIC 200.200.200.200/32 was inplace modified");
3237 * add a 3rd path. this makes the LB 16 buckets.
3239 fib_table_entry_path_add(fib_index,
3242 FIB_ENTRY_FLAG_NONE,
3244 &pfx_1_1_1_2_s_32.fp_addr,
3249 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3250 for (ii = 0; ii < N_P; ii++)
3252 fib_table_entry_path_add(fib_index,
3255 FIB_ENTRY_FLAG_NONE,
3257 &pfx_1_1_1_2_s_32.fp_addr,
3262 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3265 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3266 dpo = fib_entry_contribute_ip_forwarding(fei);
3267 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3268 "200.200.200.200/32 was inplace modified for 3rd path");
3269 FIB_TEST(16 == lb->lb_n_buckets,
3270 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3273 load_balance_map_lock(lbmi);
3274 lbm = load_balance_map_get(lbmi);
3276 for (ii = 0; ii < 16; ii++)
3278 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3279 "LB Map for 200.200.200.200/32 at %d is %d",
3280 ii, lbm->lbm_buckets[ii]);
3284 * trigger PIC by removing the first via-entry
3285 * the first 6 buckets of the map should map to the next 6
3287 fib_table_entry_path_remove(fib_index,
3292 tm->hw[0]->sw_if_index,
3295 FIB_ROUTE_PATH_FLAG_NONE);
3296 /* suspend so the update walk kicks int */
3297 vlib_process_suspend(vlib_get_main(), 1e-5);
3299 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3300 dpo = fib_entry_contribute_ip_forwarding(fei);
3301 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3302 "200.200.200.200/32 was inplace modified for 3rd path");
3303 FIB_TEST(2 == lb->lb_n_buckets,
3304 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3306 for (ii = 0; ii < 6; ii++)
3308 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3309 "LB Map for 200.200.200.200/32 at %d is %d",
3310 ii, lbm->lbm_buckets[ii]);
3312 for (ii = 6; ii < 16; ii++)
3314 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3315 "LB Map for 200.200.200.200/32 at %d is %d",
3316 ii, lbm->lbm_buckets[ii]);
3318 load_balance_map_unlock(lbmi);
3323 fib_table_entry_path_add(fib_index,
3326 FIB_ENTRY_FLAG_NONE,
3329 tm->hw[0]->sw_if_index,
3333 FIB_ROUTE_PATH_FLAG_NONE);
3335 for (ii = 0; ii < N_P; ii++)
3337 fib_table_entry_delete(fib_index,
3340 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3341 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3343 format_fib_prefix, &bgp_78s[ii]);
3345 fib_table_entry_path_remove(fib_index,
3349 &pfx_1_1_1_2_s_32.fp_addr,
3353 MPLS_LABEL_INVALID);
3354 fib_table_entry_path_remove(fib_index,
3362 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3363 fib_table_entry_path_remove(fib_index,
3367 &pfx_1_1_1_3_s_32.fp_addr,
3371 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3372 fib_table_entry_delete(fib_index,
3375 fib_table_entry_delete(fib_index,
3378 /* suspend so the update walk kicks int */
3379 vlib_process_suspend(vlib_get_main(), 1e-5);
3380 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3381 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3382 "1.1.1.1/28 removed");
3383 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3384 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3385 "1.1.1.3/32 removed");
3386 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3387 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3388 "200.200.200.200/32 removed");
3391 * add-remove test. no change.
3393 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3394 fib_path_list_db_size());
3395 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3396 fib_path_list_pool_size());
3397 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3398 fib_entry_pool_size());
3401 * A route whose paths are built up iteratively and then removed
3404 fib_prefix_t pfx_4_4_4_4_s_32 = {
3406 .fp_proto = FIB_PROTOCOL_IP4,
3409 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3413 fib_table_entry_path_add(fib_index,
3416 FIB_ENTRY_FLAG_NONE,
3419 tm->hw[0]->sw_if_index,
3423 FIB_ROUTE_PATH_FLAG_NONE);
3424 fib_table_entry_path_add(fib_index,
3427 FIB_ENTRY_FLAG_NONE,
3430 tm->hw[0]->sw_if_index,
3434 FIB_ROUTE_PATH_FLAG_NONE);
3435 fib_table_entry_path_add(fib_index,
3438 FIB_ENTRY_FLAG_NONE,
3441 tm->hw[0]->sw_if_index,
3445 FIB_ROUTE_PATH_FLAG_NONE);
3446 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3447 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3448 "4.4.4.4/32 present");
3450 fib_table_entry_delete(fib_index,
3453 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3454 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3455 "4.4.4.4/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 with multiple paths at once
3470 fib_route_path_t *r_paths = NULL;
3472 for (ii = 0; ii < 4; ii++)
3474 fib_route_path_t r_path = {
3475 .frp_proto = FIB_PROTOCOL_IP4,
3477 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3479 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3481 .frp_fib_index = ~0,
3483 vec_add1(r_paths, r_path);
3486 fib_table_entry_update(fib_index,
3489 FIB_ENTRY_FLAG_NONE,
3492 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3493 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3494 dpo = fib_entry_contribute_ip_forwarding(fei);
3496 lb = load_balance_get(dpo->dpoi_index);
3497 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3499 fib_table_entry_delete(fib_index,
3502 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3503 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3504 "4.4.4.4/32 removed");
3508 * add-remove test. no change.
3510 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3511 fib_path_list_db_size());
3512 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3513 fib_path_list_pool_size());
3514 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3515 fib_entry_pool_size());
3518 * A route deag route
3520 fib_table_entry_path_add(fib_index,
3523 FIB_ENTRY_FLAG_NONE,
3530 FIB_ROUTE_PATH_FLAG_NONE);
3532 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3533 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3535 dpo = fib_entry_contribute_ip_forwarding(fei);
3536 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3537 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3539 FIB_TEST((fib_index == lkd->lkd_fib_index),
3540 "4.4.4.4/32 is deag in %d %U",
3542 format_dpo_id, dpo, 0);
3544 fib_table_entry_delete(fib_index,
3547 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3548 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3549 "4.4.4.4/32 removed");
3553 * add-remove test. no change.
3555 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3556 fib_path_list_db_size());
3557 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3558 fib_path_list_pool_size());
3559 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3560 fib_entry_pool_size());
3564 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3566 fib_prefix_t pfx_34_1_1_1_s_32 = {
3568 .fp_proto = FIB_PROTOCOL_IP4,
3570 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3573 fib_prefix_t pfx_34_34_1_1_s_32 = {
3575 .fp_proto = FIB_PROTOCOL_IP4,
3577 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3580 fei = fib_table_entry_path_add(fib_index,
3583 FIB_ENTRY_FLAG_NONE,
3585 &pfx_34_34_1_1_s_32.fp_addr,
3590 FIB_ROUTE_PATH_FLAG_NONE);
3591 fei = fib_table_entry_path_add(fib_index,
3594 FIB_ENTRY_FLAG_NONE,
3596 &pfx_34_34_1_1_s_32.fp_addr,
3601 FIB_ROUTE_PATH_FLAG_NONE);
3602 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3603 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3607 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3608 * all of which are via 10.10.10.1, Itf1
3610 fib_table_entry_path_remove(fib_index,
3615 tm->hw[0]->sw_if_index,
3618 FIB_ROUTE_PATH_FLAG_NONE);
3619 fib_table_entry_path_remove(fib_index,
3624 tm->hw[0]->sw_if_index,
3627 FIB_ROUTE_PATH_FLAG_NONE);
3628 fib_table_entry_path_remove(fib_index,
3633 tm->hw[0]->sw_if_index,
3636 FIB_ROUTE_PATH_FLAG_NONE);
3638 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3639 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3640 "1.1.1.1/32 removed");
3641 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3642 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3643 "1.1.1.2/32 removed");
3644 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3645 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3646 "1.1.2.0/24 removed");
3649 * -3 entries and -1 shared path-list
3651 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3652 fib_path_list_db_size());
3653 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3654 fib_path_list_pool_size());
3655 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3656 fib_entry_pool_size());
3659 * An attached-host route. Expect to link to the incomplete adj
3661 fib_prefix_t pfx_4_1_1_1_s_32 = {
3663 .fp_proto = FIB_PROTOCOL_IP4,
3666 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3669 fib_table_entry_path_add(fib_index,
3672 FIB_ENTRY_FLAG_NONE,
3675 tm->hw[0]->sw_if_index,
3679 FIB_ROUTE_PATH_FLAG_NONE);
3681 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3682 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3683 ai = fib_entry_get_adj(fei);
3685 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3687 &pfx_4_1_1_1_s_32.fp_addr,
3688 tm->hw[0]->sw_if_index);
3689 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3693 * +1 entry and +1 shared path-list
3695 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3696 fib_path_list_db_size());
3697 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3698 fib_path_list_pool_size());
3699 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3700 fib_entry_pool_size());
3702 fib_table_entry_delete(fib_index,
3706 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3707 fib_path_list_db_size());
3708 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3709 fib_path_list_pool_size());
3710 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3711 fib_entry_pool_size());
3714 * add a v6 prefix via v4 next-hops
3716 fib_prefix_t pfx_2001_s_64 = {
3718 .fp_proto = FIB_PROTOCOL_IP6,
3720 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3723 fei = fib_table_entry_path_add(0, //default v6 table
3726 FIB_ENTRY_FLAG_NONE,
3729 tm->hw[0]->sw_if_index,
3733 FIB_ROUTE_PATH_FLAG_NONE);
3735 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3736 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3737 ai = fib_entry_get_adj(fei);
3739 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3740 "2001::/64 via ARP-adj");
3741 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3742 "2001::/64 is link type v6");
3743 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3744 "2001::/64 ADJ-adj is NH proto v4");
3745 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3748 * add a uRPF exempt prefix:
3750 * - it's forwarding is drop
3751 * - it's uRPF list is not empty
3752 * - the uRPF list for the default route (it's cover) is empty
3754 fei = fib_table_entry_special_add(fib_index,
3756 FIB_SOURCE_URPF_EXEMPT,
3757 FIB_ENTRY_FLAG_DROP);
3758 dpo = fib_entry_contribute_ip_forwarding(fei);
3759 FIB_TEST(load_balance_is_drop(dpo),
3760 "uRPF exempt 4.1.1.1/32 DROP");
3761 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3762 "uRPF list for exempt prefix has itf index 0");
3763 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3764 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3765 "uRPF list for 0.0.0.0/0 empty");
3767 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3770 * An adj-fib that fails the refinement criteria - no connected cover
3772 fib_prefix_t pfx_12_10_10_2_s_32 = {
3774 .fp_proto = FIB_PROTOCOL_IP4,
3777 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3781 fib_table_entry_update_one_path(fib_index,
3782 &pfx_12_10_10_2_s_32,
3784 FIB_ENTRY_FLAG_ATTACHED,
3786 &pfx_12_10_10_2_s_32.fp_addr,
3787 tm->hw[0]->sw_if_index,
3788 ~0, // invalid fib index
3791 FIB_ROUTE_PATH_FLAG_NONE);
3793 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3794 dpo = fib_entry_contribute_ip_forwarding(fei);
3795 FIB_TEST(!dpo_id_is_valid(dpo),
3796 "no connected cover adj-fib fails refinement");
3798 fib_table_entry_delete(fib_index,
3799 &pfx_12_10_10_2_s_32,
3803 * An adj-fib that fails the refinement criteria - cover is connected
3804 * but on a different interface
3806 fib_prefix_t pfx_10_10_10_127_s_32 = {
3808 .fp_proto = FIB_PROTOCOL_IP4,
3811 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3815 fib_table_entry_update_one_path(fib_index,
3816 &pfx_10_10_10_127_s_32,
3818 FIB_ENTRY_FLAG_ATTACHED,
3820 &pfx_10_10_10_127_s_32.fp_addr,
3821 tm->hw[1]->sw_if_index,
3822 ~0, // invalid fib index
3825 FIB_ROUTE_PATH_FLAG_NONE);
3827 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3828 dpo = fib_entry_contribute_ip_forwarding(fei);
3829 FIB_TEST(!dpo_id_is_valid(dpo),
3830 "wrong interface adj-fib fails refinement");
3832 fib_table_entry_delete(fib_index,
3833 &pfx_10_10_10_127_s_32,
3836 * change the table's flow-hash config - expect the update to propagete to
3837 * the entries' load-balance objects
3839 flow_hash_config_t old_hash_config, new_hash_config;
3841 old_hash_config = fib_table_get_flow_hash_config(fib_index,
3843 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
3844 IP_FLOW_HASH_DST_ADDR);
3846 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
3847 dpo = fib_entry_contribute_ip_forwarding(fei);
3848 lb = load_balance_get(dpo->dpoi_index);
3849 FIB_TEST((lb->lb_hash_config == old_hash_config),
3850 "Table and LB hash config match: %U",
3851 format_ip_flow_hash_config, lb->lb_hash_config);
3853 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
3855 FIB_TEST((lb->lb_hash_config == new_hash_config),
3856 "Table and LB newhash config match: %U",
3857 format_ip_flow_hash_config, lb->lb_hash_config);
3863 fib_table_entry_delete(fib_index,
3864 &pfx_10_10_10_1_s_32,
3866 fib_table_entry_delete(fib_index,
3867 &pfx_10_10_10_2_s_32,
3869 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3870 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
3871 "10.10.10.1/32 adj-fib removed");
3872 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3873 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
3874 "10.10.10.2/32 adj-fib removed");
3877 * -2 entries and -2 non-shared path-list
3879 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3880 fib_path_list_db_size());
3881 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
3882 fib_path_list_pool_size());
3883 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
3884 fib_entry_pool_size());
3887 * unlock the adjacencies for which this test provided a rewrite.
3888 * These are the last locks on these adjs. they should thus go away.
3892 adj_unlock(ai_12_12_12_12);
3894 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3899 * remove the interface prefixes
3901 local_pfx.fp_len = 32;
3902 fib_table_entry_special_remove(fib_index, &local_pfx,
3903 FIB_SOURCE_INTERFACE);
3904 fei = fib_table_lookup(fib_index, &local_pfx);
3906 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3907 fib_table_lookup_exact_match(fib_index, &local_pfx),
3908 "10.10.10.10/32 adj-fib removed");
3910 local_pfx.fp_len = 24;
3911 fib_table_entry_delete(fib_index, &local_pfx,
3912 FIB_SOURCE_INTERFACE);
3914 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3915 fib_table_lookup_exact_match(fib_index, &local_pfx),
3916 "10.10.10.10/24 adj-fib removed");
3919 * -2 entries and -2 non-shared path-list
3921 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3922 fib_path_list_db_size());
3923 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
3924 fib_path_list_pool_size());
3925 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
3926 fib_entry_pool_size());
3929 * Last but not least, remove the VRF
3931 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3934 "NO API Source'd prefixes");
3935 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3938 "NO RR Source'd prefixes");
3939 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
3941 FIB_SOURCE_INTERFACE)),
3942 "NO INterface Source'd prefixes");
3944 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
3946 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3947 fib_path_list_db_size());
3948 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
3949 fib_path_list_pool_size());
3950 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
3951 fib_entry_pool_size());
3952 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
3953 pool_elts(fib_urpf_list_pool));
3954 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
3955 pool_elts(load_balance_map_pool));
3956 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
3957 pool_elts(load_balance_pool));
3966 * In the default table check for the presence and correct forwarding
3967 * of the special entries
3969 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
3970 const dpo_id_t *dpo, *dpo_drop;
3971 const ip_adjacency_t *adj;
3972 const receive_dpo_t *rd;
3977 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
3980 /* via 2001:0:0:1::2 */
3981 ip46_address_t nh_2001_2 = {
3984 [0] = clib_host_to_net_u64(0x2001000000000001),
3985 [1] = clib_host_to_net_u64(0x0000000000000002),
3992 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
3994 /* Find or create FIB table 11 */
3995 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
3997 for (ii = 0; ii < 4; ii++)
3999 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4002 fib_prefix_t pfx_0_0 = {
4004 .fp_proto = FIB_PROTOCOL_IP6,
4012 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4013 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4014 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4015 "Default route is DROP");
4017 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4018 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4021 &pfx_0_0.fp_addr.ip6)),
4022 "default-route; fwd and non-fwd tables match");
4024 // FIXME - check specials.
4027 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4028 * each with 2 entries and a v6 mfib with 4 path-lists.
4029 * All entries are special so no path-list sharing.
4032 #define PNPS (5+4+4)
4033 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4034 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4035 fib_path_list_pool_size());
4036 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4037 fib_entry_pool_size());
4040 * add interface routes.
4041 * validate presence of /64 attached and /128 recieve.
4042 * test for the presence of the receive address in the glean and local adj
4044 * receive on 2001:0:0:1::1/128
4046 fib_prefix_t local_pfx = {
4048 .fp_proto = FIB_PROTOCOL_IP6,
4052 [0] = clib_host_to_net_u64(0x2001000000000001),
4053 [1] = clib_host_to_net_u64(0x0000000000000001),
4059 fib_table_entry_update_one_path(fib_index, &local_pfx,
4060 FIB_SOURCE_INTERFACE,
4061 (FIB_ENTRY_FLAG_CONNECTED |
4062 FIB_ENTRY_FLAG_ATTACHED),
4065 tm->hw[0]->sw_if_index,
4069 FIB_ROUTE_PATH_FLAG_NONE);
4070 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4072 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4074 ai = fib_entry_get_adj(fei);
4075 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4077 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4078 "attached interface adj is glean");
4079 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4080 &adj->sub_type.glean.receive_addr)),
4081 "attached interface adj is receive ok");
4082 dpo = fib_entry_contribute_ip_forwarding(fei);
4083 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4086 &local_pfx.fp_addr.ip6)),
4087 "attached-route; fwd and non-fwd tables match");
4089 local_pfx.fp_len = 128;
4090 fib_table_entry_update_one_path(fib_index, &local_pfx,
4091 FIB_SOURCE_INTERFACE,
4092 (FIB_ENTRY_FLAG_CONNECTED |
4093 FIB_ENTRY_FLAG_LOCAL),
4096 tm->hw[0]->sw_if_index,
4097 ~0, // invalid fib index
4100 FIB_ROUTE_PATH_FLAG_NONE);
4101 fei = fib_table_lookup(fib_index, &local_pfx);
4103 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4105 dpo = fib_entry_contribute_ip_forwarding(fei);
4106 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4107 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4108 "local interface adj is local");
4109 rd = receive_dpo_get(dpo->dpoi_index);
4111 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4113 "local interface adj is receive ok");
4115 dpo = fib_entry_contribute_ip_forwarding(fei);
4116 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4119 &local_pfx.fp_addr.ip6)),
4120 "local-route; fwd and non-fwd tables match");
4123 * +2 entries. +2 unshared path-lists
4125 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4126 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4127 fib_path_list_pool_size());
4128 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4129 fib_entry_pool_size());
4132 * Modify the default route to be via an adj not yet known.
4133 * this sources the defalut route with the API source, which is
4134 * a higher preference to the DEFAULT_ROUTE source
4136 fib_table_entry_path_add(fib_index, &pfx_0_0,
4138 FIB_ENTRY_FLAG_NONE,
4141 tm->hw[0]->sw_if_index,
4145 FIB_ROUTE_PATH_FLAG_NONE);
4146 fei = fib_table_lookup(fib_index, &pfx_0_0);
4148 FIB_TEST((fei == dfrt), "default route same index");
4149 ai = fib_entry_get_adj(fei);
4150 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4152 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4153 "adj is incomplete");
4154 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4155 "adj nbr next-hop ok");
4158 * find the adj in the shared db
4160 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4163 tm->hw[0]->sw_if_index);
4164 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4165 adj_unlock(locked_ai);
4168 * no more entires. +1 shared path-list
4170 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4171 fib_path_list_db_size());
4172 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4173 fib_path_list_pool_size());
4174 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4175 fib_entry_pool_size());
4178 * remove the API source from the default route. We expected
4179 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4181 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4185 tm->hw[0]->sw_if_index,
4188 FIB_ROUTE_PATH_FLAG_NONE);
4189 fei = fib_table_lookup(fib_index, &pfx_0_0);
4191 FIB_TEST((fei == dfrt), "default route same index");
4192 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4193 "Default route is DROP");
4196 * no more entires. -1 shared path-list
4198 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4199 fib_path_list_db_size());
4200 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4201 fib_path_list_pool_size());
4202 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4203 fib_entry_pool_size());
4206 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4208 fib_prefix_t pfx_2001_1_2_s_128 = {
4210 .fp_proto = FIB_PROTOCOL_IP6,
4214 [0] = clib_host_to_net_u64(0x2001000000000001),
4215 [1] = clib_host_to_net_u64(0x0000000000000002),
4220 fib_prefix_t pfx_2001_1_3_s_128 = {
4222 .fp_proto = FIB_PROTOCOL_IP6,
4226 [0] = clib_host_to_net_u64(0x2001000000000001),
4227 [1] = clib_host_to_net_u64(0x0000000000000003),
4233 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4236 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4238 &pfx_2001_1_2_s_128.fp_addr,
4239 tm->hw[0]->sw_if_index);
4240 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4241 adj = adj_get(ai_01);
4242 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4243 "adj is incomplete");
4244 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4245 &adj->sub_type.nbr.next_hop)),
4246 "adj nbr next-hop ok");
4248 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4249 fib_test_build_rewrite(eth_addr));
4250 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4252 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4253 &adj->sub_type.nbr.next_hop)),
4254 "adj nbr next-hop ok");
4256 fib_table_entry_update_one_path(fib_index,
4257 &pfx_2001_1_2_s_128,
4259 FIB_ENTRY_FLAG_ATTACHED,
4261 &pfx_2001_1_2_s_128.fp_addr,
4262 tm->hw[0]->sw_if_index,
4266 FIB_ROUTE_PATH_FLAG_NONE);
4268 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4269 ai = fib_entry_get_adj(fei);
4270 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4274 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4276 &pfx_2001_1_3_s_128.fp_addr,
4277 tm->hw[0]->sw_if_index);
4278 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4279 adj = adj_get(ai_02);
4280 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4281 "adj is incomplete");
4282 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4283 &adj->sub_type.nbr.next_hop)),
4284 "adj nbr next-hop ok");
4286 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4287 fib_test_build_rewrite(eth_addr));
4288 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4290 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4291 &adj->sub_type.nbr.next_hop)),
4292 "adj nbr next-hop ok");
4293 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4295 fib_table_entry_update_one_path(fib_index,
4296 &pfx_2001_1_3_s_128,
4298 FIB_ENTRY_FLAG_ATTACHED,
4300 &pfx_2001_1_3_s_128.fp_addr,
4301 tm->hw[0]->sw_if_index,
4305 FIB_ROUTE_PATH_FLAG_NONE);
4307 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4308 ai = fib_entry_get_adj(fei);
4309 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4312 * +2 entries, +2 unshread path-lists.
4314 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4315 fib_path_list_db_size());
4316 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4317 fib_path_list_pool_size());
4318 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4319 fib_entry_pool_size());
4322 * Add a 2 routes via the first ADJ. ensure path-list sharing
4324 fib_prefix_t pfx_2001_a_s_64 = {
4326 .fp_proto = FIB_PROTOCOL_IP6,
4330 [0] = clib_host_to_net_u64(0x200100000000000a),
4331 [1] = clib_host_to_net_u64(0x0000000000000000),
4336 fib_prefix_t pfx_2001_b_s_64 = {
4338 .fp_proto = FIB_PROTOCOL_IP6,
4342 [0] = clib_host_to_net_u64(0x200100000000000b),
4343 [1] = clib_host_to_net_u64(0x0000000000000000),
4349 fib_table_entry_path_add(fib_index,
4352 FIB_ENTRY_FLAG_NONE,
4355 tm->hw[0]->sw_if_index,
4359 FIB_ROUTE_PATH_FLAG_NONE);
4360 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4361 ai = fib_entry_get_adj(fei);
4362 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4363 fib_table_entry_path_add(fib_index,
4366 FIB_ENTRY_FLAG_NONE,
4369 tm->hw[0]->sw_if_index,
4373 FIB_ROUTE_PATH_FLAG_NONE);
4374 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4375 ai = fib_entry_get_adj(fei);
4376 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4379 * +2 entries, +1 shared path-list.
4381 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4382 fib_path_list_db_size());
4383 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4384 fib_path_list_pool_size());
4385 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4386 fib_entry_pool_size());
4389 * add a v4 prefix via a v6 next-hop
4391 fib_prefix_t pfx_1_1_1_1_s_32 = {
4393 .fp_proto = FIB_PROTOCOL_IP4,
4395 .ip4.as_u32 = 0x01010101,
4398 fei = fib_table_entry_path_add(0, // default table
4401 FIB_ENTRY_FLAG_NONE,
4404 tm->hw[0]->sw_if_index,
4408 FIB_ROUTE_PATH_FLAG_NONE);
4409 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4410 "1.1.1.1/32 o v6 route present");
4411 ai = fib_entry_get_adj(fei);
4413 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4414 "1.1.1.1/32 via ARP-adj");
4415 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4416 "1.1.1.1/32 ADJ-adj is link type v4");
4417 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4418 "1.1.1.1/32 ADJ-adj is NH proto v6");
4419 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4424 fib_prefix_t pfx_2001_c_s_64 = {
4426 .fp_proto = FIB_PROTOCOL_IP6,
4430 [0] = clib_host_to_net_u64(0x200100000000000c),
4431 [1] = clib_host_to_net_u64(0x0000000000000000),
4436 fib_table_entry_path_add(fib_index,
4439 FIB_ENTRY_FLAG_ATTACHED,
4442 tm->hw[0]->sw_if_index,
4446 FIB_ROUTE_PATH_FLAG_NONE);
4447 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4448 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4449 ai = fib_entry_get_adj(fei);
4451 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4452 "2001:0:0:c/64 attached resolves via glean");
4454 fib_table_entry_path_remove(fib_index,
4459 tm->hw[0]->sw_if_index,
4462 FIB_ROUTE_PATH_FLAG_NONE);
4463 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4464 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4467 * Shutdown the interface on which we have a connected and through
4468 * which the routes are reachable.
4469 * This will result in the connected, adj-fibs, and routes linking to drop
4470 * The local/for-us prefix continues to receive.
4472 clib_error_t * error;
4474 error = vnet_sw_interface_set_flags(vnet_get_main(),
4475 tm->hw[0]->sw_if_index,
4476 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4477 FIB_TEST((NULL == error), "Interface shutdown OK");
4479 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4480 dpo = fib_entry_contribute_ip_forwarding(fei);
4481 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4482 "2001::b/64 resolves via drop");
4484 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4485 dpo = fib_entry_contribute_ip_forwarding(fei);
4486 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4487 "2001::a/64 resolves via drop");
4488 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4489 dpo = fib_entry_contribute_ip_forwarding(fei);
4490 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4491 "2001:0:0:1::3/64 resolves via drop");
4492 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4493 dpo = fib_entry_contribute_ip_forwarding(fei);
4494 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4495 "2001:0:0:1::2/64 resolves via drop");
4496 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4497 dpo = fib_entry_contribute_ip_forwarding(fei);
4498 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4499 "2001:0:0:1::1/128 not drop");
4500 local_pfx.fp_len = 64;
4501 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4502 dpo = fib_entry_contribute_ip_forwarding(fei);
4503 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4504 "2001:0:0:1/64 resolves via drop");
4509 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4510 fib_path_list_db_size());
4511 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4512 fib_path_list_pool_size());
4513 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4514 fib_entry_pool_size());
4517 * shutdown one of the other interfaces, then add a connected.
4518 * and swap one of the routes to it.
4520 error = vnet_sw_interface_set_flags(vnet_get_main(),
4521 tm->hw[1]->sw_if_index,
4522 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4523 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4525 fib_prefix_t connected_pfx = {
4527 .fp_proto = FIB_PROTOCOL_IP6,
4530 /* 2001:0:0:2::1/64 */
4532 [0] = clib_host_to_net_u64(0x2001000000000002),
4533 [1] = clib_host_to_net_u64(0x0000000000000001),
4538 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4539 FIB_SOURCE_INTERFACE,
4540 (FIB_ENTRY_FLAG_CONNECTED |
4541 FIB_ENTRY_FLAG_ATTACHED),
4544 tm->hw[1]->sw_if_index,
4548 FIB_ROUTE_PATH_FLAG_NONE);
4549 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4550 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4551 dpo = fib_entry_contribute_ip_forwarding(fei);
4552 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4553 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4554 "2001:0:0:2/64 not resolves via drop");
4556 connected_pfx.fp_len = 128;
4557 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4558 FIB_SOURCE_INTERFACE,
4559 (FIB_ENTRY_FLAG_CONNECTED |
4560 FIB_ENTRY_FLAG_LOCAL),
4563 tm->hw[0]->sw_if_index,
4564 ~0, // invalid fib index
4567 FIB_ROUTE_PATH_FLAG_NONE);
4568 fei = fib_table_lookup(fib_index, &connected_pfx);
4570 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4571 dpo = fib_entry_contribute_ip_forwarding(fei);
4572 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4573 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4574 "local interface adj is local");
4575 rd = receive_dpo_get(dpo->dpoi_index);
4576 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4578 "local interface adj is receive ok");
4581 * +2 entries, +2 unshared path-lists
4583 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4584 fib_path_list_db_size());
4585 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4586 fib_path_list_pool_size());
4587 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4588 fib_entry_pool_size());
4592 * bring the interface back up. we expected the routes to return
4593 * to normal forwarding.
4595 error = vnet_sw_interface_set_flags(vnet_get_main(),
4596 tm->hw[0]->sw_if_index,
4597 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4598 FIB_TEST((NULL == error), "Interface bring-up OK");
4599 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4600 ai = fib_entry_get_adj(fei);
4601 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4602 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4603 ai = fib_entry_get_adj(fei);
4604 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4605 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4606 ai = fib_entry_get_adj(fei);
4607 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4608 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4609 ai = fib_entry_get_adj(fei);
4610 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4611 local_pfx.fp_len = 64;
4612 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4613 ai = fib_entry_get_adj(fei);
4615 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4616 "attached interface adj is glean");
4619 * Same test as above, but this time the HW interface goes down
4621 error = vnet_hw_interface_set_flags(vnet_get_main(),
4622 tm->hw_if_indicies[0],
4623 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4624 FIB_TEST((NULL == error), "Interface shutdown OK");
4626 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4627 dpo = fib_entry_contribute_ip_forwarding(fei);
4628 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4629 "2001::b/64 resolves via drop");
4630 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4631 dpo = fib_entry_contribute_ip_forwarding(fei);
4632 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4633 "2001::a/64 resolves via drop");
4634 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4635 dpo = fib_entry_contribute_ip_forwarding(fei);
4636 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4637 "2001:0:0:1::3/128 resolves via drop");
4638 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4639 dpo = fib_entry_contribute_ip_forwarding(fei);
4640 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4641 "2001:0:0:1::2/128 resolves via drop");
4642 local_pfx.fp_len = 128;
4643 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4644 dpo = fib_entry_contribute_ip_forwarding(fei);
4645 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4646 "2001:0:0:1::1/128 not drop");
4647 local_pfx.fp_len = 64;
4648 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4649 dpo = fib_entry_contribute_ip_forwarding(fei);
4650 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4651 "2001:0:0:1/64 resolves via drop");
4653 error = vnet_hw_interface_set_flags(vnet_get_main(),
4654 tm->hw_if_indicies[0],
4655 VNET_HW_INTERFACE_FLAG_LINK_UP);
4656 FIB_TEST((NULL == error), "Interface bring-up OK");
4657 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4658 ai = fib_entry_get_adj(fei);
4659 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4660 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4661 ai = fib_entry_get_adj(fei);
4662 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4663 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4664 ai = fib_entry_get_adj(fei);
4665 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4666 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4667 ai = fib_entry_get_adj(fei);
4668 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4669 local_pfx.fp_len = 64;
4670 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4671 ai = fib_entry_get_adj(fei);
4673 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4674 "attached interface adj is glean");
4677 * Delete the interface that the routes reolve through.
4678 * Again no routes are removed. They all point to drop.
4680 * This is considered an error case. The control plane should
4681 * not remove interfaces through which routes resolve, but
4682 * such things can happen. ALL affected routes will drop.
4684 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4686 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4687 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4688 "2001::b/64 resolves via drop");
4689 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4690 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4691 "2001::b/64 resolves via drop");
4692 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4693 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4694 "2001:0:0:1::3/64 resolves via drop");
4695 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4696 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4697 "2001:0:0:1::2/64 resolves via drop");
4698 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4699 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4700 "2001:0:0:1::1/128 is drop");
4701 local_pfx.fp_len = 64;
4702 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4703 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4704 "2001:0:0:1/64 resolves via drop");
4709 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4710 fib_path_list_db_size());
4711 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4712 fib_path_list_pool_size());
4713 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4714 fib_entry_pool_size());
4717 * Add the interface back. routes stay unresolved.
4719 error = ethernet_register_interface(vnet_get_main(),
4720 test_interface_device_class.index,
4723 &tm->hw_if_indicies[0],
4724 /* flag change */ 0);
4726 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4727 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4728 "2001::b/64 resolves via drop");
4729 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4730 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4731 "2001::b/64 resolves via drop");
4732 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4733 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4734 "2001:0:0:1::3/64 resolves via drop");
4735 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4736 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4737 "2001:0:0:1::2/64 resolves via drop");
4738 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4739 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4740 "2001:0:0:1::1/128 is drop");
4741 local_pfx.fp_len = 64;
4742 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4743 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4744 "2001:0:0:1/64 resolves via drop");
4747 * CLEANUP ALL the routes
4749 fib_table_entry_delete(fib_index,
4752 fib_table_entry_delete(fib_index,
4755 fib_table_entry_delete(fib_index,
4758 fib_table_entry_delete(fib_index,
4759 &pfx_2001_1_3_s_128,
4761 fib_table_entry_delete(fib_index,
4762 &pfx_2001_1_2_s_128,
4764 local_pfx.fp_len = 64;
4765 fib_table_entry_delete(fib_index, &local_pfx,
4766 FIB_SOURCE_INTERFACE);
4767 local_pfx.fp_len = 128;
4768 fib_table_entry_special_remove(fib_index, &local_pfx,
4769 FIB_SOURCE_INTERFACE);
4770 connected_pfx.fp_len = 64;
4771 fib_table_entry_delete(fib_index, &connected_pfx,
4772 FIB_SOURCE_INTERFACE);
4773 connected_pfx.fp_len = 128;
4774 fib_table_entry_special_remove(fib_index, &connected_pfx,
4775 FIB_SOURCE_INTERFACE);
4777 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4778 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4779 "2001::a/64 removed");
4780 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4781 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4782 "2001::b/64 removed");
4783 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4784 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4785 "2001:0:0:1::3/128 removed");
4786 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4787 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4788 "2001:0:0:1::3/128 removed");
4789 local_pfx.fp_len = 64;
4790 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4791 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4792 "2001:0:0:1/64 removed");
4793 local_pfx.fp_len = 128;
4794 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4795 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4796 "2001:0:0:1::1/128 removed");
4797 connected_pfx.fp_len = 64;
4798 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4799 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4800 "2001:0:0:2/64 removed");
4801 connected_pfx.fp_len = 128;
4802 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4803 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4804 "2001:0:0:2::1/128 removed");
4807 * -8 entries. -7 path-lists (1 was shared).
4809 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4810 fib_path_list_db_size());
4811 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
4812 fib_path_list_pool_size());
4813 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4814 fib_entry_pool_size());
4817 * now remove the VRF
4819 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4821 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4822 fib_path_list_db_size());
4823 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
4824 fib_path_list_pool_size());
4825 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
4826 fib_entry_pool_size());
4832 * return the interfaces to up state
4834 error = vnet_sw_interface_set_flags(vnet_get_main(),
4835 tm->hw[0]->sw_if_index,
4836 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4837 error = vnet_sw_interface_set_flags(vnet_get_main(),
4838 tm->hw[1]->sw_if_index,
4839 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4841 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4848 * Test Attached Exports
4853 const dpo_id_t *dpo, *dpo_drop;
4854 const u32 fib_index = 0;
4855 fib_node_index_t fei;
4862 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4866 * add interface routes. We'll assume this works. It's more rigorously
4869 fib_prefix_t local_pfx = {
4871 .fp_proto = FIB_PROTOCOL_IP4,
4875 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
4880 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
4881 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
4883 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
4885 fib_table_entry_update_one_path(fib_index, &local_pfx,
4886 FIB_SOURCE_INTERFACE,
4887 (FIB_ENTRY_FLAG_CONNECTED |
4888 FIB_ENTRY_FLAG_ATTACHED),
4891 tm->hw[0]->sw_if_index,
4895 FIB_ROUTE_PATH_FLAG_NONE);
4896 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4897 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4898 "attached interface route present");
4900 local_pfx.fp_len = 32;
4901 fib_table_entry_update_one_path(fib_index, &local_pfx,
4902 FIB_SOURCE_INTERFACE,
4903 (FIB_ENTRY_FLAG_CONNECTED |
4904 FIB_ENTRY_FLAG_LOCAL),
4907 tm->hw[0]->sw_if_index,
4908 ~0, // invalid fib index
4911 FIB_ROUTE_PATH_FLAG_NONE);
4912 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4914 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
4915 "local interface route present");
4918 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4920 fib_prefix_t pfx_10_10_10_1_s_32 = {
4922 .fp_proto = FIB_PROTOCOL_IP4,
4925 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
4928 fib_node_index_t ai;
4930 fib_table_entry_update_one_path(fib_index,
4931 &pfx_10_10_10_1_s_32,
4933 FIB_ENTRY_FLAG_ATTACHED,
4935 &pfx_10_10_10_1_s_32.fp_addr,
4936 tm->hw[0]->sw_if_index,
4937 ~0, // invalid fib index
4940 FIB_ROUTE_PATH_FLAG_NONE);
4942 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
4943 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
4944 ai = fib_entry_get_adj(fei);
4947 * create another FIB table into which routes will be imported
4949 u32 import_fib_index1;
4951 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
4954 * Add an attached route in the import FIB
4956 local_pfx.fp_len = 24;
4957 fib_table_entry_update_one_path(import_fib_index1,
4960 FIB_ENTRY_FLAG_NONE,
4963 tm->hw[0]->sw_if_index,
4964 ~0, // invalid fib index
4967 FIB_ROUTE_PATH_FLAG_NONE);
4968 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4969 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
4972 * check for the presence of the adj-fibs in the import table
4974 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
4975 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
4976 FIB_TEST((ai == fib_entry_get_adj(fei)),
4977 "adj-fib1 Import uses same adj as export");
4980 * check for the presence of the local in the import table
4982 local_pfx.fp_len = 32;
4983 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
4984 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
4987 * Add another adj-fin in the export table. Expect this
4988 * to get magically exported;
4990 fib_prefix_t pfx_10_10_10_2_s_32 = {
4992 .fp_proto = FIB_PROTOCOL_IP4,
4995 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
4999 fib_table_entry_update_one_path(fib_index,
5000 &pfx_10_10_10_2_s_32,
5002 FIB_ENTRY_FLAG_ATTACHED,
5004 &pfx_10_10_10_2_s_32.fp_addr,
5005 tm->hw[0]->sw_if_index,
5006 ~0, // invalid fib index
5009 FIB_ROUTE_PATH_FLAG_NONE);
5010 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5011 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5012 ai = fib_entry_get_adj(fei);
5014 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5015 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5016 FIB_TEST((ai == fib_entry_get_adj(fei)),
5017 "Import uses same adj as export");
5018 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5019 "ADJ-fib2 imported flags %d",
5020 fib_entry_get_flags(fei));
5023 * create a 2nd FIB table into which routes will be imported
5025 u32 import_fib_index2;
5027 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
5030 * Add an attached route in the import FIB
5032 local_pfx.fp_len = 24;
5033 fib_table_entry_update_one_path(import_fib_index2,
5036 FIB_ENTRY_FLAG_NONE,
5039 tm->hw[0]->sw_if_index,
5040 ~0, // invalid fib index
5043 FIB_ROUTE_PATH_FLAG_NONE);
5044 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5045 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5048 * check for the presence of all the adj-fibs and local in the import table
5050 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5051 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5052 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5053 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5054 local_pfx.fp_len = 32;
5055 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5056 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5059 * add a 3rd adj-fib. expect it to be exported to both tables.
5061 fib_prefix_t pfx_10_10_10_3_s_32 = {
5063 .fp_proto = FIB_PROTOCOL_IP4,
5066 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5070 fib_table_entry_update_one_path(fib_index,
5071 &pfx_10_10_10_3_s_32,
5073 FIB_ENTRY_FLAG_ATTACHED,
5075 &pfx_10_10_10_3_s_32.fp_addr,
5076 tm->hw[0]->sw_if_index,
5077 ~0, // invalid fib index
5080 FIB_ROUTE_PATH_FLAG_NONE);
5081 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5082 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5083 ai = fib_entry_get_adj(fei);
5085 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5086 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5087 FIB_TEST((ai == fib_entry_get_adj(fei)),
5088 "Import uses same adj as export");
5089 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5090 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5091 FIB_TEST((ai == fib_entry_get_adj(fei)),
5092 "Import uses same adj as export");
5095 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5097 fib_table_entry_delete(fib_index,
5098 &pfx_10_10_10_3_s_32,
5101 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5102 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5104 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5105 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5107 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5108 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5111 * remove the attached route from the 2nd FIB. expect the imported
5112 * entires to be removed
5114 local_pfx.fp_len = 24;
5115 fib_table_entry_delete(import_fib_index2,
5118 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5119 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5121 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5122 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5123 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5124 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5125 local_pfx.fp_len = 32;
5126 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5127 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5129 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5130 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5131 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5132 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5133 local_pfx.fp_len = 32;
5134 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5135 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5138 * modify the route in FIB1 so it is no longer attached. expect the imported
5139 * entires to be removed
5141 local_pfx.fp_len = 24;
5142 fib_table_entry_update_one_path(import_fib_index1,
5145 FIB_ENTRY_FLAG_NONE,
5147 &pfx_10_10_10_2_s_32.fp_addr,
5148 tm->hw[0]->sw_if_index,
5149 ~0, // invalid fib index
5152 FIB_ROUTE_PATH_FLAG_NONE);
5153 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5154 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5155 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5156 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5157 local_pfx.fp_len = 32;
5158 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5159 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5162 * modify it back to attached. expect the adj-fibs back
5164 local_pfx.fp_len = 24;
5165 fib_table_entry_update_one_path(import_fib_index1,
5168 FIB_ENTRY_FLAG_NONE,
5171 tm->hw[0]->sw_if_index,
5172 ~0, // invalid fib index
5175 FIB_ROUTE_PATH_FLAG_NONE);
5176 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5177 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5178 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5179 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5180 local_pfx.fp_len = 32;
5181 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5182 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5185 * add a covering attached next-hop for the interface address, so we have
5186 * a valid adj to find when we check the forwarding tables
5188 fib_prefix_t pfx_10_0_0_0_s_8 = {
5190 .fp_proto = FIB_PROTOCOL_IP4,
5193 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5197 fei = fib_table_entry_update_one_path(fib_index,
5200 FIB_ENTRY_FLAG_NONE,
5202 &pfx_10_10_10_3_s_32.fp_addr,
5203 tm->hw[0]->sw_if_index,
5204 ~0, // invalid fib index
5207 FIB_ROUTE_PATH_FLAG_NONE);
5208 dpo = fib_entry_contribute_ip_forwarding(fei);
5211 * remove the route in the export fib. expect the adj-fibs to be removed
5213 local_pfx.fp_len = 24;
5214 fib_table_entry_delete(fib_index,
5216 FIB_SOURCE_INTERFACE);
5218 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5219 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5220 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5221 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5222 local_pfx.fp_len = 32;
5223 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5224 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5227 * the adj-fibs in the export VRF are present in the FIB table,
5228 * but not installed in forwarding, since they have no attached cover.
5229 * Consequently a lookup in the MTRIE gives the adj for the covering
5232 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5233 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5236 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5237 FIB_TEST(lbi == dpo->dpoi_index,
5238 "10.10.10.1 forwards on \n%U not \n%U",
5239 format_load_balance, lbi, 0,
5240 format_dpo_id, dpo, 0);
5241 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5242 FIB_TEST(lbi == dpo->dpoi_index,
5243 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5244 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5245 FIB_TEST(lbi == dpo->dpoi_index,
5246 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5249 * add the export prefix back, but not as attached.
5250 * No adj-fibs in export nor import tables
5252 local_pfx.fp_len = 24;
5253 fei = fib_table_entry_update_one_path(fib_index,
5256 FIB_ENTRY_FLAG_NONE,
5258 &pfx_10_10_10_1_s_32.fp_addr,
5259 tm->hw[0]->sw_if_index,
5260 ~0, // invalid fib index
5263 FIB_ROUTE_PATH_FLAG_NONE);
5264 dpo = fib_entry_contribute_ip_forwarding(fei);
5266 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5267 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5268 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5269 FIB_TEST(lbi == dpo->dpoi_index,
5270 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5271 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5272 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5273 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5274 FIB_TEST(lbi == dpo->dpoi_index,
5275 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5277 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5278 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5279 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5280 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5281 local_pfx.fp_len = 32;
5282 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5283 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5286 * modify the export prefix so it is attached. expect all covereds to return
5288 local_pfx.fp_len = 24;
5289 fib_table_entry_update_one_path(fib_index,
5292 FIB_ENTRY_FLAG_NONE,
5295 tm->hw[0]->sw_if_index,
5296 ~0, // invalid fib index
5299 FIB_ROUTE_PATH_FLAG_NONE);
5301 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5302 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5303 dpo = fib_entry_contribute_ip_forwarding(fei);
5304 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5305 "Adj-fib1 is not drop in export");
5306 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5307 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5308 local_pfx.fp_len = 32;
5309 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5310 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5311 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5312 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5313 dpo = fib_entry_contribute_ip_forwarding(fei);
5314 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5315 "Adj-fib1 is not drop in export");
5316 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5317 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5318 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5319 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5320 local_pfx.fp_len = 32;
5321 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5322 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5325 * modify the export prefix so connected. no change.
5327 local_pfx.fp_len = 24;
5328 fib_table_entry_update_one_path(fib_index, &local_pfx,
5329 FIB_SOURCE_INTERFACE,
5330 (FIB_ENTRY_FLAG_CONNECTED |
5331 FIB_ENTRY_FLAG_ATTACHED),
5334 tm->hw[0]->sw_if_index,
5338 FIB_ROUTE_PATH_FLAG_NONE);
5340 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5341 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5342 dpo = fib_entry_contribute_ip_forwarding(fei);
5343 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5344 "Adj-fib1 is not drop in export");
5345 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5346 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5347 local_pfx.fp_len = 32;
5348 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5349 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5350 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5351 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5352 dpo = fib_entry_contribute_ip_forwarding(fei);
5353 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5354 "Adj-fib1 is not drop in export");
5355 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5356 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5357 local_pfx.fp_len = 32;
5358 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5359 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5364 fib_table_entry_delete(fib_index,
5367 fib_table_entry_delete(fib_index,
5368 &pfx_10_10_10_1_s_32,
5370 fib_table_entry_delete(fib_index,
5371 &pfx_10_10_10_2_s_32,
5373 local_pfx.fp_len = 32;
5374 fib_table_entry_delete(fib_index,
5376 FIB_SOURCE_INTERFACE);
5377 local_pfx.fp_len = 24;
5378 fib_table_entry_delete(fib_index,
5381 fib_table_entry_delete(fib_index,
5383 FIB_SOURCE_INTERFACE);
5384 local_pfx.fp_len = 24;
5385 fib_table_entry_delete(import_fib_index1,
5389 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5390 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5392 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5400 * Test the recursive route route handling for GRE tunnels
5403 fib_test_label (void)
5405 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;
5406 const u32 fib_index = 0;
5411 lb_count = pool_elts(load_balance_pool);
5416 * add interface routes. We'll assume this works. It's more rigorously
5419 fib_prefix_t local0_pfx = {
5421 .fp_proto = FIB_PROTOCOL_IP4,
5425 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5430 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5433 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5434 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5436 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5437 FIB_SOURCE_INTERFACE,
5438 (FIB_ENTRY_FLAG_CONNECTED |
5439 FIB_ENTRY_FLAG_ATTACHED),
5442 tm->hw[0]->sw_if_index,
5446 FIB_ROUTE_PATH_FLAG_NONE);
5447 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5448 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5449 "attached interface route present");
5451 local0_pfx.fp_len = 32;
5452 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5453 FIB_SOURCE_INTERFACE,
5454 (FIB_ENTRY_FLAG_CONNECTED |
5455 FIB_ENTRY_FLAG_LOCAL),
5458 tm->hw[0]->sw_if_index,
5459 ~0, // invalid fib index
5462 FIB_ROUTE_PATH_FLAG_NONE);
5463 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5465 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5466 "local interface route present");
5468 fib_prefix_t local1_pfx = {
5470 .fp_proto = FIB_PROTOCOL_IP4,
5474 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5479 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5480 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5482 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5483 FIB_SOURCE_INTERFACE,
5484 (FIB_ENTRY_FLAG_CONNECTED |
5485 FIB_ENTRY_FLAG_ATTACHED),
5488 tm->hw[1]->sw_if_index,
5492 FIB_ROUTE_PATH_FLAG_NONE);
5493 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5494 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5495 "attached interface route present");
5497 local1_pfx.fp_len = 32;
5498 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5499 FIB_SOURCE_INTERFACE,
5500 (FIB_ENTRY_FLAG_CONNECTED |
5501 FIB_ENTRY_FLAG_LOCAL),
5504 tm->hw[1]->sw_if_index,
5505 ~0, // invalid fib index
5508 FIB_ROUTE_PATH_FLAG_NONE);
5509 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5511 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5512 "local interface route present");
5514 ip46_address_t nh_10_10_10_1 = {
5516 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5519 ip46_address_t nh_10_10_11_1 = {
5521 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5524 ip46_address_t nh_10_10_11_2 = {
5526 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5530 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5533 tm->hw[1]->sw_if_index);
5534 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5537 tm->hw[1]->sw_if_index);
5538 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5541 tm->hw[0]->sw_if_index);
5542 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5545 tm->hw[1]->sw_if_index);
5546 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5549 tm->hw[1]->sw_if_index);
5552 * Add an etry with one path with a real out-going label
5554 fib_prefix_t pfx_1_1_1_1_s_32 = {
5556 .fp_proto = FIB_PROTOCOL_IP4,
5558 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5561 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5562 .type = FT_LB_LABEL_O_ADJ,
5564 .adj = ai_mpls_10_10_10_1,
5569 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5570 .type = FT_LB_LABEL_O_ADJ,
5572 .adj = ai_mpls_10_10_10_1,
5574 .eos = MPLS_NON_EOS,
5577 mpls_label_t *l99 = NULL;
5580 fib_table_entry_update_one_path(fib_index,
5583 FIB_ENTRY_FLAG_NONE,
5586 tm->hw[0]->sw_if_index,
5587 ~0, // invalid fib index
5590 FIB_ROUTE_PATH_FLAG_NONE);
5592 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5593 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5595 FIB_TEST(fib_test_validate_entry(fei,
5596 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5598 &l99_eos_o_10_10_10_1),
5599 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5602 * add a path with an implicit NULL label
5604 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5607 .adj = ai_v4_10_10_11_1,
5610 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5613 .adj = ai_mpls_10_10_11_1,
5616 mpls_label_t *l_imp_null = NULL;
5617 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5619 fei = fib_table_entry_path_add(fib_index,
5622 FIB_ENTRY_FLAG_NONE,
5625 tm->hw[1]->sw_if_index,
5626 ~0, // invalid fib index
5629 FIB_ROUTE_PATH_FLAG_NONE);
5631 FIB_TEST(fib_test_validate_entry(fei,
5632 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5634 &l99_eos_o_10_10_10_1,
5636 "1.1.1.1/32 LB 2 buckets via: "
5637 "label 99 over 10.10.10.1, "
5638 "adj over 10.10.11.1");
5641 * assign the route a local label
5643 fib_table_entry_local_label_add(fib_index,
5647 fib_prefix_t pfx_24001_eos = {
5648 .fp_proto = FIB_PROTOCOL_MPLS,
5652 fib_prefix_t pfx_24001_neos = {
5653 .fp_proto = FIB_PROTOCOL_MPLS,
5655 .fp_eos = MPLS_NON_EOS,
5659 * The EOS entry should link to both the paths,
5660 * and use an ip adj for the imp-null
5661 * The NON-EOS entry should link to both the paths,
5662 * and use an mpls adj for the imp-null
5664 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5666 FIB_TEST(fib_test_validate_entry(fei,
5667 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5669 &l99_eos_o_10_10_10_1,
5671 "24001/eos LB 2 buckets via: "
5672 "label 99 over 10.10.10.1, "
5673 "adj over 10.10.11.1");
5676 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5678 FIB_TEST(fib_test_validate_entry(fei,
5679 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5681 &l99_neos_o_10_10_10_1,
5682 &a_mpls_o_10_10_11_1),
5683 "24001/neos LB 1 bucket via: "
5684 "label 99 over 10.10.10.1 ",
5685 "mpls-adj via 10.10.11.1");
5688 * add an unlabelled path, this is excluded from the neos chains,
5690 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5693 .adj = ai_v4_10_10_11_2,
5697 fei = fib_table_entry_path_add(fib_index,
5700 FIB_ENTRY_FLAG_NONE,
5703 tm->hw[1]->sw_if_index,
5704 ~0, // invalid fib index
5707 FIB_ROUTE_PATH_FLAG_NONE);
5709 FIB_TEST(fib_test_validate_entry(fei,
5710 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5711 16, // 3 choices spread over 16 buckets
5712 &l99_eos_o_10_10_10_1,
5713 &l99_eos_o_10_10_10_1,
5714 &l99_eos_o_10_10_10_1,
5715 &l99_eos_o_10_10_10_1,
5716 &l99_eos_o_10_10_10_1,
5717 &l99_eos_o_10_10_10_1,
5728 "1.1.1.1/32 LB 16 buckets via: "
5729 "label 99 over 10.10.10.1, "
5730 "adj over 10.10.11.1",
5731 "adj over 10.10.11.2");
5734 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5736 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5737 fib_entry_contribute_forwarding(fei,
5738 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5742 * n-eos has only the 2 labelled paths
5744 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5747 FIB_TEST(fib_test_validate_entry(fei,
5748 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5750 &l99_neos_o_10_10_10_1,
5751 &a_mpls_o_10_10_11_1),
5752 "24001/neos LB 2 buckets via: "
5753 "label 99 over 10.10.10.1, "
5754 "adj-mpls over 10.10.11.2");
5757 * A labelled recursive
5759 fib_prefix_t pfx_2_2_2_2_s_32 = {
5761 .fp_proto = FIB_PROTOCOL_IP4,
5763 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5766 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5767 .type = FT_LB_LABEL_O_LB,
5769 .lb = non_eos_1_1_1_1.dpoi_index,
5774 mpls_label_t *l1600 = NULL;
5775 vec_add1(l1600, 1600);
5777 fib_table_entry_update_one_path(fib_index,
5780 FIB_ENTRY_FLAG_NONE,
5782 &pfx_1_1_1_1_s_32.fp_addr,
5787 FIB_ROUTE_PATH_FLAG_NONE);
5789 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5790 FIB_TEST(fib_test_validate_entry(fei,
5791 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5793 &l1600_eos_o_1_1_1_1),
5794 "2.2.2.2.2/32 LB 1 buckets via: "
5795 "label 1600 over 1.1.1.1");
5797 dpo_id_t dpo_44 = DPO_INVALID;
5800 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5801 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5803 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5804 "uRPF check for 2.2.2.2/32 on %d OK",
5805 tm->hw[0]->sw_if_index);
5806 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5807 "uRPF check for 2.2.2.2/32 on %d OK",
5808 tm->hw[1]->sw_if_index);
5809 FIB_TEST(!fib_urpf_check(urpfi, 99),
5810 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5813 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5814 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5815 "Shared uRPF on IP and non-EOS chain");
5820 * we are holding a lock on the non-eos LB of the via-entry.
5821 * do a PIC-core failover by shutting the link of the via-entry.
5823 * shut down the link with the valid label
5825 vnet_sw_interface_set_flags(vnet_get_main(),
5826 tm->hw[0]->sw_if_index,
5829 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5830 FIB_TEST(fib_test_validate_entry(fei,
5831 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5835 "1.1.1.1/32 LB 2 buckets via: "
5836 "adj over 10.10.11.1, ",
5837 "adj-v4 over 10.10.11.2");
5839 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5841 FIB_TEST(fib_test_validate_entry(fei,
5842 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5846 "24001/eos LB 2 buckets via: "
5847 "adj over 10.10.11.1, ",
5848 "adj-v4 over 10.10.11.2");
5850 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5852 FIB_TEST(fib_test_validate_entry(fei,
5853 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5855 &a_mpls_o_10_10_11_1),
5856 "24001/neos LB 1 buckets via: "
5857 "adj-mpls over 10.10.11.2");
5860 * test that the pre-failover load-balance has been in-place
5863 dpo_id_t current = DPO_INVALID;
5864 fib_entry_contribute_forwarding(fei,
5865 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5868 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
5870 "PIC-core LB inplace modified %U %U",
5871 format_dpo_id, &non_eos_1_1_1_1, 0,
5872 format_dpo_id, ¤t, 0);
5874 dpo_reset(&non_eos_1_1_1_1);
5875 dpo_reset(¤t);
5878 * no-shut the link with the valid label
5880 vnet_sw_interface_set_flags(vnet_get_main(),
5881 tm->hw[0]->sw_if_index,
5882 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5884 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5885 FIB_TEST(fib_test_validate_entry(fei,
5886 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5887 16, // 3 choices spread over 16 buckets
5888 &l99_eos_o_10_10_10_1,
5889 &l99_eos_o_10_10_10_1,
5890 &l99_eos_o_10_10_10_1,
5891 &l99_eos_o_10_10_10_1,
5892 &l99_eos_o_10_10_10_1,
5893 &l99_eos_o_10_10_10_1,
5904 "1.1.1.1/32 LB 16 buckets via: "
5905 "label 99 over 10.10.10.1, "
5906 "adj over 10.10.11.1",
5907 "adj-v4 over 10.10.11.2");
5910 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5912 FIB_TEST(fib_test_validate_entry(fei,
5913 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5914 16, // 3 choices spread over 16 buckets
5915 &l99_eos_o_10_10_10_1,
5916 &l99_eos_o_10_10_10_1,
5917 &l99_eos_o_10_10_10_1,
5918 &l99_eos_o_10_10_10_1,
5919 &l99_eos_o_10_10_10_1,
5920 &l99_eos_o_10_10_10_1,
5931 "24001/eos LB 16 buckets via: "
5932 "label 99 over 10.10.10.1, "
5933 "adj over 10.10.11.1",
5934 "adj-v4 over 10.10.11.2");
5936 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5938 FIB_TEST(fib_test_validate_entry(fei,
5939 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5941 &l99_neos_o_10_10_10_1,
5942 &a_mpls_o_10_10_11_1),
5943 "24001/neos LB 2 buckets via: "
5944 "label 99 over 10.10.10.1, "
5945 "adj-mpls over 10.10.11.2");
5948 * remove the first path with the valid label
5950 fib_table_entry_path_remove(fib_index,
5955 tm->hw[0]->sw_if_index,
5956 ~0, // invalid fib index
5958 FIB_ROUTE_PATH_FLAG_NONE);
5960 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5961 FIB_TEST(fib_test_validate_entry(fei,
5962 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5966 "1.1.1.1/32 LB 2 buckets via: "
5967 "adj over 10.10.11.1, "
5968 "adj-v4 over 10.10.11.2");
5970 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5972 FIB_TEST(fib_test_validate_entry(fei,
5973 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5977 "24001/eos LB 2 buckets via: "
5978 "adj over 10.10.11.1, "
5979 "adj-v4 over 10.10.11.2");
5981 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5984 FIB_TEST(fib_test_validate_entry(fei,
5985 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5987 &a_mpls_o_10_10_11_1),
5988 "24001/neos LB 1 buckets via: "
5989 "adj-mpls over 10.10.11.2");
5992 * remove the other path with a valid label
5994 fib_test_lb_bucket_t bucket_drop = {
5995 .type = FT_LB_SPECIAL,
5997 .adj = DPO_PROTO_IP4,
6000 fib_test_lb_bucket_t mpls_bucket_drop = {
6001 .type = FT_LB_SPECIAL,
6003 .adj = DPO_PROTO_MPLS,
6007 fib_table_entry_path_remove(fib_index,
6012 tm->hw[1]->sw_if_index,
6013 ~0, // invalid fib index
6015 FIB_ROUTE_PATH_FLAG_NONE);
6017 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6018 FIB_TEST(fib_test_validate_entry(fei,
6019 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6022 "1.1.1.1/32 LB 1 buckets via: "
6023 "adj over 10.10.11.2");
6025 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6027 FIB_TEST(fib_test_validate_entry(fei,
6028 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6031 "24001/eos LB 1 buckets via: "
6032 "adj over 10.10.11.2");
6034 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6036 FIB_TEST(fib_test_validate_entry(fei,
6037 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6040 "24001/neos LB 1 buckets via: DROP");
6043 * add back the path with the valid label
6048 fib_table_entry_path_add(fib_index,
6051 FIB_ENTRY_FLAG_NONE,
6054 tm->hw[0]->sw_if_index,
6055 ~0, // invalid fib index
6058 FIB_ROUTE_PATH_FLAG_NONE);
6060 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6061 FIB_TEST(fib_test_validate_entry(fei,
6062 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6064 &l99_eos_o_10_10_10_1,
6066 "1.1.1.1/32 LB 2 buckets via: "
6067 "label 99 over 10.10.10.1, "
6068 "adj over 10.10.11.2");
6070 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6072 FIB_TEST(fib_test_validate_entry(fei,
6073 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6075 &l99_eos_o_10_10_10_1,
6077 "24001/eos LB 2 buckets via: "
6078 "label 99 over 10.10.10.1, "
6079 "adj over 10.10.11.2");
6081 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6083 FIB_TEST(fib_test_validate_entry(fei,
6084 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6086 &l99_neos_o_10_10_10_1),
6087 "24001/neos LB 1 buckets via: "
6088 "label 99 over 10.10.10.1");
6091 * change the local label
6093 fib_table_entry_local_label_add(fib_index,
6097 fib_prefix_t pfx_25005_eos = {
6098 .fp_proto = FIB_PROTOCOL_MPLS,
6102 fib_prefix_t pfx_25005_neos = {
6103 .fp_proto = FIB_PROTOCOL_MPLS,
6105 .fp_eos = MPLS_NON_EOS,
6108 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6109 fib_table_lookup(fib_index, &pfx_24001_eos)),
6110 "24001/eos removed after label change");
6111 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6112 fib_table_lookup(fib_index, &pfx_24001_neos)),
6113 "24001/eos removed after label change");
6115 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6117 FIB_TEST(fib_test_validate_entry(fei,
6118 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6120 &l99_eos_o_10_10_10_1,
6122 "25005/eos LB 2 buckets via: "
6123 "label 99 over 10.10.10.1, "
6124 "adj over 10.10.11.2");
6126 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6128 FIB_TEST(fib_test_validate_entry(fei,
6129 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6131 &l99_neos_o_10_10_10_1),
6132 "25005/neos LB 1 buckets via: "
6133 "label 99 over 10.10.10.1");
6136 * remove the local label.
6137 * the check that the MPLS entries are gone is done by the fact the
6138 * MPLS table is no longer present.
6140 fib_table_entry_local_label_remove(fib_index,
6144 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6145 FIB_TEST(fib_test_validate_entry(fei,
6146 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6148 &l99_eos_o_10_10_10_1,
6150 "24001/eos LB 2 buckets via: "
6151 "label 99 over 10.10.10.1, "
6152 "adj over 10.10.11.2");
6154 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6155 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6156 "No more MPLS FIB entries => table removed");
6159 * add another via-entry for the recursive
6161 fib_prefix_t pfx_1_1_1_2_s_32 = {
6163 .fp_proto = FIB_PROTOCOL_IP4,
6165 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6168 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6169 .type = FT_LB_LABEL_O_ADJ,
6171 .adj = ai_mpls_10_10_10_1,
6176 mpls_label_t *l101 = NULL;
6177 vec_add1(l101, 101);
6179 fei = fib_table_entry_update_one_path(fib_index,
6182 FIB_ENTRY_FLAG_NONE,
6185 tm->hw[0]->sw_if_index,
6186 ~0, // invalid fib index
6189 FIB_ROUTE_PATH_FLAG_NONE);
6191 FIB_TEST(fib_test_validate_entry(fei,
6192 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6194 &l101_eos_o_10_10_10_1),
6195 "1.1.1.2/32 LB 1 buckets via: "
6196 "label 101 over 10.10.10.1");
6198 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6199 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6201 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6203 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6205 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6208 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6209 .type = FT_LB_LABEL_O_LB,
6211 .lb = non_eos_1_1_1_2.dpoi_index,
6216 mpls_label_t *l1601 = NULL;
6217 vec_add1(l1601, 1601);
6219 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6221 fei = fib_table_entry_path_add(fib_index,
6224 FIB_ENTRY_FLAG_NONE,
6226 &pfx_1_1_1_2_s_32.fp_addr,
6231 FIB_ROUTE_PATH_FLAG_NONE);
6233 FIB_TEST(fib_test_validate_entry(fei,
6234 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6236 &l1600_eos_o_1_1_1_1,
6237 &l1601_eos_o_1_1_1_2),
6238 "2.2.2.2/32 LB 2 buckets via: "
6239 "label 1600 via 1.1,1.1, "
6240 "label 16001 via 1.1.1.2");
6243 * update the via-entry so it no longer has an imp-null path.
6244 * the LB for the recursive can use an imp-null
6247 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6249 fei = fib_table_entry_update_one_path(fib_index,
6252 FIB_ENTRY_FLAG_NONE,
6255 tm->hw[1]->sw_if_index,
6256 ~0, // invalid fib index
6259 FIB_ROUTE_PATH_FLAG_NONE);
6261 FIB_TEST(fib_test_validate_entry(fei,
6262 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6265 "1.1.1.2/32 LB 1 buckets via: "
6268 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6269 FIB_TEST(fib_test_validate_entry(fei,
6270 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6272 &l1600_eos_o_1_1_1_1,
6273 &l1601_eos_o_1_1_1_2),
6274 "2.2.2.2/32 LB 2 buckets via: "
6275 "label 1600 via 1.1,1.1, "
6276 "label 16001 via 1.1.1.2");
6279 * update the via-entry so it no longer has labelled paths.
6280 * the LB for the recursive should exclue this via form its LB
6282 fei = fib_table_entry_update_one_path(fib_index,
6285 FIB_ENTRY_FLAG_NONE,
6288 tm->hw[1]->sw_if_index,
6289 ~0, // invalid fib index
6292 FIB_ROUTE_PATH_FLAG_NONE);
6294 FIB_TEST(fib_test_validate_entry(fei,
6295 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6298 "1.1.1.2/32 LB 1 buckets via: "
6301 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6302 FIB_TEST(fib_test_validate_entry(fei,
6303 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6305 &l1600_eos_o_1_1_1_1),
6306 "2.2.2.2/32 LB 1 buckets via: "
6307 "label 1600 via 1.1,1.1");
6309 dpo_reset(&non_eos_1_1_1_1);
6310 dpo_reset(&non_eos_1_1_1_2);
6313 * Add a recursive with no out-labels. We expect to use the IP of the via
6315 fib_prefix_t pfx_2_2_2_3_s_32 = {
6317 .fp_proto = FIB_PROTOCOL_IP4,
6319 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6322 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6324 fib_table_entry_update_one_path(fib_index,
6327 FIB_ENTRY_FLAG_NONE,
6329 &pfx_1_1_1_1_s_32.fp_addr,
6334 FIB_ROUTE_PATH_FLAG_NONE);
6336 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6338 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6341 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6344 .lb = ip_1_1_1_1.dpoi_index,
6348 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6349 FIB_TEST(fib_test_validate_entry(fei,
6350 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6353 "2.2.2.2.3/32 LB 1 buckets via: "
6357 * Add a recursive with an imp-null out-label.
6358 * We expect to use the IP of the via
6360 fib_prefix_t pfx_2_2_2_4_s_32 = {
6362 .fp_proto = FIB_PROTOCOL_IP4,
6364 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6368 fib_table_entry_update_one_path(fib_index,
6371 FIB_ENTRY_FLAG_NONE,
6373 &pfx_1_1_1_1_s_32.fp_addr,
6378 FIB_ROUTE_PATH_FLAG_NONE);
6380 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6381 FIB_TEST(fib_test_validate_entry(fei,
6382 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6385 "2.2.2.2.4/32 LB 1 buckets via: "
6388 dpo_reset(&ip_1_1_1_1);
6391 * Create an entry with a deep label stack
6393 fib_prefix_t pfx_2_2_5_5_s_32 = {
6395 .fp_proto = FIB_PROTOCOL_IP4,
6397 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6400 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6401 .type = FT_LB_LABEL_STACK_O_ADJ,
6402 .label_stack_o_adj = {
6403 .adj = ai_mpls_10_10_11_1,
6404 .label_stack_size = 8,
6406 200, 201, 202, 203, 204, 205, 206, 207
6411 mpls_label_t *label_stack = NULL;
6412 vec_validate(label_stack, 7);
6413 for (ii = 0; ii < 8; ii++)
6415 label_stack[ii] = ii + 200;
6418 fei = fib_table_entry_update_one_path(fib_index,
6421 FIB_ENTRY_FLAG_NONE,
6424 tm->hw[1]->sw_if_index,
6425 ~0, // invalid fib index
6428 FIB_ROUTE_PATH_FLAG_NONE);
6430 FIB_TEST(fib_test_validate_entry(fei,
6431 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6433 &ls_eos_o_10_10_10_1),
6434 "2.2.5.5/32 LB 1 buckets via: "
6436 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6441 fib_table_entry_delete(fib_index,
6445 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6446 FIB_TEST(fib_test_validate_entry(fei,
6447 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6449 &l1600_eos_o_1_1_1_1),
6450 "2.2.2.2/32 LB 1 buckets via: "
6451 "label 1600 via 1.1,1.1");
6453 fib_table_entry_delete(fib_index,
6457 FIB_TEST(fib_test_validate_entry(fei,
6458 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6461 "2.2.2.2/32 LB 1 buckets via: DROP");
6463 fib_table_entry_delete(fib_index,
6466 fib_table_entry_delete(fib_index,
6469 fib_table_entry_delete(fib_index,
6473 adj_unlock(ai_mpls_10_10_10_1);
6474 adj_unlock(ai_mpls_10_10_11_2);
6475 adj_unlock(ai_v4_10_10_11_1);
6476 adj_unlock(ai_v4_10_10_11_2);
6477 adj_unlock(ai_mpls_10_10_11_1);
6479 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6482 local0_pfx.fp_len = 32;
6483 fib_table_entry_delete(fib_index,
6485 FIB_SOURCE_INTERFACE);
6486 local0_pfx.fp_len = 24;
6487 fib_table_entry_delete(fib_index,
6489 FIB_SOURCE_INTERFACE);
6490 local1_pfx.fp_len = 32;
6491 fib_table_entry_delete(fib_index,
6493 FIB_SOURCE_INTERFACE);
6494 local1_pfx.fp_len = 24;
6495 fib_table_entry_delete(fib_index,
6497 FIB_SOURCE_INTERFACE);
6500 * +1 for the drop LB in the MPLS tables.
6502 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6503 "Load-balance resources freed %d of %d",
6504 lb_count+1, pool_elts(load_balance_pool));
6509 #define N_TEST_CHILDREN 4
6510 #define PARENT_INDEX 0
6512 typedef struct fib_node_test_t_
6517 fib_node_back_walk_ctx_t *ctxs;
6521 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6523 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6525 #define FOR_EACH_TEST_CHILD(_tc) \
6526 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
6527 ii < N_TEST_CHILDREN+1; \
6528 ii++, (_tc) = &fib_test_nodes[ii])
6531 fib_test_child_get_node (fib_node_index_t index)
6533 return (&fib_test_nodes[index].node);
6536 static int fib_test_walk_spawns_walks;
6538 static fib_node_back_walk_rc_t
6539 fib_test_child_back_walk_notify (fib_node_t *node,
6540 fib_node_back_walk_ctx_t *ctx)
6542 fib_node_test_t *tc = (fib_node_test_t*) node;
6544 vec_add1(tc->ctxs, *ctx);
6546 if (1 == fib_test_walk_spawns_walks)
6547 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6548 if (2 == fib_test_walk_spawns_walks)
6549 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6550 FIB_WALK_PRIORITY_HIGH, ctx);
6552 return (FIB_NODE_BACK_WALK_CONTINUE);
6556 fib_test_child_last_lock_gone (fib_node_t *node)
6558 fib_node_test_t *tc = (fib_node_test_t *)node;
6564 * The FIB walk's graph node virtual function table
6566 static const fib_node_vft_t fib_test_child_vft = {
6567 .fnv_get = fib_test_child_get_node,
6568 .fnv_last_lock = fib_test_child_last_lock_gone,
6569 .fnv_back_walk = fib_test_child_back_walk_notify,
6573 * the function (that should have been static but isn't so I can do this)
6574 * that processes the walk from the async queue,
6576 f64 fib_walk_process_queues(vlib_main_t * vm,
6578 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6581 fib_test_walk (void)
6583 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6584 fib_node_test_t *tc;
6588 vm = vlib_get_main();
6589 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6592 * init a fake node on which we will add children
6594 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6595 FIB_NODE_TYPE_TEST);
6597 FOR_EACH_TEST_CHILD(tc)
6599 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6600 fib_node_lock(&tc->node);
6603 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6605 FIB_NODE_TYPE_TEST, ii);
6609 * enqueue a walk across the parents children.
6611 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6613 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6614 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6615 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6616 "Parent has %d children pre-walk",
6617 fib_node_list_get_size(PARENT()->fn_children));
6620 * give the walk a large amount of time so it gets to the end
6622 fib_walk_process_queues(vm, 1);
6624 FOR_EACH_TEST_CHILD(tc)
6626 FIB_TEST(1 == vec_len(tc->ctxs),
6627 "%d child visitsed %d times",
6628 ii, vec_len(tc->ctxs));
6631 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6632 "Queue is empty post walk");
6633 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6634 "Parent has %d children post walk",
6635 fib_node_list_get_size(PARENT()->fn_children));
6638 * walk again. should be no increase in the number of visits, since
6639 * the walk will have terminated.
6641 fib_walk_process_queues(vm, 1);
6643 FOR_EACH_TEST_CHILD(tc)
6645 FIB_TEST(0 == vec_len(tc->ctxs),
6646 "%d child visitsed %d times",
6647 ii, vec_len(tc->ctxs));
6651 * schedule a low and hig priority walk. expect the high to be performed
6653 * schedule the high prio walk first so that it is further from the head
6654 * of the dependency list. that way it won't merge with the low one.
6656 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6657 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6659 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6660 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6661 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6662 FIB_WALK_PRIORITY_LOW, &low_ctx);
6664 fib_walk_process_queues(vm, 1);
6666 FOR_EACH_TEST_CHILD(tc)
6668 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6669 "%d child visitsed by high prio walk", ii);
6670 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6671 "%d child visitsed by low prio walk", ii);
6674 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6675 "Queue is empty post prio walk");
6676 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6677 "Parent has %d children post prio walk",
6678 fib_node_list_get_size(PARENT()->fn_children));
6681 * schedule 2 walks of the same priority that can be megred.
6682 * expect that each child is thus visited only once.
6684 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6685 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6687 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6688 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6689 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6690 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6692 fib_walk_process_queues(vm, 1);
6694 FOR_EACH_TEST_CHILD(tc)
6696 FIB_TEST(1 == vec_len(tc->ctxs),
6697 "%d child visitsed %d times during merge walk",
6698 ii, vec_len(tc->ctxs));
6701 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6702 "Queue is empty post merge walk");
6703 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6704 "Parent has %d children post merge walk",
6705 fib_node_list_get_size(PARENT()->fn_children));
6708 * schedule 2 walks of the same priority that cannot be megred.
6709 * expect that each child is thus visited twice and in the order
6710 * in which the walks were scheduled.
6712 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6713 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6715 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6716 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6717 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6718 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6720 fib_walk_process_queues(vm, 1);
6722 FOR_EACH_TEST_CHILD(tc)
6724 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6725 "%d child visitsed by high prio walk", ii);
6726 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6727 "%d child visitsed by low prio walk", ii);
6730 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6731 "Queue is empty post no-merge walk");
6732 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6733 "Parent has %d children post no-merge walk",
6734 fib_node_list_get_size(PARENT()->fn_children));
6737 * schedule a walk that makes one one child progress.
6738 * we do this by giving the queue draining process zero
6739 * time quanta. it's a do..while loop, so it does something.
6741 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6743 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6744 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6745 fib_walk_process_queues(vm, 0);
6747 FOR_EACH_TEST_CHILD(tc)
6749 if (ii == N_TEST_CHILDREN)
6751 FIB_TEST(1 == vec_len(tc->ctxs),
6752 "%d child visitsed %d times in zero quanta walk",
6753 ii, vec_len(tc->ctxs));
6757 FIB_TEST(0 == vec_len(tc->ctxs),
6758 "%d child visitsed %d times in 0 quanta walk",
6759 ii, vec_len(tc->ctxs));
6762 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6763 "Queue is not empty post zero quanta walk");
6764 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6765 "Parent has %d children post zero qunta walk",
6766 fib_node_list_get_size(PARENT()->fn_children));
6771 fib_walk_process_queues(vm, 0);
6773 FOR_EACH_TEST_CHILD(tc)
6775 if (ii >= N_TEST_CHILDREN-1)
6777 FIB_TEST(1 == vec_len(tc->ctxs),
6778 "%d child visitsed %d times in 2nd zero quanta walk",
6779 ii, vec_len(tc->ctxs));
6783 FIB_TEST(0 == vec_len(tc->ctxs),
6784 "%d child visitsed %d times in 2nd 0 quanta walk",
6785 ii, vec_len(tc->ctxs));
6788 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6789 "Queue is not empty post zero quanta walk");
6790 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6791 "Parent has %d children post zero qunta walk",
6792 fib_node_list_get_size(PARENT()->fn_children));
6795 * schedule another walk that will catch-up and merge.
6797 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6798 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6799 fib_walk_process_queues(vm, 1);
6801 FOR_EACH_TEST_CHILD(tc)
6803 if (ii >= N_TEST_CHILDREN-1)
6805 FIB_TEST(2 == vec_len(tc->ctxs),
6806 "%d child visitsed %d times in 2nd zero quanta merge walk",
6807 ii, vec_len(tc->ctxs));
6812 FIB_TEST(1 == vec_len(tc->ctxs),
6813 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6814 ii, vec_len(tc->ctxs));
6818 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6819 "Queue is not empty post 2nd zero quanta merge walk");
6820 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6821 "Parent has %d children post 2nd zero qunta merge walk",
6822 fib_node_list_get_size(PARENT()->fn_children));
6825 * park a async walk in the middle of the list, then have an sync walk catch
6826 * it. same expectations as async catches async.
6828 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6830 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6831 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6833 fib_walk_process_queues(vm, 0);
6834 fib_walk_process_queues(vm, 0);
6836 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6838 FOR_EACH_TEST_CHILD(tc)
6840 if (ii >= N_TEST_CHILDREN-1)
6842 FIB_TEST(2 == vec_len(tc->ctxs),
6843 "%d child visitsed %d times in sync catches async walk",
6844 ii, vec_len(tc->ctxs));
6849 FIB_TEST(1 == vec_len(tc->ctxs),
6850 "%d child visitsed %d times in sync catches async walk",
6851 ii, vec_len(tc->ctxs));
6855 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6856 "Queue is not empty post 2nd zero quanta merge walk");
6857 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6858 "Parent has %d children post 2nd zero qunta merge walk",
6859 fib_node_list_get_size(PARENT()->fn_children));
6862 * make the parent a child of one of its children, thus inducing a routing loop.
6864 fib_test_nodes[PARENT_INDEX].sibling =
6865 fib_node_child_add(FIB_NODE_TYPE_TEST,
6866 1, // the first child
6871 * execute a sync walk from the parent. each child visited spawns more sync
6872 * walks. we expect the walk to terminate.
6874 fib_test_walk_spawns_walks = 1;
6876 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6878 FOR_EACH_TEST_CHILD(tc)
6881 * child 1 - which is last in the list - has the loop.
6882 * the other children a re thus visitsed first. the we meet
6883 * child 1. we go round the loop again, visting the other children.
6884 * then we meet the walk in the dep list and bail. child 1 is not visitsed
6889 FIB_TEST(1 == vec_len(tc->ctxs),
6890 "child %d visitsed %d times during looped sync walk",
6891 ii, vec_len(tc->ctxs));
6895 FIB_TEST(2 == vec_len(tc->ctxs),
6896 "child %d visitsed %d times during looped sync walk",
6897 ii, vec_len(tc->ctxs));
6901 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6902 "Parent has %d children post sync loop walk",
6903 fib_node_list_get_size(PARENT()->fn_children));
6906 * the walk doesn't reach the max depth because the infra knows that sync
6907 * meets sync implies a loop and bails early.
6909 FIB_TEST(high_ctx.fnbw_depth == 9,
6910 "Walk context depth %d post sync loop walk",
6911 high_ctx.fnbw_depth);
6914 * execute an async walk of the graph loop, with each child spawns sync walks
6916 high_ctx.fnbw_depth = 0;
6917 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6918 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6920 fib_walk_process_queues(vm, 1);
6922 FOR_EACH_TEST_CHILD(tc)
6925 * we don't really care how many times the children are visisted, as long as
6926 * it is more than once.
6928 FIB_TEST(1 <= vec_len(tc->ctxs),
6929 "child %d visitsed %d times during looped aync spawns sync walk",
6930 ii, vec_len(tc->ctxs));
6935 * execute an async walk of the graph loop, with each child spawns async walks
6937 fib_test_walk_spawns_walks = 2;
6938 high_ctx.fnbw_depth = 0;
6939 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6940 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6942 fib_walk_process_queues(vm, 1);
6944 FOR_EACH_TEST_CHILD(tc)
6947 * we don't really care how many times the children are visisted, as long as
6948 * it is more than once.
6950 FIB_TEST(1 <= vec_len(tc->ctxs),
6951 "child %d visitsed %d times during looped async spawns async walk",
6952 ii, vec_len(tc->ctxs));
6957 fib_node_child_remove(FIB_NODE_TYPE_TEST,
6958 1, // the first child
6959 fib_test_nodes[PARENT_INDEX].sibling);
6964 FOR_EACH_TEST_CHILD(tc)
6966 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6968 fib_node_deinit(&tc->node);
6969 fib_node_unlock(&tc->node);
6971 fib_node_deinit(PARENT());
6974 * The parent will be destroyed when the last lock on it goes.
6975 * this test ensures all the walk objects are unlocking it.
6977 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
6978 "Parent was destroyed");
6984 * declaration of the otherwise static callback functions
6986 void fib_bfd_notify (bfd_listen_event_e event,
6987 const bfd_session_t *session);
6988 void adj_bfd_notify (bfd_listen_event_e event,
6989 const bfd_session_t *session);
6992 * Test BFD session interaction with FIB
6997 fib_node_index_t fei;
7001 /* via 10.10.10.1 */
7002 ip46_address_t nh_10_10_10_1 = {
7003 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7005 /* via 10.10.10.2 */
7006 ip46_address_t nh_10_10_10_2 = {
7007 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7009 /* via 10.10.10.10 */
7010 ip46_address_t nh_10_10_10_10 = {
7011 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7013 n_feis = fib_entry_pool_size();
7018 * add interface routes. we'll assume this works. it's tested elsewhere
7020 fib_prefix_t pfx_10_10_10_10_s_24 = {
7022 .fp_proto = FIB_PROTOCOL_IP4,
7023 .fp_addr = nh_10_10_10_10,
7026 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7027 FIB_SOURCE_INTERFACE,
7028 (FIB_ENTRY_FLAG_CONNECTED |
7029 FIB_ENTRY_FLAG_ATTACHED),
7032 tm->hw[0]->sw_if_index,
7033 ~0, // invalid fib index
7036 FIB_ROUTE_PATH_FLAG_NONE);
7038 fib_prefix_t pfx_10_10_10_10_s_32 = {
7040 .fp_proto = FIB_PROTOCOL_IP4,
7041 .fp_addr = nh_10_10_10_10,
7043 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7044 FIB_SOURCE_INTERFACE,
7045 (FIB_ENTRY_FLAG_CONNECTED |
7046 FIB_ENTRY_FLAG_LOCAL),
7049 tm->hw[0]->sw_if_index,
7050 ~0, // invalid fib index
7053 FIB_ROUTE_PATH_FLAG_NONE);
7056 * A BFD session via a neighbour we do not yet know
7058 bfd_session_t bfd_10_10_10_1 = {
7062 .peer_addr = nh_10_10_10_1,
7065 .hop_type = BFD_HOP_TYPE_MULTI,
7066 .local_state = BFD_STATE_init,
7069 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7072 * A new entry will be created that forwards via the adj
7074 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7077 tm->hw[0]->sw_if_index);
7078 fib_prefix_t pfx_10_10_10_1_s_32 = {
7079 .fp_addr = nh_10_10_10_1,
7081 .fp_proto = FIB_PROTOCOL_IP4,
7083 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7086 .adj = ai_10_10_10_1,
7090 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7091 FIB_TEST(fib_test_validate_entry(fei,
7092 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7095 "BFD sourced %U via %U",
7096 format_fib_prefix, &pfx_10_10_10_1_s_32,
7097 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7100 * Delete the BFD session. Expect the fib_entry to be removed
7102 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7104 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7105 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7106 "BFD sourced %U removed",
7107 format_fib_prefix, &pfx_10_10_10_1_s_32);
7110 * Add the BFD source back
7112 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7115 * source the entry via the ADJ fib
7117 fei = fib_table_entry_update_one_path(0,
7118 &pfx_10_10_10_1_s_32,
7120 FIB_ENTRY_FLAG_ATTACHED,
7123 tm->hw[0]->sw_if_index,
7124 ~0, // invalid fib index
7127 FIB_ROUTE_PATH_FLAG_NONE);
7130 * Delete the BFD session. Expect the fib_entry to remain
7132 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7134 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7135 FIB_TEST(fib_test_validate_entry(fei,
7136 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7139 "BFD sourced %U remains via %U",
7140 format_fib_prefix, &pfx_10_10_10_1_s_32,
7141 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7144 * Add the BFD source back
7146 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7149 * Create another ADJ FIB
7151 fib_prefix_t pfx_10_10_10_2_s_32 = {
7152 .fp_addr = nh_10_10_10_2,
7154 .fp_proto = FIB_PROTOCOL_IP4,
7156 fib_table_entry_update_one_path(0,
7157 &pfx_10_10_10_2_s_32,
7159 FIB_ENTRY_FLAG_ATTACHED,
7162 tm->hw[0]->sw_if_index,
7163 ~0, // invalid fib index
7166 FIB_ROUTE_PATH_FLAG_NONE);
7168 * A BFD session for the new ADJ FIB
7170 bfd_session_t bfd_10_10_10_2 = {
7174 .peer_addr = nh_10_10_10_2,
7177 .hop_type = BFD_HOP_TYPE_MULTI,
7178 .local_state = BFD_STATE_init,
7181 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7184 * remove the adj-fib source whilst the session is present
7187 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7188 fib_table_entry_update_one_path(0,
7189 &pfx_10_10_10_2_s_32,
7191 FIB_ENTRY_FLAG_ATTACHED,
7194 tm->hw[0]->sw_if_index,
7195 ~0, // invalid fib index
7198 FIB_ROUTE_PATH_FLAG_NONE);
7201 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7202 * bring one of the sessions UP, leave the other down
7204 bfd_10_10_10_1.local_state = BFD_STATE_up;
7205 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7206 bfd_10_10_10_2.local_state = BFD_STATE_down;
7207 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7210 * A recursive prefix via both of the ADJ FIBs
7212 fib_prefix_t pfx_200_0_0_0_s_24 = {
7213 .fp_proto = FIB_PROTOCOL_IP4,
7216 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7219 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7222 fib_entry_contribute_ip_forwarding(
7223 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7225 fib_entry_contribute_ip_forwarding(
7226 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7228 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7231 .lb = dpo_10_10_10_1->dpoi_index,
7234 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7237 .lb = dpo_10_10_10_2->dpoi_index,
7242 * A prefix via the adj-fib that is BFD down => DROP
7244 fei = fib_table_entry_path_add(0,
7245 &pfx_200_0_0_0_s_24,
7247 FIB_ENTRY_FLAG_NONE,
7251 0, // default fib index
7254 FIB_ROUTE_PATH_FLAG_NONE);
7255 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7256 "%U resolves via drop",
7257 format_fib_prefix, &pfx_200_0_0_0_s_24);
7260 * add a path via the UP BFD adj-fib.
7261 * we expect that the DOWN BFD ADJ FIB is not used.
7263 fei = fib_table_entry_path_add(0,
7264 &pfx_200_0_0_0_s_24,
7266 FIB_ENTRY_FLAG_NONE,
7270 0, // default fib index
7273 FIB_ROUTE_PATH_FLAG_NONE);
7275 FIB_TEST(fib_test_validate_entry(fei,
7276 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7279 "Recursive %U only UP BFD adj-fibs",
7280 format_fib_prefix, &pfx_200_0_0_0_s_24);
7283 * Send a BFD state change to UP - both sessions are now up
7284 * the recursive prefix should LB over both
7286 bfd_10_10_10_2.local_state = BFD_STATE_up;
7287 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7290 FIB_TEST(fib_test_validate_entry(fei,
7291 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7295 "Recursive %U via both UP BFD adj-fibs",
7296 format_fib_prefix, &pfx_200_0_0_0_s_24);
7299 * Send a BFD state change to DOWN
7300 * the recursive prefix should exclude the down
7302 bfd_10_10_10_2.local_state = BFD_STATE_down;
7303 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7306 FIB_TEST(fib_test_validate_entry(fei,
7307 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7310 "Recursive %U via only UP",
7311 format_fib_prefix, &pfx_200_0_0_0_s_24);
7314 * Delete the BFD session while it is in the DOWN state.
7315 * FIB should consider the entry's state as back up
7317 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
7319 FIB_TEST(fib_test_validate_entry(fei,
7320 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7324 "Recursive %U via both UP BFD adj-fibs post down session delete",
7325 format_fib_prefix, &pfx_200_0_0_0_s_24);
7328 * Delete the BFD other session while it is in the UP state.
7330 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7332 FIB_TEST(fib_test_validate_entry(fei,
7333 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7337 "Recursive %U via both UP BFD adj-fibs post up session delete",
7338 format_fib_prefix, &pfx_200_0_0_0_s_24);
7343 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
7344 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
7345 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7347 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
7348 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
7350 adj_unlock(ai_10_10_10_1);
7352 * test no-one left behind
7354 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7355 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7358 * Single-hop BFD tests
7360 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
7361 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
7363 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7365 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7368 tm->hw[0]->sw_if_index);
7370 * whilst the BFD session is not signalled, the adj is up
7372 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
7375 * bring the BFD session up
7377 bfd_10_10_10_1.local_state = BFD_STATE_up;
7378 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7379 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
7382 * bring the BFD session down
7384 bfd_10_10_10_1.local_state = BFD_STATE_down;
7385 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7386 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
7390 * add an attached next hop FIB entry via the down adj
7392 fib_prefix_t pfx_5_5_5_5_s_32 = {
7395 .as_u32 = clib_host_to_net_u32(0x05050505),
7399 .fp_proto = FIB_PROTOCOL_IP4,
7402 fei = fib_table_entry_path_add(0,
7405 FIB_ENTRY_FLAG_NONE,
7408 tm->hw[0]->sw_if_index,
7409 ~0, // invalid fib index
7412 FIB_ROUTE_PATH_FLAG_NONE);
7413 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7414 "%U resolves via drop",
7415 format_fib_prefix, &pfx_5_5_5_5_s_32);
7418 * Add a path via an ADJ that is up
7420 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7423 tm->hw[0]->sw_if_index);
7425 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
7428 .adj = ai_10_10_10_2,
7431 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
7433 fei = fib_table_entry_path_add(0,
7436 FIB_ENTRY_FLAG_NONE,
7439 tm->hw[0]->sw_if_index,
7440 ~0, // invalid fib index
7443 FIB_ROUTE_PATH_FLAG_NONE);
7445 FIB_TEST(fib_test_validate_entry(fei,
7446 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7449 "BFD sourced %U via %U",
7450 format_fib_prefix, &pfx_5_5_5_5_s_32,
7451 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
7454 * Bring up the down session - should now LB
7456 bfd_10_10_10_1.local_state = BFD_STATE_up;
7457 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7458 FIB_TEST(fib_test_validate_entry(fei,
7459 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7463 "BFD sourced %U via noth adjs",
7464 format_fib_prefix, &pfx_5_5_5_5_s_32);
7467 * remove the BFD session state from the adj
7469 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7474 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
7475 adj_unlock(ai_10_10_10_1);
7476 adj_unlock(ai_10_10_10_2);
7479 * test no-one left behind
7481 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7482 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7489 const mpls_label_t deag_label = 50;
7490 const u32 lfib_index = 0;
7491 const u32 fib_index = 0;
7492 dpo_id_t dpo = DPO_INVALID;
7493 const dpo_id_t *dpo1;
7494 fib_node_index_t lfe;
7498 adj_index_t ai_mpls_10_10_10_1;
7501 lb_count = pool_elts(load_balance_pool);
7503 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7507 * MPLS enable an interface so we get the MPLS table created
7509 mpls_sw_interface_enable_disable(&mpls_main,
7510 tm->hw[0]->sw_if_index,
7513 ip46_address_t nh_10_10_10_1 = {
7514 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7516 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7519 tm->hw[0]->sw_if_index);
7522 * Test the specials stack properly.
7524 fib_prefix_t exp_null_v6_pfx = {
7525 .fp_proto = FIB_PROTOCOL_MPLS,
7527 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7528 .fp_payload_proto = DPO_PROTO_IP6,
7530 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
7531 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
7533 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7534 format_mpls_eos_bit, MPLS_EOS);
7535 fib_entry_contribute_forwarding(lfe,
7536 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7538 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7539 lkd = lookup_dpo_get(dpo1->dpoi_index);
7541 FIB_TEST((fib_index == lkd->lkd_fib_index),
7542 "%U/%U is deag in %d %U",
7543 format_mpls_unicast_label, deag_label,
7544 format_mpls_eos_bit, MPLS_EOS,
7546 format_dpo_id, &dpo, 0);
7547 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7548 "%U/%U is dst deag",
7549 format_mpls_unicast_label, deag_label,
7550 format_mpls_eos_bit, MPLS_EOS);
7551 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
7552 "%U/%U is lookup in interface's table",
7553 format_mpls_unicast_label, deag_label,
7554 format_mpls_eos_bit, MPLS_EOS);
7555 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
7556 "%U/%U is %U dst deag",
7557 format_mpls_unicast_label, deag_label,
7558 format_mpls_eos_bit, MPLS_EOS,
7559 format_dpo_proto, lkd->lkd_proto);
7563 * A route deag route for EOS
7565 fib_prefix_t pfx = {
7566 .fp_proto = FIB_PROTOCOL_MPLS,
7568 .fp_label = deag_label,
7569 .fp_payload_proto = DPO_PROTO_IP4,
7571 lfe = fib_table_entry_path_add(lfib_index,
7574 FIB_ENTRY_FLAG_NONE,
7581 FIB_ROUTE_PATH_FLAG_NONE);
7583 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7585 format_mpls_unicast_label, deag_label,
7586 format_mpls_eos_bit, MPLS_EOS);
7588 fib_entry_contribute_forwarding(lfe,
7589 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7591 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7592 lkd = lookup_dpo_get(dpo1->dpoi_index);
7594 FIB_TEST((fib_index == lkd->lkd_fib_index),
7595 "%U/%U is deag in %d %U",
7596 format_mpls_unicast_label, deag_label,
7597 format_mpls_eos_bit, MPLS_EOS,
7599 format_dpo_id, &dpo, 0);
7600 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7601 "%U/%U is dst deag",
7602 format_mpls_unicast_label, deag_label,
7603 format_mpls_eos_bit, MPLS_EOS);
7604 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
7605 "%U/%U is %U dst deag",
7606 format_mpls_unicast_label, deag_label,
7607 format_mpls_eos_bit, MPLS_EOS,
7608 format_dpo_proto, lkd->lkd_proto);
7610 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7612 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7614 "%U/%U not present",
7615 format_mpls_unicast_label, deag_label,
7616 format_mpls_eos_bit, MPLS_EOS);
7619 * A route deag route for non-EOS
7621 pfx.fp_eos = MPLS_NON_EOS;
7622 lfe = fib_table_entry_path_add(lfib_index,
7625 FIB_ENTRY_FLAG_NONE,
7632 FIB_ROUTE_PATH_FLAG_NONE);
7634 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7636 format_mpls_unicast_label, deag_label,
7637 format_mpls_eos_bit, MPLS_NON_EOS);
7639 fib_entry_contribute_forwarding(lfe,
7640 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7642 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7643 lkd = lookup_dpo_get(dpo1->dpoi_index);
7645 FIB_TEST((fib_index == lkd->lkd_fib_index),
7646 "%U/%U is deag in %d %U",
7647 format_mpls_unicast_label, deag_label,
7648 format_mpls_eos_bit, MPLS_NON_EOS,
7650 format_dpo_id, &dpo, 0);
7651 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7652 "%U/%U is dst deag",
7653 format_mpls_unicast_label, deag_label,
7654 format_mpls_eos_bit, MPLS_NON_EOS);
7656 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
7657 "%U/%U is %U dst deag",
7658 format_mpls_unicast_label, deag_label,
7659 format_mpls_eos_bit, MPLS_NON_EOS,
7660 format_dpo_proto, lkd->lkd_proto);
7662 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7664 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7666 "%U/%U not present",
7667 format_mpls_unicast_label, deag_label,
7668 format_mpls_eos_bit, MPLS_EOS);
7675 fib_prefix_t pfx_1200 = {
7677 .fp_proto = FIB_PROTOCOL_MPLS,
7679 .fp_eos = MPLS_NON_EOS,
7681 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
7682 .type = FT_LB_LABEL_STACK_O_ADJ,
7683 .label_stack_o_adj = {
7684 .adj = ai_mpls_10_10_10_1,
7685 .label_stack_size = 4,
7689 .eos = MPLS_NON_EOS,
7692 dpo_id_t neos_1200 = DPO_INVALID;
7693 dpo_id_t ip_1200 = DPO_INVALID;
7694 mpls_label_t *l200 = NULL;
7695 vec_add1(l200, 200);
7696 vec_add1(l200, 300);
7697 vec_add1(l200, 400);
7698 vec_add1(l200, 500);
7700 lfe = fib_table_entry_update_one_path(fib_index,
7703 FIB_ENTRY_FLAG_NONE,
7706 tm->hw[0]->sw_if_index,
7707 ~0, // invalid fib index
7710 FIB_ROUTE_PATH_FLAG_NONE);
7712 FIB_TEST(fib_test_validate_entry(lfe,
7713 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7715 &neos_o_10_10_10_1),
7716 "1200/0 LB 1 buckets via: "
7720 * A recursive route via the MPLS x-connect
7722 fib_prefix_t pfx_2_2_2_3_s_32 = {
7724 .fp_proto = FIB_PROTOCOL_IP4,
7726 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7729 fib_route_path_t *rpaths = NULL, rpath = {
7730 .frp_proto = FIB_PROTOCOL_MPLS,
7731 .frp_local_label = 1200,
7732 .frp_eos = MPLS_NON_EOS,
7733 .frp_sw_if_index = ~0, // recurive
7734 .frp_fib_index = 0, // Default MPLS fib
7736 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
7737 .frp_label_stack = NULL,
7739 vec_add1(rpaths, rpath);
7741 fib_table_entry_path_add2(fib_index,
7744 FIB_ENTRY_FLAG_NONE,
7748 * A labelled recursive route via the MPLS x-connect
7750 fib_prefix_t pfx_2_2_2_4_s_32 = {
7752 .fp_proto = FIB_PROTOCOL_IP4,
7754 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7757 mpls_label_t *l999 = NULL;
7758 vec_add1(l999, 999);
7759 rpaths[0].frp_label_stack = l999,
7761 fib_table_entry_path_add2(fib_index,
7764 FIB_ENTRY_FLAG_NONE,
7767 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7768 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7770 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7771 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7774 fib_test_lb_bucket_t ip_o_1200 = {
7777 .lb = ip_1200.dpoi_index,
7780 fib_test_lb_bucket_t mpls_o_1200 = {
7781 .type = FT_LB_LABEL_O_LB,
7783 .lb = neos_1200.dpoi_index,
7789 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7790 FIB_TEST(fib_test_validate_entry(lfe,
7791 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7794 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
7795 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7796 FIB_TEST(fib_test_validate_entry(lfe,
7797 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7800 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
7802 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
7803 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
7804 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7806 dpo_reset(&neos_1200);
7807 dpo_reset(&ip_1200);
7810 * A recursive via a label that does not exist
7812 fib_test_lb_bucket_t bucket_drop = {
7813 .type = FT_LB_SPECIAL,
7815 .adj = DPO_PROTO_IP4,
7818 fib_test_lb_bucket_t mpls_bucket_drop = {
7819 .type = FT_LB_SPECIAL,
7821 .adj = DPO_PROTO_MPLS,
7825 rpaths[0].frp_label_stack = NULL;
7826 lfe = fib_table_entry_path_add2(fib_index,
7829 FIB_ENTRY_FLAG_NONE,
7832 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7833 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7835 ip_o_1200.lb.lb = ip_1200.dpoi_index;
7837 FIB_TEST(fib_test_validate_entry(lfe,
7838 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7841 "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
7842 lfe = fib_table_lookup(fib_index, &pfx_1200);
7843 FIB_TEST(fib_test_validate_entry(lfe,
7844 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7847 "1200/neos LB 1 buckets via: ip4-DROP");
7848 FIB_TEST(fib_test_validate_entry(lfe,
7849 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7852 "1200/neos LB 1 buckets via: mpls-DROP");
7854 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7856 dpo_reset(&ip_1200);
7859 * An rx-interface route.
7860 * like the tail of an mcast LSP
7862 dpo_id_t idpo = DPO_INVALID;
7864 interface_dpo_add_or_lock(DPO_PROTO_IP4,
7865 tm->hw[0]->sw_if_index,
7868 fib_prefix_t pfx_2500 = {
7870 .fp_proto = FIB_PROTOCOL_MPLS,
7873 .fp_payload_proto = DPO_PROTO_IP4,
7875 fib_test_lb_bucket_t rx_intf_0 = {
7878 .adj = idpo.dpoi_index,
7882 lfe = fib_table_entry_update_one_path(fib_index,
7885 FIB_ENTRY_FLAG_NONE,
7888 tm->hw[0]->sw_if_index,
7889 ~0, // invalid fib index
7892 FIB_ROUTE_PATH_INTF_RX);
7893 FIB_TEST(fib_test_validate_entry(lfe,
7894 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7897 "2500 rx-interface 0");
7898 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
7901 * An MPLS mulicast entry
7903 fib_prefix_t pfx_3500 = {
7905 .fp_proto = FIB_PROTOCOL_MPLS,
7908 .fp_payload_proto = DPO_PROTO_IP4,
7910 fib_test_rep_bucket_t mc_0 = {
7911 .type = FT_REP_LABEL_O_ADJ,
7913 .adj = ai_mpls_10_10_10_1,
7918 fib_test_rep_bucket_t mc_intf_0 = {
7919 .type = FT_REP_INTF,
7921 .adj = idpo.dpoi_index,
7924 mpls_label_t *l3300 = NULL;
7925 vec_add1(l3300, 3300);
7927 lfe = fib_table_entry_update_one_path(lfib_index,
7930 FIB_ENTRY_FLAG_MULTICAST,
7933 tm->hw[0]->sw_if_index,
7934 ~0, // invalid fib index
7937 FIB_ROUTE_PATH_FLAG_NONE);
7938 FIB_TEST(fib_test_validate_entry(lfe,
7939 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7942 "3500 via replicate over 10.10.10.1");
7945 * MPLS Bud-node. Add a replication via an interface-receieve path
7947 lfe = fib_table_entry_path_add(lfib_index,
7950 FIB_ENTRY_FLAG_MULTICAST,
7953 tm->hw[0]->sw_if_index,
7954 ~0, // invalid fib index
7957 FIB_ROUTE_PATH_INTF_RX);
7958 FIB_TEST(fib_test_validate_entry(lfe,
7959 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7963 "3500 via replicate over 10.10.10.1 and interface-rx");
7966 * Add a replication via an interface-free for-us path
7968 fib_test_rep_bucket_t mc_disp = {
7969 .type = FT_REP_DISP_MFIB_LOOKUP,
7971 .adj = idpo.dpoi_index,
7974 lfe = fib_table_entry_path_add(lfib_index,
7977 FIB_ENTRY_FLAG_MULTICAST,
7984 FIB_ROUTE_PATH_RPF_ID);
7985 FIB_TEST(fib_test_validate_entry(lfe,
7986 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7991 "3500 via replicate over 10.10.10.1 and interface-rx");
7995 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8001 mpls_sw_interface_enable_disable(&mpls_main,
8002 tm->hw[0]->sw_if_index,
8005 FIB_TEST(lb_count == pool_elts(load_balance_pool),
8006 "Load-balance resources freed %d of %d",
8007 lb_count, pool_elts(load_balance_pool));
8008 FIB_TEST(0 == pool_elts(interface_dpo_pool),
8009 "interface_dpo resources freed %d of %d",
8010 0, pool_elts(interface_dpo_pool));
8015 static clib_error_t *
8016 fib_test (vlib_main_t * vm,
8017 unformat_input_t * input,
8018 vlib_cli_command_t * cmd_arg)
8023 fib_test_mk_intf(4);
8025 if (unformat (input, "debug"))
8027 fib_test_do_debug = 1;
8030 if (unformat (input, "ip"))
8032 res += fib_test_v4();
8033 res += fib_test_v6();
8035 else if (unformat (input, "label"))
8037 res += fib_test_label();
8039 else if (unformat (input, "ae"))
8041 res += fib_test_ae();
8043 else if (unformat (input, "lfib"))
8047 else if (unformat (input, "walk"))
8049 res += fib_test_walk();
8051 else if (unformat (input, "bfd"))
8053 res += fib_test_bfd();
8057 res += fib_test_v4();
8058 res += fib_test_v6();
8059 res += fib_test_ae();
8060 res += fib_test_bfd();
8061 res += fib_test_label();
8065 * fib-walk process must be disabled in order for the walk tests to work
8067 fib_walk_process_disable();
8068 res += fib_test_walk();
8069 fib_walk_process_enable();
8074 return clib_error_return(0, "FIB Unit Test Failed");
8082 VLIB_CLI_COMMAND (test_fib_command, static) = {
8084 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8085 .function = fib_test,
8089 fib_test_init (vlib_main_t *vm)
8094 VLIB_INIT_FUNCTION (fib_test_init);