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),
850 "attached interface route adj present %d", ai);
852 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
853 "attached interface adj is glean");
854 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
855 &adj->sub_type.glean.receive_addr)),
856 "attached interface adj is receive ok");
858 local_pfx.fp_len = 32;
859 fib_table_entry_update_one_path(fib_index, &local_pfx,
860 FIB_SOURCE_INTERFACE,
861 (FIB_ENTRY_FLAG_CONNECTED |
862 FIB_ENTRY_FLAG_LOCAL),
865 tm->hw[0]->sw_if_index,
866 ~0, // invalid fib index
869 FIB_ROUTE_PATH_FLAG_NONE);
870 fei = fib_table_lookup(fib_index, &local_pfx);
871 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
872 fib_entry_get_flags(fei)),
873 "Flags set on local interface");
875 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
877 dpo = fib_entry_contribute_ip_forwarding(fei);
878 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
879 "RPF list for local length 0");
880 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
881 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
882 "local interface adj is local");
883 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
885 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
887 "local interface adj is receive ok");
889 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
891 FIB_SOURCE_INTERFACE)),
892 "2 Interface Source'd prefixes");
895 * +2 interface routes +2 non-shared path-lists
897 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
898 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
899 fib_path_list_pool_size());
900 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
901 fib_entry_pool_size());
904 * Modify the default route to be via an adj not yet known.
905 * this sources the defalut route with the API source, which is
906 * a higher preference to the DEFAULT_ROUTE source
908 pfx.fp_addr.ip4.as_u32 = 0;
910 fib_table_entry_path_add(fib_index, &pfx,
915 tm->hw[0]->sw_if_index,
916 ~0, // invalid fib index
919 FIB_ROUTE_PATH_FLAG_NONE);
920 fei = fib_table_lookup(fib_index, &pfx);
921 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
922 "Flags set on API route");
924 FIB_TEST((fei == dfrt), "default route same index");
925 ai = fib_entry_get_adj(fei);
926 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
928 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
929 "adj is incomplete");
930 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
931 "adj nbr next-hop ok");
932 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
935 "1 API Source'd prefixes");
938 * find the adj in the shared db
940 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
943 tm->hw[0]->sw_if_index);
944 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
945 adj_unlock(locked_ai);
948 * +1 shared path-list
950 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
951 fib_path_list_db_size());
952 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
953 fib_path_list_pool_size());
954 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
955 fib_entry_pool_size());
958 * remove the API source from the default route. We expected
959 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
961 pfx.fp_addr.ip4.as_u32 = 0;
963 fib_table_entry_path_remove(fib_index, &pfx,
967 tm->hw[0]->sw_if_index,
968 ~0, // non-recursive path, so no FIB index
970 FIB_ROUTE_PATH_FLAG_NONE);
972 fei = fib_table_lookup(fib_index, &pfx);
974 FIB_TEST((fei == dfrt), "default route same index");
975 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
976 "Default route is DROP");
979 * -1 shared-path-list
981 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
982 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
983 fib_path_list_pool_size());
984 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
985 fib_entry_pool_size());
988 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
990 fib_prefix_t pfx_10_10_10_1_s_32 = {
992 .fp_proto = FIB_PROTOCOL_IP4,
995 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
998 fib_prefix_t pfx_10_10_10_2_s_32 = {
1000 .fp_proto = FIB_PROTOCOL_IP4,
1003 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1006 fib_prefix_t pfx_11_11_11_11_s_32 = {
1008 .fp_proto = FIB_PROTOCOL_IP4,
1011 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1015 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1018 ip46_address_t nh_12_12_12_12 = {
1019 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1021 adj_index_t ai_12_12_12_12;
1024 * Add a route via an incomplete ADJ. then complete the ADJ
1025 * Expect the route LB is updated to use complete adj type.
1027 fei = fib_table_entry_update_one_path(fib_index,
1028 &pfx_11_11_11_11_s_32,
1030 FIB_ENTRY_FLAG_ATTACHED,
1032 &pfx_10_10_10_1_s_32.fp_addr,
1033 tm->hw[0]->sw_if_index,
1034 ~0, // invalid fib index
1037 FIB_ROUTE_PATH_FLAG_NONE);
1039 dpo = fib_entry_contribute_ip_forwarding(fei);
1040 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1041 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1042 "11.11.11.11/32 via incomplete adj");
1044 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1046 &pfx_10_10_10_1_s_32.fp_addr,
1047 tm->hw[0]->sw_if_index);
1048 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1049 adj = adj_get(ai_01);
1050 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1051 "adj is incomplete");
1052 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1053 &adj->sub_type.nbr.next_hop)),
1054 "adj nbr next-hop ok");
1056 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1057 fib_test_build_rewrite(eth_addr));
1058 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1060 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1061 &adj->sub_type.nbr.next_hop)),
1062 "adj nbr next-hop ok");
1063 ai = fib_entry_get_adj(fei);
1064 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1066 dpo = fib_entry_contribute_ip_forwarding(fei);
1067 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1068 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1069 "11.11.11.11/32 via complete adj");
1070 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1071 tm->hw[0]->sw_if_index),
1072 "RPF list for adj-fib contains adj");
1074 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1077 tm->hw[1]->sw_if_index);
1078 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1079 adj = adj_get(ai_12_12_12_12);
1080 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1081 "adj is incomplete");
1082 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1083 &adj->sub_type.nbr.next_hop)),
1084 "adj nbr next-hop ok");
1085 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1086 fib_test_build_rewrite(eth_addr));
1087 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1093 fei = fib_table_entry_path_add(fib_index,
1094 &pfx_10_10_10_1_s_32,
1096 FIB_ENTRY_FLAG_ATTACHED,
1098 &pfx_10_10_10_1_s_32.fp_addr,
1099 tm->hw[0]->sw_if_index,
1100 ~0, // invalid fib index
1103 FIB_ROUTE_PATH_FLAG_NONE);
1104 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1105 "Flags set on adj-fib");
1106 ai = fib_entry_get_adj(fei);
1107 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1109 fib_table_entry_path_remove(fib_index,
1110 &pfx_11_11_11_11_s_32,
1113 &pfx_10_10_10_1_s_32.fp_addr,
1114 tm->hw[0]->sw_if_index,
1115 ~0, // invalid fib index
1117 FIB_ROUTE_PATH_FLAG_NONE);
1121 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1123 &pfx_10_10_10_2_s_32.fp_addr,
1124 tm->hw[0]->sw_if_index);
1125 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1126 adj = adj_get(ai_02);
1127 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1128 "adj is incomplete");
1129 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1130 &adj->sub_type.nbr.next_hop)),
1131 "adj nbr next-hop ok");
1133 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1134 fib_test_build_rewrite(eth_addr));
1135 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1137 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1138 &adj->sub_type.nbr.next_hop)),
1139 "adj nbr next-hop ok");
1140 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1142 fib_table_entry_path_add(fib_index,
1143 &pfx_10_10_10_2_s_32,
1145 FIB_ENTRY_FLAG_ATTACHED,
1147 &pfx_10_10_10_2_s_32.fp_addr,
1148 tm->hw[0]->sw_if_index,
1149 ~0, // invalid fib index
1152 FIB_ROUTE_PATH_FLAG_NONE);
1154 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1155 ai = fib_entry_get_adj(fei);
1156 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1159 * +2 adj-fibs, and their non-shared path-lists
1161 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1162 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1163 fib_path_list_pool_size());
1164 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1165 fib_entry_pool_size());
1168 * Add 2 routes via the first ADJ. ensure path-list sharing
1170 fib_prefix_t pfx_1_1_1_1_s_32 = {
1172 .fp_proto = FIB_PROTOCOL_IP4,
1175 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1179 fib_table_entry_path_add(fib_index,
1182 FIB_ENTRY_FLAG_NONE,
1185 tm->hw[0]->sw_if_index,
1186 ~0, // invalid fib index
1189 FIB_ROUTE_PATH_FLAG_NONE);
1190 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1191 ai = fib_entry_get_adj(fei);
1192 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1195 * +1 entry and a shared path-list
1197 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1198 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1199 fib_path_list_pool_size());
1200 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1201 fib_entry_pool_size());
1204 fib_prefix_t pfx_1_1_2_0_s_24 = {
1206 .fp_proto = FIB_PROTOCOL_IP4,
1208 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1212 fib_table_entry_path_add(fib_index,
1215 FIB_ENTRY_FLAG_NONE,
1218 tm->hw[0]->sw_if_index,
1219 ~0, // invalid fib index
1222 FIB_ROUTE_PATH_FLAG_NONE);
1223 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1224 ai = fib_entry_get_adj(fei);
1225 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1230 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1231 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1232 fib_path_list_pool_size());
1233 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1234 fib_entry_pool_size());
1237 * modify 1.1.2.0/24 to use multipath.
1239 fib_table_entry_path_add(fib_index,
1242 FIB_ENTRY_FLAG_NONE,
1245 tm->hw[0]->sw_if_index,
1246 ~0, // invalid fib index
1249 FIB_ROUTE_PATH_FLAG_NONE);
1250 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1251 dpo = fib_entry_contribute_ip_forwarding(fei);
1252 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1253 1, tm->hw[0]->sw_if_index),
1254 "RPF list for 1.1.2.0/24 contains both adjs");
1256 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1257 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1258 FIB_TEST((ai_01 == dpo1->dpoi_index),
1259 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1260 ai_01, dpo1->dpoi_index);
1262 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1263 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1264 FIB_TEST((ai_02 == dpo1->dpoi_index),
1265 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1268 * +1 shared-pathlist
1270 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1271 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1272 fib_path_list_pool_size());
1273 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1274 fib_entry_pool_size());
1279 fib_table_entry_path_remove(fib_index,
1284 tm->hw[0]->sw_if_index,
1287 FIB_ROUTE_PATH_FLAG_NONE);
1288 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1289 dpo = fib_entry_contribute_ip_forwarding(fei);
1290 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1291 1, tm->hw[0]->sw_if_index),
1292 "RPF list for 1.1.2.0/24 contains one adj");
1294 ai = fib_entry_get_adj(fei);
1295 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1298 * +1 shared-pathlist
1300 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1301 fib_path_list_db_size());
1302 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1303 fib_path_list_pool_size());
1304 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1305 fib_entry_pool_size());
1308 * Add 2 recursive routes:
1309 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1310 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1312 fib_prefix_t bgp_100_pfx = {
1314 .fp_proto = FIB_PROTOCOL_IP4,
1316 /* 100.100.100.100/32 */
1317 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1321 ip46_address_t nh_1_1_1_1 = {
1322 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1325 fei = fib_table_entry_path_add(fib_index,
1328 FIB_ENTRY_FLAG_NONE,
1331 ~0, // no index provided.
1332 fib_index, // nexthop in same fib as route
1335 FIB_ROUTE_PATH_FLAG_NONE);
1337 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1338 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1339 tm->hw[0]->sw_if_index),
1340 "RPF list for adj-fib contains adj");
1343 * +1 entry and +1 shared-path-list
1345 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1346 fib_path_list_db_size());
1347 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1348 fib_path_list_pool_size());
1349 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1350 fib_entry_pool_size());
1352 fib_prefix_t bgp_101_pfx = {
1354 .fp_proto = FIB_PROTOCOL_IP4,
1356 /* 100.100.100.101/32 */
1357 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1361 fib_table_entry_path_add(fib_index,
1364 FIB_ENTRY_FLAG_NONE,
1367 ~0, // no index provided.
1368 fib_index, // nexthop in same fib as route
1371 FIB_ROUTE_PATH_FLAG_NONE);
1373 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1374 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1375 tm->hw[0]->sw_if_index),
1376 "RPF list for adj-fib contains adj");
1379 * +1 entry, but the recursive path-list is shared.
1381 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1382 fib_path_list_db_size());
1383 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1384 fib_path_list_pool_size());
1385 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1386 fib_entry_pool_size());
1389 * An special route; one where the user (me) provides the
1390 * adjacency through which the route will resovle by setting the flags
1392 fib_prefix_t ex_pfx = {
1394 .fp_proto = FIB_PROTOCOL_IP4,
1397 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1401 fib_table_entry_special_add(fib_index,
1404 FIB_ENTRY_FLAG_LOCAL);
1405 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1406 dpo = fib_entry_contribute_ip_forwarding(fei);
1407 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1408 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1409 "local interface adj is local");
1411 fib_table_entry_special_remove(fib_index,
1413 FIB_SOURCE_SPECIAL);
1414 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1415 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1416 "Exclusive reoute removed");
1419 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1420 * adjacency through which the route will resovle
1422 dpo_id_t ex_dpo = DPO_INVALID;
1424 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1427 LOOKUP_INPUT_DST_ADDR,
1428 LOOKUP_TABLE_FROM_CONFIG,
1431 fib_table_entry_special_dpo_add(fib_index,
1434 FIB_ENTRY_FLAG_EXCLUSIVE,
1436 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1437 dpo = fib_entry_contribute_ip_forwarding(fei);
1438 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1439 "exclusive remote uses lookup DPO");
1442 * update the exclusive to use a different DPO
1444 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1445 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1447 fib_table_entry_special_dpo_update(fib_index,
1450 FIB_ENTRY_FLAG_EXCLUSIVE,
1452 dpo = fib_entry_contribute_ip_forwarding(fei);
1453 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1454 "exclusive remote uses now uses NULL DPO");
1456 fib_table_entry_special_remove(fib_index,
1458 FIB_SOURCE_SPECIAL);
1459 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1460 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1461 "Exclusive reoute removed");
1465 * Add a recursive route:
1466 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1468 fib_prefix_t bgp_200_pfx = {
1470 .fp_proto = FIB_PROTOCOL_IP4,
1472 /* 200.200.200.200/32 */
1473 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1477 fib_prefix_t pfx_1_1_1_2_s_32 = {
1479 .fp_proto = FIB_PROTOCOL_IP4,
1481 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1485 fib_table_entry_path_add(fib_index,
1488 FIB_ENTRY_FLAG_NONE,
1490 &pfx_1_1_1_2_s_32.fp_addr,
1491 ~0, // no index provided.
1492 fib_index, // nexthop in same fib as route
1495 FIB_ROUTE_PATH_FLAG_NONE);
1497 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
1500 * the adj should be recursive via drop, since the route resolves via
1501 * the default route, which is itself a DROP
1503 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1504 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1505 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1506 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1507 "RPF list for 1.1.1.2/32 contains 0 adjs");
1510 * +2 entry and +1 shared-path-list
1512 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1513 fib_path_list_db_size());
1514 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1515 fib_path_list_pool_size());
1516 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1517 fib_entry_pool_size());
1520 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1521 * The paths are sort by NH first. in this case the the path with greater
1522 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1524 fib_prefix_t pfx_1_2_3_4_s_32 = {
1526 .fp_proto = FIB_PROTOCOL_IP4,
1528 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1531 fib_table_entry_path_add(fib_index,
1534 FIB_ENTRY_FLAG_NONE,
1537 tm->hw[0]->sw_if_index,
1541 FIB_ROUTE_PATH_FLAG_NONE);
1542 fei = fib_table_entry_path_add(fib_index,
1545 FIB_ENTRY_FLAG_NONE,
1548 tm->hw[1]->sw_if_index,
1552 FIB_ROUTE_PATH_FLAG_NONE);
1554 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1555 dpo = fib_entry_contribute_ip_forwarding(fei);
1556 lb = load_balance_get(dpo->dpoi_index);
1557 FIB_TEST((lb->lb_n_buckets == 4),
1558 "1.2.3.4/32 LB has %d bucket",
1561 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1562 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1563 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1564 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1566 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1567 tm->hw[0]->sw_if_index,
1568 tm->hw[1]->sw_if_index),
1569 "RPF list for 1.2.3.4/32 contains both adjs");
1573 * Unequal Cost load-balance. 4:1 ratio.
1574 * fits in a 16 bucket LB with ratio 13:3
1576 fib_prefix_t pfx_1_2_3_5_s_32 = {
1578 .fp_proto = FIB_PROTOCOL_IP4,
1580 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1583 fib_table_entry_path_add(fib_index,
1586 FIB_ENTRY_FLAG_NONE,
1589 tm->hw[1]->sw_if_index,
1593 FIB_ROUTE_PATH_FLAG_NONE);
1594 fei = fib_table_entry_path_add(fib_index,
1597 FIB_ENTRY_FLAG_NONE,
1600 tm->hw[0]->sw_if_index,
1604 FIB_ROUTE_PATH_FLAG_NONE);
1606 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1607 dpo = fib_entry_contribute_ip_forwarding(fei);
1608 lb = load_balance_get(dpo->dpoi_index);
1609 FIB_TEST((lb->lb_n_buckets == 16),
1610 "1.2.3.5/32 LB has %d bucket",
1613 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1614 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1615 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1616 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1617 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1618 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1619 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1620 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1621 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1622 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1623 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1624 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1625 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1626 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1627 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1628 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1630 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1631 tm->hw[0]->sw_if_index,
1632 tm->hw[1]->sw_if_index),
1633 "RPF list for 1.2.3.4/32 contains both adjs");
1636 * Test UCMP with a large weight skew - this produces load-balance objects with large
1637 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1638 * laso testing the LB in placce modify code when number of buckets is large.
1640 fib_prefix_t pfx_6_6_6_6_s_32 = {
1642 .fp_proto = FIB_PROTOCOL_IP4,
1645 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1648 fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1654 fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1660 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1663 .adj = ai_12_12_12_12,
1666 fib_table_entry_update_one_path(fib_index,
1669 FIB_ENTRY_FLAG_NONE,
1672 tm->hw[0]->sw_if_index,
1673 ~0, // invalid fib index
1676 FIB_ROUTE_PATH_FLAG_NONE);
1678 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1679 FIB_TEST(fib_test_validate_entry(fei,
1680 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1683 "6.6.6.6/32 via 10.10.10.1");
1685 fib_table_entry_path_add(fib_index,
1688 FIB_ENTRY_FLAG_NONE,
1691 tm->hw[0]->sw_if_index,
1692 ~0, // invalid fib index
1695 FIB_ROUTE_PATH_FLAG_NONE);
1697 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1698 FIB_TEST(fib_test_validate_entry(fei,
1699 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1765 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1767 fib_table_entry_path_add(fib_index,
1770 FIB_ENTRY_FLAG_NONE,
1773 tm->hw[1]->sw_if_index,
1774 ~0, // invalid fib index
1777 FIB_ROUTE_PATH_FLAG_NONE);
1779 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1780 FIB_TEST(fib_test_validate_entry(fei,
1781 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
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 &ip_6_6_6_6_o_12_12_12_12),
1911 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1913 fib_table_entry_path_remove(fib_index,
1918 tm->hw[1]->sw_if_index,
1919 ~0, // invalid fib index
1921 FIB_ROUTE_PATH_FLAG_NONE);
1923 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1924 FIB_TEST(fib_test_validate_entry(fei,
1925 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1991 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1993 fib_table_entry_path_remove(fib_index,
1998 tm->hw[0]->sw_if_index,
1999 ~0, // invalid fib index
2001 FIB_ROUTE_PATH_FLAG_NONE);
2003 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2004 FIB_TEST(fib_test_validate_entry(fei,
2005 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2008 "6.6.6.6/32 via 10.10.10.1");
2010 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2013 * A recursive via the two unequal cost entries
2015 fib_prefix_t bgp_44_s_32 = {
2017 .fp_proto = FIB_PROTOCOL_IP4,
2019 /* 200.200.200.201/32 */
2020 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2023 fei = fib_table_entry_path_add(fib_index,
2026 FIB_ENTRY_FLAG_NONE,
2028 &pfx_1_2_3_4_s_32.fp_addr,
2033 FIB_ROUTE_PATH_FLAG_NONE);
2034 fei = fib_table_entry_path_add(fib_index,
2037 FIB_ENTRY_FLAG_NONE,
2039 &pfx_1_2_3_5_s_32.fp_addr,
2044 FIB_ROUTE_PATH_FLAG_NONE);
2046 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2047 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2048 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2049 tm->hw[0]->sw_if_index,
2050 tm->hw[1]->sw_if_index),
2051 "RPF list for 1.2.3.4/32 contains both adjs");
2054 * test the uRPF check functions
2056 dpo_id_t dpo_44 = DPO_INVALID;
2059 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2060 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2062 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2063 "uRPF check for 68.68.68.68/32 on %d OK",
2064 tm->hw[0]->sw_if_index);
2065 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2066 "uRPF check for 68.68.68.68/32 on %d OK",
2067 tm->hw[1]->sw_if_index);
2068 FIB_TEST(!fib_urpf_check(urpfi, 99),
2069 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2073 fib_table_entry_delete(fib_index,
2076 fib_table_entry_delete(fib_index,
2079 fib_table_entry_delete(fib_index,
2084 * Add a recursive route:
2085 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2087 fib_prefix_t bgp_201_pfx = {
2089 .fp_proto = FIB_PROTOCOL_IP4,
2091 /* 200.200.200.201/32 */
2092 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2096 fib_prefix_t pfx_1_1_1_200_s_32 = {
2098 .fp_proto = FIB_PROTOCOL_IP4,
2100 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2104 fib_table_entry_path_add(fib_index,
2107 FIB_ENTRY_FLAG_NONE,
2109 &pfx_1_1_1_200_s_32.fp_addr,
2110 ~0, // no index provided.
2111 fib_index, // nexthop in same fib as route
2114 FIB_ROUTE_PATH_FLAG_NONE);
2116 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2118 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2119 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2120 "Flags set on RR via non-attached");
2121 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2122 "RPF list for BGP route empty");
2125 * +2 entry (BGP & RR) and +1 shared-path-list
2127 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2128 fib_path_list_db_size());
2129 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2130 fib_path_list_pool_size());
2131 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2132 fib_entry_pool_size());
2135 * insert a route that covers the missing 1.1.1.2/32. we epxect
2136 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2138 fib_prefix_t pfx_1_1_1_0_s_24 = {
2140 .fp_proto = FIB_PROTOCOL_IP4,
2143 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2147 fib_table_entry_path_add(fib_index,
2150 FIB_ENTRY_FLAG_NONE,
2153 tm->hw[0]->sw_if_index,
2154 ~0, // invalid fib index
2157 FIB_ROUTE_PATH_FLAG_NONE);
2158 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2159 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2160 ai = fib_entry_get_adj(fei);
2161 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2162 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2163 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2164 ai = fib_entry_get_adj(fei);
2165 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2166 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2167 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2168 ai = fib_entry_get_adj(fei);
2169 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2172 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2174 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2175 fib_path_list_db_size());
2176 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2177 fib_path_list_pool_size());
2178 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2179 fib_entry_pool_size());
2182 * the recursive adj for 200.200.200.200 should be updated.
2184 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2185 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2186 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2187 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2188 tm->hw[0]->sw_if_index),
2189 "RPF list for BGP route has itf index 0");
2192 * insert a more specific route than 1.1.1.0/24 that also covers the
2193 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2194 * 200.200.200.200 to resolve through it.
2196 fib_prefix_t pfx_1_1_1_0_s_28 = {
2198 .fp_proto = FIB_PROTOCOL_IP4,
2201 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2205 fib_table_entry_path_add(fib_index,
2208 FIB_ENTRY_FLAG_NONE,
2211 tm->hw[0]->sw_if_index,
2212 ~0, // invalid fib index
2215 FIB_ROUTE_PATH_FLAG_NONE);
2216 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2217 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2218 ai = fib_entry_get_adj(fei);
2219 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2222 * +1 entry. +1 shared path-list
2224 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2225 fib_path_list_db_size());
2226 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2227 fib_path_list_pool_size());
2228 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2229 fib_entry_pool_size());
2232 * the recursive adj for 200.200.200.200 should be updated.
2233 * 200.200.200.201 remains unchanged.
2235 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2236 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2239 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2241 fib_table_entry_path_remove(fib_index,
2246 tm->hw[0]->sw_if_index,
2249 FIB_ROUTE_PATH_FLAG_NONE);
2250 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2251 FIB_NODE_INDEX_INVALID),
2252 "1.1.1.0/28 removed");
2253 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2254 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2255 "1.1.1.0/28 lookup via /24");
2256 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2257 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2260 * -1 entry. -1 shared path-list
2262 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2263 fib_path_list_db_size());
2264 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2265 fib_path_list_pool_size());
2266 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2267 fib_entry_pool_size());
2270 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2272 fib_table_entry_path_remove(fib_index,
2277 tm->hw[0]->sw_if_index,
2280 FIB_ROUTE_PATH_FLAG_NONE);
2281 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2282 FIB_NODE_INDEX_INVALID),
2283 "1.1.1.0/24 removed");
2285 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2286 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2287 "1.1.1.2/32 route is DROP");
2288 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2289 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2290 "1.1.1.200/32 route is DROP");
2292 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2293 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2298 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2299 fib_path_list_db_size());
2300 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2301 fib_path_list_pool_size());
2302 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2303 fib_entry_pool_size());
2306 * insert the missing 1.1.1.2/32
2308 fei = fib_table_entry_path_add(fib_index,
2311 FIB_ENTRY_FLAG_NONE,
2314 tm->hw[0]->sw_if_index,
2315 ~0, // invalid fib index
2318 FIB_ROUTE_PATH_FLAG_NONE);
2319 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2320 ai = fib_entry_get_adj(fei);
2321 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2323 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2324 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2327 * no change. 1.1.1.2/32 was already there RR sourced.
2329 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2330 fib_path_list_db_size());
2331 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2332 fib_path_list_pool_size());
2333 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2334 fib_entry_pool_size());
2337 * remove 200.200.200.201/32 which does not have a valid via FIB
2339 fib_table_entry_path_remove(fib_index,
2343 &pfx_1_1_1_200_s_32.fp_addr,
2344 ~0, // no index provided.
2347 FIB_ROUTE_PATH_FLAG_NONE);
2350 * -2 entries (BGP and RR). -1 shared path-list;
2352 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2353 FIB_NODE_INDEX_INVALID),
2354 "200.200.200.201/32 removed");
2355 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2356 FIB_NODE_INDEX_INVALID),
2357 "1.1.1.200/32 removed");
2359 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2360 fib_path_list_db_size());
2361 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2362 fib_path_list_pool_size());
2363 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2364 fib_entry_pool_size());
2367 * remove 200.200.200.200/32 which does have a valid via FIB
2369 fib_table_entry_path_remove(fib_index,
2373 &pfx_1_1_1_2_s_32.fp_addr,
2374 ~0, // no index provided.
2377 FIB_ROUTE_PATH_FLAG_NONE);
2379 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2380 FIB_NODE_INDEX_INVALID),
2381 "200.200.200.200/32 removed");
2382 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2383 FIB_NODE_INDEX_INVALID),
2384 "1.1.1.2/32 still present");
2387 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2389 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2390 fib_path_list_db_size());
2391 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2392 fib_path_list_pool_size());
2393 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2394 fib_entry_pool_size());
2397 * A recursive prefix that has a 2 path load-balance.
2398 * It also shares a next-hop with other BGP prefixes and hence
2399 * test the ref counting of RR sourced prefixes and 2 level LB.
2401 const fib_prefix_t bgp_102 = {
2403 .fp_proto = FIB_PROTOCOL_IP4,
2405 /* 100.100.100.101/32 */
2406 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2409 fib_table_entry_path_add(fib_index,
2412 FIB_ENTRY_FLAG_NONE,
2414 &pfx_1_1_1_1_s_32.fp_addr,
2415 ~0, // no index provided.
2416 fib_index, // same as route
2419 FIB_ROUTE_PATH_FLAG_NONE);
2420 fib_table_entry_path_add(fib_index,
2423 FIB_ENTRY_FLAG_NONE,
2425 &pfx_1_1_1_2_s_32.fp_addr,
2426 ~0, // no index provided.
2427 fib_index, // same as route's FIB
2430 FIB_ROUTE_PATH_FLAG_NONE);
2431 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2432 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2433 dpo = fib_entry_contribute_ip_forwarding(fei);
2435 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2436 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2437 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2438 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2440 lb = load_balance_get(dpo->dpoi_index);
2441 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2442 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2443 "First via 10.10.10.1");
2444 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2445 "Second via 10.10.10.1");
2447 fib_table_entry_path_remove(fib_index,
2451 &pfx_1_1_1_1_s_32.fp_addr,
2452 ~0, // no index provided.
2453 fib_index, // same as route's FIB
2455 FIB_ROUTE_PATH_FLAG_NONE);
2456 fib_table_entry_path_remove(fib_index,
2460 &pfx_1_1_1_2_s_32.fp_addr,
2461 ~0, // no index provided.
2462 fib_index, // same as route's FIB
2464 FIB_ROUTE_PATH_FLAG_NONE);
2465 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2466 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2469 * remove the remaining recursives
2471 fib_table_entry_path_remove(fib_index,
2475 &pfx_1_1_1_1_s_32.fp_addr,
2476 ~0, // no index provided.
2477 fib_index, // same as route's FIB
2479 FIB_ROUTE_PATH_FLAG_NONE);
2480 fib_table_entry_path_remove(fib_index,
2484 &pfx_1_1_1_1_s_32.fp_addr,
2485 ~0, // no index provided.
2486 fib_index, // same as route's FIB
2488 FIB_ROUTE_PATH_FLAG_NONE);
2489 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2490 FIB_NODE_INDEX_INVALID),
2491 "100.100.100.100/32 removed");
2492 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2493 FIB_NODE_INDEX_INVALID),
2494 "100.100.100.101/32 removed");
2497 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2499 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2500 fib_path_list_db_size());
2501 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2502 fib_path_list_pool_size());
2503 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2504 fib_entry_pool_size());
2507 * Add a recursive route via a connected cover, using an adj-fib that does exist
2509 fib_table_entry_path_add(fib_index,
2512 FIB_ENTRY_FLAG_NONE,
2515 ~0, // no index provided.
2516 fib_index, // Same as route's FIB
2519 FIB_ROUTE_PATH_FLAG_NONE);
2522 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2524 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2525 fib_path_list_db_size());
2526 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2527 fib_path_list_pool_size());
2528 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2529 fib_entry_pool_size());
2531 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2532 dpo = fib_entry_contribute_ip_forwarding(fei);
2534 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2535 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2537 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2538 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2540 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2541 "Flags set on RR via existing attached");
2544 * Add a recursive route via a connected cover, using and adj-fib that does
2547 ip46_address_t nh_10_10_10_3 = {
2548 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2550 fib_prefix_t pfx_10_10_10_3 = {
2552 .fp_proto = FIB_PROTOCOL_IP4,
2553 .fp_addr = nh_10_10_10_3,
2556 fib_table_entry_path_add(fib_index,
2559 FIB_ENTRY_FLAG_NONE,
2562 ~0, // no index provided.
2566 FIB_ROUTE_PATH_FLAG_NONE);
2569 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2570 * one unshared non-recursive via 10.10.10.3
2572 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2573 fib_path_list_db_size());
2574 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2575 fib_path_list_pool_size());
2576 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2577 fib_entry_pool_size());
2579 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2582 tm->hw[0]->sw_if_index);
2584 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2585 dpo = fib_entry_contribute_ip_forwarding(fei);
2586 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2587 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2589 ai = fib_entry_get_adj(fei);
2590 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2591 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2592 fib_entry_get_flags(fei)),
2593 "Flags set on RR via non-existing attached");
2595 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2596 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2601 * remove the recursives
2603 fib_table_entry_path_remove(fib_index,
2608 ~0, // no index provided.
2609 fib_index, // same as route's FIB
2611 FIB_ROUTE_PATH_FLAG_NONE);
2612 fib_table_entry_path_remove(fib_index,
2617 ~0, // no index provided.
2618 fib_index, // same as route's FIB
2620 FIB_ROUTE_PATH_FLAG_NONE);
2622 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2623 FIB_NODE_INDEX_INVALID),
2624 "200.200.200.201/32 removed");
2625 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2626 FIB_NODE_INDEX_INVALID),
2627 "200.200.200.200/32 removed");
2628 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2629 FIB_NODE_INDEX_INVALID),
2630 "10.10.10.3/32 removed");
2633 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2634 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2636 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2637 fib_path_list_db_size());
2638 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2639 fib_path_list_pool_size());
2640 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2641 fib_entry_pool_size());
2646 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2648 fib_prefix_t pfx_5_5_5_5_s_32 = {
2650 .fp_proto = FIB_PROTOCOL_IP4,
2652 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2655 fib_prefix_t pfx_5_5_5_6_s_32 = {
2657 .fp_proto = FIB_PROTOCOL_IP4,
2659 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2662 fib_prefix_t pfx_5_5_5_7_s_32 = {
2664 .fp_proto = FIB_PROTOCOL_IP4,
2666 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2670 fib_table_entry_path_add(fib_index,
2673 FIB_ENTRY_FLAG_NONE,
2675 &pfx_5_5_5_6_s_32.fp_addr,
2676 ~0, // no index provided.
2680 FIB_ROUTE_PATH_FLAG_NONE);
2681 fib_table_entry_path_add(fib_index,
2684 FIB_ENTRY_FLAG_NONE,
2686 &pfx_5_5_5_7_s_32.fp_addr,
2687 ~0, // no index provided.
2691 FIB_ROUTE_PATH_FLAG_NONE);
2692 fib_table_entry_path_add(fib_index,
2695 FIB_ENTRY_FLAG_NONE,
2697 &pfx_5_5_5_5_s_32.fp_addr,
2698 ~0, // no index provided.
2702 FIB_ROUTE_PATH_FLAG_NONE);
2704 * +3 entries, +3 shared path-list
2706 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2707 fib_path_list_db_size());
2708 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2709 fib_path_list_pool_size());
2710 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2711 fib_entry_pool_size());
2714 * All the entries have only looped paths, so they are all drop
2716 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2717 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2718 "LB for 5.5.5.7/32 is via adj for DROP");
2719 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2720 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2721 "LB for 5.5.5.5/32 is via adj for DROP");
2722 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2723 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2724 "LB for 5.5.5.6/32 is via adj for DROP");
2727 * provide 5.5.5.6/32 with alternate path.
2728 * this will allow only 5.5.5.6/32 to forward with this path, the others
2729 * are still drop since the loop is still present.
2731 fib_table_entry_path_add(fib_index,
2734 FIB_ENTRY_FLAG_NONE,
2737 tm->hw[0]->sw_if_index,
2741 FIB_ROUTE_PATH_FLAG_NONE);
2743 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2744 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2746 lb = load_balance_get(dpo1->dpoi_index);
2747 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2749 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2750 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2751 FIB_TEST((ai_01 == dpo2->dpoi_index),
2752 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2754 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2755 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2756 "LB for 5.5.5.7/32 is via adj for DROP");
2757 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2758 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2759 "LB for 5.5.5.5/32 is via adj for DROP");
2762 * remove the alternate path for 5.5.5.6/32
2765 fib_table_entry_path_remove(fib_index,
2770 tm->hw[0]->sw_if_index,
2773 FIB_ROUTE_PATH_FLAG_NONE);
2775 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2776 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2777 "LB for 5.5.5.7/32 is via adj for DROP");
2778 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2779 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2780 "LB for 5.5.5.5/32 is via adj for DROP");
2781 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2782 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2783 "LB for 5.5.5.6/32 is via adj for DROP");
2786 * break the loop by giving 5.5.5.5/32 a new set of paths
2787 * expect all to forward via this new path.
2789 fib_table_entry_update_one_path(fib_index,
2792 FIB_ENTRY_FLAG_NONE,
2795 tm->hw[0]->sw_if_index,
2796 ~0, // invalid fib index
2799 FIB_ROUTE_PATH_FLAG_NONE);
2801 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2802 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2803 lb = load_balance_get(dpo1->dpoi_index);
2804 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2806 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2807 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2808 FIB_TEST((ai_01 == dpo2->dpoi_index),
2809 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2811 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2812 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2814 lb = load_balance_get(dpo2->dpoi_index);
2815 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2816 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2817 "5.5.5.5.7 via 5.5.5.5");
2819 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2820 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2822 lb = load_balance_get(dpo1->dpoi_index);
2823 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2824 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2825 "5.5.5.5.6 via 5.5.5.7");
2828 * revert back to the loop. so we can remove the prefixes with
2831 fib_table_entry_update_one_path(fib_index,
2834 FIB_ENTRY_FLAG_NONE,
2836 &pfx_5_5_5_6_s_32.fp_addr,
2837 ~0, // no index provided.
2841 FIB_ROUTE_PATH_FLAG_NONE);
2843 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2844 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2845 "LB for 5.5.5.7/32 is via adj for DROP");
2846 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2847 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2848 "LB for 5.5.5.5/32 is via adj for DROP");
2849 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2850 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2851 "LB for 5.5.5.6/32 is via adj for DROP");
2854 * remove all the 5.5.5.x/32 prefixes
2856 fib_table_entry_path_remove(fib_index,
2860 &pfx_5_5_5_6_s_32.fp_addr,
2861 ~0, // no index provided.
2862 fib_index, // same as route's FIB
2864 FIB_ROUTE_PATH_FLAG_NONE);
2865 fib_table_entry_path_remove(fib_index,
2869 &pfx_5_5_5_7_s_32.fp_addr,
2870 ~0, // no index provided.
2871 fib_index, // same as route's FIB
2873 FIB_ROUTE_PATH_FLAG_NONE);
2874 fib_table_entry_path_remove(fib_index,
2878 &pfx_5_5_5_5_s_32.fp_addr,
2879 ~0, // no index provided.
2880 fib_index, // same as route's FIB
2882 FIB_ROUTE_PATH_FLAG_NONE);
2883 fib_table_entry_path_remove(fib_index,
2888 ~0, // no index provided.
2889 fib_index, // same as route's FIB
2891 FIB_ROUTE_PATH_FLAG_NONE);
2894 * -3 entries, -3 shared path-list
2896 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2897 fib_path_list_db_size());
2898 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2899 fib_path_list_pool_size());
2900 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2901 fib_entry_pool_size());
2904 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2906 fib_table_entry_path_add(fib_index,
2909 FIB_ENTRY_FLAG_NONE,
2911 &pfx_5_5_5_6_s_32.fp_addr,
2912 ~0, // no index provided.
2916 FIB_ROUTE_PATH_FLAG_NONE);
2917 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2918 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2919 "1-level 5.5.5.6/32 loop is via adj for DROP");
2921 fib_table_entry_path_remove(fib_index,
2925 &pfx_5_5_5_6_s_32.fp_addr,
2926 ~0, // no index provided.
2927 fib_index, // same as route's FIB
2929 FIB_ROUTE_PATH_FLAG_NONE);
2930 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2931 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2932 "1-level 5.5.5.6/32 loop is removed");
2935 * A recursive route whose next-hop is covered by the prefix.
2936 * This would mean the via-fib, which inherits forwarding from its
2937 * cover, thus picks up forwarding from the prfix, which is via the
2938 * via-fib, and we have a loop.
2940 fib_prefix_t pfx_23_23_23_0_s_24 = {
2942 .fp_proto = FIB_PROTOCOL_IP4,
2944 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2947 fib_prefix_t pfx_23_23_23_23_s_32 = {
2949 .fp_proto = FIB_PROTOCOL_IP4,
2951 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2954 fei = fib_table_entry_path_add(fib_index,
2955 &pfx_23_23_23_0_s_24,
2957 FIB_ENTRY_FLAG_NONE,
2959 &pfx_23_23_23_23_s_32.fp_addr,
2964 FIB_ROUTE_PATH_FLAG_NONE);
2965 dpo = fib_entry_contribute_ip_forwarding(fei);
2966 FIB_TEST(load_balance_is_drop(dpo),
2967 "23.23.23.0/24 via covered is DROP");
2968 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2971 * add-remove test. no change.
2973 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2974 fib_path_list_db_size());
2975 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2976 fib_path_list_pool_size());
2977 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2978 fib_entry_pool_size());
2981 * Make the default route recursive via a unknown next-hop. Thus the
2982 * next hop's cover would be the default route
2984 fei = fib_table_entry_path_add(fib_index,
2987 FIB_ENTRY_FLAG_NONE,
2989 &pfx_23_23_23_23_s_32.fp_addr,
2994 FIB_ROUTE_PATH_FLAG_NONE);
2995 dpo = fib_entry_contribute_ip_forwarding(fei);
2996 FIB_TEST(load_balance_is_drop(dpo),
2997 "0.0.0.0.0/0 via is DROP");
2998 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
2999 "no resolving interface for looped 0.0.0.0/0");
3001 fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3002 dpo = fib_entry_contribute_ip_forwarding(fei);
3003 FIB_TEST(load_balance_is_drop(dpo),
3004 "23.23.23.23/32 via is DROP");
3005 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3006 "no resolving interface for looped 23.23.23.23/32");
3008 fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3011 * A recursive route with recursion constraints.
3012 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3014 fib_table_entry_path_add(fib_index,
3017 FIB_ENTRY_FLAG_NONE,
3024 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3026 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3027 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3029 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3030 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3032 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3033 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3036 * save the load-balance. we expect it to be inplace modified
3038 lb = load_balance_get(dpo1->dpoi_index);
3041 * add a covering prefix for the via fib that would otherwise serve
3042 * as the resolving route when the host is removed
3044 fib_table_entry_path_add(fib_index,
3047 FIB_ENTRY_FLAG_NONE,
3050 tm->hw[0]->sw_if_index,
3051 ~0, // invalid fib index
3054 FIB_ROUTE_PATH_FLAG_NONE);
3055 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3056 ai = fib_entry_get_adj(fei);
3057 FIB_TEST((ai == ai_01),
3058 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3061 * remove the host via FIB - expect the BGP prefix to be drop
3063 fib_table_entry_path_remove(fib_index,
3068 tm->hw[0]->sw_if_index,
3069 ~0, // invalid fib index
3071 FIB_ROUTE_PATH_FLAG_NONE);
3073 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3074 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3077 * add the via-entry host reoute back. expect to resolve again
3079 fib_table_entry_path_add(fib_index,
3082 FIB_ENTRY_FLAG_NONE,
3085 tm->hw[0]->sw_if_index,
3086 ~0, // invalid fib index
3089 FIB_ROUTE_PATH_FLAG_NONE);
3090 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3091 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3094 * add another path for the recursive. it will then have 2.
3096 fib_prefix_t pfx_1_1_1_3_s_32 = {
3098 .fp_proto = FIB_PROTOCOL_IP4,
3100 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3103 fib_table_entry_path_add(fib_index,
3106 FIB_ENTRY_FLAG_NONE,
3109 tm->hw[0]->sw_if_index,
3110 ~0, // invalid fib index
3113 FIB_ROUTE_PATH_FLAG_NONE);
3115 fib_table_entry_path_add(fib_index,
3118 FIB_ENTRY_FLAG_NONE,
3120 &pfx_1_1_1_3_s_32.fp_addr,
3125 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3128 * add a bunch load more entries using this path combo so that we get
3129 * an LB-map created.
3132 fib_prefix_t bgp_78s[N_P];
3133 for (ii = 0; ii < N_P; ii++)
3135 bgp_78s[ii].fp_len = 32;
3136 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3137 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3140 fib_table_entry_path_add(fib_index,
3143 FIB_ENTRY_FLAG_NONE,
3145 &pfx_1_1_1_3_s_32.fp_addr,
3150 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3151 fib_table_entry_path_add(fib_index,
3154 FIB_ENTRY_FLAG_NONE,
3161 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3164 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3165 dpo = fib_entry_contribute_ip_forwarding(fei);
3167 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3168 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3169 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3170 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3171 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3172 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3173 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3174 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3177 * expect the lb-map used by the recursive's load-balance is using both buckets
3179 load_balance_map_t *lbm;
3182 lb = load_balance_get(dpo->dpoi_index);
3184 load_balance_map_lock(lbmi);
3185 lbm = load_balance_map_get(lbmi);
3187 FIB_TEST(lbm->lbm_buckets[0] == 0,
3188 "LB maps's bucket 0 is %d",
3189 lbm->lbm_buckets[0]);
3190 FIB_TEST(lbm->lbm_buckets[1] == 1,
3191 "LB maps's bucket 1 is %d",
3192 lbm->lbm_buckets[1]);
3195 * withdraw one of the /32 via-entrys.
3196 * that ECMP path will be unresolved and forwarding should continue on the
3197 * other available path. this is an iBGP PIC edge failover.
3198 * Test the forwarding changes without re-fetching the adj from the
3199 * recursive entry. this ensures its the same one that is updated; i.e. an
3202 fib_table_entry_path_remove(fib_index,
3207 tm->hw[0]->sw_if_index,
3208 ~0, // invalid fib index
3210 FIB_ROUTE_PATH_FLAG_NONE);
3212 /* suspend so the update walk kicks int */
3213 vlib_process_suspend(vlib_get_main(), 1e-5);
3215 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3216 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3217 "post PIC 200.200.200.200/32 was inplace modified");
3219 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3220 "post PIC adj for 200.200.200.200/32 is recursive"
3221 " via adj for 1.1.1.3");
3224 * the LB maps that was locked above should have been modified to remove
3225 * the path that was down, and thus its bucket points to a path that is
3228 FIB_TEST(lbm->lbm_buckets[0] == 1,
3229 "LB maps's bucket 0 is %d",
3230 lbm->lbm_buckets[0]);
3231 FIB_TEST(lbm->lbm_buckets[1] == 1,
3232 "LB maps's bucket 1 is %d",
3233 lbm->lbm_buckets[1]);
3235 load_balance_map_unlock(lbmi);
3238 * add it back. again
3240 fib_table_entry_path_add(fib_index,
3243 FIB_ENTRY_FLAG_NONE,
3246 tm->hw[0]->sw_if_index,
3247 ~0, // invalid fib index
3250 FIB_ROUTE_PATH_FLAG_NONE);
3252 /* suspend so the update walk kicks in */
3253 vlib_process_suspend(vlib_get_main(), 1e-5);
3255 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3256 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3257 "via adj for 1.1.1.1");
3258 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3259 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3260 "via adj for 1.1.1.3");
3262 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3263 dpo = fib_entry_contribute_ip_forwarding(fei);
3264 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3265 "post PIC 200.200.200.200/32 was inplace modified");
3268 * add a 3rd path. this makes the LB 16 buckets.
3270 fib_table_entry_path_add(fib_index,
3273 FIB_ENTRY_FLAG_NONE,
3275 &pfx_1_1_1_2_s_32.fp_addr,
3280 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3281 for (ii = 0; ii < N_P; ii++)
3283 fib_table_entry_path_add(fib_index,
3286 FIB_ENTRY_FLAG_NONE,
3288 &pfx_1_1_1_2_s_32.fp_addr,
3293 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3296 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3297 dpo = fib_entry_contribute_ip_forwarding(fei);
3298 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3299 "200.200.200.200/32 was inplace modified for 3rd path");
3300 FIB_TEST(16 == lb->lb_n_buckets,
3301 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3304 load_balance_map_lock(lbmi);
3305 lbm = load_balance_map_get(lbmi);
3307 for (ii = 0; ii < 16; ii++)
3309 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3310 "LB Map for 200.200.200.200/32 at %d is %d",
3311 ii, lbm->lbm_buckets[ii]);
3315 * trigger PIC by removing the first via-entry
3316 * the first 6 buckets of the map should map to the next 6
3318 fib_table_entry_path_remove(fib_index,
3323 tm->hw[0]->sw_if_index,
3326 FIB_ROUTE_PATH_FLAG_NONE);
3327 /* suspend so the update walk kicks int */
3328 vlib_process_suspend(vlib_get_main(), 1e-5);
3330 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3331 dpo = fib_entry_contribute_ip_forwarding(fei);
3332 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3333 "200.200.200.200/32 was inplace modified for 3rd path");
3334 FIB_TEST(2 == lb->lb_n_buckets,
3335 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3337 for (ii = 0; ii < 6; ii++)
3339 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3340 "LB Map for 200.200.200.200/32 at %d is %d",
3341 ii, lbm->lbm_buckets[ii]);
3343 for (ii = 6; ii < 16; ii++)
3345 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3346 "LB Map for 200.200.200.200/32 at %d is %d",
3347 ii, lbm->lbm_buckets[ii]);
3349 load_balance_map_unlock(lbmi);
3354 fib_table_entry_path_add(fib_index,
3357 FIB_ENTRY_FLAG_NONE,
3360 tm->hw[0]->sw_if_index,
3364 FIB_ROUTE_PATH_FLAG_NONE);
3366 for (ii = 0; ii < N_P; ii++)
3368 fib_table_entry_delete(fib_index,
3371 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3372 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3374 format_fib_prefix, &bgp_78s[ii]);
3376 fib_table_entry_path_remove(fib_index,
3380 &pfx_1_1_1_2_s_32.fp_addr,
3384 MPLS_LABEL_INVALID);
3385 fib_table_entry_path_remove(fib_index,
3393 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3394 fib_table_entry_path_remove(fib_index,
3398 &pfx_1_1_1_3_s_32.fp_addr,
3402 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3403 fib_table_entry_delete(fib_index,
3406 fib_table_entry_delete(fib_index,
3409 /* suspend so the update walk kicks int */
3410 vlib_process_suspend(vlib_get_main(), 1e-5);
3411 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3412 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3413 "1.1.1.1/28 removed");
3414 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3415 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3416 "1.1.1.3/32 removed");
3417 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3418 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3419 "200.200.200.200/32 removed");
3422 * add-remove test. no change.
3424 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3425 fib_path_list_db_size());
3426 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3427 fib_path_list_pool_size());
3428 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3429 fib_entry_pool_size());
3432 * A route whose paths are built up iteratively and then removed
3435 fib_prefix_t pfx_4_4_4_4_s_32 = {
3437 .fp_proto = FIB_PROTOCOL_IP4,
3440 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3444 fib_table_entry_path_add(fib_index,
3447 FIB_ENTRY_FLAG_NONE,
3450 tm->hw[0]->sw_if_index,
3454 FIB_ROUTE_PATH_FLAG_NONE);
3455 fib_table_entry_path_add(fib_index,
3458 FIB_ENTRY_FLAG_NONE,
3461 tm->hw[0]->sw_if_index,
3465 FIB_ROUTE_PATH_FLAG_NONE);
3466 fib_table_entry_path_add(fib_index,
3469 FIB_ENTRY_FLAG_NONE,
3472 tm->hw[0]->sw_if_index,
3476 FIB_ROUTE_PATH_FLAG_NONE);
3477 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3478 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3479 "4.4.4.4/32 present");
3481 fib_table_entry_delete(fib_index,
3484 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3485 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3486 "4.4.4.4/32 removed");
3489 * add-remove test. no change.
3491 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3492 fib_path_list_db_size());
3493 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3494 fib_path_list_pool_size());
3495 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3496 fib_entry_pool_size());
3499 * A route with multiple paths at once
3501 fib_route_path_t *r_paths = NULL;
3503 for (ii = 0; ii < 4; ii++)
3505 fib_route_path_t r_path = {
3506 .frp_proto = FIB_PROTOCOL_IP4,
3508 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3510 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3512 .frp_fib_index = ~0,
3514 vec_add1(r_paths, r_path);
3517 fib_table_entry_update(fib_index,
3520 FIB_ENTRY_FLAG_NONE,
3523 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3524 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3525 dpo = fib_entry_contribute_ip_forwarding(fei);
3527 lb = load_balance_get(dpo->dpoi_index);
3528 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3530 fib_table_entry_delete(fib_index,
3533 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3534 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3535 "4.4.4.4/32 removed");
3539 * add-remove test. no change.
3541 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3542 fib_path_list_db_size());
3543 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3544 fib_path_list_pool_size());
3545 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3546 fib_entry_pool_size());
3549 * A route deag route
3551 fib_table_entry_path_add(fib_index,
3554 FIB_ENTRY_FLAG_NONE,
3561 FIB_ROUTE_PATH_FLAG_NONE);
3563 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3564 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3566 dpo = fib_entry_contribute_ip_forwarding(fei);
3567 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3568 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3570 FIB_TEST((fib_index == lkd->lkd_fib_index),
3571 "4.4.4.4/32 is deag in %d %U",
3573 format_dpo_id, dpo, 0);
3575 fib_table_entry_delete(fib_index,
3578 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3579 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3580 "4.4.4.4/32 removed");
3584 * add-remove test. no change.
3586 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3587 fib_path_list_db_size());
3588 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3589 fib_path_list_pool_size());
3590 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3591 fib_entry_pool_size());
3595 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3597 fib_prefix_t pfx_34_1_1_1_s_32 = {
3599 .fp_proto = FIB_PROTOCOL_IP4,
3601 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3604 fib_prefix_t pfx_34_34_1_1_s_32 = {
3606 .fp_proto = FIB_PROTOCOL_IP4,
3608 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3611 fei = fib_table_entry_path_add(fib_index,
3614 FIB_ENTRY_FLAG_NONE,
3616 &pfx_34_34_1_1_s_32.fp_addr,
3621 FIB_ROUTE_PATH_FLAG_NONE);
3622 fei = fib_table_entry_path_add(fib_index,
3625 FIB_ENTRY_FLAG_NONE,
3627 &pfx_34_34_1_1_s_32.fp_addr,
3632 FIB_ROUTE_PATH_FLAG_NONE);
3633 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3634 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3638 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3639 * all of which are via 10.10.10.1, Itf1
3641 fib_table_entry_path_remove(fib_index,
3646 tm->hw[0]->sw_if_index,
3649 FIB_ROUTE_PATH_FLAG_NONE);
3650 fib_table_entry_path_remove(fib_index,
3655 tm->hw[0]->sw_if_index,
3658 FIB_ROUTE_PATH_FLAG_NONE);
3659 fib_table_entry_path_remove(fib_index,
3664 tm->hw[0]->sw_if_index,
3667 FIB_ROUTE_PATH_FLAG_NONE);
3669 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3670 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3671 "1.1.1.1/32 removed");
3672 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3673 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3674 "1.1.1.2/32 removed");
3675 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3676 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3677 "1.1.2.0/24 removed");
3680 * -3 entries and -1 shared path-list
3682 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3683 fib_path_list_db_size());
3684 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3685 fib_path_list_pool_size());
3686 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3687 fib_entry_pool_size());
3690 * An attached-host route. Expect to link to the incomplete adj
3692 fib_prefix_t pfx_4_1_1_1_s_32 = {
3694 .fp_proto = FIB_PROTOCOL_IP4,
3697 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3700 fib_table_entry_path_add(fib_index,
3703 FIB_ENTRY_FLAG_NONE,
3706 tm->hw[0]->sw_if_index,
3710 FIB_ROUTE_PATH_FLAG_NONE);
3712 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3713 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3714 ai = fib_entry_get_adj(fei);
3716 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3718 &pfx_4_1_1_1_s_32.fp_addr,
3719 tm->hw[0]->sw_if_index);
3720 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3724 * +1 entry and +1 shared path-list
3726 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3727 fib_path_list_db_size());
3728 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3729 fib_path_list_pool_size());
3730 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3731 fib_entry_pool_size());
3733 fib_table_entry_delete(fib_index,
3737 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3738 fib_path_list_db_size());
3739 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3740 fib_path_list_pool_size());
3741 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3742 fib_entry_pool_size());
3745 * add a v6 prefix via v4 next-hops
3747 fib_prefix_t pfx_2001_s_64 = {
3749 .fp_proto = FIB_PROTOCOL_IP6,
3751 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3754 fei = fib_table_entry_path_add(0, //default v6 table
3757 FIB_ENTRY_FLAG_NONE,
3760 tm->hw[0]->sw_if_index,
3764 FIB_ROUTE_PATH_FLAG_NONE);
3766 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3767 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3768 ai = fib_entry_get_adj(fei);
3770 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3771 "2001::/64 via ARP-adj");
3772 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3773 "2001::/64 is link type v6");
3774 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3775 "2001::/64 ADJ-adj is NH proto v4");
3776 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3779 * add a uRPF exempt prefix:
3781 * - it's forwarding is drop
3782 * - it's uRPF list is not empty
3783 * - the uRPF list for the default route (it's cover) is empty
3785 fei = fib_table_entry_special_add(fib_index,
3787 FIB_SOURCE_URPF_EXEMPT,
3788 FIB_ENTRY_FLAG_DROP);
3789 dpo = fib_entry_contribute_ip_forwarding(fei);
3790 FIB_TEST(load_balance_is_drop(dpo),
3791 "uRPF exempt 4.1.1.1/32 DROP");
3792 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3793 "uRPF list for exempt prefix has itf index 0");
3794 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3795 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3796 "uRPF list for 0.0.0.0/0 empty");
3798 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3801 * An adj-fib that fails the refinement criteria - no connected cover
3803 fib_prefix_t pfx_12_10_10_2_s_32 = {
3805 .fp_proto = FIB_PROTOCOL_IP4,
3808 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3812 fib_table_entry_path_add(fib_index,
3813 &pfx_12_10_10_2_s_32,
3815 FIB_ENTRY_FLAG_ATTACHED,
3817 &pfx_12_10_10_2_s_32.fp_addr,
3818 tm->hw[0]->sw_if_index,
3819 ~0, // invalid fib index
3822 FIB_ROUTE_PATH_FLAG_NONE);
3824 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3825 dpo = fib_entry_contribute_ip_forwarding(fei);
3826 FIB_TEST(!dpo_id_is_valid(dpo),
3827 "no connected cover adj-fib fails refinement");
3829 fib_table_entry_delete(fib_index,
3830 &pfx_12_10_10_2_s_32,
3834 * An adj-fib that fails the refinement criteria - cover is connected
3835 * but on a different interface
3837 fib_prefix_t pfx_10_10_10_127_s_32 = {
3839 .fp_proto = FIB_PROTOCOL_IP4,
3842 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3846 fib_table_entry_path_add(fib_index,
3847 &pfx_10_10_10_127_s_32,
3849 FIB_ENTRY_FLAG_ATTACHED,
3851 &pfx_10_10_10_127_s_32.fp_addr,
3852 tm->hw[1]->sw_if_index,
3853 ~0, // invalid fib index
3856 FIB_ROUTE_PATH_FLAG_NONE);
3858 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3859 dpo = fib_entry_contribute_ip_forwarding(fei);
3860 FIB_TEST(!dpo_id_is_valid(dpo),
3861 "wrong interface adj-fib fails refinement");
3863 fib_table_entry_delete(fib_index,
3864 &pfx_10_10_10_127_s_32,
3868 * add a second path to an adj-fib
3869 * this is a sumiluation of another ARP entry created
3870 * on an interface on which the connected prefi does not exist.
3871 * The second path fails refinement. Expect to forward through the
3874 fib_prefix_t pfx_10_10_10_3_s_32 = {
3876 .fp_proto = FIB_PROTOCOL_IP4,
3879 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
3883 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3886 tm->hw[0]->sw_if_index);
3888 fib_test_lb_bucket_t ip_o_10_10_10_3 = {
3894 fei = fib_table_entry_path_add(fib_index,
3895 &pfx_10_10_10_3_s_32,
3897 FIB_ENTRY_FLAG_NONE,
3900 tm->hw[0]->sw_if_index,
3904 FIB_ROUTE_PATH_FLAG_NONE);
3905 fei = fib_table_entry_path_add(fib_index,
3906 &pfx_10_10_10_3_s_32,
3908 FIB_ENTRY_FLAG_NONE,
3911 tm->hw[1]->sw_if_index,
3915 FIB_ROUTE_PATH_FLAG_NONE);
3916 FIB_TEST(fib_test_validate_entry(fei,
3917 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3920 "10.10.10.3 via 10.10.10.3/Eth0 only");
3923 * remove the path that refines the cover, should go unresolved
3925 fib_table_entry_path_remove(fib_index,
3926 &pfx_10_10_10_3_s_32,
3930 tm->hw[0]->sw_if_index,
3933 FIB_ROUTE_PATH_FLAG_NONE);
3934 dpo = fib_entry_contribute_ip_forwarding(fei);
3935 FIB_TEST(!dpo_id_is_valid(dpo),
3936 "wrong interface adj-fib fails refinement");
3939 * add back the path that refines the cover
3941 fei = fib_table_entry_path_add(fib_index,
3942 &pfx_10_10_10_3_s_32,
3944 FIB_ENTRY_FLAG_NONE,
3947 tm->hw[0]->sw_if_index,
3951 FIB_ROUTE_PATH_FLAG_NONE);
3952 FIB_TEST(fib_test_validate_entry(fei,
3953 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3956 "10.10.10.3 via 10.10.10.3/Eth0 only");
3959 * remove the path that does not refine the cover
3961 fib_table_entry_path_remove(fib_index,
3962 &pfx_10_10_10_3_s_32,
3966 tm->hw[1]->sw_if_index,
3969 FIB_ROUTE_PATH_FLAG_NONE);
3970 FIB_TEST(fib_test_validate_entry(fei,
3971 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3974 "10.10.10.3 via 10.10.10.3/Eth0 only");
3977 * remove the path that does refine, it's the last path, so
3978 * the entry should be gone
3980 fib_table_entry_path_remove(fib_index,
3981 &pfx_10_10_10_3_s_32,
3985 tm->hw[0]->sw_if_index,
3988 FIB_ROUTE_PATH_FLAG_NONE);
3989 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
3990 FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
3995 * change the table's flow-hash config - expect the update to propagete to
3996 * the entries' load-balance objects
3998 flow_hash_config_t old_hash_config, new_hash_config;
4000 old_hash_config = fib_table_get_flow_hash_config(fib_index,
4002 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4003 IP_FLOW_HASH_DST_ADDR);
4005 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4006 dpo = fib_entry_contribute_ip_forwarding(fei);
4007 lb = load_balance_get(dpo->dpoi_index);
4008 FIB_TEST((lb->lb_hash_config == old_hash_config),
4009 "Table and LB hash config match: %U",
4010 format_ip_flow_hash_config, lb->lb_hash_config);
4012 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4014 FIB_TEST((lb->lb_hash_config == new_hash_config),
4015 "Table and LB newhash config match: %U",
4016 format_ip_flow_hash_config, lb->lb_hash_config);
4022 fib_table_entry_delete(fib_index,
4023 &pfx_10_10_10_1_s_32,
4025 fib_table_entry_delete(fib_index,
4026 &pfx_10_10_10_2_s_32,
4028 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4029 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4030 "10.10.10.1/32 adj-fib removed");
4031 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4032 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4033 "10.10.10.2/32 adj-fib removed");
4036 * -2 entries and -2 non-shared path-list
4038 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4039 fib_path_list_db_size());
4040 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4041 fib_path_list_pool_size());
4042 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4043 fib_entry_pool_size());
4046 * unlock the adjacencies for which this test provided a rewrite.
4047 * These are the last locks on these adjs. they should thus go away.
4051 adj_unlock(ai_12_12_12_12);
4053 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4058 * remove the interface prefixes
4060 local_pfx.fp_len = 32;
4061 fib_table_entry_special_remove(fib_index, &local_pfx,
4062 FIB_SOURCE_INTERFACE);
4063 fei = fib_table_lookup(fib_index, &local_pfx);
4065 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4066 fib_table_lookup_exact_match(fib_index, &local_pfx),
4067 "10.10.10.10/32 adj-fib removed");
4069 local_pfx.fp_len = 24;
4070 fib_table_entry_delete(fib_index, &local_pfx,
4071 FIB_SOURCE_INTERFACE);
4073 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4074 fib_table_lookup_exact_match(fib_index, &local_pfx),
4075 "10.10.10.10/24 adj-fib removed");
4078 * -2 entries and -2 non-shared path-list
4080 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4081 fib_path_list_db_size());
4082 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4083 fib_path_list_pool_size());
4084 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4085 fib_entry_pool_size());
4088 * Last but not least, remove the VRF
4090 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4093 "NO API Source'd prefixes");
4094 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4097 "NO RR Source'd prefixes");
4098 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4100 FIB_SOURCE_INTERFACE)),
4101 "NO INterface Source'd prefixes");
4103 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4);
4105 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4106 fib_path_list_db_size());
4107 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4108 fib_path_list_pool_size());
4109 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4110 fib_entry_pool_size());
4111 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4112 pool_elts(fib_urpf_list_pool));
4113 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4114 pool_elts(load_balance_map_pool));
4115 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4116 pool_elts(load_balance_pool));
4125 * In the default table check for the presence and correct forwarding
4126 * of the special entries
4128 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4129 const dpo_id_t *dpo, *dpo_drop;
4130 const ip_adjacency_t *adj;
4131 const receive_dpo_t *rd;
4136 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4139 /* via 2001:0:0:1::2 */
4140 ip46_address_t nh_2001_2 = {
4143 [0] = clib_host_to_net_u64(0x2001000000000001),
4144 [1] = clib_host_to_net_u64(0x0000000000000002),
4151 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4153 /* Find or create FIB table 11 */
4154 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11);
4156 for (ii = 0; ii < 4; ii++)
4158 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4161 fib_prefix_t pfx_0_0 = {
4163 .fp_proto = FIB_PROTOCOL_IP6,
4171 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4172 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4173 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4174 "Default route is DROP");
4176 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4177 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4180 &pfx_0_0.fp_addr.ip6)),
4181 "default-route; fwd and non-fwd tables match");
4183 // FIXME - check specials.
4186 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4187 * each with 2 entries and a v6 mfib with 4 path-lists.
4188 * All entries are special so no path-list sharing.
4191 #define PNPS (5+4+4)
4192 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4193 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4194 fib_path_list_pool_size());
4195 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4196 fib_entry_pool_size());
4199 * add interface routes.
4200 * validate presence of /64 attached and /128 recieve.
4201 * test for the presence of the receive address in the glean and local adj
4203 * receive on 2001:0:0:1::1/128
4205 fib_prefix_t local_pfx = {
4207 .fp_proto = FIB_PROTOCOL_IP6,
4211 [0] = clib_host_to_net_u64(0x2001000000000001),
4212 [1] = clib_host_to_net_u64(0x0000000000000001),
4218 fib_table_entry_update_one_path(fib_index, &local_pfx,
4219 FIB_SOURCE_INTERFACE,
4220 (FIB_ENTRY_FLAG_CONNECTED |
4221 FIB_ENTRY_FLAG_ATTACHED),
4224 tm->hw[0]->sw_if_index,
4228 FIB_ROUTE_PATH_FLAG_NONE);
4229 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4231 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4233 ai = fib_entry_get_adj(fei);
4234 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4236 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4237 "attached interface adj is glean");
4238 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4239 &adj->sub_type.glean.receive_addr)),
4240 "attached interface adj is receive ok");
4241 dpo = fib_entry_contribute_ip_forwarding(fei);
4242 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4245 &local_pfx.fp_addr.ip6)),
4246 "attached-route; fwd and non-fwd tables match");
4248 local_pfx.fp_len = 128;
4249 fib_table_entry_update_one_path(fib_index, &local_pfx,
4250 FIB_SOURCE_INTERFACE,
4251 (FIB_ENTRY_FLAG_CONNECTED |
4252 FIB_ENTRY_FLAG_LOCAL),
4255 tm->hw[0]->sw_if_index,
4256 ~0, // invalid fib index
4259 FIB_ROUTE_PATH_FLAG_NONE);
4260 fei = fib_table_lookup(fib_index, &local_pfx);
4262 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4264 dpo = fib_entry_contribute_ip_forwarding(fei);
4265 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4266 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4267 "local interface adj is local");
4268 rd = receive_dpo_get(dpo->dpoi_index);
4270 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4272 "local interface adj is receive ok");
4274 dpo = fib_entry_contribute_ip_forwarding(fei);
4275 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4278 &local_pfx.fp_addr.ip6)),
4279 "local-route; fwd and non-fwd tables match");
4282 * +2 entries. +2 unshared path-lists
4284 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4285 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4286 fib_path_list_pool_size());
4287 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4288 fib_entry_pool_size());
4291 * Modify the default route to be via an adj not yet known.
4292 * this sources the defalut route with the API source, which is
4293 * a higher preference to the DEFAULT_ROUTE source
4295 fib_table_entry_path_add(fib_index, &pfx_0_0,
4297 FIB_ENTRY_FLAG_NONE,
4300 tm->hw[0]->sw_if_index,
4304 FIB_ROUTE_PATH_FLAG_NONE);
4305 fei = fib_table_lookup(fib_index, &pfx_0_0);
4307 FIB_TEST((fei == dfrt), "default route same index");
4308 ai = fib_entry_get_adj(fei);
4309 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4311 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4312 "adj is incomplete");
4313 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4314 "adj nbr next-hop ok");
4317 * find the adj in the shared db
4319 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4322 tm->hw[0]->sw_if_index);
4323 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4324 adj_unlock(locked_ai);
4327 * no more entires. +1 shared path-list
4329 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4330 fib_path_list_db_size());
4331 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4332 fib_path_list_pool_size());
4333 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4334 fib_entry_pool_size());
4337 * remove the API source from the default route. We expected
4338 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4340 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4344 tm->hw[0]->sw_if_index,
4347 FIB_ROUTE_PATH_FLAG_NONE);
4348 fei = fib_table_lookup(fib_index, &pfx_0_0);
4350 FIB_TEST((fei == dfrt), "default route same index");
4351 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4352 "Default route is DROP");
4355 * no more entires. -1 shared path-list
4357 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4358 fib_path_list_db_size());
4359 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4360 fib_path_list_pool_size());
4361 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4362 fib_entry_pool_size());
4365 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4367 fib_prefix_t pfx_2001_1_2_s_128 = {
4369 .fp_proto = FIB_PROTOCOL_IP6,
4373 [0] = clib_host_to_net_u64(0x2001000000000001),
4374 [1] = clib_host_to_net_u64(0x0000000000000002),
4379 fib_prefix_t pfx_2001_1_3_s_128 = {
4381 .fp_proto = FIB_PROTOCOL_IP6,
4385 [0] = clib_host_to_net_u64(0x2001000000000001),
4386 [1] = clib_host_to_net_u64(0x0000000000000003),
4392 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4395 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4397 &pfx_2001_1_2_s_128.fp_addr,
4398 tm->hw[0]->sw_if_index);
4399 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4400 adj = adj_get(ai_01);
4401 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4402 "adj is incomplete");
4403 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4404 &adj->sub_type.nbr.next_hop)),
4405 "adj nbr next-hop ok");
4407 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4408 fib_test_build_rewrite(eth_addr));
4409 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4411 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4412 &adj->sub_type.nbr.next_hop)),
4413 "adj nbr next-hop ok");
4415 fib_table_entry_path_add(fib_index,
4416 &pfx_2001_1_2_s_128,
4418 FIB_ENTRY_FLAG_ATTACHED,
4420 &pfx_2001_1_2_s_128.fp_addr,
4421 tm->hw[0]->sw_if_index,
4425 FIB_ROUTE_PATH_FLAG_NONE);
4427 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4428 ai = fib_entry_get_adj(fei);
4429 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4433 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4435 &pfx_2001_1_3_s_128.fp_addr,
4436 tm->hw[0]->sw_if_index);
4437 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4438 adj = adj_get(ai_02);
4439 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4440 "adj is incomplete");
4441 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4442 &adj->sub_type.nbr.next_hop)),
4443 "adj nbr next-hop ok");
4445 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4446 fib_test_build_rewrite(eth_addr));
4447 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4449 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4450 &adj->sub_type.nbr.next_hop)),
4451 "adj nbr next-hop ok");
4452 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4454 fib_table_entry_path_add(fib_index,
4455 &pfx_2001_1_3_s_128,
4457 FIB_ENTRY_FLAG_ATTACHED,
4459 &pfx_2001_1_3_s_128.fp_addr,
4460 tm->hw[0]->sw_if_index,
4464 FIB_ROUTE_PATH_FLAG_NONE);
4466 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4467 ai = fib_entry_get_adj(fei);
4468 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4471 * +2 entries, +2 unshread path-lists.
4473 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4474 fib_path_list_db_size());
4475 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4476 fib_path_list_pool_size());
4477 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4478 fib_entry_pool_size());
4481 * Add a 2 routes via the first ADJ. ensure path-list sharing
4483 fib_prefix_t pfx_2001_a_s_64 = {
4485 .fp_proto = FIB_PROTOCOL_IP6,
4489 [0] = clib_host_to_net_u64(0x200100000000000a),
4490 [1] = clib_host_to_net_u64(0x0000000000000000),
4495 fib_prefix_t pfx_2001_b_s_64 = {
4497 .fp_proto = FIB_PROTOCOL_IP6,
4501 [0] = clib_host_to_net_u64(0x200100000000000b),
4502 [1] = clib_host_to_net_u64(0x0000000000000000),
4508 fib_table_entry_path_add(fib_index,
4511 FIB_ENTRY_FLAG_NONE,
4514 tm->hw[0]->sw_if_index,
4518 FIB_ROUTE_PATH_FLAG_NONE);
4519 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4520 ai = fib_entry_get_adj(fei);
4521 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4522 fib_table_entry_path_add(fib_index,
4525 FIB_ENTRY_FLAG_NONE,
4528 tm->hw[0]->sw_if_index,
4532 FIB_ROUTE_PATH_FLAG_NONE);
4533 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4534 ai = fib_entry_get_adj(fei);
4535 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4538 * +2 entries, +1 shared path-list.
4540 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4541 fib_path_list_db_size());
4542 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4543 fib_path_list_pool_size());
4544 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4545 fib_entry_pool_size());
4548 * add a v4 prefix via a v6 next-hop
4550 fib_prefix_t pfx_1_1_1_1_s_32 = {
4552 .fp_proto = FIB_PROTOCOL_IP4,
4554 .ip4.as_u32 = 0x01010101,
4557 fei = fib_table_entry_path_add(0, // default table
4560 FIB_ENTRY_FLAG_NONE,
4563 tm->hw[0]->sw_if_index,
4567 FIB_ROUTE_PATH_FLAG_NONE);
4568 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4569 "1.1.1.1/32 o v6 route present");
4570 ai = fib_entry_get_adj(fei);
4572 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4573 "1.1.1.1/32 via ARP-adj");
4574 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4575 "1.1.1.1/32 ADJ-adj is link type v4");
4576 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4577 "1.1.1.1/32 ADJ-adj is NH proto v6");
4578 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4583 fib_prefix_t pfx_2001_c_s_64 = {
4585 .fp_proto = FIB_PROTOCOL_IP6,
4589 [0] = clib_host_to_net_u64(0x200100000000000c),
4590 [1] = clib_host_to_net_u64(0x0000000000000000),
4595 fib_table_entry_path_add(fib_index,
4598 FIB_ENTRY_FLAG_ATTACHED,
4601 tm->hw[0]->sw_if_index,
4605 FIB_ROUTE_PATH_FLAG_NONE);
4606 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4607 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4608 ai = fib_entry_get_adj(fei);
4610 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4611 "2001:0:0:c/64 attached resolves via glean");
4613 fib_table_entry_path_remove(fib_index,
4618 tm->hw[0]->sw_if_index,
4621 FIB_ROUTE_PATH_FLAG_NONE);
4622 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4623 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4626 * Shutdown the interface on which we have a connected and through
4627 * which the routes are reachable.
4628 * This will result in the connected, adj-fibs, and routes linking to drop
4629 * The local/for-us prefix continues to receive.
4631 clib_error_t * error;
4633 error = vnet_sw_interface_set_flags(vnet_get_main(),
4634 tm->hw[0]->sw_if_index,
4635 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4636 FIB_TEST((NULL == error), "Interface shutdown OK");
4638 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
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::b/64 resolves via drop");
4643 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
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::a/64 resolves via drop");
4647 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4648 dpo = fib_entry_contribute_ip_forwarding(fei);
4649 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4650 "2001:0:0:1::3/64 resolves via drop");
4651 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4652 dpo = fib_entry_contribute_ip_forwarding(fei);
4653 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4654 "2001:0:0:1::2/64 resolves via drop");
4655 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4656 dpo = fib_entry_contribute_ip_forwarding(fei);
4657 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4658 "2001:0:0:1::1/128 not drop");
4659 local_pfx.fp_len = 64;
4660 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4661 dpo = fib_entry_contribute_ip_forwarding(fei);
4662 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4663 "2001:0:0:1/64 resolves via drop");
4668 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4669 fib_path_list_db_size());
4670 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4671 fib_path_list_pool_size());
4672 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4673 fib_entry_pool_size());
4676 * shutdown one of the other interfaces, then add a connected.
4677 * and swap one of the routes to it.
4679 error = vnet_sw_interface_set_flags(vnet_get_main(),
4680 tm->hw[1]->sw_if_index,
4681 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4682 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4684 fib_prefix_t connected_pfx = {
4686 .fp_proto = FIB_PROTOCOL_IP6,
4689 /* 2001:0:0:2::1/64 */
4691 [0] = clib_host_to_net_u64(0x2001000000000002),
4692 [1] = clib_host_to_net_u64(0x0000000000000001),
4697 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4698 FIB_SOURCE_INTERFACE,
4699 (FIB_ENTRY_FLAG_CONNECTED |
4700 FIB_ENTRY_FLAG_ATTACHED),
4703 tm->hw[1]->sw_if_index,
4707 FIB_ROUTE_PATH_FLAG_NONE);
4708 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4709 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4710 dpo = fib_entry_contribute_ip_forwarding(fei);
4711 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4712 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4713 "2001:0:0:2/64 not resolves via drop");
4715 connected_pfx.fp_len = 128;
4716 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4717 FIB_SOURCE_INTERFACE,
4718 (FIB_ENTRY_FLAG_CONNECTED |
4719 FIB_ENTRY_FLAG_LOCAL),
4722 tm->hw[0]->sw_if_index,
4723 ~0, // invalid fib index
4726 FIB_ROUTE_PATH_FLAG_NONE);
4727 fei = fib_table_lookup(fib_index, &connected_pfx);
4729 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4730 dpo = fib_entry_contribute_ip_forwarding(fei);
4731 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4732 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4733 "local interface adj is local");
4734 rd = receive_dpo_get(dpo->dpoi_index);
4735 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4737 "local interface adj is receive ok");
4740 * +2 entries, +2 unshared path-lists
4742 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4743 fib_path_list_db_size());
4744 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4745 fib_path_list_pool_size());
4746 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4747 fib_entry_pool_size());
4751 * bring the interface back up. we expected the routes to return
4752 * to normal forwarding.
4754 error = vnet_sw_interface_set_flags(vnet_get_main(),
4755 tm->hw[0]->sw_if_index,
4756 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4757 FIB_TEST((NULL == error), "Interface bring-up OK");
4758 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4759 ai = fib_entry_get_adj(fei);
4760 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4761 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4762 ai = fib_entry_get_adj(fei);
4763 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4764 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4765 ai = fib_entry_get_adj(fei);
4766 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4767 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4768 ai = fib_entry_get_adj(fei);
4769 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4770 local_pfx.fp_len = 64;
4771 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4772 ai = fib_entry_get_adj(fei);
4774 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4775 "attached interface adj is glean");
4778 * Same test as above, but this time the HW interface goes down
4780 error = vnet_hw_interface_set_flags(vnet_get_main(),
4781 tm->hw_if_indicies[0],
4782 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4783 FIB_TEST((NULL == error), "Interface shutdown OK");
4785 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4786 dpo = fib_entry_contribute_ip_forwarding(fei);
4787 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4788 "2001::b/64 resolves via drop");
4789 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4790 dpo = fib_entry_contribute_ip_forwarding(fei);
4791 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4792 "2001::a/64 resolves via drop");
4793 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4794 dpo = fib_entry_contribute_ip_forwarding(fei);
4795 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4796 "2001:0:0:1::3/128 resolves via drop");
4797 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4798 dpo = fib_entry_contribute_ip_forwarding(fei);
4799 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4800 "2001:0:0:1::2/128 resolves via drop");
4801 local_pfx.fp_len = 128;
4802 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4803 dpo = fib_entry_contribute_ip_forwarding(fei);
4804 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4805 "2001:0:0:1::1/128 not drop");
4806 local_pfx.fp_len = 64;
4807 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4808 dpo = fib_entry_contribute_ip_forwarding(fei);
4809 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4810 "2001:0:0:1/64 resolves via drop");
4812 error = vnet_hw_interface_set_flags(vnet_get_main(),
4813 tm->hw_if_indicies[0],
4814 VNET_HW_INTERFACE_FLAG_LINK_UP);
4815 FIB_TEST((NULL == error), "Interface bring-up OK");
4816 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4817 ai = fib_entry_get_adj(fei);
4818 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4819 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4820 ai = fib_entry_get_adj(fei);
4821 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4822 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4823 ai = fib_entry_get_adj(fei);
4824 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4825 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4826 ai = fib_entry_get_adj(fei);
4827 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4828 local_pfx.fp_len = 64;
4829 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4830 ai = fib_entry_get_adj(fei);
4832 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4833 "attached interface adj is glean");
4836 * Delete the interface that the routes reolve through.
4837 * Again no routes are removed. They all point to drop.
4839 * This is considered an error case. The control plane should
4840 * not remove interfaces through which routes resolve, but
4841 * such things can happen. ALL affected routes will drop.
4843 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4845 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4846 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4847 "2001::b/64 resolves via drop");
4848 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4849 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4850 "2001::b/64 resolves via drop");
4851 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4852 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4853 "2001:0:0:1::3/64 resolves via drop");
4854 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4855 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4856 "2001:0:0:1::2/64 resolves via drop");
4857 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4858 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4859 "2001:0:0:1::1/128 is drop");
4860 local_pfx.fp_len = 64;
4861 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4862 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4863 "2001:0:0:1/64 resolves via drop");
4868 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4869 fib_path_list_db_size());
4870 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4871 fib_path_list_pool_size());
4872 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4873 fib_entry_pool_size());
4876 * Add the interface back. routes stay unresolved.
4878 error = ethernet_register_interface(vnet_get_main(),
4879 test_interface_device_class.index,
4882 &tm->hw_if_indicies[0],
4883 /* flag change */ 0);
4885 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4886 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4887 "2001::b/64 resolves via drop");
4888 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4889 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4890 "2001::b/64 resolves via drop");
4891 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4892 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4893 "2001:0:0:1::3/64 resolves via drop");
4894 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4895 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4896 "2001:0:0:1::2/64 resolves via drop");
4897 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4898 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4899 "2001:0:0:1::1/128 is drop");
4900 local_pfx.fp_len = 64;
4901 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4902 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4903 "2001:0:0:1/64 resolves via drop");
4906 * CLEANUP ALL the routes
4908 fib_table_entry_delete(fib_index,
4911 fib_table_entry_delete(fib_index,
4914 fib_table_entry_delete(fib_index,
4917 fib_table_entry_delete(fib_index,
4918 &pfx_2001_1_3_s_128,
4920 fib_table_entry_delete(fib_index,
4921 &pfx_2001_1_2_s_128,
4923 local_pfx.fp_len = 64;
4924 fib_table_entry_delete(fib_index, &local_pfx,
4925 FIB_SOURCE_INTERFACE);
4926 local_pfx.fp_len = 128;
4927 fib_table_entry_special_remove(fib_index, &local_pfx,
4928 FIB_SOURCE_INTERFACE);
4929 connected_pfx.fp_len = 64;
4930 fib_table_entry_delete(fib_index, &connected_pfx,
4931 FIB_SOURCE_INTERFACE);
4932 connected_pfx.fp_len = 128;
4933 fib_table_entry_special_remove(fib_index, &connected_pfx,
4934 FIB_SOURCE_INTERFACE);
4936 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4937 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
4938 "2001::a/64 removed");
4939 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4940 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
4941 "2001::b/64 removed");
4942 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4943 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
4944 "2001:0:0:1::3/128 removed");
4945 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4946 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
4947 "2001:0:0:1::3/128 removed");
4948 local_pfx.fp_len = 64;
4949 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4950 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4951 "2001:0:0:1/64 removed");
4952 local_pfx.fp_len = 128;
4953 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4954 fib_table_lookup_exact_match(fib_index, &local_pfx)),
4955 "2001:0:0:1::1/128 removed");
4956 connected_pfx.fp_len = 64;
4957 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4958 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4959 "2001:0:0:2/64 removed");
4960 connected_pfx.fp_len = 128;
4961 FIB_TEST((FIB_NODE_INDEX_INVALID ==
4962 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
4963 "2001:0:0:2::1/128 removed");
4966 * -8 entries. -7 path-lists (1 was shared).
4968 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4969 fib_path_list_db_size());
4970 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
4971 fib_path_list_pool_size());
4972 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4973 fib_entry_pool_size());
4976 * now remove the VRF
4978 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6);
4980 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4981 fib_path_list_db_size());
4982 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
4983 fib_path_list_pool_size());
4984 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
4985 fib_entry_pool_size());
4991 * return the interfaces to up state
4993 error = vnet_sw_interface_set_flags(vnet_get_main(),
4994 tm->hw[0]->sw_if_index,
4995 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4996 error = vnet_sw_interface_set_flags(vnet_get_main(),
4997 tm->hw[1]->sw_if_index,
4998 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5000 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5007 * Test Attached Exports
5012 const dpo_id_t *dpo, *dpo_drop;
5013 const u32 fib_index = 0;
5014 fib_node_index_t fei;
5021 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5025 * add interface routes. We'll assume this works. It's more rigorously
5028 fib_prefix_t local_pfx = {
5030 .fp_proto = FIB_PROTOCOL_IP4,
5034 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5039 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5040 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5042 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5044 fib_table_entry_update_one_path(fib_index, &local_pfx,
5045 FIB_SOURCE_INTERFACE,
5046 (FIB_ENTRY_FLAG_CONNECTED |
5047 FIB_ENTRY_FLAG_ATTACHED),
5050 tm->hw[0]->sw_if_index,
5054 FIB_ROUTE_PATH_FLAG_NONE);
5055 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5056 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5057 "attached interface route present");
5059 local_pfx.fp_len = 32;
5060 fib_table_entry_update_one_path(fib_index, &local_pfx,
5061 FIB_SOURCE_INTERFACE,
5062 (FIB_ENTRY_FLAG_CONNECTED |
5063 FIB_ENTRY_FLAG_LOCAL),
5066 tm->hw[0]->sw_if_index,
5067 ~0, // invalid fib index
5070 FIB_ROUTE_PATH_FLAG_NONE);
5071 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5073 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5074 "local interface route present");
5077 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5079 fib_prefix_t pfx_10_10_10_1_s_32 = {
5081 .fp_proto = FIB_PROTOCOL_IP4,
5084 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5087 fib_node_index_t ai;
5089 fib_table_entry_path_add(fib_index,
5090 &pfx_10_10_10_1_s_32,
5092 FIB_ENTRY_FLAG_ATTACHED,
5094 &pfx_10_10_10_1_s_32.fp_addr,
5095 tm->hw[0]->sw_if_index,
5096 ~0, // invalid fib index
5099 FIB_ROUTE_PATH_FLAG_NONE);
5101 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5102 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5103 ai = fib_entry_get_adj(fei);
5106 * create another FIB table into which routes will be imported
5108 u32 import_fib_index1;
5110 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11);
5113 * Add an attached route in the import FIB
5115 local_pfx.fp_len = 24;
5116 fib_table_entry_update_one_path(import_fib_index1,
5119 FIB_ENTRY_FLAG_NONE,
5122 tm->hw[0]->sw_if_index,
5123 ~0, // invalid fib index
5126 FIB_ROUTE_PATH_FLAG_NONE);
5127 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5128 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5131 * check for the presence of the adj-fibs in the import table
5133 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5134 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5135 FIB_TEST((ai == fib_entry_get_adj(fei)),
5136 "adj-fib1 Import uses same adj as export");
5139 * check for the presence of the local in the import table
5141 local_pfx.fp_len = 32;
5142 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5143 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5146 * Add another adj-fin in the export table. Expect this
5147 * to get magically exported;
5149 fib_prefix_t pfx_10_10_10_2_s_32 = {
5151 .fp_proto = FIB_PROTOCOL_IP4,
5154 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5158 fib_table_entry_path_add(fib_index,
5159 &pfx_10_10_10_2_s_32,
5161 FIB_ENTRY_FLAG_ATTACHED,
5163 &pfx_10_10_10_2_s_32.fp_addr,
5164 tm->hw[0]->sw_if_index,
5165 ~0, // invalid fib index
5168 FIB_ROUTE_PATH_FLAG_NONE);
5169 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5170 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5171 ai = fib_entry_get_adj(fei);
5173 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5174 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5175 FIB_TEST((ai == fib_entry_get_adj(fei)),
5176 "Import uses same adj as export");
5177 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5178 "ADJ-fib2 imported flags %d",
5179 fib_entry_get_flags(fei));
5182 * create a 2nd FIB table into which routes will be imported
5184 u32 import_fib_index2;
5186 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12);
5189 * Add an attached route in the import FIB
5191 local_pfx.fp_len = 24;
5192 fib_table_entry_update_one_path(import_fib_index2,
5195 FIB_ENTRY_FLAG_NONE,
5198 tm->hw[0]->sw_if_index,
5199 ~0, // invalid fib index
5202 FIB_ROUTE_PATH_FLAG_NONE);
5203 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5204 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5207 * check for the presence of all the adj-fibs and local in the import table
5209 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5210 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5211 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5212 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5213 local_pfx.fp_len = 32;
5214 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5215 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5218 * add a 3rd adj-fib. expect it to be exported to both tables.
5220 fib_prefix_t pfx_10_10_10_3_s_32 = {
5222 .fp_proto = FIB_PROTOCOL_IP4,
5225 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5229 fib_table_entry_path_add(fib_index,
5230 &pfx_10_10_10_3_s_32,
5232 FIB_ENTRY_FLAG_ATTACHED,
5234 &pfx_10_10_10_3_s_32.fp_addr,
5235 tm->hw[0]->sw_if_index,
5236 ~0, // invalid fib index
5239 FIB_ROUTE_PATH_FLAG_NONE);
5240 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5241 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5242 ai = fib_entry_get_adj(fei);
5244 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5245 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5246 FIB_TEST((ai == fib_entry_get_adj(fei)),
5247 "Import uses same adj as export");
5248 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5249 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5250 FIB_TEST((ai == fib_entry_get_adj(fei)),
5251 "Import uses same adj as export");
5254 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5256 fib_table_entry_delete(fib_index,
5257 &pfx_10_10_10_3_s_32,
5260 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5261 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5263 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5264 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5266 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5267 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5270 * remove the attached route from the 2nd FIB. expect the imported
5271 * entires to be removed
5273 local_pfx.fp_len = 24;
5274 fib_table_entry_delete(import_fib_index2,
5277 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5278 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5280 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5281 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5282 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5283 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5284 local_pfx.fp_len = 32;
5285 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5286 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5288 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5289 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5290 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5291 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5292 local_pfx.fp_len = 32;
5293 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5294 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5297 * modify the route in FIB1 so it is no longer attached. expect the imported
5298 * entires to be removed
5300 local_pfx.fp_len = 24;
5301 fib_table_entry_update_one_path(import_fib_index1,
5304 FIB_ENTRY_FLAG_NONE,
5306 &pfx_10_10_10_2_s_32.fp_addr,
5307 tm->hw[0]->sw_if_index,
5308 ~0, // invalid fib index
5311 FIB_ROUTE_PATH_FLAG_NONE);
5312 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5313 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5314 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5315 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5316 local_pfx.fp_len = 32;
5317 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5318 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5321 * modify it back to attached. expect the adj-fibs back
5323 local_pfx.fp_len = 24;
5324 fib_table_entry_update_one_path(import_fib_index1,
5327 FIB_ENTRY_FLAG_NONE,
5330 tm->hw[0]->sw_if_index,
5331 ~0, // invalid fib index
5334 FIB_ROUTE_PATH_FLAG_NONE);
5335 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5336 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5337 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5338 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5339 local_pfx.fp_len = 32;
5340 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5341 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5344 * add a covering attached next-hop for the interface address, so we have
5345 * a valid adj to find when we check the forwarding tables
5347 fib_prefix_t pfx_10_0_0_0_s_8 = {
5349 .fp_proto = FIB_PROTOCOL_IP4,
5352 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5356 fei = fib_table_entry_update_one_path(fib_index,
5359 FIB_ENTRY_FLAG_NONE,
5361 &pfx_10_10_10_3_s_32.fp_addr,
5362 tm->hw[0]->sw_if_index,
5363 ~0, // invalid fib index
5366 FIB_ROUTE_PATH_FLAG_NONE);
5367 dpo = fib_entry_contribute_ip_forwarding(fei);
5370 * remove the route in the export fib. expect the adj-fibs to be removed
5372 local_pfx.fp_len = 24;
5373 fib_table_entry_delete(fib_index,
5375 FIB_SOURCE_INTERFACE);
5377 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5378 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5379 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5380 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5381 local_pfx.fp_len = 32;
5382 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5383 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5386 * the adj-fibs in the export VRF are present in the FIB table,
5387 * but not installed in forwarding, since they have no attached cover.
5388 * Consequently a lookup in the MTRIE gives the adj for the covering
5391 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5392 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5395 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5396 FIB_TEST(lbi == dpo->dpoi_index,
5397 "10.10.10.1 forwards on \n%U not \n%U",
5398 format_load_balance, lbi, 0,
5399 format_dpo_id, dpo, 0);
5400 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5401 FIB_TEST(lbi == dpo->dpoi_index,
5402 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5403 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5404 FIB_TEST(lbi == dpo->dpoi_index,
5405 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5408 * add the export prefix back, but not as attached.
5409 * No adj-fibs in export nor import tables
5411 local_pfx.fp_len = 24;
5412 fei = fib_table_entry_update_one_path(fib_index,
5415 FIB_ENTRY_FLAG_NONE,
5417 &pfx_10_10_10_1_s_32.fp_addr,
5418 tm->hw[0]->sw_if_index,
5419 ~0, // invalid fib index
5422 FIB_ROUTE_PATH_FLAG_NONE);
5423 dpo = fib_entry_contribute_ip_forwarding(fei);
5425 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5426 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5427 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5428 FIB_TEST(lbi == dpo->dpoi_index,
5429 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5430 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5431 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5432 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5433 FIB_TEST(lbi == dpo->dpoi_index,
5434 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5436 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5437 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5438 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5439 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5440 local_pfx.fp_len = 32;
5441 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5442 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5445 * modify the export prefix so it is attached. expect all covereds to return
5447 local_pfx.fp_len = 24;
5448 fib_table_entry_update_one_path(fib_index,
5451 FIB_ENTRY_FLAG_NONE,
5454 tm->hw[0]->sw_if_index,
5455 ~0, // invalid fib index
5458 FIB_ROUTE_PATH_FLAG_NONE);
5460 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5461 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5462 dpo = fib_entry_contribute_ip_forwarding(fei);
5463 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5464 "Adj-fib1 is not drop in export");
5465 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5466 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5467 local_pfx.fp_len = 32;
5468 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5469 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5470 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5471 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5472 dpo = fib_entry_contribute_ip_forwarding(fei);
5473 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5474 "Adj-fib1 is not drop in export");
5475 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5476 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5477 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5478 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5479 local_pfx.fp_len = 32;
5480 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5481 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5484 * modify the export prefix so connected. no change.
5486 local_pfx.fp_len = 24;
5487 fib_table_entry_update_one_path(fib_index, &local_pfx,
5488 FIB_SOURCE_INTERFACE,
5489 (FIB_ENTRY_FLAG_CONNECTED |
5490 FIB_ENTRY_FLAG_ATTACHED),
5493 tm->hw[0]->sw_if_index,
5497 FIB_ROUTE_PATH_FLAG_NONE);
5499 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5500 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5501 dpo = fib_entry_contribute_ip_forwarding(fei);
5502 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5503 "Adj-fib1 is not drop in export");
5504 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5505 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5506 local_pfx.fp_len = 32;
5507 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5508 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5509 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5510 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5511 dpo = fib_entry_contribute_ip_forwarding(fei);
5512 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5513 "Adj-fib1 is not drop in export");
5514 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5515 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5516 local_pfx.fp_len = 32;
5517 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5518 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5523 fib_table_entry_delete(fib_index,
5526 fib_table_entry_delete(fib_index,
5527 &pfx_10_10_10_1_s_32,
5529 fib_table_entry_delete(fib_index,
5530 &pfx_10_10_10_2_s_32,
5532 local_pfx.fp_len = 32;
5533 fib_table_entry_delete(fib_index,
5535 FIB_SOURCE_INTERFACE);
5536 local_pfx.fp_len = 24;
5537 fib_table_entry_delete(fib_index,
5540 fib_table_entry_delete(fib_index,
5542 FIB_SOURCE_INTERFACE);
5543 local_pfx.fp_len = 24;
5544 fib_table_entry_delete(import_fib_index1,
5548 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4);
5549 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4);
5551 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5559 * Test the recursive route route handling for GRE tunnels
5562 fib_test_label (void)
5564 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;
5565 const u32 fib_index = 0;
5570 lb_count = pool_elts(load_balance_pool);
5575 * add interface routes. We'll assume this works. It's more rigorously
5578 fib_prefix_t local0_pfx = {
5580 .fp_proto = FIB_PROTOCOL_IP4,
5584 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5589 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5592 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5593 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5595 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5596 FIB_SOURCE_INTERFACE,
5597 (FIB_ENTRY_FLAG_CONNECTED |
5598 FIB_ENTRY_FLAG_ATTACHED),
5601 tm->hw[0]->sw_if_index,
5605 FIB_ROUTE_PATH_FLAG_NONE);
5606 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5607 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5608 "attached interface route present");
5610 local0_pfx.fp_len = 32;
5611 fib_table_entry_update_one_path(fib_index, &local0_pfx,
5612 FIB_SOURCE_INTERFACE,
5613 (FIB_ENTRY_FLAG_CONNECTED |
5614 FIB_ENTRY_FLAG_LOCAL),
5617 tm->hw[0]->sw_if_index,
5618 ~0, // invalid fib index
5621 FIB_ROUTE_PATH_FLAG_NONE);
5622 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
5624 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5625 "local interface route present");
5627 fib_prefix_t local1_pfx = {
5629 .fp_proto = FIB_PROTOCOL_IP4,
5633 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
5638 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
5639 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
5641 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5642 FIB_SOURCE_INTERFACE,
5643 (FIB_ENTRY_FLAG_CONNECTED |
5644 FIB_ENTRY_FLAG_ATTACHED),
5647 tm->hw[1]->sw_if_index,
5651 FIB_ROUTE_PATH_FLAG_NONE);
5652 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5653 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5654 "attached interface route present");
5656 local1_pfx.fp_len = 32;
5657 fib_table_entry_update_one_path(fib_index, &local1_pfx,
5658 FIB_SOURCE_INTERFACE,
5659 (FIB_ENTRY_FLAG_CONNECTED |
5660 FIB_ENTRY_FLAG_LOCAL),
5663 tm->hw[1]->sw_if_index,
5664 ~0, // invalid fib index
5667 FIB_ROUTE_PATH_FLAG_NONE);
5668 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
5670 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5671 "local interface route present");
5673 ip46_address_t nh_10_10_10_1 = {
5675 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5678 ip46_address_t nh_10_10_11_1 = {
5680 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5683 ip46_address_t nh_10_10_11_2 = {
5685 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5689 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5692 tm->hw[1]->sw_if_index);
5693 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5696 tm->hw[1]->sw_if_index);
5697 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5700 tm->hw[0]->sw_if_index);
5701 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5704 tm->hw[1]->sw_if_index);
5705 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5708 tm->hw[1]->sw_if_index);
5711 * Add an etry with one path with a real out-going label
5713 fib_prefix_t pfx_1_1_1_1_s_32 = {
5715 .fp_proto = FIB_PROTOCOL_IP4,
5717 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
5720 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
5721 .type = FT_LB_LABEL_O_ADJ,
5723 .adj = ai_mpls_10_10_10_1,
5728 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
5729 .type = FT_LB_LABEL_O_ADJ,
5731 .adj = ai_mpls_10_10_10_1,
5733 .eos = MPLS_NON_EOS,
5736 mpls_label_t *l99 = NULL;
5739 fib_table_entry_update_one_path(fib_index,
5742 FIB_ENTRY_FLAG_NONE,
5745 tm->hw[0]->sw_if_index,
5746 ~0, // invalid fib index
5749 FIB_ROUTE_PATH_FLAG_NONE);
5751 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5752 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
5754 FIB_TEST(fib_test_validate_entry(fei,
5755 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5757 &l99_eos_o_10_10_10_1),
5758 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
5761 * add a path with an implicit NULL label
5763 fib_test_lb_bucket_t a_o_10_10_11_1 = {
5766 .adj = ai_v4_10_10_11_1,
5769 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
5772 .adj = ai_mpls_10_10_11_1,
5775 mpls_label_t *l_imp_null = NULL;
5776 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
5778 fei = fib_table_entry_path_add(fib_index,
5781 FIB_ENTRY_FLAG_NONE,
5784 tm->hw[1]->sw_if_index,
5785 ~0, // invalid fib index
5788 FIB_ROUTE_PATH_FLAG_NONE);
5790 FIB_TEST(fib_test_validate_entry(fei,
5791 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5793 &l99_eos_o_10_10_10_1,
5795 "1.1.1.1/32 LB 2 buckets via: "
5796 "label 99 over 10.10.10.1, "
5797 "adj over 10.10.11.1");
5800 * assign the route a local label
5802 fib_table_entry_local_label_add(fib_index,
5806 fib_prefix_t pfx_24001_eos = {
5807 .fp_proto = FIB_PROTOCOL_MPLS,
5811 fib_prefix_t pfx_24001_neos = {
5812 .fp_proto = FIB_PROTOCOL_MPLS,
5814 .fp_eos = MPLS_NON_EOS,
5818 * The EOS entry should link to both the paths,
5819 * and use an ip adj for the imp-null
5820 * The NON-EOS entry should link to both the paths,
5821 * and use an mpls adj for the imp-null
5823 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5825 FIB_TEST(fib_test_validate_entry(fei,
5826 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
5828 &l99_eos_o_10_10_10_1,
5830 "24001/eos LB 2 buckets via: "
5831 "label 99 over 10.10.10.1, "
5832 "adj over 10.10.11.1");
5835 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5837 FIB_TEST(fib_test_validate_entry(fei,
5838 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5840 &l99_neos_o_10_10_10_1,
5841 &a_mpls_o_10_10_11_1),
5842 "24001/neos LB 1 bucket via: "
5843 "label 99 over 10.10.10.1 ",
5844 "mpls-adj via 10.10.11.1");
5847 * add an unlabelled path, this is excluded from the neos chains,
5849 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
5852 .adj = ai_v4_10_10_11_2,
5856 fei = fib_table_entry_path_add(fib_index,
5859 FIB_ENTRY_FLAG_NONE,
5862 tm->hw[1]->sw_if_index,
5863 ~0, // invalid fib index
5866 FIB_ROUTE_PATH_FLAG_NONE);
5868 FIB_TEST(fib_test_validate_entry(fei,
5869 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5870 16, // 3 choices spread over 16 buckets
5871 &l99_eos_o_10_10_10_1,
5872 &l99_eos_o_10_10_10_1,
5873 &l99_eos_o_10_10_10_1,
5874 &l99_eos_o_10_10_10_1,
5875 &l99_eos_o_10_10_10_1,
5876 &l99_eos_o_10_10_10_1,
5887 "1.1.1.1/32 LB 16 buckets via: "
5888 "label 99 over 10.10.10.1, "
5889 "adj over 10.10.11.1",
5890 "adj over 10.10.11.2");
5893 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
5895 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
5896 fib_entry_contribute_forwarding(fei,
5897 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5901 * n-eos has only the 2 labelled paths
5903 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
5906 FIB_TEST(fib_test_validate_entry(fei,
5907 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
5909 &l99_neos_o_10_10_10_1,
5910 &a_mpls_o_10_10_11_1),
5911 "24001/neos LB 2 buckets via: "
5912 "label 99 over 10.10.10.1, "
5913 "adj-mpls over 10.10.11.2");
5916 * A labelled recursive
5918 fib_prefix_t pfx_2_2_2_2_s_32 = {
5920 .fp_proto = FIB_PROTOCOL_IP4,
5922 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
5925 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
5926 .type = FT_LB_LABEL_O_LB,
5928 .lb = non_eos_1_1_1_1.dpoi_index,
5933 mpls_label_t *l1600 = NULL;
5934 vec_add1(l1600, 1600);
5936 fib_table_entry_update_one_path(fib_index,
5939 FIB_ENTRY_FLAG_NONE,
5941 &pfx_1_1_1_1_s_32.fp_addr,
5946 FIB_ROUTE_PATH_FLAG_NONE);
5948 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
5949 FIB_TEST(fib_test_validate_entry(fei,
5950 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5952 &l1600_eos_o_1_1_1_1),
5953 "2.2.2.2.2/32 LB 1 buckets via: "
5954 "label 1600 over 1.1.1.1");
5956 dpo_id_t dpo_44 = DPO_INVALID;
5959 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
5960 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
5962 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
5963 "uRPF check for 2.2.2.2/32 on %d OK",
5964 tm->hw[0]->sw_if_index);
5965 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
5966 "uRPF check for 2.2.2.2/32 on %d OK",
5967 tm->hw[1]->sw_if_index);
5968 FIB_TEST(!fib_urpf_check(urpfi, 99),
5969 "uRPF check for 2.2.2.2/32 on 99 not-OK",
5972 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
5973 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
5974 "Shared uRPF on IP and non-EOS chain");
5979 * we are holding a lock on the non-eos LB of the via-entry.
5980 * do a PIC-core failover by shutting the link of the via-entry.
5982 * shut down the link with the valid label
5984 vnet_sw_interface_set_flags(vnet_get_main(),
5985 tm->hw[0]->sw_if_index,
5988 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
5989 FIB_TEST(fib_test_validate_entry(fei,
5990 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5994 "1.1.1.1/32 LB 2 buckets via: "
5995 "adj over 10.10.11.1, ",
5996 "adj-v4 over 10.10.11.2");
5998 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6000 FIB_TEST(fib_test_validate_entry(fei,
6001 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6005 "24001/eos LB 2 buckets via: "
6006 "adj over 10.10.11.1, ",
6007 "adj-v4 over 10.10.11.2");
6009 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6011 FIB_TEST(fib_test_validate_entry(fei,
6012 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6014 &a_mpls_o_10_10_11_1),
6015 "24001/neos LB 1 buckets via: "
6016 "adj-mpls over 10.10.11.2");
6019 * test that the pre-failover load-balance has been in-place
6022 dpo_id_t current = DPO_INVALID;
6023 fib_entry_contribute_forwarding(fei,
6024 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6027 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6029 "PIC-core LB inplace modified %U %U",
6030 format_dpo_id, &non_eos_1_1_1_1, 0,
6031 format_dpo_id, ¤t, 0);
6033 dpo_reset(&non_eos_1_1_1_1);
6034 dpo_reset(¤t);
6037 * no-shut the link with the valid label
6039 vnet_sw_interface_set_flags(vnet_get_main(),
6040 tm->hw[0]->sw_if_index,
6041 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6043 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6044 FIB_TEST(fib_test_validate_entry(fei,
6045 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6046 16, // 3 choices spread over 16 buckets
6047 &l99_eos_o_10_10_10_1,
6048 &l99_eos_o_10_10_10_1,
6049 &l99_eos_o_10_10_10_1,
6050 &l99_eos_o_10_10_10_1,
6051 &l99_eos_o_10_10_10_1,
6052 &l99_eos_o_10_10_10_1,
6063 "1.1.1.1/32 LB 16 buckets via: "
6064 "label 99 over 10.10.10.1, "
6065 "adj over 10.10.11.1",
6066 "adj-v4 over 10.10.11.2");
6069 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6071 FIB_TEST(fib_test_validate_entry(fei,
6072 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6073 16, // 3 choices spread over 16 buckets
6074 &l99_eos_o_10_10_10_1,
6075 &l99_eos_o_10_10_10_1,
6076 &l99_eos_o_10_10_10_1,
6077 &l99_eos_o_10_10_10_1,
6078 &l99_eos_o_10_10_10_1,
6079 &l99_eos_o_10_10_10_1,
6090 "24001/eos LB 16 buckets via: "
6091 "label 99 over 10.10.10.1, "
6092 "adj over 10.10.11.1",
6093 "adj-v4 over 10.10.11.2");
6095 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6097 FIB_TEST(fib_test_validate_entry(fei,
6098 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6100 &l99_neos_o_10_10_10_1,
6101 &a_mpls_o_10_10_11_1),
6102 "24001/neos LB 2 buckets via: "
6103 "label 99 over 10.10.10.1, "
6104 "adj-mpls over 10.10.11.2");
6107 * remove the first path with the valid label
6109 fib_table_entry_path_remove(fib_index,
6114 tm->hw[0]->sw_if_index,
6115 ~0, // invalid fib index
6117 FIB_ROUTE_PATH_FLAG_NONE);
6119 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6120 FIB_TEST(fib_test_validate_entry(fei,
6121 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6125 "1.1.1.1/32 LB 2 buckets via: "
6126 "adj over 10.10.11.1, "
6127 "adj-v4 over 10.10.11.2");
6129 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6131 FIB_TEST(fib_test_validate_entry(fei,
6132 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6136 "24001/eos LB 2 buckets via: "
6137 "adj over 10.10.11.1, "
6138 "adj-v4 over 10.10.11.2");
6140 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6143 FIB_TEST(fib_test_validate_entry(fei,
6144 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6146 &a_mpls_o_10_10_11_1),
6147 "24001/neos LB 1 buckets via: "
6148 "adj-mpls over 10.10.11.2");
6151 * remove the other path with a valid label
6153 fib_test_lb_bucket_t bucket_drop = {
6154 .type = FT_LB_SPECIAL,
6156 .adj = DPO_PROTO_IP4,
6159 fib_test_lb_bucket_t mpls_bucket_drop = {
6160 .type = FT_LB_SPECIAL,
6162 .adj = DPO_PROTO_MPLS,
6166 fib_table_entry_path_remove(fib_index,
6171 tm->hw[1]->sw_if_index,
6172 ~0, // invalid fib index
6174 FIB_ROUTE_PATH_FLAG_NONE);
6176 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6177 FIB_TEST(fib_test_validate_entry(fei,
6178 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6181 "1.1.1.1/32 LB 1 buckets via: "
6182 "adj over 10.10.11.2");
6184 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6186 FIB_TEST(fib_test_validate_entry(fei,
6187 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6190 "24001/eos LB 1 buckets via: "
6191 "adj over 10.10.11.2");
6193 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6195 FIB_TEST(fib_test_validate_entry(fei,
6196 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6199 "24001/neos LB 1 buckets via: DROP");
6202 * add back the path with the valid label
6207 fib_table_entry_path_add(fib_index,
6210 FIB_ENTRY_FLAG_NONE,
6213 tm->hw[0]->sw_if_index,
6214 ~0, // invalid fib index
6217 FIB_ROUTE_PATH_FLAG_NONE);
6219 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6220 FIB_TEST(fib_test_validate_entry(fei,
6221 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6223 &l99_eos_o_10_10_10_1,
6225 "1.1.1.1/32 LB 2 buckets via: "
6226 "label 99 over 10.10.10.1, "
6227 "adj over 10.10.11.2");
6229 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6231 FIB_TEST(fib_test_validate_entry(fei,
6232 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6234 &l99_eos_o_10_10_10_1,
6236 "24001/eos LB 2 buckets via: "
6237 "label 99 over 10.10.10.1, "
6238 "adj over 10.10.11.2");
6240 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6242 FIB_TEST(fib_test_validate_entry(fei,
6243 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6245 &l99_neos_o_10_10_10_1),
6246 "24001/neos LB 1 buckets via: "
6247 "label 99 over 10.10.10.1");
6250 * change the local label
6252 fib_table_entry_local_label_add(fib_index,
6256 fib_prefix_t pfx_25005_eos = {
6257 .fp_proto = FIB_PROTOCOL_MPLS,
6261 fib_prefix_t pfx_25005_neos = {
6262 .fp_proto = FIB_PROTOCOL_MPLS,
6264 .fp_eos = MPLS_NON_EOS,
6267 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6268 fib_table_lookup(fib_index, &pfx_24001_eos)),
6269 "24001/eos removed after label change");
6270 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6271 fib_table_lookup(fib_index, &pfx_24001_neos)),
6272 "24001/eos removed after label change");
6274 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6276 FIB_TEST(fib_test_validate_entry(fei,
6277 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6279 &l99_eos_o_10_10_10_1,
6281 "25005/eos LB 2 buckets via: "
6282 "label 99 over 10.10.10.1, "
6283 "adj over 10.10.11.2");
6285 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6287 FIB_TEST(fib_test_validate_entry(fei,
6288 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6290 &l99_neos_o_10_10_10_1),
6291 "25005/neos LB 1 buckets via: "
6292 "label 99 over 10.10.10.1");
6295 * remove the local label.
6296 * the check that the MPLS entries are gone is done by the fact the
6297 * MPLS table is no longer present.
6299 fib_table_entry_local_label_remove(fib_index,
6303 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6304 FIB_TEST(fib_test_validate_entry(fei,
6305 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6307 &l99_eos_o_10_10_10_1,
6309 "24001/eos LB 2 buckets via: "
6310 "label 99 over 10.10.10.1, "
6311 "adj over 10.10.11.2");
6313 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6314 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6315 "No more MPLS FIB entries => table removed");
6318 * add another via-entry for the recursive
6320 fib_prefix_t pfx_1_1_1_2_s_32 = {
6322 .fp_proto = FIB_PROTOCOL_IP4,
6324 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6327 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6328 .type = FT_LB_LABEL_O_ADJ,
6330 .adj = ai_mpls_10_10_10_1,
6335 mpls_label_t *l101 = NULL;
6336 vec_add1(l101, 101);
6338 fei = fib_table_entry_update_one_path(fib_index,
6341 FIB_ENTRY_FLAG_NONE,
6344 tm->hw[0]->sw_if_index,
6345 ~0, // invalid fib index
6348 FIB_ROUTE_PATH_FLAG_NONE);
6350 FIB_TEST(fib_test_validate_entry(fei,
6351 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6353 &l101_eos_o_10_10_10_1),
6354 "1.1.1.2/32 LB 1 buckets via: "
6355 "label 101 over 10.10.10.1");
6357 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6358 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6360 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6362 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6364 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6367 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6368 .type = FT_LB_LABEL_O_LB,
6370 .lb = non_eos_1_1_1_2.dpoi_index,
6375 mpls_label_t *l1601 = NULL;
6376 vec_add1(l1601, 1601);
6378 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6380 fei = fib_table_entry_path_add(fib_index,
6383 FIB_ENTRY_FLAG_NONE,
6385 &pfx_1_1_1_2_s_32.fp_addr,
6390 FIB_ROUTE_PATH_FLAG_NONE);
6392 FIB_TEST(fib_test_validate_entry(fei,
6393 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6395 &l1600_eos_o_1_1_1_1,
6396 &l1601_eos_o_1_1_1_2),
6397 "2.2.2.2/32 LB 2 buckets via: "
6398 "label 1600 via 1.1,1.1, "
6399 "label 16001 via 1.1.1.2");
6402 * update the via-entry so it no longer has an imp-null path.
6403 * the LB for the recursive can use an imp-null
6406 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6408 fei = fib_table_entry_update_one_path(fib_index,
6411 FIB_ENTRY_FLAG_NONE,
6414 tm->hw[1]->sw_if_index,
6415 ~0, // invalid fib index
6418 FIB_ROUTE_PATH_FLAG_NONE);
6420 FIB_TEST(fib_test_validate_entry(fei,
6421 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6424 "1.1.1.2/32 LB 1 buckets via: "
6427 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6428 FIB_TEST(fib_test_validate_entry(fei,
6429 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6431 &l1600_eos_o_1_1_1_1,
6432 &l1601_eos_o_1_1_1_2),
6433 "2.2.2.2/32 LB 2 buckets via: "
6434 "label 1600 via 1.1,1.1, "
6435 "label 16001 via 1.1.1.2");
6438 * update the via-entry so it no longer has labelled paths.
6439 * the LB for the recursive should exclue this via form its LB
6441 fei = fib_table_entry_update_one_path(fib_index,
6444 FIB_ENTRY_FLAG_NONE,
6447 tm->hw[1]->sw_if_index,
6448 ~0, // invalid fib index
6451 FIB_ROUTE_PATH_FLAG_NONE);
6453 FIB_TEST(fib_test_validate_entry(fei,
6454 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6457 "1.1.1.2/32 LB 1 buckets via: "
6460 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6461 FIB_TEST(fib_test_validate_entry(fei,
6462 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6464 &l1600_eos_o_1_1_1_1),
6465 "2.2.2.2/32 LB 1 buckets via: "
6466 "label 1600 via 1.1,1.1");
6468 dpo_reset(&non_eos_1_1_1_1);
6469 dpo_reset(&non_eos_1_1_1_2);
6472 * Add a recursive with no out-labels. We expect to use the IP of the via
6474 fib_prefix_t pfx_2_2_2_3_s_32 = {
6476 .fp_proto = FIB_PROTOCOL_IP4,
6478 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
6481 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6483 fib_table_entry_update_one_path(fib_index,
6486 FIB_ENTRY_FLAG_NONE,
6488 &pfx_1_1_1_1_s_32.fp_addr,
6493 FIB_ROUTE_PATH_FLAG_NONE);
6495 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6497 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6500 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6503 .lb = ip_1_1_1_1.dpoi_index,
6507 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
6508 FIB_TEST(fib_test_validate_entry(fei,
6509 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6512 "2.2.2.2.3/32 LB 1 buckets via: "
6516 * Add a recursive with an imp-null out-label.
6517 * We expect to use the IP of the via
6519 fib_prefix_t pfx_2_2_2_4_s_32 = {
6521 .fp_proto = FIB_PROTOCOL_IP4,
6523 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
6527 fib_table_entry_update_one_path(fib_index,
6530 FIB_ENTRY_FLAG_NONE,
6532 &pfx_1_1_1_1_s_32.fp_addr,
6537 FIB_ROUTE_PATH_FLAG_NONE);
6539 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
6540 FIB_TEST(fib_test_validate_entry(fei,
6541 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6544 "2.2.2.2.4/32 LB 1 buckets via: "
6547 dpo_reset(&ip_1_1_1_1);
6550 * Create an entry with a deep label stack
6552 fib_prefix_t pfx_2_2_5_5_s_32 = {
6554 .fp_proto = FIB_PROTOCOL_IP4,
6556 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
6559 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
6560 .type = FT_LB_LABEL_STACK_O_ADJ,
6561 .label_stack_o_adj = {
6562 .adj = ai_mpls_10_10_11_1,
6563 .label_stack_size = 8,
6565 200, 201, 202, 203, 204, 205, 206, 207
6570 mpls_label_t *label_stack = NULL;
6571 vec_validate(label_stack, 7);
6572 for (ii = 0; ii < 8; ii++)
6574 label_stack[ii] = ii + 200;
6577 fei = fib_table_entry_update_one_path(fib_index,
6580 FIB_ENTRY_FLAG_NONE,
6583 tm->hw[1]->sw_if_index,
6584 ~0, // invalid fib index
6587 FIB_ROUTE_PATH_FLAG_NONE);
6589 FIB_TEST(fib_test_validate_entry(fei,
6590 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6592 &ls_eos_o_10_10_10_1),
6593 "2.2.5.5/32 LB 1 buckets via: "
6595 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
6600 fib_table_entry_delete(fib_index,
6604 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6605 FIB_TEST(fib_test_validate_entry(fei,
6606 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6608 &l1600_eos_o_1_1_1_1),
6609 "2.2.2.2/32 LB 1 buckets via: "
6610 "label 1600 via 1.1,1.1");
6612 fib_table_entry_delete(fib_index,
6616 FIB_TEST(fib_test_validate_entry(fei,
6617 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6620 "2.2.2.2/32 LB 1 buckets via: DROP");
6622 fib_table_entry_delete(fib_index,
6625 fib_table_entry_delete(fib_index,
6628 fib_table_entry_delete(fib_index,
6632 adj_unlock(ai_mpls_10_10_10_1);
6633 adj_unlock(ai_mpls_10_10_11_2);
6634 adj_unlock(ai_v4_10_10_11_1);
6635 adj_unlock(ai_v4_10_10_11_2);
6636 adj_unlock(ai_mpls_10_10_11_1);
6638 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6641 local0_pfx.fp_len = 32;
6642 fib_table_entry_delete(fib_index,
6644 FIB_SOURCE_INTERFACE);
6645 local0_pfx.fp_len = 24;
6646 fib_table_entry_delete(fib_index,
6648 FIB_SOURCE_INTERFACE);
6649 local1_pfx.fp_len = 32;
6650 fib_table_entry_delete(fib_index,
6652 FIB_SOURCE_INTERFACE);
6653 local1_pfx.fp_len = 24;
6654 fib_table_entry_delete(fib_index,
6656 FIB_SOURCE_INTERFACE);
6659 * +1 for the drop LB in the MPLS tables.
6661 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
6662 "Load-balance resources freed %d of %d",
6663 lb_count+1, pool_elts(load_balance_pool));
6668 #define N_TEST_CHILDREN 4
6669 #define PARENT_INDEX 0
6671 typedef struct fib_node_test_t_
6676 fib_node_back_walk_ctx_t *ctxs;
6680 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
6682 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
6684 #define FOR_EACH_TEST_CHILD(_tc) \
6685 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
6686 ii < N_TEST_CHILDREN+1; \
6687 ii++, (_tc) = &fib_test_nodes[ii])
6690 fib_test_child_get_node (fib_node_index_t index)
6692 return (&fib_test_nodes[index].node);
6695 static int fib_test_walk_spawns_walks;
6697 static fib_node_back_walk_rc_t
6698 fib_test_child_back_walk_notify (fib_node_t *node,
6699 fib_node_back_walk_ctx_t *ctx)
6701 fib_node_test_t *tc = (fib_node_test_t*) node;
6703 vec_add1(tc->ctxs, *ctx);
6705 if (1 == fib_test_walk_spawns_walks)
6706 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
6707 if (2 == fib_test_walk_spawns_walks)
6708 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
6709 FIB_WALK_PRIORITY_HIGH, ctx);
6711 return (FIB_NODE_BACK_WALK_CONTINUE);
6715 fib_test_child_last_lock_gone (fib_node_t *node)
6717 fib_node_test_t *tc = (fib_node_test_t *)node;
6723 * The FIB walk's graph node virtual function table
6725 static const fib_node_vft_t fib_test_child_vft = {
6726 .fnv_get = fib_test_child_get_node,
6727 .fnv_last_lock = fib_test_child_last_lock_gone,
6728 .fnv_back_walk = fib_test_child_back_walk_notify,
6732 * the function (that should have been static but isn't so I can do this)
6733 * that processes the walk from the async queue,
6735 f64 fib_walk_process_queues(vlib_main_t * vm,
6737 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
6740 fib_test_walk (void)
6742 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
6743 fib_node_test_t *tc;
6747 vm = vlib_get_main();
6748 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
6751 * init a fake node on which we will add children
6753 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
6754 FIB_NODE_TYPE_TEST);
6756 FOR_EACH_TEST_CHILD(tc)
6758 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
6759 fib_node_lock(&tc->node);
6762 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
6764 FIB_NODE_TYPE_TEST, ii);
6768 * enqueue a walk across the parents children.
6770 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6772 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6773 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6774 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6775 "Parent has %d children pre-walk",
6776 fib_node_list_get_size(PARENT()->fn_children));
6779 * give the walk a large amount of time so it gets to the end
6781 fib_walk_process_queues(vm, 1);
6783 FOR_EACH_TEST_CHILD(tc)
6785 FIB_TEST(1 == vec_len(tc->ctxs),
6786 "%d child visitsed %d times",
6787 ii, vec_len(tc->ctxs));
6790 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6791 "Queue is empty post walk");
6792 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6793 "Parent has %d children post walk",
6794 fib_node_list_get_size(PARENT()->fn_children));
6797 * walk again. should be no increase in the number of visits, since
6798 * the walk will have terminated.
6800 fib_walk_process_queues(vm, 1);
6802 FOR_EACH_TEST_CHILD(tc)
6804 FIB_TEST(0 == vec_len(tc->ctxs),
6805 "%d child visitsed %d times",
6806 ii, vec_len(tc->ctxs));
6810 * schedule a low and hig priority walk. expect the high to be performed
6812 * schedule the high prio walk first so that it is further from the head
6813 * of the dependency list. that way it won't merge with the low one.
6815 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6816 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6818 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6819 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6820 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6821 FIB_WALK_PRIORITY_LOW, &low_ctx);
6823 fib_walk_process_queues(vm, 1);
6825 FOR_EACH_TEST_CHILD(tc)
6827 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6828 "%d child visitsed by high prio walk", ii);
6829 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6830 "%d child visitsed by low prio walk", ii);
6833 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6834 "Queue is empty post prio walk");
6835 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6836 "Parent has %d children post prio walk",
6837 fib_node_list_get_size(PARENT()->fn_children));
6840 * schedule 2 walks of the same priority that can be megred.
6841 * expect that each child is thus visited only once.
6843 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6844 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6846 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6847 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6848 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6849 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6851 fib_walk_process_queues(vm, 1);
6853 FOR_EACH_TEST_CHILD(tc)
6855 FIB_TEST(1 == vec_len(tc->ctxs),
6856 "%d child visitsed %d times during merge walk",
6857 ii, vec_len(tc->ctxs));
6860 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6861 "Queue is empty post merge walk");
6862 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6863 "Parent has %d children post merge walk",
6864 fib_node_list_get_size(PARENT()->fn_children));
6867 * schedule 2 walks of the same priority that cannot be megred.
6868 * expect that each child is thus visited twice and in the order
6869 * in which the walks were scheduled.
6871 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6872 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
6874 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6875 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6876 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6877 FIB_WALK_PRIORITY_HIGH, &low_ctx);
6879 fib_walk_process_queues(vm, 1);
6881 FOR_EACH_TEST_CHILD(tc)
6883 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
6884 "%d child visitsed by high prio walk", ii);
6885 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
6886 "%d child visitsed by low prio walk", ii);
6889 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6890 "Queue is empty post no-merge walk");
6891 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6892 "Parent has %d children post no-merge walk",
6893 fib_node_list_get_size(PARENT()->fn_children));
6896 * schedule a walk that makes one one child progress.
6897 * we do this by giving the queue draining process zero
6898 * time quanta. it's a do..while loop, so it does something.
6900 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6902 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6903 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6904 fib_walk_process_queues(vm, 0);
6906 FOR_EACH_TEST_CHILD(tc)
6908 if (ii == N_TEST_CHILDREN)
6910 FIB_TEST(1 == vec_len(tc->ctxs),
6911 "%d child visitsed %d times in zero quanta walk",
6912 ii, vec_len(tc->ctxs));
6916 FIB_TEST(0 == vec_len(tc->ctxs),
6917 "%d child visitsed %d times in 0 quanta walk",
6918 ii, vec_len(tc->ctxs));
6921 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6922 "Queue is not empty post zero quanta walk");
6923 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6924 "Parent has %d children post zero qunta walk",
6925 fib_node_list_get_size(PARENT()->fn_children));
6930 fib_walk_process_queues(vm, 0);
6932 FOR_EACH_TEST_CHILD(tc)
6934 if (ii >= N_TEST_CHILDREN-1)
6936 FIB_TEST(1 == vec_len(tc->ctxs),
6937 "%d child visitsed %d times in 2nd zero quanta walk",
6938 ii, vec_len(tc->ctxs));
6942 FIB_TEST(0 == vec_len(tc->ctxs),
6943 "%d child visitsed %d times in 2nd 0 quanta walk",
6944 ii, vec_len(tc->ctxs));
6947 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6948 "Queue is not empty post zero quanta walk");
6949 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
6950 "Parent has %d children post zero qunta walk",
6951 fib_node_list_get_size(PARENT()->fn_children));
6954 * schedule another walk that will catch-up and merge.
6956 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6957 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6958 fib_walk_process_queues(vm, 1);
6960 FOR_EACH_TEST_CHILD(tc)
6962 if (ii >= N_TEST_CHILDREN-1)
6964 FIB_TEST(2 == vec_len(tc->ctxs),
6965 "%d child visitsed %d times in 2nd zero quanta merge walk",
6966 ii, vec_len(tc->ctxs));
6971 FIB_TEST(1 == vec_len(tc->ctxs),
6972 "%d child visitsed %d times in 2nd 0 quanta merge walk",
6973 ii, vec_len(tc->ctxs));
6977 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
6978 "Queue is not empty post 2nd zero quanta merge walk");
6979 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
6980 "Parent has %d children post 2nd zero qunta merge walk",
6981 fib_node_list_get_size(PARENT()->fn_children));
6984 * park a async walk in the middle of the list, then have an sync walk catch
6985 * it. same expectations as async catches async.
6987 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
6989 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
6990 FIB_WALK_PRIORITY_HIGH, &high_ctx);
6992 fib_walk_process_queues(vm, 0);
6993 fib_walk_process_queues(vm, 0);
6995 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
6997 FOR_EACH_TEST_CHILD(tc)
6999 if (ii >= N_TEST_CHILDREN-1)
7001 FIB_TEST(2 == vec_len(tc->ctxs),
7002 "%d child visitsed %d times in sync catches async walk",
7003 ii, vec_len(tc->ctxs));
7008 FIB_TEST(1 == vec_len(tc->ctxs),
7009 "%d child visitsed %d times in sync catches async walk",
7010 ii, vec_len(tc->ctxs));
7014 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7015 "Queue is not empty post 2nd zero quanta merge walk");
7016 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7017 "Parent has %d children post 2nd zero qunta merge walk",
7018 fib_node_list_get_size(PARENT()->fn_children));
7021 * make the parent a child of one of its children, thus inducing a routing loop.
7023 fib_test_nodes[PARENT_INDEX].sibling =
7024 fib_node_child_add(FIB_NODE_TYPE_TEST,
7025 1, // the first child
7030 * execute a sync walk from the parent. each child visited spawns more sync
7031 * walks. we expect the walk to terminate.
7033 fib_test_walk_spawns_walks = 1;
7035 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7037 FOR_EACH_TEST_CHILD(tc)
7040 * child 1 - which is last in the list - has the loop.
7041 * the other children a re thus visitsed first. the we meet
7042 * child 1. we go round the loop again, visting the other children.
7043 * then we meet the walk in the dep list and bail. child 1 is not visitsed
7048 FIB_TEST(1 == vec_len(tc->ctxs),
7049 "child %d visitsed %d times during looped sync walk",
7050 ii, vec_len(tc->ctxs));
7054 FIB_TEST(2 == vec_len(tc->ctxs),
7055 "child %d visitsed %d times during looped sync walk",
7056 ii, vec_len(tc->ctxs));
7060 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7061 "Parent has %d children post sync loop walk",
7062 fib_node_list_get_size(PARENT()->fn_children));
7065 * the walk doesn't reach the max depth because the infra knows that sync
7066 * meets sync implies a loop and bails early.
7068 FIB_TEST(high_ctx.fnbw_depth == 9,
7069 "Walk context depth %d post sync loop walk",
7070 high_ctx.fnbw_depth);
7073 * execute an async walk of the graph loop, with each child spawns sync walks
7075 high_ctx.fnbw_depth = 0;
7076 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7077 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7079 fib_walk_process_queues(vm, 1);
7081 FOR_EACH_TEST_CHILD(tc)
7084 * we don't really care how many times the children are visisted, as long as
7085 * it is more than once.
7087 FIB_TEST(1 <= vec_len(tc->ctxs),
7088 "child %d visitsed %d times during looped aync spawns sync walk",
7089 ii, vec_len(tc->ctxs));
7094 * execute an async walk of the graph loop, with each child spawns async walks
7096 fib_test_walk_spawns_walks = 2;
7097 high_ctx.fnbw_depth = 0;
7098 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7099 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7101 fib_walk_process_queues(vm, 1);
7103 FOR_EACH_TEST_CHILD(tc)
7106 * we don't really care how many times the children are visisted, as long as
7107 * it is more than once.
7109 FIB_TEST(1 <= vec_len(tc->ctxs),
7110 "child %d visitsed %d times during looped async spawns async walk",
7111 ii, vec_len(tc->ctxs));
7116 fib_node_child_remove(FIB_NODE_TYPE_TEST,
7117 1, // the first child
7118 fib_test_nodes[PARENT_INDEX].sibling);
7123 FOR_EACH_TEST_CHILD(tc)
7125 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7127 fib_node_deinit(&tc->node);
7128 fib_node_unlock(&tc->node);
7130 fib_node_deinit(PARENT());
7133 * The parent will be destroyed when the last lock on it goes.
7134 * this test ensures all the walk objects are unlocking it.
7136 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7137 "Parent was destroyed");
7143 * declaration of the otherwise static callback functions
7145 void fib_bfd_notify (bfd_listen_event_e event,
7146 const bfd_session_t *session);
7147 void adj_bfd_notify (bfd_listen_event_e event,
7148 const bfd_session_t *session);
7151 * Test BFD session interaction with FIB
7156 fib_node_index_t fei;
7160 /* via 10.10.10.1 */
7161 ip46_address_t nh_10_10_10_1 = {
7162 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7164 /* via 10.10.10.2 */
7165 ip46_address_t nh_10_10_10_2 = {
7166 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7168 /* via 10.10.10.10 */
7169 ip46_address_t nh_10_10_10_10 = {
7170 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7172 n_feis = fib_entry_pool_size();
7177 * add interface routes. we'll assume this works. it's tested elsewhere
7179 fib_prefix_t pfx_10_10_10_10_s_24 = {
7181 .fp_proto = FIB_PROTOCOL_IP4,
7182 .fp_addr = nh_10_10_10_10,
7185 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7186 FIB_SOURCE_INTERFACE,
7187 (FIB_ENTRY_FLAG_CONNECTED |
7188 FIB_ENTRY_FLAG_ATTACHED),
7191 tm->hw[0]->sw_if_index,
7192 ~0, // invalid fib index
7195 FIB_ROUTE_PATH_FLAG_NONE);
7197 fib_prefix_t pfx_10_10_10_10_s_32 = {
7199 .fp_proto = FIB_PROTOCOL_IP4,
7200 .fp_addr = nh_10_10_10_10,
7202 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7203 FIB_SOURCE_INTERFACE,
7204 (FIB_ENTRY_FLAG_CONNECTED |
7205 FIB_ENTRY_FLAG_LOCAL),
7208 tm->hw[0]->sw_if_index,
7209 ~0, // invalid fib index
7212 FIB_ROUTE_PATH_FLAG_NONE);
7215 * A BFD session via a neighbour we do not yet know
7217 bfd_session_t bfd_10_10_10_1 = {
7221 .peer_addr = nh_10_10_10_1,
7224 .hop_type = BFD_HOP_TYPE_MULTI,
7225 .local_state = BFD_STATE_init,
7228 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7231 * A new entry will be created that forwards via the adj
7233 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7236 tm->hw[0]->sw_if_index);
7237 fib_prefix_t pfx_10_10_10_1_s_32 = {
7238 .fp_addr = nh_10_10_10_1,
7240 .fp_proto = FIB_PROTOCOL_IP4,
7242 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7245 .adj = ai_10_10_10_1,
7249 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7250 FIB_TEST(fib_test_validate_entry(fei,
7251 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7254 "BFD sourced %U via %U",
7255 format_fib_prefix, &pfx_10_10_10_1_s_32,
7256 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7259 * Delete the BFD session. Expect the fib_entry to be removed
7261 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7263 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7264 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7265 "BFD sourced %U removed",
7266 format_fib_prefix, &pfx_10_10_10_1_s_32);
7269 * Add the BFD source back
7271 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7274 * source the entry via the ADJ fib
7276 fei = fib_table_entry_path_add(0,
7277 &pfx_10_10_10_1_s_32,
7279 FIB_ENTRY_FLAG_ATTACHED,
7282 tm->hw[0]->sw_if_index,
7283 ~0, // invalid fib index
7286 FIB_ROUTE_PATH_FLAG_NONE);
7289 * Delete the BFD session. Expect the fib_entry to remain
7291 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7293 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7294 FIB_TEST(fib_test_validate_entry(fei,
7295 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7298 "BFD sourced %U remains via %U",
7299 format_fib_prefix, &pfx_10_10_10_1_s_32,
7300 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7303 * Add the BFD source back
7305 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7308 * Create another ADJ FIB
7310 fib_prefix_t pfx_10_10_10_2_s_32 = {
7311 .fp_addr = nh_10_10_10_2,
7313 .fp_proto = FIB_PROTOCOL_IP4,
7315 fib_table_entry_path_add(0,
7316 &pfx_10_10_10_2_s_32,
7318 FIB_ENTRY_FLAG_ATTACHED,
7321 tm->hw[0]->sw_if_index,
7322 ~0, // invalid fib index
7325 FIB_ROUTE_PATH_FLAG_NONE);
7327 * A BFD session for the new ADJ FIB
7329 bfd_session_t bfd_10_10_10_2 = {
7333 .peer_addr = nh_10_10_10_2,
7336 .hop_type = BFD_HOP_TYPE_MULTI,
7337 .local_state = BFD_STATE_init,
7340 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7343 * remove the adj-fib source whilst the session is present
7346 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7347 fib_table_entry_path_add(0,
7348 &pfx_10_10_10_2_s_32,
7350 FIB_ENTRY_FLAG_ATTACHED,
7353 tm->hw[0]->sw_if_index,
7354 ~0, // invalid fib index
7357 FIB_ROUTE_PATH_FLAG_NONE);
7360 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7361 * bring one of the sessions UP, leave the other down
7363 bfd_10_10_10_1.local_state = BFD_STATE_up;
7364 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7365 bfd_10_10_10_2.local_state = BFD_STATE_down;
7366 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7369 * A recursive prefix via both of the ADJ FIBs
7371 fib_prefix_t pfx_200_0_0_0_s_24 = {
7372 .fp_proto = FIB_PROTOCOL_IP4,
7375 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7378 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7381 fib_entry_contribute_ip_forwarding(
7382 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7384 fib_entry_contribute_ip_forwarding(
7385 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7387 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7390 .lb = dpo_10_10_10_1->dpoi_index,
7393 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7396 .lb = dpo_10_10_10_2->dpoi_index,
7401 * A prefix via the adj-fib that is BFD down => DROP
7403 fei = fib_table_entry_path_add(0,
7404 &pfx_200_0_0_0_s_24,
7406 FIB_ENTRY_FLAG_NONE,
7410 0, // default fib index
7413 FIB_ROUTE_PATH_FLAG_NONE);
7414 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7415 "%U resolves via drop",
7416 format_fib_prefix, &pfx_200_0_0_0_s_24);
7419 * add a path via the UP BFD adj-fib.
7420 * we expect that the DOWN BFD ADJ FIB is not used.
7422 fei = fib_table_entry_path_add(0,
7423 &pfx_200_0_0_0_s_24,
7425 FIB_ENTRY_FLAG_NONE,
7429 0, // default fib index
7432 FIB_ROUTE_PATH_FLAG_NONE);
7434 FIB_TEST(fib_test_validate_entry(fei,
7435 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7438 "Recursive %U only UP BFD adj-fibs",
7439 format_fib_prefix, &pfx_200_0_0_0_s_24);
7442 * Send a BFD state change to UP - both sessions are now up
7443 * the recursive prefix should LB over both
7445 bfd_10_10_10_2.local_state = BFD_STATE_up;
7446 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7449 FIB_TEST(fib_test_validate_entry(fei,
7450 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7454 "Recursive %U via both UP BFD adj-fibs",
7455 format_fib_prefix, &pfx_200_0_0_0_s_24);
7458 * Send a BFD state change to DOWN
7459 * the recursive prefix should exclude the down
7461 bfd_10_10_10_2.local_state = BFD_STATE_down;
7462 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7465 FIB_TEST(fib_test_validate_entry(fei,
7466 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7469 "Recursive %U via only UP",
7470 format_fib_prefix, &pfx_200_0_0_0_s_24);
7473 * Delete the BFD session while it is in the DOWN state.
7474 * FIB should consider the entry's state as back up
7476 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
7478 FIB_TEST(fib_test_validate_entry(fei,
7479 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7483 "Recursive %U via both UP BFD adj-fibs post down session delete",
7484 format_fib_prefix, &pfx_200_0_0_0_s_24);
7487 * Delete the BFD other session while it is in the UP state.
7489 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7491 FIB_TEST(fib_test_validate_entry(fei,
7492 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7496 "Recursive %U via both UP BFD adj-fibs post up session delete",
7497 format_fib_prefix, &pfx_200_0_0_0_s_24);
7502 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
7503 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
7504 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7506 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
7507 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
7509 adj_unlock(ai_10_10_10_1);
7511 * test no-one left behind
7513 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7514 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7517 * Single-hop BFD tests
7519 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
7520 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
7522 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7524 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7527 tm->hw[0]->sw_if_index);
7529 * whilst the BFD session is not signalled, the adj is up
7531 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
7534 * bring the BFD session up
7536 bfd_10_10_10_1.local_state = BFD_STATE_up;
7537 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7538 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
7541 * bring the BFD session down
7543 bfd_10_10_10_1.local_state = BFD_STATE_down;
7544 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7545 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
7549 * add an attached next hop FIB entry via the down adj
7551 fib_prefix_t pfx_5_5_5_5_s_32 = {
7554 .as_u32 = clib_host_to_net_u32(0x05050505),
7558 .fp_proto = FIB_PROTOCOL_IP4,
7561 fei = fib_table_entry_path_add(0,
7564 FIB_ENTRY_FLAG_NONE,
7567 tm->hw[0]->sw_if_index,
7568 ~0, // invalid fib index
7571 FIB_ROUTE_PATH_FLAG_NONE);
7572 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7573 "%U resolves via drop",
7574 format_fib_prefix, &pfx_5_5_5_5_s_32);
7577 * Add a path via an ADJ that is up
7579 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7582 tm->hw[0]->sw_if_index);
7584 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
7587 .adj = ai_10_10_10_2,
7590 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
7592 fei = fib_table_entry_path_add(0,
7595 FIB_ENTRY_FLAG_NONE,
7598 tm->hw[0]->sw_if_index,
7599 ~0, // invalid fib index
7602 FIB_ROUTE_PATH_FLAG_NONE);
7604 FIB_TEST(fib_test_validate_entry(fei,
7605 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7608 "BFD sourced %U via %U",
7609 format_fib_prefix, &pfx_5_5_5_5_s_32,
7610 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
7613 * Bring up the down session - should now LB
7615 bfd_10_10_10_1.local_state = BFD_STATE_up;
7616 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7617 FIB_TEST(fib_test_validate_entry(fei,
7618 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7622 "BFD sourced %U via noth adjs",
7623 format_fib_prefix, &pfx_5_5_5_5_s_32);
7626 * remove the BFD session state from the adj
7628 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7633 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
7634 adj_unlock(ai_10_10_10_1);
7635 adj_unlock(ai_10_10_10_2);
7638 * test no-one left behind
7640 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
7641 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
7648 const mpls_label_t deag_label = 50;
7649 const u32 lfib_index = 0;
7650 const u32 fib_index = 0;
7651 dpo_id_t dpo = DPO_INVALID;
7652 const dpo_id_t *dpo1;
7653 fib_node_index_t lfe;
7657 adj_index_t ai_mpls_10_10_10_1;
7660 lb_count = pool_elts(load_balance_pool);
7662 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7666 * MPLS enable an interface so we get the MPLS table created
7668 mpls_sw_interface_enable_disable(&mpls_main,
7669 tm->hw[0]->sw_if_index,
7672 ip46_address_t nh_10_10_10_1 = {
7673 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7675 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7678 tm->hw[0]->sw_if_index);
7681 * Test the specials stack properly.
7683 fib_prefix_t exp_null_v6_pfx = {
7684 .fp_proto = FIB_PROTOCOL_MPLS,
7686 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7687 .fp_payload_proto = DPO_PROTO_IP6,
7689 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
7690 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
7692 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
7693 format_mpls_eos_bit, MPLS_EOS);
7694 fib_entry_contribute_forwarding(lfe,
7695 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7697 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7698 lkd = lookup_dpo_get(dpo1->dpoi_index);
7700 FIB_TEST((fib_index == lkd->lkd_fib_index),
7701 "%U/%U is deag in %d %U",
7702 format_mpls_unicast_label, deag_label,
7703 format_mpls_eos_bit, MPLS_EOS,
7705 format_dpo_id, &dpo, 0);
7706 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7707 "%U/%U is dst deag",
7708 format_mpls_unicast_label, deag_label,
7709 format_mpls_eos_bit, MPLS_EOS);
7710 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
7711 "%U/%U is lookup in interface's table",
7712 format_mpls_unicast_label, deag_label,
7713 format_mpls_eos_bit, MPLS_EOS);
7714 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
7715 "%U/%U is %U dst deag",
7716 format_mpls_unicast_label, deag_label,
7717 format_mpls_eos_bit, MPLS_EOS,
7718 format_dpo_proto, lkd->lkd_proto);
7722 * A route deag route for EOS
7724 fib_prefix_t pfx = {
7725 .fp_proto = FIB_PROTOCOL_MPLS,
7727 .fp_label = deag_label,
7728 .fp_payload_proto = DPO_PROTO_IP4,
7730 lfe = fib_table_entry_path_add(lfib_index,
7733 FIB_ENTRY_FLAG_NONE,
7740 FIB_ROUTE_PATH_FLAG_NONE);
7742 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7744 format_mpls_unicast_label, deag_label,
7745 format_mpls_eos_bit, MPLS_EOS);
7747 fib_entry_contribute_forwarding(lfe,
7748 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7750 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7751 lkd = lookup_dpo_get(dpo1->dpoi_index);
7753 FIB_TEST((fib_index == lkd->lkd_fib_index),
7754 "%U/%U is deag in %d %U",
7755 format_mpls_unicast_label, deag_label,
7756 format_mpls_eos_bit, MPLS_EOS,
7758 format_dpo_id, &dpo, 0);
7759 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7760 "%U/%U is dst deag",
7761 format_mpls_unicast_label, deag_label,
7762 format_mpls_eos_bit, MPLS_EOS);
7763 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
7764 "%U/%U is %U dst deag",
7765 format_mpls_unicast_label, deag_label,
7766 format_mpls_eos_bit, MPLS_EOS,
7767 format_dpo_proto, lkd->lkd_proto);
7769 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7771 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7773 "%U/%U not present",
7774 format_mpls_unicast_label, deag_label,
7775 format_mpls_eos_bit, MPLS_EOS);
7778 * A route deag route for non-EOS
7780 pfx.fp_eos = MPLS_NON_EOS;
7781 lfe = fib_table_entry_path_add(lfib_index,
7784 FIB_ENTRY_FLAG_NONE,
7791 FIB_ROUTE_PATH_FLAG_NONE);
7793 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
7795 format_mpls_unicast_label, deag_label,
7796 format_mpls_eos_bit, MPLS_NON_EOS);
7798 fib_entry_contribute_forwarding(lfe,
7799 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7801 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
7802 lkd = lookup_dpo_get(dpo1->dpoi_index);
7804 FIB_TEST((fib_index == lkd->lkd_fib_index),
7805 "%U/%U is deag in %d %U",
7806 format_mpls_unicast_label, deag_label,
7807 format_mpls_eos_bit, MPLS_NON_EOS,
7809 format_dpo_id, &dpo, 0);
7810 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
7811 "%U/%U is dst deag",
7812 format_mpls_unicast_label, deag_label,
7813 format_mpls_eos_bit, MPLS_NON_EOS);
7815 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
7816 "%U/%U is %U dst deag",
7817 format_mpls_unicast_label, deag_label,
7818 format_mpls_eos_bit, MPLS_NON_EOS,
7819 format_dpo_proto, lkd->lkd_proto);
7821 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
7823 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
7825 "%U/%U not present",
7826 format_mpls_unicast_label, deag_label,
7827 format_mpls_eos_bit, MPLS_EOS);
7834 fib_prefix_t pfx_1200 = {
7836 .fp_proto = FIB_PROTOCOL_MPLS,
7838 .fp_eos = MPLS_NON_EOS,
7840 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
7841 .type = FT_LB_LABEL_STACK_O_ADJ,
7842 .label_stack_o_adj = {
7843 .adj = ai_mpls_10_10_10_1,
7844 .label_stack_size = 4,
7848 .eos = MPLS_NON_EOS,
7851 dpo_id_t neos_1200 = DPO_INVALID;
7852 dpo_id_t ip_1200 = DPO_INVALID;
7853 mpls_label_t *l200 = NULL;
7854 vec_add1(l200, 200);
7855 vec_add1(l200, 300);
7856 vec_add1(l200, 400);
7857 vec_add1(l200, 500);
7859 lfe = fib_table_entry_update_one_path(fib_index,
7862 FIB_ENTRY_FLAG_NONE,
7865 tm->hw[0]->sw_if_index,
7866 ~0, // invalid fib index
7869 FIB_ROUTE_PATH_FLAG_NONE);
7871 FIB_TEST(fib_test_validate_entry(lfe,
7872 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7874 &neos_o_10_10_10_1),
7875 "1200/0 LB 1 buckets via: "
7879 * A recursive route via the MPLS x-connect
7881 fib_prefix_t pfx_2_2_2_3_s_32 = {
7883 .fp_proto = FIB_PROTOCOL_IP4,
7885 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7888 fib_route_path_t *rpaths = NULL, rpath = {
7889 .frp_proto = FIB_PROTOCOL_MPLS,
7890 .frp_local_label = 1200,
7891 .frp_eos = MPLS_NON_EOS,
7892 .frp_sw_if_index = ~0, // recurive
7893 .frp_fib_index = 0, // Default MPLS fib
7895 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
7896 .frp_label_stack = NULL,
7898 vec_add1(rpaths, rpath);
7900 fib_table_entry_path_add2(fib_index,
7903 FIB_ENTRY_FLAG_NONE,
7907 * A labelled recursive route via the MPLS x-connect
7909 fib_prefix_t pfx_2_2_2_4_s_32 = {
7911 .fp_proto = FIB_PROTOCOL_IP4,
7913 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7916 mpls_label_t *l999 = NULL;
7917 vec_add1(l999, 999);
7918 rpaths[0].frp_label_stack = l999,
7920 fib_table_entry_path_add2(fib_index,
7923 FIB_ENTRY_FLAG_NONE,
7926 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7927 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7929 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7930 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7933 fib_test_lb_bucket_t ip_o_1200 = {
7936 .lb = ip_1200.dpoi_index,
7939 fib_test_lb_bucket_t mpls_o_1200 = {
7940 .type = FT_LB_LABEL_O_LB,
7942 .lb = neos_1200.dpoi_index,
7948 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7949 FIB_TEST(fib_test_validate_entry(lfe,
7950 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7953 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
7954 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7955 FIB_TEST(fib_test_validate_entry(lfe,
7956 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7959 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
7961 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
7962 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
7963 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
7965 dpo_reset(&neos_1200);
7966 dpo_reset(&ip_1200);
7969 * A recursive via a label that does not exist
7971 fib_test_lb_bucket_t bucket_drop = {
7972 .type = FT_LB_SPECIAL,
7974 .adj = DPO_PROTO_IP4,
7977 fib_test_lb_bucket_t mpls_bucket_drop = {
7978 .type = FT_LB_SPECIAL,
7980 .adj = DPO_PROTO_MPLS,
7984 rpaths[0].frp_label_stack = NULL;
7985 lfe = fib_table_entry_path_add2(fib_index,
7988 FIB_ENTRY_FLAG_NONE,
7991 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
7992 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7994 ip_o_1200.lb.lb = ip_1200.dpoi_index;
7996 FIB_TEST(fib_test_validate_entry(lfe,
7997 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8000 "2.2.2.2.4/32 LB 1 buckets via: label 1200 EOS");
8001 lfe = fib_table_lookup(fib_index, &pfx_1200);
8002 FIB_TEST(fib_test_validate_entry(lfe,
8003 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8006 "1200/neos LB 1 buckets via: ip4-DROP");
8007 FIB_TEST(fib_test_validate_entry(lfe,
8008 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8011 "1200/neos LB 1 buckets via: mpls-DROP");
8013 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8015 dpo_reset(&ip_1200);
8018 * An rx-interface route.
8019 * like the tail of an mcast LSP
8021 dpo_id_t idpo = DPO_INVALID;
8023 interface_dpo_add_or_lock(DPO_PROTO_IP4,
8024 tm->hw[0]->sw_if_index,
8027 fib_prefix_t pfx_2500 = {
8029 .fp_proto = FIB_PROTOCOL_MPLS,
8032 .fp_payload_proto = DPO_PROTO_IP4,
8034 fib_test_lb_bucket_t rx_intf_0 = {
8037 .adj = idpo.dpoi_index,
8041 lfe = fib_table_entry_update_one_path(fib_index,
8044 FIB_ENTRY_FLAG_NONE,
8047 tm->hw[0]->sw_if_index,
8048 ~0, // invalid fib index
8051 FIB_ROUTE_PATH_INTF_RX);
8052 FIB_TEST(fib_test_validate_entry(lfe,
8053 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8056 "2500 rx-interface 0");
8057 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8060 * An MPLS mulicast entry
8062 fib_prefix_t pfx_3500 = {
8064 .fp_proto = FIB_PROTOCOL_MPLS,
8067 .fp_payload_proto = DPO_PROTO_IP4,
8069 fib_test_rep_bucket_t mc_0 = {
8070 .type = FT_REP_LABEL_O_ADJ,
8072 .adj = ai_mpls_10_10_10_1,
8077 fib_test_rep_bucket_t mc_intf_0 = {
8078 .type = FT_REP_INTF,
8080 .adj = idpo.dpoi_index,
8083 mpls_label_t *l3300 = NULL;
8084 vec_add1(l3300, 3300);
8086 lfe = fib_table_entry_update_one_path(lfib_index,
8089 FIB_ENTRY_FLAG_MULTICAST,
8092 tm->hw[0]->sw_if_index,
8093 ~0, // invalid fib index
8096 FIB_ROUTE_PATH_FLAG_NONE);
8097 FIB_TEST(fib_test_validate_entry(lfe,
8098 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8101 "3500 via replicate over 10.10.10.1");
8104 * MPLS Bud-node. Add a replication via an interface-receieve path
8106 lfe = fib_table_entry_path_add(lfib_index,
8109 FIB_ENTRY_FLAG_MULTICAST,
8112 tm->hw[0]->sw_if_index,
8113 ~0, // invalid fib index
8116 FIB_ROUTE_PATH_INTF_RX);
8117 FIB_TEST(fib_test_validate_entry(lfe,
8118 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8122 "3500 via replicate over 10.10.10.1 and interface-rx");
8125 * Add a replication via an interface-free for-us path
8127 fib_test_rep_bucket_t mc_disp = {
8128 .type = FT_REP_DISP_MFIB_LOOKUP,
8130 .adj = idpo.dpoi_index,
8133 lfe = fib_table_entry_path_add(lfib_index,
8136 FIB_ENTRY_FLAG_MULTICAST,
8143 FIB_ROUTE_PATH_RPF_ID);
8144 FIB_TEST(fib_test_validate_entry(lfe,
8145 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8150 "3500 via replicate over 10.10.10.1 and interface-rx");
8154 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8160 mpls_sw_interface_enable_disable(&mpls_main,
8161 tm->hw[0]->sw_if_index,
8164 FIB_TEST(lb_count == pool_elts(load_balance_pool),
8165 "Load-balance resources freed %d of %d",
8166 lb_count, pool_elts(load_balance_pool));
8167 FIB_TEST(0 == pool_elts(interface_dpo_pool),
8168 "interface_dpo resources freed %d of %d",
8169 0, pool_elts(interface_dpo_pool));
8174 static clib_error_t *
8175 fib_test (vlib_main_t * vm,
8176 unformat_input_t * input,
8177 vlib_cli_command_t * cmd_arg)
8182 fib_test_mk_intf(4);
8184 if (unformat (input, "debug"))
8186 fib_test_do_debug = 1;
8189 if (unformat (input, "ip"))
8191 res += fib_test_v4();
8192 res += fib_test_v6();
8194 else if (unformat (input, "label"))
8196 res += fib_test_label();
8198 else if (unformat (input, "ae"))
8200 res += fib_test_ae();
8202 else if (unformat (input, "lfib"))
8206 else if (unformat (input, "walk"))
8208 res += fib_test_walk();
8210 else if (unformat (input, "bfd"))
8212 res += fib_test_bfd();
8216 res += fib_test_v4();
8217 res += fib_test_v6();
8218 res += fib_test_ae();
8219 res += fib_test_bfd();
8220 res += fib_test_label();
8224 * fib-walk process must be disabled in order for the walk tests to work
8226 fib_walk_process_disable();
8227 res += fib_test_walk();
8228 fib_walk_process_enable();
8233 return clib_error_return(0, "FIB Unit Test Failed");
8241 VLIB_CLI_COMMAND (test_fib_command, static) = {
8243 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8244 .function = fib_test,
8248 fib_test_init (vlib_main_t *vm)
8253 VLIB_INIT_FUNCTION (fib_test_init);